Enable basic rendering of custom elements in secondary Renderers

By factoring element and other static-ish data out of Simulation and protecting basic graphical element properties (i.e. everything that contributes to graphics other than the Graphics callback) with an std::shared_mutex. This is taken exclusively (std::unique_lock) by the main thread when it changes these properties, and inclusively (std::shared_lock) by non-main-thread code that uses Renderer.
This commit is contained in:
Tamás Bálint Misius 2023-12-08 19:00:10 +01:00
parent 9f8449357f
commit dd875987b9
No known key found for this signature in database
GPG Key ID: 5B472A12F6ECA9F2
79 changed files with 1038 additions and 736 deletions

View File

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

View File

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

View File

@ -328,6 +328,7 @@ static void CheckBsonFieldFloat(bson_iterator iter, const char *field, float *se
void GameSave::readOPS(const std::vector<char> &data)
{
auto &builtinGol = SimulationData::builtinGol;
constexpr auto currentVersion = Version(currentVersionMajor, 0);
constexpr auto nextVersion = Version(nextVersionMajor, 0);
@ -1185,6 +1186,7 @@ void GameSave::readOPS(const std::vector<char> &data)
#define MTOS(str) MTOS_EXPAND(str)
void GameSave::readPSv(const std::vector<char> &dataVec)
{
auto &builtinGol = SimulationData::builtinGol;
Renderer::PopulateTables();
unsigned char * saveData = (unsigned char *)&dataVec[0];
@ -1197,7 +1199,7 @@ void GameSave::readPSv(const std::vector<char> &dataVec)
char tempSignText[255];
sign tempSign("", 0, 0, sign::Left);
auto &elements = GetElements();
auto &builtinElements = GetElements();
//New file header uses PSv, replacing fuC. This is to detect if the client uses a new save format for temperatures
//This creates a problem for old clients, that display and "corrupt" error instead of a "newer version" error
@ -1607,7 +1609,7 @@ void GameSave::readPSv(const std::vector<char> &dataVec)
}
else
{
particles[i-1].temp = elements[particles[i-1].type].DefaultProperties.temp;
particles[i-1].temp = builtinElements[particles[i-1].type].DefaultProperties.temp;
}
}
}
@ -1970,7 +1972,7 @@ std::pair<bool, std::vector<char>> GameSave::serialiseOPS() const
That way, if we ever need a 25th bit, we won't have to change the save format
*/
auto &elements = GetElements();
auto &builtinElements = GetElements();
auto &possiblyCarriesType = Particle::PossiblyCarriesType();
auto &properties = Particle::GetProperties();
// Allocate enough space to store all Particles and 3 bytes on top of that per Particle, for the field descriptors.
@ -2200,7 +2202,7 @@ std::pair<bool, std::vector<char>> GameSave::serialiseOPS() const
{
for (auto index : possiblyCarriesType)
{
if (elements[particles[i].type].CarriesTypeIn & (1U << index))
if (builtinElements[particles[i].type].CarriesTypeIn & (1U << index))
{
auto *prop = reinterpret_cast<const int *>(reinterpret_cast<const char *>(&particles[i]) + properties[index].Offset);
if (TYP(*prop) > 0xFF)

View File

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

View File

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

View File

@ -11,7 +11,8 @@
std::unique_ptr<VideoBuffer> Renderer::WallIcon(int wallID, Vec2<int> size)
{
auto wtypes = LoadWalls();
auto &sd = SimulationData::CRef();
auto &wtypes = sd.wtypes;
if (wallID < 0 || wallID >= int(wtypes.size()))
return nullptr;
wall_type const &wtype = wtypes[wallID];
@ -170,14 +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<YRES; ny++)
@ -199,7 +200,7 @@ void Renderer::render_parts()
if(nx >= XRES || nx < 0 || ny >= YRES || ny < 0)
continue;
if(TYP(sim->photons[ny][nx]) && !(sim->elements[t].Properties & TYPE_ENERGY) && t!=PT_STKM && t!=PT_STKM2 && t!=PT_FIGH)
if(TYP(sim->photons[ny][nx]) && !(elements[t].Properties & TYPE_ENERGY) && t!=PT_STKM && t!=PT_STKM2 && t!=PT_FIGH)
continue;
//Defaults
@ -242,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<uint8_t> prgb = sim->wtypes[wt].colour;
RGB<uint8_t> grgb = sim->wtypes[wt].eglow;
RGB<uint8_t> prgb = wtypes[wt].colour;
RGB<uint8_t> grgb = wtypes[wt].eglow;
if (findingElement)
{
@ -951,7 +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<uint8_t> glow = sim->wtypes[wt].eglow;
RGB<uint8_t> glow = wtypes[wt].eglow;
int alpha = 255;
int cr = (alpha*glow.Red + (255-alpha)*fire_r[y/CELL][x/CELL]) >> 8;
int cg = (alpha*glow.Green + (255-alpha)*fire_g[y/CELL][x/CELL]) >> 8;

View File

@ -167,6 +167,8 @@ public:
#undef RENDERER_TABLE
static void PopulateTables();
bool useGraphicsFunction = false;
private:
int gridSize;
};

View File

@ -4,7 +4,7 @@
#include "client/Client.h"
#include "common/tpt-rand.h"
#include "simulation/GOLString.h"
#include "simulation/Simulation.h"
#include "simulation/SimulationData.h"
#include "gui/Style.h"
#include "gui/interface/Button.h"
@ -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;

View File

@ -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();
}

View File

@ -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<ByteString>{});
std::vector<ByteString> validatedCustomLifeTypes;
std::vector<Simulation::CustomGOLData> newCustomGol;
std::vector<CustomGOLData> newCustomGol;
bool removedAny = false;
for (auto gol : customGOLTypes)
{
@ -311,7 +315,7 @@ void GameModel::BuildMenus()
removedAny = true;
continue;
}
Simulation::CustomGOLData gd;
CustomGOLData gd;
gd.nameString = parts[0];
gd.ruleString = parts[1];
auto &colour1String = parts[2];
@ -350,26 +354,25 @@ void GameModel::BuildMenus()
Tool * tempTool = new ElementTool(PT_LIFE|PMAPID(gd.rule), gd.nameString, "Custom GOL type: " + gd.ruleString, RGB<uint8_t>::Unpack(gd.colour1), "DEFAULT_PT_LIFECUST_"+gd.nameString.ToAscii(), NULL);
menuList[SC_LIFE]->AddTool(tempTool);
}
sim->SetCustomGOL(newCustomGol);
sd.SetCustomGOL(newCustomGol);
}
//Build other menus from wall data
for(int i = 0; i < UI_WALLCOUNT; i++)
{
Tool * tempTool = new WallTool(i, sim->wtypes[i].descs, sim->wtypes[i].colour, sim->wtypes[i].identifier, sim->wtypes[i].textureGen);
Tool * tempTool = new WallTool(i, sd.wtypes[i].descs, sd.wtypes[i].colour, sd.wtypes[i].identifier, sd.wtypes[i].textureGen);
menuList[SC_WALL]->AddTool(tempTool);
//sim->wtypes[i]
}
//Build menu for tools
for (size_t i = 0; i < sim->tools.size(); i++)
for (size_t i = 0; i < sd.tools.size(); i++)
{
Tool *tempTool = new Tool(
i,
sim->tools[i].Name,
sim->tools[i].Description,
sim->tools[i].Colour,
sim->tools[i].Identifier
sd.tools[i].Name,
sd.tools[i].Description,
sd.tools[i].Colour,
sd.tools[i].Identifier
);
menuList[SC_TOOL]->AddTool(tempTool);
}

