From 44590d82e983708ca3bc7529ce33b592eeeb0581 Mon Sep 17 00:00:00 2001 From: jacob1 Date: Fri, 27 Aug 2021 23:57:55 -0400 Subject: [PATCH] Add a few more Lua functions sim.replaceModeFlags sim.listCustomGol sim.addCustomGol sim.removeCustomGol tpt.perfectCircleBrush sim.floodDeco --- src/gui/game/GOLTool.cpp | 29 +-------- src/gui/game/GameModel.cpp | 18 ++---- src/gui/game/GameModel.h | 2 +- src/lua/LegacyLuaAPI.cpp | 12 ++++ src/lua/LuaScriptHelper.h | 1 + src/lua/LuaScriptInterface.cpp | 105 +++++++++++++++++++++++++++++++++ src/lua/LuaScriptInterface.h | 6 ++ src/simulation/GOLString.cpp | 28 +++++++++ src/simulation/GOLString.h | 1 + src/simulation/Simulation.h | 1 + 10 files changed, 164 insertions(+), 39 deletions(-) diff --git a/src/gui/game/GOLTool.cpp b/src/gui/game/GOLTool.cpp index 0bb27389f..4d553bf1a 100644 --- a/src/gui/game/GOLTool.cpp +++ b/src/gui/game/GOLTool.cpp @@ -156,33 +156,10 @@ void GOLWindow::Validate() Client::Ref().SetPrefUnicode("CustomGOL.Name", nameString); Client::Ref().SetPrefUnicode("CustomGOL.Rule", ruleString); - auto customGOLTypes = Client::Ref().GetPrefByteStringArray("CustomGOL.Types"); - Json::Value newCustomGOLTypes(Json::arrayValue); - bool nameTaken = false; - for (auto gol : customGOLTypes) - { - auto parts = gol.FromUtf8().PartitionBy(' '); - if (parts.size()) - { - if (parts[0] == nameString) - { - nameTaken = true; - } - } - newCustomGOLTypes.append(gol); - } - if (nameTaken) - { - new ErrorMessage("Could not add GOL type", "Name already taken"); - return; - } + auto color1 = (((highColour.Red << 8) | highColour.Green) << 8) | highColour.Blue; + auto color2 = (((lowColour.Red << 8) | lowColour.Green) << 8) | lowColour.Blue; + AddCustomGol(ruleString, nameString, color1, color2); - StringBuilder sb; - auto colour1 = (((highColour.Red << 8) | highColour.Green) << 8) | highColour.Blue; - auto colour2 = (((lowColour.Red << 8) | lowColour.Green) << 8) | lowColour.Blue; - sb << nameString << " " << ruleString << " " << colour1 << " " << colour2; - newCustomGOLTypes.append(sb.Build().ToUtf8()); - Client::Ref().SetPref("CustomGOL.Types", newCustomGOLTypes); tool->gameModel->SelectNextIdentifier = "DEFAULT_PT_LIFECUST_" + nameString.ToAscii(); tool->gameModel->SelectNextTool = toolSelection; } diff --git a/src/gui/game/GameModel.cpp b/src/gui/game/GameModel.cpp index 1a96f4388..a8eba37e0 100644 --- a/src/gui/game/GameModel.cpp +++ b/src/gui/game/GameModel.cpp @@ -1640,26 +1640,20 @@ void GameModel::SetPerfectCircle(bool perfectCircle) } } -void GameModel::RemoveCustomGOLType(const ByteString &identifier) +bool GameModel::RemoveCustomGOLType(const ByteString &identifier) { + bool removedAny = false; auto customGOLTypes = Client::Ref().GetPrefByteStringArray("CustomGOL.Types"); Json::Value newCustomGOLTypes(Json::arrayValue); for (auto gol : customGOLTypes) { auto parts = gol.PartitionBy(' '); - bool remove = false; - if (parts.size()) - { - if ("DEFAULT_PT_LIFECUST_" + parts[0] == identifier) - { - remove = true; - } - } - if (!remove) - { + if (parts.size() && "DEFAULT_PT_LIFECUST_" + parts[0] == identifier) + removedAny = true; + else newCustomGOLTypes.append(gol); - } } Client::Ref().SetPref("CustomGOL.Types", newCustomGOLTypes); BuildMenus(); + return removedAny; } diff --git a/src/gui/game/GameModel.h b/src/gui/game/GameModel.h index d9b0d5d5c..142e54a15 100644 --- a/src/gui/game/GameModel.h +++ b/src/gui/game/GameModel.h @@ -238,7 +238,7 @@ public: void AddNotification(Notification * notification); void RemoveNotification(Notification * notification); - void RemoveCustomGOLType(const ByteString &identifier); + bool RemoveCustomGOLType(const ByteString &identifier); ByteString SelectNextIdentifier; int SelectNextTool; diff --git a/src/lua/LegacyLuaAPI.cpp b/src/lua/LegacyLuaAPI.cpp index 7178ad068..8a36e7d16 100644 --- a/src/lua/LegacyLuaAPI.cpp +++ b/src/lua/LegacyLuaAPI.cpp @@ -1523,4 +1523,16 @@ int luatpt_record(lua_State* l) return 1; } +int luatpt_perfectCircle(lua_State* l) +{ + if (!lua_gettop(l)) + { + lua_pushboolean(l, luacon_model->GetPerfectCircle()); + return 1; + } + luaL_checktype(l, 1, LUA_TBOOLEAN); + luacon_model->SetPerfectCircle(lua_toboolean(l, 1)); + return 0; +} + #endif diff --git a/src/lua/LuaScriptHelper.h b/src/lua/LuaScriptHelper.h index 9f9ca4ccb..945b8d2b2 100644 --- a/src/lua/LuaScriptHelper.h +++ b/src/lua/LuaScriptHelper.h @@ -135,5 +135,6 @@ int luatpt_setwindowsize(lua_State* l); int luatpt_screenshot(lua_State* l); int luatpt_record(lua_State* l); +int luatpt_perfectCircle(lua_State* l); #endif /* LUASCRIPTHELPER_H_ */ diff --git a/src/lua/LuaScriptInterface.cpp b/src/lua/LuaScriptInterface.cpp index a79d0b51f..a11c74f2c 100644 --- a/src/lua/LuaScriptInterface.cpp +++ b/src/lua/LuaScriptInterface.cpp @@ -34,6 +34,7 @@ #include "simulation/ElementCommon.h" #include "simulation/ElementClasses.h" #include "simulation/ElementGraphics.h" +#include "simulation/GOLString.h" #include "simulation/Simulation.h" #include "simulation/ToolClasses.h" @@ -217,6 +218,7 @@ LuaScriptInterface::LuaScriptInterface(GameController * c, GameModel * m): {"get_clipboard", &platform_clipboardCopy}, {"set_clipboard", &platform_clipboardPaste}, {"setdrawcap", &luatpt_setdrawcap}, + {"perfectCircleBrush", &luatpt_perfectCircle}, {NULL,NULL} }; @@ -822,6 +824,7 @@ void LuaScriptInterface::initSimulationAPI() {"decoBox", simulation_decoBox}, {"decoColor", simulation_decoColor}, {"decoColour", simulation_decoColor}, + {"floodDeco", simulation_floodDeco}, {"clearSim", simulation_clearSim}, {"clearRect", simulation_clearRect}, {"resetTemp", simulation_resetTemp}, @@ -852,6 +855,10 @@ void LuaScriptInterface::initSimulationAPI() {"framerender", simulation_framerender}, {"gspeed", simulation_gspeed}, {"takeSnapshot", simulation_takeSnapshot}, + {"replaceModeFlags", simulation_replaceModeFlags}, + {"listCustomGol", simulation_listCustomGol}, + {"addCustomGol", simulation_addCustomGol}, + {"removeCustomGol", simulation_removeCustomGol}, {NULL, NULL} }; luaL_register(l, "simulation", simulationAPIMethods); @@ -1684,6 +1691,24 @@ int LuaScriptInterface::simulation_decoColor(lua_State * l) return 0; } +int LuaScriptInterface::simulation_floodDeco(lua_State * l) +{ + int x = luaL_checkinteger(l, 1); + int y = luaL_checkinteger(l, 2); + int r = luaL_checkinteger(l, 3); + int g = luaL_checkinteger(l, 4); + int b = luaL_checkinteger(l, 5); + int a = luaL_checkinteger(l, 6); + + if (x < 0 || x >= XRES || y < 0 || y >= YRES) + return luaL_error(l, "coordinates out of range (%d,%d)", x, y); + + // hilariously broken, intersects with console and all Lua graphics + pixel loc = luacon_ren->vid[x + y * WINDOWW]; + luacon_sim->ApplyDecorationFill(luacon_ren, x, y, r, g, b, a, PIXR(loc), PIXG(loc), PIXB(loc)); + return 0; +} + int LuaScriptInterface::simulation_clearSim(lua_State * l) { luacon_controller->ClearSim(); @@ -2244,6 +2269,86 @@ int LuaScriptInterface::simulation_takeSnapshot(lua_State * l) return 0; } +int LuaScriptInterface::simulation_replaceModeFlags(lua_State *l) +{ + if (lua_gettop(l) == 0) + { + lua_pushinteger(l, luacon_controller->GetReplaceModeFlags()); + return 1; + } + unsigned int flags = luaL_checkinteger(l, 1); + if (flags & ~(REPLACE_MODE | SPECIFIC_DELETE)) + return luaL_error(l, "Invalid flags"); + if ((flags & REPLACE_MODE) && (flags & SPECIFIC_DELETE)) + return luaL_error(l, "Cannot set replace mode and specific delete at the same time"); + luacon_controller->SetReplaceModeFlags(flags); + return 0; +} + +int LuaScriptInterface::simulation_listCustomGol(lua_State *l) +{ + int i = 0; + lua_newtable(l); + for (auto &cgol : luacon_sim->GetCustomGol()) + { + lua_newtable(l); + lua_pushstring(l, cgol.nameString.ToUtf8().c_str()); + lua_setfield(l, -2, "name"); + lua_pushstring(l, cgol.ruleString.ToUtf8().c_str()); + lua_setfield(l, -2, "rulestr"); + lua_pushnumber(l, cgol.rule); + lua_setfield(l, -2, "rule"); + lua_pushnumber(l, cgol.colour1); + lua_setfield(l, -2, "color1"); + lua_pushnumber(l, cgol.colour2); + lua_setfield(l, -2, "color2"); + lua_rawseti(l, -2, ++i); + } + return 1; +} + +int LuaScriptInterface::simulation_addCustomGol(lua_State *l) +{ + int rule; + String ruleString; + if (lua_isnumber(l, 1)) + { + rule = luaL_checkinteger(l, 1); + ruleString = SerialiseGOLRule(rule); + rule = ParseGOLString(ruleString); + } + else + { + ruleString = ByteString(luaL_checkstring(l, 1)).FromUtf8(); + rule = ParseGOLString(ruleString); + } + String nameString = ByteString(luaL_checkstring(l, 2)).FromUtf8(); + unsigned int color1 = luaL_checkinteger(l, 3); + unsigned int color2 = luaL_checkinteger(l, 4); + + if (nameString.empty() || !ValidateGOLName(nameString)) + return luaL_error(l, "Invalid name provided"); + if (rule == -1) + return luaL_error(l, "Invalid rule provided"); + if (luacon_sim->GetCustomGOLByRule(rule)) + return luaL_error(l, "This Custom GoL rule already exists"); + + if (!AddCustomGol(ruleString, nameString, color1, color2)) + return luaL_error(l, "Duplicate name, cannot add"); + luacon_model->BuildMenus(); + return 0; +} + +int LuaScriptInterface::simulation_removeCustomGol(lua_State *l) +{ + ByteString nameString = luaL_checkstring(l, 1); + bool removedAny = luacon_model->RemoveCustomGOLType("DEFAULT_PT_LIFECUST_" + nameString); + if (removedAny) + luacon_model->BuildMenus(); + lua_pushboolean(l, removedAny); + return 1; +} + //// Begin Renderer API void LuaScriptInterface::initRendererAPI() diff --git a/src/lua/LuaScriptInterface.h b/src/lua/LuaScriptInterface.h index 2eecd30b9..3f0724950 100644 --- a/src/lua/LuaScriptInterface.h +++ b/src/lua/LuaScriptInterface.h @@ -84,6 +84,7 @@ class LuaScriptInterface: public CommandInterface static int simulation_decoLine(lua_State * l); static int simulation_decoBox(lua_State * l); static int simulation_decoColor(lua_State * l); + static int simulation_floodDeco(lua_State * l); static int simulation_clearSim(lua_State * l); static int simulation_clearRect(lua_State * l); static int simulation_resetTemp(lua_State * l); @@ -112,6 +113,11 @@ class LuaScriptInterface: public CommandInterface static int simulation_framerender(lua_State * l); static int simulation_gspeed(lua_State * l); static int simulation_takeSnapshot(lua_State *l); + static int simulation_replaceModeFlags(lua_State *l); + static int simulation_listCustomGol(lua_State *l); + static int simulation_addCustomGol(lua_State *l); + static int simulation_removeCustomGol(lua_State *l); + //Renderer void initRendererAPI(); diff --git a/src/simulation/GOLString.cpp b/src/simulation/GOLString.cpp index 859bd0ed4..d57d25e4e 100644 --- a/src/simulation/GOLString.cpp +++ b/src/simulation/GOLString.cpp @@ -1,4 +1,5 @@ #include "GOLString.h" +#include "client/Client.h" int ParseGOLString(const String &value) { @@ -93,3 +94,30 @@ String SerialiseGOLRule(int rule) } return golName.Build(); } + +bool AddCustomGol(String ruleString, String nameString, unsigned int highColor, unsigned int lowColor) +{ + auto customGOLTypes = Client::Ref().GetPrefByteStringArray("CustomGOL.Types"); + Json::Value newCustomGOLTypes(Json::arrayValue); + bool nameTaken = false; + for (auto gol : customGOLTypes) + { + auto parts = gol.FromUtf8().PartitionBy(' '); + if (parts.size()) + { + if (parts[0] == nameString) + { + nameTaken = true; + } + } + newCustomGOLTypes.append(gol); + } + if (nameTaken) + return false; + + StringBuilder sb; + sb << nameString << " " << ruleString << " " << highColor << " " << lowColor; + newCustomGOLTypes.append(sb.Build().ToUtf8()); + Client::Ref().SetPref("CustomGOL.Types", newCustomGOLTypes); + return true; +} diff --git a/src/simulation/GOLString.h b/src/simulation/GOLString.h index 78799594b..766a1dc1b 100644 --- a/src/simulation/GOLString.h +++ b/src/simulation/GOLString.h @@ -6,3 +6,4 @@ bool ValidateGOLName(const String &value); int ParseGOLString(const String &value); String SerialiseGOLRule(int rule); +bool AddCustomGol(String ruleString, String nameString, unsigned int highColor, unsigned int lowColor); diff --git a/src/simulation/Simulation.h b/src/simulation/Simulation.h index c32d6e9d3..1d1e5a2ec 100644 --- a/src/simulation/Simulation.h +++ b/src/simulation/Simulation.h @@ -241,6 +241,7 @@ private: public: const CustomGOLData *GetCustomGOLByRule(int rule) const; + const std::vector GetCustomGol() { return customGol; } void SetCustomGOL(std::vector newCustomGol); private: