Merge branch 'The-Powder-Toy:master' into paper

This commit is contained in:
Rebmiami 2023-12-11 14:00:01 +00:00 committed by GitHub
commit 5613bf70f5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
147 changed files with 1790 additions and 1458 deletions

View File

@ -212,6 +212,7 @@ if host_platform == 'emscripten'
'-s', 'FS_DEBUG',
'-s', 'MODULARIZE',
'-s', 'EXPORT_NAME=create_' + app_exe,
'-Wl,-u,_emscripten_run_callback_on_thread',
'-lidbfs.js',
]
emcc_args = [

View File

@ -54,7 +54,7 @@ option(
'build_num',
type: 'integer',
min: 0,
value: 353,
value: 354,
description: 'Build number, should be strictly monotonously increasing across public releases'
)
option(
@ -75,7 +75,7 @@ option(
'upstream_build_num',
type: 'integer',
min: 0,
value: 353,
value: 354,
description: 'Upstream build number, mod owners should not change this but merge upstream changes to it'
)
option(

View File

@ -12,6 +12,7 @@
#include "common/platform/Platform.h"
#include "graphics/Graphics.h"
#include "simulation/SaveRenderer.h"
#include "simulation/SimulationData.h"
#include "common/tpt-rand.h"
#include "gui/game/Favorite.h"
#include "gui/Style.h"
@ -180,6 +181,7 @@ struct ExplicitSingletons
std::unique_ptr<SaveRenderer> saveRenderer;
std::unique_ptr<Favorite> favorite;
std::unique_ptr<ui::Engine> engine;
std::unique_ptr<SimulationData> simulationData;
std::unique_ptr<GameController> gameController;
};
static std::unique_ptr<ExplicitSingletons> explicitSingletons;
@ -416,6 +418,7 @@ int Main(int argc, char *argv[])
}
auto wrapWithBluescreen = [&]() {
explicitSingletons->simulationData = std::make_unique<SimulationData>();
explicitSingletons->gameController = std::make_unique<GameController>();
auto *gameController = explicitSingletons->gameController.get();
engine.ShowWindow(gameController->GetView());

View File

@ -6,6 +6,7 @@
#include "gui/interface/Engine.h"
#include "client/GameSave.h"
#include "simulation/Simulation.h"
#include "simulation/SimulationData.h"
#include "common/platform/Platform.h"
#include <ctime>
#include <iostream>
@ -39,6 +40,7 @@ int main(int argc, char *argv[])
throw e;
}
auto simulationData = std::make_unique<SimulationData>();
Simulation * sim = new Simulation();
Renderer * ren = new Renderer(sim);

View File

@ -61,3 +61,5 @@ constexpr float GLASS_IOR = 1.9f;
constexpr float GLASS_DISP = 0.07f;
constexpr float R_TEMP = 22;
constexpr bool LATENTHEAT = false;

View File

@ -3,6 +3,7 @@
#include "Format.h"
#include "simulation/Simulation.h"
#include "simulation/ElementClasses.h"
#include "simulation/elements/PIPE.h"
#include "common/tpt-compat.h"
#include "bson/BSON.h"
#include "graphics/Renderer.h"
@ -46,6 +47,86 @@ GameSave::GameSave(const std::vector<char> &data, bool newWantAuthors)
}
}
void GameSave::MapPalette()
{
int partMap[PT_NUM];
for(int i = 0; i < PT_NUM; i++)
{
partMap[i] = i;
}
auto &sd = SimulationData::CRef();
auto &elements = sd.elements;
if(palette.size())
{
if (version >= Version(98, 0))
{
for(int i = 0; i < PT_NUM; i++)
{
partMap[i] = 0;
}
}
for(auto &pi : palette)
{
if (pi.second > 0 && pi.second < PT_NUM)
{
int myId = 0;
for (int i = 0; i < PT_NUM; i++)
{
if (elements[i].Enabled && elements[i].Identifier == pi.first)
{
myId = i;
}
}
if (myId)
{
partMap[pi.second] = myId;
}
else
{
missingElements.identifiers.insert(pi);
}
}
}
}
auto paletteLookup = [this, &partMap](int type) {
if (type > 0 && type < PT_NUM)
{
auto carriedType = partMap[type];
if (!carriedType) // type is not 0 so this shouldn't be 0 either
{
missingElements.ids.insert(type);
}
type = carriedType;
}
return type;
};
unsigned int pmapmask = (1<<pmapbits)-1;
auto &possiblyCarriesType = Particle::PossiblyCarriesType();
auto &properties = Particle::GetProperties();
for (int n = 0; n < NPART && n < particlesCount; n++)
{
Particle &tempPart = particles[n];
if (tempPart.type <= 0 || tempPart.type >= PT_NUM)
{
continue;
}
tempPart.type = paletteLookup(tempPart.type);
for (auto index : possiblyCarriesType)
{
if (elements[tempPart.type].CarriesTypeIn & (1U << index))
{
auto *prop = reinterpret_cast<int *>(reinterpret_cast<char *>(&tempPart) + properties[index].Offset);
auto carriedType = *prop & int(pmapmask);
auto extra = *prop >> pmapbits;
carriedType = paletteLookup(carriedType);
*prop = PMAP(extra, carriedType);
}
}
}
}
void GameSave::Expand(const std::vector<char> &data)
{
try
@ -67,6 +148,7 @@ void GameSave::Expand(const std::vector<char> &data)
std::cerr << "Got Magic number '" << data[0] << data[1] << data[2] << "'" << std::endl;
throw ParseException(ParseException::Corrupt, "Invalid save format");
}
MapPalette();
}
else
{
@ -114,9 +196,6 @@ std::pair<bool, std::vector<char>> GameSave::Serialise() const
return { false, {} };
}
extern const std::array<Vec2<int>, 8> Element_PIPE_offsets;
void Element_PIPE_transformPatchOffsets(Particle &part, const std::array<int, 8> &offsetMap);
void GameSave::Transform(Mat2<int> transform, Vec2<int> nudge)
{
// undo translation by rotation
@ -328,6 +407,7 @@ static void CheckBsonFieldFloat(bson_iterator iter, const char *field, float *se
void GameSave::readOPS(const std::vector<char> &data)
{
auto &builtinGol = SimulationData::builtinGol;
constexpr auto currentVersion = Version(currentVersionMajor, 0);
constexpr auto nextVersion = Version(nextVersionMajor, 0);
@ -1185,6 +1265,7 @@ void GameSave::readOPS(const std::vector<char> &data)
#define MTOS(str) MTOS_EXPAND(str)
void GameSave::readPSv(const std::vector<char> &dataVec)
{
auto &builtinGol = SimulationData::builtinGol;
Renderer::PopulateTables();
unsigned char * saveData = (unsigned char *)&dataVec[0];
@ -1197,7 +1278,7 @@ void GameSave::readPSv(const std::vector<char> &dataVec)
char tempSignText[255];
sign tempSign("", 0, 0, sign::Left);
auto &elements = GetElements();
auto &builtinElements = GetElements();
//New file header uses PSv, replacing fuC. This is to detect if the client uses a new save format for temperatures
//This creates a problem for old clients, that display and "corrupt" error instead of a "newer version" error
@ -1607,7 +1688,7 @@ void GameSave::readPSv(const std::vector<char> &dataVec)
}
else
{
particles[i-1].temp = elements[particles[i-1].type].DefaultProperties.temp;
particles[i-1].temp = builtinElements[particles[i-1].type].DefaultProperties.temp;
}
}
}
@ -1970,7 +2051,7 @@ std::pair<bool, std::vector<char>> GameSave::serialiseOPS() const
That way, if we ever need a 25th bit, we won't have to change the save format
*/
auto &elements = GetElements();
auto &builtinElements = GetElements();
auto &possiblyCarriesType = Particle::PossiblyCarriesType();
auto &properties = Particle::GetProperties();
// Allocate enough space to store all Particles and 3 bytes on top of that per Particle, for the field descriptors.
@ -1980,6 +2061,9 @@ std::pair<bool, std::vector<char>> GameSave::serialiseOPS() const
std::vector<unsigned> partsSaveIndex(NPART);
unsigned int partsCount = 0;
std::fill(&partsSaveIndex[0], &partsSaveIndex[0] + NPART, 0);
auto &sd = SimulationData::CRef();
auto &elements = sd.elements;
std::set<int> paletteSet;
for (auto pos : partS.OriginRect().Range<TOP_TO_BOTTOM, LEFT_TO_RIGHT>())
{
//Find the first particle in this position
@ -1997,6 +2081,16 @@ std::pair<bool, std::vector<char>> GameSave::serialiseOPS() const
//Store saved particle index+1 for this partsptr index (0 means not saved)
partsSaveIndex[i] = (partsCount++) + 1;
paletteSet.insert(particles[i].type);
for (auto index : possiblyCarriesType)
{
if (elements[particles[i].type].CarriesTypeIn & (1U << index))
{
auto *prop = reinterpret_cast<const int *>(reinterpret_cast<const char *>(&particles[i]) + properties[index].Offset);
paletteSet.insert(TYP(*prop));
}
}
//Type (required)
partsData[partsDataLen++] = particles[i].type;
@ -2200,7 +2294,7 @@ std::pair<bool, std::vector<char>> GameSave::serialiseOPS() const
{
for (auto index : possiblyCarriesType)
{
if (elements[particles[i].type].CarriesTypeIn & (1U << index))
if (builtinElements[particles[i].type].CarriesTypeIn & (1U << index))
{
auto *prop = reinterpret_cast<const int *>(reinterpret_cast<const char *>(&particles[i]) + properties[index].Offset);
if (TYP(*prop) > 0xFF)
@ -2250,6 +2344,12 @@ std::pair<bool, std::vector<char>> GameSave::serialiseOPS() const
}
}
std::vector<PaletteItem> paletteData;
for (int ID : paletteSet)
{
paletteData.push_back(GameSave::PaletteItem(elements[ID].Identifier, ID));
}
unsigned int soapLinkDataLen = 0;
std::vector<unsigned char> soapLinkData(3*soapCount);
if (soapCount)
@ -2381,10 +2481,10 @@ std::pair<bool, std::vector<char>> GameSave::serialiseOPS() const
{
bson_append_binary(&b, "parts", (char)BSON_BIN_USER, (const char *)&partsData[0], partsDataLen);
if (palette.size())
if (paletteData.size())
{
bson_append_start_array(&b, "palette");
for(auto iter = palette.begin(), end = palette.end(); iter != end; ++iter)
for(auto iter = paletteData.begin(), end = paletteData.end(); iter != end; ++iter)
{
bson_append_int(&b, (*iter).first.c_str(), (*iter).second);
}

View File

@ -5,6 +5,7 @@
#include "common/Version.h"
#include "simulation/Sign.h"
#include "simulation/Particle.h"
#include "simulation/MissingElements.h"
#include "Misc.h"
#include "SimulationConfig.h"
#include <vector>
@ -62,6 +63,8 @@ class GameSave
void readPSv(const std::vector<char> &data);
std::pair<bool, std::vector<char>> serialiseOPS() const;
void MapPalette();
public:
Vec2<int> blockSize = { 0, 0 };
bool fromNewerVersion = false;
@ -101,6 +104,8 @@ public:
int edgeMode = 0;
bool wantAuthors = true;
MissingElements missingElements;
//Signs
std::vector<sign> signs;
StkmData stkm;

View File

@ -29,7 +29,7 @@ ThumbnailRendererTask::~ThumbnailRendererTask()
bool ThumbnailRendererTask::doWork()
{
std::tie(thumbnail, std::ignore) = SaveRenderer::Ref().Render(save.get(), decorations, fire);
thumbnail = SaveRenderer::Ref().Render(save.get(), decorations, fire);
if (thumbnail)
{
thumbnail->ResizeToFit(size, true);

View File

@ -28,4 +28,9 @@ public:
{
return *Instance();
}
static const Type &CRef()
{
return Ref();
}
};

View File

@ -27,6 +27,21 @@ struct Version
return *this < other || *this == other;
}
constexpr bool operator >=(const Version &other) const
{
return !(*this < other);
}
constexpr bool operator >(const Version &other) const
{
return !(*this <= other);
}
constexpr bool operator !=(const Version &other) const
{
return !(*this == other);
}
constexpr size_t operator [](size_t index) const
{
return components[index];

View File

@ -1,9 +1,7 @@
#include "ElementPopulation.h"
#include "gui/interface/Engine.h"
#include "simulation/Simulation.h"
#include "simulation/SimulationData.h"
#include "graphics/Graphics.h"
ElementPopulationDebug::ElementPopulationDebug(unsigned int id, Simulation * sim):
@ -16,6 +14,8 @@ ElementPopulationDebug::ElementPopulationDebug(unsigned int id, Simulation * sim
void ElementPopulationDebug::Draw()
{
auto &sd = SimulationData::CRef();
auto &elements = sd.elements;
Graphics * g = ui::Engine::Ref().g;
int yBottom = YRES-10;
@ -30,7 +30,7 @@ void ElementPopulationDebug::Draw()
int bars = 0;
for(int i = 0; i < PT_NUM; i++)
{
if(sim->elements[i].Enabled)
if(elements[i].Enabled)
{
if(maxVal < sim->elementCount[i])
maxVal = float(sim->elementCount[i]);
@ -49,13 +49,13 @@ void ElementPopulationDebug::Draw()
bars = 0;
for(int i = 0; i < PT_NUM; i++)
{
if(sim->elements[i].Enabled)
if(elements[i].Enabled)
{
auto count = sim->elementCount[i];
auto barSize = int(count * scale - 0.5f);
int barX = bars;//*2;
RGB<uint8_t> colour = sim->elements[i].Colour;
RGB<uint8_t> colour = elements[i].Colour;
g->DrawLine({ xStart+barX, yBottom+3 }, { xStart+barX, yBottom+2 }, colour);
if(sim->elementCount[i])

View File

@ -6,7 +6,7 @@
#include "simulation/ElementClasses.h"
#include "graphics/Graphics.h"
SurfaceNormals::SurfaceNormals(unsigned int id, Simulation *newSim, GameView *newView, GameController *newController) :
SurfaceNormals::SurfaceNormals(unsigned int id, const Simulation *newSim, GameView *newView, GameController *newController) :
DebugInfo(id), sim(newSim), view(newView), controller(newController)
{
}
@ -29,7 +29,7 @@ void SurfaceNormals::Draw()
auto &parts = sim->parts;
auto x = int(parts[i].x + 0.5f);
auto y = int(parts[i].y + 0.5f);
auto mr = sim->PlanMove(i, x, y, false);
auto mr = Simulation::PlanMove<false>(*sim, i, x, y);
if (t == PT_PHOT)
{
if (parts[i].flags & FLAG_SKIPMOVE)
@ -48,7 +48,7 @@ void SurfaceNormals::Draw()
}
}
}
auto gn = sim->get_normal_interp(t, parts[i].x, parts[i].y, mr.vx, mr.vy);
auto gn = sim->get_normal_interp<false>(*sim, t, parts[i].x, parts[i].y, mr.vx, mr.vy);
if (!gn.success)
{
return;

View File

@ -6,12 +6,12 @@ class GameView;
class GameController;
class SurfaceNormals : public DebugInfo
{
Simulation *sim;
const Simulation *sim;
GameView *view;
GameController *controller;
public:
SurfaceNormals(unsigned int id, Simulation *newSim, GameView *newView, GameController *newController);
SurfaceNormals(unsigned int id, const Simulation *newSim, GameView *newView, GameController *newController);
void Draw() override;
};

View File

@ -7,11 +7,13 @@
#include "simulation/ElementClasses.h"
#include "simulation/Air.h"
#include "simulation/gravity/Gravity.h"
#include "simulation/orbitalparts.h"
#include <cmath>
std::unique_ptr<VideoBuffer> Renderer::WallIcon(int wallID, Vec2<int> size)
{
auto wtypes = LoadWalls();
auto &sd = SimulationData::CRef();
auto &wtypes = sd.wtypes;
if (wallID < 0 || wallID >= int(wtypes.size()))
return nullptr;
wall_type const &wtype = wtypes[wallID];
@ -170,14 +172,20 @@ void Renderer::DrawSigns()
void Renderer::render_parts()
{
auto &sd = SimulationData::CRef();
auto &elements = sd.elements;
auto &graphicscache = sd.graphicscache;
GraphicsFuncContext gfctx;
gfctx.ren = this;
gfctx.sim = sim;
gfctx.rng.seed(rng());
gfctx.pipeSubcallCpart = nullptr;
gfctx.pipeSubcallTpart = nullptr;
int deca, decr, decg, decb, cola, colr, colg, colb, firea, firer, fireg, fireb, pixel_mode, q, i, t, nx, ny, x, y;
int orbd[4] = {0, 0, 0, 0}, orbl[4] = {0, 0, 0, 0};
Particle * parts;
Element *elements;
if(!sim)
return;
parts = sim->parts;
elements = sim->elements.data();
auto *parts = sim->parts;
if (gridSize)//draws the grid
{
for (ny=0; ny<YRES; ny++)
@ -199,7 +207,7 @@ void Renderer::render_parts()
if(nx >= XRES || nx < 0 || ny >= YRES || ny < 0)
continue;
if(TYP(sim->photons[ny][nx]) && !(sim->elements[t].Properties & TYPE_ENERGY) && t!=PT_STKM && t!=PT_STKM2 && t!=PT_FIGH)
if(TYP(sim->photons[ny][nx]) && !(elements[t].Properties & TYPE_ENERGY) && t!=PT_STKM && t!=PT_STKM2 && t!=PT_FIGH)
continue;
//Defaults
@ -242,18 +250,22 @@ void Renderer::render_parts()
}
else if(!(colour_mode & COLOUR_BASC))
{
if (!elements[t].Graphics || (*(elements[t].Graphics))(this, &(sim->parts[i]), nx, ny, &pixel_mode, &cola, &colr, &colg, &colb, &firea, &firer, &fireg, &fireb)) //That's a lot of args, a struct might be better
auto *graphics = elements[t].Graphics;
auto makeReady = !graphics || graphics(gfctx, &(sim->parts[i]), nx, ny, &pixel_mode, &cola, &colr, &colg, &colb, &firea, &firer, &fireg, &fireb); //That's a lot of args, a struct might be better
if (makeReady && sim->useLuaCallbacks)
{
graphicscache[t].isready = 1;
graphicscache[t].pixel_mode = pixel_mode;
graphicscache[t].cola = cola;
graphicscache[t].colr = colr;
graphicscache[t].colg = colg;
graphicscache[t].colb = colb;
graphicscache[t].firea = firea;
graphicscache[t].firer = firer;
graphicscache[t].fireg = fireg;
graphicscache[t].fireb = fireb;
// useLuaCallbacks is true so we locked sd.elementGraphicsMx exclusively
auto &wgraphicscache = SimulationData::Ref().graphicscache;
wgraphicscache[t].isready = 1;
wgraphicscache[t].pixel_mode = pixel_mode;
wgraphicscache[t].cola = cola;
wgraphicscache[t].colr = colr;
wgraphicscache[t].colg = colg;
wgraphicscache[t].colb = colb;
wgraphicscache[t].firea = firea;
wgraphicscache[t].firer = firer;
wgraphicscache[t].fireg = fireg;
wgraphicscache[t].fireb = fireb;
}
}
if((elements[t].Properties & PROP_HOT_GLOW) && sim->parts[i].temp>(elements[t].HighTemperature-800.0f))
@ -431,7 +443,7 @@ void Renderer::render_parts()
if(pixel_mode & PSPEC_STICKMAN)
{
int legr, legg, legb;
playerst *cplayer;
const playerst *cplayer;
if(t==PT_STKM)
cplayer = &sim->player;
else if(t==PT_STKM2)
@ -619,7 +631,7 @@ void Renderer::render_parts()
}
if(pixel_mode & PMODE_SPARK)
{
auto flicker = float(rng()%20);
auto flicker = float(gfctx.rng()%20);
auto gradv = 4*sim->parts[i].life + flicker;
for (x = 0; gradv>0.5; x++) {
auto col = RGBA<uint8_t>(
@ -636,7 +648,7 @@ void Renderer::render_parts()
}
if(pixel_mode & PMODE_FLARE)
{
auto flicker = float(rng()%20);
auto flicker = float(gfctx.rng()%20);
auto gradv = flicker + fabs(parts[i].vx)*17 + fabs(sim->parts[i].vy)*17;
BlendPixel({ nx, ny }, RGBA<uint8_t>(colr, colg, colb, int((gradv*4)>255?255:(gradv*4)) ));
BlendPixel({ nx+1, ny }, RGBA<uint8_t>(colr, colg, colb,int( (gradv*2)>255?255:(gradv*2)) ));
@ -658,7 +670,7 @@ void Renderer::render_parts()
}
if(pixel_mode & PMODE_LFLARE)
{
auto flicker = float(rng()%20);
auto flicker = float(gfctx.rng()%20);
auto gradv = flicker + fabs(parts[i].vx)*17 + fabs(parts[i].vy)*17;
BlendPixel({ nx, ny }, RGBA<uint8_t>(colr, colg, colb, int((gradv*4)>255?255:(gradv*4)) ));
BlendPixel({ nx+1, ny }, RGBA<uint8_t>(colr, colg, colb, int((gradv*2)>255?255:(gradv*2)) ));
@ -685,7 +697,7 @@ void Renderer::render_parts()
int r;
float drad = 0.0f;
float ddist = 0.0f;
sim->orbitalparts_get(parts[i].life, parts[i].ctype, orbd, orbl);
orbitalparts_get(parts[i].life, parts[i].ctype, orbd, orbl);
for (r = 0; r < 4; r++) {
ddist = ((float)orbd[r])/16.0f;
drad = (TPT_PI_FLT * ((float)orbl[r]) / 180.0f)*1.41f;
@ -702,7 +714,7 @@ void Renderer::render_parts()
int r;
float drad = 0.0f;
float ddist = 0.0f;
sim->orbitalparts_get(parts[i].life, parts[i].ctype, orbd, orbl);
orbitalparts_get(parts[i].life, parts[i].ctype, orbd, orbl);
for (r = 0; r < 4; r++) {
ddist = ((float)orbd[r])/16.0f;
drad = (TPT_PI_FLT * ((float)orbl[r]) / 180.0f)*1.41f;
@ -927,6 +939,8 @@ void Renderer::draw_air()
void Renderer::DrawWalls()
{
auto &sd = SimulationData::CRef();
auto &wtypes = sd.wtypes;
for (int y = 0; y < YCELLS; y++)
for (int x =0; x < XCELLS; x++)
if (sim->bmap[y][x])
@ -935,8 +949,8 @@ void Renderer::DrawWalls()
if (wt >= UI_WALLCOUNT)
continue;
unsigned char powered = sim->emap[y][x];
RGB<uint8_t> prgb = sim->wtypes[wt].colour;
RGB<uint8_t> grgb = sim->wtypes[wt].eglow;
RGB<uint8_t> prgb = wtypes[wt].colour;
RGB<uint8_t> grgb = wtypes[wt].eglow;
if (findingElement)
{
@ -951,7 +965,7 @@ void Renderer::DrawWalls()
pixel pc = prgb.Pack();
pixel gc = grgb.Pack();
switch (sim->wtypes[wt].drawstyle)
switch (wtypes[wt].drawstyle)
{
case 0:
if (wt == WL_EWALL || wt == WL_STASIS)
@ -1075,7 +1089,7 @@ void Renderer::DrawWalls()
// when in blob view, draw some blobs...
if (render_mode & PMODE_BLOB)
{
switch (sim->wtypes[wt].drawstyle)
switch (wtypes[wt].drawstyle)
{
case 0:
if (wt == WL_EWALL || wt == WL_STASIS)
@ -1156,10 +1170,10 @@ void Renderer::DrawWalls()
}
}
if (sim->wtypes[wt].eglow.Pack() && powered)
if (wtypes[wt].eglow.Pack() && powered)
{
// glow if electrified
RGB<uint8_t> glow = sim->wtypes[wt].eglow;
RGB<uint8_t> glow = wtypes[wt].eglow;
int alpha = 255;
int cr = (alpha*glow.Red + (255-alpha)*fire_r[y/CELL][x/CELL]) >> 8;
int cg = (alpha*glow.Green + (255-alpha)*fire_g[y/CELL][x/CELL]) >> 8;

View File

@ -1,5 +1,6 @@
#pragma once
#include "Graphics.h"
#include "gui/game/RenderPreset.h"
#include "gui/interface/Point.h"
#include "common/tpt-rand.h"
#include "SimulationConfig.h"
@ -12,28 +13,17 @@
class RenderPreset;
class Simulation;
class Renderer;
struct Particle;
struct gcache_item
struct GraphicsFuncContext
{
int isready;
int pixel_mode;
int cola, colr, colg, colb;
int firea, firer, fireg, fireb;
gcache_item() :
isready(0),
pixel_mode(0),
cola(0),
colr(0),
colg(0),
colb(0),
firea(0),
firer(0),
fireg(0),
fireb(0)
{
}
const Renderer *ren;
const Simulation *sim;
RNG rng;
const Particle *pipeSubcallCpart;
Particle *pipeSubcallTpart;
};
typedef struct gcache_item gcache_item;
int HeatToColour(float temp);
@ -64,8 +54,7 @@ public:
RNG rng;
Simulation * sim;
gcache_item *graphicscache;
const Simulation *sim;
std::vector<unsigned int> render_modes;
unsigned int render_mode;
@ -147,8 +136,7 @@ public:
static std::unique_ptr<VideoBuffer> WallIcon(int wallID, Vec2<int> size);
Renderer(Simulation * sim);
~Renderer();
Renderer(Simulation *newSim);
#define RENDERER_TABLE(name) \
static std::vector<RGB<uint8_t>> name; \

View File

@ -224,8 +224,8 @@ void Renderer::PopulateTables()
}
}
Renderer::Renderer(Simulation * sim):
sim(NULL),
Renderer::Renderer(Simulation *newSim):
sim(newSim),
render_mode(0),
colour_mode(0),
display_mode(0),
@ -246,8 +246,6 @@ Renderer::Renderer(Simulation * sim):
{
PopulateTables();
this->sim = sim;
memset(fire_r, 0, sizeof(fire_r));
memset(fire_g, 0, sizeof(fire_g));
memset(fire_b, 0, sizeof(fire_b));
@ -323,10 +321,6 @@ Renderer::Renderer(Simulation * sim):
COLOUR_LIFE
});
//Prepare the graphics cache
graphicscache = new gcache_item[PT_NUM];
std::fill(&graphicscache[0], &graphicscache[0] + PT_NUM, gcache_item());
prepare_alpha(CELL, 1.0f);
}
@ -466,9 +460,4 @@ VideoBuffer Renderer::DumpFrame()
return newBuffer;
}
Renderer::~Renderer()
{
delete[] graphicscache;
}
template struct RasterDrawMethods<Renderer>;

View File

@ -0,0 +1,15 @@
#pragma once
struct gcache_item
{
int isready = 0;
int pixel_mode = 0;
int cola = 0;
int colr = 0;
int colg = 0;
int colb = 0;
int firea = 0;
int firer = 0;
int fireg = 0;
int fireb = 0;
};

View File

@ -4,7 +4,7 @@
#include "client/Client.h"
#include "common/tpt-rand.h"
#include "simulation/GOLString.h"
#include "simulation/Simulation.h"
#include "simulation/SimulationData.h"
#include "gui/Style.h"
#include "gui/interface/Button.h"
@ -23,14 +23,13 @@ class GOLWindow: public ui::Window
ui::Button *highColourButton, *lowColourButton;
ui::Textbox *nameField, *ruleField;
GameModel &gameModel;
Simulation *sim;
int toolSelection;
void updateGradient();
void validate();
public:
GOLWindow(GameModel &gameModel, Simulation *sim, int toolSelection, int rule, RGB<uint8_t> colour1, RGB<uint8_t> colour2);
GOLWindow(GameModel &gameModel, int toolSelection, int rule, RGB<uint8_t> colour1, RGB<uint8_t> colour2);
virtual ~GOLWindow()
{}
@ -39,12 +38,11 @@ public:
void OnTryExit(ExitMethod method) override;
};
GOLWindow::GOLWindow(GameModel &gameModel_, Simulation *sim_, int toolSelection, int rule, RGB<uint8_t> colour1, RGB<uint8_t> colour2):
GOLWindow::GOLWindow(GameModel &gameModel_, int toolSelection, int rule, RGB<uint8_t> colour1, RGB<uint8_t> colour2):
ui::Window(ui::Point(-1, -1), ui::Point(200, 108)),
highColour(colour1.WithAlpha(0xFF)),
lowColour(colour2.WithAlpha(0xFF)),
gameModel(gameModel_),
sim(sim_),
toolSelection(toolSelection)
{
highColour.Alpha = 255;
@ -135,6 +133,7 @@ void GOLWindow::updateGradient()
void GOLWindow::validate()
{
auto &sd = SimulationData::CRef();
auto nameString = nameField->GetText();
auto ruleString = ruleField->GetText();
if (!ValidateGOLName(nameString))
@ -149,7 +148,7 @@ void GOLWindow::validate()
new ErrorMessage("Could not add GOL type", "Invalid rule provided");
return;
}
if (sim->GetCustomGOLByRule(rule))
if (sd.GetCustomGOLByRule(rule))
{
new ErrorMessage("Could not add GOL type", "This Custom GoL rule already exists");
return;
@ -204,5 +203,5 @@ void GOLWindow::OnDraw()
void GOLTool::OpenWindow(Simulation *sim, int toolSelection, int rule, RGB<uint8_t> colour1, RGB<uint8_t> colour2)
{
new GOLWindow(gameModel, sim, toolSelection, rule, colour1, colour2);
new GOLWindow(gameModel, toolSelection, rule, colour1, colour2);
}

View File

@ -31,6 +31,7 @@
#include "simulation/Simulation.h"
#include "simulation/SimulationData.h"
#include "simulation/Snapshot.h"
#include "simulation/elements/STKM.h"
#include "gui/dialogues/ErrorMessage.h"
#include "gui/dialogues/InformationMessage.h"
@ -757,11 +758,12 @@ void GameController::ResetAir()
void GameController::ResetSpark()
{
auto &sd = SimulationData::CRef();
Simulation * sim = gameModel->GetSimulation();
for (int i = 0; i < NPART; i++)
if (sim->parts[i].type == PT_SPRK)
{
if (sim->parts[i].ctype >= 0 && sim->parts[i].ctype < PT_NUM && sim->elements[sim->parts[i].ctype].Enabled)
if (sim->parts[i].ctype >= 0 && sim->parts[i].ctype < PT_NUM && sd.elements[sim->parts[i].ctype].Enabled)
{
sim->parts[i].type = sim->parts[i].ctype;
sim->parts[i].ctype = sim->parts[i].life = 0;
@ -849,6 +851,7 @@ void GameController::LoadRenderPreset(int presetNum)
void GameController::Update()
{
auto &sd = SimulationData::CRef();
ui::Point pos = gameView->GetMousePosition();
gameModel->GetRenderer()->mousePos = PointTranslate(pos);
if (pos.X < XRES && pos.Y < YRES)
@ -875,11 +878,10 @@ void GameController::Update()
if (activeTool->Identifier.BeginsWith("DEFAULT_PT_"))
{
int sr = activeTool->ToolID;
if (sr && sim->IsElementOrNone(sr))
if (sr && sd.IsElementOrNone(sr))
rightSelected = sr;
}
void Element_STKM_set_element(Simulation *sim, playerst *playerp, int element);
if (!sim->player.spwn)
Element_STKM_set_element(sim, &sim->player, rightSelected);
if (!sim->player2.spwn)
@ -1497,20 +1499,14 @@ String GameController::ElementResolve(int type, int ctype)
// "NONE" should never be displayed in the HUD
if (!type)
return "";
if (gameModel && gameModel->GetSimulation())
{
return gameModel->GetSimulation()->ElementResolve(type, ctype);
}
return "";
auto &sd = SimulationData::CRef();
return sd.ElementResolve(type, ctype);
}
String GameController::BasicParticleInfo(Particle const &sample_part)
{
if (gameModel && gameModel->GetSimulation())
{
return gameModel->GetSimulation()->BasicParticleInfo(sample_part);
}
return "";
auto &sd = SimulationData::CRef();
return sd.BasicParticleInfo(sample_part);
}
void GameController::ReloadSim()
@ -1529,18 +1525,15 @@ void GameController::ReloadSim()
bool GameController::IsValidElement(int type)
{
if (gameModel && gameModel->GetSimulation())
{
return (type && gameModel->GetSimulation()->IsElement(type));
}
else
return false;
auto &sd = SimulationData::CRef();
return type && sd.IsElement(type);
}
String GameController::WallName(int type)
{
if(gameModel && gameModel->GetSimulation() && type >= 0 && type < UI_WALLCOUNT)
return gameModel->GetSimulation()->wtypes[type].name;
auto &sd = SimulationData::CRef();
if(type >= 0 && type < UI_WALLCOUNT)
return sd.wtypes[type].name;
else
return String();
}

View File

@ -56,6 +56,7 @@ GameModel::GameModel():
decoSpace(0)
{
sim = new Simulation();
sim->useLuaCallbacks = true;
ren = new Renderer(sim);
activeTools = regularToolset;
@ -219,6 +220,9 @@ void GameModel::BuildQuickOptionMenu(GameController * controller)
void GameModel::BuildMenus()
{
auto &sd = SimulationData::Ref();
auto &elements = sd.elements;
auto &builtinGol = SimulationData::builtinGol;
int lastMenu = -1;
if(activeMenu != -1)
lastMenu = activeMenu;
@ -253,35 +257,35 @@ void GameModel::BuildMenus()
//Create menus
for (int i = 0; i < SC_TOTAL; i++)
{
menuList.push_back(new Menu(sim->msections[i].icon, sim->msections[i].name, sim->msections[i].doshow));
menuList.push_back(new Menu(sd.msections[i].icon, sd.msections[i].name, sd.msections[i].doshow));
}
//Build menus from Simulation elements
for(int i = 0; i < PT_NUM; i++)
{
if(sim->elements[i].Enabled)
if(elements[i].Enabled)
{
Tool * tempTool;
if(i == PT_LIGH)
{
tempTool = new Element_LIGH_Tool(i, sim->elements[i].Name, sim->elements[i].Description, sim->elements[i].Colour, sim->elements[i].Identifier, sim->elements[i].IconGenerator);
tempTool = new Element_LIGH_Tool(i, elements[i].Name, elements[i].Description, elements[i].Colour, elements[i].Identifier, elements[i].IconGenerator);
}
else if(i == PT_TESC)
{
tempTool = new Element_TESC_Tool(i, sim->elements[i].Name, sim->elements[i].Description, sim->elements[i].Colour, sim->elements[i].Identifier, sim->elements[i].IconGenerator);
tempTool = new Element_TESC_Tool(i, elements[i].Name, elements[i].Description, elements[i].Colour, elements[i].Identifier, elements[i].IconGenerator);
}
else if(i == PT_STKM || i == PT_FIGH || i == PT_STKM2)
{
tempTool = new PlopTool(i, sim->elements[i].Name, sim->elements[i].Description, sim->elements[i].Colour, sim->elements[i].Identifier, sim->elements[i].IconGenerator);
tempTool = new PlopTool(i, elements[i].Name, elements[i].Description, elements[i].Colour, elements[i].Identifier, elements[i].IconGenerator);
}
else
{
tempTool = new ElementTool(i, sim->elements[i].Name, sim->elements[i].Description, sim->elements[i].Colour, sim->elements[i].Identifier, sim->elements[i].IconGenerator);
tempTool = new ElementTool(i, elements[i].Name, elements[i].Description, elements[i].Colour, elements[i].Identifier, elements[i].IconGenerator);
}
if (sim->elements[i].MenuSection >= 0 && sim->elements[i].MenuSection < SC_TOTAL && sim->elements[i].MenuVisible)
if (elements[i].MenuSection >= 0 && elements[i].MenuSection < SC_TOTAL && elements[i].MenuVisible)
{
menuList[sim->elements[i].MenuSection]->AddTool(tempTool);
menuList[elements[i].MenuSection]->AddTool(tempTool);
}
else
{
@ -301,7 +305,7 @@ void GameModel::BuildMenus()
auto &prefs = GlobalPrefs::Ref();
auto customGOLTypes = prefs.Get("CustomGOL.Types", std::vector<ByteString>{});
std::vector<ByteString> validatedCustomLifeTypes;
std::vector<Simulation::CustomGOLData> newCustomGol;
std::vector<CustomGOLData> newCustomGol;
bool removedAny = false;
for (auto gol : customGOLTypes)
{
@ -311,7 +315,7 @@ void GameModel::BuildMenus()
removedAny = true;
continue;
}
Simulation::CustomGOLData gd;
CustomGOLData gd;
gd.nameString = parts[0];
gd.ruleString = parts[1];
auto &colour1String = parts[2];
@ -350,26 +354,25 @@ void GameModel::BuildMenus()
Tool * tempTool = new ElementTool(PT_LIFE|PMAPID(gd.rule), gd.nameString, "Custom GOL type: " + gd.ruleString, RGB<uint8_t>::Unpack(gd.colour1), "DEFAULT_PT_LIFECUST_"+gd.nameString.ToAscii(), NULL);
menuList[SC_LIFE]->AddTool(tempTool);
}
sim->SetCustomGOL(newCustomGol);
sd.SetCustomGOL(newCustomGol);
}
//Build other menus from wall data
for(int i = 0; i < UI_WALLCOUNT; i++)
{
Tool * tempTool = new WallTool(i, sim->wtypes[i].descs, sim->wtypes[i].colour, sim->wtypes[i].identifier, sim->wtypes[i].textureGen);
Tool * tempTool = new WallTool(i, sd.wtypes[i].descs, sd.wtypes[i].colour, sd.wtypes[i].identifier, sd.wtypes[i].textureGen);
menuList[SC_WALL]->AddTool(tempTool);
//sim->wtypes[i]
}
//Build menu for tools
for (size_t i = 0; i < sim->tools.size(); i++)
for (size_t i = 0; i < sd.tools.size(); i++)
{
Tool *tempTool = new Tool(
i,
sim->tools[i].Name,
sim->tools[i].Description,
sim->tools[i].Colour,
sim->tools[i].Identifier
sd.tools[i].Name,
sd.tools[i].Description,
sd.tools[i].Colour,
sd.tools[i].Identifier
);
menuList[SC_TOOL]->AddTool(tempTool);
}

View File

@ -1964,7 +1964,7 @@ void GameView::NotifyTransformedPlaceSaveChanged(GameModel *sender)
{
if (sender->GetTransformedPlaceSave())
{
std::tie(placeSaveThumb, std::ignore) = SaveRenderer::Ref().Render(sender->GetTransformedPlaceSave(), true, true, sender->GetRenderer());
placeSaveThumb = SaveRenderer::Ref().Render(sender->GetTransformedPlaceSave(), true, true, sender->GetRenderer());
selectMode = PlaceSave;
selectPoint2 = mousePosition;
}
@ -2108,6 +2108,9 @@ void GameView::OnDraw()
Graphics * g = GetGraphics();
if (ren)
{
// we're the main thread, we may write graphicscache
auto &sd = SimulationData::Ref();
std::unique_lock lk(sd.elementGraphicsMx);
ren->clearScreen();
ren->RenderBegin();
ren->SetSample(c->PointTranslate(currentMouse));

View File

@ -1,5 +1,6 @@
#pragma once
#include "Config.h"
#include "SimulationConfig.h"
#include "common/String.h"
inline ByteString VersionInfo()
@ -23,9 +24,10 @@ inline ByteString VersionInfo()
{
sb << " LUACONSOLE";
}
#ifdef REALISTIC
sb << " REALISTIC";
#endif
if constexpr (LATENTHEAT)
{
sb << " LATENTHEAT";
}
if constexpr (NOHTTP)
{
sb << " NOHTTP";

View File

@ -114,6 +114,8 @@ void PropertyWindow::Update()
void PropertyWindow::CheckProperty()
{
auto &sd = SimulationData::CRef();
auto &elements = sd.elements;
configuration.reset();
PropertyTool::Configuration newConfiguration;
if (!(property->GetOption().second!=-1 && textField->GetText().length() > 0))
@ -142,7 +144,7 @@ void PropertyWindow::CheckProperty()
else
{
// Try to parse as particle name
v = sim->GetParticleType(value.ToUtf8());
v = sd.GetParticleType(value.ToUtf8());
// Try to parse special GoL rules
if (v == -1 && properties[property->GetOption().second].Name == "ctype")
@ -160,7 +162,7 @@ void PropertyWindow::CheckProperty()
}
else
{
v = sim->GetParticleType(value.ToUtf8());
v = sd.GetParticleType(value.ToUtf8());
if (v == -1)
{
for (auto *elementTool : tool->gameModel.GetMenuList()[SC_LIFE]->GetToolList())
@ -182,7 +184,7 @@ void PropertyWindow::CheckProperty()
}
}
if (properties[property->GetOption().second].Name == "type" && (v < 0 || v >= PT_NUM || !sim->elements[v].Enabled))
if (properties[property->GetOption().second].Name == "type" && (v < 0 || v >= PT_NUM || !elements[v].Enabled))
{
return;
}

View File

@ -4,6 +4,7 @@
#include "client/Client.h"
#include "client/SaveInfo.h"
#include "client/GameSave.h"
#include "client/http/AddCommentRequest.h"
#include "client/http/ReportSaveRequest.h"
@ -570,7 +571,8 @@ void PreviewView::NotifySaveChanged(PreviewModel * sender)
if(save->GetGameSave())
{
std::tie(savePreview, missingElements) = SaveRenderer::Ref().Render(save->GetGameSave(), false, true);
missingElements = save->GetGameSave()->missingElements;
savePreview = SaveRenderer::Ref().Render(save->GetGameSave(), false, true);
if (savePreview)
savePreview->ResizeToFit(RES / 2, true);
missingElementsButton->Visible = missingElements.identifiers.size() || missingElements.ids.size();

View File

@ -1,6 +1,7 @@
#include "RenderView.h"
#include "simulation/ElementGraphics.h"
#include "simulation/SimulationData.h"
#include "graphics/Graphics.h"
#include "graphics/Renderer.h"
@ -158,6 +159,9 @@ void RenderView::OnDraw()
g->DrawFilledRect(WINDOW.OriginRect(), 0x000000_rgb);
if(ren)
{
// we're the main thread, we may write graphicscache
auto &sd = SimulationData::Ref();
std::unique_lock lk(sd.elementGraphicsMx);
ren->clearScreen();
ren->RenderBegin();
ren->RenderEnd();

View File

@ -26,12 +26,15 @@ void initLegacyProps()
std::vector<StructProperty> properties = Element::GetProperties();
for (auto prop : properties)
{
// TODO: move aliases to the property table in Element.cpp?
if (prop.Name == "MenuVisible")
legacyPropNames.insert(std::pair<ByteString, StructProperty>("menu", prop));
else if (prop.Name == "PhotonReflectWavelengths")
continue;
else if (prop.Name == "CarriesTypeIn")
continue;
else if (prop.Name == "LatentHeat")
continue;
else if (prop.Name == "Temperature")
legacyPropNames.insert(std::pair<ByteString, StructProperty>("heat", prop));
else if (prop.Name == "HeatConduct")
@ -152,6 +155,8 @@ int luacon_partswrite(lua_State* l)
int luacon_transitionread(lua_State* l)
{
auto &sd = SimulationData::CRef();
auto &elements = sd.elements;
ByteString key = tpt_lua_optByteString(l, 2, "");
if (legacyTransitionNames.find(key) == legacyTransitionNames.end())
return luaL_error(l, "Invalid property");
@ -162,12 +167,12 @@ int luacon_transitionread(lua_State* l)
lua_rawget(l, 1);
int i = lua_tointeger (l, lua_gettop(l));
lua_pop(l, 1);
if (!luacon_sim->IsElement(i))
if (!sd.IsElement(i))
{
return luaL_error(l, "Invalid index");
}
intptr_t propertyAddress = (intptr_t)(((unsigned char*)&luacon_sim->elements[i]) + prop.Offset);
intptr_t propertyAddress = (intptr_t)(((const unsigned char*)&elements[i]) + prop.Offset);
LuaScriptInterface::LuaGetProperty(l, prop, propertyAddress);
return 1;
@ -175,6 +180,8 @@ int luacon_transitionread(lua_State* l)
int luacon_transitionwrite(lua_State* l)
{
auto &sd = SimulationData::Ref();
auto &elements = sd.elements;
ByteString key = tpt_lua_optByteString(l, 2, "");
if (legacyTransitionNames.find(key) == legacyTransitionNames.end())
return luaL_error(l, "Invalid property");
@ -185,7 +192,7 @@ int luacon_transitionwrite(lua_State* l)
lua_rawget(l, 1);
int i = lua_tointeger (l, lua_gettop(l));
lua_pop(l, 1);
if (!luacon_sim->IsElement(i))
if (!sd.IsElement(i))
{
return luaL_error(l, "Invalid index");
}
@ -193,13 +200,13 @@ int luacon_transitionwrite(lua_State* l)
if (prop.Type == StructProperty::TransitionType)
{
int type = luaL_checkinteger(l, 3);
if (!luacon_sim->IsElementOrNone(type) && type != NT && type != ST)
if (!sd.IsElementOrNone(type) && type != NT && type != ST)
{
return luaL_error(l, "Invalid element");
}
}
intptr_t propertyAddress = (intptr_t)(((unsigned char*)&luacon_sim->elements[i]) + prop.Offset);
intptr_t propertyAddress = (intptr_t)(((unsigned char*)&elements[i]) + prop.Offset);
LuaScriptInterface::LuaSetProperty(l, prop, propertyAddress, 3);
return 0;
@ -207,6 +214,8 @@ int luacon_transitionwrite(lua_State* l)
int luacon_elementread(lua_State* l)
{
auto &sd = SimulationData::CRef();
auto &elements = sd.elements;
ByteString key = tpt_lua_optByteString(l, 2, "");
if (legacyPropNames.find(key) == legacyPropNames.end())
return luaL_error(l, "Invalid property");
@ -217,12 +226,12 @@ int luacon_elementread(lua_State* l)
lua_rawget(l, 1);
int i = lua_tointeger (l, lua_gettop(l));
lua_pop(l, 1);
if (!luacon_sim->IsElement(i))
if (!sd.IsElement(i))
{
return luaL_error(l, "Invalid index");
}
intptr_t propertyAddress = (intptr_t)(((unsigned char*)&luacon_sim->elements[i]) + prop.Offset);
intptr_t propertyAddress = (intptr_t)(((const unsigned char*)&elements[i]) + prop.Offset);
LuaScriptInterface::LuaGetProperty(l, prop, propertyAddress);
return 1;
@ -230,6 +239,9 @@ int luacon_elementread(lua_State* l)
int luacon_elementwrite(lua_State* l)
{
auto &sd = SimulationData::Ref();
std::unique_lock lk(sd.elementGraphicsMx);
auto &elements = sd.elements;
ByteString key = tpt_lua_optByteString(l, 2, "");
if (legacyPropNames.find(key) == legacyPropNames.end())
return luaL_error(l, "Invalid property");
@ -240,18 +252,18 @@ int luacon_elementwrite(lua_State* l)
lua_rawget(l, 1);
int i = lua_tointeger (l, lua_gettop(l));
lua_pop(l, 1);
if (!luacon_sim->IsElement(i))
if (!sd.IsElement(i))
{
return luaL_error(l, "Invalid index");
}
intptr_t propertyAddress = (intptr_t)(((unsigned char*)&luacon_sim->elements[i]) + prop.Offset);
intptr_t propertyAddress = (intptr_t)(((unsigned char*)&elements[i]) + prop.Offset);
LuaScriptInterface::LuaSetProperty(l, prop, propertyAddress, 3);
luacon_model->BuildMenus();
auto *luacon_ci = static_cast<LuaScriptInterface *>(commandInterface);
luacon_ci->custom_init_can_move();
std::fill(&luacon_ren->graphicscache[0], &luacon_ren->graphicscache[0] + PT_NUM, gcache_item());
sd.graphicscache = std::array<gcache_item, PT_NUM>();
return 0;
}
@ -278,21 +290,23 @@ String luacon_geterror()
//tpt. api methods
int luatpt_getelement(lua_State *l)
{
auto &sd = SimulationData::CRef();
auto &elements = sd.elements;
int t;
if (lua_isnumber(l, 1))
{
t = luaL_optint(l, 1, 1);
if (!luacon_sim->IsElementOrNone(t))
if (!sd.IsElementOrNone(t))
{
return luaL_error(l, "Unrecognised element number '%d'", t);
}
tpt_lua_pushString(l, luacon_sim->elements[t].Name);
tpt_lua_pushString(l, elements[t].Name);
}
else
{
luaL_checktype(l, 1, LUA_TSTRING);
auto name = tpt_lua_optByteString(l, 1, "");
if ((t = luacon_sim->GetParticleType(name))==-1)
if ((t = sd.GetParticleType(name))==-1)
return luaL_error(l, "Unrecognised element '%s'", name.c_str());
lua_pushinteger(l, t);
}
@ -326,6 +340,7 @@ int luatpt_drawtext(lua_State* l)
int luatpt_create(lua_State* l)
{
auto &sd = SimulationData::CRef();
int x, y, retid, t = -1;
x = abs(luaL_optint(l, 1, 0));
y = abs(luaL_optint(l, 2, 0));
@ -334,13 +349,13 @@ int luatpt_create(lua_State* l)
if (lua_isnumber(l, 3))
{
t = luaL_optint(l, 3, 0);
if (!luacon_sim->IsElement(t))
if (!sd.IsElement(t))
{
return luaL_error(l, "Unrecognised element number '%d'", t);
}
} else {
auto name = tpt_lua_optByteString(l, 3, "dust");
if ((t = luacon_sim->GetParticleType(name)) == -1)
if ((t = sd.GetParticleType(name)) == -1)
return luaL_error(l,"Unrecognised element '%s'", name.c_str());
}
retid = luacon_sim->create_part(-1, x, y, t);
@ -547,6 +562,7 @@ int luatpt_reset_spark(lua_State* l)
int luatpt_set_property(lua_State* l)
{
auto &sd = SimulationData::CRef();
auto *luacon_ci = static_cast<LuaScriptInterface *>(commandInterface);
int r, i, x, y, w, h, t = 0, nx, ny, partsel = 0;
float f = 0;
@ -565,7 +581,7 @@ int luatpt_set_property(lua_State* l)
if(!lua_isnumber(l, acount) && lua_isstring(l, acount))
{
auto name = tpt_lua_optByteString(l, acount, "none");
if ((partsel = luacon_sim->GetParticleType(name)) == -1)
if ((partsel = sd.GetParticleType(name)) == -1)
return luaL_error(l, "Unrecognised element '%s'", name.c_str());
}
}
@ -576,13 +592,13 @@ int luatpt_set_property(lua_State* l)
else
t = luaL_optint(l, 2, 0);
if (byteStringEqualsLiteral(prop, "type") && !luacon_sim->IsElementOrNone(t))
if (byteStringEqualsLiteral(prop, "type") && !sd.IsElementOrNone(t))
return luaL_error(l, "Unrecognised element number '%d'", t);
}
else if (lua_isstring(l, 2))
{
auto name = tpt_lua_checkByteString(l, 2);
if ((t = luacon_sim->GetParticleType(name))==-1)
if ((t = sd.GetParticleType(name))==-1)
return luaL_error(l, "Unrecognised element '%s'", name.c_str());
}
else
@ -1141,12 +1157,15 @@ int luatpt_menu_enabled(lua_State* l)
int acount = lua_gettop(l);
if (acount == 1)
{
lua_pushboolean(l, luacon_sim->msections[menusection].doshow);
lua_pushboolean(l, SimulationData::CRef().msections[menusection].doshow);
return 1;
}
luaL_checktype(l, 2, LUA_TBOOLEAN);
int enabled = lua_toboolean(l, 2);
luacon_sim->msections[menusection].doshow = enabled;
{
auto &sd = SimulationData::Ref();
sd.msections[menusection].doshow = enabled;
}
luacon_model->BuildMenus();
return 0;
}

View File

@ -451,11 +451,13 @@ LuaScriptInterface::LuaScriptInterface(GameController * c, GameModel * m):
tptPart->Assign(l, -1);
lua_pop(l, 1);
auto &sd = SimulationData::CRef();
auto &elements = sd.elements;
lua_newtable(l);
tptElements = lua_gettop(l);
for (int i = 1; i < PT_NUM; i++)
{
tpt_lua_pushString(l, luacon_sim->elements[i].Name.ToLower());
tpt_lua_pushString(l, elements[i].Name.ToLower());
lua_newtable(l);
currentElement = lua_gettop(l);
lua_pushinteger(l, i);
@ -475,7 +477,7 @@ LuaScriptInterface::LuaScriptInterface(GameController * c, GameModel * m):
tptElementTransitions = lua_gettop(l);
for (int i = 1; i < PT_NUM; i++)
{
tpt_lua_pushString(l, luacon_sim->elements[i].Name.ToLower());
tpt_lua_pushString(l, elements[i].Name.ToLower());
lua_newtable(l);
currentElement = lua_gettop(l);
lua_newtable(l);
@ -536,14 +538,15 @@ LuaScriptInterface::LuaScriptInterface(GameController * c, GameModel * m):
void LuaScriptInterface::custom_init_can_move()
{
luacon_sim->init_can_move();
auto &sd = SimulationData::Ref();
sd.init_can_move();
for (auto moving = 0; moving < PT_NUM; ++moving)
{
for (auto into = 0; into < PT_NUM; ++into)
{
if (custom_can_move[moving][into] & 0x80)
{
luacon_sim->can_move[moving][into] = custom_can_move[moving][into] & 0x7F;
sd.can_move[moving][into] = custom_can_move[moving][into] & 0x7F;
}
}
}
@ -1112,6 +1115,8 @@ int simulation_deletesign(lua_State *l)
void LuaScriptInterface::initSimulationAPI()
{
auto &sd = SimulationData::CRef();
//Methods
struct luaL_Reg simulationAPIMethods [] = {
{"partNeighbours", simulation_partNeighbours},
@ -1227,7 +1232,7 @@ void LuaScriptInterface::initSimulationAPI()
SETCONST(l, TOOL_NGRV);
SETCONST(l, TOOL_MIX);
SETCONST(l, TOOL_CYCL);
lua_pushinteger(l, luacon_sim->tools.size()); lua_setfield(l, -2, "TOOL_WIND");
lua_pushinteger(l, sd.tools.size()); lua_setfield(l, -2, "TOOL_WIND");
SETCONST(l, DECO_DRAW);
SETCONST(l, DECO_CLEAR);
@ -1266,12 +1271,12 @@ void LuaScriptInterface::initSimulationAPI()
lua_newtable(l);
for (int i = 0; i < UI_WALLCOUNT; i++)
{
tpt_lua_pushByteString(l, luacon_sim->wtypes[i].identifier);
tpt_lua_pushByteString(l, sd.wtypes[i].identifier);
lua_pushinteger(l, i);
lua_settable(l, -3);
lua_pushinteger(l, i);
tpt_lua_pushByteString(l, luacon_sim->wtypes[i].identifier);
tpt_lua_pushByteString(l, sd.wtypes[i].identifier);
lua_settable(l, -3);
}
lua_setfield(l, -2, "walls");
@ -1898,6 +1903,7 @@ int LuaScriptInterface::simulation_floodWalls(lua_State * l)
int LuaScriptInterface::simulation_toolBrush(lua_State * l)
{
auto &sd = SimulationData::CRef();
int x = luaL_optint(l,1,-1);
int y = luaL_optint(l,2,-1);
int rx = luaL_optint(l,3,5);
@ -1905,12 +1911,12 @@ int LuaScriptInterface::simulation_toolBrush(lua_State * l)
int tool = luaL_optint(l,5,0);
int brushID = luaL_optint(l,6,CIRCLE_BRUSH);
float strength = luaL_optnumber(l,7,1.0f);
if (tool == (int)luacon_sim->tools.size())
if (tool == (int)sd.tools.size())
{
lua_pushinteger(l, 0);
return 1;
}
else if (tool < 0 || tool > (int)luacon_sim->tools.size())
else if (tool < 0 || tool > (int)sd.tools.size())
return luaL_error(l, "Invalid tool id '%d'", tool);
Brush *brush = luacon_model->GetBrushByID(brushID);
@ -1926,6 +1932,7 @@ int LuaScriptInterface::simulation_toolBrush(lua_State * l)
int LuaScriptInterface::simulation_toolLine(lua_State * l)
{
auto &sd = SimulationData::CRef();
int x1 = luaL_optint(l,1,-1);
int y1 = luaL_optint(l,2,-1);
int x2 = luaL_optint(l,3,-1);
@ -1938,7 +1945,7 @@ int LuaScriptInterface::simulation_toolLine(lua_State * l)
if (x1 < 0 || x2 < 0 || x1 >= XRES || x2 >= XRES || y1 < 0 || y2 < 0 || y1 >= YRES || y2 >= YRES)
return luaL_error(l, "coordinates out of range (%d,%d),(%d,%d)", x1, y1, x2, y2);
if (tool < 0 || tool >= (int)luacon_sim->tools.size()+1)
if (tool < 0 || tool >= (int)sd.tools.size()+1)
return luaL_error(l, "Invalid tool id '%d'", tool);
Brush *brush = luacon_model->GetBrushByID(brushID);
@ -1947,7 +1954,7 @@ int LuaScriptInterface::simulation_toolLine(lua_State * l)
auto newBrush = brush->Clone();
newBrush->SetRadius(ui::Point(rx, ry));
if (tool == (int)luacon_sim->tools.size())
if (tool == (int)sd.tools.size())
{
Tool *windTool = luacon_model->GetToolFromIdentifier("DEFAULT_UI_WIND");
float oldStrength = windTool->Strength;
@ -1962,6 +1969,7 @@ int LuaScriptInterface::simulation_toolLine(lua_State * l)
int LuaScriptInterface::simulation_toolBox(lua_State * l)
{
auto &sd = SimulationData::CRef();
int x1 = luaL_optint(l,1,-1);
int y1 = luaL_optint(l,2,-1);
int x2 = luaL_optint(l,3,-1);
@ -1970,12 +1978,12 @@ int LuaScriptInterface::simulation_toolBox(lua_State * l)
return luaL_error(l, "coordinates out of range (%d,%d),(%d,%d)", x1, y1, x2, y2);
int tool = luaL_optint(l,5,0);
float strength = luaL_optnumber(l,6,1.0f);
if (tool == (int)luacon_sim->tools.size())
if (tool == (int)sd.tools.size())
{
lua_pushinteger(l, 0);
return 1;
}
else if (tool < 0 || tool >= (int)luacon_sim->tools.size())
else if (tool < 0 || tool >= (int)sd.tools.size())
return luaL_error(l, "Invalid tool id '%d'", tool);
luacon_sim->ToolBox(x1, y1, x2, y2, tool, strength);
@ -2110,12 +2118,14 @@ int LuaScriptInterface::simulation_clearRect(lua_State * l)
int LuaScriptInterface::simulation_resetTemp(lua_State * l)
{
auto &sd = SimulationData::CRef();
auto &elements = sd.elements;
bool onlyConductors = luaL_optint(l, 1, 0);
for (int i = 0; i < luacon_sim->parts_lastActiveIndex; i++)
{
if (luacon_sim->parts[i].type && (luacon_sim->elements[luacon_sim->parts[i].type].HeatConduct || !onlyConductors))
if (luacon_sim->parts[i].type && (elements[luacon_sim->parts[i].type].HeatConduct || !onlyConductors))
{
luacon_sim->parts[i].temp = luacon_sim->elements[luacon_sim->parts[i].type].DefaultProperties.temp;
luacon_sim->parts[i].temp = elements[luacon_sim->parts[i].type].DefaultProperties.temp;
}
}
return 0;
@ -2427,14 +2437,16 @@ int LuaScriptInterface::simulation_canMove(lua_State * l)
if (lua_gettop(l) < 3)
{
lua_pushnumber(l, luacon_sim->can_move[movingElement][destinationElement]);
auto &sd = SimulationData::CRef();
lua_pushnumber(l, sd.can_move[movingElement][destinationElement]);
return 1;
}
else
{
int setting = luaL_checkint(l, 3) & 0x7F;
luacon_ci->custom_can_move[movingElement][destinationElement] = setting | 0x80;
luacon_sim->can_move[movingElement][destinationElement] = setting;
auto &sd = SimulationData::Ref();
sd.can_move[movingElement][destinationElement] = setting;
return 0;
}
}
@ -2684,9 +2696,10 @@ int LuaScriptInterface::simulation_replaceModeFlags(lua_State *l)
int LuaScriptInterface::simulation_listCustomGol(lua_State *l)
{
auto &sd = SimulationData::CRef();
int i = 0;
lua_newtable(l);
for (auto &cgol : luacon_sim->GetCustomGol())
for (auto &cgol : sd.GetCustomGol())
{
lua_newtable(l);
tpt_lua_pushString(l, cgol.nameString);
@ -2706,6 +2719,7 @@ int LuaScriptInterface::simulation_listCustomGol(lua_State *l)
int LuaScriptInterface::simulation_addCustomGol(lua_State *l)
{
auto &sd = SimulationData::CRef();
int rule;
String ruleString;
if (lua_isnumber(l, 1))
@ -2727,7 +2741,7 @@ int LuaScriptInterface::simulation_addCustomGol(lua_State *l)
return luaL_error(l, "Invalid name provided");
if (rule == -1)
return luaL_error(l, "Invalid rule provided");
if (luacon_sim->GetCustomGOLByRule(rule))
if (sd.GetCustomGOLByRule(rule))
return luaL_error(l, "This Custom GoL rule already exists");
if (!AddCustomGol(ruleString, nameString, color1, color2))
@ -3145,15 +3159,17 @@ void LuaScriptInterface::initElementsAPI()
SETCONST(l, SC_DECO);
//Element identifiers
auto &sd = SimulationData::CRef();
auto &elements = sd.elements;
for(int i = 0; i < PT_NUM; i++)
{
if(luacon_sim->elements[i].Enabled)
if(elements[i].Enabled)
{
tpt_lua_pushByteString(l, luacon_sim->elements[i].Identifier);
tpt_lua_pushByteString(l, elements[i].Identifier);
lua_pushinteger(l, i);
lua_settable(l, -3);
ByteString realIdentifier = ByteString::Build("DEFAULT_PT_", luacon_sim->elements[i].Name.ToUtf8());
if (i != 0 && i != PT_NBHL && i != PT_NWHL && luacon_sim->elements[i].Identifier != realIdentifier)
ByteString realIdentifier = ByteString::Build("DEFAULT_PT_", elements[i].Name.ToUtf8());
if (i != 0 && i != PT_NBHL && i != PT_NWHL && elements[i].Identifier != realIdentifier)
{
tpt_lua_pushByteString(l, realIdentifier);
lua_pushinteger(l, i);
@ -3270,52 +3286,58 @@ void LuaScriptInterface::LuaSetParticleProperty(lua_State* l, int particleID, St
int LuaScriptInterface::elements_loadDefault(lua_State * l)
{
auto &sd = SimulationData::Ref();
std::unique_lock lk(sd.elementGraphicsMx);
auto &elements = sd.elements;
auto &builtinElements = GetElements();
auto *luacon_ci = static_cast<LuaScriptInterface *>(commandInterface);
int args = lua_gettop(l);
if (args)
{
luaL_checktype(l, 1, LUA_TNUMBER);
int id = lua_tointeger(l, 1);
if (id < 0 || id >= PT_NUM)
return luaL_error(l, "Invalid element");
lua_getglobal(l, "elements");
tpt_lua_pushByteString(l, luacon_sim->elements[id].Identifier);
lua_pushnil(l);
lua_settable(l, -3);
auto const &elementList = GetElements();
if (id < (int)elementList.size())
luacon_sim->elements[id] = elementList[id];
else
luacon_sim->elements[id] = Element();
tpt_lua_pushByteString(l, luacon_sim->elements[id].Identifier);
lua_pushinteger(l, id);
lua_settable(l, -3);
lua_pop(l, 1);
}
else
{
auto const &elementList = GetElements();
for (int i = 0; i < PT_NUM; i++)
int args = lua_gettop(l);
if (args)
{
if (i < (int)elementList.size())
luacon_sim->elements[i] = elementList[i];
luaL_checktype(l, 1, LUA_TNUMBER);
int id = lua_tointeger(l, 1);
if (id < 0 || id >= PT_NUM)
return luaL_error(l, "Invalid element");
lua_getglobal(l, "elements");
ByteString identifier = SimulationData::CRef().elements[id].Identifier;
tpt_lua_pushByteString(l, identifier);
lua_pushnil(l);
lua_settable(l, -3);
if (id < (int)builtinElements.size())
elements[id] = builtinElements[id];
else
luacon_sim->elements[i] = Element();
elements[id] = Element();
tpt_lua_pushByteString(l, identifier);
lua_pushinteger(l, id);
lua_settable(l, -3);
lua_pop(l, 1);
}
lua_pushnil(l);
lua_setglobal(l, "elements");
lua_pushnil(l);
lua_setglobal(l, "elem");
else
{
for (int i = 0; i < PT_NUM; i++)
{
if (i < (int)builtinElements.size())
elements[i] = builtinElements[i];
else
elements[i] = Element();
}
lua_getglobal(l, "package");
lua_getfield(l, -1, "loaded");
lua_pushnil(l);
lua_setfield(l, -2, "elements");
lua_pushnil(l);
lua_setglobal(l, "elements");
lua_pushnil(l);
lua_setglobal(l, "elem");
luacon_ci->initElementsAPI();
lua_getglobal(l, "package");
lua_getfield(l, -1, "loaded");
lua_pushnil(l);
lua_setfield(l, -2, "elements");
luacon_ci->initElementsAPI();
}
}
luacon_model->BuildMenus();
@ -3327,8 +3349,7 @@ int LuaScriptInterface::elements_loadDefault(lua_State * l)
}
}
luacon_ci->custom_init_can_move();
std::fill(luacon_ren->graphicscache, luacon_ren->graphicscache+PT_NUM, gcache_item());
SaveRenderer::Ref().Flush(0, PT_NUM);
sd.graphicscache = std::array<gcache_item, PT_NUM>();
return 0;
}
@ -3355,40 +3376,49 @@ int LuaScriptInterface::elements_allocate(lua_State * l)
auto identifier = group + "_PT_" + id;
for(int i = 0; i < PT_NUM; i++)
{
if(luacon_sim->elements[i].Enabled && ByteString(luacon_sim->elements[i].Identifier) == identifier)
return luaL_error(l, "Element identifier already in use");
}
int newID = -1;
// Start out at 255 so that lua element IDs are still one byte (better save compatibility)
for (int i = PT_NUM >= 255 ? 255 : PT_NUM; i >= 0; i--)
{
if (!luacon_sim->elements[i].Enabled)
auto &sd = SimulationData::CRef();
auto &elements = sd.elements;
for(int i = 0; i < PT_NUM; i++)
{
newID = i;
break;
if(elements[i].Enabled && ByteString(elements[i].Identifier) == identifier)
return luaL_error(l, "Element identifier already in use");
}
}
// If not enough space, then we start with the new maimum ID
if (newID == -1)
{
for (int i = PT_NUM-1; i >= 255; i--)
// Start out at 255 so that lua element IDs are still one byte (better save compatibility)
for (int i = PT_NUM >= 255 ? 255 : PT_NUM; i >= 0; i--)
{
if (!luacon_sim->elements[i].Enabled)
if (!elements[i].Enabled)
{
newID = i;
break;
}
}
// If not enough space, then we start with the new maimum ID
if (newID == -1)
{
for (int i = PT_NUM-1; i >= 255; i--)
{
if (!elements[i].Enabled)
{
newID = i;
break;
}
}
}
}
if (newID != -1)
{
luacon_sim->elements[newID] = Element();
luacon_sim->elements[newID].Enabled = true;
luacon_sim->elements[newID].Identifier = identifier;
{
auto &sd = SimulationData::Ref();
std::unique_lock lk(sd.elementGraphicsMx);
auto &elements = sd.elements;
elements[newID] = Element();
elements[newID].Enabled = true;
elements[newID].Identifier = identifier;
}
lua_getglobal(l, "elements");
tpt_lua_pushByteString(l, identifier);
@ -3411,8 +3441,13 @@ int LuaScriptInterface::elements_allocate(lua_State * l)
static int luaUpdateWrapper(UPDATE_FUNC_ARGS)
{
if (!sim->useLuaCallbacks)
{
return 0;
}
auto *luacon_ci = static_cast<LuaScriptInterface *>(commandInterface);
auto *builtinUpdate = GetElements()[parts[i].type].Update;
auto &builtinElements = GetElements();
auto *builtinUpdate = builtinElements[parts[i].type].Update;
if (builtinUpdate && lua_el_mode[parts[i].type] == 1)
{
if (builtinUpdate(UPDATE_FUNC_SUBCALL_ARGS))
@ -3455,11 +3490,21 @@ static int luaUpdateWrapper(UPDATE_FUNC_ARGS)
static int luaGraphicsWrapper(GRAPHICS_FUNC_ARGS)
{
if (!gfctx.sim->useLuaCallbacks)
{
return Element::defaultGraphics(GRAPHICS_FUNC_SUBCALL_ARGS);
}
auto *luacon_ci = static_cast<LuaScriptInterface *>(commandInterface);
if (lua_gr_func[cpart->type])
{
auto *pipeSubcallWcpart = gfctx.pipeSubcallCpart ? luacon_sim->parts + (gfctx.pipeSubcallCpart - gfctx.sim->parts) : nullptr;
if (pipeSubcallWcpart)
{
std::swap(*pipeSubcallWcpart, *gfctx.pipeSubcallTpart);
cpart = pipeSubcallWcpart;
}
int cache = 0, callret;
int i = cpart - ren->sim->parts; // pointer arithmetic be like
int i = cpart - gfctx.sim->parts; // pointer arithmetic be like
lua_rawgeti(luacon_ci->l, LUA_REGISTRYINDEX, lua_gr_func[cpart->type]);
lua_pushinteger(luacon_ci->l, i);
lua_pushinteger(luacon_ci->l, *colr);
@ -3495,6 +3540,10 @@ static int luaGraphicsWrapper(GRAPHICS_FUNC_ARGS)
}
lua_pop(luacon_ci->l, 10);
}
if (pipeSubcallWcpart)
{
std::swap(*pipeSubcallWcpart, *gfctx.pipeSubcallTpart);
}
return cache;
}
return 0;
@ -3502,6 +3551,10 @@ static int luaGraphicsWrapper(GRAPHICS_FUNC_ARGS)
static void luaCreateWrapper(ELEMENT_CREATE_FUNC_ARGS)
{
if (!sim->useLuaCallbacks)
{
return;
}
auto *luacon_ci = static_cast<LuaScriptInterface *>(commandInterface);
if (luaCreateHandlers[sim->parts[i].type])
{
@ -3521,6 +3574,13 @@ static void luaCreateWrapper(ELEMENT_CREATE_FUNC_ARGS)
static bool luaCreateAllowedWrapper(ELEMENT_CREATE_ALLOWED_FUNC_ARGS)
{
if (!sim->useLuaCallbacks)
{
// Nothing really bad can happen, no callbacks are allowed anyway. The worst thing that can happen
// is that a well-crafted save looks odd in previews because it has multiple Element::defaultGraphics-rendered
// instances of something that should be limited to one instance.
return 1;
}
auto *luacon_ci = static_cast<LuaScriptInterface *>(commandInterface);
bool ret = false;
if (luaCreateAllowedHandlers[t])
@ -3547,6 +3607,10 @@ static bool luaCreateAllowedWrapper(ELEMENT_CREATE_ALLOWED_FUNC_ARGS)
static void luaChangeTypeWrapper(ELEMENT_CHANGETYPE_FUNC_ARGS)
{
if (!sim->useLuaCallbacks)
{
return;
}
auto *luacon_ci = static_cast<LuaScriptInterface *>(commandInterface);
if (luaChangeTypeHandlers[sim->parts[i].type])
{
@ -3566,6 +3630,10 @@ static void luaChangeTypeWrapper(ELEMENT_CHANGETYPE_FUNC_ARGS)
static bool luaCtypeDrawWrapper(CTYPEDRAW_FUNC_ARGS)
{
if (!sim->useLuaCallbacks)
{
return false;
}
auto *luacon_ci = static_cast<LuaScriptInterface *>(commandInterface);
bool ret = false;
if (luaCtypeDrawHandlers[sim->parts[i].type])
@ -3591,133 +3659,140 @@ static bool luaCtypeDrawWrapper(CTYPEDRAW_FUNC_ARGS)
int LuaScriptInterface::elements_element(lua_State * l)
{
auto &builtinElements = GetElements();
auto *luacon_ci = static_cast<LuaScriptInterface *>(commandInterface);
int id = luaL_checkinteger(l, 1);
if (!luacon_sim->IsElementOrNone(id))
if (!SimulationData::CRef().IsElementOrNone(id))
{
return luaL_error(l, "Invalid element");
}
if (lua_gettop(l) > 1)
{
luaL_checktype(l, 2, LUA_TTABLE);
//Write values from native data to a table
for (auto &prop : Element::GetProperties())
{
tpt_lua_pushByteString(l, prop.Name);
lua_gettable(l, -2);
if (lua_type(l, -1) != LUA_TNIL)
auto &sd = SimulationData::Ref();
std::unique_lock lk(sd.elementGraphicsMx);
auto &elements = sd.elements;
luaL_checktype(l, 2, LUA_TTABLE);
//Write values from native data to a table
for (auto &prop : Element::GetProperties())
{
intptr_t propertyAddress = (intptr_t)(((unsigned char*)&luacon_sim->elements[id]) + prop.Offset);
LuaSetProperty(l, prop, propertyAddress, -1);
tpt_lua_pushByteString(l, prop.Name);
lua_gettable(l, -2);
if (lua_type(l, -1) != LUA_TNIL)
{
intptr_t propertyAddress = (intptr_t)(((unsigned char*)&elements[id]) + prop.Offset);
LuaSetProperty(l, prop, propertyAddress, -1);
}
lua_pop(l, 1);
}
lua_getfield(l, -1, "Update");
if (lua_type(l, -1) == LUA_TFUNCTION)
{
lua_el_func[id].Assign(l, -1);
lua_el_mode[id] = 1;
elements[id].Update = luaUpdateWrapper;
}
else if (lua_type(l, -1) == LUA_TBOOLEAN && !lua_toboolean(l, -1))
{
lua_el_func[id].Clear();
lua_el_mode[id] = 0;
elements[id].Update = builtinElements[id].Update;
}
lua_pop(l, 1);
}
lua_getfield(l, -1, "Update");
if (lua_type(l, -1) == LUA_TFUNCTION)
{
lua_el_func[id].Assign(l, -1);
lua_el_mode[id] = 1;
luacon_sim->elements[id].Update = luaUpdateWrapper;
}
else if (lua_type(l, -1) == LUA_TBOOLEAN && !lua_toboolean(l, -1))
{
lua_el_func[id].Clear();
lua_el_mode[id] = 0;
luacon_sim->elements[id].Update = GetElements()[id].Update;
}
lua_pop(l, 1);
lua_getfield(l, -1, "Graphics");
if (lua_type(l, -1) == LUA_TFUNCTION)
{
lua_gr_func[id].Assign(l, -1);
elements[id].Graphics = luaGraphicsWrapper;
}
else if (lua_type(l, -1) == LUA_TBOOLEAN && !lua_toboolean(l, -1))
{
lua_gr_func[id].Clear();
elements[id].Graphics = builtinElements[id].Graphics;
}
lua_pop(l, 1);
lua_getfield(l, -1, "Graphics");
if (lua_type(l, -1) == LUA_TFUNCTION)
{
lua_gr_func[id].Assign(l, -1);
luacon_sim->elements[id].Graphics = luaGraphicsWrapper;
}
else if (lua_type(l, -1) == LUA_TBOOLEAN && !lua_toboolean(l, -1))
{
lua_gr_func[id].Clear();
luacon_sim->elements[id].Graphics = GetElements()[id].Graphics;
}
lua_pop(l, 1);
lua_getfield(l, -1, "Create");
if (lua_type(l, -1) == LUA_TFUNCTION)
{
luaCreateHandlers[id].Assign(l, -1);
elements[id].Create = luaCreateWrapper;
}
else if (lua_type(l, -1) == LUA_TBOOLEAN && !lua_toboolean(l, -1))
{
luaCreateHandlers[id].Clear();
elements[id].Create = builtinElements[id].Create;
}
lua_pop(l, 1);
lua_getfield(l, -1, "Create");
if (lua_type(l, -1) == LUA_TFUNCTION)
{
luaCreateHandlers[id].Assign(l, -1);
luacon_sim->elements[id].Create = luaCreateWrapper;
}
else if (lua_type(l, -1) == LUA_TBOOLEAN && !lua_toboolean(l, -1))
{
luaCreateHandlers[id].Clear();
luacon_sim->elements[id].Create = GetElements()[id].Create;
}
lua_pop(l, 1);
lua_getfield(l, -1, "CreateAllowed");
if (lua_type(l, -1) == LUA_TFUNCTION)
{
luaCreateAllowedHandlers[id].Assign(l, -1);
elements[id].CreateAllowed = luaCreateAllowedWrapper;
}
else if (lua_type(l, -1) == LUA_TBOOLEAN && !lua_toboolean(l, -1))
{
luaCreateAllowedHandlers[id].Clear();
elements[id].CreateAllowed = builtinElements[id].CreateAllowed;
}
lua_pop(l, 1);
lua_getfield(l, -1, "CreateAllowed");
if (lua_type(l, -1) == LUA_TFUNCTION)
{
luaCreateAllowedHandlers[id].Assign(l, -1);
luacon_sim->elements[id].CreateAllowed = luaCreateAllowedWrapper;
}
else if (lua_type(l, -1) == LUA_TBOOLEAN && !lua_toboolean(l, -1))
{
luaCreateAllowedHandlers[id].Clear();
luacon_sim->elements[id].CreateAllowed = GetElements()[id].CreateAllowed;
}
lua_pop(l, 1);
lua_getfield(l, -1, "ChangeType");
if (lua_type(l, -1) == LUA_TFUNCTION)
{
luaChangeTypeHandlers[id].Assign(l, -1);
elements[id].ChangeType = luaChangeTypeWrapper;
}
else if (lua_type(l, -1) == LUA_TBOOLEAN && !lua_toboolean(l, -1))
{
luaChangeTypeHandlers[id].Clear();
elements[id].ChangeType = builtinElements[id].ChangeType;
}
lua_pop(l, 1);
lua_getfield(l, -1, "ChangeType");
if (lua_type(l, -1) == LUA_TFUNCTION)
{
luaChangeTypeHandlers[id].Assign(l, -1);
luacon_sim->elements[id].ChangeType = luaChangeTypeWrapper;
}
else if (lua_type(l, -1) == LUA_TBOOLEAN && !lua_toboolean(l, -1))
{
luaChangeTypeHandlers[id].Clear();
luacon_sim->elements[id].ChangeType = GetElements()[id].ChangeType;
}
lua_pop(l, 1);
lua_getfield(l, -1, "CtypeDraw");
if (lua_type(l, -1) == LUA_TFUNCTION)
{
luaCtypeDrawHandlers[id].Assign(l, -1);
elements[id].CtypeDraw = luaCtypeDrawWrapper;
}
else if (lua_type(l, -1) == LUA_TBOOLEAN && !lua_toboolean(l, -1))
{
luaCtypeDrawHandlers[id].Clear();
elements[id].CtypeDraw = builtinElements[id].CtypeDraw;
}
lua_pop(l, 1);
lua_getfield(l, -1, "CtypeDraw");
if (lua_type(l, -1) == LUA_TFUNCTION)
{
luaCtypeDrawHandlers[id].Assign(l, -1);
luacon_sim->elements[id].CtypeDraw = luaCtypeDrawWrapper;
}
else if (lua_type(l, -1) == LUA_TBOOLEAN && !lua_toboolean(l, -1))
{
luaCtypeDrawHandlers[id].Clear();
luacon_sim->elements[id].CtypeDraw = GetElements()[id].CtypeDraw;
}
lua_pop(l, 1);
lua_getfield(l, -1, "DefaultProperties");
SetDefaultProperties(l, id, lua_gettop(l));
lua_pop(l, 1);
lua_getfield(l, -1, "DefaultProperties");
SetDefaultProperties(l, id, lua_gettop(l));
lua_pop(l, 1);
sd.graphicscache[id].isready = 0;
}
luacon_model->BuildMenus();
luacon_ci->custom_init_can_move();
luacon_ren->graphicscache[id].isready = 0;
SaveRenderer::Ref().Flush(id, id + 1);
return 0;
}
else
{
auto &sd = SimulationData::CRef();
auto &elements = sd.elements;
//Write values from native data to a table
lua_newtable(l);
for (auto &prop : Element::GetProperties())
{
tpt_lua_pushByteString(l, prop.Name);
intptr_t propertyAddress = (intptr_t)(((unsigned char*)&luacon_sim->elements[id]) + prop.Offset);
intptr_t propertyAddress = (intptr_t)(((unsigned char*)&elements[id]) + prop.Offset);
LuaGetProperty(l, prop, propertyAddress);
lua_settable(l, -3);
}
tpt_lua_pushByteString(l, luacon_sim->elements[id].Identifier);
tpt_lua_pushByteString(l, elements[id].Identifier);
lua_setfield(l, -2, "Identifier");
GetDefaultProperties(l, id);
@ -3729,10 +3804,12 @@ int LuaScriptInterface::elements_element(lua_State * l)
void LuaScriptInterface::GetDefaultProperties(lua_State * l, int id)
{
auto &sd = SimulationData::CRef();
auto &elements = sd.elements;
lua_newtable(l);
for (auto &prop : Particle::GetProperties())
{
auto propertyAddress = reinterpret_cast<intptr_t>((reinterpret_cast<unsigned char*>(&luacon_sim->elements[id].DefaultProperties)) + prop.Offset);
auto propertyAddress = reinterpret_cast<intptr_t>((reinterpret_cast<const unsigned char*>(&elements[id].DefaultProperties)) + prop.Offset);
tpt_lua_pushByteString(l, prop.Name);
LuaGetProperty(l, prop, propertyAddress);
lua_settable(l, -3);
@ -3748,6 +3825,8 @@ void LuaScriptInterface::GetDefaultProperties(lua_State * l, int id)
void LuaScriptInterface::SetDefaultProperties(lua_State * l, int id, int stackPos)
{
auto &sd = SimulationData::Ref();
auto &elements = sd.elements;
if (lua_type(l, stackPos) == LUA_TTABLE)
{
for (auto &prop : Particle::GetProperties())
@ -3768,7 +3847,7 @@ void LuaScriptInterface::SetDefaultProperties(lua_State * l, int id, int stackPo
}
if (lua_type(l, -1) != LUA_TNIL)
{
auto propertyAddress = reinterpret_cast<intptr_t>((reinterpret_cast<unsigned char*>(&luacon_sim->elements[id].DefaultProperties)) + prop.Offset);
auto propertyAddress = reinterpret_cast<intptr_t>((reinterpret_cast<unsigned char*>(&elements[id].DefaultProperties)) + prop.Offset);
LuaSetProperty(l, prop, propertyAddress, -1);
}
lua_pop(l, 1);
@ -3778,9 +3857,10 @@ void LuaScriptInterface::SetDefaultProperties(lua_State * l, int id, int stackPo
int LuaScriptInterface::elements_property(lua_State * l)
{
auto &builtinElements = GetElements();
auto *luacon_ci = static_cast<LuaScriptInterface *>(commandInterface);
int id = luaL_checkinteger(l, 1);
if (!luacon_sim->IsElementOrNone(id))
if (!SimulationData::CRef().IsElementOrNone(id))
{
return luaL_error(l, "Invalid element");
}
@ -3793,6 +3873,9 @@ int LuaScriptInterface::elements_property(lua_State * l)
if (lua_gettop(l) > 2)
{
auto &sd = SimulationData::Ref();
std::unique_lock lk(sd.elementGraphicsMx);
auto &elements = sd.elements;
if (prop != properties.end())
{
if (lua_type(l, 3) != LUA_TNIL)
@ -3800,20 +3883,17 @@ int LuaScriptInterface::elements_property(lua_State * l)
if (prop->Type == StructProperty::TransitionType)
{
int type = luaL_checkinteger(l, 3);
if (!luacon_sim->IsElementOrNone(type) && type != NT && type != ST)
if (!SimulationData::CRef().IsElementOrNone(type) && type != NT && type != ST)
{
return luaL_error(l, "Invalid element");
}
}
intptr_t propertyAddress = (intptr_t)(((unsigned char*)&luacon_sim->elements[id]) + prop->Offset);
intptr_t propertyAddress = (intptr_t)(((unsigned char*)&elements[id]) + prop->Offset);
LuaSetProperty(l, *prop, propertyAddress, 3);
luacon_model->BuildMenus();
luacon_ci->custom_init_can_move();
sd.graphicscache[id].isready = 0;
}
luacon_model->BuildMenus();
luacon_ci->custom_init_can_move();
luacon_ren->graphicscache[id].isready = 0;
SaveRenderer::Ref().Flush(id, id + 1);
}
else if (propertyName == "Update")
{
@ -3834,13 +3914,13 @@ int LuaScriptInterface::elements_property(lua_State * l)
break;
}
lua_el_func[id].Assign(l, 3);
luacon_sim->elements[id].Update = luaUpdateWrapper;
elements[id].Update = luaUpdateWrapper;
}
else if (lua_type(l, 3) == LUA_TBOOLEAN && !lua_toboolean(l, 3))
{
lua_el_func[id].Clear();
lua_el_mode[id] = 0;
luacon_sim->elements[id].Update = GetElements()[id].Update;
elements[id].Update = builtinElements[id].Update;
}
}
else if (propertyName == "Graphics")
@ -3848,27 +3928,26 @@ int LuaScriptInterface::elements_property(lua_State * l)
if (lua_type(l, 3) == LUA_TFUNCTION)
{
lua_gr_func[id].Assign(l, 3);
luacon_sim->elements[id].Graphics = luaGraphicsWrapper;
elements[id].Graphics = luaGraphicsWrapper;
}
else if (lua_type(l, 3) == LUA_TBOOLEAN && !lua_toboolean(l, 3))
{
lua_gr_func[id].Clear();
luacon_sim->elements[id].Graphics = GetElements()[id].Graphics;
elements[id].Graphics = builtinElements[id].Graphics;
}
luacon_ren->graphicscache[id].isready = 0;
SaveRenderer::Ref().Flush(id, id + 1);
sd.graphicscache[id].isready = 0;
}
else if (propertyName == "Create")
{
if (lua_type(l, 3) == LUA_TFUNCTION)
{
luaCreateHandlers[id].Assign(l, 3);
luacon_sim->elements[id].Create = luaCreateWrapper;
elements[id].Create = luaCreateWrapper;
}
else if (lua_type(l, 3) == LUA_TBOOLEAN && !lua_toboolean(l, 3))
{
luaCreateHandlers[id].Clear();
luacon_sim->elements[id].Create = GetElements()[id].Create;
elements[id].Create = builtinElements[id].Create;
}
}
else if (propertyName == "CreateAllowed")
@ -3876,12 +3955,12 @@ int LuaScriptInterface::elements_property(lua_State * l)
if (lua_type(l, 3) == LUA_TFUNCTION)
{
luaCreateAllowedHandlers[id].Assign(l, 3);
luacon_sim->elements[id].CreateAllowed = luaCreateAllowedWrapper;
elements[id].CreateAllowed = luaCreateAllowedWrapper;
}
else if (lua_type(l, 3) == LUA_TBOOLEAN && !lua_toboolean(l, 3))
{
luaCreateAllowedHandlers[id].Clear();
luacon_sim->elements[id].CreateAllowed = GetElements()[id].CreateAllowed;
elements[id].CreateAllowed = builtinElements[id].CreateAllowed;
}
}
else if (propertyName == "ChangeType")
@ -3889,12 +3968,12 @@ int LuaScriptInterface::elements_property(lua_State * l)
if (lua_type(l, 3) == LUA_TFUNCTION)
{
luaChangeTypeHandlers[id].Assign(l, 3);
luacon_sim->elements[id].ChangeType = luaChangeTypeWrapper;
elements[id].ChangeType = luaChangeTypeWrapper;
}
else if (lua_type(l, 3) == LUA_TBOOLEAN && !lua_toboolean(l, 3))
{
luaChangeTypeHandlers[id].Clear();
luacon_sim->elements[id].ChangeType = GetElements()[id].ChangeType;
elements[id].ChangeType = builtinElements[id].ChangeType;
}
}
else if (propertyName == "CtypeDraw")
@ -3902,12 +3981,12 @@ int LuaScriptInterface::elements_property(lua_State * l)
if (lua_type(l, 3) == LUA_TFUNCTION)
{
luaCtypeDrawHandlers[id].Assign(l, 3);
luacon_sim->elements[id].CtypeDraw = luaCtypeDrawWrapper;
elements[id].CtypeDraw = luaCtypeDrawWrapper;
}
else if (lua_type(l, 3) == LUA_TBOOLEAN && !lua_toboolean(l, 3))
{
luaCtypeDrawHandlers[id].Clear();
luacon_sim->elements[id].CtypeDraw = GetElements()[id].CtypeDraw;
elements[id].CtypeDraw = builtinElements[id].CtypeDraw;
}
}
else if (propertyName == "DefaultProperties")
@ -3922,15 +4001,17 @@ int LuaScriptInterface::elements_property(lua_State * l)
}
else
{
auto &sd = SimulationData::CRef();
auto &elements = sd.elements;
if (prop != properties.end())
{
intptr_t propertyAddress = (intptr_t)(((unsigned char*)&luacon_sim->elements[id]) + prop->Offset);
intptr_t propertyAddress = (intptr_t)(((const unsigned char*)&elements[id]) + prop->Offset);
LuaGetProperty(l, *prop, propertyAddress);
return 1;
}
else if (propertyName == "Identifier")
{
tpt_lua_pushByteString(l, luacon_sim->elements[id].Identifier);
tpt_lua_pushByteString(l, elements[id].Identifier);
return 1;
}
else if (propertyName == "DefaultProperties")
@ -3948,18 +4029,26 @@ int LuaScriptInterface::elements_property(lua_State * l)
int LuaScriptInterface::elements_free(lua_State * l)
{
int id = luaL_checkinteger(l, 1);
if (!luacon_sim->IsElement(id))
ByteString identifier;
{
return luaL_error(l, "Invalid element");
auto &sd = SimulationData::CRef();
if (!sd.IsElement(id))
{
return luaL_error(l, "Invalid element");
}
identifier = sd.elements[id].Identifier;
if (identifier.BeginsWith("DEFAULT_PT_"))
{
return luaL_error(l, "Cannot free default elements");
}
}
ByteString identifier = luacon_sim->elements[id].Identifier;
if (identifier.BeginsWith("DEFAULT_PT_"))
{
return luaL_error(l, "Cannot free default elements");
auto &sd = SimulationData::Ref();
std::unique_lock lk(sd.elementGraphicsMx);
sd.elements[id].Enabled = false;
}
luacon_sim->elements[id].Enabled = false;
luacon_model->BuildMenus();
lua_getglobal(l, "elements");
@ -3973,7 +4062,8 @@ int LuaScriptInterface::elements_free(lua_State * l)
int LuaScriptInterface::elements_exists(lua_State * l)
{
lua_pushboolean(l, luacon_sim->IsElement(luaL_checkinteger(l, 1)));
auto &sd = SimulationData::CRef();
lua_pushboolean(l, sd.IsElement(luaL_checkinteger(l, 1)));
return 1;
}

View File

@ -244,6 +244,7 @@ String TPTScriptInterface::FormatCommand(String command)
AnyType TPTScriptInterface::tptS_set(std::deque<String> * words)
{
auto &sd = SimulationData::CRef();
//Arguments from stack
StringType property = eval(words);
AnyType selector = eval(words);
@ -300,7 +301,7 @@ AnyType TPTScriptInterface::tptS_set(std::deque<String> * words)
}
else
{
newValue = m->GetSimulation()->GetParticleType(((StringType)value).Value().ToUtf8());
newValue = sd.GetParticleType(((StringType)value).Value().ToUtf8());
if (newValue < 0 || newValue >= PT_NUM)
{
// TODO: add element CAKE to invalidate this
@ -312,7 +313,7 @@ AnyType TPTScriptInterface::tptS_set(std::deque<String> * words)
}
else
throw GeneralException("Invalid value for assignment");
if (property.Value() == "type" && (newValue < 0 || newValue >= PT_NUM || !sim->elements[newValue].Enabled))
if (property.Value() == "type" && (newValue < 0 || newValue >= PT_NUM || !sd.elements[newValue].Enabled))
throw GeneralException("Invalid element");
if (selector.GetType() == TypePoint || selector.GetType() == TypeNumber)
@ -390,7 +391,7 @@ AnyType TPTScriptInterface::tptS_set(std::deque<String> * words)
if (selector.GetType() == TypeNumber)
type = ((NumberType)selector).Value();
else if (selector.GetType() == TypeString)
type = m->GetSimulation()->GetParticleType(((StringType)selector).Value().ToUtf8());
type = sd.GetParticleType(((StringType)selector).Value().ToUtf8());
if (type<0 || type>=PT_NUM)
throw GeneralException("Invalid particle type");
@ -439,6 +440,7 @@ AnyType TPTScriptInterface::tptS_set(std::deque<String> * words)
AnyType TPTScriptInterface::tptS_create(std::deque<String> * words)
{
auto &sd = SimulationData::CRef();
//Arguments from stack
AnyType createType = eval(words);
PointType position = eval(words);
@ -449,7 +451,7 @@ AnyType TPTScriptInterface::tptS_create(std::deque<String> * words)
if(createType.GetType() == TypeNumber)
type = ((NumberType)createType).Value();
else if(createType.GetType() == TypeString)
type = m->GetSimulation()->GetParticleType(((StringType)createType).Value().ToUtf8());
type = sd.GetParticleType(((StringType)createType).Value().ToUtf8());
else
throw GeneralException("Invalid type");
@ -549,6 +551,7 @@ AnyType TPTScriptInterface::tptS_bubble(std::deque<String> * words)
AnyType TPTScriptInterface::tptS_reset(std::deque<String> * words)
{
auto &sd = SimulationData::CRef();
//Arguments from stack
StringType reset = eval(words);
String resetStr = reset.Value();
@ -582,7 +585,7 @@ AnyType TPTScriptInterface::tptS_reset(std::deque<String> * words)
{
if (sim->parts[i].type)
{
sim->parts[i].temp = sim->elements[sim->parts[i].type].DefaultProperties.temp;
sim->parts[i].temp = sd.elements[sim->parts[i].type].DefaultProperties.temp;
}
}
}

View File

@ -354,6 +354,8 @@ void Air::Invert()
// called when loading saves / stamps to ensure nothing "leaks" the first frame
void Air::ApproximateBlockAirMaps()
{
auto &sd = SimulationData::CRef();
auto &elements = sd.elements;
for (int i = 0; i <= sim.parts_lastActiveIndex; i++)
{
int type = sim.parts[i].type;
@ -372,7 +374,7 @@ void Air::ApproximateBlockAirMaps()
}
}
// mostly accurate insulator blocking, besides checking GEL
else if ((type == PT_HSWC && sim.parts[i].life != 10) || sim.elements[type].HeatConduct <= (sim.rng()%250))
else if ((type == PT_HSWC && sim.parts[i].life != 10) || elements[type].HeatConduct <= (sim.rng()%250))
{
int x = ((int)(sim.parts[i].x+0.5f))/CELL, y = ((int)(sim.parts[i].y+0.5f))/CELL;
if (InBounds(x, y) && !(bmap_blockairh[y][x]&0x8))

View File

@ -8,7 +8,8 @@ struct BuiltinGOL
String name;
int oldtype;
int ruleset;
RGB<uint8_t> colour, colour2;
RGB<uint8_t> colour = RGB<uint8_t>(0, 0, 0);
RGB<uint8_t> colour2 = RGB<uint8_t>(0, 0, 0);
int goltype;
String description;
};

View File

@ -13,7 +13,7 @@
#include <iostream>
#include <cmath>
std::unique_ptr<Snapshot> Simulation::CreateSnapshot()
std::unique_ptr<Snapshot> Simulation::CreateSnapshot() const
{
auto snap = std::make_unique<Snapshot>();
snap->AirPressure .insert (snap->AirPressure .begin(), &pv [0][0] , &pv [0][0] + NCELL);
@ -188,7 +188,8 @@ int Simulation::Tool(int x, int y, int tool, int brushX, int brushY, float stren
cpart = &(parts[ID(r)]);
else if ((r = photons[y][x]))
cpart = &(parts[ID(r)]);
return tools[tool].Perform(this, cpart, x, y, brushX, brushY, strength);
auto &sd = SimulationData::CRef();
return sd.tools[tool].Perform(this, cpart, x, y, brushX, brushY, strength);
}
int Simulation::CreateWalls(int x, int y, int rx, int ry, int wall, Brush const *cBrush)
@ -428,27 +429,6 @@ int Simulation::CreatePartFlags(int x, int y, int c, int flags)
return 0;
}
int Simulation::GetParticleType(ByteString type)
{
type = type.ToUpper();
// alternative names for some elements
if (byteStringEqualsLiteral(type, "C4"))
return PT_PLEX;
else if (byteStringEqualsLiteral(type, "C5"))
return PT_C5;
else if (byteStringEqualsLiteral(type, "NONE"))
return PT_NONE;
for (int i = 1; i < PT_NUM; i++)
{
if (elements[i].Name.size() && elements[i].Enabled && type == elements[i].Name.ToUtf8().ToUpper())
{
return i;
}
}
return -1;
}
void Simulation::ApplyDecoration(int x, int y, int colR_, int colG_, int colB_, int colA_, int mode)
{
int rp;
@ -1058,6 +1038,8 @@ int Simulation::FloodParts(int x, int y, int fullc, int cm, int flags)
coord_stack[coord_stack_size][1] = y;
coord_stack_size++;
auto &sd = SimulationData::CRef();
auto &elements = sd.elements;
do
{
coord_stack_size--;

View File

@ -29,6 +29,7 @@ Element::Element():
Weight(50),
HeatConduct(128),
LatentHeat(0),
Description("No description"),
Properties(TYPE_SOLID),
@ -54,45 +55,58 @@ Element::Element():
std::vector<StructProperty> const &Element::GetProperties()
{
static std::vector<StructProperty> properties = {
{ "Name", StructProperty::String, offsetof(Element, Name ) },
{ "Colour", StructProperty::Colour, offsetof(Element, Colour ) },
{ "Color", StructProperty::Colour, offsetof(Element, Colour ) },
{ "MenuVisible", StructProperty::Integer, offsetof(Element, MenuVisible ) },
{ "MenuSection", StructProperty::Integer, offsetof(Element, MenuSection ) },
{ "Enabled", StructProperty::Integer, offsetof(Element, Enabled ) },
{ "Advection", StructProperty::Float, offsetof(Element, Advection ) },
{ "AirDrag", StructProperty::Float, offsetof(Element, AirDrag ) },
{ "AirLoss", StructProperty::Float, offsetof(Element, AirLoss ) },
{ "Loss", StructProperty::Float, offsetof(Element, Loss ) },
{ "Collision", StructProperty::Float, offsetof(Element, Collision ) },
{ "Gravity", StructProperty::Float, offsetof(Element, Gravity ) },
{ "NewtonianGravity", StructProperty::Float, offsetof(Element, NewtonianGravity ) },
{ "Diffusion", StructProperty::Float, offsetof(Element, Diffusion ) },
{ "HotAir", StructProperty::Float, offsetof(Element, HotAir ) },
{ "Falldown", StructProperty::Integer, offsetof(Element, Falldown ) },
{ "Flammable", StructProperty::Integer, offsetof(Element, Flammable ) },
{ "Explosive", StructProperty::Integer, offsetof(Element, Explosive ) },
{ "Meltable", StructProperty::Integer, offsetof(Element, Meltable ) },
{ "Hardness", StructProperty::Integer, offsetof(Element, Hardness ) },
{ "PhotonReflectWavelengths", StructProperty::UInteger, offsetof(Element, PhotonReflectWavelengths ) },
{ "CarriesTypeIn", StructProperty::UInteger, offsetof(Element, CarriesTypeIn ) },
{ "Weight", StructProperty::Integer, offsetof(Element, Weight ) },
{ "Temperature", StructProperty::Float, offsetof(Element, DefaultProperties.temp ) },
{ "HeatConduct", StructProperty::UChar, offsetof(Element, HeatConduct ) },
{ "Description", StructProperty::String, offsetof(Element, Description ) },
{ "State", StructProperty::Removed, 0 },
{ "Properties", StructProperty::Integer, offsetof(Element, Properties ) },
{ "LowPressure", StructProperty::Float, offsetof(Element, LowPressure ) },
{ "LowPressureTransition", StructProperty::TransitionType, offsetof(Element, LowPressureTransition ) },
{ "HighPressure", StructProperty::Float, offsetof(Element, HighPressure ) },
{ "HighPressureTransition", StructProperty::TransitionType, offsetof(Element, HighPressureTransition ) },
{ "LowTemperature", StructProperty::Float, offsetof(Element, LowTemperature ) },
{ "LowTemperatureTransition", StructProperty::TransitionType, offsetof(Element, LowTemperatureTransition ) },
{ "HighTemperature", StructProperty::Float, offsetof(Element, HighTemperature ) },
{ "HighTemperatureTransition", StructProperty::TransitionType, offsetof(Element, HighTemperatureTransition) }
struct DoOnce
{
std::vector<StructProperty> properties;
DoOnce()
{
properties = {
{ "Name", StructProperty::String, offsetof(Element, Name ) },
{ "Colour", StructProperty::Colour, offsetof(Element, Colour ) },
{ "Color", StructProperty::Colour, offsetof(Element, Colour ) },
{ "MenuVisible", StructProperty::Integer, offsetof(Element, MenuVisible ) },
{ "MenuSection", StructProperty::Integer, offsetof(Element, MenuSection ) },
{ "Enabled", StructProperty::Integer, offsetof(Element, Enabled ) },
{ "Advection", StructProperty::Float, offsetof(Element, Advection ) },
{ "AirDrag", StructProperty::Float, offsetof(Element, AirDrag ) },
{ "AirLoss", StructProperty::Float, offsetof(Element, AirLoss ) },
{ "Loss", StructProperty::Float, offsetof(Element, Loss ) },
{ "Collision", StructProperty::Float, offsetof(Element, Collision ) },
{ "Gravity", StructProperty::Float, offsetof(Element, Gravity ) },
{ "NewtonianGravity", StructProperty::Float, offsetof(Element, NewtonianGravity ) },
{ "Diffusion", StructProperty::Float, offsetof(Element, Diffusion ) },
{ "HotAir", StructProperty::Float, offsetof(Element, HotAir ) },
{ "Falldown", StructProperty::Integer, offsetof(Element, Falldown ) },
{ "Flammable", StructProperty::Integer, offsetof(Element, Flammable ) },
{ "Explosive", StructProperty::Integer, offsetof(Element, Explosive ) },
{ "Meltable", StructProperty::Integer, offsetof(Element, Meltable ) },
{ "Hardness", StructProperty::Integer, offsetof(Element, Hardness ) },
{ "PhotonReflectWavelengths", StructProperty::UInteger, offsetof(Element, PhotonReflectWavelengths ) },
{ "CarriesTypeIn", StructProperty::UInteger, offsetof(Element, CarriesTypeIn ) },
{ "Weight", StructProperty::Integer, offsetof(Element, Weight ) },
{ "Temperature", StructProperty::Float, offsetof(Element, DefaultProperties.temp ) },
{ "HeatConduct", StructProperty::UChar, offsetof(Element, HeatConduct ) },
{ "Description", StructProperty::String, offsetof(Element, Description ) },
{ "State", StructProperty::Removed, 0 },
{ "Properties", StructProperty::Integer, offsetof(Element, Properties ) },
{ "LowPressure", StructProperty::Float, offsetof(Element, LowPressure ) },
{ "LowPressureTransition", StructProperty::TransitionType, offsetof(Element, LowPressureTransition ) },
{ "HighPressure", StructProperty::Float, offsetof(Element, HighPressure ) },
{ "HighPressureTransition", StructProperty::TransitionType, offsetof(Element, HighPressureTransition ) },
{ "LowTemperature", StructProperty::Float, offsetof(Element, LowTemperature ) },
{ "LowTemperatureTransition", StructProperty::TransitionType, offsetof(Element, LowTemperatureTransition ) },
{ "HighTemperature", StructProperty::Float, offsetof(Element, HighTemperature ) },
{ "HighTemperatureTransition", StructProperty::TransitionType, offsetof(Element, HighTemperatureTransition) }
};
if constexpr (LATENTHEAT)
{
properties.push_back({ "LatentHeat", StructProperty::UInteger, offsetof(Element, LatentHeat) });
}
}
};
return properties;
static DoOnce doOnce;
return doOnce.properties;
}
int Element::legacyUpdate(UPDATE_FUNC_ARGS) {
@ -216,14 +230,16 @@ int Element::legacyUpdate(UPDATE_FUNC_ARGS) {
int Element::defaultGraphics(GRAPHICS_FUNC_ARGS)
{
auto &sd = SimulationData::CRef();
auto &elements = sd.elements;
int t = cpart->type;
//Property based defaults
if(ren->sim->elements[t].Properties & PROP_RADIOACTIVE) *pixel_mode |= PMODE_GLOW;
if(ren->sim->elements[t].Properties & TYPE_LIQUID)
if(elements[t].Properties & PROP_RADIOACTIVE) *pixel_mode |= PMODE_GLOW;
if(elements[t].Properties & TYPE_LIQUID)
{
*pixel_mode |= PMODE_BLUR;
}
if(ren->sim->elements[t].Properties & TYPE_GAS)
if(elements[t].Properties & TYPE_GAS)
{
*pixel_mode &= ~PMODE;
*pixel_mode |= FIRE_BLEND;
@ -238,7 +254,9 @@ int Element::defaultGraphics(GRAPHICS_FUNC_ARGS)
bool Element::basicCtypeDraw(CTYPEDRAW_FUNC_ARGS)
{
if (sim->parts[i].type == t || sim->elements[t].Properties & PROP_NOCTYPEDRAW)
auto &sd = SimulationData::CRef();
auto &elements = sd.elements;
if (sim->parts[i].type == t || elements[t].Properties & PROP_NOCTYPEDRAW)
{
return false;
}

View File

@ -8,6 +8,7 @@
class Simulation;
class Renderer;
struct GraphicsFuncContext;
class VideoBuffer;
struct Particle;
class Element
@ -38,6 +39,7 @@ public:
unsigned int PhotonReflectWavelengths;
int Weight;
unsigned char HeatConduct;
unsigned int LatentHeat;
String Description;
unsigned int Properties;
unsigned int CarriesTypeIn;

View File

@ -1,12 +1,12 @@
#include "ElementCommon.h"
std::vector<Element> const &GetElements()
std::array<Element, PT_NUM> const &GetElements()
{
struct DoOnce
{
std::vector<Element> elements;
std::array<Element, PT_NUM> elements;
DoOnce() : elements(PT_NUM)
DoOnce()
{
#define ELEMENT_NUMBERS_CALL
#include "ElementNumbers.h"

View File

@ -1,5 +1,5 @@
#pragma once
#include <vector>
#include <array>
#include "SimulationData.h"
#include "Element.h"
@ -8,4 +8,4 @@
#include "ElementNumbers.h"
#undef ELEMENT_NUMBERS_ENUMERATE
std::vector<Element> const &GetElements();
std::array<Element, PT_NUM> const &GetElements();

View File

@ -8,6 +8,7 @@
#include "Particle.h"
#include "ElementGraphics.h"
#include "Simulation.h"
#include "SimulationData.h"
#include "graphics/Renderer.h"
#include <algorithm>
#include <cmath>

View File

@ -42,8 +42,8 @@ constexpr auto FLAG_PHOTDECO = UINT32_C(0x00000008); // compatibility with
#define UPDATE_FUNC_ARGS Simulation* sim, int i, int x, int y, int surround_space, int nt, Particle *parts, int pmap[YRES][XRES]
#define UPDATE_FUNC_SUBCALL_ARGS sim, i, x, y, surround_space, nt, parts, pmap
#define GRAPHICS_FUNC_ARGS Renderer * ren, Particle *cpart, int nx, int ny, int *pixel_mode, int* cola, int *colr, int *colg, int *colb, int *firea, int *firer, int *fireg, int *fireb
#define GRAPHICS_FUNC_SUBCALL_ARGS ren, cpart, nx, ny, pixel_mode, cola, colr, colg, colb, firea, firer, fireg, fireb
#define GRAPHICS_FUNC_ARGS GraphicsFuncContext &gfctx, const Particle *cpart, int nx, int ny, int *pixel_mode, int* cola, int *colr, int *colg, int *colb, int *firea, int *firer, int *fireg, int *fireb
#define GRAPHICS_FUNC_SUBCALL_ARGS gfctx, cpart, nx, ny, pixel_mode, cola, colr, colg, colb, firea, firer, fireg, fireb
#define ELEMENT_CREATE_FUNC_ARGS Simulation *sim, int i, int x, int y, int t, int v

View File

@ -6,22 +6,23 @@
#include "graphics/Renderer.h"
#include "Simulation.h"
#include "SimulationData.h"
SaveRenderer::SaveRenderer(){
sim = new Simulation();
ren = new Renderer(sim);
SaveRenderer::SaveRenderer()
{
sim = std::make_unique<Simulation>();
ren = std::make_unique<Renderer>(sim.get());
ren->decorations_enable = true;
ren->blackDecorations = true;
}
void SaveRenderer::Flush(int begin, int end)
{
std::lock_guard<std::mutex> gx(renderMutex);
std::fill(ren->graphicscache + begin, ren->graphicscache + end, gcache_item());
}
SaveRenderer::~SaveRenderer() = default;
std::pair<std::unique_ptr<VideoBuffer>, MissingElements> SaveRenderer::Render(const GameSave *save, bool decorations, bool fire, Renderer *renderModeSource)
std::unique_ptr<VideoBuffer> SaveRenderer::Render(const GameSave *save, bool decorations, bool fire, Renderer *renderModeSource)
{
// this function usually runs on a thread different from where element info in SimulationData may be written, so we acquire a read-only lock on it
auto &sd = SimulationData::CRef();
std::shared_lock lk(sd.elementGraphicsMx);
std::lock_guard<std::mutex> gx(renderMutex);
ren->ResetModes();
@ -34,7 +35,7 @@ std::pair<std::unique_ptr<VideoBuffer>, MissingElements> SaveRenderer::Render(co
sim->clear_sim();
auto missingElementTypes = sim->Load(save, true, { 0, 0 });
sim->Load(save, true, { 0, 0 });
ren->decorations_enable = true;
ren->blackDecorations = !decorations;
ren->ClearAccumulation();
@ -58,11 +59,5 @@ std::pair<std::unique_ptr<VideoBuffer>, MissingElements> SaveRenderer::Render(co
auto tempThumb = std::make_unique<VideoBuffer>(save->blockSize * CELL);
tempThumb->BlendImage(ren->Data(), 0xFF, ren->Size().OriginRect());
return { std::move(tempThumb), missingElementTypes };
}
SaveRenderer::~SaveRenderer()
{
delete ren;
delete sim;
return tempThumb;
}

View File

@ -5,21 +5,20 @@
#include <vector>
#include "common/ExplicitSingleton.h"
#include "common/String.h"
#include "MissingElements.h"
class GameSave;
class VideoBuffer;
class Graphics;
class Simulation;
class Renderer;
class SaveRenderer: public ExplicitSingleton<SaveRenderer> {
Simulation * sim;
Renderer * ren;
class SaveRenderer: public ExplicitSingleton<SaveRenderer>
{
std::unique_ptr<Simulation> sim;
std::unique_ptr<Renderer> ren;
std::mutex renderMutex;
public:
SaveRenderer();
std::pair<std::unique_ptr<VideoBuffer>, MissingElements> Render(const GameSave *save, bool decorations = true, bool fire = true, Renderer *renderModeSource = nullptr);
void Flush(int begin, int end);
virtual ~SaveRenderer();
~SaveRenderer();
std::unique_ptr<VideoBuffer> Render(const GameSave *save, bool decorations = true, bool fire = true, Renderer *renderModeSource = nullptr);
};

View File

@ -1,7 +1,8 @@
#include "Sign.h"
#include "graphics/Graphics.h"
#include "simulation/Simulation.h"
#include "Simulation.h"
#include "SimulationData.h"
sign::sign(String text_, int x_, int y_, Justification justification_):
x(x_),
@ -11,8 +12,9 @@ sign::sign(String text_, int x_, int y_, Justification justification_):
{
}
String sign::getDisplayText(Simulation *sim, int &x0, int &y0, int &w, int &h, bool colorize, bool *v95) const
String sign::getDisplayText(const Simulation *sim, int &x0, int &y0, int &w, int &h, bool colorize, bool *v95) const
{
auto &sd = SimulationData::CRef();
String drawable_text;
auto si = std::make_pair(0, Type::Normal);
if (text.find('{') == text.npos)
@ -79,13 +81,13 @@ String sign::getDisplayText(Simulation *sim, int &x0, int &y0, int &w, int &h, b
}
else if (between_curlies == "type")
{
formatted_text << (part ? sim->BasicParticleInfo(*part) : (formatted_text.Size() ? String::Build("empty") : String::Build("Empty")));
formatted_text << (part ? sd.BasicParticleInfo(*part) : (formatted_text.Size() ? String::Build("empty") : String::Build("Empty")));
if (v95)
*v95 = true;
}
else if (between_curlies == "ctype")
{
formatted_text << (part ? (sim->IsElementOrNone(part->ctype) ? sim->ElementResolve(part->ctype, -1) : String::Build(part->ctype)) : (formatted_text.Size() ? String::Build("empty") : String::Build("Empty")));
formatted_text << (part ? (sd.IsElementOrNone(part->ctype) ? sd.ElementResolve(part->ctype, -1) : String::Build(part->ctype)) : (formatted_text.Size() ? String::Build("empty") : String::Build("Empty")));
if (v95)
*v95 = true;
}

View File

@ -28,6 +28,6 @@ struct sign
String text;
sign(String text_, int x_, int y_, Justification justification_);
String getDisplayText(Simulation *sim, int &x, int &y, int &w, int &h, bool colorize = true, bool *v95 = nullptr) const;
String getDisplayText(const Simulation *sim, int &x, int &y, int &w, int &h, bool colorize = true, bool *v95 = nullptr) const;
std::pair<int, Type> split() const;
};

File diff suppressed because it is too large Load Diff

View File

@ -11,7 +11,6 @@
#include "common/tpt-rand.h"
#include "Element.h"
#include "SimulationConfig.h"
#include "MissingElements.h"
#include <cstring>
#include <cstddef>
#include <vector>
@ -22,7 +21,6 @@
constexpr int CHANNELS = int(MAX_TEMP - 73) / 100 + 2;
class Snapshot;
class SimTool;
class Brush;
class SimulationSample;
struct matrix2d;
@ -37,24 +35,17 @@ class GameSave;
class Simulation
{
public:
GravityPtr grav;
Air * air;
std::unique_ptr<Air> air;
RNG rng;
std::vector<sign> signs;
std::array<Element, PT_NUM> elements;
//Element * elements;
std::vector<SimTool> tools;
std::vector<unsigned int> platent;
std::vector<wall_type> wtypes;
std::vector<menu_section> msections;
int currentTick;
int replaceModeSelected;
int replaceModeFlags;
char can_move[PT_NUM][PT_NUM];
int debug_nextToUpdate;
int debug_mostRecentlyUpdated = -1; // -1 when between full update loops
int parts_lastActiveIndex;
@ -122,41 +113,37 @@ public:
uint64_t frameCount;
bool ensureDeterminism;
MissingElements Load(const GameSave *save, bool includePressure, Vec2<int> blockP); // block coordinates
void Load(const GameSave *save, bool includePressure, Vec2<int> blockP); // block coordinates
std::unique_ptr<GameSave> Save(bool includePressure, Rect<int> partR); // particle coordinates
void SaveSimOptions(GameSave &gameSave);
SimulationSample GetSample(int x, int y);
std::unique_ptr<Snapshot> CreateSnapshot();
std::unique_ptr<Snapshot> CreateSnapshot() const;
void Restore(const Snapshot &snap);
int is_blocking(int t, int x, int y);
int is_boundary(int pt, int x, int y);
int find_next_boundary(int pt, int *x, int *y, int dm, int *em, bool reverse);
int is_blocking(int t, int x, int y) const;
int is_boundary(int pt, int x, int y) const;
int find_next_boundary(int pt, int *x, int *y, int dm, int *em, bool reverse) const;
void photoelectric_effect(int nx, int ny);
int do_move(int i, int x, int y, float nxf, float nyf);
bool move(int i, int x, int y, float nxf, float nyf);
int try_move(int i, int x, int y, int nx, int ny);
int eval_move(int pt, int nx, int ny, unsigned *rr) const;
struct PlanMoveResult
{
int fin_x, fin_y, clear_x, clear_y;
float fin_xf, fin_yf, clear_xf, clear_yf;
float vx, vy;
};
PlanMoveResult PlanMove(int i, int x, int y, bool update_emap);
void init_can_move();
template<bool UpdateEmap, class Sim>
static PlanMoveResult PlanMove(Sim &sim, int i, int x, int y);
bool IsWallBlocking(int x, int y, int type) const;
bool IsElement(int type) const {
return (type > 0 && type < PT_NUM && elements[type].Enabled);
}
bool IsElementOrNone(int type) const {
return (type >= 0 && type < PT_NUM && elements[type].Enabled);
}
void create_cherenkov_photon(int pp);
void create_gain_photon(int pp);
void kill_part(int i);
bool FloodFillPmapCheck(int x, int y, int type);
bool FloodFillPmapCheck(int x, int y, int type) const;
int flood_prop(int x, int y, StructProperty prop, PropertyValue propvalue);
bool flood_water(int x, int y, int i);
int FloodINST(int x, int y);
@ -177,7 +164,6 @@ public:
void CheckStacking();
void BeforeSim();
void AfterSim();
void rotate_area(int area_x, int area_y, int area_w, int area_h, int invert);
void clear_area(int area_x, int area_y, int area_w, int area_h);
void SetEdgeMode(int newEdgeMode);
@ -212,13 +198,8 @@ public:
void CreateBox(int x1, int y1, int x2, int y2, int c, int flags = -1);
int FloodParts(int x, int y, int c, int cm, int flags = -1);
void GetGravityField(int x, int y, float particleGrav, float newtonGrav, float & pGravX, float & pGravY);
int GetParticleType(ByteString type);
void orbitalparts_get(int block1, int block2, int resblock1[], int resblock2[]);
void orbitalparts_set(int *block1, int *block2, int resblock1[], int resblock2[]);
int get_wavelength_bin(int *wm);
struct GetNormalResult
{
@ -226,38 +207,14 @@ public:
float nx, ny;
int lx, ly, rx, ry;
};
GetNormalResult get_normal(int pt, int x, int y, float dx, float dy);
GetNormalResult get_normal_interp(int pt, float x0, float y0, float dx, float dy);
GetNormalResult get_normal(int pt, int x, int y, float dx, float dy) const;
template<bool PhotoelectricEffect, class Sim>
static GetNormalResult get_normal_interp(Sim &sim, int pt, float x0, float y0, float dx, float dy);
void clear_sim();
Simulation();
~Simulation();
// These don't really belong anywhere at the moment, so go here for loop edge mode
static int remainder_p(int x, int y);
static float remainder_p(float x, float y);
String ElementResolve(int type, int ctype) const;
String BasicParticleInfo(Particle const &sample_part) const;
struct CustomGOLData
{
int rule, colour1, colour2;
String nameString, ruleString;
inline bool operator <(const CustomGOLData &other) const
{
return rule < other.rule;
}
};
private:
std::vector<CustomGOLData> customGol;
public:
const CustomGOLData *GetCustomGOLByRule(int rule) const;
const std::vector<CustomGOLData> GetCustomGol() { return customGol; }
void SetCustomGOL(std::vector<CustomGOLData> newCustomGol);
bool useLuaCallbacks = false;
private:
CoordStack& getCoordStackSingleton();

View File

@ -1,16 +1,16 @@
#include "SimulationData.h"
#include "ElementGraphics.h"
#include "ElementDefs.h"
#include "ElementClasses.h"
#include "GOLString.h"
#include "BuiltinGOL.h"
#include "WallType.h"
#include "MenuSection.h"
#include "ToolClasses.h"
#include "Misc.h"
#include "graphics/Renderer.h"
const BuiltinGOL builtinGol[NGOL] = {
const std::array<BuiltinGOL, NGOL> SimulationData::builtinGol = {{
// * Ruleset:
// * bits x = 8..0: stay if x neighbours present
// * bits x = 16..9: begin if x-8 neighbours present
@ -45,9 +45,9 @@ const BuiltinGOL builtinGol[NGOL] = {
{ "STAR", GT_STAR, 0x98478, 0x000040_rgb, 0x0000E6_rgb, NGT_STAR, String("Like Star Wars rule: B278/S3456/6") },
{ "FROG", GT_FROG, 0x21806, 0x006400_rgb, 0x00FF00_rgb, NGT_FROG, String("Frogs: B34/S12/3") },
{ "BRAN", GT_BRAN, 0x25440, 0xFFFF00_rgb, 0x969600_rgb, NGT_BRAN, String("Brian 6: B246/S6/3" )}
};
}};
std::vector<wall_type> LoadWalls()
static std::vector<wall_type> LoadWalls()
{
return
std::vector<wall_type>{
@ -73,7 +73,7 @@ std::vector<wall_type> LoadWalls()
};
}
std::vector<menu_section> LoadMenus()
static std::vector<menu_section> LoadMenus()
{
return
std::vector<menu_section>{
@ -98,170 +98,244 @@ std::vector<menu_section> LoadMenus()
};
}
std::vector<unsigned int> LoadLatent()
void SimulationData::init_can_move()
{
return
std::vector<unsigned int>{
/* NONE */ 0,
/* DUST */ 0,
/* WATR */ 7500,
/* OIL */ 0,
/* FIRE */ 0,
/* STNE */ 0,
/* LAVA */ 0,
/* GUN */ 0,
/* NITR */ 0,
/* CLNE */ 0,
/* GAS */ 0,
/* C-4 */ 0,
/* GOO */ 0,
/* ICE */ 1095,
/* METL */ 919,
/* SPRK */ 0,
/* SNOW */ 1095,
/* WOOD */ 0,
/* NEUT */ 0,
/* PLUT */ 0,
/* PLNT */ 0,
/* ACID */ 0,
/* VOID */ 0,
/* WTRV */ 0,
/* CNCT */ 0,
/* DSTW */ 7500,
/* SALT */ 0,
/* SLTW */ 7500,
/* DMND */ 0,
/* BMTL */ 0,
/* BRMT */ 0,
/* PHOT */ 0,
/* URAN */ 0,
/* WAX */ 0,
/* MWAX */ 0,
/* PSCN */ 0,
/* NSCN */ 0,
/* LN2 */ 0,
/* INSL */ 0,
/* VACU */ 0,
/* VENT */ 0,
/* RBDM */ 0,
/* LRBD */ 0,
/* NTCT */ 0,
/* SAND */ 0,
/* GLAS */ 0,
/* PTCT */ 0,
/* BGLA */ 0,
/* THDR */ 0,
/* PLSM */ 0,
/* ETRD */ 0,
/* NICE */ 0,
/* NBLE */ 0,
/* BTRY */ 0,
/* LCRY */ 0,
/* STKM */ 0,
/* SWCH */ 0,
/* SMKE */ 0,
/* DESL */ 0,
/* COAL */ 0,
/* LO2 */ 0,
/* O2 */ 0,
/* INWR */ 0,
/* YEST */ 0,
/* DYST */ 0,
/* THRM */ 0,
/* GLOW */ 0,
/* BRCK */ 0,
/* CFLM */ 0,
/* FIRW */ 0,
/* FUSE */ 0,
/* FSEP */ 0,
/* AMTR */ 0,
/* BCOL */ 0,
/* PCLN */ 0,
/* HSWC */ 0,
/* IRON */ 0,
/* MORT */ 0,
/* LIFE */ 0,
/* DLAY */ 0,
/* CO2 */ 0,
/* DRIC */ 0,
/* CBNW */ 7500,
/* STOR */ 0,
/* STOR */ 0,
/* FREE */ 0,
/* FREE */ 0,
/* FREE */ 0,
/* FREE */ 0,
/* FREE */ 0,
/* SPNG */ 0,
/* RIME */ 0,
/* FOG */ 0,
/* BCLN */ 0,
/* LOVE */ 0,
/* DEUT */ 0,
/* WARP */ 0,
/* PUMP */ 0,
/* FWRK */ 0,
/* PIPE */ 0,
/* FRZZ */ 0,
/* FRZW */ 0,
/* GRAV */ 0,
/* BIZR */ 0,
/* BIZRG*/ 0,
/* BIZRS*/ 0,
/* INST */ 0,
/* ISOZ */ 0,
/* ISZS */ 0,
/* PRTI */ 0,
/* PRTO */ 0,
/* PSTE */ 0,
/* PSTS */ 0,
/* ANAR */ 0,
/* VINE */ 0,
/* INVS */ 0,
/* EQVE */ 0,
/* SPWN2*/ 0,
/* SPAWN*/ 0,
/* SHLD1*/ 0,
/* SHLD2*/ 0,
/* SHLD3*/ 0,
/* SHLD4*/ 0,
/* LOlZ */ 0,
/* WIFI */ 0,
/* FILT */ 0,
/* ARAY */ 0,
/* BRAY */ 0,
/* STKM2*/ 0,
/* BOMB */ 0,
/* C-5 */ 0,
/* SING */ 0,
/* QRTZ */ 0,
/* PQRT */ 0,
/* EMP */ 0,
/* BREL */ 0,
/* ELEC */ 0,
/* ACEL */ 0,
/* DCEL */ 0,
/* TNT */ 0,
/* IGNP */ 0,
/* BOYL */ 0,
/* GEL */ 0,
/* FREE */ 0,
/* FREE */ 0,
/* FREE */ 0,
/* FREE */ 0,
/* WIND */ 0,
/* H2 */ 0,
/* SOAP */ 0,
/* NBHL */ 0,
/* NWHL */ 0,
/* MERC */ 0,
/* PBCN */ 0,
/* GPMP */ 0,
/* CLST */ 0,
/* WIRE */ 0,
/* GBMB */ 0,
/* FIGH */ 0,
/* FRAY */ 0,
/* REPL */ 0,
};
int movingType, destinationType;
// can_move[moving type][type at destination]
// 0 = No move/Bounce
// 1 = Swap
// 2 = Both particles occupy the same space.
// 3 = Varies, go run some extra checks
//particles that don't exist shouldn't move...
for (destinationType = 0; destinationType < PT_NUM; destinationType++)
can_move[0][destinationType] = 0;
//initialize everything else to swapping by default
for (movingType = 1; movingType < PT_NUM; movingType++)
for (destinationType = 0; destinationType < PT_NUM; destinationType++)
can_move[movingType][destinationType] = 1;
//photons go through everything by default
for (destinationType = 1; destinationType < PT_NUM; destinationType++)
can_move[PT_PHOT][destinationType] = 2;
for (movingType = 1; movingType < PT_NUM; movingType++)
{
for (destinationType = 1; destinationType < PT_NUM; destinationType++)
{
//weight check, also prevents particles of same type displacing each other
if (elements[movingType].Weight <= elements[destinationType].Weight || destinationType == PT_GEL)
can_move[movingType][destinationType] = 0;
//other checks for NEUT and energy particles
if (movingType == PT_NEUT && (elements[destinationType].Properties&PROP_NEUTPASS))
can_move[movingType][destinationType] = 2;
if (movingType == PT_NEUT && (elements[destinationType].Properties&PROP_NEUTABSORB))
can_move[movingType][destinationType] = 1;
if (movingType == PT_NEUT && (elements[destinationType].Properties&PROP_NEUTPENETRATE))
can_move[movingType][destinationType] = 1;
if (destinationType == PT_NEUT && (elements[movingType].Properties&PROP_NEUTPENETRATE))
can_move[movingType][destinationType] = 0;
if ((elements[movingType].Properties&TYPE_ENERGY) && (elements[destinationType].Properties&TYPE_ENERGY))
can_move[movingType][destinationType] = 2;
}
}
for (destinationType = 0; destinationType < PT_NUM; destinationType++)
{
//set what stickmen can move through
int stkm_move = 0;
if (elements[destinationType].Properties & (TYPE_LIQUID | TYPE_GAS))
stkm_move = 2;
if (!destinationType || destinationType == PT_PRTO || destinationType == PT_SPAWN || destinationType == PT_SPAWN2)
stkm_move = 2;
can_move[PT_STKM][destinationType] = stkm_move;
can_move[PT_STKM2][destinationType] = stkm_move;
can_move[PT_FIGH][destinationType] = stkm_move;
//spark shouldn't move
can_move[PT_SPRK][destinationType] = 0;
}
for (movingType = 1; movingType < PT_NUM; movingType++)
{
//everything "swaps" with VACU and BHOL to make them eat things
can_move[movingType][PT_BHOL] = 1;
can_move[movingType][PT_NBHL] = 1;
//nothing goes through stickmen
can_move[movingType][PT_STKM] = 0;
can_move[movingType][PT_STKM2] = 0;
can_move[movingType][PT_FIGH] = 0;
//INVS behaviour varies with pressure
can_move[movingType][PT_INVIS] = 3;
//stop CNCT from being displaced by other particles
can_move[movingType][PT_CNCT] = 0;
//VOID and PVOD behaviour varies with powered state and ctype
can_move[movingType][PT_PVOD] = 3;
can_move[movingType][PT_VOID] = 3;
//nothing moves through EMBR (not sure why, but it's killed when it touches anything)
can_move[movingType][PT_EMBR] = 0;
can_move[PT_EMBR][movingType] = 0;
//Energy particles move through VIBR and BVBR, so it can absorb them
if (elements[movingType].Properties & TYPE_ENERGY)
{
can_move[movingType][PT_VIBR] = 1;
can_move[movingType][PT_BVBR] = 1;
}
//SAWD cannot be displaced by other powders
if (elements[movingType].Properties & TYPE_PART)
can_move[movingType][PT_SAWD] = 0;
}
//a list of lots of things PHOT can move through
// TODO: replace with property
for (destinationType = 0; destinationType < PT_NUM; destinationType++)
{
if (destinationType == PT_GLAS || destinationType == PT_PHOT || destinationType == PT_FILT || destinationType == PT_INVIS
|| destinationType == PT_CLNE || destinationType == PT_PCLN || destinationType == PT_BCLN || destinationType == PT_PBCN
|| destinationType == PT_WATR || destinationType == PT_DSTW || destinationType == PT_SLTW || destinationType == PT_GLOW
|| destinationType == PT_ISOZ || destinationType == PT_ISZS || destinationType == PT_QRTZ || destinationType == PT_PQRT
|| destinationType == PT_H2 || destinationType == PT_BGLA || destinationType == PT_C5)
can_move[PT_PHOT][destinationType] = 2;
if (destinationType != PT_DMND && destinationType != PT_INSL && destinationType != PT_VOID && destinationType != PT_PVOD && destinationType != PT_VIBR && destinationType != PT_BVBR && destinationType != PT_PRTI && destinationType != PT_PRTO)
{
can_move[PT_PROT][destinationType] = 2;
can_move[PT_GRVT][destinationType] = 2;
}
}
//other special cases that weren't covered above
can_move[PT_DEST][PT_DMND] = 0;
can_move[PT_DEST][PT_CLNE] = 0;
can_move[PT_DEST][PT_PCLN] = 0;
can_move[PT_DEST][PT_BCLN] = 0;
can_move[PT_DEST][PT_PBCN] = 0;
can_move[PT_DEST][PT_ROCK] = 0;
can_move[PT_NEUT][PT_INVIS] = 2;
can_move[PT_ELEC][PT_LCRY] = 2;
can_move[PT_ELEC][PT_EXOT] = 2;
can_move[PT_ELEC][PT_GLOW] = 2;
can_move[PT_PHOT][PT_LCRY] = 3; //varies according to LCRY life
can_move[PT_PHOT][PT_GPMP] = 3;
can_move[PT_PHOT][PT_BIZR] = 2;
can_move[PT_ELEC][PT_BIZR] = 2;
can_move[PT_PHOT][PT_BIZRG] = 2;
can_move[PT_ELEC][PT_BIZRG] = 2;
can_move[PT_PHOT][PT_BIZRS] = 2;
can_move[PT_ELEC][PT_BIZRS] = 2;
can_move[PT_BIZR][PT_FILT] = 2;
can_move[PT_BIZRG][PT_FILT] = 2;
can_move[PT_ANAR][PT_WHOL] = 1; //WHOL eats ANAR
can_move[PT_ANAR][PT_NWHL] = 1;
can_move[PT_ELEC][PT_DEUT] = 1;
can_move[PT_THDR][PT_THDR] = 2;
can_move[PT_EMBR][PT_EMBR] = 2;
can_move[PT_TRON][PT_SWCH] = 3;
can_move[PT_SOAP][PT_OIL] = 0;
can_move[PT_OIL][PT_SOAP] = 1;
}
const CustomGOLData *SimulationData::GetCustomGOLByRule(int rule) const
{
// * Binary search. customGol is already sorted, see SetCustomGOL.
auto it = std::lower_bound(customGol.begin(), customGol.end(), rule, [](const CustomGOLData &item, int rule) {
return item.rule < rule;
});
if (it != customGol.end() && !(rule < it->rule))
{
return &*it;
}
return nullptr;
}
void SimulationData::SetCustomGOL(std::vector<CustomGOLData> newCustomGol)
{
std::sort(newCustomGol.begin(), newCustomGol.end());
customGol = newCustomGol;
}
String SimulationData::ElementResolve(int type, int ctype) const
{
if (type == PT_LIFE)
{
if (ctype >= 0 && ctype < NGOL)
{
return builtinGol[ctype].name;
}
auto *cgol = GetCustomGOLByRule(ctype);
if (cgol)
{
return cgol->nameString;
}
return SerialiseGOLRule(ctype);
}
else if (type >= 0 && type < PT_NUM)
return elements[type].Name;
return "Empty";
}
String SimulationData::BasicParticleInfo(Particle const &sample_part) const
{
StringBuilder sampleInfo;
int type = sample_part.type;
int ctype = sample_part.ctype;
int storedCtype = sample_part.tmp4;
if (type == PT_LAVA && IsElement(ctype))
{
sampleInfo << "Molten " << ElementResolve(ctype, -1);
}
else if ((type == PT_PIPE || type == PT_PPIP) && IsElement(ctype))
{
if (ctype == PT_LAVA && IsElement(storedCtype))
{
sampleInfo << ElementResolve(type, -1) << " with molten " << ElementResolve(storedCtype, -1);
}
else
{
sampleInfo << ElementResolve(type, -1) << " with " << ElementResolve(ctype, storedCtype);
}
}
else
{
sampleInfo << ElementResolve(type, ctype);
}
return sampleInfo.Build();
}
int SimulationData::GetParticleType(ByteString type) const
{
type = type.ToUpper();
// alternative names for some elements
if (byteStringEqualsLiteral(type, "C4"))
{
return PT_PLEX;
}
else if (byteStringEqualsLiteral(type, "C5"))
{
return PT_C5;
}
else if (byteStringEqualsLiteral(type, "NONE"))
{
return PT_NONE;
}
for (int i = 1; i < PT_NUM; i++)
{
if (elements[i].Name.size() && elements[i].Enabled && type == elements[i].Name.ToUtf8().ToUpper())
{
return i;
}
}
return -1;
}
SimulationData::SimulationData()
{
init_can_move();
msections = LoadMenus();
wtypes = LoadWalls();
elements = GetElements();
tools = GetTools();
}

View File

@ -1,8 +1,19 @@
#pragma once
#include "SimulationConfig.h"
#include "ElementDefs.h"
#include "common/ExplicitSingleton.h"
#include "common/String.h"
#include "MenuSection.h"
#include "BuiltinGOL.h"
#include "SimTool.h"
#include "Element.h"
#include "Particle.h"
#include "WallType.h"
#include "graphics/gcache_item.h"
#include <cstdint>
#include <vector>
#include <array>
#include <shared_mutex>
constexpr int SC_WALL = 0;
constexpr int SC_ELEC = 1;
@ -148,20 +159,61 @@ enum GravityMode
GRAV_VERTICAL, GRAV_OFF, GRAV_RADIAL, GRAV_CUSTOM, NUM_GRAV_MODES
};
struct part_type;
struct part_transition;
struct CustomGOLData
{
int rule, colour1, colour2;
String nameString, ruleString;
struct wall_type;
struct BuiltinGOL;
struct menu_section;
inline bool operator <(const CustomGOLData &other) const
{
return rule < other.rule;
}
};
class SimTool;
class Element;
class SimulationData : public ExplicitSingleton<SimulationData>
{
public:
std::array<Element, PT_NUM> elements;
std::array<gcache_item, PT_NUM> graphicscache;
std::vector<SimTool> tools;
std::vector<wall_type> wtypes;
std::vector<menu_section> msections;
char can_move[PT_NUM][PT_NUM];
static const std::array<BuiltinGOL, NGOL> builtinGol;
extern const BuiltinGOL builtinGol[];
// Element properties that enable basic graphics (i.e. every property that has to do with graphics other than
// the graphics callback itself) are only ever written by the main thread, but they are read by some other
// threads that use Renderer to render thumbnails and such. Take this std::shared_mutex with an std::unique_lock
// when writing such properties in the main thread, and with an std::shared_lock when reading such properties
// in these secondary Renderer threads. Don't take it with an std::shared_lock when reading such properties in
// the main thread; the main thread doesn't race with itself.
mutable std::shared_mutex elementGraphicsMx;
std::vector<wall_type> LoadWalls();
private:
std::vector<CustomGOLData> customGol;
std::vector<menu_section> LoadMenus();
public:
SimulationData();
void InitElements();
std::vector<unsigned int> LoadLatent();
void init_can_move();
const CustomGOLData *GetCustomGOLByRule(int rule) const;
const std::vector<CustomGOLData> &GetCustomGol() const { return customGol; }
void SetCustomGOL(std::vector<CustomGOLData> newCustomGol);
String ElementResolve(int type, int ctype) const;
String BasicParticleInfo(Particle const &sample_part) const;
int GetParticleType(ByteString type) const;
bool IsElement(int type) const
{
return (type > 0 && type < PT_NUM && elements[type].Enabled);
}
bool IsElementOrNone(int type) const
{
return (type >= 0 && type < PT_NUM && elements[type].Enabled);
}
};

View File

@ -49,6 +49,8 @@ void Element::Element_ACEL()
static int update(UPDATE_FUNC_ARGS)
{
auto &sd = SimulationData::CRef();
auto &elements = sd.elements;
float multiplier;
if (parts[i].life!=0)
{
@ -71,7 +73,7 @@ static int update(UPDATE_FUNC_ARGS)
r = sim->photons[y+ry][x+rx];
if (!r)
continue;
if(sim->elements[TYP(r)].Properties & (TYPE_PART | TYPE_LIQUID | TYPE_GAS | TYPE_ENERGY))
if(elements[TYP(r)].Properties & (TYPE_PART | TYPE_LIQUID | TYPE_GAS | TYPE_ENERGY))
{
parts[ID(r)].vx *= multiplier;
parts[ID(r)].vy *= multiplier;

View File

@ -52,6 +52,8 @@ void Element::Element_ACID()
static int update(UPDATE_FUNC_ARGS)
{
auto &sd = SimulationData::CRef();
auto &elements = sd.elements;
for (auto rx = -2; rx <= 2; rx++)
{
for (auto ry = -2; ry <= 2; ry++)
@ -80,11 +82,11 @@ static int update(UPDATE_FUNC_ARGS)
sim->kill_part(ID(r));
}
}
else if (rt != PT_CLNE && rt != PT_PCLN && parts[i].life >= 50 && sim->rng.chance(sim->elements[rt].Hardness, 1000))
else if (rt != PT_CLNE && rt != PT_PCLN && parts[i].life >= 50 && sim->rng.chance(elements[rt].Hardness, 1000))
{
if (sim->parts_avg(i, ID(r),PT_GLAS)!= PT_GLAS)//GLAS protects stuff from acid
{
float newtemp = ((60.0f-(float)sim->elements[rt].Hardness))*7.0f;
float newtemp = ((60.0f-(float)elements[rt].Hardness))*7.0f;
if(newtemp < 0){
newtemp = 0;
}

View File

@ -1,4 +1,5 @@
#include "simulation/ElementCommon.h"
#include "FILT.h"
static int update(UPDATE_FUNC_ARGS);
@ -47,6 +48,8 @@ void Element::Element_ARAY()
static int update(UPDATE_FUNC_ARGS)
{
auto &sd = SimulationData::CRef();
auto &elements = sd.elements;
int short_bray_life = parts[i].life > 0 ? parts[i].life : 30;
int long_bray_life = parts[i].life > 0 ? parts[i].life : 1020;
for (int rx = -1; rx <= 1; rx++)
@ -128,7 +131,6 @@ static int update(UPDATE_FUNC_ARGS)
{
if (parts[r].tmp != 6)
{
int Element_FILT_interactWavelengths(Simulation *sim, Particle* cpart, int origWl);
colored = Element_FILT_interactWavelengths(sim, &parts[r], colored);
if (!colored)
break;
@ -170,7 +172,7 @@ static int update(UPDATE_FUNC_ARGS)
if (nyy!=0 || nxx!=0)
sim->create_part(-1, x+nxi+nxx, y+nyi+nyy, PT_SPRK);
if (!(nostop && parts[r].type==PT_SPRK && parts[r].ctype >= 0 && parts[r].ctype < PT_NUM && (sim->elements[parts[r].ctype].Properties&PROP_CONDUCTS)))
if (!(nostop && parts[r].type==PT_SPRK && parts[r].ctype >= 0 && parts[r].ctype < PT_NUM && (elements[parts[r].ctype].Properties&PROP_CONDUCTS)))
docontinue = 0;
else
docontinue = 1;

View File

@ -51,6 +51,8 @@ constexpr float ADVECTION = 0.1f;
static int update(UPDATE_FUNC_ARGS)
{
auto &sd = SimulationData::CRef();
auto &elements = sd.elements;
if (!parts[i].life && sim->pv[y/CELL][x/CELL]>4.0f)
parts[i].life = sim->rng.between(80, 119);
if (parts[i].life)
@ -58,7 +60,7 @@ static int update(UPDATE_FUNC_ARGS)
parts[i].vx += ADVECTION*sim->vx[y/CELL][x/CELL];
parts[i].vy += ADVECTION*sim->vy[y/CELL][x/CELL];
}
if (parts[i].ctype<=0 || parts[i].ctype>=PT_NUM || !sim->elements[parts[i].ctype].Enabled)
if (parts[i].ctype<=0 || parts[i].ctype>=PT_NUM || !elements[parts[i].ctype].Enabled)
{
for (auto rx = -1; rx <= 1; rx++)
{
@ -90,7 +92,7 @@ static int update(UPDATE_FUNC_ARGS)
int np = sim->create_part(-1, x + sim->rng.between(-1, 1), y + sim->rng.between(-1, 1), TYP(parts[i].ctype));
if (np>=0)
{
if (parts[i].ctype==PT_LAVA && parts[i].tmp>0 && parts[i].tmp<PT_NUM && sim->elements[parts[i].tmp].HighTemperatureTransition==PT_LAVA)
if (parts[i].ctype==PT_LAVA && parts[i].tmp>0 && parts[i].tmp<PT_NUM && elements[parts[i].tmp].HighTemperatureTransition==PT_LAVA)
parts[np].ctype = parts[i].tmp;
}
}

View File

@ -1,7 +1,5 @@
#include "simulation/ElementCommon.h"
int Element_COAL_update(UPDATE_FUNC_ARGS);
int Element_COAL_graphics(GRAPHICS_FUNC_ARGS);
#include "COAL.h"
void Element::Element_BCOL()
{

View File

@ -1,7 +1,5 @@
#include "simulation/ElementCommon.h"
int Element_BIZR_update(UPDATE_FUNC_ARGS);
int Element_BIZR_graphics(GRAPHICS_FUNC_ARGS);
#include "BIZR.h"
void Element::Element_BIZR()
{

View File

@ -0,0 +1,5 @@
#pragma once
#include "simulation/ElementDefs.h"
int Element_BIZR_graphics(GRAPHICS_FUNC_ARGS);
int Element_BIZR_update(UPDATE_FUNC_ARGS);

View File

@ -1,7 +1,5 @@
#include "simulation/ElementCommon.h"
int Element_BIZR_update(UPDATE_FUNC_ARGS);
int Element_BIZR_graphics(GRAPHICS_FUNC_ARGS);
#include "BIZR.h"
void Element::Element_BIZRG()
{

View File

@ -1,7 +1,5 @@
#include "simulation/ElementCommon.h"
int Element_BIZR_update(UPDATE_FUNC_ARGS);
int Element_BIZR_graphics(GRAPHICS_FUNC_ARGS);
#include "BIZR.h"
void Element::Element_BIZRS()
{

View File

@ -47,6 +47,8 @@ void Element::Element_BTRY()
static int update(UPDATE_FUNC_ARGS)
{
auto &sd = SimulationData::CRef();
auto &elements = sd.elements;
for (auto rx = -2; rx <= 2; rx++)
{
for (auto ry = -2; ry <= 2; ry++)
@ -59,7 +61,7 @@ static int update(UPDATE_FUNC_ARGS)
auto rt = TYP(r);
if (sim->parts_avg(i,ID(r),PT_INSL) != PT_INSL)
{
if ((sim->elements[rt].Properties&PROP_CONDUCTS) && !(rt==PT_WATR||rt==PT_SLTW||rt==PT_NTCT||rt==PT_PTCT||rt==PT_INWR) && parts[ID(r)].life==0)
if ((elements[rt].Properties&PROP_CONDUCTS) && !(rt==PT_WATR||rt==PT_SLTW||rt==PT_NTCT||rt==PT_PTCT||rt==PT_INWR) && parts[ID(r)].life==0)
{
parts[ID(r)].life = 4;
parts[ID(r)].ctype = rt;

View File

@ -1,7 +1,5 @@
#include "simulation/ElementCommon.h"
int Element_VIBR_update(UPDATE_FUNC_ARGS);
int Element_VIBR_graphics(GRAPHICS_FUNC_ARGS);
#include "VIBR.h"
void Element::Element_BVBR()
{

View File

@ -49,6 +49,8 @@ void Element::Element_C5()
static int update(UPDATE_FUNC_ARGS)
{
auto &sd = SimulationData::CRef();
auto &elements = sd.elements;
for (auto rx = -2; rx <= 2; rx++)
{
for (auto ry = -2; ry <= 2; ry++)
@ -58,7 +60,7 @@ static int update(UPDATE_FUNC_ARGS)
auto r = pmap[y+ry][x+rx];
if (!r)
continue;
if ((TYP(r)!=PT_C5 && parts[ID(r)].temp<100 && sim->elements[TYP(r)].HeatConduct && (TYP(r)!=PT_HSWC||parts[ID(r)].life==10)) || TYP(r)==PT_CFLM)
if ((TYP(r)!=PT_C5 && parts[ID(r)].temp<100 && elements[TYP(r)].HeatConduct && (TYP(r)!=PT_HSWC||parts[ID(r)].life==10)) || TYP(r)==PT_CFLM)
{
if (sim->rng.chance(1, 6))
{

View File

@ -49,6 +49,8 @@ void Element::Element_CAUS()
static int update(UPDATE_FUNC_ARGS)
{
auto &sd = SimulationData::CRef();
auto &elements = sd.elements;
for (int rx = -2; rx <= 2; rx++)
{
for (int ry = -2; ry <= 2; ry++)
@ -68,12 +70,12 @@ static int update(UPDATE_FUNC_ARGS)
}
else if (TYP(r) != PT_ACID && TYP(r) != PT_CAUS && TYP(r) != PT_RFRG && TYP(r) != PT_RFGL)
{
if ((TYP(r) != PT_CLNE && TYP(r) != PT_PCLN && sim->rng.chance(sim->elements[TYP(r)].Hardness, 1000)) && parts[i].life >= 50)
if ((TYP(r) != PT_CLNE && TYP(r) != PT_PCLN && sim->rng.chance(elements[TYP(r)].Hardness, 1000)) && parts[i].life >= 50)
{
// GLAS protects stuff from acid
if (sim->parts_avg(i, ID(r),PT_GLAS) != PT_GLAS)
{
float newtemp = ((60.0f - (float)sim->elements[TYP(r)].Hardness)) * 7.0f;
float newtemp = ((60.0f - (float)elements[TYP(r)].Hardness)) * 7.0f;
if (newtemp < 0)
newtemp = 0;
parts[i].temp += newtemp;

View File

@ -31,6 +31,7 @@ void Element::Element_CBNW()
DefaultProperties.temp = R_TEMP - 2.0f + 273.15f;
HeatConduct = 29;
LatentHeat = 7500;
Description = "Carbonated water. Slowly releases CO2.";
Properties = TYPE_LIQUID|PROP_CONDUCTS|PROP_LIFE_DEC|PROP_NEUTPENETRATE;
@ -50,6 +51,8 @@ void Element::Element_CBNW()
static int update(UPDATE_FUNC_ARGS)
{
auto &sd = SimulationData::CRef();
auto &elements = sd.elements;
if (sim->pv[y/CELL][x/CELL]<=3)
{
if (sim->pv[y/CELL][x/CELL] <= -0.5 || sim->rng.chance(1, 4000))
@ -87,12 +90,12 @@ static int update(UPDATE_FUNC_ARGS)
auto r = pmap[y+ry][x+rx];
if (!r)
continue;
if ((sim->elements[TYP(r)].Properties&TYPE_PART) && parts[i].tmp == 0 && sim->rng.chance(1, 83))
if ((elements[TYP(r)].Properties&TYPE_PART) && parts[i].tmp == 0 && sim->rng.chance(1, 83))
{
//Start explode
parts[i].tmp = sim->rng.between(0, 24);
}
else if((sim->elements[TYP(r)].Properties&TYPE_SOLID) && TYP(r)!=PT_DMND && TYP(r)!=PT_GLAS && parts[i].tmp == 0 && sim->rng.chance(int(2 - sim->pv[y/CELL][x/CELL]), 6667))
else if((elements[TYP(r)].Properties&TYPE_SOLID) && TYP(r)!=PT_DMND && TYP(r)!=PT_GLAS && parts[i].tmp == 0 && sim->rng.chance(int(2 - sim->pv[y/CELL][x/CELL]), 6667))
{
sim->part_change_type(i,x,y,PT_CO2);
parts[i].ctype = 5;

View File

@ -49,7 +49,9 @@ void Element::Element_CLNE()
static int update(UPDATE_FUNC_ARGS)
{
if (parts[i].ctype<=0 || parts[i].ctype>=PT_NUM || !sim->elements[parts[i].ctype].Enabled)
auto &sd = SimulationData::CRef();
auto &elements = sd.elements;
if (parts[i].ctype<=0 || parts[i].ctype>=PT_NUM || !elements[parts[i].ctype].Enabled)
{
for (auto rx = -1; rx <= 1; rx++)
{
@ -81,7 +83,7 @@ static int update(UPDATE_FUNC_ARGS)
int np = sim->create_part(-1, x + sim->rng.between(-1, 1), y + sim->rng.between(-1, 1), TYP(parts[i].ctype));
if (np>=0)
{
if (parts[i].ctype==PT_LAVA && parts[i].tmp>0 && parts[i].tmp<PT_NUM && sim->elements[parts[i].tmp].HighTemperatureTransition==PT_LAVA)
if (parts[i].ctype==PT_LAVA && parts[i].tmp>0 && parts[i].tmp<PT_NUM && elements[parts[i].tmp].HighTemperatureTransition==PT_LAVA)
parts[np].ctype = parts[i].tmp;
}
}

View File

@ -1,7 +1,5 @@
#include "simulation/ElementCommon.h"
int Element_COAL_update(UPDATE_FUNC_ARGS);
int Element_COAL_graphics(GRAPHICS_FUNC_ARGS);
#include "COAL.h"
void Element::Element_COAL()
{

View File

@ -0,0 +1,5 @@
#pragma once
#include "simulation/ElementDefs.h"
int Element_COAL_graphics(GRAPHICS_FUNC_ARGS);
int Element_COAL_update(UPDATE_FUNC_ARGS);

View File

@ -49,8 +49,10 @@ void Element::Element_CONV()
static int update(UPDATE_FUNC_ARGS)
{
auto &sd = SimulationData::CRef();
auto &elements = sd.elements;
int ctype = TYP(parts[i].ctype);
if (ctype<=0 || ctype>=PT_NUM || !sim->elements[ctype].Enabled || ctype==PT_CONV)
if (ctype<=0 || ctype>=PT_NUM || !elements[ctype].Enabled || ctype==PT_CONV)
{
for (auto rx = -1; rx <= 1; rx++)
{
@ -76,7 +78,7 @@ static int update(UPDATE_FUNC_ARGS)
}
else
{
int restrictElement = sim->IsElement(parts[i].tmp) ? parts[i].tmp : 0;
int restrictElement = sd.IsElement(parts[i].tmp) ? parts[i].tmp : 0;
for (auto rx = -1; rx <= 1; rx++)
{
for (auto ry = -1; ry <= 1; ry++)

View File

@ -1,4 +1,5 @@
#include "simulation/ElementCommon.h"
#include "FILT.h"
static int update(UPDATE_FUNC_ARGS);
static bool ctypeDraw(CTYPEDRAW_FUNC_ARGS);
@ -51,9 +52,11 @@ void Element::Element_CRAY()
static int update(UPDATE_FUNC_ARGS)
{
auto &sd = SimulationData::CRef();
auto &elements = sd.elements;
int nxx, nyy, docontinue, nxi, nyi;
// set ctype to things that touch it if it doesn't have one already
if (parts[i].ctype<=0 || !sim->elements[TYP(parts[i].ctype)].Enabled)
if (parts[i].ctype<=0 || !elements[TYP(parts[i].ctype)].Enabled)
{
for (int rx = -1; rx <= 1; rx++)
{
@ -114,7 +117,6 @@ static int update(UPDATE_FUNC_ARGS)
colored = 0xFF000000;
else if (parts[ID(r)].tmp==0)
{
int Element_FILT_getWavelengths(Particle* cpart);
colored = wavelengthToDecoColour(Element_FILT_getWavelengths(&parts[ID(r)]));
}
else if (colored==0xFF000000)
@ -166,6 +168,8 @@ static unsigned int wavelengthToDecoColour(int wavelength)
static bool ctypeDraw(CTYPEDRAW_FUNC_ARGS)
{
auto &sd = SimulationData::CRef();
auto &elements = sd.elements;
if (!Element::ctypeDrawVInCtype(CTYPEDRAW_FUNC_SUBCALL_ARGS))
{
return false;
@ -174,6 +178,6 @@ static bool ctypeDraw(CTYPEDRAW_FUNC_ARGS)
{
sim->parts[i].ctype |= PMAPID(30);
}
sim->parts[i].temp = sim->elements[t].DefaultProperties.temp;
sim->parts[i].temp = elements[t].DefaultProperties.temp;
return true;
}

View File

@ -49,6 +49,8 @@ void Element::Element_DCEL()
static int update(UPDATE_FUNC_ARGS)
{
auto &sd = SimulationData::CRef();
auto &elements = sd.elements;
float multiplier = 1.0f/1.1f;
if (parts[i].life!=0)
{
@ -66,7 +68,7 @@ static int update(UPDATE_FUNC_ARGS)
r = sim->photons[y+ry][x+rx];
if (!r)
continue;
if (sim->elements[TYP(r)].Properties & (TYPE_PART | TYPE_LIQUID | TYPE_GAS | TYPE_ENERGY))
if (elements[TYP(r)].Properties & (TYPE_PART | TYPE_LIQUID | TYPE_GAS | TYPE_ENERGY))
{
parts[ID(r)].vx *= multiplier;
parts[ID(r)].vy *= multiplier;

View File

@ -49,6 +49,8 @@ void Element::Element_DEST()
static int update(UPDATE_FUNC_ARGS)
{
auto &sd = SimulationData::CRef();
auto &elements = sd.elements;
int rx = sim->rng.between(-2, 2);
int ry = sim->rng.between(-2, 2);
int r = pmap[y+ry][x+rx];
@ -81,11 +83,11 @@ static int update(UPDATE_FUNC_ARGS)
else if (sim->rng.chance(1, 3))
{
sim->kill_part(ID(r));
parts[i].life -= 4*((sim->elements[rt].Properties&TYPE_SOLID)?3:1);
parts[i].life -= 4*((elements[rt].Properties&TYPE_SOLID)?3:1);
if (parts[i].life<=0)
parts[i].life=1;
}
else if (sim->elements[rt].HeatConduct)
else if (elements[rt].HeatConduct)
parts[ID(r)].temp = MAX_TEMP;
parts[i].temp=MAX_TEMP;
sim->pv[y/CELL][x/CELL]+=80.0f;

View File

@ -50,6 +50,8 @@ void Element::Element_DMG()
static int update(UPDATE_FUNC_ARGS)
{
auto &sd = SimulationData::CRef();
auto &elements = sd.elements;
int rad = 25;
for (auto rx = -1; rx <= 1; rx++)
{
@ -84,8 +86,8 @@ static int update(UPDATE_FUNC_ARGS)
sim->vy[(y+nxj)/CELL][(x+nxi)/CELL] += fy;
sim->pv[(y+nxj)/CELL][(x+nxi)/CELL] += 1.0f;
auto t = TYP(rr);
if (t && sim->elements[t].HighPressureTransition>-1 && sim->elements[t].HighPressureTransition<PT_NUM)
sim->part_change_type(ID(rr), x+nxi, y+nxj, sim->elements[t].HighPressureTransition);
if (t && elements[t].HighPressureTransition>-1 && elements[t].HighPressureTransition<PT_NUM)
sim->part_change_type(ID(rr), x+nxi, y+nxj, elements[t].HighPressureTransition);
else if (t == PT_BMTL)
sim->part_change_type(ID(rr), x+nxi, y+nxj, PT_BRMT);
else if (t == PT_GLAS)

View File

@ -50,6 +50,8 @@ void Element::Element_DRAY()
static int update(UPDATE_FUNC_ARGS)
{
auto &sd = SimulationData::CRef();
auto &elements = sd.elements;
int ctype = TYP(parts[i].ctype), ctypeExtra = ID(parts[i].ctype), copyLength = parts[i].tmp, copySpaces = parts[i].tmp2;
if (copySpaces < 0)
copySpaces = parts[i].tmp2 = 0;
@ -98,7 +100,7 @@ static int update(UPDATE_FUNC_ARGS)
foundParticle = true;
}
// now that it knows what kind of particle it is copying, do some extra stuff here so we can determine when to stop
if ((ctype && sim->elements[ctype].Properties&TYPE_ENERGY) || isEnergy)
if ((ctype && elements[ctype].Properties&TYPE_ENERGY) || isEnergy)
rr = sim->photons[yCurrent][xCurrent];
else
rr = pmap[yCurrent][xCurrent];

View File

@ -30,6 +30,7 @@ void Element::Element_DSTW()
DefaultProperties.temp = R_TEMP - 2.0f + 273.15f;
HeatConduct = 23;
LatentHeat = 7500;
Description = "Distilled water, does not conduct electricity.";
Properties = TYPE_LIQUID|PROP_NEUTPASS;

View File

@ -51,6 +51,8 @@ void Element::Element_DTEC()
static int update(UPDATE_FUNC_ARGS)
{
auto &sd = SimulationData::CRef();
auto &elements = sd.elements;
int rd = parts[i].tmp2;
if (rd > 25) parts[i].tmp2 = rd = 25;
if (parts[i].life)
@ -68,7 +70,7 @@ static int update(UPDATE_FUNC_ARGS)
auto rt = TYP(r);
if (sim->parts_avg(i,ID(r),PT_INSL) != PT_INSL)
{
if ((sim->elements[rt].Properties&PROP_CONDUCTS) && !(rt==PT_WATR||rt==PT_SLTW||rt==PT_NTCT||rt==PT_PTCT||rt==PT_INWR) && parts[ID(r)].life==0)
if ((elements[rt].Properties&PROP_CONDUCTS) && !(rt==PT_WATR||rt==PT_SLTW||rt==PT_NTCT||rt==PT_PTCT||rt==PT_INWR) && parts[ID(r)].life==0)
{
parts[ID(r)].life = 4;
parts[ID(r)].ctype = rt;

View File

@ -52,6 +52,8 @@ void Element::Element_ELEC()
static int update(UPDATE_FUNC_ARGS)
{
auto &sd = SimulationData::CRef();
auto &elements = sd.elements;
for (auto rx = -2; rx <= 2; rx++)
{
for (auto ry = -2; ry <= 2; ry++)
@ -118,7 +120,7 @@ static int update(UPDATE_FUNC_ARGS)
case PT_NONE: //seems to speed up ELEC even if it isn't used
break;
default:
if ((sim->elements[rt].Properties & PROP_CONDUCTS) && (rt!=PT_NBLE||parts[i].temp<2273.15))
if ((elements[rt].Properties & PROP_CONDUCTS) && (rt!=PT_NBLE||parts[i].temp<2273.15))
{
sim->create_part(-1, x+rx, y+ry, PT_SPRK);
sim->kill_part(i);

View File

@ -52,6 +52,8 @@ void Element::Element_EMBR()
static int update(UPDATE_FUNC_ARGS)
{
auto &sd = SimulationData::CRef();
auto &elements = sd.elements;
for (auto rx = -1; rx <= 1; rx++)
{
for (auto ry = -1; ry <= 1; ry++)
@ -61,7 +63,7 @@ static int update(UPDATE_FUNC_ARGS)
auto r = pmap[y+ry][x+rx];
if (!r)
continue;
if ((sim->elements[TYP(r)].Properties & (TYPE_SOLID | TYPE_PART | TYPE_LIQUID)) && !(sim->elements[TYP(r)].Properties & PROP_SPARKSETTLE))
if ((elements[TYP(r)].Properties & (TYPE_SOLID | TYPE_PART | TYPE_LIQUID)) && !(elements[TYP(r)].Properties & PROP_SPARKSETTLE))
{
sim->kill_part(i);
return 1;
@ -98,9 +100,9 @@ static int graphics(GRAPHICS_FUNC_ARGS)
}
bool deco = false;
if (ren->decorations_enable && cpart->dcolour && (cpart->dcolour&0xFF000000))
if (gfctx.ren->decorations_enable && cpart->dcolour && (cpart->dcolour&0xFF000000))
{
if (!ren->blackDecorations) // if blackDecorations is off, always show deco
if (!gfctx.ren->blackDecorations) // if blackDecorations is off, always show deco
deco = true;
else if (((cpart->dcolour>>24)&0xFF) >= 250 && ((cpart->dcolour>>16)&0xFF) <= 5 && ((cpart->dcolour>>8)&0xFF) <= 5 && ((cpart->dcolour)&0xFF) <= 5) // else only render black deco
deco = true;

View File

@ -0,0 +1,4 @@
#pragma once
#include "simulation/ElementDefs.h"
void Element_EMP_Trigger(Simulation *sim, int triggerCount);

View File

@ -0,0 +1,4 @@
#pragma once
#include "simulation/ElementDefs.h"
int Element_ETRD_nearestSparkablePart(Simulation *sim, int targetId);

View File

@ -196,7 +196,7 @@ static int graphics(GRAPHICS_FUNC_ARGS)
auto c = cpart->tmp2;
if (cpart->life < 1001)
{
if (ren->rng.chance(cpart->tmp2 - 1, 1000))
if (gfctx.rng.chance(cpart->tmp2 - 1, 1000))
{
float frequency = 0.04045f;
*colr = int(sin(frequency*c + 4) * 127 + 150);

View File

@ -1,15 +1,10 @@
#include "simulation/ElementCommon.h"
#include "STKM.h"
static int update(UPDATE_FUNC_ARGS);
static bool createAllowed(ELEMENT_CREATE_ALLOWED_FUNC_ARGS);
static void changeType(ELEMENT_CHANGETYPE_FUNC_ARGS);
static void Free(Simulation *sim, unsigned char i);
bool Element_FIGH_CanAlloc(Simulation *sim);
int Element_FIGH_Alloc(Simulation *sim);
void Element_FIGH_NewFighter(Simulation *sim, int fighterID, int i, int elem);
int Element_STKM_graphics(GRAPHICS_FUNC_ARGS);
void Element_STKM_init_legs(Simulation * sim, playerst *playerp, int i);
int Element_STKM_run_stickman(playerst *playerp, UPDATE_FUNC_ARGS);
void Element::Element_FIGH()
{
@ -64,6 +59,8 @@ void Element::Element_FIGH()
static int update(UPDATE_FUNC_ARGS)
{
auto &sd = SimulationData::CRef();
auto &elements = sd.elements;
if (parts[i].tmp < 0 || parts[i].tmp >= MAX_FIGHTERS)
{
sim->kill_part(i);
@ -104,8 +101,8 @@ static int update(UPDATE_FUNC_ARGS)
if ((pow(float(tarx-x), 2) + pow(float(tary-y), 2))<600)
{
if (figh->elem == PT_LIGH || figh->elem == PT_NEUT
|| sim->elements[figh->elem].Properties & (PROP_DEADLY | PROP_RADIOACTIVE)
|| sim->elements[figh->elem].DefaultProperties.temp >= 323 || sim->elements[figh->elem].DefaultProperties.temp <= 243)
|| elements[figh->elem].Properties & (PROP_DEADLY | PROP_RADIOACTIVE)
|| elements[figh->elem].DefaultProperties.temp >= 323 || elements[figh->elem].DefaultProperties.temp <= 243)
figh->comm = (int)figh->comm | 0x08;
}
else if (tarx<x)

View File

@ -1,9 +1,8 @@
#include "simulation/ElementCommon.h"
#include "FILT.h"
static int graphics(GRAPHICS_FUNC_ARGS);
static void create(ELEMENT_CREATE_FUNC_ARGS);
int Element_FILT_interactWavelengths(Simulation *sim, Particle* cpart, int origWl);
int Element_FILT_getWavelengths(Particle* cpart);
void Element::Element_FILT()
{
@ -135,7 +134,7 @@ int Element_FILT_interactWavelengths(Simulation *sim, Particle* cpart, int origW
}
}
int Element_FILT_getWavelengths(Particle* cpart)
int Element_FILT_getWavelengths(const Particle* cpart)
{
if (cpart->ctype&0x3FFFFFFF)
{

View File

@ -0,0 +1,5 @@
#pragma once
#include "simulation/ElementDefs.h"
int Element_FILT_getWavelengths(const Particle* cpart);
int Element_FILT_interactWavelengths(Simulation *sim, Particle* cpart, int origWl);

View File

@ -1,7 +1,7 @@
#include "simulation/ElementCommon.h"
#include "FIRE.h"
#include <algorithm>
int Element_FIRE_update(UPDATE_FUNC_ARGS);
static int updateLegacy(UPDATE_FUNC_ARGS);
static int graphics(GRAPHICS_FUNC_ARGS);
static void create(ELEMENT_CREATE_FUNC_ARGS);
@ -54,6 +54,8 @@ void Element::Element_FIRE()
int Element_FIRE_update(UPDATE_FUNC_ARGS)
{
auto &sd = SimulationData::CRef();
auto &elements = sd.elements;
int t = parts[i].type;
switch (t)
{
@ -131,7 +133,7 @@ int Element_FIRE_update(UPDATE_FUNC_ARGS)
}
}
}
else if ((parts[i].ctype == PT_STNE || !parts[i].ctype) && pres >= 30.0f && (parts[i].temp > sim->elements[PT_ROCK].HighTemperature || pres < sim->elements[PT_ROCK].HighPressure)) // Form ROCK with pressure, if it will stay molten or not immediately break
else if ((parts[i].ctype == PT_STNE || !parts[i].ctype) && pres >= 30.0f && (parts[i].temp > elements[PT_ROCK].HighTemperature || pres < elements[PT_ROCK].HighPressure)) // Form ROCK with pressure, if it will stay molten or not immediately break
{
parts[i].tmp2 = sim->rng.between(0, 10); // Provide tmp2 for color noise
parts[i].ctype = PT_ROCK;
@ -207,7 +209,7 @@ int Element_FIRE_update(UPDATE_FUNC_ARGS)
if (parts[i].ctype == PT_QRTZ && rt == PT_LAVA && parts[ID(r)].ctype == PT_CLST)
{
float pres = std::max(sim->pv[y/CELL][x/CELL]*10.0f, 0.0f);
if (parts[i].temp >= pres+sim->elements[PT_CRMC].HighTemperature+50.0f)
if (parts[i].temp >= pres+elements[PT_CRMC].HighTemperature+50.0f)
{
parts[i].ctype = PT_CRMC;
parts[ID(r)].ctype = PT_CRMC;
@ -224,7 +226,7 @@ int Element_FIRE_update(UPDATE_FUNC_ARGS)
case 1:
parts[i].ctype = PT_CLST;
// avoid creating CRMC.
if (parts[i].temp >= sim->elements[PT_PQRT].HighTemperature * 3)
if (parts[i].temp >= elements[PT_PQRT].HighTemperature * 3)
{
parts[i].ctype = PT_PQRT;
}
@ -246,7 +248,7 @@ int Element_FIRE_update(UPDATE_FUNC_ARGS)
}
else if (rt == PT_HEAC && parts[i].ctype == PT_HEAC)
{
if (parts[ID(r)].temp > sim->elements[PT_HEAC].HighTemperature)
if (parts[ID(r)].temp > elements[PT_HEAC].HighTemperature)
{
sim->part_change_type(ID(r), x+rx, y+ry, PT_LAVA);
parts[ID(r)].ctype = PT_HEAC;
@ -265,18 +267,18 @@ int Element_FIRE_update(UPDATE_FUNC_ARGS)
}
}
if ((surround_space || sim->elements[rt].Explosive) &&
sim->elements[rt].Flammable && sim->rng.chance(int(sim->elements[rt].Flammable + (sim->pv[(y+ry)/CELL][(x+rx)/CELL] * 10.0f)), 1000) &&
if ((surround_space || elements[rt].Explosive) &&
elements[rt].Flammable && sim->rng.chance(int(elements[rt].Flammable + (sim->pv[(y+ry)/CELL][(x+rx)/CELL] * 10.0f)), 1000) &&
//exceptions, t is the thing causing the spark and rt is what's burning
(t != PT_SPRK || (rt != PT_RBDM && rt != PT_LRBD && rt != PT_INSL)) &&
(t != PT_PHOT || rt != PT_INSL) &&
(rt != PT_SPNG || parts[ID(r)].life == 0))
{
sim->part_change_type(ID(r), x+rx, y+ry, PT_FIRE);
parts[ID(r)].temp = restrict_flt(sim->elements[PT_FIRE].DefaultProperties.temp + (sim->elements[rt].Flammable/2), MIN_TEMP, MAX_TEMP);
parts[ID(r)].temp = restrict_flt(elements[PT_FIRE].DefaultProperties.temp + (elements[rt].Flammable/2), MIN_TEMP, MAX_TEMP);
parts[ID(r)].life = sim->rng.between(180, 259);
parts[ID(r)].tmp = parts[ID(r)].ctype = 0;
if (sim->elements[rt].Explosive)
if (elements[rt].Explosive)
sim->pv[y/CELL][x/CELL] += 0.25f * CFDS;
}
}
@ -289,6 +291,8 @@ int Element_FIRE_update(UPDATE_FUNC_ARGS)
static int updateLegacy(UPDATE_FUNC_ARGS)
{
auto &sd = SimulationData::CRef();
auto &elements = sd.elements;
int t = parts[i].type;
for (auto rx = -2; rx <= 2; rx++)
{
@ -305,10 +309,10 @@ static int updateLegacy(UPDATE_FUNC_ARGS)
auto lpv = (int)sim->pv[(y+ry)/CELL][(x+rx)/CELL];
if (lpv < 1) lpv = 1;
if (sim->elements[rt].Meltable &&
if (elements[rt].Meltable &&
((rt!=PT_RBDM && rt!=PT_LRBD) || t!=PT_SPRK)
&& ((t!=PT_FIRE&&t!=PT_PLSM) || (rt!=PT_METL && rt!=PT_IRON && rt!=PT_ETRD && rt!=PT_PSCN && rt!=PT_NSCN && rt!=PT_NTCT && rt!=PT_PTCT && rt!=PT_BMTL && rt!=PT_BRMT && rt!=PT_SALT && rt!=PT_INWR))
&& sim->rng.chance(sim->elements[rt].Meltable*lpv, 1000))
&& sim->rng.chance(elements[rt].Meltable*lpv, 1000))
{
if (t!=PT_LAVA || parts[i].life>0)
{

View File

@ -0,0 +1,4 @@
#pragma once
#include "simulation/ElementDefs.h"
int Element_FIRE_update(UPDATE_FUNC_ARGS);

View File

@ -49,6 +49,8 @@ void Element::Element_FIRW()
static int update(UPDATE_FUNC_ARGS)
{
auto &sd = SimulationData::CRef();
auto &elements = sd.elements;
if (parts[i].tmp<=0)
{
for (auto rx = -1; rx <= 1; rx++)
@ -64,12 +66,12 @@ static int update(UPDATE_FUNC_ARGS)
if (rt==PT_FIRE||rt==PT_PLSM||rt==PT_THDR)
{
float gx, gy, multiplier;
sim->GetGravityField(x, y, sim->elements[PT_FIRW].Gravity, 1.0f, gx, gy);
sim->GetGravityField(x, y, elements[PT_FIRW].Gravity, 1.0f, gx, gy);
if (gx*gx+gy*gy < 0.001f)
{
float angle = sim->rng.between(0, 6283) * 0.001f;//(in radians, between 0 and 2*pi)
gx += sinf(angle)*sim->elements[PT_FIRW].Gravity*0.5f;
gy += cosf(angle)*sim->elements[PT_FIRW].Gravity*0.5f;
gx += sinf(angle)*elements[PT_FIRW].Gravity*0.5f;
gy += cosf(angle)*elements[PT_FIRW].Gravity*0.5f;
}
parts[i].tmp = 1;
parts[i].life = sim->rng.between(20, 29);

View File

@ -48,6 +48,8 @@ void Element::Element_FOG()
static int update(UPDATE_FUNC_ARGS)
{
auto &sd = SimulationData::CRef();
auto &elements = sd.elements;
for (auto rx = -1; rx <= 1; rx++)
{
for (auto ry = -1; ry <= 1; ry++)
@ -57,7 +59,7 @@ static int update(UPDATE_FUNC_ARGS)
auto r = pmap[y+ry][x+rx];
if (!r)
continue;
if ((sim->elements[TYP(r)].Properties&TYPE_SOLID) && sim->rng.chance(1, 10) && parts[i].life==0 && !(TYP(r)==PT_CLNE || TYP(r)==PT_PCLN)) // TODO: should this also exclude BCLN?
if ((elements[TYP(r)].Properties&TYPE_SOLID) && sim->rng.chance(1, 10) && parts[i].life==0 && !(TYP(r)==PT_CLNE || TYP(r)==PT_PCLN)) // TODO: should this also exclude BCLN?
{
sim->part_change_type(i,x,y,PT_RIME);
}

View File

@ -48,6 +48,8 @@ void Element::Element_FRAY()
static int update(UPDATE_FUNC_ARGS)
{
auto &sd = SimulationData::CRef();
auto &elements = sd.elements;
int curlen;
if (parts[i].tmp > 0)
curlen = parts[i].tmp;
@ -73,7 +75,7 @@ static int update(UPDATE_FUNC_ARGS)
r = pmap[y+nyi+nyy][x+nxi+nxx];
if (!r)
r = sim->photons[y+nyi+nyy][x+nxi+nxx];
if (r && !(sim->elements[TYP(r)].Properties & TYPE_SOLID)){
if (r && !(elements[TYP(r)].Properties & TYPE_SOLID)){
parts[ID(r)].vx += nxi*((parts[i].temp-273.15f)/10.0f);
parts[ID(r)].vy += nyi*((parts[i].temp-273.15f)/10.0f);
}

View File

@ -48,16 +48,18 @@ void Element::Element_FWRK()
static int update(UPDATE_FUNC_ARGS)
{
auto &sd = SimulationData::CRef();
auto &elements = sd.elements;
if (parts[i].life == 0 && ((surround_space && parts[i].temp>400 && sim->rng.chance(int(9+parts[i].temp/40), 100000)) || parts[i].ctype == PT_DUST))
{
float gx, gy, multiplier, gmax;
int randTmp;
sim->GetGravityField(x, y, sim->elements[PT_FWRK].Gravity, 1.0f, gx, gy);
sim->GetGravityField(x, y, elements[PT_FWRK].Gravity, 1.0f, gx, gy);
if (gx*gx+gy*gy < 0.001f)
{
float angle = sim->rng.between(0, 6283) * 0.001f;//(in radians, between 0 and 2*pi)
gx += sinf(angle)*sim->elements[PT_FWRK].Gravity*0.5f;
gy += cosf(angle)*sim->elements[PT_FWRK].Gravity*0.5f;
gx += sinf(angle)*elements[PT_FWRK].Gravity*0.5f;
gy += cosf(angle)*elements[PT_FWRK].Gravity*0.5f;
}
gmax = std::max(fabsf(gx), fabsf(gy));
if (sim->eval_move(PT_FWRK, (int)(x-(gx/gmax)+0.5f), (int)(y-(gy/gmax)+0.5f), NULL))

View File

@ -50,6 +50,8 @@ void Element::Element_GEL()
static int update(UPDATE_FUNC_ARGS)
{
auto &sd = SimulationData::CRef();
auto &elements = sd.elements;
if (parts[i].tmp > 100)
parts[i].tmp = 100;
if (parts[i].tmp < 0)
@ -133,17 +135,17 @@ static int update(UPDATE_FUNC_ARGS)
dy = parts[i].y - parts[ID(r)].y;
//Stickiness
if ((dx*dx + dy*dy)>1.5 && (gel || !sim->elements[rt].Falldown || (fabs((float)rx)<2 && fabs((float)ry)<2)))
if ((dx*dx + dy*dy)>1.5 && (gel || !elements[rt].Falldown || (fabs((float)rx)<2 && fabs((float)ry)<2)))
{
float per, nd;
nd = dx*dx + dy*dy - 0.5;
per = 5*(1 - parts[i].tmp/100)*(nd/(dx*dx + dy*dy + nd) - 0.5);
if (sim->elements[rt].Properties&TYPE_LIQUID)
if (elements[rt].Properties&TYPE_LIQUID)
per *= 0.1f;
dx *= per; dy *= per;
parts[i].vx += dx;
parts[i].vy += dy;
if ((sim->elements[rt].Properties&TYPE_PART) || rt==PT_GOO)
if ((elements[rt].Properties&TYPE_PART) || rt==PT_GOO)
{
parts[ID(r)].vx -= dx;
parts[ID(r)].vy -= dy;

View File

@ -90,7 +90,7 @@ static int graphics(GRAPHICS_FUNC_ARGS)
*colg = int(restrict_flt(64.0f+cpart->ctype, 0, 255));
*colb = int(restrict_flt(64.0f+cpart->tmp, 0, 255));
int rng = ren->rng.between(1, 32); //
int rng = gfctx.rng.between(1, 32); //
if(((*colr) + (*colg) + (*colb)) > (256 + rng)) {
*colr -= 54;
*colg -= 54;

View File

@ -99,7 +99,7 @@ static int update(UPDATE_FUNC_ARGS)
static int graphics(GRAPHICS_FUNC_ARGS)
{
int rndstore = ren->rng.gen();
int rndstore = gfctx.rng.gen();
*colr += (rndstore % 10) - 5;
rndstore >>= 4;
*colg += (rndstore % 10)- 5;

View File

@ -63,12 +63,12 @@ static int graphics(GRAPHICS_FUNC_ARGS)
{
int GRAV_R, GRAV_B, GRAV_G, GRAV_R2, GRAV_B2, GRAV_G2;
GRAV_R = std::abs((ren->sim->currentTick%120)-60);
GRAV_G = std::abs(((ren->sim->currentTick+60)%120)-60);
GRAV_B = std::abs(((ren->sim->currentTick+120)%120)-60);
GRAV_R2 = std::abs((ren->sim->currentTick%60)-30);
GRAV_G2 = std::abs(((ren->sim->currentTick+30)%60)-30);
GRAV_B2 = std::abs(((ren->sim->currentTick+60)%60)-30);
GRAV_R = std::abs((gfctx.sim->currentTick%120)-60);
GRAV_G = std::abs(((gfctx.sim->currentTick+60)%120)-60);
GRAV_B = std::abs(((gfctx.sim->currentTick+120)%120)-60);
GRAV_R2 = std::abs((gfctx.sim->currentTick%60)-30);
GRAV_G2 = std::abs(((gfctx.sim->currentTick+30)%60)-30);
GRAV_B2 = std::abs(((gfctx.sim->currentTick+60)%60)-30);
*colr = 20;

View File

@ -47,6 +47,8 @@ void Element::Element_H2()
static int update(UPDATE_FUNC_ARGS)
{
auto &sd = SimulationData::CRef();
auto &can_move = sd.can_move;
for (auto rx = -2; rx <= 2; rx++)
{
for (auto ry = -2; ry <= 2; ry++)
@ -119,7 +121,7 @@ static int update(UPDATE_FUNC_ARGS)
parts[j].tmp = 0x1;
}
auto rx = x + sim->rng.between(-1, 1), ry = y + sim->rng.between(-1, 1), rt = TYP(pmap[ry][rx]);
if (sim->can_move[PT_PLSM][rt] || rt == PT_H2)
if (can_move[PT_PLSM][rt] || rt == PT_H2)
{
j = sim->create_part(-3,rx,ry,PT_PLSM);
if (j>-1)

View File

@ -48,7 +48,8 @@ void Element::Element_HEAC()
}
static const auto isInsulator = [](Simulation* a, int b) -> bool {
return b && (a->elements[TYP(b)].HeatConduct == 0 || (TYP(b) == PT_HSWC && a->parts[ID(b)].life != 10));
auto &sd = SimulationData::CRef();
return b && (sd.elements[TYP(b)].HeatConduct == 0 || (TYP(b) == PT_HSWC && a->parts[ID(b)].life != 10));
};
// If this is used elsewhere (GOLD), it should be moved into Simulation.h
@ -118,6 +119,8 @@ bool CheckLine(Simulation* sim, int x1, int y1, int x2, int y2, BinaryPredicate
static int update(UPDATE_FUNC_ARGS)
{
auto &sd = SimulationData::CRef();
auto &elements = sd.elements;
const int rad = 4;
int rry, rrx, r, count = 0;
float tempAgg = 0;
@ -130,13 +133,13 @@ static int update(UPDATE_FUNC_ARGS)
if (x+rrx >= 0 && x+rrx < XRES && y+rry >= 0 && y+rry < YRES && !CheckLine(sim, x, y, x+rrx, y+rry, isInsulator))
{
r = pmap[y+rry][x+rrx];
if (r && sim->elements[TYP(r)].HeatConduct > 0 && (TYP(r) != PT_HSWC || parts[ID(r)].life == 10))
if (r && elements[TYP(r)].HeatConduct > 0 && (TYP(r) != PT_HSWC || parts[ID(r)].life == 10))
{
count++;
tempAgg += parts[ID(r)].temp;
}
r = sim->photons[y+rry][x+rrx];
if (r && sim->elements[TYP(r)].HeatConduct > 0 && (TYP(r) != PT_HSWC || parts[ID(r)].life == 10))
if (r && elements[TYP(r)].HeatConduct > 0 && (TYP(r) != PT_HSWC || parts[ID(r)].life == 10))
{
count++;
tempAgg += parts[ID(r)].temp;
@ -158,12 +161,12 @@ static int update(UPDATE_FUNC_ARGS)
if (x+rrx >= 0 && x+rrx < XRES && y+rry >= 0 && y+rry < YRES && !CheckLine(sim, x, y, x+rrx, y+rry, isInsulator))
{
r = pmap[y+rry][x+rrx];
if (r && sim->elements[TYP(r)].HeatConduct > 0 && (TYP(r) != PT_HSWC || parts[ID(r)].life == 10))
if (r && elements[TYP(r)].HeatConduct > 0 && (TYP(r) != PT_HSWC || parts[ID(r)].life == 10))
{
parts[ID(r)].temp = parts[i].temp;
}
r = sim->photons[y+rry][x+rrx];
if (r && sim->elements[TYP(r)].HeatConduct > 0 && (TYP(r) != PT_HSWC || parts[ID(r)].life == 10))
if (r && elements[TYP(r)].HeatConduct > 0 && (TYP(r) != PT_HSWC || parts[ID(r)].life == 10))
{
parts[ID(r)].temp = parts[i].temp;
}

View File

@ -30,6 +30,7 @@ void Element::Element_ICEI()
DefaultProperties.temp = R_TEMP - 50.0f + 273.15f;
HeatConduct = 46;
LatentHeat = 1095;
Description = "Crushes under pressure. Cools down air.";
Properties = TYPE_SOLID|PROP_LIFE_DEC|PROP_NEUTPASS;
@ -50,6 +51,8 @@ void Element::Element_ICEI()
static int update(UPDATE_FUNC_ARGS)
{
auto &sd = SimulationData::CRef();
auto &elements = sd.elements;
if (parts[i].ctype==PT_FRZW)//get colder if it is from FRZW
{
parts[i].temp = restrict_flt(parts[i].temp-1.0f, MIN_TEMP, MAX_TEMP);
@ -65,7 +68,7 @@ static int update(UPDATE_FUNC_ARGS)
continue;
if (TYP(r)==PT_SALT || TYP(r)==PT_SLTW)
{
if (parts[i].temp > sim->elements[PT_SLTW].LowTemperature && sim->rng.chance(1, 200))
if (parts[i].temp > elements[PT_SLTW].LowTemperature && sim->rng.chance(1, 200))
{
sim->part_change_type(i,x,y,PT_SLTW);
sim->part_change_type(ID(r),x+rx,y+ry,PT_SLTW);

View File

@ -1,6 +1,6 @@
#include "simulation/ElementCommon.h"
#include "FIRE.h"
int Element_FIRE_update(UPDATE_FUNC_ARGS);
static int graphics(GRAPHICS_FUNC_ARGS);
static void create(ELEMENT_CREATE_FUNC_ARGS);

View File

@ -107,9 +107,9 @@ static int update(UPDATE_FUNC_ARGS)
static int graphics(GRAPHICS_FUNC_ARGS)
{
bool deco = false;
if (ren->decorations_enable && cpart->dcolour && (cpart->dcolour&0xFF000000))
if (gfctx.ren->decorations_enable && cpart->dcolour && (cpart->dcolour&0xFF000000))
{
if (!ren->blackDecorations) // if blackDecorations is off, always show deco
if (!gfctx.ren->blackDecorations) // if blackDecorations is off, always show deco
deco = true;
else if(((cpart->dcolour>>24)&0xFF) >= 250 && ((cpart->dcolour>>16)&0xFF) <= 5 && ((cpart->dcolour>>8)&0xFF) <= 5 && ((cpart->dcolour)&0xFF) <= 5) // else only render black deco
deco = true;

View File

@ -1,5 +1,5 @@
#include "simulation/ElementCommon.h"
#include <iostream>
#include "FILT.h"
static int update(UPDATE_FUNC_ARGS);
@ -74,8 +74,10 @@ static bool phot_data_type(int rt)
*/
static bool accepted_conductor(Simulation* sim, int r)
{
auto &sd = SimulationData::CRef();
auto &elements = sd.elements;
int rt = TYP(r);
return (sim->elements[rt].Properties & PROP_CONDUCTS) &&
return (elements[rt].Properties & PROP_CONDUCTS) &&
!(rt == PT_WATR || rt == PT_SLTW || rt == PT_NTCT ||
rt == PT_PTCT || rt == PT_INWR) &&
sim->parts[ID(r)].life == 0;
@ -149,7 +151,6 @@ static int update(UPDATE_FUNC_ARGS)
continue;
int nx = x + rx, ny = y + ry;
int Element_FILT_getWavelengths(Particle* cpart);
int photonWl = TYP(rr) == PT_FILT ?
Element_FILT_getWavelengths(&parts[ID(rr)]) :
parts[ID(rr)].ctype;

View File

@ -50,6 +50,7 @@ void Element::Element_LIFE()
static int graphics(GRAPHICS_FUNC_ARGS)
{
auto &builtinGol = SimulationData::builtinGol;
auto colour1 = RGB<uint8_t>::Unpack(cpart->dcolour);
auto colour2 = RGB<uint8_t>::Unpack(cpart->tmp);
if (!cpart->dcolour)
@ -57,10 +58,10 @@ static int graphics(GRAPHICS_FUNC_ARGS)
colour1 = 0xFFFFFF_rgb;
}
auto ruleset = cpart->ctype;
bool renderDeco = !ren->blackDecorations;
bool renderDeco = !gfctx.ren->blackDecorations;
if (ruleset >= 0 && ruleset < NGOL)
{
if (!renderDeco || !ren->decorations_enable)
if (!renderDeco || !gfctx.ren->decorations_enable)
{
colour1 = builtinGol[ruleset].colour;
colour2 = builtinGol[ruleset].colour2;
@ -91,6 +92,8 @@ static int graphics(GRAPHICS_FUNC_ARGS)
static void create(ELEMENT_CREATE_FUNC_ARGS)
{
auto &sd = SimulationData::CRef();
auto &builtinGol = sd.builtinGol;
if (v == -1)
v = 0;
// * 0x200000: No need to look for colours, they'll be set later anyway.
@ -105,7 +108,7 @@ static void create(ELEMENT_CREATE_FUNC_ARGS)
}
else if (!skipLookup)
{
auto *cgol = sim->GetCustomGOLByRule(v);
auto *cgol = sd.GetCustomGOLByRule(v);
if (cgol)
{
sim->parts[i].dcolour = cgol->colour1;

View File

@ -79,6 +79,8 @@ static int update(UPDATE_FUNC_ARGS)
sim->hv[y/CELL][x/CELL] = MAX_TEMP;
}
auto &sd = SimulationData::CRef();
auto &elements = sd.elements;
for (auto rx = -2; rx <= 2; rx++)
{
for (auto ry = -2; ry <= 2; ry++)
@ -89,15 +91,15 @@ static int update(UPDATE_FUNC_ARGS)
if (!r)
continue;
auto rt = TYP(r);
if ((surround_space || sim->elements[rt].Explosive) &&
if ((surround_space || elements[rt].Explosive) &&
(rt!=PT_SPNG || parts[ID(r)].life==0) &&
sim->elements[rt].Flammable && sim->rng.chance(sim->elements[rt].Flammable + int(sim->pv[(y+ry)/CELL][(x+rx)/CELL] * 10.0f), 1000))
elements[rt].Flammable && sim->rng.chance(elements[rt].Flammable + int(sim->pv[(y+ry)/CELL][(x+rx)/CELL] * 10.0f), 1000))
{
sim->part_change_type(ID(r),x+rx,y+ry,PT_FIRE);
parts[ID(r)].temp = restrict_flt(sim->elements[PT_FIRE].DefaultProperties.temp + (sim->elements[rt].Flammable/2), MIN_TEMP, MAX_TEMP);
parts[ID(r)].temp = restrict_flt(elements[PT_FIRE].DefaultProperties.temp + (elements[rt].Flammable/2), MIN_TEMP, MAX_TEMP);
parts[ID(r)].life = sim->rng.between(180, 259);
parts[ID(r)].tmp = parts[ID(r)].ctype = 0;
if (sim->elements[rt].Explosive)
if (elements[rt].Explosive)
sim->pv[y/CELL][x/CELL] += 0.25f * CFDS;
}
switch (rt)
@ -138,7 +140,7 @@ static int update(UPDATE_FUNC_ARGS)
break;
case PT_HEAC:
parts[ID(r)].temp = restrict_flt(parts[ID(r)].temp+powderful/10, MIN_TEMP, MAX_TEMP);
if (parts[ID(r)].temp > sim->elements[PT_HEAC].HighTemperature)
if (parts[ID(r)].temp > elements[PT_HEAC].HighTemperature)
{
sim->part_change_type(ID(r), x+rx, y+ry, PT_LAVA);
parts[ID(r)].ctype = PT_HEAC;
@ -147,10 +149,10 @@ static int update(UPDATE_FUNC_ARGS)
default:
break;
}
if ((sim->elements[TYP(r)].Properties&PROP_CONDUCTS) && parts[ID(r)].life==0)
if ((elements[TYP(r)].Properties&PROP_CONDUCTS) && parts[ID(r)].life==0)
sim->create_part(ID(r),x+rx,y+ry,PT_SPRK);
sim->pv[y/CELL][x/CELL] += powderful/400;
if (sim->elements[TYP(r)].HeatConduct) parts[ID(r)].temp = restrict_flt(parts[ID(r)].temp+powderful/1.3, MIN_TEMP, MAX_TEMP);
if (elements[TYP(r)].HeatConduct) parts[ID(r)].temp = restrict_flt(parts[ID(r)].temp+powderful/1.3, MIN_TEMP, MAX_TEMP);
}
}
}

View File

@ -257,7 +257,7 @@ static int graphics(GRAPHICS_FUNC_ARGS)
// Charged lith
else if (cpart->ctype > 0)
{
int mult = ren->rng.between(cpart->ctype / 3, cpart->ctype) / 15;
int mult = gfctx.rng.between(cpart->ctype / 3, cpart->ctype) / 15;
mult = std::min(6, mult);
*colr -= 30 * mult;
*colb += 20 * mult;

View File

@ -0,0 +1,7 @@
#pragma once
#include "simulation/ElementDefs.h"
extern int Element_LOLZ_RuleTable[9][9];
extern int Element_LOLZ_lolz[XRES/9][YRES/9];
extern int Element_LOVE_RuleTable[9][9];
extern int Element_LOVE_love[XRES/9][YRES/9];

View File

@ -50,6 +50,8 @@ void Element::Element_LSNS()
static int update(UPDATE_FUNC_ARGS)
{
auto &sd = SimulationData::CRef();
auto &elements = sd.elements;
int rd = parts[i].tmp2;
if (rd > 25) parts[i].tmp2 = rd = 25;
if (parts[i].life)
@ -69,7 +71,7 @@ static int update(UPDATE_FUNC_ARGS)
int rt = TYP(r);
if (sim->parts_avg(i, ID(r), PT_INSL) != PT_INSL)
{
if ((sim->elements[rt].Properties&PROP_CONDUCTS) && !(rt == PT_WATR || rt == PT_SLTW || rt == PT_NTCT || rt == PT_PTCT || rt == PT_INWR) && parts[ID(r)].life == 0)
if ((elements[rt].Properties&PROP_CONDUCTS) && !(rt == PT_WATR || rt == PT_SLTW || rt == PT_NTCT || rt == PT_PTCT || rt == PT_INWR) && parts[ID(r)].life == 0)
{
parts[ID(r)].life = 4;
parts[ID(r)].ctype = rt;

View File

@ -27,6 +27,7 @@ void Element::Element_METL()
Weight = 100;
HeatConduct = 251;
LatentHeat = 919;
Description = "The basic conductor. Meltable.";
Properties = TYPE_SOLID|PROP_CONDUCTS|PROP_LIFE_DEC|PROP_HOT_GLOW;

Some files were not shown because too many files have changed in this diff Show More