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/client/GameSave.cpp b/src/client/GameSave.cpp index 294aac63d..3d08d48ca 100644 --- a/src/client/GameSave.cpp +++ b/src/client/GameSave.cpp @@ -328,6 +328,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 +1186,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 +1199,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 +1609,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 +1972,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. @@ -2200,7 +2202,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) 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/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/graphics/Renderer.cpp b/src/graphics/Renderer.cpp index 07e1fb1be..9179d52cc 100644 --- a/src/graphics/Renderer.cpp +++ b/src/graphics/Renderer.cpp @@ -11,7 +11,8 @@ 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 +171,14 @@ void Renderer::DrawSigns() void Renderer::render_parts() { + auto &sd = SimulationData::CRef(); + auto &elements = sd.elements; 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(); 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,7 +243,8 @@ 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 = useGraphicsFunction ? elements[t].Graphics : nullptr; + if (!graphics || 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 { graphicscache[t].isready = 1; graphicscache[t].pixel_mode = pixel_mode; @@ -927,6 +929,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 +939,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 +955,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 +1079,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 +1160,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..d1f2b0909 100644 --- a/src/graphics/Renderer.h +++ b/src/graphics/Renderer.h @@ -167,6 +167,8 @@ public: #undef RENDERER_TABLE static void PopulateTables(); + bool useGraphicsFunction = false; + private: int gridSize; }; diff --git a/src/gui/game/GOLTool.cpp b/src/gui/game/GOLTool.cpp index 19381f19c..c44a48b58 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" @@ -135,6 +135,7 @@ void GOLWindow::updateGradient() void GOLWindow::validate() { + auto &sd = SimulationData::CRef(); auto nameString = nameField->GetText(); auto ruleString = ruleField->GetText(); if (!ValidateGOLName(nameString)) @@ -149,7 +150,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; diff --git a/src/gui/game/GameController.cpp b/src/gui/game/GameController.cpp index add450109..33b5640a4 100644 --- a/src/gui/game/GameController.cpp +++ b/src/gui/game/GameController.cpp @@ -757,11 +757,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 +850,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,7 +877,7 @@ 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; } @@ -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..92b93904d 100644 --- a/src/gui/game/GameModel.cpp +++ b/src/gui/game/GameModel.cpp @@ -57,6 +57,7 @@ GameModel::GameModel(): { sim = new Simulation(); ren = new Renderer(sim); + ren->useGraphicsFunction = true; 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/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/lua/LegacyLuaAPI.cpp b/src/lua/LegacyLuaAPI.cpp index 32e009e16..93dd81006 100644 --- a/src/lua/LegacyLuaAPI.cpp +++ b/src/lua/LegacyLuaAPI.cpp @@ -152,6 +152,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 +164,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 +177,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 +189,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 +197,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 +211,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 +223,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 +236,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,12 +249,12 @@ 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(); @@ -278,21 +287,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 +337,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 +346,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 +559,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 +578,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 +589,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 +1154,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..d5625b6b7 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,64 @@ void LuaScriptInterface::LuaSetParticleProperty(lua_State* l, int particleID, St int LuaScriptInterface::elements_loadDefault(lua_State * l) { + 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]; - else - luacon_sim->elements[i] = Element(); + 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); + + { + auto &sd = SimulationData::Ref(); + std::unique_lock lk(sd.elementGraphicsMx); + auto &elements = sd.elements; + if (id < (int)builtinElements.size()) + elements[id] = builtinElements[id]; + else + 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 + { + { + auto &sd = SimulationData::Ref(); + std::unique_lock lk(sd.elementGraphicsMx); + auto &elements = sd.elements; + for (int i = 0; i < PT_NUM; i++) + { + if (i < (int)builtinElements.size()) + elements[i] = builtinElements[i]; + else + elements[i] = Element(); + } + } + lua_pushnil(l); + lua_setglobal(l, "elements"); + lua_pushnil(l); + lua_setglobal(l, "elem"); - lua_getglobal(l, "package"); - lua_getfield(l, -1, "loaded"); - lua_pushnil(l); - lua_setfield(l, -2, "elements"); + lua_getglobal(l, "package"); + lua_getfield(l, -1, "loaded"); + lua_pushnil(l); + lua_setfield(l, -2, "elements"); - luacon_ci->initElementsAPI(); + luacon_ci->initElementsAPI(); + } } luacon_model->BuildMenus(); @@ -3355,40 +3383,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); @@ -3412,7 +3449,8 @@ int LuaScriptInterface::elements_allocate(lua_State * l) static int luaUpdateWrapper(UPDATE_FUNC_ARGS) { 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)) @@ -3591,109 +3629,115 @@ 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, "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, "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, "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, "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, "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, "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); - 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); - 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); - 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); - 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); - 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); @@ -3707,17 +3751,19 @@ int LuaScriptInterface::elements_element(lua_State * l) } 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 +3775,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 +3796,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 +3818,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 +3828,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"); } @@ -3800,14 +3851,18 @@ 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); - LuaSetProperty(l, *prop, propertyAddress, 3); + { + auto &sd = SimulationData::Ref(); + std::unique_lock lk(sd.elementGraphicsMx); + auto &elements = sd.elements; + intptr_t propertyAddress = (intptr_t)(((unsigned char*)&elements[id]) + prop->Offset); + LuaSetProperty(l, *prop, propertyAddress, 3); + } } luacon_model->BuildMenus(); @@ -3817,6 +3872,8 @@ int LuaScriptInterface::elements_property(lua_State * l) } else if (propertyName == "Update") { + auto &sd = SimulationData::Ref(); + auto &elements = sd.elements; if (lua_type(l, 3) == LUA_TFUNCTION) { switch (luaL_optint(l, 4, 0)) @@ -3834,80 +3891,90 @@ 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") { + auto &sd = SimulationData::Ref(); + auto &elements = sd.elements; 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); } else if (propertyName == "Create") { + auto &sd = SimulationData::Ref(); + auto &elements = sd.elements; 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") { + auto &sd = SimulationData::Ref(); + auto &elements = sd.elements; 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") { + auto &sd = SimulationData::Ref(); + auto &elements = sd.elements; 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") { + auto &sd = SimulationData::Ref(); + auto &elements = sd.elements; 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 +3989,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 +4017,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 +4050,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..fb5d67faa 100644 --- a/src/simulation/Element.cpp +++ b/src/simulation/Element.cpp @@ -216,14 +216,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 +240,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/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/SaveRenderer.cpp b/src/simulation/SaveRenderer.cpp index ad6709dae..63dea381d 100644 --- a/src/simulation/SaveRenderer.cpp +++ b/src/simulation/SaveRenderer.cpp @@ -6,6 +6,7 @@ #include "graphics/Renderer.h" #include "Simulation.h" +#include "SimulationData.h" SaveRenderer::SaveRenderer(){ sim = new Simulation(); @@ -22,6 +23,9 @@ void SaveRenderer::Flush(int begin, int end) std::pair, MissingElements> 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(); diff --git a/src/simulation/Sign.cpp b/src/simulation/Sign.cpp index e885fcc65..590bd21ff 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_), @@ -13,6 +14,7 @@ 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 { + 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/Simulation.cpp b/src/simulation/Simulation.cpp index 74a0fa132..dab7bbd2e 100644 --- a/src/simulation/Simulation.cpp +++ b/src/simulation/Simulation.cpp @@ -4,7 +4,6 @@ #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" @@ -30,6 +29,9 @@ MissingElements Simulation::Load(const GameSave *save, bool includePressure, Vec { partMap[i] = i; } + + auto &sd = SimulationData::CRef(); + auto &elements = sd.elements; if(save->palette.size()) { for(int i = 0; i < PT_NUM; i++) @@ -359,6 +361,9 @@ std::unique_ptr Simulation::Save(bool includePressure, Rect partR // 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; @@ -493,8 +498,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 +718,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(); @@ -1101,6 +1110,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 +1133,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 +1154,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 +1240,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); @@ -1700,6 +1577,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; @@ -1883,6 +1762,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 +1795,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 +1840,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; @@ -2238,6 +2124,8 @@ void Simulation::delete_part(int x, int y)//calls kill_part with the particle lo Simulation::PlanMoveResult Simulation::PlanMove(int i, int x, int y, bool update_emap) { + auto &sd = SimulationData::CRef(); + auto &can_move = sd.can_move; // 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 @@ -2348,6 +2236,8 @@ Simulation::PlanMoveResult Simulation::PlanMove(int i, int x, int y, bool update 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) @@ -2585,16 +2475,16 @@ void Simulation::UpdateParticles(int start, int end) 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) @@ -3470,6 +3360,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 +3444,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 +3621,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++) @@ -3997,10 +3892,7 @@ void Simulation::AfterSim() frameCount += 1; } -Simulation::~Simulation() -{ - delete air; -} +Simulation::~Simulation() = default; Simulation::Simulation(): replaceModeSelected(0), @@ -4050,7 +3942,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,88 +3954,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); diff --git a/src/simulation/Simulation.h b/src/simulation/Simulation.h index 194d197ed..4a71591ba 100644 --- a/src/simulation/Simulation.h +++ b/src/simulation/Simulation.h @@ -22,7 +22,6 @@ constexpr int CHANNELS = int(MAX_TEMP - 73) / 100 + 2; class Snapshot; -class SimTool; class Brush; class SimulationSample; struct matrix2d; @@ -37,24 +36,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; @@ -127,7 +119,7 @@ public: 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); @@ -145,18 +137,11 @@ public: float vx, vy; }; PlanMoveResult PlanMove(int i, int x, int y, bool update_emap); - void init_can_move(); 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 +162,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,11 +196,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); @@ -236,29 +217,6 @@ public: 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); - private: CoordStack& getCoordStackSingleton(); }; diff --git a/src/simulation/SimulationData.cpp b/src/simulation/SimulationData.cpp index bbfaeed4c..a6a9ba39c 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,7 +98,7 @@ std::vector LoadMenus() }; } -std::vector LoadLatent() +static std::vector LoadLatent() { return std::vector{ @@ -265,3 +265,246 @@ std::vector LoadLatent() /* REPL */ 0, }; } + +void SimulationData::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; +} + +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(); + platent = LoadLatent(); + elements = GetElements(); + tools = GetTools(); +} diff --git a/src/simulation/SimulationData.h b/src/simulation/SimulationData.h index 90dbed540..9f92f7725 100644 --- a/src/simulation/SimulationData.h +++ b/src/simulation/SimulationData.h @@ -1,8 +1,18 @@ #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 #include #include +#include constexpr int SC_WALL = 0; constexpr int SC_ELEC = 1; @@ -148,20 +158,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::vector tools; + std::vector platent; + 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..e60cee4ee 100644 --- a/src/simulation/elements/ARAY.cpp +++ b/src/simulation/elements/ARAY.cpp @@ -47,6 +47,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++) @@ -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/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..ac3b09d1e 100644 --- a/src/simulation/elements/CBNW.cpp +++ b/src/simulation/elements/CBNW.cpp @@ -50,6 +50,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 +89,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..878ffe5b5 100644 --- a/src/simulation/elements/CRAY.cpp +++ b/src/simulation/elements/CRAY.cpp @@ -51,9 +51,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++) { @@ -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/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..70b2cba1e 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; diff --git a/src/simulation/elements/FIGH.cpp b/src/simulation/elements/FIGH.cpp index fc82caee3..6d32775d1 100644 --- a/src/simulation/elements/FIGH.cpp +++ b/src/simulation/elements/FIGH.cpp @@ -64,6 +64,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 +106,8 @@ static int update(UPDATE_FUNC_ARGS) if ((pow(float(tarx-x), 2) + pow(float(tary-y), 2))<600) { if (figh->elem == PT_LIGH || figh->elem == PT_NEUT - || sim->elements[figh->elem].Properties & (PROP_DEADLY | PROP_RADIOACTIVE) - || sim->elements[figh->elem].DefaultProperties.temp >= 323 || sim->elements[figh->elem].DefaultProperties.temp <= 243) + || elements[figh->elem].Properties & (PROP_DEADLY | PROP_RADIOACTIVE) + || elements[figh->elem].DefaultProperties.temp >= 323 || elements[figh->elem].DefaultProperties.temp <= 243) figh->comm = (int)figh->comm | 0x08; } else if (tarx= 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; @@ -202,7 +204,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; @@ -219,7 +221,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; } @@ -241,7 +243,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; @@ -260,18 +262,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; } } @@ -284,6 +286,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++) { @@ -300,10 +304,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/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/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..db533fb9f 100644 --- a/src/simulation/elements/ICEI.cpp +++ b/src/simulation/elements/ICEI.cpp @@ -50,6 +50,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 +67,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/LDTC.cpp b/src/simulation/elements/LDTC.cpp index 0020cc8ad..850f57635 100644 --- a/src/simulation/elements/LDTC.cpp +++ b/src/simulation/elements/LDTC.cpp @@ -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; diff --git a/src/simulation/elements/LIFE.cpp b/src/simulation/elements/LIFE.cpp index 184df2f44..fda53089a 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) @@ -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/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/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/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..d749c0531 100644 --- a/src/simulation/elements/PBCN.cpp +++ b/src/simulation/elements/PBCN.cpp @@ -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].tmpelements[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 +261,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,8 +346,10 @@ int Element_PIPE_update(UPDATE_FUNC_ARGS) int Element_PIPE_graphics(GRAPHICS_FUNC_ARGS) { + auto &sd = SimulationData::CRef(); + auto &elements = sd.elements; int t = TYP(cpart->ctype); - if (t>0 && tsim->elements[t].Enabled) + if (t>0 && ttmp = tpart.tmp3; cpart->ctype = tpart.tmp4; - RGB colour = ren->sim->elements[t].Colour; + RGB colour = elements[t].Colour; *colr = colour.Red; *colg = colour.Green; *colb = colour.Blue; - if (ren->sim->elements[t].Graphics) + if (elements[t].Graphics) { - (*(ren->sim->elements[t].Graphics))(ren, cpart, nx, ny, pixel_mode, cola, colr, colg, colb, firea, firer, fireg, fireb); + (*(elements[t].Graphics))(ren, cpart, nx, ny, pixel_mode, cola, colr, colg, colb, firea, firer, fireg, fireb); } else { @@ -419,6 +423,8 @@ int Element_PIPE_graphics(GRAPHICS_FUNC_ARGS) void Element_PIPE_transfer_pipe_to_part(Simulation * sim, 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) @@ -436,7 +442,7 @@ void Element_PIPE_transfer_pipe_to_part(Simulation * sim, Particle *pipe, Partic 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; 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..53869e43e 100644 --- a/src/simulation/elements/PRTI.cpp +++ b/src/simulation/elements/PRTI.cpp @@ -59,6 +59,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 +78,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 +96,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); 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/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/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/SPRK.cpp b/src/simulation/elements/SPRK.cpp index 4b43a5869..3d2381422 100644 --- a/src/simulation/elements/SPRK.cpp +++ b/src/simulation/elements/SPRK.cpp @@ -52,6 +52,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 +61,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; @@ -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..79f79a786 100644 --- a/src/simulation/elements/STKM.cpp +++ b/src/simulation/elements/STKM.cpp @@ -114,6 +114,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 +127,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 +451,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 +522,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 +629,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 +643,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 +660,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 +745,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/STOR.cpp b/src/simulation/elements/STOR.cpp index d0af46772..b2b09b475 100644 --- a/src/simulation/elements/STOR.cpp +++ b/src/simulation/elements/STOR.cpp @@ -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..c4005da1b 100644 --- a/src/simulation/elements/VIBR.cpp +++ b/src/simulation/elements/VIBR.cpp @@ -50,6 +50,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 +91,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 +104,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/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/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;