View File

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

View File

@ -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<LuaScriptInterface *>(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;
}

View File

@ -451,11 +451,13 @@ LuaScriptInterface::LuaScriptInterface(GameController * c, GameModel * m):
tptPart->Assign(l, -1);
lua_pop(l, 1);
auto &sd = SimulationData::CRef();
auto &elements = sd.elements;
lua_newtable(l);
tptElements = lua_gettop(l);
for (int i = 1; i < PT_NUM; i++)
{
tpt_lua_pushString(l, luacon_sim->elements[i].Name.ToLower());
tpt_lua_pushString(l, elements[i].Name.ToLower());
lua_newtable(l);
currentElement = lua_gettop(l);
lua_pushinteger(l, i);
@ -475,7 +477,7 @@ LuaScriptInterface::LuaScriptInterface(GameController * c, GameModel * m):
tptElementTransitions = lua_gettop(l);
for (int i = 1; i < PT_NUM; i++)
{
tpt_lua_pushString(l, luacon_sim->elements[i].Name.ToLower());
tpt_lua_pushString(l, elements[i].Name.ToLower());
lua_newtable(l);
currentElement = lua_gettop(l);
lua_newtable(l);
@ -536,14 +538,15 @@ LuaScriptInterface::LuaScriptInterface(GameController * c, GameModel * m):
void LuaScriptInterface::custom_init_can_move()
{
luacon_sim->init_can_move();
auto &sd = SimulationData::Ref();
sd.init_can_move();
for (auto moving = 0; moving < PT_NUM; ++moving)
{
for (auto into = 0; into < PT_NUM; ++into)
{
if (custom_can_move[moving][into] & 0x80)
{
luacon_sim->can_move[moving][into] = custom_can_move[moving][into] & 0x7F;
sd.can_move[moving][into] = custom_can_move[moving][into] & 0x7F;
}
}
}
@ -1112,6 +1115,8 @@ int simulation_deletesign(lua_State *l)
void LuaScriptInterface::initSimulationAPI()
{
auto &sd = SimulationData::CRef();
//Methods
struct luaL_Reg simulationAPIMethods [] = {
{"partNeighbours", simulation_partNeighbours},
@ -1227,7 +1232,7 @@ void LuaScriptInterface::initSimulationAPI()
SETCONST(l, TOOL_NGRV);
SETCONST(l, TOOL_MIX);
SETCONST(l, TOOL_CYCL);
lua_pushinteger(l, luacon_sim->tools.size()); lua_setfield(l, -2, "TOOL_WIND");
lua_pushinteger(l, sd.tools.size()); lua_setfield(l, -2, "TOOL_WIND");
SETCONST(l, DECO_DRAW);
SETCONST(l, DECO_CLEAR);
@ -1266,12 +1271,12 @@ void LuaScriptInterface::initSimulationAPI()
lua_newtable(l);
for (int i = 0; i < UI_WALLCOUNT; i++)
{
tpt_lua_pushByteString(l, luacon_sim->wtypes[i].identifier);
tpt_lua_pushByteString(l, sd.wtypes[i].identifier);
lua_pushinteger(l, i);
lua_settable(l, -3);
lua_pushinteger(l, i);
tpt_lua_pushByteString(l, luacon_sim->wtypes[i].identifier);
tpt_lua_pushByteString(l, sd.wtypes[i].identifier);
lua_settable(l, -3);
}
lua_setfield(l, -2, "walls");
@ -1898,6 +1903,7 @@ int LuaScriptInterface::simulation_floodWalls(lua_State * l)
int LuaScriptInterface::simulation_toolBrush(lua_State * l)
{
auto &sd = SimulationData::CRef();
int x = luaL_optint(l,1,-1);
int y = luaL_optint(l,2,-1);
int rx = luaL_optint(l,3,5);
@ -1905,12 +1911,12 @@ int LuaScriptInterface::simulation_toolBrush(lua_State * l)
int tool = luaL_optint(l,5,0);
int brushID = luaL_optint(l,6,CIRCLE_BRUSH);
float strength = luaL_optnumber(l,7,1.0f);
if (tool == (int)luacon_sim->tools.size())
if (tool == (int)sd.tools.size())
{
lua_pushinteger(l, 0);
return 1;
}
else if (tool < 0 || tool > (int)luacon_sim->tools.size())
else if (tool < 0 || tool > (int)sd.tools.size())
return luaL_error(l, "Invalid tool id '%d'", tool);
Brush *brush = luacon_model->GetBrushByID(brushID);
@ -1926,6 +1932,7 @@ int LuaScriptInterface::simulation_toolBrush(lua_State * l)
int LuaScriptInterface::simulation_toolLine(lua_State * l)
{
auto &sd = SimulationData::CRef();
int x1 = luaL_optint(l,1,-1);
int y1 = luaL_optint(l,2,-1);
int x2 = luaL_optint(l,3,-1);
@ -1938,7 +1945,7 @@ int LuaScriptInterface::simulation_toolLine(lua_State * l)
if (x1 < 0 || x2 < 0 || x1 >= XRES || x2 >= XRES || y1 < 0 || y2 < 0 || y1 >= YRES || y2 >= YRES)
return luaL_error(l, "coordinates out of range (%d,%d),(%d,%d)", x1, y1, x2, y2);
if (tool < 0 || tool >= (int)luacon_sim->tools.size()+1)
if (tool < 0 || tool >= (int)sd.tools.size()+1)
return luaL_error(l, "Invalid tool id '%d'", tool);
Brush *brush = luacon_model->GetBrushByID(brushID);
@ -1947,7 +1954,7 @@ int LuaScriptInterface::simulation_toolLine(lua_State * l)
auto newBrush = brush->Clone();
newBrush->SetRadius(ui::Point(rx, ry));
if (tool == (int)luacon_sim->tools.size())
if (tool == (int)sd.tools.size())
{
Tool *windTool = luacon_model->GetToolFromIdentifier("DEFAULT_UI_WIND");
float oldStrength = windTool->Strength;
@ -1962,6 +1969,7 @@ int LuaScriptInterface::simulation_toolLine(lua_State * l)
int LuaScriptInterface::simulation_toolBox(lua_State * l)
{
auto &sd = SimulationData::CRef();
int x1 = luaL_optint(l,1,-1);
int y1 = luaL_optint(l,2,-1);
int x2 = luaL_optint(l,3,-1);
@ -1970,12 +1978,12 @@ int LuaScriptInterface::simulation_toolBox(lua_State * l)
return luaL_error(l, "coordinates out of range (%d,%d),(%d,%d)", x1, y1, x2, y2);
int tool = luaL_optint(l,5,0);
float strength = luaL_optnumber(l,6,1.0f);
if (tool == (int)luacon_sim->tools.size())
if (tool == (int)sd.tools.size())
{
lua_pushinteger(l, 0);
return 1;
}
else if (tool < 0 || tool >= (int)luacon_sim->tools.size())
else if (tool < 0 || tool >= (int)sd.tools.size())
return luaL_error(l, "Invalid tool id '%d'", tool);
luacon_sim->ToolBox(x1, y1, x2, y2, tool, strength);
@ -2110,12 +2118,14 @@ int LuaScriptInterface::simulation_clearRect(lua_State * l)
int LuaScriptInterface::simulation_resetTemp(lua_State * l)
{
auto &sd = SimulationData::CRef();
auto &elements = sd.elements;
bool onlyConductors = luaL_optint(l, 1, 0);
for (int i = 0; i < luacon_sim->parts_lastActiveIndex; i++)
{
if (luacon_sim->parts[i].type && (luacon_sim->elements[luacon_sim->parts[i].type].HeatConduct || !onlyConductors))
if (luacon_sim->parts[i].type && (elements[luacon_sim->parts[i].type].HeatConduct || !onlyConductors))
{
luacon_sim->parts[i].temp = luacon_sim->elements[luacon_sim->parts[i].type].DefaultProperties.temp;
luacon_sim->parts[i].temp = elements[luacon_sim->parts[i].type].DefaultProperties.temp;
}
}
return 0;
@ -2427,14 +2437,16 @@ int LuaScriptInterface::simulation_canMove(lua_State * l)
if (lua_gettop(l) < 3)
{
lua_pushnumber(l, luacon_sim->can_move[movingElement][destinationElement]);
auto &sd = SimulationData::CRef();
lua_pushnumber(l, sd.can_move[movingElement][destinationElement]);
return 1;
}
else
{
int setting = luaL_checkint(l, 3) & 0x7F;
luacon_ci->custom_can_move[movingElement][destinationElement] = setting | 0x80;
luacon_sim->can_move[movingElement][destinationElement] = setting;
auto &sd = SimulationData::Ref();
sd.can_move[movingElement][destinationElement] = setting;
return 0;
}
}
@ -2684,9 +2696,10 @@ int LuaScriptInterface::simulation_replaceModeFlags(lua_State *l)
int LuaScriptInterface::simulation_listCustomGol(lua_State *l)
{
auto &sd = SimulationData::CRef();
int i = 0;
lua_newtable(l);
for (auto &cgol : luacon_sim->GetCustomGol())
for (auto &cgol : sd.GetCustomGol())
{
lua_newtable(l);
tpt_lua_pushString(l, cgol.nameString);
@ -2706,6 +2719,7 @@ int LuaScriptInterface::simulation_listCustomGol(lua_State *l)
int LuaScriptInterface::simulation_addCustomGol(lua_State *l)
{
auto &sd = SimulationData::CRef();
int rule;
String ruleString;
if (lua_isnumber(l, 1))
@ -2727,7 +2741,7 @@ int LuaScriptInterface::simulation_addCustomGol(lua_State *l)
return luaL_error(l, "Invalid name provided");
if (rule == -1)
return luaL_error(l, "Invalid rule provided");
if (luacon_sim->GetCustomGOLByRule(rule))
if (sd.GetCustomGOLByRule(rule))
return luaL_error(l, "This Custom GoL rule already exists");
if (!AddCustomGol(ruleString, nameString, color1, color2))
@ -3145,15 +3159,17 @@ void LuaScriptInterface::initElementsAPI()
SETCONST(l, SC_DECO);
//Element identifiers
auto &sd = SimulationData::CRef();
auto &elements = sd.elements;
for(int i = 0; i < PT_NUM; i++)
{
if(luacon_sim->elements[i].Enabled)
if(elements[i].Enabled)
{
tpt_lua_pushByteString(l, luacon_sim->elements[i].Identifier);
tpt_lua_pushByteString(l, elements[i].Identifier);
lua_pushinteger(l, i);
lua_settable(l, -3);
ByteString realIdentifier = ByteString::Build("DEFAULT_PT_", luacon_sim->elements[i].Name.ToUtf8());
if (i != 0 && i != PT_NBHL && i != PT_NWHL && luacon_sim->elements[i].Identifier != realIdentifier)
ByteString realIdentifier = ByteString::Build("DEFAULT_PT_", elements[i].Name.ToUtf8());
if (i != 0 && i != PT_NBHL && i != PT_NWHL && elements[i].Identifier != realIdentifier)
{
tpt_lua_pushByteString(l, realIdentifier);
lua_pushinteger(l, i);
@ -3270,52 +3286,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<LuaScriptInterface *>(commandInterface);
int args = lua_gettop(l);
if (args)
{
luaL_checktype(l, 1, LUA_TNUMBER);
int id = lua_tointeger(l, 1);
if (id < 0 || id >= PT_NUM)
return luaL_error(l, "Invalid element");
lua_getglobal(l, "elements");
tpt_lua_pushByteString(l, luacon_sim->elements[id].Identifier);
lua_pushnil(l);
lua_settable(l, -3);
auto const &elementList = GetElements();
if (id < (int)elementList.size())
luacon_sim->elements[id] = elementList[id];
else
luacon_sim->elements[id] = Element();
tpt_lua_pushByteString(l, luacon_sim->elements[id].Identifier);
lua_pushinteger(l, id);
lua_settable(l, -3);
lua_pop(l, 1);
}
else
{
auto const &elementList = GetElements();
for (int i = 0; i < PT_NUM; i++)
int args = lua_gettop(l);
if (args)
{
if (i < (int)elementList.size())
luacon_sim->elements[i] = elementList[i];
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<LuaScriptInterface *>(commandInterface);
auto *builtinUpdate = GetElements()[parts[i].type].Update;
auto &builtinElements = GetElements();
auto *builtinUpdate = builtinElements[parts[i].type].Update;
if (builtinUpdate && lua_el_mode[parts[i].type] == 1)
{
if (builtinUpdate(UPDATE_FUNC_SUBCALL_ARGS))
@ -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<LuaScriptInterface *>(commandInterface);
int id = luaL_checkinteger(l, 1);
if (!luacon_sim->IsElementOrNone(id))
if (!SimulationData::CRef().IsElementOrNone(id))
{
return luaL_error(l, "Invalid element");
}
if (lua_gettop(l) > 1)
{
luaL_checktype(l, 2, LUA_TTABLE);
//Write values from native data to a table
for (auto &prop : Element::GetProperties())
{
tpt_lua_pushByteString(l, prop.Name);
lua_gettable(l, -2);
if (lua_type(l, -1) != LUA_TNIL)
auto &sd = SimulationData::Ref();
std::unique_lock lk(sd.elementGraphicsMx);
auto &elements = sd.elements;
luaL_checktype(l, 2, LUA_TTABLE);
//Write values from native data to a table
for (auto &prop : Element::GetProperties())
{
intptr_t propertyAddress = (intptr_t)(((unsigned char*)&luacon_sim->elements[id]) + prop.Offset);
LuaSetProperty(l, prop, propertyAddress, -1);
tpt_lua_pushByteString(l, prop.Name);
lua_gettable(l, -2);
if (lua_type(l, -1) != LUA_TNIL)
{
intptr_t propertyAddress = (intptr_t)(((unsigned char*)&elements[id]) + prop.Offset);
LuaSetProperty(l, prop, propertyAddress, -1);
}
lua_pop(l, 1);
}
lua_getfield(l, -1, "Update");
if (lua_type(l, -1) == LUA_TFUNCTION)
{
lua_el_func[id].Assign(l, -1);
lua_el_mode[id] = 1;
elements[id].Update = luaUpdateWrapper;
}
else if (lua_type(l, -1) == LUA_TBOOLEAN && !lua_toboolean(l, -1))
{
lua_el_func[id].Clear();
lua_el_mode[id] = 0;
elements[id].Update = builtinElements[id].Update;
}
lua_pop(l, 1);
lua_getfield(l, -1, "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<intptr_t>((reinterpret_cast<unsigned char*>(&luacon_sim->elements[id].DefaultProperties)) + prop.Offset);
auto propertyAddress = reinterpret_cast<intptr_t>((reinterpret_cast<const unsigned char*>(&elements[id].DefaultProperties)) + prop.Offset);
tpt_lua_pushByteString(l, prop.Name);
LuaGetProperty(l, prop, propertyAddress);
lua_settable(l, -3);
@ -3748,6 +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<intptr_t>((reinterpret_cast<unsigned char*>(&luacon_sim->elements[id].DefaultProperties)) + prop.Offset);
auto propertyAddress = reinterpret_cast<intptr_t>((reinterpret_cast<unsigned char*>(&elements[id].DefaultProperties)) + prop.Offset);
LuaSetProperty(l, prop, propertyAddress, -1);
}
lua_pop(l, 1);
@ -3778,9 +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<LuaScriptInterface *>(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;
}

View File

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

View File

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

View File

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

View File

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

View File

@ -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;
}

View File

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

View File

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

View File

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

View File

@ -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<std::unique_ptr<VideoBuffer>, 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<std::mutex> gx(renderMutex);
ren->ResetModes();

View File

@ -1,7 +1,8 @@
#include "Sign.h"
#include "graphics/Graphics.h"
#include "simulation/Simulation.h"
#include "Simulation.h"
#include "SimulationData.h"
sign::sign(String text_, int x_, int y_, Justification justification_):
x(x_),
@ -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;
}

View File

@ -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<GameSave> Simulation::Save(bool includePressure, Rect<int> partR
// Now stores all particles, not just SOAP (but still only used for soap)
std::map<unsigned int, unsigned int> particleMap;
std::set<int> 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<Air>(*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<CustomGOLData> 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);

View File

@ -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> air;
RNG rng;
std::vector<sign> signs;
std::array<Element, PT_NUM> elements;
//Element * elements;
std::vector<SimTool> tools;
std::vector<unsigned int> platent;
std::vector<wall_type> wtypes;
std::vector<menu_section> msections;
int currentTick;
int replaceModeSelected;
int replaceModeFlags;
char can_move[PT_NUM][PT_NUM];
int debug_nextToUpdate;
int debug_mostRecentlyUpdated = -1; // -1 when between full update loops
int parts_lastActiveIndex;
@ -127,7 +119,7 @@ public:
void SaveSimOptions(GameSave &gameSave);
SimulationSample GetSample(int x, int y);
std::unique_ptr<Snapshot> CreateSnapshot();
std::unique_ptr<Snapshot> CreateSnapshot() const;
void Restore(const Snapshot &snap);
int is_blocking(int t, int x, int y);
@ -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<CustomGOLData> customGol;
public:
const CustomGOLData *GetCustomGOLByRule(int rule) const;
const std::vector<CustomGOLData> GetCustomGol() { return customGol; }
void SetCustomGOL(std::vector<CustomGOLData> newCustomGol);
private:
CoordStack& getCoordStackSingleton();
};

View File

@ -1,16 +1,16 @@
#include "SimulationData.h"
#include "ElementGraphics.h"
#include "ElementDefs.h"
#include "ElementClasses.h"
#include "GOLString.h"
#include "BuiltinGOL.h"
#include "WallType.h"
#include "MenuSection.h"
#include "ToolClasses.h"
#include "Misc.h"
#include "graphics/Renderer.h"
const BuiltinGOL builtinGol[NGOL] = {
const std::array<BuiltinGOL, NGOL> SimulationData::builtinGol = {{
// * Ruleset:
// * bits x = 8..0: stay if x neighbours present
// * bits x = 16..9: begin if x-8 neighbours present
@ -45,9 +45,9 @@ const BuiltinGOL builtinGol[NGOL] = {
{ "STAR", GT_STAR, 0x98478, 0x000040_rgb, 0x0000E6_rgb, NGT_STAR, String("Like Star Wars rule: B278/S3456/6") },
{ "FROG", GT_FROG, 0x21806, 0x006400_rgb, 0x00FF00_rgb, NGT_FROG, String("Frogs: B34/S12/3") },
{ "BRAN", GT_BRAN, 0x25440, 0xFFFF00_rgb, 0x969600_rgb, NGT_BRAN, String("Brian 6: B246/S6/3" )}
};
}};
std::vector<wall_type> LoadWalls()
static std::vector<wall_type> LoadWalls()
{
return
std::vector<wall_type>{
@ -73,7 +73,7 @@ std::vector<wall_type> LoadWalls()
};
}
std::vector<menu_section> LoadMenus()
static std::vector<menu_section> LoadMenus()
{
return
std::vector<menu_section>{
@ -98,7 +98,7 @@ std::vector<menu_section> LoadMenus()
};
}
std::vector<unsigned int> LoadLatent()
static std::vector<unsigned int> LoadLatent()
{
return
std::vector<unsigned int>{
@ -265,3 +265,246 @@ std::vector<unsigned int> 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<CustomGOLData> newCustomGol)
{
std::sort(newCustomGol.begin(), newCustomGol.end());
customGol = newCustomGol;
}
String SimulationData::ElementResolve(int type, int ctype) const
{
if (type == PT_LIFE)
{
if (ctype >= 0 && ctype < NGOL)
{
return builtinGol[ctype].name;
}
auto *cgol = GetCustomGOLByRule(ctype);
if (cgol)
{
return cgol->nameString;
}
return SerialiseGOLRule(ctype);
}
else if (type >= 0 && type < PT_NUM)
return elements[type].Name;
return "Empty";
}
String SimulationData::BasicParticleInfo(Particle const &sample_part) const
{
StringBuilder sampleInfo;
int type = sample_part.type;
int ctype = sample_part.ctype;
int storedCtype = sample_part.tmp4;
if (type == PT_LAVA && IsElement(ctype))
{
sampleInfo << "Molten " << ElementResolve(ctype, -1);
}
else if ((type == PT_PIPE || type == PT_PPIP) && IsElement(ctype))
{
if (ctype == PT_LAVA && IsElement(storedCtype))
{
sampleInfo << ElementResolve(type, -1) << " with molten " << ElementResolve(storedCtype, -1);
}
else
{
sampleInfo << ElementResolve(type, -1) << " with " << ElementResolve(ctype, storedCtype);
}
}
else
{
sampleInfo << ElementResolve(type, ctype);
}
return sampleInfo.Build();
}
int SimulationData::GetParticleType(ByteString type) const
{
type = type.ToUpper();
// alternative names for some elements
if (byteStringEqualsLiteral(type, "C4"))
{
return PT_PLEX;
}
else if (byteStringEqualsLiteral(type, "C5"))
{
return PT_C5;
}
else if (byteStringEqualsLiteral(type, "NONE"))
{
return PT_NONE;
}
for (int i = 1; i < PT_NUM; i++)
{
if (elements[i].Name.size() && elements[i].Enabled && type == elements[i].Name.ToUtf8().ToUpper())
{
return i;
}
}
return -1;
}
SimulationData::SimulationData()
{
init_can_move();
msections = LoadMenus();
wtypes = LoadWalls();
platent = LoadLatent();
elements = GetElements();
tools = GetTools();
}

View File

@ -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 <cstdint>
#include <vector>
#include <array>
#include <shared_mutex>
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<SimulationData>
{
public:
std::array<Element, PT_NUM> elements;
std::vector<SimTool> tools;
std::vector<unsigned int> platent;
std::vector<wall_type> wtypes;
std::vector<menu_section> msections;
char can_move[PT_NUM][PT_NUM];
static const std::array<BuiltinGOL, NGOL> builtinGol;
extern const BuiltinGOL builtinGol[];
// Element properties that enable basic graphics (i.e. every property that has to do with graphics other than
// the graphics callback itself) are only ever written by the main thread, but they are read by some other
// threads that use Renderer to render thumbnails and such. Take this std::shared_mutex with an std::unique_lock
// when writing such properties in the main thread, and with an std::shared_lock when reading such properties
// in these secondary Renderer threads. Don't take it with an std::shared_lock when reading such properties in
// the main thread; the main thread doesn't race with itself.
mutable std::shared_mutex elementGraphicsMx;
std::vector<wall_type> LoadWalls();
private:
std::vector<CustomGOLData> customGol;
std::vector<menu_section> LoadMenus();
public:
SimulationData();
void InitElements();
std::vector<unsigned int> LoadLatent();
void init_can_move();
const CustomGOLData *GetCustomGOLByRule(int rule) const;
const std::vector<CustomGOLData> &GetCustomGol() const { return customGol; }
void SetCustomGOL(std::vector<CustomGOLData> newCustomGol);
String ElementResolve(int type, int ctype) const;
String BasicParticleInfo(Particle const &sample_part) const;
int GetParticleType(ByteString type) const;
bool IsElement(int type) const
{
return (type > 0 && type < PT_NUM && elements[type].Enabled);
}
bool IsElementOrNone(int type) const
{
return (type >= 0 && type < PT_NUM && elements[type].Enabled);
}
};

View File

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

View File

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

View File

@ -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;

View File

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

View File

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

View File

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

View File

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

View File

@ -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;

View File

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

View File

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

View File

@ -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;
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -52,6 +52,8 @@ void Element::Element_EMBR()
static int update(UPDATE_FUNC_ARGS)
{
auto &sd = SimulationData::CRef();
auto &elements = sd.elements;
for (auto rx = -1; rx <= 1; rx++)
{
for (auto ry = -1; ry <= 1; ry++)
@ -61,7 +63,7 @@ static int update(UPDATE_FUNC_ARGS)
auto r = pmap[y+ry][x+rx];
if (!r)
continue;
if ((sim->elements[TYP(r)].Properties & (TYPE_SOLID | TYPE_PART | TYPE_LIQUID)) && !(sim->elements[TYP(r)].Properties & PROP_SPARKSETTLE))
if ((elements[TYP(r)].Properties & (TYPE_SOLID | TYPE_PART | TYPE_LIQUID)) && !(elements[TYP(r)].Properties & PROP_SPARKSETTLE))
{
sim->kill_part(i);
return 1;

View File

@ -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<x)

View File

@ -54,6 +54,8 @@ void Element::Element_FIRE()
int Element_FIRE_update(UPDATE_FUNC_ARGS)
{
auto &sd = SimulationData::CRef();
auto &elements = sd.elements;
int t = parts[i].type;
switch (t)
{
@ -131,7 +133,7 @@ int Element_FIRE_update(UPDATE_FUNC_ARGS)
}
}
}
else if ((parts[i].ctype == PT_STNE || !parts[i].ctype) && pres >= 30.0f && (parts[i].temp > sim->elements[PT_ROCK].HighTemperature || pres < sim->elements[PT_ROCK].HighPressure)) // Form ROCK with pressure, if it will stay molten or not immediately break
else if ((parts[i].ctype == PT_STNE || !parts[i].ctype) && pres >= 30.0f && (parts[i].temp > elements[PT_ROCK].HighTemperature || pres < elements[PT_ROCK].HighPressure)) // Form ROCK with pressure, if it will stay molten or not immediately break
{
parts[i].tmp2 = sim->rng.between(0, 10); // Provide tmp2 for color noise
parts[i].ctype = PT_ROCK;
@ -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)
{

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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);

View File

@ -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;

View File

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

View File

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

View File

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

View File

@ -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)

View File

@ -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)

View File

@ -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].ctype<PT_NUM && sim->elements[parts[i].ctype].Enabled)
if (parts[i].ctype>0 && parts[i].ctype<PT_NUM && elements[parts[i].ctype].Enabled)
{
if (parts[i].ctype==PT_PHOT) {//create photons a different way
for (auto rx = -1; rx <= 1; rx++)
@ -156,7 +158,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>-1)
{
if (parts[i].ctype==PT_LAVA && parts[i].tmp>0 && parts[i].tmp<PT_NUM && sim->elements[parts[i].tmp].HighTemperatureTransition==PT_LAVA)
if (parts[i].ctype==PT_LAVA && parts[i].tmp>0 && parts[i].tmp<PT_NUM && elements[parts[i].tmp].HighTemperatureTransition==PT_LAVA)
parts[np].ctype = parts[i].tmp;
}
}

View File

@ -52,6 +52,8 @@ void Element::Element_PCLN()
static int update(UPDATE_FUNC_ARGS)
{
auto &sd = SimulationData::CRef();
auto &elements = sd.elements;
if (parts[i].life>0 && 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].ctype<PT_NUM && sim->elements[parts[i].ctype].Enabled && parts[i].life==10)
if (parts[i].ctype>0 && parts[i].ctype<PT_NUM && elements[parts[i].ctype].Enabled && parts[i].life==10)
{
if (parts[i].ctype==PT_PHOT) {//create photons a different way
for (auto rx = -1; rx <= 1; rx++)
@ -147,7 +149,7 @@ static int update(UPDATE_FUNC_ARGS)
int np = sim->create_part(-1, x + sim->rng.between(-1, 1), y + sim->rng.between(-1, 1), TYP(parts[i].ctype));
if (np>=0)
{
if (parts[i].ctype==PT_LAVA && parts[i].tmp>0 && parts[i].tmp<PT_NUM && sim->elements[parts[i].tmp].HighTemperatureTransition==PT_LAVA)
if (parts[i].ctype==PT_LAVA && parts[i].tmp>0 && parts[i].tmp<PT_NUM && elements[parts[i].tmp].HighTemperatureTransition==PT_LAVA)
parts[np].ctype = parts[i].tmp;
}
}

View File

@ -123,7 +123,9 @@ static unsigned int nextColor(unsigned int flags)
int Element_PIPE_update(UPDATE_FUNC_ARGS)
{
if (parts[i].ctype && !sim->elements[TYP(parts[i].ctype)].Enabled)
auto &sd = SimulationData::CRef();
auto &elements = sd.elements;
if (parts[i].ctype && !elements[TYP(parts[i].ctype)].Enabled)
parts[i].ctype = 0;
if (parts[i].tmp & PPIP_TMPFLAG_TRIGGERS)
{
@ -259,14 +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 && t<PT_NUM && ren->sim->elements[t].Enabled)
if (t>0 && t<PT_NUM && elements[t].Enabled)
{
if (t == PT_STKM || t == PT_STKM2 || t == PT_FIGH)
return 0;
@ -374,13 +378,13 @@ int Element_PIPE_graphics(GRAPHICS_FUNC_ARGS)
cpart->tmp = tpart.tmp3;
cpart->ctype = tpart.tmp4;
RGB<uint8_t> colour = ren->sim->elements[t].Colour;
RGB<uint8_t> 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;

View File

@ -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;
}

View File

@ -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);

View File

@ -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;

View File

@ -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);

View File

@ -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);

View File

@ -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.

View File

@ -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)

View File

@ -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;
}

View File

@ -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);

View File

@ -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;
}

View File

@ -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;

View File

@ -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))

View File

@ -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;

View File

@ -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;

View File

@ -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;