diff --git a/meson.build b/meson.build index 7d78d3237..db7963020 100644 --- a/meson.build +++ b/meson.build @@ -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 = [ diff --git a/meson_options.txt b/meson_options.txt index 44a15d4cb..34b3a7904 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -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( diff --git a/src/PowderToy.cpp b/src/PowderToy.cpp index 42b364699..39e62dba4 100644 --- a/src/PowderToy.cpp +++ b/src/PowderToy.cpp @@ -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; std::unique_ptr favorite; std::unique_ptr engine; + std::unique_ptr simulationData; std::unique_ptr gameController; }; static std::unique_ptr explicitSingletons; @@ -416,6 +418,7 @@ int Main(int argc, char *argv[]) } auto wrapWithBluescreen = [&]() { + explicitSingletons->simulationData = std::make_unique(); explicitSingletons->gameController = std::make_unique(); auto *gameController = explicitSingletons->gameController.get(); engine.ShowWindow(gameController->GetView()); diff --git a/src/PowderToyRenderer.cpp b/src/PowderToyRenderer.cpp index 78a3d91f1..d7c35aed4 100644 --- a/src/PowderToyRenderer.cpp +++ b/src/PowderToyRenderer.cpp @@ -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 #include @@ -39,6 +40,7 @@ int main(int argc, char *argv[]) throw e; } + auto simulationData = std::make_unique(); Simulation * sim = new Simulation(); Renderer * ren = new Renderer(sim); diff --git a/src/SimulationConfig.h b/src/SimulationConfig.h index 1fd9aef83..f98f29be6 100644 --- a/src/SimulationConfig.h +++ b/src/SimulationConfig.h @@ -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; diff --git a/src/client/GameSave.cpp b/src/client/GameSave.cpp index 294aac63d..75050f46c 100644 --- a/src/client/GameSave.cpp +++ b/src/client/GameSave.cpp @@ -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 &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<= PT_NUM) + { + continue; + } + tempPart.type = paletteLookup(tempPart.type); + for (auto index : possiblyCarriesType) + { + if (elements[tempPart.type].CarriesTypeIn & (1U << index)) + { + auto *prop = reinterpret_cast(reinterpret_cast(&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 &data) { try @@ -67,6 +148,7 @@ void GameSave::Expand(const std::vector &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> GameSave::Serialise() const return { false, {} }; } -extern const std::array, 8> Element_PIPE_offsets; -void Element_PIPE_transformPatchOffsets(Particle &part, const std::array &offsetMap); - void GameSave::Transform(Mat2 transform, Vec2 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 &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 &data) #define MTOS(str) MTOS_EXPAND(str) void GameSave::readPSv(const std::vector &dataVec) { + auto &builtinGol = SimulationData::builtinGol; Renderer::PopulateTables(); unsigned char * saveData = (unsigned char *)&dataVec[0]; @@ -1197,7 +1278,7 @@ void GameSave::readPSv(const std::vector &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 &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> 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> GameSave::serialiseOPS() const std::vector partsSaveIndex(NPART); unsigned int partsCount = 0; std::fill(&partsSaveIndex[0], &partsSaveIndex[0] + NPART, 0); + auto &sd = SimulationData::CRef(); + auto &elements = sd.elements; + std::set paletteSet; for (auto pos : partS.OriginRect().Range()) { //Find the first particle in this position @@ -1997,6 +2081,16 @@ std::pair> 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(reinterpret_cast(&particles[i]) + properties[index].Offset); + paletteSet.insert(TYP(*prop)); + } + } + //Type (required) partsData[partsDataLen++] = particles[i].type; @@ -2200,7 +2294,7 @@ std::pair> 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(reinterpret_cast(&particles[i]) + properties[index].Offset); if (TYP(*prop) > 0xFF) @@ -2250,6 +2344,12 @@ std::pair> GameSave::serialiseOPS() const } } + std::vector paletteData; + for (int ID : paletteSet) + { + paletteData.push_back(GameSave::PaletteItem(elements[ID].Identifier, ID)); + } + unsigned int soapLinkDataLen = 0; std::vector soapLinkData(3*soapCount); if (soapCount) @@ -2381,10 +2481,10 @@ std::pair> 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); } diff --git a/src/client/GameSave.h b/src/client/GameSave.h index a22d359a3..bf34a6563 100644 --- a/src/client/GameSave.h +++ b/src/client/GameSave.h @@ -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 @@ -62,6 +63,8 @@ class GameSave void readPSv(const std::vector &data); std::pair> serialiseOPS() const; + void MapPalette(); + public: Vec2 blockSize = { 0, 0 }; bool fromNewerVersion = false; @@ -101,6 +104,8 @@ public: int edgeMode = 0; bool wantAuthors = true; + MissingElements missingElements; + //Signs std::vector signs; StkmData stkm; diff --git a/src/client/ThumbnailRendererTask.cpp b/src/client/ThumbnailRendererTask.cpp index 5267ed88d..fe40d5802 100644 --- a/src/client/ThumbnailRendererTask.cpp +++ b/src/client/ThumbnailRendererTask.cpp @@ -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); diff --git a/src/common/ExplicitSingleton.h b/src/common/ExplicitSingleton.h index a21887b76..715a0c4bd 100644 --- a/src/common/ExplicitSingleton.h +++ b/src/common/ExplicitSingleton.h @@ -28,4 +28,9 @@ public: { return *Instance(); } + + static const Type &CRef() + { + return Ref(); + } }; diff --git a/src/common/Version.h b/src/common/Version.h index ae215e3f0..c8febaad7 100644 --- a/src/common/Version.h +++ b/src/common/Version.h @@ -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]; diff --git a/src/debug/ElementPopulation.cpp b/src/debug/ElementPopulation.cpp index 76ec04133..0f5849d73 100644 --- a/src/debug/ElementPopulation.cpp +++ b/src/debug/ElementPopulation.cpp @@ -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 colour = sim->elements[i].Colour; + RGB colour = elements[i].Colour; g->DrawLine({ xStart+barX, yBottom+3 }, { xStart+barX, yBottom+2 }, colour); if(sim->elementCount[i]) diff --git a/src/debug/SurfaceNormals.cpp b/src/debug/SurfaceNormals.cpp index 9cf8e6da1..da034f796 100644 --- a/src/debug/SurfaceNormals.cpp +++ b/src/debug/SurfaceNormals.cpp @@ -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(*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(*sim, t, parts[i].x, parts[i].y, mr.vx, mr.vy); if (!gn.success) { return; diff --git a/src/debug/SurfaceNormals.h b/src/debug/SurfaceNormals.h index 48bcf5d96..5c767f1ea 100644 --- a/src/debug/SurfaceNormals.h +++ b/src/debug/SurfaceNormals.h @@ -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; }; diff --git a/src/graphics/Renderer.cpp b/src/graphics/Renderer.cpp index 07e1fb1be..7b52489ee 100644 --- a/src/graphics/Renderer.cpp +++ b/src/graphics/Renderer.cpp @@ -7,11 +7,13 @@ #include "simulation/ElementClasses.h" #include "simulation/Air.h" #include "simulation/gravity/Gravity.h" +#include "simulation/orbitalparts.h" #include std::unique_ptr Renderer::WallIcon(int wallID, Vec2 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= 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( @@ -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(colr, colg, colb, int((gradv*4)>255?255:(gradv*4)) )); BlendPixel({ nx+1, ny }, RGBA(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(colr, colg, colb, int((gradv*4)>255?255:(gradv*4)) )); BlendPixel({ nx+1, ny }, RGBA(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 prgb = sim->wtypes[wt].colour; - RGB grgb = sim->wtypes[wt].eglow; + RGB prgb = wtypes[wt].colour; + RGB 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 glow = sim->wtypes[wt].eglow; + RGB 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; diff --git a/src/graphics/Renderer.h b/src/graphics/Renderer.h index e0db7cfcb..35f90bbc4 100644 --- a/src/graphics/Renderer.h +++ b/src/graphics/Renderer.h @@ -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 render_modes; unsigned int render_mode; @@ -147,8 +136,7 @@ public: static std::unique_ptr WallIcon(int wallID, Vec2 size); - Renderer(Simulation * sim); - ~Renderer(); + Renderer(Simulation *newSim); #define RENDERER_TABLE(name) \ static std::vector> name; \ diff --git a/src/graphics/RendererBasic.cpp b/src/graphics/RendererBasic.cpp index 1d4efbf08..97e4287e4 100644 --- a/src/graphics/RendererBasic.cpp +++ b/src/graphics/RendererBasic.cpp @@ -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; diff --git a/src/graphics/gcache_item.h b/src/graphics/gcache_item.h new file mode 100644 index 000000000..b824ae359 --- /dev/null +++ b/src/graphics/gcache_item.h @@ -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; +}; diff --git a/src/gui/game/GOLTool.cpp b/src/gui/game/GOLTool.cpp index 19381f19c..b5f273816 100644 --- a/src/gui/game/GOLTool.cpp +++ b/src/gui/game/GOLTool.cpp @@ -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 colour1, RGB colour2); + GOLWindow(GameModel &gameModel, int toolSelection, int rule, RGB colour1, RGB colour2); virtual ~GOLWindow() {} @@ -39,12 +38,11 @@ public: void OnTryExit(ExitMethod method) override; }; -GOLWindow::GOLWindow(GameModel &gameModel_, Simulation *sim_, int toolSelection, int rule, RGB colour1, RGB colour2): +GOLWindow::GOLWindow(GameModel &gameModel_, int toolSelection, int rule, RGB colour1, RGB 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 colour1, RGB colour2) { - new GOLWindow(gameModel, sim, toolSelection, rule, colour1, colour2); + new GOLWindow(gameModel, toolSelection, rule, colour1, colour2); } diff --git a/src/gui/game/GameController.cpp b/src/gui/game/GameController.cpp index add450109..d60216018 100644 --- a/src/gui/game/GameController.cpp +++ b/src/gui/game/GameController.cpp @@ -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(); } diff --git a/src/gui/game/GameModel.cpp b/src/gui/game/GameModel.cpp index 81250ff6e..f95deec30 100644 --- a/src/gui/game/GameModel.cpp +++ b/src/gui/game/GameModel.cpp @@ -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{}); std::vector validatedCustomLifeTypes; - std::vector newCustomGol; + std::vector 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::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); } diff --git a/src/gui/game/GameView.cpp b/src/gui/game/GameView.cpp index 19d9c2781..d1379cc90 100644 --- a/src/gui/game/GameView.cpp +++ b/src/gui/game/GameView.cpp @@ -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)); diff --git a/src/gui/game/IntroText.h b/src/gui/game/IntroText.h index ba094c0f0..36f66b9dc 100644 --- a/src/gui/game/IntroText.h +++ b/src/gui/game/IntroText.h @@ -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"; diff --git a/src/gui/game/PropertyTool.cpp b/src/gui/game/PropertyTool.cpp index eb3f8a794..36b80d659 100644 --- a/src/gui/game/PropertyTool.cpp +++ b/src/gui/game/PropertyTool.cpp @@ -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; } diff --git a/src/gui/preview/PreviewView.cpp b/src/gui/preview/PreviewView.cpp index 05506539a..5c322d05d 100644 --- a/src/gui/preview/PreviewView.cpp +++ b/src/gui/preview/PreviewView.cpp @@ -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(); diff --git a/src/gui/render/RenderView.cpp b/src/gui/render/RenderView.cpp index d64286407..2fbb19e3f 100644 --- a/src/gui/render/RenderView.cpp +++ b/src/gui/render/RenderView.cpp @@ -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(); diff --git a/src/lua/LegacyLuaAPI.cpp b/src/lua/LegacyLuaAPI.cpp index 32e009e16..6eae5d11a 100644 --- a/src/lua/LegacyLuaAPI.cpp +++ b/src/lua/LegacyLuaAPI.cpp @@ -26,12 +26,15 @@ void initLegacyProps() std::vector 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("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("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(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(); 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(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; } diff --git a/src/lua/LuaScriptInterface.cpp b/src/lua/LuaScriptInterface.cpp index 3a884f946..36f7d10bf 100644 --- a/src/lua/LuaScriptInterface.cpp +++ b/src/lua/LuaScriptInterface.cpp @@ -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(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(); 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(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(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(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(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(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(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(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((reinterpret_cast(&luacon_sim->elements[id].DefaultProperties)) + prop.Offset); + auto propertyAddress = reinterpret_cast((reinterpret_cast(&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((reinterpret_cast(&luacon_sim->elements[id].DefaultProperties)) + prop.Offset); + auto propertyAddress = reinterpret_cast((reinterpret_cast(&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(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; } diff --git a/src/lua/TPTScriptInterface.cpp b/src/lua/TPTScriptInterface.cpp index 659715f17..b03995292 100644 --- a/src/lua/TPTScriptInterface.cpp +++ b/src/lua/TPTScriptInterface.cpp @@ -244,6 +244,7 @@ String TPTScriptInterface::FormatCommand(String command) AnyType TPTScriptInterface::tptS_set(std::deque * 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 * 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 * 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 * 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 * words) AnyType TPTScriptInterface::tptS_create(std::deque * 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 * 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 * words) AnyType TPTScriptInterface::tptS_reset(std::deque * 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 * 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; } } } diff --git a/src/simulation/Air.cpp b/src/simulation/Air.cpp index 166ea561e..4d7aaef50 100644 --- a/src/simulation/Air.cpp +++ b/src/simulation/Air.cpp @@ -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)) diff --git a/src/simulation/BuiltinGOL.h b/src/simulation/BuiltinGOL.h index 9a4f7c959..bf7417d96 100644 --- a/src/simulation/BuiltinGOL.h +++ b/src/simulation/BuiltinGOL.h @@ -8,7 +8,8 @@ struct BuiltinGOL String name; int oldtype; int ruleset; - RGB colour, colour2; + RGB colour = RGB(0, 0, 0); + RGB colour2 = RGB(0, 0, 0); int goltype; String description; }; diff --git a/src/simulation/Editing.cpp b/src/simulation/Editing.cpp index 2c38765e0..1cbd316f6 100644 --- a/src/simulation/Editing.cpp +++ b/src/simulation/Editing.cpp @@ -13,7 +13,7 @@ #include #include -std::unique_ptr Simulation::CreateSnapshot() +std::unique_ptr Simulation::CreateSnapshot() const { auto snap = std::make_unique(); 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--; diff --git a/src/simulation/Element.cpp b/src/simulation/Element.cpp index 2ca1b3b22..ec46e4353 100644 --- a/src/simulation/Element.cpp +++ b/src/simulation/Element.cpp @@ -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 const &Element::GetProperties() { - static std::vector 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 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; } diff --git a/src/simulation/Element.h b/src/simulation/Element.h index 8610273bd..d2026decf 100644 --- a/src/simulation/Element.h +++ b/src/simulation/Element.h @@ -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; diff --git a/src/simulation/ElementClasses.cpp b/src/simulation/ElementClasses.cpp index 74ed3bbee..2dc7ae7b6 100644 --- a/src/simulation/ElementClasses.cpp +++ b/src/simulation/ElementClasses.cpp @@ -1,12 +1,12 @@ #include "ElementCommon.h" -std::vector const &GetElements() +std::array const &GetElements() { struct DoOnce { - std::vector elements; + std::array elements; - DoOnce() : elements(PT_NUM) + DoOnce() { #define ELEMENT_NUMBERS_CALL #include "ElementNumbers.h" diff --git a/src/simulation/ElementClasses.h b/src/simulation/ElementClasses.h index eae598970..a6f9a7100 100644 --- a/src/simulation/ElementClasses.h +++ b/src/simulation/ElementClasses.h @@ -1,5 +1,5 @@ #pragma once -#include +#include #include "SimulationData.h" #include "Element.h" @@ -8,4 +8,4 @@ #include "ElementNumbers.h" #undef ELEMENT_NUMBERS_ENUMERATE -std::vector const &GetElements(); +std::array const &GetElements(); diff --git a/src/simulation/ElementCommon.h b/src/simulation/ElementCommon.h index 3f6f90c74..6aa2a8c8c 100644 --- a/src/simulation/ElementCommon.h +++ b/src/simulation/ElementCommon.h @@ -8,6 +8,7 @@ #include "Particle.h" #include "ElementGraphics.h" #include "Simulation.h" +#include "SimulationData.h" #include "graphics/Renderer.h" #include #include diff --git a/src/simulation/ElementDefs.h b/src/simulation/ElementDefs.h index c808d1fc4..285119e7d 100644 --- a/src/simulation/ElementDefs.h +++ b/src/simulation/ElementDefs.h @@ -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 diff --git a/src/simulation/SaveRenderer.cpp b/src/simulation/SaveRenderer.cpp index ad6709dae..733409f76 100644 --- a/src/simulation/SaveRenderer.cpp +++ b/src/simulation/SaveRenderer.cpp @@ -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(); + ren = std::make_unique(sim.get()); ren->decorations_enable = true; ren->blackDecorations = true; } -void SaveRenderer::Flush(int begin, int end) -{ - std::lock_guard gx(renderMutex); - std::fill(ren->graphicscache + begin, ren->graphicscache + end, gcache_item()); -} +SaveRenderer::~SaveRenderer() = default; -std::pair, MissingElements> SaveRenderer::Render(const GameSave *save, bool decorations, bool fire, Renderer *renderModeSource) +std::unique_ptr 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 gx(renderMutex); ren->ResetModes(); @@ -34,7 +35,7 @@ std::pair, 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, MissingElements> SaveRenderer::Render(co auto tempThumb = std::make_unique(save->blockSize * CELL); tempThumb->BlendImage(ren->Data(), 0xFF, ren->Size().OriginRect()); - return { std::move(tempThumb), missingElementTypes }; -} - -SaveRenderer::~SaveRenderer() -{ - delete ren; - delete sim; + return tempThumb; } diff --git a/src/simulation/SaveRenderer.h b/src/simulation/SaveRenderer.h index d2a245339..a5fffca98 100644 --- a/src/simulation/SaveRenderer.h +++ b/src/simulation/SaveRenderer.h @@ -5,21 +5,20 @@ #include #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 { - Simulation * sim; - Renderer * ren; +class SaveRenderer: public ExplicitSingleton +{ + std::unique_ptr sim; + std::unique_ptr ren; std::mutex renderMutex; + public: SaveRenderer(); - std::pair, 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 Render(const GameSave *save, bool decorations = true, bool fire = true, Renderer *renderModeSource = nullptr); }; diff --git a/src/simulation/Sign.cpp b/src/simulation/Sign.cpp index e885fcc65..bc1c65b60 100644 --- a/src/simulation/Sign.cpp +++ b/src/simulation/Sign.cpp @@ -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; } diff --git a/src/simulation/Sign.h b/src/simulation/Sign.h index 211d46437..0d4f514ac 100644 --- a/src/simulation/Sign.h +++ b/src/simulation/Sign.h @@ -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 split() const; }; diff --git a/src/simulation/Simulation.cpp b/src/simulation/Simulation.cpp index 74a0fa132..b1040f7d9 100644 --- a/src/simulation/Simulation.cpp +++ b/src/simulation/Simulation.cpp @@ -4,79 +4,33 @@ #include "gravity/Gravity.h" #include "ToolClasses.h" #include "SimulationData.h" -#include "GOLString.h" #include "client/GameSave.h" #include "common/tpt-compat.h" #include "common/tpt-rand.h" #include "common/tpt-thread-local.h" #include "gui/game/Brush.h" +#include "elements/EMP.h" +#include "elements/LOLZ.h" +#include "elements/STKM.h" +#include "elements/PIPE.h" +#include "elements/FILT.h" #include #include -extern int Element_PPIP_ppip_changed; -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]; - -MissingElements Simulation::Load(const GameSave *save, bool includePressure, Vec2 blockP) // block coordinates +static float remainder_p(float x, float y) { - MissingElements missingElements; - auto partP = blockP * CELL; - unsigned int pmapmask = (1<pmapbits)-1; + return std::fmod(x, y) + (x>=0 ? 0 : y); +} - int partMap[PT_NUM]; - for(int i = 0; i < PT_NUM; i++) - { - partMap[i] = i; - } - if(save->palette.size()) - { - for(int i = 0; i < PT_NUM; i++) - { - partMap[i] = 0; - } - for(auto &pi : save->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 = [&partMap, &missingElements](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; - }; +void Simulation::Load(const GameSave *save, bool includePressure, Vec2 blockP) // block coordinates +{ + auto partP = blockP * CELL; + + auto &sd = SimulationData::CRef(); + auto &elements = sd.elements; RecalcFreeParticles(false); - auto &possiblyCarriesType = Particle::PossiblyCarriesType(); - auto &properties = Particle::GetProperties(); - std::map soapList; for (int n = 0; n < NPART && n < save->particlesCount; n++) { @@ -91,26 +45,12 @@ MissingElements Simulation::Load(const GameSave *save, bool includePressure, Vec int x = int(tempPart.x + 0.5f); int y = int(tempPart.y + 0.5f); - // Check various scenarios where we are unable to spawn the element, and set type to 0 to block spawning later if (!InBounds(x, y)) { continue; } - tempPart.type = paletteLookup(tempPart.type); - for (auto index : possiblyCarriesType) - { - if (elements[tempPart.type].CarriesTypeIn & (1U << index)) - { - auto *prop = reinterpret_cast(reinterpret_cast(&tempPart) + properties[index].Offset); - auto carriedType = *prop & int(pmapmask); - auto extra = *prop >> save->pmapbits; - carriedType = paletteLookup(carriedType); - *prop = PMAP(extra, carriedType); - } - } - // Ensure we can spawn this element if ((player.spwn == 1 && tempPart.type==PT_STKM) || (player2.spwn == 1 && tempPart.type==PT_STKM2)) { @@ -120,7 +60,6 @@ MissingElements Simulation::Load(const GameSave *save, bool includePressure, Vec { continue; } - bool Element_FIGH_CanAlloc(Simulation *sim); if (tempPart.type == PT_FIGH && !Element_FIGH_CanAlloc(this)) { continue; @@ -152,7 +91,6 @@ MissingElements Simulation::Load(const GameSave *save, bool includePressure, Vec elementCount[tempPart.type]++; - void Element_STKM_init_legs(Simulation * sim, playerst *playerp, int i); switch (parts[i].type) { case PT_STKM: @@ -193,7 +131,6 @@ MissingElements Simulation::Load(const GameSave *save, bool includePressure, Vec case PT_FIGH: { unsigned int oldTmp = parts[i].tmp; - int Element_FIGH_Alloc(Simulation *sim); parts[i].tmp = Element_FIGH_Alloc(this); if (parts[i].tmp >= 0) { @@ -205,7 +142,6 @@ MissingElements Simulation::Load(const GameSave *save, bool includePressure, Vec parts[i].ctype = 0; } fighters[parts[i].tmp].elem = PT_DUST; - void Element_FIGH_NewFighter(Simulation *sim, int fighterID, int i, int elem); Element_FIGH_NewFighter(this, parts[i].tmp, i, parts[i].ctype); if (fan) fighters[parts[i].tmp].fan = true; @@ -337,8 +273,6 @@ MissingElements Simulation::Load(const GameSave *save, bool includePressure, Vec { air->ApproximateBlockAirMaps(); } - - return missingElements; } std::unique_ptr Simulation::Save(bool includePressure, Rect partR) // particle coordinates @@ -347,8 +281,6 @@ std::unique_ptr Simulation::Save(bool includePressure, Rect partR auto blockP = blockR.TopLeft; auto newSave = std::make_unique(blockR.Size()); - auto &possiblyCarriesType = Particle::PossiblyCarriesType(); - auto &properties = Particle::GetProperties(); newSave->frameCount = frameCount; newSave->rngState = rng.state(); @@ -358,7 +290,9 @@ std::unique_ptr Simulation::Save(bool includePressure, Rect partR // Map of soap particles loaded into this save, old ID -> new ID // Now stores all particles, not just SOAP (but still only used for soap) std::map particleMap; - std::set paletteSet; + + auto &sd = SimulationData::CRef(); + auto &elements = sd.elements; for (int i = 0; i < NPART; i++) { int x, y; @@ -376,22 +310,10 @@ std::unique_ptr Simulation::Save(bool includePressure, Rect partR storedParts++; elementCount[tempPart.type]++; - paletteSet.insert(tempPart.type); - for (auto index : possiblyCarriesType) - { - if (elements[tempPart.type].CarriesTypeIn & (1U << index)) - { - auto *prop = reinterpret_cast(reinterpret_cast(&tempPart) + properties[index].Offset); - paletteSet.insert(TYP(*prop)); - } - } } } } - for (int ID : paletteSet) - newSave->palette.push_back(GameSave::PaletteItem(elements[ID].Identifier, ID)); - if (storedParts && elementCount[PT_SOAP]) { // fix SOAP links using particleMap, a map of old particle ID -> new particle ID @@ -493,8 +415,10 @@ void Simulation::SaveSimOptions(GameSave &gameSave) gameSave.aheatEnable = aheat_enable; } -bool Simulation::FloodFillPmapCheck(int x, int y, int type) +bool Simulation::FloodFillPmapCheck(int x, int y, int type) const { + auto &sd = SimulationData::CRef(); + auto &elements = sd.elements; if (type == 0) return !pmap[y][x] && !photons[y][x]; if (elements[type].Properties&TYPE_ENERGY) @@ -711,6 +635,8 @@ bool Simulation::flood_water(int x, int y, int i) char *bitmap = bitmapPtr.get(); std::fill(&bitmap[0], &bitmap[0] + XRES * YRES, 0); + auto &sd = SimulationData::CRef(); + auto &elements = sd.elements; try { CoordStack& cs = getCoordStackSingleton(); @@ -860,38 +786,6 @@ void Simulation::CreateLine(int x1, int y1, int x2, int y2, int c) } } -void Simulation::orbitalparts_get(int block1, int block2, int resblock1[], int resblock2[]) -{ - resblock1[0] = (block1&0x000000FF); - resblock1[1] = (block1&0x0000FF00)>>8; - resblock1[2] = (block1&0x00FF0000)>>16; - resblock1[3] = (block1&0xFF000000)>>24; - - resblock2[0] = (block2&0x000000FF); - resblock2[1] = (block2&0x0000FF00)>>8; - resblock2[2] = (block2&0x00FF0000)>>16; - resblock2[3] = (block2&0xFF000000)>>24; -} - -void Simulation::orbitalparts_set(int *block1, int *block2, int resblock1[], int resblock2[]) -{ - int block1tmp = 0; - int block2tmp = 0; - - block1tmp = (resblock1[0]&0xFF); - block1tmp |= (resblock1[1]&0xFF)<<8; - block1tmp |= (resblock1[2]&0xFF)<<16; - block1tmp |= (resblock1[3]&0xFF)<<24; - - block2tmp = (resblock2[0]&0xFF); - block2tmp |= (resblock2[1]&0xFF)<<8; - block2tmp |= (resblock2[2]&0xFF)<<16; - block2tmp |= (resblock2[3]&0xFF)<<24; - - *block1 = block1tmp; - *block2 = block2tmp; -} - inline int Simulation::is_wire(int x, int y) { return bmap[y][x]==WL_DETECT || bmap[y][x]==WL_EWALL || bmap[y][x]==WL_ALLOWLIQUID || bmap[y][x]==WL_WALLELEC || bmap[y][x]==WL_ALLOWALLELEC || bmap[y][x]==WL_EHOLE || bmap[y][x]==WL_STASIS; @@ -1101,6 +995,8 @@ void Simulation::clear_sim(void) bool Simulation::IsWallBlocking(int x, int y, int type) const { + auto &sd = SimulationData::CRef(); + auto &elements = sd.elements; if (bmap[y/CELL][x/CELL]) { int wall = bmap[y/CELL][x/CELL]; @@ -1122,145 +1018,6 @@ bool Simulation::IsWallBlocking(int x, int y, int type) const return false; } -void Simulation::init_can_move() -{ - 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; -} - /* RETURN-value explanation 1 = Swap @@ -1282,6 +1039,9 @@ int Simulation::eval_move(int pt, int nx, int ny, unsigned *rr) const *rr = r; if (pt>=PT_NUM || TYP(r)>=PT_NUM) return 0; + auto &sd = SimulationData::CRef(); + auto &can_move = sd.can_move; + auto &elements = sd.elements; result = can_move[pt][TYP(r)]; if (result == 3) { @@ -1365,6 +1125,8 @@ int Simulation::try_move(int i, int x, int y, int nx, int ny) if (!e && parts[i].type==PT_PHOT && ((TYP(r)==PT_BMTL && rng.chance(1, 2)) || TYP(pmap[y][x])==PT_BMTL)) e = 2; + auto &sd = SimulationData::CRef(); + auto &elements = sd.elements; if (!e) //if no movement { int rt = TYP(r); @@ -1412,7 +1174,6 @@ int Simulation::try_move(int i, int x, int y, int nx, int ny) return 0; } - int Element_FILT_interactWavelengths(Simulation *sim, Particle* cpart, int origWl); if (e == 2) //if occupy same space { switch (parts[i].type) @@ -1700,6 +1461,8 @@ int Simulation::do_move(int i, int x, int y, float nxf, float nyf) bool Simulation::move(int i, int x, int y, float nxf, float nyf) { + auto &sd = SimulationData::CRef(); + auto &elements = sd.elements; int nx = (int)(nxf+0.5f), ny = (int)(nyf+0.5f); int t = parts[i].type; parts[i].x = nxf; @@ -1741,7 +1504,7 @@ void Simulation::photoelectric_effect(int nx, int ny)//create sparks from PHOT w } } -int Simulation::is_blocking(int t, int x, int y) +int Simulation::is_blocking(int t, int x, int y) const { if (t & REFRACT) { if (x<0 || y<0 || x>=XRES || y>=YRES) @@ -1754,7 +1517,7 @@ int Simulation::is_blocking(int t, int x, int y) return !eval_move(t, x, y, NULL); } -int Simulation::is_boundary(int pt, int x, int y) +int Simulation::is_boundary(int pt, int x, int y) const { if (!is_blocking(pt,x,y)) return 0; @@ -1763,7 +1526,7 @@ int Simulation::is_boundary(int pt, int x, int y) return 1; } -int Simulation::find_next_boundary(int pt, int *x, int *y, int dm, int *em, bool reverse) +int Simulation::find_next_boundary(int pt, int *x, int *y, int dm, int *em, bool reverse) const { static int dx[8] = {1,1,0,-1,-1,-1,0,1}; static int dy[8] = {0,1,1,1,0,-1,-1,-1}; @@ -1802,7 +1565,7 @@ int Simulation::find_next_boundary(int pt, int *x, int *y, int dm, int *em, bool return 0; } -Simulation::GetNormalResult Simulation::get_normal(int pt, int x, int y, float dx, float dy) +Simulation::GetNormalResult Simulation::get_normal(int pt, int x, int y, float dx, float dy) const { int ldm, rdm, lm, rm; int lx, ly, lv, rx, ry, rv; @@ -1847,7 +1610,24 @@ Simulation::GetNormalResult Simulation::get_normal(int pt, int x, int y, float d return { true, nx, ny, lx, ly, rx, ry }; } -Simulation::GetNormalResult Simulation::get_normal_interp(int pt, float x0, float y0, float dx, float dy) + + +template +void PhotoelectricEffectHelper(Sim &sim, int x, int y); + +template<> +void PhotoelectricEffectHelper(const Simulation &sim, int x, int y) +{ +} + +template<> +void PhotoelectricEffectHelper(Simulation &sim, int x, int y) +{ + sim.photoelectric_effect(x, y); +} + +template +Simulation::GetNormalResult Simulation::get_normal_interp(Sim &sim, int pt, float x0, float y0, float dx, float dy) { int x, y, i; @@ -1861,7 +1641,7 @@ Simulation::GetNormalResult Simulation::get_normal_interp(int pt, float x0, floa { return { false }; } - if (is_boundary(pt, x, y)) + if (sim.is_boundary(pt, x, y)) break; x0 += dx; y0 += dy; @@ -1870,11 +1650,14 @@ Simulation::GetNormalResult Simulation::get_normal_interp(int pt, float x0, floa return { false }; if (pt == PT_PHOT) - photoelectric_effect(x, y); + PhotoelectricEffectHelper(sim, x, y); - return get_normal(pt, x, y, dx, dy); + return sim.get_normal(pt, x, y, dx, dy); } +template +Simulation::GetNormalResult Simulation::get_normal_interp(const Simulation &sim, int pt, float x0, float y0, float dx, float dy); + void Simulation::kill_part(int i)//kills particle number i { if (i < 0 || i >= NPART) @@ -1883,6 +1666,8 @@ void Simulation::kill_part(int i)//kills particle number i int x = (int)(parts[i].x + 0.5f); int y = (int)(parts[i].y + 0.5f); + auto &sd = SimulationData::CRef(); + auto &elements = sd.elements; int t = parts[i].type; if (t && elements[t].ChangeType) { @@ -1914,6 +1699,9 @@ bool Simulation::part_change_type(int i, int x, int y, int t) { if (x<0 || y<0 || x>=XRES || y>=YRES || i>=NPART || t<0 || t>=PT_NUM || !parts[i].type) return false; + + auto &sd = SimulationData::CRef(); + auto &elements = sd.elements; if (!elements[t].Enabled || t == PT_NONE) { kill_part(i); @@ -1956,6 +1744,8 @@ int Simulation::create_part(int p, int x, int y, int t, int v) { int i, oldType = PT_NONE; + auto &sd = SimulationData::CRef(); + auto &elements = sd.elements; if (x<0 || y<0 || x>=XRES || y>=YRES || t<=0 || t>=PT_NUM || !elements[t].Enabled) return -1; @@ -2236,12 +2026,31 @@ void Simulation::delete_part(int x, int y)//calls kill_part with the particle lo kill_part(ID(i)); } -Simulation::PlanMoveResult Simulation::PlanMove(int i, int x, int y, bool update_emap) +template +void UpdateEmapHelper(Sim &sim, int fin_x, int fin_y); + +template<> +void UpdateEmapHelper(const Simulation &sim, int fin_x, int fin_y) { - // This function would be const if not for calling set_emap if update_emap is true, - // and users of this function *expect* it to be const if update_emap is false. So - // whenever you change something here, make sure it compiles *as const* if you - // remove the set_emap call. +} + +template<> +void UpdateEmapHelper(Simulation &sim, int fin_x, int fin_y) +{ + if (sim.bmap[fin_y/CELL][fin_x/CELL]==WL_DETECT && sim.emap[fin_y/CELL][fin_x/CELL]<8) + sim.set_emap(fin_x/CELL, fin_y/CELL); +} + +template +Simulation::PlanMoveResult Simulation::PlanMove(Sim &sim, int i, int x, int y) +{ + auto &parts = sim.parts; + auto &bmap = sim.bmap; + auto &emap = sim.emap; + auto &pmap = sim.pmap; + auto edgeMode = sim.edgeMode; + auto &sd = SimulationData::CRef(); + auto &can_move = sd.can_move; auto t = parts[i].type; int fin_x, fin_y, clear_x, clear_y; float fin_xf, fin_yf, clear_xf, clear_yf; @@ -2317,7 +2126,7 @@ Simulation::PlanMoveResult Simulation::PlanMove(int i, int x, int y, bool update } //block if particle can't move (0), or some special cases where it returns 1 (can_move = 3 but returns 1 meaning particle will be eaten) //also photons are still blocked (slowed down) by any particle (even ones it can move through), and absorb wall also blocks particles - int eval = eval_move(t, fin_x, fin_y, NULL); + int eval = sim.eval_move(t, fin_x, fin_y, NULL); if (!eval || (can_move[t][TYP(pmap[fin_y][fin_x])] == 3 && eval == 1) || (t == PT_PHOT && pmap[fin_y][fin_x]) || bmap[fin_y/CELL][fin_x/CELL]==WL_DESTROYALL || closedEholeStart!=(bmap[fin_y/CELL][fin_x/CELL] == WL_EHOLE && !emap[fin_y/CELL][fin_x/CELL])) { // found an obstacle @@ -2327,8 +2136,7 @@ Simulation::PlanMoveResult Simulation::PlanMove(int i, int x, int y, bool update clear_y = (int)(clear_yf+0.5f); break; } - if (update_emap && bmap[fin_y/CELL][fin_x/CELL]==WL_DETECT && emap[fin_y/CELL][fin_x/CELL]<8) - set_emap(fin_x/CELL, fin_y/CELL); + UpdateEmapHelper(sim, fin_x, fin_y); } } return { @@ -2345,9 +2153,14 @@ Simulation::PlanMoveResult Simulation::PlanMove(int i, int x, int y, bool update }; } +template +Simulation::PlanMoveResult Simulation::PlanMove(const Simulation &sim, int i, int x, int y); + void Simulation::UpdateParticles(int start, int end) { //the main particle loop function, goes over all particles. + auto &sd = SimulationData::CRef(); + auto &elements = sd.elements; for (auto i = start; i < end && i <= parts_lastActiveIndex; i++) { if (parts[i].type) @@ -2442,14 +2255,17 @@ void Simulation::UpdateParticles(int start, int end) if (elements[t].Diffusion)//the random diffusion that gasses have { -#ifdef REALISTIC - //The magic number controls diffusion speed - parts[i].vx += 0.05*sqrtf(parts[i].temp)*elements[t].Diffusion*(2.0f*rng.uniform01()-1.0f); - parts[i].vy += 0.05*sqrtf(parts[i].temp)*elements[t].Diffusion*(2.0f*rng.uniform01()-1.0f); -#else - parts[i].vx += elements[t].Diffusion*(2.0f*rng.uniform01()-1.0f); - parts[i].vy += elements[t].Diffusion*(2.0f*rng.uniform01()-1.0f); -#endif + if constexpr (LATENTHEAT) + { + //The magic number controls diffusion speed + parts[i].vx += 0.05*sqrtf(parts[i].temp)*elements[t].Diffusion*(2.0f*rng.uniform01()-1.0f); + parts[i].vy += 0.05*sqrtf(parts[i].temp)*elements[t].Diffusion*(2.0f*rng.uniform01()-1.0f); + } + else + { + parts[i].vx += elements[t].Diffusion*(2.0f*rng.uniform01()-1.0f); + parts[i].vy += elements[t].Diffusion*(2.0f*rng.uniform01()-1.0f); + } } auto transitionOccurred = false; @@ -2500,35 +2316,41 @@ void Simulation::UpdateParticles(int start, int end) } //heat transfer code -#ifdef REALISTIC - if (t&&(t!=PT_HSWC||parts[i].life==10)&&(elements[t].HeatConduct*gel_scale)) -#else auto h_count = 0; - if (t && (t!=PT_HSWC||parts[i].life==10) && rng.chance(int(elements[t].HeatConduct*gel_scale), 250)) -#endif + bool cond; + if constexpr (LATENTHEAT) + { + cond = t && (t!=PT_HSWC||parts[i].life==10) && elements[t].HeatConduct*gel_scale > 0; + } + else + { + cond = t && (t!=PT_HSWC||parts[i].life==10) && rng.chance(int(elements[t].HeatConduct*gel_scale), 250); + } + if (cond) { if (aheat_enable && !(elements[t].Properties&PROP_NOAMBHEAT)) { -#ifdef REALISTIC - auto c_heat = parts[i].temp*96.645/elements[t].HeatConduct*gel_scale*fabs(elements[t].Weight) + hv[y/CELL][x/CELL]*100*(pv[y/CELL][x/CELL]-MIN_PRESSURE)/(MAX_PRESSURE-MIN_PRESSURE)*2; - float c_Cm = 96.645/elements[t].HeatConduct*gel_scale*fabs(elements[t].Weight) + 100*(pv[y/CELL][x/CELL]-MIN_PRESSURE)/(MAX_PRESSURE-MIN_PRESSURE)*2; - auto pt = c_heat/c_Cm; - pt = restrict_flt(pt, -MAX_TEMP+MIN_TEMP, MAX_TEMP-MIN_TEMP); - parts[i].temp = pt; - //Pressure increase from heat (temporary) - pv[y/CELL][x/CELL] += (pt-hv[y/CELL][x/CELL])*0.004; - hv[y/CELL][x/CELL] = pt; -#else - auto c_heat = (hv[y/CELL][x/CELL]-parts[i].temp)*0.04; - c_heat = restrict_flt(c_heat, -MAX_TEMP+MIN_TEMP, MAX_TEMP-MIN_TEMP); - parts[i].temp += c_heat; - hv[y/CELL][x/CELL] -= c_heat; -#endif + if constexpr (LATENTHEAT) + { + auto c_heat = parts[i].temp*96.645/elements[t].HeatConduct*gel_scale*std::fabs(elements[t].Weight) + hv[y/CELL][x/CELL]*100*(pv[y/CELL][x/CELL]-MIN_PRESSURE)/(MAX_PRESSURE-MIN_PRESSURE)*2; + float c_Cm = 96.645/elements[t].HeatConduct*gel_scale*std::fabs(elements[t].Weight) + 100*(pv[y/CELL][x/CELL]-MIN_PRESSURE)/(MAX_PRESSURE-MIN_PRESSURE)*2; + auto pt = c_heat/c_Cm; + pt = restrict_flt(pt, -MAX_TEMP+MIN_TEMP, MAX_TEMP-MIN_TEMP); + parts[i].temp = pt; + //Pressure increase from heat (temporary) + pv[y/CELL][x/CELL] += (pt-hv[y/CELL][x/CELL])*0.004; + hv[y/CELL][x/CELL] = pt; + } + else + { + auto c_heat = (hv[y/CELL][x/CELL]-parts[i].temp)*0.04; + c_heat = restrict_flt(c_heat, -MAX_TEMP+MIN_TEMP, MAX_TEMP-MIN_TEMP); + parts[i].temp += c_heat; + hv[y/CELL][x/CELL] -= c_heat; + } } auto c_heat = 0.0f; -#ifdef REALISTIC float c_Cm = 0.0f; -#endif int surround_hconduct[8]; for (auto j=0; j<8; j++) { @@ -2546,79 +2368,87 @@ void Simulation::UpdateParticles(int start, int end) && (t!=PT_FILT || rt!=PT_HSWC || parts[ID(r)].tmp != 1)) { surround_hconduct[j] = ID(r); -#ifdef REALISTIC - if (rt==PT_GEL) - gel_scale = parts[ID(r)].tmp*2.55f; - else gel_scale = 1.0f; + if constexpr (LATENTHEAT) + { + if (rt==PT_GEL) + gel_scale = parts[ID(r)].tmp*2.55f; + else gel_scale = 1.0f; - c_heat += parts[ID(r)].temp*96.645/elements[rt].HeatConduct*gel_scale*fabs(elements[rt].Weight); - c_Cm += 96.645/elements[rt].HeatConduct*gel_scale*fabs(elements[rt].Weight); -#else - c_heat += parts[ID(r)].temp; -#endif + c_heat += parts[ID(r)].temp*96.645/elements[rt].HeatConduct*gel_scale*std::fabs(elements[rt].Weight); + c_Cm += 96.645/elements[rt].HeatConduct*gel_scale*std::fabs(elements[rt].Weight); + } + else + { + c_heat += parts[ID(r)].temp; + } h_count++; } } float pt = R_TEMP; -#ifdef REALISTIC - if (t==PT_GEL) - gel_scale = parts[i].tmp*2.55f; - else gel_scale = 1.0f; - - if (t == PT_PHOT) - pt = (c_heat+parts[i].temp*96.645)/(c_Cm+96.645); - else - pt = (c_heat+parts[i].temp*96.645/elements[t].HeatConduct*gel_scale*fabs(elements[t].Weight))/(c_Cm+96.645/elements[t].HeatConduct*gel_scale*fabs(elements[t].Weight)); - - c_heat += parts[i].temp*96.645/elements[t].HeatConduct*gel_scale*fabs(elements[t].Weight); - c_Cm += 96.645/elements[t].HeatConduct*gel_scale*fabs(elements[t].Weight); - parts[i].temp = restrict_flt(pt, MIN_TEMP, MAX_TEMP); -#else - pt = (c_heat+parts[i].temp)/(h_count+1); - pt = parts[i].temp = restrict_flt(pt, MIN_TEMP, MAX_TEMP); - for (auto j=0; j<8; j++) + if constexpr (LATENTHEAT) { - parts[surround_hconduct[j]].temp = pt; + if (t==PT_GEL) + gel_scale = parts[i].tmp*2.55f; + else gel_scale = 1.0f; + + if (t == PT_PHOT) + pt = (c_heat+parts[i].temp*96.645)/(c_Cm+96.645); + else + pt = (c_heat+parts[i].temp*96.645/elements[t].HeatConduct*gel_scale*std::fabs(elements[t].Weight))/(c_Cm+96.645/elements[t].HeatConduct*gel_scale*std::fabs(elements[t].Weight)); + + c_heat += parts[i].temp*96.645/elements[t].HeatConduct*gel_scale*std::fabs(elements[t].Weight); + c_Cm += 96.645/elements[t].HeatConduct*gel_scale*std::fabs(elements[t].Weight); + parts[i].temp = restrict_flt(pt, MIN_TEMP, MAX_TEMP); + } + else + { + pt = (c_heat+parts[i].temp)/(h_count+1); + pt = parts[i].temp = restrict_flt(pt, MIN_TEMP, MAX_TEMP); + for (auto j=0; j<8; j++) + { + parts[surround_hconduct[j]].temp = pt; + } } -#endif auto ctemph = pt; auto ctempl = pt; // change boiling point with pressure - if (((elements[t].Properties&TYPE_LIQUID) && IsElementOrNone(elements[t].HighTemperatureTransition) && (elements[elements[t].HighTemperatureTransition].Properties&TYPE_GAS)) + if (((elements[t].Properties&TYPE_LIQUID) && sd.IsElementOrNone(elements[t].HighTemperatureTransition) && (elements[elements[t].HighTemperatureTransition].Properties&TYPE_GAS)) || t==PT_LNTG || t==PT_SLTW) ctemph -= 2.0f*pv[y/CELL][x/CELL]; - else if (((elements[t].Properties&TYPE_GAS) && IsElementOrNone(elements[t].LowTemperatureTransition) && (elements[elements[t].LowTemperatureTransition].Properties&TYPE_LIQUID)) + else if (((elements[t].Properties&TYPE_GAS) && sd.IsElementOrNone(elements[t].LowTemperatureTransition) && (elements[elements[t].LowTemperatureTransition].Properties&TYPE_LIQUID)) || t==PT_WTRV) ctempl -= 2.0f*pv[y/CELL][x/CELL]; auto s = 1; //A fix for ice with ctype = 0 - if ((t==PT_ICEI || t==PT_SNOW) && (!IsElement(parts[i].ctype) || parts[i].ctype==PT_ICEI || parts[i].ctype==PT_SNOW)) + if ((t==PT_ICEI || t==PT_SNOW) && (!sd.IsElement(parts[i].ctype) || parts[i].ctype==PT_ICEI || parts[i].ctype==PT_SNOW)) parts[i].ctype = PT_WATR; if (elements[t].HighTemperatureTransition>-1 && ctemph>=elements[t].HighTemperature) { // particle type change due to high temperature -#ifdef REALISTIC float dbt = ctempl - pt; if (elements[t].HighTemperatureTransition != PT_NUM) { - if (platent[t] <= (c_heat - (elements[t].HighTemperature - dbt)*c_Cm)) + if constexpr (LATENTHEAT) { - pt = (c_heat - platent[t])/c_Cm; - t = elements[t].HighTemperatureTransition; + if (elements[t].LatentHeat <= (c_heat - (elements[t].HighTemperature - dbt)*c_Cm)) + { + pt = (c_heat - elements[t].LatentHeat)/c_Cm; + t = elements[t].HighTemperatureTransition; + } + else + { + parts[i].temp = restrict_flt(elements[t].HighTemperature - dbt, MIN_TEMP, MAX_TEMP); + s = 0; + } } else { - parts[i].temp = restrict_flt(elements[t].HighTemperature - dbt, MIN_TEMP, MAX_TEMP); - s = 0; + t = elements[t].HighTemperatureTransition; } } -#else - if (elements[t].HighTemperatureTransition != PT_NUM) - t = elements[t].HighTemperatureTransition; -#endif else if (t == PT_ICEI || t == PT_SNOW) { if (parts[i].ctype > 0 && parts[i].ctype < PT_NUM && parts[i].ctype != t) @@ -2633,25 +2463,28 @@ void Simulation::UpdateParticles(int start, int end) if (s) { -#ifdef REALISTIC - //One ice table value for all it's kinds - if (platent[t] <= (c_heat - (elements[parts[i].ctype].LowTemperature - dbt)*c_Cm)) + if constexpr (LATENTHEAT) + { + //One ice table value for all it's kinds + if (elements[t].LatentHeat <= (c_heat - (elements[parts[i].ctype].LowTemperature - dbt)*c_Cm)) + { + pt = (c_heat - elements[t].LatentHeat)/c_Cm; + t = parts[i].ctype; + parts[i].ctype = PT_NONE; + parts[i].life = 0; + } + else + { + parts[i].temp = restrict_flt(elements[parts[i].ctype].LowTemperature - dbt, MIN_TEMP, MAX_TEMP); + s = 0; + } + } + else { - pt = (c_heat - platent[t])/c_Cm; t = parts[i].ctype; parts[i].ctype = PT_NONE; parts[i].life = 0; } - else - { - parts[i].temp = restrict_flt(elements[parts[i].ctype].LowTemperature - dbt, MIN_TEMP, MAX_TEMP); - s = 0; - } -#else - t = parts[i].ctype; - parts[i].ctype = PT_NONE; - parts[i].life = 0; -#endif } } else @@ -2659,21 +2492,24 @@ void Simulation::UpdateParticles(int start, int end) } else if (t == PT_SLTW) { -#ifdef REALISTIC - if (platent[t] <= (c_heat - (elements[t].HighTemperature - dbt)*c_Cm)) + if constexpr (LATENTHEAT) { - pt = (c_heat - platent[t])/c_Cm; + if (elements[t].LatentHeat <= (c_heat - (elements[t].HighTemperature - dbt)*c_Cm)) + { + pt = (c_heat - elements[t].LatentHeat)/c_Cm; - t = rng.chance(1, 4) ? PT_SALT : PT_WTRV; + t = rng.chance(1, 4) ? PT_SALT : PT_WTRV; + } + else + { + parts[i].temp = restrict_flt(elements[t].HighTemperature - dbt, MIN_TEMP, MAX_TEMP); + s = 0; + } } else { - parts[i].temp = restrict_flt(elements[t].HighTemperature - dbt, MIN_TEMP, MAX_TEMP); - s = 0; + t = rng.chance(1, 4) ? PT_SALT : PT_WTRV; } -#else - t = rng.chance(1, 4) ? PT_SALT : PT_WTRV; -#endif } else if (t == PT_BRMT) { @@ -2706,25 +2542,27 @@ void Simulation::UpdateParticles(int start, int end) else if (elements[t].LowTemperatureTransition > -1 && ctempl= (c_heat - (elements[t].LowTemperature - dbt)*c_Cm)) + if constexpr (LATENTHEAT) { - pt = (c_heat + platent[elements[t].LowTemperatureTransition])/c_Cm; - t = elements[t].LowTemperatureTransition; + if (elements[elements[t].LowTemperatureTransition].LatentHeat >= (c_heat - (elements[t].LowTemperature - dbt)*c_Cm)) + { + pt = (c_heat + elements[elements[t].LowTemperatureTransition].LatentHeat)/c_Cm; + t = elements[t].LowTemperatureTransition; + } + else + { + parts[i].temp = restrict_flt(elements[t].LowTemperature - dbt, MIN_TEMP, MAX_TEMP); + s = 0; + } } else { - parts[i].temp = restrict_flt(elements[t].LowTemperature - dbt, MIN_TEMP, MAX_TEMP); - s = 0; + t = elements[t].LowTemperatureTransition; } } -#else - if (elements[t].LowTemperatureTransition != PT_NUM) - t = elements[t].LowTemperatureTransition; -#endif else if (t == PT_WTRV) { t = (pt < 273.0f) ? PT_RIME : PT_DSTW; @@ -2783,13 +2621,14 @@ void Simulation::UpdateParticles(int start, int end) } else s = 0; -#ifdef REALISTIC - pt = restrict_flt(pt, MIN_TEMP, MAX_TEMP); - for (auto j=0; j<8; j++) + if constexpr (LATENTHEAT) { - parts[surround_hconduct[j]].temp = pt; + pt = restrict_flt(pt, MIN_TEMP, MAX_TEMP); + for (auto j=0; j<8; j++) + { + parts[surround_hconduct[j]].temp = pt; + } } -#endif if (s) // particle type change occurred { if (t==PT_ICEI || t==PT_LAVA || t==PT_SNOW) @@ -2986,7 +2825,7 @@ killed: int fin_x, fin_y, clear_x, clear_y; float fin_xf, fin_yf, clear_xf, clear_yf; { - auto mr = PlanMove(i, x, y, true); + auto mr = PlanMove(*this, i, x, y); fin_x = mr.fin_x; fin_y = mr.fin_y; clear_x = mr.clear_x; @@ -3083,7 +2922,7 @@ killed: int lt_glas = (lt == PT_GLAS) || (lt == PT_BGLA); if ((rt_glas && !lt_glas) || (lt_glas && !rt_glas)) { - auto gn = get_normal_interp(REFRACT|t, parts[i].x, parts[i].y, parts[i].vx, parts[i].vy); + auto gn = get_normal_interp(*this, REFRACT|t, parts[i].x, parts[i].y, parts[i].vx, parts[i].vy); if (!gn.success) { kill_part(i); continue; @@ -3167,7 +3006,7 @@ killed: parts[i].ctype &= mask; } - auto gn = get_normal_interp(t, parts[i].x, parts[i].y, parts[i].vx, parts[i].vy); + auto gn = get_normal_interp(*this, t, parts[i].x, parts[i].y, parts[i].vx, parts[i].vy); if (gn.success) { auto nrx = gn.nx; @@ -3470,6 +3309,8 @@ void Simulation::RecalcFreeParticles(bool do_life_dec) memset(photons, 0, sizeof(photons)); NUM_PARTS = 0; + auto &sd = SimulationData::CRef(); + auto &elements = sd.elements; //the particle loop that resets the pmap/photon maps every frame, to update them. for (int i = 0; i <= parts_lastActiveIndex; i++) { @@ -3552,6 +3393,7 @@ void Simulation::RecalcFreeParticles(bool do_life_dec) void Simulation::SimulateGoL() { + auto &builtinGol = SimulationData::builtinGol; CGOL = 0; for (int i = 0; i <= parts_lastActiveIndex; ++i) { @@ -3728,6 +3570,8 @@ void Simulation::SimulateGoL() void Simulation::CheckStacking() { + auto &sd = SimulationData::CRef(); + auto &elements = sd.elements; bool excessive_stacking_found = false; force_stacking_check = false; for (int y = 0; y < YRES; y++) @@ -3989,7 +3833,6 @@ void Simulation::AfterSim() if (emp_trigger_count) { // pitiful attempt at trying to keep code relating to a given element in the same file - void Element_EMP_Trigger(Simulation *sim, int triggerCount); Element_EMP_Trigger(this, emp_trigger_count); emp_trigger_count = 0; } @@ -3997,10 +3840,7 @@ void Simulation::AfterSim() frameCount += 1; } -Simulation::~Simulation() -{ - delete air; -} +Simulation::~Simulation() = default; Simulation::Simulation(): replaceModeSelected(0), @@ -4050,7 +3890,7 @@ Simulation::Simulation(): gravmap = &grav->gravmap[0]; //Create and attach air simulation - air = new Air(*this); + air = std::make_unique(*this); //Give air sim references to our data air->bmap = bmap; air->emap = emap; @@ -4062,98 +3902,14 @@ Simulation::Simulation(): pv = air->pv; hv = air->hv; - msections = LoadMenus(); - wtypes = LoadWalls(); - platent = LoadLatent(); - std::copy(GetElements().begin(), GetElements().end(), elements.begin()); - tools = GetTools(); - player.comm = 0; player2.comm = 0; - init_can_move(); clear_sim(); grav->gravity_mask(); } -const Simulation::CustomGOLData *Simulation::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 Simulation::SetCustomGOL(std::vector newCustomGol) -{ - std::sort(newCustomGol.begin(), newCustomGol.end()); - customGol = newCustomGol; -} - -String Simulation::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 Simulation::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 Simulation::remainder_p(int x, int y) -{ - return (x % y) + (x>=0 ? 0 : y); -} - -float Simulation::remainder_p(float x, float y) -{ - return std::fmod(x, y) + (x>=0 ? 0 : y); -} - constexpr size_t ce_log2(size_t n) { return ((n < 2) ? 1 : 1 + ce_log2(n / 2)); diff --git a/src/simulation/Simulation.h b/src/simulation/Simulation.h index 194d197ed..c23a80d4f 100644 --- a/src/simulation/Simulation.h +++ b/src/simulation/Simulation.h @@ -11,7 +11,6 @@ #include "common/tpt-rand.h" #include "Element.h" #include "SimulationConfig.h" -#include "MissingElements.h" #include #include #include @@ -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; RNG rng; std::vector signs; - std::array elements; //Element * elements; - std::vector tools; - std::vector platent; - std::vector wtypes; - std::vector 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 blockP); // block coordinates + void Load(const GameSave *save, bool includePressure, Vec2 blockP); // block coordinates std::unique_ptr Save(bool includePressure, Rect partR); // particle coordinates void SaveSimOptions(GameSave &gameSave); SimulationSample GetSample(int x, int y); - std::unique_ptr CreateSnapshot(); + std::unique_ptr 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 + 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 + 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 customGol; - -public: - const CustomGOLData *GetCustomGOLByRule(int rule) const; - const std::vector GetCustomGol() { return customGol; } - void SetCustomGOL(std::vector newCustomGol); + bool useLuaCallbacks = false; private: CoordStack& getCoordStackSingleton(); diff --git a/src/simulation/SimulationData.cpp b/src/simulation/SimulationData.cpp index bbfaeed4c..1e101a851 100644 --- a/src/simulation/SimulationData.cpp +++ b/src/simulation/SimulationData.cpp @@ -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 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 LoadWalls() +static std::vector LoadWalls() { return std::vector{ @@ -73,7 +73,7 @@ std::vector LoadWalls() }; } -std::vector LoadMenus() +static std::vector LoadMenus() { return std::vector{ @@ -98,170 +98,244 @@ std::vector LoadMenus() }; } -std::vector LoadLatent() +void SimulationData::init_can_move() { - return - std::vector{ - /* 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 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(); } diff --git a/src/simulation/SimulationData.h b/src/simulation/SimulationData.h index 90dbed540..0f8bebda3 100644 --- a/src/simulation/SimulationData.h +++ b/src/simulation/SimulationData.h @@ -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 #include #include +#include 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 +{ +public: + std::array elements; + std::array graphicscache; + std::vector tools; + std::vector wtypes; + std::vector msections; + char can_move[PT_NUM][PT_NUM]; + static const std::array 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 LoadWalls(); +private: + std::vector customGol; -std::vector LoadMenus(); +public: + SimulationData(); + void InitElements(); -std::vector LoadLatent(); + void init_can_move(); + + const CustomGOLData *GetCustomGOLByRule(int rule) const; + const std::vector &GetCustomGol() const { return customGol; } + void SetCustomGOL(std::vector 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); + } + +}; diff --git a/src/simulation/elements/ACEL.cpp b/src/simulation/elements/ACEL.cpp index b0c9a4cb9..24a8b45f8 100644 --- a/src/simulation/elements/ACEL.cpp +++ b/src/simulation/elements/ACEL.cpp @@ -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; diff --git a/src/simulation/elements/ACID.cpp b/src/simulation/elements/ACID.cpp index 7baa317e8..620ced22c 100644 --- a/src/simulation/elements/ACID.cpp +++ b/src/simulation/elements/ACID.cpp @@ -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; } diff --git a/src/simulation/elements/ARAY.cpp b/src/simulation/elements/ARAY.cpp index 7784adefc..e101e3aac 100644 --- a/src/simulation/elements/ARAY.cpp +++ b/src/simulation/elements/ARAY.cpp @@ -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; diff --git a/src/simulation/elements/BCLN.cpp b/src/simulation/elements/BCLN.cpp index aebb675b9..78be0805d 100644 --- a/src/simulation/elements/BCLN.cpp +++ b/src/simulation/elements/BCLN.cpp @@ -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].tmpelements[parts[i].tmp].HighTemperatureTransition==PT_LAVA) + if (parts[i].ctype==PT_LAVA && parts[i].tmp>0 && parts[i].tmpparts_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; diff --git a/src/simulation/elements/BVBR.cpp b/src/simulation/elements/BVBR.cpp index 3a1b26686..38d04ae4d 100644 --- a/src/simulation/elements/BVBR.cpp +++ b/src/simulation/elements/BVBR.cpp @@ -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() { diff --git a/src/simulation/elements/C5.cpp b/src/simulation/elements/C5.cpp index 3b164a953..963245bfc 100644 --- a/src/simulation/elements/C5.cpp +++ b/src/simulation/elements/C5.cpp @@ -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)) { diff --git a/src/simulation/elements/CAUS.cpp b/src/simulation/elements/CAUS.cpp index afa318dee..5069ea67e 100644 --- a/src/simulation/elements/CAUS.cpp +++ b/src/simulation/elements/CAUS.cpp @@ -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; diff --git a/src/simulation/elements/CBNW.cpp b/src/simulation/elements/CBNW.cpp index 274364677..0c81ce7d2 100644 --- a/src/simulation/elements/CBNW.cpp +++ b/src/simulation/elements/CBNW.cpp @@ -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; diff --git a/src/simulation/elements/CLNE.cpp b/src/simulation/elements/CLNE.cpp index 72caac538..c3b910b8c 100644 --- a/src/simulation/elements/CLNE.cpp +++ b/src/simulation/elements/CLNE.cpp @@ -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].tmpelements[parts[i].tmp].HighTemperatureTransition==PT_LAVA) + if (parts[i].ctype==PT_LAVA && parts[i].tmp>0 && parts[i].tmp=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++) diff --git a/src/simulation/elements/CRAY.cpp b/src/simulation/elements/CRAY.cpp index 4e3d68d2e..197f84cff 100644 --- a/src/simulation/elements/CRAY.cpp +++ b/src/simulation/elements/CRAY.cpp @@ -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; } diff --git a/src/simulation/elements/DCEL.cpp b/src/simulation/elements/DCEL.cpp index c52c5ccbd..202959908 100644 --- a/src/simulation/elements/DCEL.cpp +++ b/src/simulation/elements/DCEL.cpp @@ -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; diff --git a/src/simulation/elements/DEST.cpp b/src/simulation/elements/DEST.cpp index 1f09a87db..b2c91c13b 100644 --- a/src/simulation/elements/DEST.cpp +++ b/src/simulation/elements/DEST.cpp @@ -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; diff --git a/src/simulation/elements/DMG.cpp b/src/simulation/elements/DMG.cpp index 0067555ad..ba0e4f043 100644 --- a/src/simulation/elements/DMG.cpp +++ b/src/simulation/elements/DMG.cpp @@ -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].HighPressureTransitionpart_change_type(ID(rr), x+nxi, y+nxj, sim->elements[t].HighPressureTransition); + if (t && elements[t].HighPressureTransition>-1 && elements[t].HighPressureTransitionpart_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) diff --git a/src/simulation/elements/DRAY.cpp b/src/simulation/elements/DRAY.cpp index 97218461d..6654370fd 100644 --- a/src/simulation/elements/DRAY.cpp +++ b/src/simulation/elements/DRAY.cpp @@ -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]; diff --git a/src/simulation/elements/DSTW.cpp b/src/simulation/elements/DSTW.cpp index 5565bf53b..6d097c327 100644 --- a/src/simulation/elements/DSTW.cpp +++ b/src/simulation/elements/DSTW.cpp @@ -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; diff --git a/src/simulation/elements/DTEC.cpp b/src/simulation/elements/DTEC.cpp index 911bd2dde..44a15d327 100644 --- a/src/simulation/elements/DTEC.cpp +++ b/src/simulation/elements/DTEC.cpp @@ -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; diff --git a/src/simulation/elements/ELEC.cpp b/src/simulation/elements/ELEC.cpp index 9874019e9..f759983c9 100644 --- a/src/simulation/elements/ELEC.cpp +++ b/src/simulation/elements/ELEC.cpp @@ -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); diff --git a/src/simulation/elements/EMBR.cpp b/src/simulation/elements/EMBR.cpp index c94a1ad5d..4edaa1ddd 100644 --- a/src/simulation/elements/EMBR.cpp +++ b/src/simulation/elements/EMBR.cpp @@ -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; diff --git a/src/simulation/elements/EMP.h b/src/simulation/elements/EMP.h new file mode 100644 index 000000000..d6352f49e --- /dev/null +++ b/src/simulation/elements/EMP.h @@ -0,0 +1,4 @@ +#pragma once +#include "simulation/ElementDefs.h" + +void Element_EMP_Trigger(Simulation *sim, int triggerCount); diff --git a/src/simulation/elements/ETRD.h b/src/simulation/elements/ETRD.h new file mode 100644 index 000000000..35e799fc7 --- /dev/null +++ b/src/simulation/elements/ETRD.h @@ -0,0 +1,4 @@ +#pragma once +#include "simulation/ElementDefs.h" + +int Element_ETRD_nearestSparkablePart(Simulation *sim, int targetId); diff --git a/src/simulation/elements/EXOT.cpp b/src/simulation/elements/EXOT.cpp index c4d630f3e..5b9d7592b 100644 --- a/src/simulation/elements/EXOT.cpp +++ b/src/simulation/elements/EXOT.cpp @@ -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); diff --git a/src/simulation/elements/FIGH.cpp b/src/simulation/elements/FIGH.cpp index fc82caee3..9f23603e8 100644 --- a/src/simulation/elements/FIGH.cpp +++ b/src/simulation/elements/FIGH.cpp @@ -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 (tarxctype&0x3FFFFFFF) { diff --git a/src/simulation/elements/FILT.h b/src/simulation/elements/FILT.h new file mode 100644 index 000000000..9289e9218 --- /dev/null +++ b/src/simulation/elements/FILT.h @@ -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); diff --git a/src/simulation/elements/FIRE.cpp b/src/simulation/elements/FIRE.cpp index 59c243a97..e845d9b79 100644 --- a/src/simulation/elements/FIRE.cpp +++ b/src/simulation/elements/FIRE.cpp @@ -1,7 +1,7 @@ #include "simulation/ElementCommon.h" +#include "FIRE.h" #include -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) { diff --git a/src/simulation/elements/FIRE.h b/src/simulation/elements/FIRE.h new file mode 100644 index 000000000..0d07ea535 --- /dev/null +++ b/src/simulation/elements/FIRE.h @@ -0,0 +1,4 @@ +#pragma once +#include "simulation/ElementDefs.h" + +int Element_FIRE_update(UPDATE_FUNC_ARGS); diff --git a/src/simulation/elements/FIRW.cpp b/src/simulation/elements/FIRW.cpp index 8510a9f25..c09f67c7f 100644 --- a/src/simulation/elements/FIRW.cpp +++ b/src/simulation/elements/FIRW.cpp @@ -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); diff --git a/src/simulation/elements/FOG.cpp b/src/simulation/elements/FOG.cpp index 19765bdcd..830c0adfc 100644 --- a/src/simulation/elements/FOG.cpp +++ b/src/simulation/elements/FOG.cpp @@ -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); } diff --git a/src/simulation/elements/FRAY.cpp b/src/simulation/elements/FRAY.cpp index 286e28755..df011d61a 100644 --- a/src/simulation/elements/FRAY.cpp +++ b/src/simulation/elements/FRAY.cpp @@ -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); } diff --git a/src/simulation/elements/FWRK.cpp b/src/simulation/elements/FWRK.cpp index 4a6f5ef69..236e9b5e2 100644 --- a/src/simulation/elements/FWRK.cpp +++ b/src/simulation/elements/FWRK.cpp @@ -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)) diff --git a/src/simulation/elements/GEL.cpp b/src/simulation/elements/GEL.cpp index 7da0abfbe..b1fed66b3 100644 --- a/src/simulation/elements/GEL.cpp +++ b/src/simulation/elements/GEL.cpp @@ -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; diff --git a/src/simulation/elements/GLOW.cpp b/src/simulation/elements/GLOW.cpp index 7df7367c4..f9e986c41 100644 --- a/src/simulation/elements/GLOW.cpp +++ b/src/simulation/elements/GLOW.cpp @@ -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; diff --git a/src/simulation/elements/GOLD.cpp b/src/simulation/elements/GOLD.cpp index cab7bfa63..e45dd2ff9 100644 --- a/src/simulation/elements/GOLD.cpp +++ b/src/simulation/elements/GOLD.cpp @@ -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; diff --git a/src/simulation/elements/GRAV.cpp b/src/simulation/elements/GRAV.cpp index cd818851d..c36d4687a 100644 --- a/src/simulation/elements/GRAV.cpp +++ b/src/simulation/elements/GRAV.cpp @@ -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; diff --git a/src/simulation/elements/H2.cpp b/src/simulation/elements/H2.cpp index ccb0ae299..c7cedc4c6 100644 --- a/src/simulation/elements/H2.cpp +++ b/src/simulation/elements/H2.cpp @@ -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) diff --git a/src/simulation/elements/HEAC.cpp b/src/simulation/elements/HEAC.cpp index 9fdb10928..7d06e18d1 100644 --- a/src/simulation/elements/HEAC.cpp +++ b/src/simulation/elements/HEAC.cpp @@ -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; } diff --git a/src/simulation/elements/ICEI.cpp b/src/simulation/elements/ICEI.cpp index 3f93528df..a69572184 100644 --- a/src/simulation/elements/ICEI.cpp +++ b/src/simulation/elements/ICEI.cpp @@ -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); diff --git a/src/simulation/elements/LAVA.cpp b/src/simulation/elements/LAVA.cpp index 0dcd4c3b5..c1c1f68e3 100644 --- a/src/simulation/elements/LAVA.cpp +++ b/src/simulation/elements/LAVA.cpp @@ -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); diff --git a/src/simulation/elements/LCRY.cpp b/src/simulation/elements/LCRY.cpp index 7c0b5d6d6..08336aa95 100644 --- a/src/simulation/elements/LCRY.cpp +++ b/src/simulation/elements/LCRY.cpp @@ -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; diff --git a/src/simulation/elements/LDTC.cpp b/src/simulation/elements/LDTC.cpp index 0020cc8ad..db52e2511 100644 --- a/src/simulation/elements/LDTC.cpp +++ b/src/simulation/elements/LDTC.cpp @@ -1,5 +1,5 @@ #include "simulation/ElementCommon.h" -#include +#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; diff --git a/src/simulation/elements/LIFE.cpp b/src/simulation/elements/LIFE.cpp index 184df2f44..411f4096e 100644 --- a/src/simulation/elements/LIFE.cpp +++ b/src/simulation/elements/LIFE.cpp @@ -50,6 +50,7 @@ void Element::Element_LIFE() static int graphics(GRAPHICS_FUNC_ARGS) { + auto &builtinGol = SimulationData::builtinGol; auto colour1 = RGB::Unpack(cpart->dcolour); auto colour2 = RGB::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; diff --git a/src/simulation/elements/LIGH.cpp b/src/simulation/elements/LIGH.cpp index 92380b43e..4743c1814 100644 --- a/src/simulation/elements/LIGH.cpp +++ b/src/simulation/elements/LIGH.cpp @@ -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); } } } diff --git a/src/simulation/elements/LITH.cpp b/src/simulation/elements/LITH.cpp index 4ace0e832..7a647d2c9 100644 --- a/src/simulation/elements/LITH.cpp +++ b/src/simulation/elements/LITH.cpp @@ -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; diff --git a/src/simulation/elements/LOLZ.h b/src/simulation/elements/LOLZ.h new file mode 100644 index 000000000..1eaecdab7 --- /dev/null +++ b/src/simulation/elements/LOLZ.h @@ -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]; diff --git a/src/simulation/elements/LSNS.cpp b/src/simulation/elements/LSNS.cpp index a70f4a22e..a5f933fe0 100644 --- a/src/simulation/elements/LSNS.cpp +++ b/src/simulation/elements/LSNS.cpp @@ -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; diff --git a/src/simulation/elements/METL.cpp b/src/simulation/elements/METL.cpp index bcb3656ef..122fe30cf 100644 --- a/src/simulation/elements/METL.cpp +++ b/src/simulation/elements/METL.cpp @@ -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; diff --git a/src/simulation/elements/NBLE.cpp b/src/simulation/elements/NBLE.cpp index e2b9daffe..52ec8017f 100644 --- a/src/simulation/elements/NBLE.cpp +++ b/src/simulation/elements/NBLE.cpp @@ -49,6 +49,8 @@ void Element::Element_NBLE() static int update(UPDATE_FUNC_ARGS) { + auto &sd = SimulationData::CRef(); + auto &can_move = sd.can_move; if (parts[i].temp > 5273.15 && sim->pv[y/CELL][x/CELL] > 100.0f) { parts[i].tmp |= 0x1; @@ -75,7 +77,7 @@ static int update(UPDATE_FUNC_ARGS) parts[j].tmp = 0x1; } int 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_NBLE) + if (can_move[PT_PLSM][rt] || rt == PT_NBLE) { j = sim->create_part(-3,rx,ry,PT_PLSM); if (j != -1) diff --git a/src/simulation/elements/NEUT.cpp b/src/simulation/elements/NEUT.cpp index bfd0c146a..1feb16ea4 100644 --- a/src/simulation/elements/NEUT.cpp +++ b/src/simulation/elements/NEUT.cpp @@ -1,6 +1,6 @@ #include "simulation/ElementCommon.h" +#include "FIRE.h" -int Element_FIRE_update(UPDATE_FUNC_ARGS); static int update(UPDATE_FUNC_ARGS); static int graphics(GRAPHICS_FUNC_ARGS); static void create(ELEMENT_CREATE_FUNC_ARGS); diff --git a/src/simulation/elements/NTCT.cpp b/src/simulation/elements/NTCT.cpp index 47c219eb7..3e51cd974 100644 --- a/src/simulation/elements/NTCT.cpp +++ b/src/simulation/elements/NTCT.cpp @@ -1,6 +1,5 @@ #include "simulation/ElementCommon.h" - -int Element_NTCT_update(UPDATE_FUNC_ARGS); +#include "NTCT.h" void Element::Element_NTCT() { diff --git a/src/simulation/elements/NTCT.h b/src/simulation/elements/NTCT.h new file mode 100644 index 000000000..0ceed8a5f --- /dev/null +++ b/src/simulation/elements/NTCT.h @@ -0,0 +1,4 @@ +#pragma once +#include "simulation/ElementDefs.h" + +int Element_NTCT_update(UPDATE_FUNC_ARGS); diff --git a/src/simulation/elements/O2.cpp b/src/simulation/elements/O2.cpp index bba9c936f..06747486d 100644 --- a/src/simulation/elements/O2.cpp +++ b/src/simulation/elements/O2.cpp @@ -47,6 +47,8 @@ void Element::Element_O2() 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++) @@ -99,7 +101,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), r = TYP(pmap[ry][rx]); - if (sim->can_move[PT_PLSM][r] || r == PT_O2) + if (can_move[PT_PLSM][r] || r == PT_O2) { j = sim->create_part(-3,rx,ry,PT_PLSM); if (j > -1) diff --git a/src/simulation/elements/PBCN.cpp b/src/simulation/elements/PBCN.cpp index e2b678d52..21ad6930e 100644 --- a/src/simulation/elements/PBCN.cpp +++ b/src/simulation/elements/PBCN.cpp @@ -1,8 +1,8 @@ #include "simulation/ElementCommon.h" +#include "PCLN.h" static int update(UPDATE_FUNC_ARGS); static int graphics(GRAPHICS_FUNC_ARGS); -bool Element_PCLN_ctypeDraw(CTYPEDRAW_FUNC_ARGS); void Element::Element_PBCN() { @@ -54,6 +54,8 @@ constexpr float ADVECTION = 0.1f; static int update(UPDATE_FUNC_ARGS) { + auto &sd = SimulationData::CRef(); + auto &elements = sd.elements; if (!parts[i].tmp2 && sim->pv[y/CELL][x/CELL]>4.0f) parts[i].tmp2 = sim->rng.between(80, 119); if (parts[i].tmp2) @@ -66,7 +68,7 @@ static int update(UPDATE_FUNC_ARGS) return 1; } } - 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++) { @@ -117,7 +119,7 @@ static int update(UPDATE_FUNC_ARGS) } } } - if (parts[i].ctype>0 && parts[i].ctypeelements[parts[i].ctype].Enabled) + if (parts[i].ctype>0 && parts[i].ctypecreate_part(-1, x + sim->rng.between(-1, 1), y + sim->rng.between(-1, 1), TYP(parts[i].ctype)); if (np>-1) { - if (parts[i].ctype==PT_LAVA && parts[i].tmp>0 && parts[i].tmpelements[parts[i].tmp].HighTemperatureTransition==PT_LAVA) + if (parts[i].ctype==PT_LAVA && parts[i].tmp>0 && parts[i].tmp0 && parts[i].life!=10) parts[i].life--; for (auto rx = -2; rx <= 2; rx++) @@ -83,7 +85,7 @@ static int update(UPDATE_FUNC_ARGS) } } } - 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++) { @@ -108,7 +110,7 @@ static int update(UPDATE_FUNC_ARGS) } } } - if (parts[i].ctype>0 && parts[i].ctypeelements[parts[i].ctype].Enabled && parts[i].life==10) + if (parts[i].ctype>0 && parts[i].ctypecreate_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].tmpelements[parts[i].tmp].HighTemperatureTransition==PT_LAVA) + if (parts[i].ctype==PT_LAVA && parts[i].tmp>0 && parts[i].tmprng.between(0, 7) * 0.78540f; sim->parts[i].vx = 3.0f * cosf(a); sim->parts[i].vy = 3.0f * sinf(a); - int Element_FILT_interactWavelengths(Simulation *sim, Particle* cpart, int origWl); if (TYP(sim->pmap[y][x]) == PT_FILT) sim->parts[i].ctype = Element_FILT_interactWavelengths(sim, &sim->parts[ID(sim->pmap[y][x])], sim->parts[i].ctype); } diff --git a/src/simulation/elements/PIPE.cpp b/src/simulation/elements/PIPE.cpp index c39961f00..827ef1a8d 100644 --- a/src/simulation/elements/PIPE.cpp +++ b/src/simulation/elements/PIPE.cpp @@ -1,14 +1,11 @@ #include "simulation/ElementCommon.h" +#include "PIPE.h" +#include "SOAP.h" -extern const std::array, 8> Element_PIPE_offsets; -void Element_PIPE_transformPatchOffsets(Particle &part, const std::array &offsetMap); -int Element_PIPE_update(UPDATE_FUNC_ARGS); -int Element_PIPE_graphics(GRAPHICS_FUNC_ARGS); -void Element_PIPE_transfer_pipe_to_part(Simulation * sim, Particle *pipe, Particle *part, bool STOR); +static void props_pipe_to_part(const Particle *pipe, Particle *part, bool STOR); static void transfer_part_to_pipe(Particle *part, Particle *pipe); static void transfer_pipe_to_pipe(Particle *src, Particle *dest, bool STOR); static void pushParticle(Simulation * sim, int i, int count, int original); -void Element_SOAP_detach(Simulation * sim, int i); void Element::Element_PIPE() { @@ -123,7 +120,9 @@ static unsigned int nextColor(unsigned int flags) int Element_PIPE_update(UPDATE_FUNC_ARGS) { - if (parts[i].ctype && !sim->elements[TYP(parts[i].ctype)].Enabled) + auto &sd = SimulationData::CRef(); + auto &elements = sd.elements; + if (parts[i].ctype && !elements[TYP(parts[i].ctype)].Enabled) parts[i].ctype = 0; if (parts[i].tmp & PPIP_TMPFLAG_TRIGGERS) { @@ -259,14 +258,14 @@ int Element_PIPE_update(UPDATE_FUNC_ARGS) } } //try eating particle at entrance - else if (!TYP(parts[i].ctype) && (sim->elements[TYP(r)].Properties & (TYPE_PART | TYPE_LIQUID | TYPE_GAS | TYPE_ENERGY))) + else if (!TYP(parts[i].ctype) && (elements[TYP(r)].Properties & (TYPE_PART | TYPE_LIQUID | TYPE_GAS | TYPE_ENERGY))) { if (TYP(r)==PT_SOAP) Element_SOAP_detach(sim, ID(r)); transfer_part_to_pipe(parts+(ID(r)), parts+i); sim->kill_part(ID(r)); } - else if (!TYP(parts[i].ctype) && TYP(r)==PT_STOR && sim->IsElement(parts[ID(r)].tmp) && (sim->elements[parts[ID(r)].tmp].Properties & (TYPE_PART | TYPE_LIQUID | TYPE_GAS | TYPE_ENERGY))) + else if (!TYP(parts[i].ctype) && TYP(r)==PT_STOR && sd.IsElement(parts[ID(r)].tmp) && (elements[parts[ID(r)].tmp].Properties & (TYPE_PART | TYPE_LIQUID | TYPE_GAS | TYPE_ENERGY))) { // STOR stores properties in the same places as PIPE does transfer_pipe_to_pipe(parts+(ID(r)), parts+i, true); @@ -344,51 +343,60 @@ int Element_PIPE_update(UPDATE_FUNC_ARGS) int Element_PIPE_graphics(GRAPHICS_FUNC_ARGS) { + auto &sd = SimulationData::CRef(); + auto &elements = sd.elements; + auto &graphicscache = sd.graphicscache; int t = TYP(cpart->ctype); - if (t>0 && tsim->elements[t].Enabled) + if (t>0 && tgraphicscache[t].isready) + if (graphicscache[t].isready) { - *pixel_mode = ren->graphicscache[t].pixel_mode; - *cola = ren->graphicscache[t].cola; - *colr = ren->graphicscache[t].colr; - *colg = ren->graphicscache[t].colg; - *colb = ren->graphicscache[t].colb; - *firea = ren->graphicscache[t].firea; - *firer = ren->graphicscache[t].firer; - *fireg = ren->graphicscache[t].fireg; - *fireb = ren->graphicscache[t].fireb; + *pixel_mode = graphicscache[t].pixel_mode; + *cola = graphicscache[t].cola; + *colr = graphicscache[t].colr; + *colg = graphicscache[t].colg; + *colb = graphicscache[t].colb; + *firea = graphicscache[t].firea; + *firer = graphicscache[t].firer; + *fireg = graphicscache[t].fireg; + *fireb = graphicscache[t].fireb; } else { - // Temp particle used for graphics. - Particle tpart = *cpart; - - // Emulate the graphics of stored particle. - memset(cpart, 0, sizeof(Particle)); - cpart->type = t; - cpart->temp = tpart.temp; - cpart->life = tpart.tmp2; - cpart->tmp = tpart.tmp3; - cpart->ctype = tpart.tmp4; - - RGB colour = ren->sim->elements[t].Colour; + // We emulate the graphics of the stored particle. We need a const Particle *cpart to pass to the graphics function, + // but we don't have a Particle that is populated the way the graphics function expects, so we construct a temporary + // one and present that to it. + // + // Native graphics functions are well-behaved and use the cpart we give them, no questions asked, so we can just have + // the Particle on stack. Swapping the pointers in cpart with tpart takes care of passing the particle on stack to the + // native graphics function. Lua graphics functions are more complicated to appease: they access particle data through the + // particle ID, so not only do we have to give them a correctly populated Particle, it also has to be somewhere in Simulation. + // luaGraphicsWrapper takes care of this. + RGB colour = elements[t].Colour; *colr = colour.Red; *colg = colour.Green; *colb = colour.Blue; - if (ren->sim->elements[t].Graphics) + auto *graphics = elements[t].Graphics; + if (graphics) { - (*(ren->sim->elements[t].Graphics))(ren, cpart, nx, ny, pixel_mode, cola, colr, colg, colb, firea, firer, fireg, fireb); + Particle tpart; + props_pipe_to_part(cpart, &tpart, false); + auto *prevPipeSubcallCpart = gfctx.pipeSubcallCpart; + auto *prevPipeSubcallTpart = gfctx.pipeSubcallTpart; + gfctx.pipeSubcallCpart = cpart; + gfctx.pipeSubcallTpart = &tpart; + cpart = gfctx.pipeSubcallTpart; + graphics(GRAPHICS_FUNC_SUBCALL_ARGS); + cpart = gfctx.pipeSubcallCpart; + gfctx.pipeSubcallCpart = prevPipeSubcallCpart; + gfctx.pipeSubcallTpart = prevPipeSubcallTpart; } else { - Element::defaultGraphics(ren, cpart, nx, ny, pixel_mode, cola, colr, colg, colb, firea, firer, fireg, fireb); + Element::defaultGraphics(GRAPHICS_FUNC_SUBCALL_ARGS); } - - // Restore original particle data. - *cpart = tpart; } } else @@ -417,26 +425,26 @@ int Element_PIPE_graphics(GRAPHICS_FUNC_ARGS) return 0; } -void Element_PIPE_transfer_pipe_to_part(Simulation * sim, Particle *pipe, Particle *part, bool STOR) +static void props_pipe_to_part(const Particle *pipe, Particle *part, bool STOR) { + auto &sd = SimulationData::CRef(); + auto &elements = sd.elements; // STOR also calls this function to move particles from STOR to PRTI // PIPE was changed, so now PIPE and STOR don't use the same particle storage format if (STOR) { part->type = TYP(pipe->tmp); - pipe->tmp = 0; } else { part->type = TYP(pipe->ctype); - pipe->ctype = 0; } part->temp = pipe->temp; part->life = pipe->tmp2; part->tmp = pipe->tmp3; part->ctype = pipe->tmp4; - if (!(sim->elements[part->type].Properties & TYPE_ENERGY)) + if (!(elements[part->type].Properties & TYPE_ENERGY)) { part->vx = 0.0f; part->vy = 0.0f; @@ -446,6 +454,19 @@ void Element_PIPE_transfer_pipe_to_part(Simulation * sim, Particle *pipe, Partic part->dcolour = 0; } +void Element_PIPE_transfer_pipe_to_part(Simulation * sim, Particle *pipe, Particle *part, bool STOR) +{ + props_pipe_to_part(pipe, part, STOR); + if (STOR) + { + pipe->tmp = 0; + } + else + { + pipe->ctype = 0; + } +} + static void transfer_part_to_pipe(Particle *part, Particle *pipe) { pipe->ctype = part->type; diff --git a/src/simulation/elements/PIPE.h b/src/simulation/elements/PIPE.h new file mode 100644 index 000000000..759c13675 --- /dev/null +++ b/src/simulation/elements/PIPE.h @@ -0,0 +1,11 @@ +#pragma once +#include "simulation/ElementDefs.h" + +int Element_PIPE_graphics(GRAPHICS_FUNC_ARGS); +void Element_PIPE_transfer_pipe_to_part(Simulation * sim, Particle *pipe, Particle *part, bool STOR); +void Element_PIPE_transformPatchOffsets(Particle &part, const std::array &offsetMap); +int Element_PIPE_update(UPDATE_FUNC_ARGS); +void Element_PPIP_flood_trigger(Simulation * sim, int x, int y, int sparkedBy); + +extern int Element_PPIP_ppip_changed; +extern const std::array, 8> Element_PIPE_offsets; diff --git a/src/simulation/elements/PLSM.cpp b/src/simulation/elements/PLSM.cpp index b737a8a0a..525442175 100644 --- a/src/simulation/elements/PLSM.cpp +++ b/src/simulation/elements/PLSM.cpp @@ -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); diff --git a/src/simulation/elements/PPIP.cpp b/src/simulation/elements/PPIP.cpp index e245dbbc7..1909fd6cb 100644 --- a/src/simulation/elements/PPIP.cpp +++ b/src/simulation/elements/PPIP.cpp @@ -1,7 +1,5 @@ #include "simulation/ElementCommon.h" - -int Element_PIPE_update(UPDATE_FUNC_ARGS); -int Element_PIPE_graphics(GRAPHICS_FUNC_ARGS); +#include "PIPE.h" void Element::Element_PPIP() { diff --git a/src/simulation/elements/PQRT.cpp b/src/simulation/elements/PQRT.cpp index 7a2cfc8db..ef3f8e106 100644 --- a/src/simulation/elements/PQRT.cpp +++ b/src/simulation/elements/PQRT.cpp @@ -1,7 +1,6 @@ #include "simulation/ElementCommon.h" +#include "QRTZ.h" -int Element_QRTZ_update(UPDATE_FUNC_ARGS); -int Element_QRTZ_graphics(GRAPHICS_FUNC_ARGS); static void create(ELEMENT_CREATE_FUNC_ARGS); void Element::Element_PQRT() diff --git a/src/simulation/elements/PROT.cpp b/src/simulation/elements/PROT.cpp index 5d0c7a2a3..6dfa398c9 100644 --- a/src/simulation/elements/PROT.cpp +++ b/src/simulation/elements/PROT.cpp @@ -54,6 +54,8 @@ void Element::Element_PROT() static int update(UPDATE_FUNC_ARGS) { + auto &sd = SimulationData::CRef(); + auto &elements = sd.elements; sim->pv[y/CELL][x/CELL] -= .003f; int under = pmap[y][x]; int utype = TYP(under); @@ -111,14 +113,14 @@ static int update(UPDATE_FUNC_ARGS) break; default: //set off explosives (only when hot because it wasn't as fun when it made an entire save explode) - if (parts[i].temp > 273.15f + 500.0f && (sim->elements[utype].Flammable || sim->elements[utype].Explosive || utype == PT_BANG)) + if (parts[i].temp > 273.15f + 500.0f && (elements[utype].Flammable || elements[utype].Explosive || utype == PT_BANG)) { sim->create_part(uID, x, y, PT_FIRE); - parts[uID].temp += restrict_flt(float(sim->elements[utype].Flammable * 5), MIN_TEMP, MAX_TEMP); + parts[uID].temp += restrict_flt(float(elements[utype].Flammable * 5), MIN_TEMP, MAX_TEMP); sim->pv[y / CELL][x / CELL] += 1.00f; } //prevent inactive sparkable elements from being sparked - else if ((sim->elements[utype].Properties&PROP_CONDUCTS) && parts[uID].life <= 4) + else if ((elements[utype].Properties&PROP_CONDUCTS) && parts[uID].life <= 4) { parts[uID].life = 40 + parts[uID].life; } diff --git a/src/simulation/elements/PRTI.cpp b/src/simulation/elements/PRTI.cpp index c0675eed5..fb8f80261 100644 --- a/src/simulation/elements/PRTI.cpp +++ b/src/simulation/elements/PRTI.cpp @@ -1,9 +1,10 @@ #include "simulation/ElementCommon.h" +#include "simulation/orbitalparts.h" +#include "PIPE.h" +#include "SOAP.h" -void Element_PIPE_transfer_pipe_to_part(Simulation * sim, Particle *pipe, Particle *part, bool STOR); static int update(UPDATE_FUNC_ARGS); static int graphics(GRAPHICS_FUNC_ARGS); -void Element_SOAP_detach(Simulation * sim, int i); void Element::Element_PRTI() { @@ -59,6 +60,8 @@ void Element::Element_PRTI() static int update(UPDATE_FUNC_ARGS) { + auto &sd = SimulationData::CRef(); + auto &elements = sd.elements; int fe = 0; parts[i].tmp = (int)((parts[i].temp-73.15f)/100+1); @@ -76,7 +79,7 @@ static int update(UPDATE_FUNC_ARGS) int r = pmap[y+ry][x+rx]; if (!r || TYP(r) == PT_STOR) fe = 1; - if (!r || (!(sim->elements[TYP(r)].Properties & (TYPE_PART | TYPE_LIQUID | TYPE_GAS | TYPE_ENERGY)) && TYP(r)!=PT_SPRK && TYP(r)!=PT_STOR)) + if (!r || (!(elements[TYP(r)].Properties & (TYPE_PART | TYPE_LIQUID | TYPE_GAS | TYPE_ENERGY)) && TYP(r)!=PT_SPRK && TYP(r)!=PT_STOR)) { r = sim->photons[y+ry][x+rx]; if (!r) @@ -94,7 +97,7 @@ static int update(UPDATE_FUNC_ARGS) { if (TYP(r) == PT_STOR) { - if (sim->IsElement(parts[ID(r)].tmp) && (sim->elements[parts[ID(r)].tmp].Properties & (TYPE_PART | TYPE_LIQUID | TYPE_GAS | TYPE_ENERGY))) + if (sd.IsElement(parts[ID(r)].tmp) && (elements[parts[ID(r)].tmp].Properties & (TYPE_PART | TYPE_LIQUID | TYPE_GAS | TYPE_ENERGY))) { // STOR uses same format as PIPE, so we can use this function to do the transfer Element_PIPE_transfer_pipe_to_part(sim, parts+(ID(r)), &sim->portalp[parts[i].tmp][count][nnx], true); @@ -121,7 +124,7 @@ static int update(UPDATE_FUNC_ARGS) int orbl[4] = {0, 0, 0, 0}; //Orbital locations if (!sim->parts[i].life) parts[i].life = sim->rng.gen(); if (!sim->parts[i].ctype) parts[i].ctype = sim->rng.gen(); - sim->orbitalparts_get(parts[i].life, parts[i].ctype, orbd, orbl); + orbitalparts_get(parts[i].life, parts[i].ctype, orbd, orbl); for (int r = 0; r < 4; r++) { if (orbd[r]>1) { orbd[r] -= 12; @@ -137,7 +140,7 @@ static int update(UPDATE_FUNC_ARGS) orbl[r] = sim->rng.between(0, 254); } } - sim->orbitalparts_set(&parts[i].life, &parts[i].ctype, orbd, orbl); + orbitalparts_set(&parts[i].life, &parts[i].ctype, orbd, orbl); } else { parts[i].life = 0; parts[i].ctype = 0; diff --git a/src/simulation/elements/PRTO.cpp b/src/simulation/elements/PRTO.cpp index bf9b1e485..9924417a9 100644 --- a/src/simulation/elements/PRTO.cpp +++ b/src/simulation/elements/PRTO.cpp @@ -1,4 +1,5 @@ #include "simulation/ElementCommon.h" +#include "simulation/orbitalparts.h" static int update(UPDATE_FUNC_ARGS); static int graphics(GRAPHICS_FUNC_ARGS); @@ -144,7 +145,7 @@ static int update(UPDATE_FUNC_ARGS) int orbl[4] = {0, 0, 0, 0}; //Orbital locations if (!sim->parts[i].life) parts[i].life = sim->rng.gen(); if (!sim->parts[i].ctype) parts[i].ctype = sim->rng.gen(); - sim->orbitalparts_get(parts[i].life, parts[i].ctype, orbd, orbl); + orbitalparts_get(parts[i].life, parts[i].ctype, orbd, orbl); for (auto r = 0; r < 4; r++) { if (orbd[r]<254) @@ -166,7 +167,7 @@ static int update(UPDATE_FUNC_ARGS) orbl[r] = sim->rng.between(0, 254); } } - sim->orbitalparts_set(&parts[i].life, &parts[i].ctype, orbd, orbl); + orbitalparts_set(&parts[i].life, &parts[i].ctype, orbd, orbl); } else { diff --git a/src/simulation/elements/PSNS.cpp b/src/simulation/elements/PSNS.cpp index 3d893f287..221efbef8 100644 --- a/src/simulation/elements/PSNS.cpp +++ b/src/simulation/elements/PSNS.cpp @@ -48,6 +48,8 @@ void Element::Element_PSNS() static int update(UPDATE_FUNC_ARGS) { + auto &sd = SimulationData::CRef(); + auto &elements = sd.elements; if ((parts[i].tmp == 0 && sim->pv[y/CELL][x/CELL] > parts[i].temp-273.15f) || (parts[i].tmp == 2 && sim->pv[y/CELL][x/CELL] < parts[i].temp-273.15f)) { for (auto rx = -2; rx <= 2; rx++) @@ -62,7 +64,7 @@ static int update(UPDATE_FUNC_ARGS) if (sim->parts_avg(i,ID(r),PT_INSL) != PT_INSL) { auto rt = TYP(r); - 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; diff --git a/src/simulation/elements/QRTZ.cpp b/src/simulation/elements/QRTZ.cpp index 76f778eae..a0c4987b6 100644 --- a/src/simulation/elements/QRTZ.cpp +++ b/src/simulation/elements/QRTZ.cpp @@ -1,7 +1,6 @@ #include "simulation/ElementCommon.h" +#include "QRTZ.h" -int Element_QRTZ_update(UPDATE_FUNC_ARGS); -int Element_QRTZ_graphics(GRAPHICS_FUNC_ARGS); static void create(ELEMENT_CREATE_FUNC_ARGS); void Element::Element_QRTZ() diff --git a/src/simulation/elements/QRTZ.h b/src/simulation/elements/QRTZ.h new file mode 100644 index 000000000..f08613b0b --- /dev/null +++ b/src/simulation/elements/QRTZ.h @@ -0,0 +1,5 @@ +#pragma once +#include "simulation/ElementDefs.h" + +int Element_QRTZ_graphics(GRAPHICS_FUNC_ARGS); +int Element_QRTZ_update(UPDATE_FUNC_ARGS); diff --git a/src/simulation/elements/RFGL.cpp b/src/simulation/elements/RFGL.cpp index ee8372368..16536c204 100644 --- a/src/simulation/elements/RFGL.cpp +++ b/src/simulation/elements/RFGL.cpp @@ -1,6 +1,5 @@ #include "simulation/ElementCommon.h" - -int Element_RFRG_update(UPDATE_FUNC_ARGS); +#include "RFRG.h" void Element::Element_RFGL() { diff --git a/src/simulation/elements/RFRG.cpp b/src/simulation/elements/RFRG.cpp index 0c728ef16..50936fbff 100644 --- a/src/simulation/elements/RFRG.cpp +++ b/src/simulation/elements/RFRG.cpp @@ -1,6 +1,5 @@ #include "simulation/ElementCommon.h" - -int Element_RFRG_update(UPDATE_FUNC_ARGS); +#include "RFRG.h" void Element::Element_RFRG() { diff --git a/src/simulation/elements/RFRG.h b/src/simulation/elements/RFRG.h new file mode 100644 index 000000000..828394ef6 --- /dev/null +++ b/src/simulation/elements/RFRG.h @@ -0,0 +1,4 @@ +#pragma once +#include "simulation/ElementDefs.h" + +int Element_RFRG_update(UPDATE_FUNC_ARGS); diff --git a/src/simulation/elements/RPEL.cpp b/src/simulation/elements/RPEL.cpp index 0bde82704..44232165b 100644 --- a/src/simulation/elements/RPEL.cpp +++ b/src/simulation/elements/RPEL.cpp @@ -49,6 +49,8 @@ void Element::Element_RPEL() static int update(UPDATE_FUNC_ARGS) { + auto &sd = SimulationData::CRef(); + auto &elements = sd.elements; int r, rx, ry, ri; for(ri = 0; ri <= 10; ri++) { @@ -60,7 +62,7 @@ static int update(UPDATE_FUNC_ARGS) if (!r) r = sim->photons[y+ry][x+rx]; - if (r && !(sim->elements[TYP(r)].Properties & TYPE_SOLID)) { + if (r && !(elements[TYP(r)].Properties & TYPE_SOLID)) { if (!parts[i].ctype || parts[i].ctype == parts[ID(r)].type) { parts[ID(r)].vx += isign(rx)*((parts[i].temp-273.15)/10.0f); parts[ID(r)].vy += isign(ry)*((parts[i].temp-273.15)/10.0f); diff --git a/src/simulation/elements/SLTW.cpp b/src/simulation/elements/SLTW.cpp index 2a3805f23..95423b398 100644 --- a/src/simulation/elements/SLTW.cpp +++ b/src/simulation/elements/SLTW.cpp @@ -29,6 +29,7 @@ void Element::Element_SLTW() Weight = 35; HeatConduct = 75; + LatentHeat = 7500; Description = "Saltwater, conducts electricity, difficult to freeze."; Properties = TYPE_LIQUID|PROP_CONDUCTS|PROP_LIFE_DEC|PROP_NEUTPENETRATE; diff --git a/src/simulation/elements/SNOW.cpp b/src/simulation/elements/SNOW.cpp index e729db65c..08b273cb0 100644 --- a/src/simulation/elements/SNOW.cpp +++ b/src/simulation/elements/SNOW.cpp @@ -31,6 +31,7 @@ void Element::Element_SNOW() DefaultProperties.temp = R_TEMP - 30.0f + 273.15f; HeatConduct = 46; + LatentHeat = 1095; Description = "Light particles. Created when ICE breaks under pressure."; Properties = TYPE_PART|PROP_NEUTPASS; diff --git a/src/simulation/elements/SOAP.cpp b/src/simulation/elements/SOAP.cpp index 1c335c540..0cf43ff60 100644 --- a/src/simulation/elements/SOAP.cpp +++ b/src/simulation/elements/SOAP.cpp @@ -99,6 +99,8 @@ static int update(UPDATE_FUNC_ARGS) //0x02 - first mate yes/no //0x04 - "back" mate yes/no + auto &sd = SimulationData::CRef(); + auto &elements = sd.elements; if (parts[i].ctype&1) { // reset invalid SOAP links @@ -171,7 +173,7 @@ static int update(UPDATE_FUNC_ARGS) if (parts[i].temp>FREEZING) { if (sim->bmap[(y+ry)/CELL][(x+rx)/CELL] - || (r && !(sim->elements[TYP(r)].Properties&TYPE_GAS) + || (r && !(elements[TYP(r)].Properties&TYPE_GAS) && TYP(r) != PT_SOAP && TYP(r) != PT_GLAS)) { Element_SOAP_detach(sim, i); diff --git a/src/simulation/elements/SOAP.h b/src/simulation/elements/SOAP.h new file mode 100644 index 000000000..5c04f8b07 --- /dev/null +++ b/src/simulation/elements/SOAP.h @@ -0,0 +1,4 @@ +#pragma once +#include "simulation/ElementDefs.h" + +void Element_SOAP_detach(Simulation * sim, int i); diff --git a/src/simulation/elements/SPRK.cpp b/src/simulation/elements/SPRK.cpp index 4b43a5869..bd75919ab 100644 --- a/src/simulation/elements/SPRK.cpp +++ b/src/simulation/elements/SPRK.cpp @@ -1,6 +1,9 @@ #include "simulation/ElementCommon.h" +#include "NTCT.h" +#include "PIPE.h" +#include "FIRE.h" +#include "ETRD.h" -int Element_FIRE_update(UPDATE_FUNC_ARGS); static int update(UPDATE_FUNC_ARGS); static int graphics(GRAPHICS_FUNC_ARGS); @@ -52,6 +55,8 @@ void Element::Element_SPRK() static int update(UPDATE_FUNC_ARGS) { + auto &sd = SimulationData::CRef(); + auto &elements = sd.elements; int ct = parts[i].ctype; Element_FIRE_update(UPDATE_FUNC_SUBCALL_ARGS); @@ -59,7 +64,7 @@ static int update(UPDATE_FUNC_ARGS) { if (ct==PT_WATR||ct==PT_SLTW||ct==PT_PSCN||ct==PT_NSCN||ct==PT_ETRD||ct==PT_INWR) parts[i].temp = R_TEMP + 273.15f; - if (ct<=0 || ct>=PT_NUM || !sim->elements[parts[i].ctype].Enabled) + if (ct<=0 || ct>=PT_NUM || !elements[parts[i].ctype].Enabled) ct = PT_METL; parts[i].ctype = PT_NONE; parts[i].life = 4; @@ -81,13 +86,11 @@ static int update(UPDATE_FUNC_ARGS) return 1; case PT_NTCT: case PT_PTCT: - int Element_NTCT_update(UPDATE_FUNC_ARGS); Element_NTCT_update(UPDATE_FUNC_SUBCALL_ARGS); break; case PT_ETRD: if (parts[i].life==1) { - int Element_ETRD_nearestSparkablePart(Simulation *sim, int targetId); auto nearp = Element_ETRD_nearestSparkablePart(sim, i); if (nearp!=-1 && sim->parts_avg(i, nearp, PT_INSL)!=PT_INSL) { @@ -245,7 +248,6 @@ static int update(UPDATE_FUNC_ARGS) case PT_PPIP: if (parts[i].life == 3 && pavg!=PT_INSL) { - void Element_PPIP_flood_trigger(Simulation * sim, int x, int y, int sparkedBy); if (sender == PT_NSCN || sender == PT_PSCN || sender == PT_INST) Element_PPIP_flood_trigger(sim, x+rx, y+ry, sender); } @@ -271,7 +273,7 @@ static int update(UPDATE_FUNC_ARGS) } if (pavg == PT_INSL) continue; //Insulation blocks everything past here - if (!((sim->elements[receiver].Properties&PROP_CONDUCTS)||receiver==PT_INST||receiver==PT_QRTZ)) continue; //Stop non-conducting receivers, allow INST and QRTZ as special cases + if (!((elements[receiver].Properties&PROP_CONDUCTS)||receiver==PT_INST||receiver==PT_QRTZ)) continue; //Stop non-conducting receivers, allow INST and QRTZ as special cases if (abs(rx)+abs(ry)>=4 &&sender!=PT_SWCH&&receiver!=PT_SWCH) continue; //Only switch conducts really far if (receiver==sender && receiver!=PT_INST && receiver!=PT_QRTZ) goto conduct; //Everything conducts to itself, except INST. diff --git a/src/simulation/elements/STKM.cpp b/src/simulation/elements/STKM.cpp index 78455a74c..5452c1591 100644 --- a/src/simulation/elements/STKM.cpp +++ b/src/simulation/elements/STKM.cpp @@ -1,14 +1,10 @@ #include "simulation/ElementCommon.h" +#include "STKM.h" static int update(UPDATE_FUNC_ARGS); -int Element_STKM_graphics(GRAPHICS_FUNC_ARGS); static void create(ELEMENT_CREATE_FUNC_ARGS); static bool createAllowed(ELEMENT_CREATE_ALLOWED_FUNC_ARGS); static void changeType(ELEMENT_CHANGETYPE_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_STKM_set_element(Simulation *sim, playerst *playerp, int element); -void Element_STKM_interact(Simulation *sim, playerst *playerp, int i, int x, int y); void Element::Element_STKM() { @@ -114,6 +110,8 @@ void die(Simulation *sim, playerst *playerp, int i) int Element_STKM_run_stickman(playerst *playerp, UPDATE_FUNC_ARGS) { + auto &sd = SimulationData::CRef(); + auto &elements = sd.elements; int r, rx, ry; int t = parts[i].type; float pp, d; @@ -125,7 +123,7 @@ int Element_STKM_run_stickman(playerst *playerp, UPDATE_FUNC_ARGS) float rocketBootsHeadEffectV = 0.3f;// stronger acceleration vertically, to counteract gravity float rocketBootsFeetEffectV = 0.45f; - if (!playerp->fan && parts[i].ctype && sim->IsElementOrNone(parts[i].ctype)) + if (!playerp->fan && parts[i].ctype && sd.IsElementOrNone(parts[i].ctype)) Element_STKM_set_element(sim, playerp, parts[i].ctype); playerp->frames++; @@ -449,7 +447,7 @@ int Element_STKM_run_stickman(playerst *playerp, UPDATE_FUNC_ARGS) { ry -= 2 * sim->rng.between(0, 1) + 1; r = pmap[ry][rx]; - if (sim->elements[TYP(r)].Properties&TYPE_SOLID) + if (elements[TYP(r)].Properties&TYPE_SOLID) { sim->create_part(-1, rx, ry, PT_SPRK); playerp->frames = 0; @@ -520,7 +518,7 @@ int Element_STKM_run_stickman(playerst *playerp, UPDATE_FUNC_ARGS) { parts[np].vx -= -mvy*(5*((((int)playerp->pcomm)&0x02) == 0x02) - 5*(((int)(playerp->pcomm)&0x01) == 0x01)); parts[np].vy -= mvx*(5*((((int)playerp->pcomm)&0x02) == 0x02) - 5*(((int)(playerp->pcomm)&0x01) == 0x01)); - parts[i].vx -= (sim->elements[(int)playerp->elem].Weight*parts[np].vx)/1000; + parts[i].vx -= (elements[(int)playerp->elem].Weight*parts[np].vx)/1000; } playerp->frames = 0; } @@ -627,6 +625,8 @@ int Element_STKM_run_stickman(playerst *playerp, UPDATE_FUNC_ARGS) void Element_STKM_interact(Simulation *sim, playerst *playerp, int i, int x, int y) { + auto &sd = SimulationData::CRef(); + auto &elements = sd.elements; int r; if (x<0 || y<0 || x>=XRES || y>=YRES || !sim->parts[i].type) return; @@ -639,13 +639,13 @@ void Element_STKM_interact(Simulation *sim, playerst *playerp, int i, int x, int damage += sim->rng.between(32, 51); } - if (sim->elements[TYP(r)].HeatConduct && (TYP(r)!=PT_HSWC||sim->parts[ID(r)].life==10) && ((playerp->elem!=PT_LIGH && sim->parts[ID(r)].temp>=323) || sim->parts[ID(r)].temp<=243) && (!playerp->rocketBoots || TYP(r)!=PT_PLSM)) + if (elements[TYP(r)].HeatConduct && (TYP(r)!=PT_HSWC||sim->parts[ID(r)].life==10) && ((playerp->elem!=PT_LIGH && sim->parts[ID(r)].temp>=323) || sim->parts[ID(r)].temp<=243) && (!playerp->rocketBoots || TYP(r)!=PT_PLSM)) { damage += 2; playerp->accs[3] -= 1; } - if (sim->elements[TYP(r)].Properties&PROP_DEADLY) + if (elements[TYP(r)].Properties&PROP_DEADLY) switch (TYP(r)) { case PT_ACID: @@ -656,7 +656,7 @@ void Element_STKM_interact(Simulation *sim, playerst *playerp, int i, int x, int break; } - if (sim->elements[TYP(r)].Properties&PROP_RADIOACTIVE) + if (elements[TYP(r)].Properties&PROP_RADIOACTIVE) damage++; if (damage) @@ -741,10 +741,12 @@ void Element_STKM_init_legs(Simulation * sim, playerst *playerp, int i) void Element_STKM_set_element(Simulation *sim, playerst *playerp, int element) { - if (sim->elements[element].Falldown != 0 - || sim->elements[element].Properties&TYPE_GAS - || sim->elements[element].Properties&TYPE_LIQUID - || sim->elements[element].Properties&TYPE_ENERGY + auto &sd = SimulationData::CRef(); + auto &elements = sd.elements; + if (elements[element].Falldown != 0 + || elements[element].Properties&TYPE_GAS + || elements[element].Properties&TYPE_LIQUID + || elements[element].Properties&TYPE_ENERGY || element == PT_LOLZ || element == PT_LOVE) { if (!playerp->rocketBoots || element != PT_PLSM) diff --git a/src/simulation/elements/STKM.h b/src/simulation/elements/STKM.h new file mode 100644 index 000000000..69651309b --- /dev/null +++ b/src/simulation/elements/STKM.h @@ -0,0 +1,12 @@ +#pragma once +#include "simulation/ElementDefs.h" + +int Element_FIGH_Alloc(Simulation *sim); +bool Element_FIGH_CanAlloc(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); +void Element_STKM_interact(Simulation *sim, playerst *playerp, int i, int x, int y); +int Element_STKM_run_stickman(playerst *playerp, UPDATE_FUNC_ARGS); +void Element_STKM_set_element(Simulation *sim, playerst *playerp, int element); +void Element_STKM_set_element(Simulation *sim, playerst *playerp, int element); diff --git a/src/simulation/elements/STKM2.cpp b/src/simulation/elements/STKM2.cpp index 2ee01e931..a399ca366 100644 --- a/src/simulation/elements/STKM2.cpp +++ b/src/simulation/elements/STKM2.cpp @@ -1,12 +1,10 @@ #include "simulation/ElementCommon.h" +#include "STKM.h" static int update(UPDATE_FUNC_ARGS); static void create(ELEMENT_CREATE_FUNC_ARGS); static bool createAllowed(ELEMENT_CREATE_ALLOWED_FUNC_ARGS); static void changeType(ELEMENT_CHANGETYPE_FUNC_ARGS); -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_STKM2() { diff --git a/src/simulation/elements/STOR.cpp b/src/simulation/elements/STOR.cpp index d0af46772..3e93a661c 100644 --- a/src/simulation/elements/STOR.cpp +++ b/src/simulation/elements/STOR.cpp @@ -1,6 +1,6 @@ #include "simulation/ElementCommon.h" +#include "SOAP.h" -void Element_SOAP_detach(Simulation * sim, int i); static int update(UPDATE_FUNC_ARGS); static int graphics(GRAPHICS_FUNC_ARGS); static bool ctypeDraw(CTYPEDRAW_FUNC_ARGS); @@ -53,7 +53,9 @@ void Element::Element_STOR() static int update(UPDATE_FUNC_ARGS) { - if (!sim->IsElementOrNone(parts[i].tmp)) + auto &sd = SimulationData::CRef(); + auto &elements = sd.elements; + if (!sd.IsElementOrNone(parts[i].tmp)) parts[i].tmp = 0; if(parts[i].life && !parts[i].tmp) parts[i].life--; @@ -66,7 +68,7 @@ static int update(UPDATE_FUNC_ARGS) auto r = pmap[y+ry][x+rx]; if ((ID(r))>=NPART || !r) continue; - if (!parts[i].tmp && !parts[i].life && TYP(r)!=PT_STOR && !(sim->elements[TYP(r)].Properties&TYPE_SOLID) && (!parts[i].ctype || TYP(r)==parts[i].ctype)) + if (!parts[i].tmp && !parts[i].life && TYP(r)!=PT_STOR && !(elements[TYP(r)].Properties&TYPE_SOLID) && (!parts[i].ctype || TYP(r)==parts[i].ctype)) { if (TYP(r) == PT_SOAP) Element_SOAP_detach(sim, ID(r)); @@ -120,7 +122,9 @@ static int graphics(GRAPHICS_FUNC_ARGS) static bool ctypeDraw(CTYPEDRAW_FUNC_ARGS) { - if (sim->elements[t].Properties & TYPE_SOLID) + auto &sd = SimulationData::CRef(); + auto &elements = sd.elements; + if (elements[t].Properties & TYPE_SOLID) { return false; } diff --git a/src/simulation/elements/THDR.cpp b/src/simulation/elements/THDR.cpp index c22e7a474..ce3dc1cbd 100644 --- a/src/simulation/elements/THDR.cpp +++ b/src/simulation/elements/THDR.cpp @@ -50,6 +50,8 @@ void Element::Element_THDR() static int update(UPDATE_FUNC_ARGS) { + auto &sd = SimulationData::CRef(); + auto &elements = sd.elements; bool kill=false; for (auto rx = -2; rx <= 2; rx++) { @@ -61,7 +63,7 @@ static int update(UPDATE_FUNC_ARGS) if (!r) continue; auto rt = TYP(r); - if ((sim->elements[TYP(r)].Properties&PROP_CONDUCTS) && parts[ID(r)].life==0 && !(rt==PT_WATR||rt==PT_SLTW) && parts[ID(r)].ctype!=PT_SPRK) + if ((elements[TYP(r)].Properties&PROP_CONDUCTS) && parts[ID(r)].life==0 && !(rt==PT_WATR||rt==PT_SLTW) && parts[ID(r)].ctype!=PT_SPRK) { parts[ID(r)].ctype = parts[ID(r)].type; sim->part_change_type(ID(r),x+rx,y+ry,PT_SPRK); diff --git a/src/simulation/elements/TRON.cpp b/src/simulation/elements/TRON.cpp index 4c9c7a24f..b818d25fa 100644 --- a/src/simulation/elements/TRON.cpp +++ b/src/simulation/elements/TRON.cpp @@ -270,9 +270,11 @@ static int trymovetron(Simulation * sim, int x, int y, int dir, int i, int len) static bool canmovetron(Simulation * sim, int r, int len) { + auto &sd = SimulationData::CRef(); + auto &elements = sd.elements; if (!r || (TYP(r) == PT_SWCH && sim->parts[ID(r)].life >= 10) || (TYP(r) == PT_INVIS && sim->parts[ID(r)].tmp2 == 1)) return true; - if ((((sim->elements[TYP(r)].Properties & PROP_LIFE_KILL_DEC) && sim->parts[ID(r)].life > 0)|| ((sim->elements[TYP(r)].Properties & PROP_LIFE_KILL) && (sim->elements[TYP(r)].Properties & PROP_LIFE_DEC))) && sim->parts[ID(r)].life < len) + if ((((elements[TYP(r)].Properties & PROP_LIFE_KILL_DEC) && sim->parts[ID(r)].life > 0)|| ((elements[TYP(r)].Properties & PROP_LIFE_KILL) && (elements[TYP(r)].Properties & PROP_LIFE_DEC))) && sim->parts[ID(r)].life < len) return true; return false; } diff --git a/src/simulation/elements/TSNS.cpp b/src/simulation/elements/TSNS.cpp index 7da107e06..3bb981d32 100644 --- a/src/simulation/elements/TSNS.cpp +++ b/src/simulation/elements/TSNS.cpp @@ -49,6 +49,8 @@ void Element::Element_TSNS() 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; @@ -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; diff --git a/src/simulation/elements/TUNG.cpp b/src/simulation/elements/TUNG.cpp index 086359a1d..4e5a22bd6 100644 --- a/src/simulation/elements/TUNG.cpp +++ b/src/simulation/elements/TUNG.cpp @@ -52,8 +52,10 @@ void Element::Element_TUNG() static int update(UPDATE_FUNC_ARGS) { + auto &sd = SimulationData::CRef(); + auto &elements = sd.elements; bool splode = false; - const float MELTING_POINT = sim->elements[PT_TUNG].HighTemperature; + const float MELTING_POINT = elements[PT_TUNG].HighTemperature; if(parts[i].temp > 2400.0) { @@ -112,7 +114,9 @@ static int update(UPDATE_FUNC_ARGS) static int graphics(GRAPHICS_FUNC_ARGS) { - const float MELTING_POINT = ren->sim->elements[PT_TUNG].HighTemperature; + auto &sd = SimulationData::CRef(); + auto &elements = sd.elements; + const float MELTING_POINT = elements[PT_TUNG].HighTemperature; double startTemp = (MELTING_POINT - 1500.0); double tempOver = (((cpart->temp - startTemp)/1500.0)*TPT_PI_FLT) - (TPT_PI_FLT/2.0); if(tempOver > -(TPT_PI_FLT/2.0)) diff --git a/src/simulation/elements/VIBR.cpp b/src/simulation/elements/VIBR.cpp index fbb6a6c96..26959596c 100644 --- a/src/simulation/elements/VIBR.cpp +++ b/src/simulation/elements/VIBR.cpp @@ -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_VIBR() { @@ -50,6 +48,8 @@ void Element::Element_VIBR() int Element_VIBR_update(UPDATE_FUNC_ARGS) { + auto &sd = SimulationData::CRef(); + auto &elements = sd.elements; int rndstore = 0; if (!parts[i].life) //if not exploding { @@ -89,7 +89,7 @@ int Element_VIBR_update(UPDATE_FUNC_ARGS) auto ry = (rndstore>>2)%3-1; rndstore = rndstore >> 4; auto r = pmap[y+ry][x+rx]; - if (TYP(r) && TYP(r) != PT_BREC && (sim->elements[TYP(r)].Properties&PROP_CONDUCTS) && !parts[ID(r)].life) + if (TYP(r) && TYP(r) != PT_BREC && (elements[TYP(r)].Properties&PROP_CONDUCTS) && !parts[ID(r)].life) { parts[ID(r)].life = 4; parts[ID(r)].ctype = TYP(r); @@ -102,7 +102,7 @@ int Element_VIBR_update(UPDATE_FUNC_ARGS) auto rx = rndstore%7-3; auto ry = (rndstore>>3)%7-3; auto r = pmap[y+ry][x+rx]; - if (TYP(r) && TYP(r)!=PT_VIBR && TYP(r)!=PT_BVBR && sim->elements[TYP(r)].HeatConduct && (TYP(r)!=PT_HSWC||parts[ID(r)].life==10)) + if (TYP(r) && TYP(r)!=PT_VIBR && TYP(r)!=PT_BVBR && elements[TYP(r)].HeatConduct && (TYP(r)!=PT_HSWC||parts[ID(r)].life==10)) { parts[ID(r)].temp += parts[i].tmp*3; parts[i].tmp = 0; diff --git a/src/simulation/elements/VIBR.h b/src/simulation/elements/VIBR.h new file mode 100644 index 000000000..452e27784 --- /dev/null +++ b/src/simulation/elements/VIBR.h @@ -0,0 +1,5 @@ +#pragma once +#include "simulation/ElementDefs.h" + +int Element_VIBR_graphics(GRAPHICS_FUNC_ARGS); +int Element_VIBR_update(UPDATE_FUNC_ARGS); diff --git a/src/simulation/elements/VIRS.cpp b/src/simulation/elements/VIRS.cpp index bd185d225..3940b77bd 100644 --- a/src/simulation/elements/VIRS.cpp +++ b/src/simulation/elements/VIRS.cpp @@ -1,6 +1,6 @@ #include "simulation/ElementCommon.h" +#include "VIRS.h" -int Element_VIRS_update(UPDATE_FUNC_ARGS); static int graphics(GRAPHICS_FUNC_ARGS); void Element::Element_VIRS() diff --git a/src/simulation/elements/VIRS.h b/src/simulation/elements/VIRS.h new file mode 100644 index 000000000..a5a664dcf --- /dev/null +++ b/src/simulation/elements/VIRS.h @@ -0,0 +1,4 @@ +#pragma once +#include "simulation/ElementDefs.h" + +int Element_VIRS_update(UPDATE_FUNC_ARGS); diff --git a/src/simulation/elements/VRSG.cpp b/src/simulation/elements/VRSG.cpp index 11a204af2..bfa13aa4e 100644 --- a/src/simulation/elements/VRSG.cpp +++ b/src/simulation/elements/VRSG.cpp @@ -1,6 +1,6 @@ #include "simulation/ElementCommon.h" +#include "VIRS.h" -int Element_VIRS_update(UPDATE_FUNC_ARGS); static int graphics(GRAPHICS_FUNC_ARGS); void Element::Element_VRSG() diff --git a/src/simulation/elements/VRSS.cpp b/src/simulation/elements/VRSS.cpp index 6ba0fee9f..221508393 100644 --- a/src/simulation/elements/VRSS.cpp +++ b/src/simulation/elements/VRSS.cpp @@ -1,6 +1,6 @@ #include "simulation/ElementCommon.h" +#include "VIRS.h" -int Element_VIRS_update(UPDATE_FUNC_ARGS); static int graphics(GRAPHICS_FUNC_ARGS); void Element::Element_VRSS() diff --git a/src/simulation/elements/VSNS.cpp b/src/simulation/elements/VSNS.cpp index baefbe56b..7c5a95de8 100644 --- a/src/simulation/elements/VSNS.cpp +++ b/src/simulation/elements/VSNS.cpp @@ -50,6 +50,8 @@ void Element::Element_VSNS() 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) @@ -67,7 +69,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; @@ -98,7 +100,7 @@ static int update(UPDATE_FUNC_ARGS) { case 1: // serialization - if (TYP(r) != PT_VSNS && TYP(r) != PT_FILT && !(sim->elements[TYP(r)].Properties & TYPE_SOLID)) + if (TYP(r) != PT_VSNS && TYP(r) != PT_FILT && !(elements[TYP(r)].Properties & TYPE_SOLID)) { doSerialization = true; Vs = Vm; @@ -118,12 +120,12 @@ static int update(UPDATE_FUNC_ARGS) break; case 2: // Invert mode - if (!(sim->elements[TYP(r)].Properties & TYPE_SOLID) && Vm <= parts[i].temp - 273.15) + if (!(elements[TYP(r)].Properties & TYPE_SOLID) && Vm <= parts[i].temp - 273.15) parts[i].life = 1; break; default: // Normal mode - if (!(sim->elements[TYP(r)].Properties & TYPE_SOLID) && Vm > parts[i].temp - 273.15) + if (!(elements[TYP(r)].Properties & TYPE_SOLID) && Vm > parts[i].temp - 273.15) parts[i].life = 1; break; } @@ -158,7 +160,7 @@ static int update(UPDATE_FUNC_ARGS) //Deserialization. if (doDeserialization) { - if (TYP(r) != PT_FILT && !(sim->elements[TYP(r)].Properties & TYPE_SOLID)) + if (TYP(r) != PT_FILT && !(elements[TYP(r)].Properties & TYPE_SOLID)) { float Vx = parts[ID(r)].vx; float Vy = parts[ID(r)].vy; diff --git a/src/simulation/elements/WATR.cpp b/src/simulation/elements/WATR.cpp index 2e82c5e06..849682903 100644 --- a/src/simulation/elements/WATR.cpp +++ b/src/simulation/elements/WATR.cpp @@ -30,6 +30,7 @@ void Element::Element_WATR() DefaultProperties.temp = R_TEMP - 2.0f + 273.15f; HeatConduct = 29; + LatentHeat = 7500; Description = "Water. Conducts electricity, freezes, and extinguishes fires."; Properties = TYPE_LIQUID|PROP_CONDUCTS|PROP_LIFE_DEC|PROP_NEUTPASS; diff --git a/src/simulation/orbitalparts.h b/src/simulation/orbitalparts.h new file mode 100644 index 000000000..b5ba2be35 --- /dev/null +++ b/src/simulation/orbitalparts.h @@ -0,0 +1,33 @@ +#pragma once + +inline void orbitalparts_get(int block1, int block2, int resblock1[], int resblock2[]) +{ + resblock1[0] = (block1&0x000000FF); + resblock1[1] = (block1&0x0000FF00)>>8; + resblock1[2] = (block1&0x00FF0000)>>16; + resblock1[3] = (block1&0xFF000000)>>24; + + resblock2[0] = (block2&0x000000FF); + resblock2[1] = (block2&0x0000FF00)>>8; + resblock2[2] = (block2&0x00FF0000)>>16; + resblock2[3] = (block2&0xFF000000)>>24; +} + +inline void orbitalparts_set(int *block1, int *block2, int resblock1[], int resblock2[]) +{ + int block1tmp = 0; + int block2tmp = 0; + + block1tmp = (resblock1[0]&0xFF); + block1tmp |= (resblock1[1]&0xFF)<<8; + block1tmp |= (resblock1[2]&0xFF)<<16; + block1tmp |= (resblock1[3]&0xFF)<<24; + + block2tmp = (resblock2[0]&0xFF); + block2tmp |= (resblock2[1]&0xFF)<<8; + block2tmp |= (resblock2[2]&0xFF)<<16; + block2tmp |= (resblock2[3]&0xFF)<<24; + + *block1 = block1tmp; + *block2 = block2tmp; +} diff --git a/src/simulation/simtools/MIX.cpp b/src/simulation/simtools/MIX.cpp index 2b79e15ee..eb2ffcf99 100644 --- a/src/simulation/simtools/MIX.cpp +++ b/src/simulation/simtools/MIX.cpp @@ -16,6 +16,8 @@ void SimTool::Tool_MIX() static int perform(Simulation * sim, Particle * cpart, int x, int y, int brushX, int brushY, float strength) { + auto &sd = SimulationData::CRef(); + auto &elements = sd.elements; int thisPart = sim->pmap[y][x]; if(!thisPart) return 0; @@ -25,7 +27,7 @@ static int perform(Simulation * sim, Particle * cpart, int x, int y, int brushX, int distance = (int)(std::pow(strength, .5f) * 10); - if(!(sim->elements[TYP(thisPart)].Properties & (TYPE_PART | TYPE_LIQUID | TYPE_GAS))) + if(!(elements[TYP(thisPart)].Properties & (TYPE_PART | TYPE_LIQUID | TYPE_GAS))) return 0; int newX = x + (sim->rng() % distance) - (distance/2); @@ -38,7 +40,7 @@ static int perform(Simulation * sim, Particle * cpart, int x, int y, int brushX, if(!thatPart) return 0; - if ((sim->elements[TYP(thisPart)].Properties&STATE_FLAGS) != (sim->elements[TYP(thatPart)].Properties&STATE_FLAGS)) + if ((elements[TYP(thisPart)].Properties&STATE_FLAGS) != (elements[TYP(thatPart)].Properties&STATE_FLAGS)) return 0; sim->pmap[y][x] = thatPart;