diff --git a/src/common/platform/Platform.h b/src/common/platform/Platform.h index 610c3b442..9e5475d66 100644 --- a/src/common/platform/Platform.h +++ b/src/common/platform/Platform.h @@ -1,5 +1,6 @@ #pragma once #include "common/String.h" +#include #include #include #include diff --git a/src/lua/CommandInterface.cpp b/src/lua/CommandInterface.cpp index f2d6a47fc..1db0ce68c 100644 --- a/src/lua/CommandInterface.cpp +++ b/src/lua/CommandInterface.cpp @@ -10,12 +10,12 @@ CommandInterface *commandInterface = nullptr; -CommandInterface::CommandInterface(GameController * c, GameModel * m) +CommandInterface::CommandInterface(GameController *newGameController, GameModel *newGameModel) { assert(!commandInterface); commandInterface = this; - this->m = m; - this->c = c; + this->m = newGameModel; + this->c = newGameController; } CommandInterface::~CommandInterface() diff --git a/src/lua/CommandInterface.h b/src/lua/CommandInterface.h index 623471fd1..d0b277f5b 100644 --- a/src/lua/CommandInterface.h +++ b/src/lua/CommandInterface.h @@ -12,7 +12,7 @@ protected: String lastError; GameModel * m; GameController * c; - CommandInterface(GameController * c, GameModel * m); + CommandInterface(GameController *newGameController, GameModel *newGameModel); public: enum LogType { LogError, LogWarning, LogNotice }; @@ -35,7 +35,7 @@ public: String GetLastError(); virtual ~CommandInterface(); - static CommandInterface *Create(GameController * c, GameModel * m); + static CommandInterface *Create(GameController *newGameController, GameModel *newGameModel); }; extern CommandInterface *commandInterface; diff --git a/src/lua/LuaButton.cpp b/src/lua/LuaButton.cpp index 156b710ac..c23d2ba57 100644 --- a/src/lua/LuaButton.cpp +++ b/src/lua/LuaButton.cpp @@ -15,53 +15,53 @@ Luna::RegType LuaButton::methods[] = { {0, 0} }; -LuaButton::LuaButton(lua_State * l) : - LuaComponent(l) +LuaButton::LuaButton(lua_State *L) : + LuaComponent(L) { - int posX = luaL_optinteger(l, 1, 0); - int posY = luaL_optinteger(l, 2, 0); - int sizeX = luaL_optinteger(l, 3, 10); - int sizeY = luaL_optinteger(l, 4, 10); - String text = tpt_lua_optString(l, 5, ""); - String toolTip = tpt_lua_optString(l, 6, ""); + int posX = luaL_optinteger(L, 1, 0); + int posY = luaL_optinteger(L, 2, 0); + int sizeX = luaL_optinteger(L, 3, 10); + int sizeY = luaL_optinteger(L, 4, 10); + String text = tpt_lua_optString(L, 5, ""); + String toolTip = tpt_lua_optString(L, 6, ""); button = new ui::Button(ui::Point(posX, posY), ui::Point(sizeX, sizeY), text, toolTip); component = button; button->SetActionCallback({ [this] { triggerAction(); } }); } -int LuaButton::enabled(lua_State * l) +int LuaButton::enabled(lua_State *L) { - int args = lua_gettop(l); + int args = lua_gettop(L); if(args) { - luaL_checktype(l, 1, LUA_TBOOLEAN); - button->Enabled = lua_toboolean(l, 1); + luaL_checktype(L, 1, LUA_TBOOLEAN); + button->Enabled = lua_toboolean(L, 1); return 0; } else { - lua_pushboolean(l, button->Enabled); + lua_pushboolean(L, button->Enabled); return 1; } } -int LuaButton::action(lua_State * l) +int LuaButton::action(lua_State *L) { - return actionFunction.CheckAndAssignArg1(l); + return actionFunction.CheckAndAssignArg1(L); } -int LuaButton::text(lua_State * l) +int LuaButton::text(lua_State *L) { - int args = lua_gettop(l); + int args = lua_gettop(L); if(args) { - button->SetText(tpt_lua_checkString(l, 1)); + button->SetText(tpt_lua_checkString(L, 1)); return 0; } else { - tpt_lua_pushString(l, button->GetText()); + tpt_lua_pushString(L, button->GetText()); return 1; } } @@ -70,11 +70,11 @@ void LuaButton::triggerAction() { if(actionFunction) { - lua_rawgeti(l, LUA_REGISTRYINDEX, actionFunction); - lua_rawgeti(l, LUA_REGISTRYINDEX, owner_ref); - if (tpt_lua_pcall(l, 1, 0, 0, eventTraitNone)) + lua_rawgeti(L, LUA_REGISTRYINDEX, actionFunction); + lua_rawgeti(L, LUA_REGISTRYINDEX, owner_ref); + if (tpt_lua_pcall(L, 1, 0, 0, eventTraitNone)) { - ci->Log(CommandInterface::LogError, tpt_lua_toString(l, -1)); + ci->Log(CommandInterface::LogError, tpt_lua_toString(L, -1)); } } } diff --git a/src/lua/LuaButton.h b/src/lua/LuaButton.h index bfc65aa06..fa48a16cf 100644 --- a/src/lua/LuaButton.h +++ b/src/lua/LuaButton.h @@ -15,13 +15,13 @@ class LuaButton: public LuaComponent ui::Button * button; LuaComponentCallback actionFunction; void triggerAction(); - int action(lua_State * l); - int text(lua_State * l); - int enabled(lua_State * l); + int action(lua_State *L); + int text(lua_State *L); + int enabled(lua_State *L); public: static const char className[]; static Luna::RegType methods[]; - LuaButton(lua_State * l); + LuaButton(lua_State *L); ~LuaButton(); }; diff --git a/src/lua/LuaBz2.cpp b/src/lua/LuaBz2.cpp new file mode 100644 index 000000000..5d6e35508 --- /dev/null +++ b/src/lua/LuaBz2.cpp @@ -0,0 +1,64 @@ +#include "LuaScriptInterface.h" +#include "bzip2/bz2wrap.h" + +static int compress(lua_State *L) +{ + auto src = tpt_lua_checkByteString(L, 1); + auto maxSize = size_t(luaL_optinteger(L, 2, 0)); + std::vector dest; + auto result = BZ2WCompress(dest, src.data(), src.size(), maxSize); +#define RETURN_ERR(str) lua_pushnil(L); lua_pushinteger(L, int(result)); lua_pushliteral(L, str); return 3 + switch (result) + { + case BZ2WCompressOk: break; + case BZ2WCompressNomem: RETURN_ERR("out of memory"); + case BZ2WCompressLimit: RETURN_ERR("size limit exceeded"); + } +#undef RETURN_ERR + tpt_lua_pushByteString(L, ByteString(dest.begin(), dest.end())); + return 1; +} + +static int decompress(lua_State *L) +{ + auto src = tpt_lua_checkByteString(L, 1); + auto maxSize = size_t(luaL_optinteger(L, 2, 0)); + std::vector dest; + auto result = BZ2WDecompress(dest, src.data(), src.size(), maxSize); +#define RETURN_ERR(str) lua_pushnil(L); lua_pushinteger(L, int(result)); lua_pushliteral(L, str); return 3 + switch (result) + { + case BZ2WDecompressOk: break; + case BZ2WDecompressNomem: RETURN_ERR("out of memory"); + case BZ2WDecompressLimit: RETURN_ERR("size limit exceeded"); + case BZ2WDecompressType: + case BZ2WDecompressBad: + case BZ2WDecompressEof: RETURN_ERR("corrupted stream"); + } +#undef RETURN_ERR + tpt_lua_pushByteString(L, ByteString(dest.begin(), dest.end())); + return 1; +} + +void LuaBz2::Open(lua_State *L) +{ + static const luaL_Reg reg[] = { +#define LFUNC(v) { #v, v } + LFUNC(compress), + LFUNC(decompress), +#undef LFUNC + { NULL, NULL } + }; + lua_newtable(L); + luaL_register(L, NULL, reg); +#define LCONSTAS(k, v) lua_pushinteger(L, int(v)); lua_setfield(L, -2, k) + LCONSTAS("COMPRESS_NOMEM" , BZ2WCompressNomem ); + LCONSTAS("COMPRESS_LIMIT" , BZ2WCompressLimit ); + LCONSTAS("DECOMPRESS_NOMEM", BZ2WDecompressNomem); + LCONSTAS("DECOMPRESS_LIMIT", BZ2WDecompressLimit); + LCONSTAS("DECOMPRESS_TYPE" , BZ2WDecompressType ); + LCONSTAS("DECOMPRESS_BAD" , BZ2WDecompressBad ); + LCONSTAS("DECOMPRESS_EOF" , BZ2WDecompressEof ); +#undef LCONSTAS + lua_setglobal(L, "bz2"); +} diff --git a/src/lua/LuaCheckbox.cpp b/src/lua/LuaCheckbox.cpp index 2c7a02d1a..113906e6d 100644 --- a/src/lua/LuaCheckbox.cpp +++ b/src/lua/LuaCheckbox.cpp @@ -15,51 +15,51 @@ Luna::RegType LuaCheckbox::methods[] = { {0, 0} }; -LuaCheckbox::LuaCheckbox(lua_State * l) : - LuaComponent(l) +LuaCheckbox::LuaCheckbox(lua_State *L) : + LuaComponent(L) { - int posX = luaL_optinteger(l, 1, 0); - int posY = luaL_optinteger(l, 2, 0); - int sizeX = luaL_optinteger(l, 3, 10); - int sizeY = luaL_optinteger(l, 4, 10); - String text = tpt_lua_optString(l, 5, ""); + int posX = luaL_optinteger(L, 1, 0); + int posY = luaL_optinteger(L, 2, 0); + int sizeX = luaL_optinteger(L, 3, 10); + int sizeY = luaL_optinteger(L, 4, 10); + String text = tpt_lua_optString(L, 5, ""); checkbox = new ui::Checkbox(ui::Point(posX, posY), ui::Point(sizeX, sizeY), text, ""); component = checkbox; checkbox->SetActionCallback({ [this] { triggerAction(); } }); } -int LuaCheckbox::checked(lua_State * l) +int LuaCheckbox::checked(lua_State *L) { - int args = lua_gettop(l); + int args = lua_gettop(L); if(args) { - checkbox->SetChecked(lua_toboolean(l, 1)); + checkbox->SetChecked(lua_toboolean(L, 1)); return 0; } else { - lua_pushboolean(l, checkbox->GetChecked()); + lua_pushboolean(L, checkbox->GetChecked()); return 1; } } -int LuaCheckbox::action(lua_State * l) +int LuaCheckbox::action(lua_State *L) { - return actionFunction.CheckAndAssignArg1(l); + return actionFunction.CheckAndAssignArg1(L); } -int LuaCheckbox::text(lua_State * l) +int LuaCheckbox::text(lua_State *L) { - int args = lua_gettop(l); + int args = lua_gettop(L); if(args) { - checkbox->SetText(tpt_lua_checkString(l, 1)); + checkbox->SetText(tpt_lua_checkString(L, 1)); return 0; } else { - tpt_lua_pushString(l, checkbox->GetText()); + tpt_lua_pushString(L, checkbox->GetText()); return 1; } } @@ -68,12 +68,12 @@ void LuaCheckbox::triggerAction() { if(actionFunction) { - lua_rawgeti(l, LUA_REGISTRYINDEX, actionFunction); - lua_rawgeti(l, LUA_REGISTRYINDEX, owner_ref); - lua_pushboolean(l, checkbox->GetChecked()); - if (tpt_lua_pcall(l, 2, 0, 0, eventTraitNone)) + lua_rawgeti(L, LUA_REGISTRYINDEX, actionFunction); + lua_rawgeti(L, LUA_REGISTRYINDEX, owner_ref); + lua_pushboolean(L, checkbox->GetChecked()); + if (tpt_lua_pcall(L, 2, 0, 0, eventTraitNone)) { - ci->Log(CommandInterface::LogError, tpt_lua_toString(l, -1)); + ci->Log(CommandInterface::LogError, tpt_lua_toString(L, -1)); } } } diff --git a/src/lua/LuaCheckbox.h b/src/lua/LuaCheckbox.h index 26fd2e310..8d10ee2c5 100644 --- a/src/lua/LuaCheckbox.h +++ b/src/lua/LuaCheckbox.h @@ -15,13 +15,13 @@ class LuaCheckbox: public LuaComponent ui::Checkbox * checkbox; LuaComponentCallback actionFunction; void triggerAction(); - int action(lua_State * l); - int checked(lua_State * l); - int text(lua_State * l); + int action(lua_State *L); + int checked(lua_State *L); + int text(lua_State *L); public: static const char className[]; static Luna::RegType methods[]; - LuaCheckbox(lua_State * l); + LuaCheckbox(lua_State *L); ~LuaCheckbox(); }; diff --git a/src/lua/LuaCompat.c b/src/lua/LuaCompat.c index 3df2efbb3..53b39aea8 100644 --- a/src/lua/LuaCompat.c +++ b/src/lua/LuaCompat.c @@ -2,15 +2,13 @@ #if LUA_VERSION_NUM >= 502 // Implement missing luaL_typerror function -int luaL_typerror (lua_State *L, int narg, const char *tname) +int luaL_typerror(lua_State *L, int narg, const char *tname) { const char *msg = lua_pushfstring(L, "%s expected, got %s", tname, luaL_typename(L, narg)); return luaL_argerror(L, narg, msg); } -void luaL_register (lua_State *L, - const char *libname, - const luaL_Reg *l) +void luaL_register(lua_State *L, const char *libname, const luaL_Reg *l) { if (libname) { @@ -20,18 +18,7 @@ void luaL_register (lua_State *L, } luaL_setfuncs(L, l, 0); } - -void tpt_lua_setmainthread(lua_State *L) -{ -} - -void tpt_lua_getmainthread(lua_State *L) -{ - lua_rawgeti(L, LUA_REGISTRYINDEX, LUA_RIDX_MAINTHREAD); -} - #else - # ifndef lua_pushglobaltable // * Thank you moonjit // Implement function added in lua 5.2 that we now use void lua_pushglobaltable(lua_State *L) @@ -39,42 +26,4 @@ void lua_pushglobaltable(lua_State *L) lua_pushvalue(L, LUA_GLOBALSINDEX); } # endif - -void tpt_lua_setmainthread(lua_State *L) -{ - lua_pushthread(L); - lua_setfield(L, LUA_REGISTRYINDEX, "tpt_lua_mainthread"); -} - -void tpt_lua_getmainthread(lua_State *L) -{ - lua_getfield(L, LUA_REGISTRYINDEX, "tpt_lua_mainthread"); -} - #endif - -// Useful helper function, mainly used for logging -int luaL_tostring(lua_State *L, int n) -{ - luaL_checkany(L, n); - switch (lua_type(L, n)) - { - case LUA_TNUMBER: - lua_tostring(L, n); - lua_pushvalue(L, n); - break; - case LUA_TSTRING: - lua_pushvalue(L, n); - break; - case LUA_TBOOLEAN: - lua_pushstring(L, (lua_toboolean(L, n) ? "true" : "false")); - break; - case LUA_TNIL: - lua_pushliteral(L, "nil"); - break; - default: - lua_pushfstring(L, "%s: %p", luaL_typename(L, n), lua_topointer(L, n)); - break; - } - return 1; -} diff --git a/src/lua/LuaCompat.h b/src/lua/LuaCompat.h index 5fd87bc1a..e4d2df3b4 100644 --- a/src/lua/LuaCompat.h +++ b/src/lua/LuaCompat.h @@ -9,9 +9,6 @@ extern "C" #include #include -LUALIB_API void tpt_lua_setmainthread(lua_State *L); -LUALIB_API void tpt_lua_getmainthread(lua_State *L); - #if LUA_VERSION_NUM >= 502 void luaL_register(lua_State *L, const char *libname, const luaL_Reg *l); #define lua_strlen(L,i) lua_rawlen(L, (i)) @@ -25,7 +22,6 @@ LUALIB_API int (luaL_typerror) (lua_State *L, int narg, const char *tname); LUALIB_API void (lua_pushglobaltable) (lua_State *L); # endif #endif -int luaL_tostring(lua_State *L, int n); #ifdef __cplusplus } diff --git a/src/lua/LuaComponent.cpp b/src/lua/LuaComponent.cpp index 65293f3a8..496055b91 100644 --- a/src/lua/LuaComponent.cpp +++ b/src/lua/LuaComponent.cpp @@ -4,72 +4,72 @@ #include "gui/interface/Component.h" #include "gui/interface/Window.h" -int LuaComponentCallback::CheckAndAssignArg1(lua_State *l) +int LuaComponentCallback::CheckAndAssignArg1(lua_State *L) { - if (lua_type(l, 1) != LUA_TNIL) + if (lua_type(L, 1) != LUA_TNIL) { - luaL_checktype(l, 1, LUA_TFUNCTION); + luaL_checktype(L, 1, LUA_TFUNCTION); } - LuaSmartRef::Assign(l, 1); + LuaSmartRef::Assign(L, 1); return 0; } -LuaComponent::LuaComponent(lua_State * l) : component(nullptr), owner_ref(LUA_REFNIL) +LuaComponent::LuaComponent(lua_State *L) : component(nullptr), owner_ref(LUA_REFNIL) { - this->l = l; // I don't get how this doesn't cause crashes later on + this->L = L; // I don't get how this doesn't cause crashes later on ci = static_cast(commandInterface); } -int LuaComponent::position(lua_State * l) +int LuaComponent::position(lua_State *L) { - int args = lua_gettop(l); + int args = lua_gettop(L); if(args) { - luaL_checktype(l, 1, LUA_TNUMBER); - luaL_checktype(l, 2, LUA_TNUMBER); - component->Position = ui::Point(lua_tointeger(l, 1), lua_tointeger(l, 2)); + luaL_checktype(L, 1, LUA_TNUMBER); + luaL_checktype(L, 2, LUA_TNUMBER); + component->Position = ui::Point(lua_tointeger(L, 1), lua_tointeger(L, 2)); return 0; } else { - lua_pushinteger(l, component->Position.X); - lua_pushinteger(l, component->Position.Y); + lua_pushinteger(L, component->Position.X); + lua_pushinteger(L, component->Position.Y); return 2; } } -int LuaComponent::size(lua_State * l) +int LuaComponent::size(lua_State *L) { - int args = lua_gettop(l); + int args = lua_gettop(L); if(args) { - luaL_checktype(l, 1, LUA_TNUMBER); - luaL_checktype(l, 2, LUA_TNUMBER); - component->Size = ui::Point(lua_tointeger(l, 1), lua_tointeger(l, 2)); + luaL_checktype(L, 1, LUA_TNUMBER); + luaL_checktype(L, 2, LUA_TNUMBER); + component->Size = ui::Point(lua_tointeger(L, 1), lua_tointeger(L, 2)); component->Invalidate(); return 0; } else { - lua_pushinteger(l, component->Size.X); - lua_pushinteger(l, component->Size.Y); + lua_pushinteger(L, component->Size.X); + lua_pushinteger(L, component->Size.Y); return 2; } } -int LuaComponent::visible(lua_State * l) +int LuaComponent::visible(lua_State *L) { - int args = lua_gettop(l); + int args = lua_gettop(L); if(args) { - luaL_checktype(l, 1, LUA_TBOOLEAN); - component->Visible = lua_toboolean(l, 1); + luaL_checktype(L, 1, LUA_TBOOLEAN); + component->Visible = lua_toboolean(L, 1); return 0; } else { - lua_pushboolean(l, component->Visible); + lua_pushboolean(L, component->Visible); return 1; } } diff --git a/src/lua/LuaComponent.h b/src/lua/LuaComponent.h index 09e67901a..f2b556e27 100644 --- a/src/lua/LuaComponent.h +++ b/src/lua/LuaComponent.h @@ -15,25 +15,25 @@ class LuaComponentCallback : public LuaSmartRef { public: using LuaSmartRef::LuaSmartRef; - int CheckAndAssignArg1(lua_State *l); + int CheckAndAssignArg1(lua_State *L); }; class LuaComponent { protected: ui::Component * component; - lua_State * l; + lua_State *L; LuaWindow * parent = nullptr; - int position(lua_State * l); - int size(lua_State * l); - int visible(lua_State * l); + int position(lua_State *L); + int size(lua_State *L); + int visible(lua_State *L); public: LuaScriptInterface * ci; int owner_ref; ui::Component * GetComponent() { return component; } void SetParentWindow(LuaWindow *parent) { this->parent = parent; } - LuaComponent(lua_State * l); + LuaComponent(lua_State *L); ~LuaComponent(); }; diff --git a/src/lua/LuaElements.cpp b/src/lua/LuaElements.cpp new file mode 100644 index 000000000..66612a936 --- /dev/null +++ b/src/lua/LuaElements.cpp @@ -0,0 +1,900 @@ +#include "LuaScriptInterface.h" +#include "gui/game/GameModel.h" +#include "simulation/ElementClasses.h" +#include "simulation/ElementCommon.h" +#include "simulation/SimulationData.h" +#include + +static void getDefaultProperties(lua_State *L, int id) +{ + auto &sd = SimulationData::CRef(); + auto &elements = sd.elements; + lua_newtable(L); + for (auto &prop : Particle::GetProperties()) + { + auto propertyAddress = reinterpret_cast((reinterpret_cast(&elements[id].DefaultProperties)) + prop.Offset); + tpt_lua_pushByteString(L, prop.Name); + LuaGetProperty(L, prop, propertyAddress); + lua_settable(L, -3); + } + for (auto &alias : Particle::GetPropertyAliases()) + { + tpt_lua_pushByteString(L, alias.from); + tpt_lua_pushByteString(L, alias.to); + lua_gettable(L, -3); + lua_settable(L, -3); + } +} + +static void 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()) + { + tpt_lua_pushByteString(L, prop.Name); + lua_gettable(L, stackPos); + if (lua_type(L, -1) == LUA_TNIL) + { + for (auto &alias : Particle::GetPropertyAliases()) + { + if (alias.to == prop.Name) + { + lua_pop(L, 1); + tpt_lua_pushByteString(L, alias.from); + lua_gettable(L, stackPos); + } + } + } + if (lua_type(L, -1) != LUA_TNIL) + { + auto propertyAddress = reinterpret_cast((reinterpret_cast(&elements[id].DefaultProperties)) + prop.Offset); + LuaSetProperty(L, prop, propertyAddress, -1); + } + lua_pop(L, 1); + } + } +} + +static void manageElementIdentifier(lua_State *L, int id, bool add) +{ + auto &sd = SimulationData::CRef(); + auto &elements = sd.elements; + if (elements[id].Enabled) + { + lua_getglobal(L, "elements"); + tpt_lua_pushByteString(L, elements[id].Identifier); + if (add) + { + lua_pushinteger(L, id); + } + else + { + lua_pushnil(L); + } + lua_settable(L, -3); + if (elements[id].Identifier.BeginsWith("DEFAULT_PT_")) + { + ByteString realIdentifier = ByteString::Build("DEFAULT_PT_", elements[id].Name.ToUtf8()); + if (id != 0 && id != PT_NBHL && id != PT_NWHL && elements[id].Identifier != realIdentifier) + { + tpt_lua_pushByteString(L, realIdentifier); + if (add) + { + lua_pushinteger(L, id); + } + else + { + lua_pushnil(L); + } + lua_settable(L, -3); + } + } + lua_pop(L, 1); + } +} + +static int luaUpdateWrapper(UPDATE_FUNC_ARGS) +{ + if (!sim->useLuaCallbacks) + { + return 0; + } + auto *lsi = static_cast(commandInterface); + auto &builtinElements = GetElements(); + auto *builtinUpdate = builtinElements[parts[i].type].Update; + auto &customElements = lsi->customElements; + if (builtinUpdate && customElements[parts[i].type].updateMode == UPDATE_AFTER) + { + if (builtinUpdate(UPDATE_FUNC_SUBCALL_ARGS)) + return 1; + x = (int)(parts[i].x+0.5f); + y = (int)(parts[i].y+0.5f); + } + if (customElements[parts[i].type].update) + { + int retval = 0, callret; + lua_rawgeti(lsi->L, LUA_REGISTRYINDEX, customElements[parts[i].type].update); + lua_pushinteger(lsi->L, i); + lua_pushinteger(lsi->L, x); + lua_pushinteger(lsi->L, y); + lua_pushinteger(lsi->L, surround_space); + lua_pushinteger(lsi->L, nt); + callret = tpt_lua_pcall(lsi->L, 5, 1, 0, eventTraitSimRng); + if (callret) + lsi->Log(CommandInterface::LogError, LuaGetError()); + if(lua_isboolean(lsi->L, -1)){ + retval = lua_toboolean(lsi->L, -1); + } + lua_pop(lsi->L, 1); + if (retval) + { + return 1; + } + x = (int)(parts[i].x+0.5f); + y = (int)(parts[i].y+0.5f); + } + if (builtinUpdate && customElements[parts[i].type].updateMode == UPDATE_BEFORE) + { + if (builtinUpdate(UPDATE_FUNC_SUBCALL_ARGS)) + return 1; + x = (int)(parts[i].x+0.5f); + y = (int)(parts[i].y+0.5f); + } + return 0; +} + +static int luaGraphicsWrapper(GRAPHICS_FUNC_ARGS) +{ + if (!gfctx.sim->useLuaCallbacks) + { + return Element::defaultGraphics(GRAPHICS_FUNC_SUBCALL_ARGS); + } + auto *lsi = static_cast(commandInterface); + auto &customElements = lsi->customElements; + auto *sim = lsi->sim; + if (customElements[cpart->type].graphics) + { + auto *pipeSubcallWcpart = gfctx.pipeSubcallCpart ? sim->parts + (gfctx.pipeSubcallCpart - gfctx.sim->parts) : nullptr; + if (pipeSubcallWcpart) + { + std::swap(*pipeSubcallWcpart, *gfctx.pipeSubcallTpart); + cpart = pipeSubcallWcpart; + } + int cache = 0, callret; + int i = cpart - gfctx.sim->parts; // pointer arithmetic be like + lua_rawgeti(lsi->L, LUA_REGISTRYINDEX, customElements[cpart->type].graphics); + lua_pushinteger(lsi->L, i); + lua_pushinteger(lsi->L, *colr); + lua_pushinteger(lsi->L, *colg); + lua_pushinteger(lsi->L, *colb); + callret = tpt_lua_pcall(lsi->L, 4, 10, 0, eventTraitSimGraphics); + if (callret) + { + lsi->Log(CommandInterface::LogError, LuaGetError()); + lua_pop(lsi->L, 1); + } + else + { + bool valid = true; + for (int i = -10; i < 0; i++) + if (!lua_isnumber(lsi->L, i) && !lua_isnil(lsi->L, i)) + { + valid = false; + break; + } + if (valid) + { + cache = luaL_optint(lsi->L, -10, 0); + *pixel_mode = luaL_optint(lsi->L, -9, *pixel_mode); + *cola = luaL_optint(lsi->L, -8, *cola); + *colr = luaL_optint(lsi->L, -7, *colr); + *colg = luaL_optint(lsi->L, -6, *colg); + *colb = luaL_optint(lsi->L, -5, *colb); + *firea = luaL_optint(lsi->L, -4, *firea); + *firer = luaL_optint(lsi->L, -3, *firer); + *fireg = luaL_optint(lsi->L, -2, *fireg); + *fireb = luaL_optint(lsi->L, -1, *fireb); + } + lua_pop(lsi->L, 10); + } + if (pipeSubcallWcpart) + { + std::swap(*pipeSubcallWcpart, *gfctx.pipeSubcallTpart); + } + return cache; + } + return 0; +} + +static void luaCreateWrapper(ELEMENT_CREATE_FUNC_ARGS) +{ + if (!sim->useLuaCallbacks) + { + return; + } + auto *lsi = static_cast(commandInterface); + auto &customElements = lsi->customElements; + if (customElements[sim->parts[i].type].create) + { + lua_rawgeti(lsi->L, LUA_REGISTRYINDEX, customElements[sim->parts[i].type].create); + lua_pushinteger(lsi->L, i); + lua_pushinteger(lsi->L, x); + lua_pushinteger(lsi->L, y); + lua_pushinteger(lsi->L, t); + lua_pushinteger(lsi->L, v); + if (tpt_lua_pcall(lsi->L, 5, 0, 0, eventTraitSimRng)) + { + lsi->Log(CommandInterface::LogError, "In create func: " + LuaGetError()); + lua_pop(lsi->L, 1); + } + } +} + +static bool luaCreateAllowedWrapper(ELEMENT_CREATE_ALLOWED_FUNC_ARGS) +{ + if (!sim->useLuaCallbacks) + { + // Nothing really bad can happen, no callbacks are allowed anyway. The worst thing that can happen + // is that a well-crafted save looks odd in previews because it has multiple Element::defaultGraphics-rendered + // instances of something that should be limited to one instance. + return 1; + } + auto *lsi = static_cast(commandInterface); + auto &customElements = lsi->customElements; + bool ret = false; + if (customElements[t].createAllowed) + { + lua_rawgeti(lsi->L, LUA_REGISTRYINDEX, customElements[t].createAllowed); + lua_pushinteger(lsi->L, i); + lua_pushinteger(lsi->L, x); + lua_pushinteger(lsi->L, y); + lua_pushinteger(lsi->L, t); + if (tpt_lua_pcall(lsi->L, 4, 1, 0, eventTraitSimRng)) + { + lsi->Log(CommandInterface::LogError, "In create allowed: " + LuaGetError()); + lua_pop(lsi->L, 1); + } + else + { + if (lua_isboolean(lsi->L, -1)) + ret = lua_toboolean(lsi->L, -1); + lua_pop(lsi->L, 1); + } + } + return ret; +} + +static void luaChangeTypeWrapper(ELEMENT_CHANGETYPE_FUNC_ARGS) +{ + if (!sim->useLuaCallbacks) + { + return; + } + auto *lsi = static_cast(commandInterface); + auto &customElements = lsi->customElements; + if (customElements[sim->parts[i].type].changeType) + { + lua_rawgeti(lsi->L, LUA_REGISTRYINDEX, customElements[sim->parts[i].type].changeType); + lua_pushinteger(lsi->L, i); + lua_pushinteger(lsi->L, x); + lua_pushinteger(lsi->L, y); + lua_pushinteger(lsi->L, from); + lua_pushinteger(lsi->L, to); + if (tpt_lua_pcall(lsi->L, 5, 0, 0, eventTraitSimRng)) + { + lsi->Log(CommandInterface::LogError, "In change type: " + LuaGetError()); + lua_pop(lsi->L, 1); + } + } +} + +static bool luaCtypeDrawWrapper(CTYPEDRAW_FUNC_ARGS) +{ + if (!sim->useLuaCallbacks) + { + return false; + } + auto *lsi = static_cast(commandInterface); + auto &customElements = lsi->customElements; + bool ret = false; + if (customElements[sim->parts[i].type].ctypeDraw) + { + lua_rawgeti(lsi->L, LUA_REGISTRYINDEX, customElements[sim->parts[i].type].ctypeDraw); + lua_pushinteger(lsi->L, i); + lua_pushinteger(lsi->L, t); + lua_pushinteger(lsi->L, v); + if (tpt_lua_pcall(lsi->L, 3, 1, 0, eventTraitSimRng)) + { + lsi->Log(CommandInterface::LogError, LuaGetError()); + lua_pop(lsi->L, 1); + } + else + { + if (lua_isboolean(lsi->L, -1)) + ret = lua_toboolean(lsi->L, -1); + lua_pop(lsi->L, 1); + } + } + return ret; +} + +static int allocate(lua_State *L) +{ + auto *lsi = static_cast(commandInterface); + luaL_checktype(L, 1, LUA_TSTRING); + luaL_checktype(L, 2, LUA_TSTRING); + auto group = tpt_lua_toByteString(L, 1).ToUpper(); + auto id = tpt_lua_toByteString(L, 2).ToUpper(); + + if (id.Contains("_")) + { + return luaL_error(L, "The element name may not contain '_'."); + } + if (group.Contains("_")) + { + return luaL_error(L, "The group name may not contain '_'."); + } + if (group == "DEFAULT") + { + return luaL_error(L, "You cannot create elements in the 'DEFAULT' group."); + } + + auto identifier = group + "_PT_" + id; + + int newID = -1; + { + auto &sd = SimulationData::CRef(); + auto &elements = sd.elements; + for(int i = 0; i < PT_NUM; i++) + { + if(elements[i].Enabled && ByteString(elements[i].Identifier) == identifier) + return luaL_error(L, "Element identifier already in use"); + } + + // 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 (!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) + { + { + 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); + lua_pushinteger(L, newID); + lua_settable(L, -3); + lua_pop(L, 1); + + for (auto elem = 0; elem < PT_NUM; ++elem) + { + lsi->customCanMove[elem][newID] = 0; + lsi->customCanMove[newID][elem] = 0; + } + lsi->gameModel->BuildMenus(); + lsi->InitCustomCanMove(); + } + + lua_pushinteger(L, newID); + return 1; +} + +static int element(lua_State *L) +{ + auto &builtinElements = GetElements(); + auto *lsi = static_cast(commandInterface); + auto &customElements = lsi->customElements; + int id = luaL_checkinteger(L, 1); + if (!SimulationData::CRef().IsElementOrNone(id)) + { + return luaL_error(L, "Invalid element"); + } + + if (lua_gettop(L) > 1) + { + { + 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()) + { + 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) + { + customElements[id].update.Assign(L, -1); + customElements[id].updateMode = UPDATE_AFTER; + elements[id].Update = luaUpdateWrapper; + } + else if (lua_type(L, -1) == LUA_TBOOLEAN && !lua_toboolean(L, -1)) + { + customElements[id].update.Clear(); + customElements[id].updateMode = UPDATE_AFTER; + elements[id].Update = builtinElements[id].Update; + } + lua_pop(L, 1); + + lua_getfield(L, -1, "Graphics"); + if (lua_type(L, -1) == LUA_TFUNCTION) + { + customElements[id].graphics.Assign(L, -1); + elements[id].Graphics = luaGraphicsWrapper; + } + else if (lua_type(L, -1) == LUA_TBOOLEAN && !lua_toboolean(L, -1)) + { + customElements[id].graphics.Clear(); + elements[id].Graphics = builtinElements[id].Graphics; + } + lua_pop(L, 1); + + lua_getfield(L, -1, "Create"); + if (lua_type(L, -1) == LUA_TFUNCTION) + { + customElements[id].create.Assign(L, -1); + elements[id].Create = luaCreateWrapper; + } + else if (lua_type(L, -1) == LUA_TBOOLEAN && !lua_toboolean(L, -1)) + { + customElements[id].create.Clear(); + elements[id].Create = builtinElements[id].Create; + } + lua_pop(L, 1); + + lua_getfield(L, -1, "CreateAllowed"); + if (lua_type(L, -1) == LUA_TFUNCTION) + { + customElements[id].createAllowed.Assign(L, -1); + elements[id].CreateAllowed = luaCreateAllowedWrapper; + } + else if (lua_type(L, -1) == LUA_TBOOLEAN && !lua_toboolean(L, -1)) + { + customElements[id].createAllowed.Clear(); + elements[id].CreateAllowed = builtinElements[id].CreateAllowed; + } + lua_pop(L, 1); + + lua_getfield(L, -1, "ChangeType"); + if (lua_type(L, -1) == LUA_TFUNCTION) + { + customElements[id].changeType.Assign(L, -1); + elements[id].ChangeType = luaChangeTypeWrapper; + } + else if (lua_type(L, -1) == LUA_TBOOLEAN && !lua_toboolean(L, -1)) + { + customElements[id].changeType.Clear(); + elements[id].ChangeType = builtinElements[id].ChangeType; + } + lua_pop(L, 1); + + lua_getfield(L, -1, "CtypeDraw"); + if (lua_type(L, -1) == LUA_TFUNCTION) + { + customElements[id].ctypeDraw.Assign(L, -1); + elements[id].CtypeDraw = luaCtypeDrawWrapper; + } + else if (lua_type(L, -1) == LUA_TBOOLEAN && !lua_toboolean(L, -1)) + { + customElements[id].ctypeDraw.Clear(); + elements[id].CtypeDraw = builtinElements[id].CtypeDraw; + } + lua_pop(L, 1); + + lua_getfield(L, -1, "DefaultProperties"); + setDefaultProperties(L, id, lua_gettop(L)); + lua_pop(L, 1); + + sd.graphicscache[id].isready = 0; + } + lsi->gameModel->BuildMenus(); + lsi->InitCustomCanMove(); + + return 0; + } + else + { + auto &sd = SimulationData::CRef(); + auto &elements = sd.elements; + //Write values from native data to a table + lua_newtable(L); + for (auto &prop : Element::GetProperties()) + { + tpt_lua_pushByteString(L, prop.Name); + intptr_t propertyAddress = (intptr_t)(((unsigned char*)&elements[id]) + prop.Offset); + LuaGetProperty(L, prop, propertyAddress); + lua_settable(L, -3); + } + + tpt_lua_pushByteString(L, elements[id].Identifier); + lua_setfield(L, -2, "Identifier"); + + getDefaultProperties(L, id); + lua_setfield(L, -2, "DefaultProperties"); + + return 1; + } +} + +static int property(lua_State *L) +{ + auto &builtinElements = GetElements(); + auto *lsi = static_cast(commandInterface); + auto &customElements = lsi->customElements; + int id = luaL_checkinteger(L, 1); + if (!SimulationData::CRef().IsElementOrNone(id)) + { + return luaL_error(L, "Invalid element"); + } + ByteString propertyName = tpt_lua_checkByteString(L, 2); + + auto &properties = Element::GetProperties(); + auto prop = std::find_if(properties.begin(), properties.end(), [&propertyName](StructProperty const &p) { + return p.Name == propertyName; + }); + + if (lua_gettop(L) > 2) + { + auto &sd = SimulationData::Ref(); + std::unique_lock lk(sd.elementGraphicsMx); + auto &elements = sd.elements; + if (prop != properties.end()) + { + if (lua_type(L, 3) != LUA_TNIL) + { + if (prop->Type == StructProperty::TransitionType) + { + int type = luaL_checkinteger(L, 3); + if (!SimulationData::CRef().IsElementOrNone(type) && type != NT && type != ST) + { + return luaL_error(L, "Invalid element"); + } + } + intptr_t propertyAddress = (intptr_t)(((unsigned char*)&elements[id]) + prop->Offset); + manageElementIdentifier(L, id, false); + LuaSetProperty(L, *prop, propertyAddress, 3); + manageElementIdentifier(L, id, true); + lsi->gameModel->BuildMenus(); + lsi->InitCustomCanMove(); + sd.graphicscache[id].isready = 0; + } + } + else if (propertyName == "Update") + { + if (lua_type(L, 3) == LUA_TFUNCTION) + { + switch (luaL_optint(L, 4, 0)) + { + case 2: + customElements[id].updateMode = UPDATE_BEFORE; + break; + + case 1: + customElements[id].updateMode = UPDATE_REPLACE; + break; + + default: + customElements[id].updateMode = UPDATE_AFTER; + break; + } + customElements[id].update.Assign(L, 3); + elements[id].Update = luaUpdateWrapper; + } + else if (lua_type(L, 3) == LUA_TBOOLEAN && !lua_toboolean(L, 3)) + { + customElements[id].update.Clear(); + customElements[id].updateMode = UPDATE_AFTER; + elements[id].Update = builtinElements[id].Update; + } + } + else if (propertyName == "Graphics") + { + if (lua_type(L, 3) == LUA_TFUNCTION) + { + customElements[id].graphics.Assign(L, 3); + elements[id].Graphics = luaGraphicsWrapper; + } + else if (lua_type(L, 3) == LUA_TBOOLEAN && !lua_toboolean(L, 3)) + { + customElements[id].graphics.Clear(); + elements[id].Graphics = builtinElements[id].Graphics; + } + sd.graphicscache[id].isready = 0; + } + else if (propertyName == "Create") + { + if (lua_type(L, 3) == LUA_TFUNCTION) + { + customElements[id].create.Assign(L, 3); + elements[id].Create = luaCreateWrapper; + } + else if (lua_type(L, 3) == LUA_TBOOLEAN && !lua_toboolean(L, 3)) + { + customElements[id].create.Clear(); + elements[id].Create = builtinElements[id].Create; + } + } + else if (propertyName == "CreateAllowed") + { + if (lua_type(L, 3) == LUA_TFUNCTION) + { + customElements[id].createAllowed.Assign(L, 3); + elements[id].CreateAllowed = luaCreateAllowedWrapper; + } + else if (lua_type(L, 3) == LUA_TBOOLEAN && !lua_toboolean(L, 3)) + { + customElements[id].createAllowed.Clear(); + elements[id].CreateAllowed = builtinElements[id].CreateAllowed; + } + } + else if (propertyName == "ChangeType") + { + if (lua_type(L, 3) == LUA_TFUNCTION) + { + customElements[id].changeType.Assign(L, 3); + elements[id].ChangeType = luaChangeTypeWrapper; + } + else if (lua_type(L, 3) == LUA_TBOOLEAN && !lua_toboolean(L, 3)) + { + customElements[id].changeType.Clear(); + elements[id].ChangeType = builtinElements[id].ChangeType; + } + } + else if (propertyName == "CtypeDraw") + { + if (lua_type(L, 3) == LUA_TFUNCTION) + { + customElements[id].ctypeDraw.Assign(L, 3); + elements[id].CtypeDraw = luaCtypeDrawWrapper; + } + else if (lua_type(L, 3) == LUA_TBOOLEAN && !lua_toboolean(L, 3)) + { + customElements[id].ctypeDraw.Clear(); + elements[id].CtypeDraw = builtinElements[id].CtypeDraw; + } + } + else if (propertyName == "DefaultProperties") + { + setDefaultProperties(L, id, 3); + } + else + { + return luaL_error(L, "Invalid element property"); + } + return 0; + } + else + { + auto &sd = SimulationData::CRef(); + auto &elements = sd.elements; + if (prop != properties.end()) + { + 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, elements[id].Identifier); + return 1; + } + else if (propertyName == "DefaultProperties") + { + getDefaultProperties(L, id); + return 1; + } + else + { + return luaL_error(L, "Invalid element property"); + } + } +} + +static int ffree(lua_State *L) +{ + int id = luaL_checkinteger(L, 1); + ByteString identifier; + { + 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"); + } + } + + { + auto &sd = SimulationData::Ref(); + std::unique_lock lk(sd.elementGraphicsMx); + sd.elements[id].Enabled = false; + } + auto *lsi = static_cast(commandInterface); + lsi->gameModel->BuildMenus(); + + lua_getglobal(L, "elements"); + tpt_lua_pushByteString(L, identifier); + lua_pushnil(L); + lua_settable(L, -3); + lua_pop(L, 1); + + return 0; +} + +static int exists(lua_State *L) +{ + auto &sd = SimulationData::CRef(); + lua_pushboolean(L, sd.IsElement(luaL_checkinteger(L, 1))); + return 1; +} + +static int loadDefault(lua_State *L) +{ + auto &sd = SimulationData::Ref(); + std::unique_lock lk(sd.elementGraphicsMx); + auto &elements = sd.elements; + auto &builtinElements = GetElements(); + auto *lsi = static_cast(commandInterface); + { + auto loadDefaultOne = [L, &elements, &builtinElements](int id) { + lua_getglobal(L, "elements"); + ByteString identifier = elements[id].Identifier; + tpt_lua_pushByteString(L, identifier); + lua_pushnil(L); + lua_settable(L, -3); + + manageElementIdentifier(L, id, false); + if (id < (int)builtinElements.size()) + elements[id] = builtinElements[id]; + else + elements[id] = Element(); + manageElementIdentifier(L, id, true); + + tpt_lua_pushByteString(L, identifier); + lua_pushinteger(L, id); + lua_settable(L, -3); + lua_pop(L, 1); + }; + 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"); + loadDefaultOne(id); + } + else + { + for (int i = 0; i < PT_NUM; i++) + { + loadDefaultOne(i); + } + } + } + + lsi->gameModel->BuildMenus(); + for (auto moving = 0; moving < PT_NUM; ++moving) + { + for (auto into = 0; into < PT_NUM; ++into) + { + lsi->customCanMove[moving][into] = 0; + } + } + lsi->InitCustomCanMove(); + sd.graphicscache = std::array(); + return 0; +} + +static int getByName(lua_State *L) +{ + lua_pushinteger(L, SimulationData::CRef().GetParticleType(tpt_lua_checkByteString(L, 1))); + return 1; +} + +void LuaElements::Open(lua_State *L) +{ + static const luaL_Reg reg[] = { +#define LFUNC(v) { #v, v } + LFUNC(allocate), + LFUNC(element), + LFUNC(property), + LFUNC(exists), + LFUNC(loadDefault), + LFUNC(getByName), +#undef LFUNC + { "free", ffree }, + { NULL, NULL } + }; + lua_newtable(L); + luaL_register(L, NULL, reg); +#define LCONST(v) lua_pushinteger(L, int(v)); lua_setfield(L, -2, #v) + LCONST(TYPE_PART); + LCONST(TYPE_LIQUID); + LCONST(TYPE_SOLID); + LCONST(TYPE_GAS); + LCONST(TYPE_ENERGY); + LCONST(PROP_CONDUCTS); + LCONST(PROP_BLACK); + LCONST(PROP_NEUTPENETRATE); + LCONST(PROP_NEUTABSORB); + LCONST(PROP_NEUTPASS); + LCONST(PROP_DEADLY); + LCONST(PROP_HOT_GLOW); + LCONST(PROP_LIFE); + LCONST(PROP_RADIOACTIVE); + LCONST(PROP_LIFE_DEC); + LCONST(PROP_LIFE_KILL); + LCONST(PROP_LIFE_KILL_DEC); + LCONST(PROP_SPARKSETTLE); + LCONST(PROP_NOAMBHEAT); + LCONST(PROP_NOCTYPEDRAW); + LCONST(SC_WALL); + LCONST(SC_ELEC); + LCONST(SC_POWERED); + LCONST(SC_SENSOR); + LCONST(SC_FORCE); + LCONST(SC_EXPLOSIVE); + LCONST(SC_GAS); + LCONST(SC_LIQUID); + LCONST(SC_POWDERS); + LCONST(SC_SOLIDS); + LCONST(SC_NUCLEAR); + LCONST(SC_SPECIAL); + LCONST(SC_LIFE); + LCONST(SC_TOOL); + LCONST(SC_DECO); + LCONST(UPDATE_AFTER); + LCONST(UPDATE_REPLACE); + LCONST(UPDATE_BEFORE); + LCONST(NUM_UPDATEMODES); +#undef LCONST + lua_pushvalue(L, -1); + lua_setglobal(L, "elements"); + lua_setglobal(L, "elem"); + for (int i = 0; i < PT_NUM; i++) + { + manageElementIdentifier(L, i, true); + } +} diff --git a/src/lua/LuaEvent.cpp b/src/lua/LuaEvent.cpp new file mode 100644 index 000000000..3d2a5b750 --- /dev/null +++ b/src/lua/LuaEvent.cpp @@ -0,0 +1,86 @@ +#include "LuaScriptInterface.h" +#include "common/VariantIndex.h" +#include "PowderToySDL.h" + +static int fregister(lua_State *L) +{ + auto *lsi = static_cast(commandInterface); + int eventType = luaL_checkinteger(L, 1); + luaL_checktype(L, 2, LUA_TFUNCTION); + if (eventType < 0 || eventType >= int(lsi->gameControllerEventHandlers.size())) + { + luaL_error(L, "Invalid event type: %i", lua_tointeger(L, 1)); + } + lsi->gameControllerEventHandlers[eventType].Push(L); + auto length = lua_objlen(L, -1); + lua_pushvalue(L, 2); + lua_rawseti(L, -2, length + 1); + lua_pushvalue(L, 2); + return 1; +} + +static int unregister(lua_State *L) +{ + auto *lsi = static_cast(commandInterface); + int eventType = luaL_checkinteger(L, 1); + luaL_checktype(L, 2, LUA_TFUNCTION); + if (eventType < 0 || eventType >= int(lsi->gameControllerEventHandlers.size())) + { + luaL_error(L, "Invalid event type: %i", lua_tointeger(L, 1)); + } + lsi->gameControllerEventHandlers[eventType].Push(L); + auto length = lua_objlen(L, -1); + int skip = 0; + for (auto i = 1U; i <= length; ++i) + { + lua_rawgeti(L, -1, i); + if (!skip && lua_equal(L, -1, 2)) + { + skip = 1; + } + lua_pop(L, 1); + lua_rawgeti(L, -1, i + skip); + lua_rawseti(L, -2, i); + } + return 0; +} + +static int getModifiers(lua_State *L) +{ + lua_pushnumber(L, GetModifiers()); + return 1; +} + +void LuaEvent::Open(lua_State *L) +{ + static const luaL_Reg reg[] = { +#define LFUNC(v) { #v, v } + LFUNC(unregister), + LFUNC(getModifiers), +#undef LFUNC + { "register", fregister }, + { NULL, NULL } + }; + lua_newtable(L); + luaL_register(L, NULL, reg); +#define LVICONST(id, v) lua_pushinteger(L, VariantIndex()); lua_setfield(L, -2, v) + LVICONST(TextInputEvent , "TEXTINPUT" ); + LVICONST(TextEditingEvent , "TEXTEDITING" ); + LVICONST(KeyPressEvent , "KEYPRESS" ); + LVICONST(KeyReleaseEvent , "KEYRELEASE" ); + LVICONST(MouseDownEvent , "MOUSEDOWN" ); + LVICONST(MouseUpEvent , "MOUSEUP" ); + LVICONST(MouseMoveEvent , "MOUSEMOVE" ); + LVICONST(MouseWheelEvent , "MOUSEWHEEL" ); + LVICONST(TickEvent , "TICK" ); + LVICONST(BlurEvent , "BLUR" ); + LVICONST(CloseEvent , "CLOSE" ); + LVICONST(BeforeSimEvent , "BEFORESIM" ); + LVICONST(AfterSimEvent , "AFTERSIM" ); + LVICONST(BeforeSimDrawEvent, "BEFORESIMDRAW"); + LVICONST(AfterSimDrawEvent , "AFTERSIMDRAW" ); +#undef LVICONST + lua_pushvalue(L, -1); + lua_setglobal(L, "event"); + lua_setglobal(L, "evt"); +} diff --git a/src/lua/LuaFileSystem.cpp b/src/lua/LuaFileSystem.cpp new file mode 100644 index 000000000..1344c8163 --- /dev/null +++ b/src/lua/LuaFileSystem.cpp @@ -0,0 +1,119 @@ +#include "LuaScriptInterface.h" +#include "common/platform/Platform.h" + +static int list(lua_State *L) +{ + auto directoryName = tpt_lua_checkByteString(L, 1); + lua_newtable(L); + int index = 0; + for (auto &name : Platform::DirectorySearch(directoryName, "", {})) + { + if (name != "." && name != "..") + { + index += 1; + tpt_lua_pushByteString(L, name); + lua_rawseti(L, -2, index); + } + } + return 1; +} + +static int exists(lua_State *L) +{ + auto filename = tpt_lua_checkByteString(L, 1); + bool ret = Platform::Stat(filename); + lua_pushboolean(L, ret); + return 1; +} + +static int isFile(lua_State *L) +{ + auto filename = tpt_lua_checkByteString(L, 1); + bool ret = Platform::FileExists(filename); + lua_pushboolean(L, ret); + return 1; +} + +static int isDirectory(lua_State *L) +{ + auto dirname = tpt_lua_checkByteString(L, 1); + bool ret = Platform::DirectoryExists(dirname); + lua_pushboolean(L, ret); + return 1; +} + +static int isLink(lua_State *L) +{ + auto dirname = tpt_lua_checkByteString(L, 1); + bool ret = Platform::IsLink(dirname); + lua_pushboolean(L, ret); + return 1; +} + +static int makeDirectory(lua_State *L) +{ + auto dirname = tpt_lua_checkByteString(L, 1); + + int ret = 0; + ret = Platform::MakeDirectory(dirname); + lua_pushboolean(L, ret); + return 1; +} + +static int removeDirectory(lua_State *L) +{ + auto directory = tpt_lua_checkByteString(L, 1); + + bool ret = Platform::DeleteDirectory(directory); + lua_pushboolean(L, ret); + return 1; +} + +static int removeFile(lua_State *L) +{ + auto filename = tpt_lua_checkByteString(L, 1); + lua_pushboolean(L, Platform::RemoveFile(filename)); + return 1; +} + +static int move(lua_State *L) +{ + auto filename = tpt_lua_checkByteString(L, 1); + auto newFilename = tpt_lua_checkByteString(L, 2); + bool replace = lua_toboolean(L, 3); + lua_pushboolean(L, Platform::RenameFile(filename, newFilename, replace)); + return 1; +} + +static int copy(lua_State *L) +{ + auto filename = tpt_lua_checkByteString(L, 1); + auto newFilename = tpt_lua_checkByteString(L, 2); + std::vector fileData; + lua_pushboolean(L, Platform::ReadFile(fileData, filename) && Platform::WriteFile(fileData, newFilename)); + return 1; +} + +void LuaFileSystem::Open(lua_State *L) +{ + static const luaL_Reg reg[] = { +#define LFUNC(v) { #v, v } + LFUNC(list), + LFUNC(exists), + LFUNC(isFile), + LFUNC(isDirectory), + LFUNC(isLink), + LFUNC(makeDirectory), + LFUNC(removeDirectory), + LFUNC(removeFile), + LFUNC(move), + LFUNC(copy), +#undef LFUNC + { NULL, NULL } + }; + lua_newtable(L); + luaL_register(L, NULL, reg); + lua_pushvalue(L, -1); + lua_setglobal(L, "fileSystem"); + lua_setglobal(L, "fs"); +} diff --git a/src/lua/LuaGraphics.cpp b/src/lua/LuaGraphics.cpp new file mode 100644 index 000000000..1a9316f52 --- /dev/null +++ b/src/lua/LuaGraphics.cpp @@ -0,0 +1,307 @@ +#include "LuaScriptInterface.h" +#include "graphics/Graphics.h" +#include "graphics/Renderer.h" + +static int32_t int32Truncate(double n) +{ + if (n >= 0x1p31) + { + n -= 0x1p32; + } + return int32_t(n); +} + +static std::variant currentGraphics() +{ + auto *lsi = static_cast(commandInterface); + if (lsi->eventTraits & eventTraitSimGraphics) + { + return lsi->ren; + } + return lsi->g; +} + +static int textSize(lua_State *L) +{ + auto text = tpt_lua_optString(L, 1, ""); + auto size = Graphics::TextSize(text); + lua_pushinteger(L, size.X); + lua_pushinteger(L, size.Y); + return 2; +} + +static int drawText(lua_State *L) +{ + int x = lua_tointeger(L, 1); + int y = lua_tointeger(L, 2); + auto text = tpt_lua_optString(L, 3, ""); + int r = luaL_optint(L, 4, 255); + int g = luaL_optint(L, 5, 255); + int b = luaL_optint(L, 6, 255); + int a = luaL_optint(L, 7, 255); + + if (r<0) r = 0; + else if (r>255) r = 255; + if (g<0) g = 0; + else if (g>255) g = 255; + if (b<0) b = 0; + else if (b>255) b = 255; + if (a<0) a = 0; + else if (a>255) a = 255; + + std::visit([x, y, r, g, b, a, &text](auto p) { + p->BlendText({ x, y }, text, RGBA(r, g, b, a)); + }, currentGraphics()); + return 0; +} + +static int drawPixel(lua_State *L) +{ + auto x = luaL_optint(L, 1, 0); + auto y = luaL_optint(L, 2, 0); + auto r = luaL_optint(L, 3, 255); + auto g = luaL_optint(L, 4, 255); + auto b = luaL_optint(L, 5, 255); + auto a = luaL_optint(L, 6, 255); + if (r < 0 ) r = 0 ; + else if (r > 255) r = 255; + if (g < 0 ) g = 0 ; + else if (g > 255) g = 255; + if (b < 0 ) b = 0 ; + else if (b > 255) b = 255; + if (a < 0 ) a = 0 ; + else if (a > 255) a = 255; + auto *lsi = static_cast(commandInterface); + lsi->g->BlendPixel({ x, y }, RGBA(r, g, b, a)); + return 0; +} + +static int drawLine(lua_State *L) +{ + int x1 = lua_tointeger(L, 1); + int y1 = lua_tointeger(L, 2); + int x2 = lua_tointeger(L, 3); + int y2 = lua_tointeger(L, 4); + int r = luaL_optint(L, 5, 255); + int g = luaL_optint(L, 6, 255); + int b = luaL_optint(L, 7, 255); + int a = luaL_optint(L, 8, 255); + + if (r<0) r = 0; + else if (r>255) r = 255; + if (g<0) g = 0; + else if (g>255) g = 255; + if (b<0) b = 0; + else if (b>255) b = 255; + if (a<0) a = 0; + else if (a>255) a = 255; + + std::visit([x1, y1, x2, y2, r, g, b, a](auto p) { + if (a == 255) + { + p->DrawLine({ x1, y1 }, { x2, y2 }, RGB(r, g, b)); + } + else + { + p->BlendLine({ x1, y1 }, { x2, y2 }, RGBA(r, g, b, a)); + } + }, currentGraphics()); + return 0; +} + +static int drawRect(lua_State *L) +{ + int x = lua_tointeger(L, 1); + int y = lua_tointeger(L, 2); + int width = lua_tointeger(L, 3); + int height = lua_tointeger(L, 4); + int r = luaL_optint(L, 5, 255); + int g = luaL_optint(L, 6, 255); + int b = luaL_optint(L, 7, 255); + int a = luaL_optint(L, 8, 255); + + if (r<0) r = 0; + else if (r>255) r = 255; + if (g<0) g = 0; + else if (g>255) g = 255; + if (b<0) b = 0; + else if (b>255) b = 255; + if (a<0) a = 0; + else if (a>255) a = 255; + + std::visit([x, y, width, height, r, g, b, a](auto p) { + if (a == 255) + { + p->DrawRect(RectSized(Vec2{ x, y }, Vec2{ width, height }), RGB(r, g, b)); + } + else + { + p->BlendRect(RectSized(Vec2{ x, y }, Vec2{ width, height }), RGBA(r, g, b, a)); + } + }, currentGraphics()); + return 0; +} + +static int fillRect(lua_State *L) +{ + int x = lua_tointeger(L, 1); + int y = lua_tointeger(L, 2); + int width = lua_tointeger(L, 3); + int height = lua_tointeger(L, 4); + int r = luaL_optint(L, 5, 255); + int g = luaL_optint(L, 6, 255); + int b = luaL_optint(L, 7, 255); + int a = luaL_optint(L, 8, 255); + + if (r<0) r = 0; + else if (r>255) r = 255; + if (g<0) g = 0; + else if (g>255) g = 255; + if (b<0) b = 0; + else if (b>255) b = 255; + if (a<0) a = 0; + else if (a>255) a = 255; + + std::visit([x, y, width, height, r, g, b, a](auto p) { + if (a == 255) + { + p->DrawFilledRect(RectSized(Vec2{ x, y }, Vec2{ width, height }), RGB(r, g, b)); + } + else + { + p->BlendFilledRect(RectSized(Vec2{ x, y }, Vec2{ width, height }), RGBA(r, g, b, a)); + } + }, currentGraphics()); + return 0; +} + +static int drawCircle(lua_State *L) +{ + int x = lua_tointeger(L, 1); + int y = lua_tointeger(L, 2); + int rx = lua_tointeger(L, 3); + int ry = lua_tointeger(L, 4); + int r = luaL_optint(L, 5, 255); + int g = luaL_optint(L, 6, 255); + int b = luaL_optint(L, 7, 255); + int a = luaL_optint(L, 8, 255); + + if (r<0) r = 0; + else if (r>255) r = 255; + if (g<0) g = 0; + else if (g>255) g = 255; + if (b<0) b = 0; + else if (b>255) b = 255; + if (a<0) a = 0; + else if (a>255) a = 255; + + std::visit([x, y, rx, ry, r, g, b, a](auto p) { + p->BlendEllipse({ x, y }, { abs(rx), abs(ry) }, RGBA(r, g, b, a)); + }, currentGraphics()); + return 0; +} + +static int fillCircle(lua_State *L) +{ + int x = lua_tointeger(L, 1); + int y = lua_tointeger(L, 2); + int rx = lua_tointeger(L, 3); + int ry = lua_tointeger(L, 4); + int r = luaL_optint(L, 5, 255); + int g = luaL_optint(L, 6, 255); + int b = luaL_optint(L, 7, 255); + int a = luaL_optint(L, 8, 255); + + if (r<0) r = 0; + else if (r>255) r = 255; + if (g<0) g = 0; + else if (g>255) g = 255; + if (b<0) b = 0; + else if (b>255) b = 255; + if (a<0) a = 0; + else if (a>255) a = 255; + + std::visit([x, y, rx, ry, r, g, b, a](auto p) { + p->BlendFilledEllipse({ x, y }, { abs(rx), abs(ry) }, RGBA(r, g, b, a)); + }, currentGraphics()); + return 0; +} + +static int getColors(lua_State *L) +{ + unsigned int color = int32Truncate(lua_tonumber(L, 1)); + + int a = color >> 24; + int r = (color >> 16)&0xFF; + int g = (color >> 8)&0xFF; + int b = color&0xFF; + + lua_pushinteger(L, r); + lua_pushinteger(L, g); + lua_pushinteger(L, b); + lua_pushinteger(L, a); + return 4; +} + +static int getHexColor(lua_State *L) +{ + int r = lua_tointeger(L, 1); + int g = lua_tointeger(L, 2); + int b = lua_tointeger(L, 3); + int a = 0; + if (lua_gettop(L) >= 4) + a = lua_tointeger(L, 4); + unsigned int color = (a<<24) + (r<<16) + (g<<8) + b; + + lua_pushinteger(L, color); + return 1; +} + +static int setClipRect(lua_State *L) +{ + auto *lsi = static_cast(commandInterface); + if (lsi->eventTraits & eventTraitSimGraphics) + { + return luaL_error(L, "simulation graphics do not support clip rects"); + } + int x = luaL_optinteger(L, 1, 0); + int y = luaL_optinteger(L, 2, 0); + int w = luaL_optinteger(L, 3, WINDOWW); + int h = luaL_optinteger(L, 4, WINDOWH); + auto rect = RectSized(Vec2(x, y), Vec2(w, h)); + lsi->g->SwapClipRect(rect); + lua_pushinteger(L, rect.TopLeft.X); + lua_pushinteger(L, rect.TopLeft.Y); + lua_pushinteger(L, rect.Size().X); + lua_pushinteger(L, rect.Size().Y); + return 4; +} + +void LuaGraphics::Open(lua_State *L) +{ + static const luaL_Reg reg[] = { +#define LFUNC(v) { #v, v } + LFUNC(textSize), + LFUNC(drawText), + LFUNC(drawPixel), + LFUNC(drawLine), + LFUNC(drawRect), + LFUNC(fillRect), + LFUNC(drawCircle), + LFUNC(fillCircle), + LFUNC(getColors), + LFUNC(getHexColor), + LFUNC(setClipRect), +#undef LFUNC + { NULL, NULL } + }; + lua_newtable(L); + luaL_register(L, NULL, reg); +#define LCONSTAS(k, v) lua_pushinteger(L, int(v)); lua_setfield(L, -2, k) + LCONSTAS("WIDTH", WINDOWW); + LCONSTAS("HEIGHT", WINDOWH); +#undef LCONSTAS + lua_pushvalue(L, -1); + lua_setglobal(L, "graphics"); + lua_setglobal(L, "gfx"); +} diff --git a/src/lua/LuaHttp.cpp b/src/lua/LuaHttp.cpp index 7d07e53cc..221e709a3 100644 --- a/src/lua/LuaHttp.cpp +++ b/src/lua/LuaHttp.cpp @@ -1,4 +1,4 @@ -#include "LuaHttp.h" +#include "LuaScriptInterface.h" #include "client/http/Request.h" #include "client/Client.h" #include "json/json.h" @@ -46,16 +46,16 @@ private: } public: - static int Make(lua_State *l, const ByteString &uri, bool isPost, const ByteString &verb, RequestType type, const http::PostData &postData, const std::vector &headers) + static int Make(lua_State *L, const ByteString &uri, bool isPost, const ByteString &verb, RequestType type, const http::PostData &postData, const std::vector &headers) { auto authUser = Client::Ref().GetAuthUser(); if (type == getAuthToken && !authUser.UserID) { - lua_pushnil(l); - lua_pushliteral(l, "not authenticated"); + lua_pushnil(L); + lua_pushliteral(L, "not authenticated"); return 2; } - auto *rh = (RequestHandle *)lua_newuserdata(l, sizeof(RequestHandle)); + auto *rh = (RequestHandle *)lua_newuserdata(L, sizeof(RequestHandle)); if (!rh) { return 0; @@ -80,8 +80,8 @@ public: rh->request->AuthHeaders(ByteString::Build(authUser.UserID), authUser.SessionID); } rh->request->Start(); - luaL_newmetatable(l, "HTTPRequest"); - lua_setmetatable(l, -2); + luaL_newmetatable(L, "HTTPRequest"); + lua_setmetatable(L, -2); return 1; } @@ -158,48 +158,48 @@ public: } }; -static int http_request_gc(lua_State *l) +static int HTTPRequest_gc(lua_State *L) { - auto *rh = (RequestHandle *)luaL_checkudata(l, 1, "HTTPRequest"); + auto *rh = (RequestHandle *)luaL_checkudata(L, 1, "HTTPRequest"); rh->~RequestHandle(); return 0; } -static int http_request_status(lua_State *l) +static int HTTPRequest_status(lua_State *L) { - auto *rh = (RequestHandle *)luaL_checkudata(l, 1, "HTTPRequest"); + auto *rh = (RequestHandle *)luaL_checkudata(L, 1, "HTTPRequest"); if (rh->Dead()) { - lua_pushliteral(l, "dead"); + lua_pushliteral(L, "dead"); } else if (rh->Done()) { - lua_pushliteral(l, "done"); + lua_pushliteral(L, "done"); } else { - lua_pushliteral(l, "running"); + lua_pushliteral(L, "running"); } return 1; } -static int http_request_progress(lua_State *l) +static int HTTPRequest_progress(lua_State *L) { - auto *rh = (RequestHandle *)luaL_checkudata(l, 1, "HTTPRequest"); + auto *rh = (RequestHandle *)luaL_checkudata(L, 1, "HTTPRequest"); if (!rh->Dead()) { int64_t total, done; rh->Progress(&total, &done); - lua_pushinteger(l, total); - lua_pushinteger(l, done); + lua_pushinteger(L, total); + lua_pushinteger(L, done); return 2; } return 0; } -static int http_request_cancel(lua_State *l) +static int HTTPRequest_cancel(lua_State *L) { - auto *rh = (RequestHandle *)luaL_checkudata(l, 1, "HTTPRequest"); + auto *rh = (RequestHandle *)luaL_checkudata(L, 1, "HTTPRequest"); if (!rh->Dead()) { rh->Cancel(); @@ -207,33 +207,33 @@ static int http_request_cancel(lua_State *l) return 0; } -static int http_request_finish(lua_State *l) +static int HTTPRequest_finish(lua_State *L) { - auto *rh = (RequestHandle *)luaL_checkudata(l, 1, "HTTPRequest"); + auto *rh = (RequestHandle *)luaL_checkudata(L, 1, "HTTPRequest"); if (!rh->Dead()) { std::vector headers; auto [ status, data ] = rh->Finish(headers); - tpt_lua_pushByteString(l, data); - lua_pushinteger(l, status); - lua_newtable(l); + tpt_lua_pushByteString(L, data); + lua_pushinteger(L, status); + lua_newtable(L); for (auto i = 0; i < int(headers.size()); ++i) { - lua_newtable(l); - lua_pushlstring(l, headers[i].name.data(), headers[i].name.size()); - lua_rawseti(l, -2, 1); - lua_pushlstring(l, headers[i].value.data(), headers[i].value.size()); - lua_rawseti(l, -2, 2); - lua_rawseti(l, -2, i + 1); + lua_newtable(L); + lua_pushlstring(L, headers[i].name.data(), headers[i].name.size()); + lua_rawseti(L, -2, 1); + lua_pushlstring(L, headers[i].value.data(), headers[i].value.size()); + lua_rawseti(L, -2, 2); + lua_rawseti(L, -2, i + 1); } return 3; } return 0; } -static int http_request(lua_State *l, bool isPost) +static int request(lua_State *L, bool isPost) { - ByteString uri = tpt_lua_checkByteString(l, 1); + ByteString uri = tpt_lua_checkByteString(L, 1); http::PostData postData; auto headersIndex = 2; auto verbIndex = 3; @@ -242,152 +242,160 @@ static int http_request(lua_State *l, bool isPost) { headersIndex += 1; verbIndex += 1; - if (lua_isstring(l, 2)) + if (lua_isstring(L, 2)) { - postData = tpt_lua_toByteString(l, 2); + postData = tpt_lua_toByteString(L, 2); } - else if (lua_istable(l, 2)) + else if (lua_istable(L, 2)) { postData = http::FormData{}; auto &formData = std::get(postData); - auto size = lua_objlen(l, 2); + auto size = lua_objlen(L, 2); if (size) { for (auto i = 0U; i < size; ++i) { - lua_rawgeti(l, 2, i + 1); - if (!lua_istable(l, -1)) + lua_rawgeti(L, 2, i + 1); + if (!lua_istable(L, -1)) { - luaL_error(l, "form item %i is not a table", i + 1); + luaL_error(L, "form item %i is not a table", i + 1); } - lua_rawgeti(l, -1, 1); - if (!lua_isstring(l, -1)) + lua_rawgeti(L, -1, 1); + if (!lua_isstring(L, -1)) { - luaL_error(l, "name of form item %i is not a string", i + 1); + luaL_error(L, "name of form item %i is not a string", i + 1); } - auto name = tpt_lua_toByteString(l, -1); - lua_pop(l, 1); - lua_rawgeti(l, -1, 2); - if (!lua_isstring(l, -1)) + auto name = tpt_lua_toByteString(L, -1); + lua_pop(L, 1); + lua_rawgeti(L, -1, 2); + if (!lua_isstring(L, -1)) { - luaL_error(l, "value of form item %i is not a string", i + 1); + luaL_error(L, "value of form item %i is not a string", i + 1); } - auto value = tpt_lua_toByteString(l, -1); - lua_pop(l, 1); + auto value = tpt_lua_toByteString(L, -1); + lua_pop(L, 1); std::optional filename; - lua_rawgeti(l, -1, 3); - if (!lua_isnoneornil(l, -1)) + lua_rawgeti(L, -1, 3); + if (!lua_isnoneornil(L, -1)) { - if (!lua_isstring(l, -1)) + if (!lua_isstring(L, -1)) { - luaL_error(l, "filename of form item %i is not a string", i + 1); + luaL_error(L, "filename of form item %i is not a string", i + 1); } - filename = tpt_lua_toByteString(l, -1); + filename = tpt_lua_toByteString(L, -1); } - lua_pop(l, 1); + lua_pop(L, 1); formData.push_back({ name, value, filename }); - lua_pop(l, 1); + lua_pop(L, 1); } } else { - lua_pushnil(l); - while (lua_next(l, 2)) + lua_pushnil(L); + while (lua_next(L, 2)) { - lua_pushvalue(l, -2); - formData.push_back({ tpt_lua_toByteString(l, -1), tpt_lua_toByteString(l, -2) }); - lua_pop(l, 2); + lua_pushvalue(L, -2); + formData.push_back({ tpt_lua_toByteString(L, -1), tpt_lua_toByteString(L, -2) }); + lua_pop(L, 2); } } } } std::vector headers; - if (lua_istable(l, headersIndex)) + if (lua_istable(L, headersIndex)) { - auto size = lua_objlen(l, headersIndex); + auto size = lua_objlen(L, headersIndex); if (size) { for (auto i = 0U; i < size; ++i) { - lua_rawgeti(l, headersIndex, i + 1); - if (!lua_istable(l, -1)) + lua_rawgeti(L, headersIndex, i + 1); + if (!lua_istable(L, -1)) { - luaL_error(l, "header %i is not a table", i + 1); + luaL_error(L, "header %i is not a table", i + 1); } - lua_rawgeti(l, -1, 1); - if (!lua_isstring(l, -1)) + lua_rawgeti(L, -1, 1); + if (!lua_isstring(L, -1)) { - luaL_error(l, "name of header %i is not a string", i + 1); + luaL_error(L, "name of header %i is not a string", i + 1); } - auto name = tpt_lua_toByteString(l, -1); - lua_pop(l, 1); - lua_rawgeti(l, -1, 2); - if (!lua_isstring(l, -1)) + auto name = tpt_lua_toByteString(L, -1); + lua_pop(L, 1); + lua_rawgeti(L, -1, 2); + if (!lua_isstring(L, -1)) { - luaL_error(l, "value of header %i is not a string", i + 1); + luaL_error(L, "value of header %i is not a string", i + 1); } - auto value = tpt_lua_toByteString(l, -1); - lua_pop(l, 1); + auto value = tpt_lua_toByteString(L, -1); + lua_pop(L, 1); headers.push_back({ name, value }); - lua_pop(l, 1); + lua_pop(L, 1); } } else { // old dictionary format - lua_pushnil(l); - while (lua_next(l, headersIndex)) + lua_pushnil(L); + while (lua_next(L, headersIndex)) { - lua_pushvalue(l, -2); - headers.push_back({ tpt_lua_toByteString(l, -1), tpt_lua_toByteString(l, -2) }); - lua_pop(l, 2); + lua_pushvalue(L, -2); + headers.push_back({ tpt_lua_toByteString(L, -1), tpt_lua_toByteString(L, -2) }); + lua_pop(L, 2); } } } - auto verb = tpt_lua_optByteString(l, verbIndex, ""); - return RequestHandle::Make(l, uri, isPost, verb, RequestHandle::normal, postData, headers); + auto verb = tpt_lua_optByteString(L, verbIndex, ""); + return RequestHandle::Make(L, uri, isPost, verb, RequestHandle::normal, postData, headers); } -static int http_get_auth_token(lua_State *l) +static int getAuthToken(lua_State *L) { - return RequestHandle::Make(l, ByteString::Build(SCHEME, SERVER, "/ExternalAuth.api?Action=Get&Audience=", format::URLEncode(tpt_lua_checkByteString(l, 1))), false, {}, RequestHandle::getAuthToken, {}, {}); + return RequestHandle::Make(L, ByteString::Build(SCHEME, SERVER, "/ExternalAuth.api?Action=Get&Audience=", format::URLEncode(tpt_lua_checkByteString(L, 1))), false, {}, RequestHandle::getAuthToken, {}, {}); } -static int http_get(lua_State * l) +static int get(lua_State *L) { - return http_request(l, false); + return request(L, false); } -static int http_post(lua_State * l) +static int post(lua_State *L) { - return http_request(l, true); + return request(L, true); } -void LuaHttp::Open(lua_State *l) +void LuaHttp::Open(lua_State *L) { - luaL_newmetatable(l, "HTTPRequest"); - lua_pushcfunction(l, http_request_gc); - lua_setfield(l, -2, "__gc"); - lua_newtable(l); - struct luaL_Reg httpRequestIndexMethods[] = { - { "status", http_request_status }, - { "progress", http_request_progress }, - { "cancel", http_request_cancel }, - { "finish", http_request_finish }, - { NULL, NULL } - }; - luaL_register(l, NULL, httpRequestIndexMethods); - lua_setfield(l, -2, "__index"); - lua_pop(l, 1); - lua_newtable(l); - struct luaL_Reg httpMethods[] = { - { "get", http_get }, - { "post", http_post }, - { "getAuthToken", http_get_auth_token }, - { NULL, NULL } - }; - luaL_register(l, NULL, httpMethods); - lua_setglobal(l, "http"); + { + static const luaL_Reg reg[] = { +#define LFUNC(v) { #v, HTTPRequest_ ## v } + LFUNC(status), + LFUNC(progress), + LFUNC(cancel), + LFUNC(finish), +#undef LFUNC + { NULL, NULL } + }; + luaL_newmetatable(L, "HTTPRequest"); + lua_pushcfunction(L, HTTPRequest_gc); + lua_setfield(L, -2, "__gc"); + lua_newtable(L); + luaL_register(L, NULL, reg); + lua_setfield(L, -2, "__index"); + lua_pop(L, 1); + } + { + static const luaL_Reg reg[] = { +#define LFUNC(v) { #v, v } + LFUNC(get), + LFUNC(post), + LFUNC(getAuthToken), +#undef LFUNC + { NULL, NULL } + }; + lua_newtable(L); + luaL_register(L, NULL, reg); + lua_setglobal(L, "http"); + } } diff --git a/src/lua/LuaHttp.h b/src/lua/LuaHttp.h deleted file mode 100644 index 1cceabced..000000000 --- a/src/lua/LuaHttp.h +++ /dev/null @@ -1,7 +0,0 @@ -#pragma once -#include "LuaCompat.h" - -namespace LuaHttp -{ - void Open(lua_State *l); -} diff --git a/src/lua/LuaInterface.cpp b/src/lua/LuaInterface.cpp new file mode 100644 index 000000000..211825bed --- /dev/null +++ b/src/lua/LuaInterface.cpp @@ -0,0 +1,498 @@ +#include "LuaScriptInterface.h" +#include "gui/dialogues/ConfirmPrompt.h" +#include "gui/dialogues/ErrorMessage.h" +#include "gui/dialogues/InformationMessage.h" +#include "gui/dialogues/TextPrompt.h" +#include "gui/game/Brush.h" +#include "gui/game/GameController.h" +#include "gui/game/GameModel.h" +#include "gui/game/GameView.h" +#include "gui/game/Tool.h" +#include "gui/interface/Engine.h" +#include "LuaButton.h" +#include "LuaCheckbox.h" +#include "LuaLabel.h" +#include "LuaLuna.h" +#include "LuaProgressBar.h" +#include "LuaSDLKeys.h" +#include "LuaSlider.h" +#include "LuaTextbox.h" +#include "LuaWindow.h" +#include "prefs/GlobalPrefs.h" +#include "simulation/SimulationData.h" + +template +struct PickIfTypeHelper; + +template<> +struct PickIfTypeHelper +{ + static constexpr auto LuaType = LUA_TSTRING; + static String Get(lua_State *L, int index) { return tpt_lua_checkString(L, index); } +}; + +template<> +struct PickIfTypeHelper +{ + static constexpr auto LuaType = LUA_TBOOLEAN; + static bool Get(lua_State *L, int index) { return lua_toboolean(L, index); } +}; + +template +static Type PickIfType(lua_State *L, int index, Type defaultValue) +{ + return lua_type(L, index) == PickIfTypeHelper::LuaType ? PickIfTypeHelper::Get(L, index) : defaultValue; +} + +static int beginMessageBox(lua_State *L) +{ + auto title = PickIfType(L, 1, String("Title")); + auto message = PickIfType(L, 2, String("Message")); + auto large = PickIfType(L, 3, false); + auto cb = std::make_shared(); // * Bind to main lua state (might be different from L). + cb->Assign(L, lua_gettop(L)); + new InformationMessage(title, message, large, { [cb]() { + auto *lsi = static_cast(commandInterface); + auto L = lsi->L; + cb->Push(L); + if (lua_isfunction(L, -1)) + { + if (tpt_lua_pcall(L, 0, 0, 0, eventTraitNone)) + { + lsi->Log(CommandInterface::LogError, LuaGetError()); + } + } + else + { + lua_pop(L, 1); + } + } }); + return 0; +} + +static int beginThrowError(lua_State *L) +{ + auto errorMessage = PickIfType(L, 1, String("Error text")); + auto cb = std::make_shared(); // * Bind to main lua state (might be different from L). + cb->Assign(L, lua_gettop(L)); + new ErrorMessage("Error", errorMessage, { [cb]() { + auto *lsi = static_cast(commandInterface); + auto L = lsi->L; + cb->Push(L); + if (lua_isfunction(L, -1)) + { + if (tpt_lua_pcall(L, 0, 0, 0, eventTraitNone)) + { + lsi->Log(CommandInterface::LogError, LuaGetError()); + } + } + else + { + lua_pop(L, 1); + } + } }); + return 0; +} + +static int beginInput(lua_State *L) +{ + auto title = PickIfType(L, 1, String("Title")); + auto prompt = PickIfType(L, 2, String("Enter some text:")); + auto text = PickIfType(L, 3, String("")); + auto shadow = PickIfType(L, 4, String("")); + auto cb = std::make_shared(); // * Bind to main lua state (might be different from L). + cb->Assign(L, lua_gettop(L)); + auto handle = [cb](std::optional input) { + auto *lsi = static_cast(commandInterface); + auto L = lsi->L; + cb->Push(L); + if (lua_isfunction(L, -1)) + { + if (input) + { + tpt_lua_pushString(L, *input); + } + else + { + lua_pushnil(L); + } + if (tpt_lua_pcall(L, 1, 0, 0, eventTraitNone)) + { + lsi->Log(CommandInterface::LogError, LuaGetError()); + } + } + else + { + lua_pop(L, 1); + } + }; + new TextPrompt(title, prompt, text, shadow, false, { [handle](const String &input) { + handle(input); + }, [handle]() { + handle(std::nullopt); + } }); + return 0; +} + +static int beginConfirm(lua_State *L) +{ + auto title = PickIfType(L, 1, String("Title")); + auto message = PickIfType(L, 2, String("Message")); + auto buttonText = PickIfType(L, 3, String("Confirm")); + auto cb = std::make_shared(); // * Bind to main lua state (might be different from L). + cb->Assign(L, lua_gettop(L)); + auto handle = [cb](int result) { + auto *lsi = static_cast(commandInterface); + auto L = lsi->L; + cb->Push(L); + if (lua_isfunction(L, -1)) + { + lua_pushboolean(L, result); + if (tpt_lua_pcall(L, 1, 0, 0, eventTraitNone)) + { + lsi->Log(CommandInterface::LogError, LuaGetError()); + } + } + else + { + lua_pop(L, 1); + } + }; + new ConfirmPrompt(title, message, { [handle]() { + handle(1); + }, [handle]() { + handle(0); + } }, buttonText); + return 0; +} + +static int console(lua_State *L) +{ + auto *lsi = static_cast(commandInterface); + int acount = lua_gettop(L); + if (acount == 0) + { + lua_pushboolean(L, lsi->window != ui::Engine::Ref().GetWindow()); + return 1; + } + if (lua_toboolean(L, 1)) + lsi->gameController->ShowConsole(); + else + lsi->gameController->HideConsole(); + return 0; +} + +static int brushID(lua_State *L) +{ + auto *lsi = static_cast(commandInterface); + if (lua_gettop(L) < 1) + { + lua_pushnumber(L, lsi->gameModel->GetBrushID()); + return 1; + } + auto index = luaL_checkint(L, 1); + if (index < 0 || index >= int(lsi->gameModel->BrushListSize())) + { + return luaL_error(L, "Invalid brush index %i", index); + } + lsi->gameModel->SetBrushID(index); + return 0; +} + +static int brushRadius(lua_State *L) +{ + auto *lsi = static_cast(commandInterface); + if (lua_gettop(L) < 1) + { + auto radius = lsi->gameModel->GetBrush().GetRadius(); + lua_pushnumber(L, radius.X); + lua_pushnumber(L, radius.Y); + return 2; + } + lsi->gameModel->GetBrush().SetRadius({ luaL_checkint(L, 1), luaL_checkint(L, 2) }); + return 0; +} + +static int mousePosition(lua_State *L) +{ + auto *lsi = static_cast(commandInterface); + auto pos = lsi->gameController->GetView()->GetMousePosition(); + lua_pushnumber(L, pos.X); + lua_pushnumber(L, pos.Y); + return 2; +} + +static int activeTool(lua_State *L) +{ auto *lsi = static_cast(commandInterface); + auto index = luaL_checkint(L, 1); + if (index < 0 || index >= NUM_TOOLINDICES) + { + return luaL_error(L, "Invalid tool index %i", index); + } + if (lua_gettop(L) < 2) + { + tpt_lua_pushByteString(L, lsi->gameModel->GetActiveTool(index)->Identifier); + return 1; + } + auto identifier = tpt_lua_checkByteString(L, 2); + auto *tool = lsi->gameModel->GetToolFromIdentifier(identifier); + if (!tool) + { + return luaL_error(L, "Invalid tool identifier %s", identifier.c_str()); + } + lsi->gameController->SetActiveTool(index, tool); + return 0; +} + +static int addComponent(lua_State *L) +{ + auto *lsi = static_cast(commandInterface); + void *opaque = nullptr; + LuaComponent *luaComponent = nullptr; + if ((opaque = Luna::tryGet(L, 1))) + luaComponent = Luna::get(opaque); + else if ((opaque = Luna::tryGet(L, 1))) + luaComponent = Luna::get(opaque); + else if ((opaque = Luna::tryGet(L, 1))) + luaComponent = Luna::get(opaque); + else if ((opaque = Luna::tryGet(L, 1))) + luaComponent = Luna::get(opaque); + else if ((opaque = Luna::tryGet(L, 1))) + luaComponent = Luna::get(opaque); + else if ((opaque = Luna::tryGet(L, 1))) + luaComponent = Luna::get(opaque); + else + luaL_typerror(L, 1, "Component"); + if (lsi->window && luaComponent) + { + auto ok = lsi->grabbedComponents.insert(std::make_pair(luaComponent, LuaSmartRef())); + if (ok.second) + { + auto it = ok.first; + it->second.Assign(L, 1); + it->first->owner_ref = it->second; + } + lsi->window->AddComponent(luaComponent->GetComponent()); + } + return 0; +} + +static int removeComponent(lua_State *L) +{ + auto *lsi = static_cast(commandInterface); + void *opaque = nullptr; + LuaComponent *luaComponent = nullptr; + if ((opaque = Luna::tryGet(L, 1))) + luaComponent = Luna::get(opaque); + else if ((opaque = Luna::tryGet(L, 1))) + luaComponent = Luna::get(opaque); + else if ((opaque = Luna::tryGet(L, 1))) + luaComponent = Luna::get(opaque); + else if ((opaque = Luna::tryGet(L, 1))) + luaComponent = Luna::get(opaque); + else if ((opaque = Luna::tryGet(L, 1))) + luaComponent = Luna::get(opaque); + else if ((opaque = Luna::tryGet(L, 1))) + luaComponent = Luna::get(opaque); + else + luaL_typerror(L, 1, "Component"); + if(lsi->window && luaComponent) + { + ui::Component *component = luaComponent->GetComponent(); + lsi->window->RemoveComponent(component); + auto it = lsi->grabbedComponents.find(luaComponent); + if (it != lsi->grabbedComponents.end()) + { + it->second.Clear(); + it->first->owner_ref = it->second; + lsi->grabbedComponents.erase(it); + } + } + return 0; +} + +static int grabTextInput(lua_State *L) +{ + auto *lsi = static_cast(commandInterface); + lsi->textInputRefcount += 1; + lsi->gameController->GetView()->DoesTextInput = lsi->textInputRefcount > 0; + return 0; +} + +static int dropTextInput(lua_State *L) +{ + auto *lsi = static_cast(commandInterface); + lsi->textInputRefcount -= 1; + lsi->gameController->GetView()->DoesTextInput = lsi->textInputRefcount > 0; + return 0; +} + +static int textInputRect(lua_State *L) +{ + int x = luaL_checkint(L, 1); + int y = luaL_checkint(L, 2); + int w = luaL_checkint(L, 3); + int h = luaL_checkint(L, 4); + ui::Engine::Ref().TextInputRect(ui::Point{ x, y }, ui::Point{ w, h }); + return 0; +} + +static int showWindow(lua_State *L) +{ + LuaWindow * window = Luna::check(L, 1); + + if(window && ui::Engine::Ref().GetWindow()!=window->GetWindow()) + ui::Engine::Ref().ShowWindow(window->GetWindow()); + return 0; +} + +static int closeWindow(lua_State *L) +{ + LuaWindow * window = Luna::check(L, 1); + if (window) + window->GetWindow()->CloseActiveWindow(); + return 0; +} + +static int perfectCircleBrush(lua_State *L) +{ + auto *lsi = static_cast(commandInterface); + if (!lua_gettop(L)) + { + lua_pushboolean(L, lsi->gameModel->GetPerfectCircle()); + return 1; + } + luaL_checktype(L, 1, LUA_TBOOLEAN); + lsi->gameModel->SetPerfectCircle(lua_toboolean(L, 1)); + return 0; +} + +static int activeMenu(lua_State *L) +{ + auto *lsi = static_cast(commandInterface); + int acount = lua_gettop(L); + if (acount == 0) + { + lua_pushinteger(L, lsi->gameModel->GetActiveMenu()); + return 1; + } + int menuid = luaL_checkint(L, 1); + if (menuid >= 0 && menuid < SC_TOTAL) + lsi->gameController->SetActiveMenu(menuid); + else + return luaL_error(L, "Invalid menu"); + return 0; +} + +static int menuEnabled(lua_State *L) +{ + int menusection = luaL_checkint(L, 1); + if (menusection < 0 || menusection >= SC_TOTAL) + return luaL_error(L, "Invalid menu"); + int acount = lua_gettop(L); + if (acount == 1) + { + lua_pushboolean(L, SimulationData::CRef().msections[menusection].doshow); + return 1; + } + luaL_checktype(L, 2, LUA_TBOOLEAN); + int enabled = lua_toboolean(L, 2); + { + auto &sd = SimulationData::Ref(); + sd.msections[menusection].doshow = enabled; + } + auto *lsi = static_cast(commandInterface); + lsi->gameModel->BuildMenus(); + return 0; +} + +static int numMenus(lua_State *L) +{ + int acount = lua_gettop(L); + bool onlyEnabled = true; + if (acount > 0) + { + luaL_checktype(L, 1, LUA_TBOOLEAN); + onlyEnabled = lua_toboolean(L, 1); + } + auto *lsi = static_cast(commandInterface); + lua_pushinteger(L, lsi->gameController->GetNumMenus(onlyEnabled)); + return 1; +} + +static int windowSize(lua_State *L) +{ + auto &g = ui::Engine::Ref(); + if (lua_gettop(L) < 1) + { + lua_pushinteger(L, g.GetScale()); + lua_pushboolean(L, g.GetFullscreen()); + return 2; + } + int scale = luaL_optint(L,1,1); + auto kiosk = lua_toboolean(L,2); + // TODO: handle this the same way as it's handled in PowderToySDL.cpp + // > maybe bind the maximum allowed scale to screen size somehow + if (scale < 1 || scale > 10) + { + scale = 1; + } + { + auto &prefs = GlobalPrefs::Ref(); + Prefs::DeferWrite dw(prefs); + prefs.Set("Scale", scale); + prefs.Set("Fullscreen", kiosk); + } + g.SetScale(scale); + g.SetFullscreen(kiosk); + return 0; +} + +void LuaInterface::Open(lua_State *L) +{ + static const luaL_Reg reg[] = { +#define LFUNC(v) { #v, v } + LFUNC(showWindow), + LFUNC(closeWindow), + LFUNC(addComponent), + LFUNC(removeComponent), + LFUNC(grabTextInput), + LFUNC(dropTextInput), + LFUNC(textInputRect), + LFUNC(beginInput), + LFUNC(beginMessageBox), + LFUNC(beginConfirm), + LFUNC(beginThrowError), + LFUNC(activeMenu), + LFUNC(menuEnabled), + LFUNC(numMenus), + LFUNC(perfectCircleBrush), + LFUNC(console), + LFUNC(windowSize), + LFUNC(brushID), + LFUNC(brushRadius), + LFUNC(mousePosition), + LFUNC(activeTool), +#undef LFUNC + { NULL, NULL } + }; + lua_newtable(L); + luaL_register(L, NULL, reg); +#define LCONSTAS(k, v) lua_pushinteger(L, int(v)); lua_setfield(L, -2, k) + LCONSTAS("MOUSEUP_NORMAL" , GameController::mouseUpNormal); + LCONSTAS("MOUSEUP_BLUR" , GameController::mouseUpBlur); + LCONSTAS("MOUSEUP_DRAWEND", GameController::mouseUpDrawEnd); + LCONSTAS("NUM_TOOLINDICES", NUM_TOOLINDICES); +#undef LCONSTAS + initLuaSDLKeys(L); + lua_pushvalue(L, -1); + lua_setglobal(L, "interface"); + lua_setglobal(L, "ui"); + Luna::Register(L); + Luna::Register(L); + Luna::Register(L); + Luna::Register(L); + Luna::Register(L); + Luna::Register(L); + Luna::Register(L); +} diff --git a/src/lua/LuaLabel.cpp b/src/lua/LuaLabel.cpp index b67e82367..c35e02e98 100644 --- a/src/lua/LuaLabel.cpp +++ b/src/lua/LuaLabel.cpp @@ -13,31 +13,31 @@ Luna::RegType LuaLabel::methods[] = { {0, 0} }; -LuaLabel::LuaLabel(lua_State * l) : - LuaComponent(l) +LuaLabel::LuaLabel(lua_State *L) : + LuaComponent(L) { - this->l = l; - int posX = luaL_optinteger(l, 1, 0); - int posY = luaL_optinteger(l, 2, 0); - int sizeX = luaL_optinteger(l, 3, 10); - int sizeY = luaL_optinteger(l, 4, 10); - String text = tpt_lua_optString(l, 5, ""); + this->L = L; + int posX = luaL_optinteger(L, 1, 0); + int posY = luaL_optinteger(L, 2, 0); + int sizeX = luaL_optinteger(L, 3, 10); + int sizeY = luaL_optinteger(L, 4, 10); + String text = tpt_lua_optString(L, 5, ""); label = new ui::Label(ui::Point(posX, posY), ui::Point(sizeX, sizeY), text); component = label; } -int LuaLabel::text(lua_State * l) +int LuaLabel::text(lua_State *L) { - int args = lua_gettop(l); + int args = lua_gettop(L); if(args) { - label->SetText(tpt_lua_checkString(l, 1)); + label->SetText(tpt_lua_checkString(L, 1)); return 0; } else { - tpt_lua_pushString(l, label->GetText()); + tpt_lua_pushString(L, label->GetText()); return 1; } } diff --git a/src/lua/LuaLabel.h b/src/lua/LuaLabel.h index 59c86b530..4d51a1f9c 100644 --- a/src/lua/LuaLabel.h +++ b/src/lua/LuaLabel.h @@ -13,11 +13,11 @@ class LuaScriptInterface; class LuaLabel: public LuaComponent { ui::Label * label; - int text(lua_State * l); + int text(lua_State *L); public: static const char className[]; static Luna::RegType methods[]; - LuaLabel(lua_State * l); + LuaLabel(lua_State *L); ~LuaLabel(); }; diff --git a/src/lua/LuaLuna.h b/src/lua/LuaLuna.h index 371c48853..464c0f32a 100644 --- a/src/lua/LuaLuna.h +++ b/src/lua/LuaLuna.h @@ -54,7 +54,7 @@ public: } // get userdata from Lua stack and return pointer to T object - static T * check(lua_State * L, int narg) + static T * check(lua_State *L, int narg) { userdataType *ud = static_cast(luaL_checkudata(L, narg, T::className)); if(!ud) @@ -62,7 +62,7 @@ public: return ud->pT; // pointer to T object } - static void * tryGet(lua_State * L, int narg) + static void * tryGet(lua_State *L, int narg) { if(checkType(L, narg, T::className)) { @@ -77,7 +77,7 @@ public: } } - static bool checkType (lua_State * L, int idx, const char *name) + static bool checkType (lua_State *L, int idx, const char *name) { // returns true if a userdata is of a certain type int res; @@ -98,7 +98,7 @@ private: Luna(); // hide default constructor // member function dispatcher - static int thunk(lua_State * L) + static int thunk(lua_State *L) { // stack has userdata, followed by method args T *obj = check(L, 1); // get 'self', or if you prefer, 'this' @@ -110,7 +110,7 @@ private: // create a new T object and // push onto the Lua stack a userdata containing a pointer to T object - static int new_T(lua_State * L) + static int new_T(lua_State *L) { if (!lua_gettop(L)) return 0; @@ -133,7 +133,7 @@ private: return 0; } - static int tostring_T (lua_State * L) + static int tostring_T (lua_State *L) { char buff[32]; userdataType *ud = static_cast(lua_touserdata(L, 1)); diff --git a/src/lua/LuaMisc.cpp b/src/lua/LuaMisc.cpp new file mode 100644 index 000000000..a9c4fe285 --- /dev/null +++ b/src/lua/LuaMisc.cpp @@ -0,0 +1,300 @@ +#include "LuaScriptInterface.h" +#include "client/http/Request.h" +#include "common/platform/Platform.h" +#include "compat.lua.h" +#include "Config.h" +#include "gui/dialogues/ErrorMessage.h" +#include "gui/dialogues/InformationMessage.h" +#include "gui/game/GameController.h" +#include "gui/game/GameModel.h" +#include "gui/game/GameView.h" +#include "gui/interface/Engine.h" + +static int getUserName(lua_State *L) +{ + auto *lsi = static_cast(commandInterface); + if (lsi->gameModel->GetUser().UserID) + { + tpt_lua_pushByteString(L, lsi->gameModel->GetUser().Username); + return 1; + } + lua_pushliteral(L, ""); + return 1; +} + +static int installScriptManager(lua_State *L) +{ + auto *lsi = static_cast(commandInterface); + if (lsi->scriptManagerDownload) + { + new ErrorMessage("Script download", "A script download is already pending"); + return 0; + } + lsi->gameController->HideConsole(); + if (ui::Engine::Ref().GetWindow() != lsi->gameController->GetView()) + { + new ErrorMessage("Script download", "You must run this function from the console"); + return 0; + } + lsi->scriptManagerDownload = std::make_unique(ByteString::Build(SCHEME, "starcatcher.us/scripts/main.lua?get=1")); + lsi->scriptManagerDownload->Start(); + return 0; +} + +void LuaMisc::Tick(lua_State *L) +{ + auto *lsi = static_cast(commandInterface); + if (lsi->scriptManagerDownload && lsi->scriptManagerDownload->CheckDone()) + { + struct Status + { + struct Ok + { + }; + struct GetFailed + { + String error; + }; + struct RunFailed + { + String error; + }; + using Value = std::variant< + Ok, + GetFailed, + RunFailed + >; + Value value; + }; + auto complete = [](Status status) { + if (std::get_if(&status.value)) + { + new InformationMessage("Install script manager", "Script manager successfully installed", false); + } + if (auto *requestFailed = std::get_if(&status.value)) + { + new ErrorMessage("Install script manager", "Failed to get script manager: " + requestFailed->error); + } + if (auto *runFailed = std::get_if(&status.value)) + { + new ErrorMessage("Install script manager", "Failed to run script manager: " + runFailed->error); + } + }; + try + { + auto ret = lsi->scriptManagerDownload->StatusCode(); + auto scriptData = lsi->scriptManagerDownload->Finish().second; + if (!scriptData.size()) + { + complete({ Status::GetFailed{ "Server did not return data" } }); + return; + } + if (ret != 200) + { + complete({ Status::GetFailed{ ByteString(http::StatusText(ret)).FromUtf8() } }); + return; + } + ByteString filename = "autorun.lua"; + if (!Platform::WriteFile(std::vector(scriptData.begin(), scriptData.end()), filename)) + { + complete({ Status::GetFailed{ String::Build("Unable to write to ", filename.FromUtf8()) } }); + return; + } + if (tpt_lua_dostring(L, ByteString::Build("dofile('", filename, "')"))) + { + complete({ Status::RunFailed{ LuaGetError() } }); + return; + } + complete({ Status::Ok{} }); + } + catch (const http::RequestError &ex) + { + complete({ Status::GetFailed{ ByteString(ex.what()).FromUtf8() } }); + } + lsi->scriptManagerDownload.reset(); + } +} + +static int flog(lua_State *L) +{ + auto *lsi = static_cast(commandInterface); + int args = lua_gettop(L); + String text; + bool hasText = false; + for(int i = 1; i <= args; i++) + { + LuaToLoggableString(L, -1); + if (hasText) + { + text = tpt_lua_optString(L, -1, "") + ", " + text; + } + else + { + text = tpt_lua_optString(L, -1, ""); + hasText = true; + } + lua_pop(L, 2); + } + if (lsi->currentCommand) + { + auto lastError = lsi->GetLastError(); + if (lsi->luacon_hasLastError) + lastError += "; "; + lastError += text; + lsi->SetLastError(lastError); + lsi->luacon_hasLastError = true; + } + else + lsi->Log(CommandInterface::LogNotice, text); + return 0; +} + +static int screenshot(lua_State *L) +{ + int captureUI = luaL_optint(L, 1, 0); + int fileType = luaL_optint(L, 2, 0); + + auto *lsi = static_cast(commandInterface); + ByteString filename = lsi->gameController->TakeScreenshot(captureUI, fileType); + if (filename.size()) + { + tpt_lua_pushByteString(L, filename); + return 1; + } + return 0; +} + +static int record(lua_State *L) +{ + if (!lua_isboolean(L, -1)) + return luaL_typerror(L, 1, lua_typename(L, LUA_TBOOLEAN)); + bool record = lua_toboolean(L, -1); + auto *lsi = static_cast(commandInterface); + int recordingFolder = lsi->gameController->Record(record); + lua_pushinteger(L, recordingFolder); + return 1; +} + +static int compatChunk(lua_State *L) +{ + lua_pushlstring(L, reinterpret_cast(compat_lua), compat_lua_size); + return 1; +} +static int debug(lua_State *L) +{ + auto *lsi = static_cast(commandInterface); + int acount = lua_gettop(L); + if (acount == 0) + { + lua_pushinteger(L, lsi->gameController->GetDebugFlags()); + return 1; + } + int debugFlags = luaL_optint(L, 1, 0); + lsi->gameController->SetDebugFlags(debugFlags); + return 0; +} + +static int fpsCap(lua_State *L) +{ + int acount = lua_gettop(L); + if (acount == 0) + { + auto fpsLimit = ui::Engine::Ref().GetFpsLimit(); + if (std::holds_alternative(fpsLimit)) + { + lua_pushliteral(L, "vsync"); + } + else if (std::holds_alternative(fpsLimit)) + { + lua_pushnumber(L, 2); + } + else + { + lua_pushnumber(L, std::get(fpsLimit).value); + } + return 1; + } + if (lua_isstring(L, 1) && byteStringEqualsLiteral(tpt_lua_toByteString(L, 1), "vsync")) + { + ui::Engine::Ref().SetFpsLimit(FpsLimitVsync{}); + return 0; + } + float fpscap = luaL_checknumber(L, 1); + if (fpscap < 2) + { + return luaL_error(L, "fps cap too small"); + } + if (fpscap == 2) + { + ui::Engine::Ref().SetFpsLimit(FpsLimitNone{}); + return 0; + } + ui::Engine::Ref().SetFpsLimit(FpsLimitExplicit{ fpscap }); + return 0; +} + +static int drawCap(lua_State *L) +{ + int acount = lua_gettop(L); + if (acount == 0) + { + lua_pushinteger(L, ui::Engine::Ref().GetDrawingFrequencyLimit()); + return 1; + } + int drawcap = luaL_checkint(L, 1); + if(drawcap < 0) + return luaL_error(L, "draw cap too small"); + ui::Engine::Ref().SetDrawingFrequencyLimit(drawcap); + return 0; +} + +void LuaMisc::Open(lua_State *L) +{ + static const luaL_Reg reg[] = { +#define LFUNC(v) { #v, v } + LFUNC(getUserName), + LFUNC(installScriptManager), + LFUNC(screenshot), + LFUNC(record), + LFUNC(debug), + LFUNC(fpsCap), + LFUNC(drawCap), + LFUNC(compatChunk), +#undef LFUNC + { "log", flog }, + { NULL, NULL } + }; + lua_newtable(L); + luaL_register(L, NULL, reg); +#define LCONST(v) lua_pushinteger(L, int(v)); lua_setfield(L, -2, #v) + LCONST(DEBUG_PARTS); + LCONST(DEBUG_ELEMENTPOP); + LCONST(DEBUG_LINES); + LCONST(DEBUG_PARTICLE); + LCONST(DEBUG_SURFNORM); +#undef LCONST + { + lua_newtable(L); +#define LCONSTAS(k, v) lua_pushinteger(L, int(v)); lua_setfield(L, -2, k) + LCONSTAS("major" , DISPLAY_VERSION[0]); + LCONSTAS("minor" , DISPLAY_VERSION[1]); + LCONSTAS("build" , APP_VERSION.build); + LCONSTAS("upstreamMajor", UPSTREAM_VERSION.displayVersion[0]); + LCONSTAS("upstreamMinor", UPSTREAM_VERSION.displayVersion[1]); + LCONSTAS("upstreamBuild", UPSTREAM_VERSION.build); + LCONSTAS("modid" , MOD_ID); +#undef LCONSTAS + lua_pushboolean(L, SNAPSHOT); + lua_setfield(L, -2, "snapshot"); + lua_pushboolean(L, BETA); + lua_setfield(L, -2, "beta"); + auto vcsTag = ByteString(VCS_TAG); + if (vcsTag.size()) + { + tpt_lua_pushByteString(L, vcsTag); + lua_setfield(L, -2, "vcstag"); + } + lua_setfield(L, -2, "version"); + } + lua_setglobal(L, "tpt"); +} diff --git a/src/lua/LuaPlatform.cpp b/src/lua/LuaPlatform.cpp new file mode 100644 index 000000000..857b8b81e --- /dev/null +++ b/src/lua/LuaPlatform.cpp @@ -0,0 +1,80 @@ +#include "LuaScriptInterface.h" +#include "common/platform/Platform.h" +#include "Config.h" +#include "PowderToySDL.h" + +static int platform(lua_State *L) +{ + tpt_lua_pushByteString(L, IDENT_PLATFORM); + return 1; +} + +static int ident(lua_State *L) +{ + tpt_lua_pushByteString(L, IDENT); + return 1; +} + +static int releaseType(lua_State *L) +{ + tpt_lua_pushByteString(L, ByteString(1, IDENT_RELTYPE)); + return 1; +} + +static int exeName(lua_State *L) +{ + ByteString name = Platform::ExecutableName(); + if (name.length()) + tpt_lua_pushByteString(L, name); + else + luaL_error(L, "Error, could not get executable name"); + return 1; +} + +static int restart(lua_State *L) +{ + Platform::DoRestart(); + return 0; +} + +static int openLink(lua_State *L) +{ + auto uri = tpt_lua_checkByteString(L, 1); + Platform::OpenURI(uri); + return 0; +} + +static int clipboardCopy(lua_State *L) +{ + tpt_lua_pushByteString(L, ClipboardPull()); + return 1; +} + +static int clipboardPaste(lua_State *L) +{ + luaL_checktype(L, 1, LUA_TSTRING); + ClipboardPush(tpt_lua_optByteString(L, 1, "")); + return 0; +} + +void LuaPlatform::Open(lua_State *L) +{ + static const luaL_Reg reg[] = { +#define LFUNC(v) { #v, v } + LFUNC(platform), + LFUNC(ident), + LFUNC(releaseType), + LFUNC(exeName), + LFUNC(restart), + LFUNC(openLink), + LFUNC(clipboardCopy), + LFUNC(clipboardPaste), +#undef LFUNC + { NULL, NULL } + }; + lua_newtable(L); + luaL_register(L, NULL, reg); + lua_pushvalue(L, -1); + lua_setglobal(L, "platform"); + lua_setglobal(L, "plat"); +} diff --git a/src/lua/LuaProgressBar.cpp b/src/lua/LuaProgressBar.cpp index 11efdf3c1..248e082af 100644 --- a/src/lua/LuaProgressBar.cpp +++ b/src/lua/LuaProgressBar.cpp @@ -14,46 +14,46 @@ Luna::RegType LuaProgressBar::methods[] = { {0, 0} }; -LuaProgressBar::LuaProgressBar(lua_State * l) : - LuaComponent(l) +LuaProgressBar::LuaProgressBar(lua_State *L) : + LuaComponent(L) { - int posX = luaL_optinteger(l, 1, 0); - int posY = luaL_optinteger(l, 2, 0); - int sizeX = luaL_optinteger(l, 3, 10); - int sizeY = luaL_optinteger(l, 4, 10); - int value = luaL_optinteger(l, 5, 0); - String status = tpt_lua_optString(l, 6, ""); + int posX = luaL_optinteger(L, 1, 0); + int posY = luaL_optinteger(L, 2, 0); + int sizeX = luaL_optinteger(L, 3, 10); + int sizeY = luaL_optinteger(L, 4, 10); + int value = luaL_optinteger(L, 5, 0); + String status = tpt_lua_optString(L, 6, ""); progressBar = new ui::ProgressBar(ui::Point(posX, posY), ui::Point(sizeX, sizeY), value, status); component = progressBar; } -int LuaProgressBar::progress(lua_State * l) +int LuaProgressBar::progress(lua_State *L) { - int args = lua_gettop(l); + int args = lua_gettop(L); if(args) { - progressBar->SetProgress(lua_tointeger(l, 1)); + progressBar->SetProgress(lua_tointeger(L, 1)); return 0; } else { - lua_pushinteger(l, progressBar->GetProgress()); + lua_pushinteger(L, progressBar->GetProgress()); return 1; } } -int LuaProgressBar::status(lua_State * l) +int LuaProgressBar::status(lua_State *L) { - int args = lua_gettop(l); + int args = lua_gettop(L); if(args) { - progressBar->SetStatus(tpt_lua_checkString(l, 1)); + progressBar->SetStatus(tpt_lua_checkString(L, 1)); return 0; } else { - tpt_lua_pushString(l, progressBar->GetStatus()); + tpt_lua_pushString(L, progressBar->GetStatus()); return 1; } } diff --git a/src/lua/LuaProgressBar.h b/src/lua/LuaProgressBar.h index 1c86b2fd2..1b9ff03ac 100644 --- a/src/lua/LuaProgressBar.h +++ b/src/lua/LuaProgressBar.h @@ -13,12 +13,12 @@ class LuaScriptInterface; class LuaProgressBar: public LuaComponent { ui::ProgressBar * progressBar; - int progress(lua_State * l); - int status(lua_State * l); + int progress(lua_State *L); + int status(lua_State *L); public: static const char className[]; static Luna::RegType methods[]; - LuaProgressBar(lua_State * l); + LuaProgressBar(lua_State *L); ~LuaProgressBar(); }; diff --git a/src/lua/LuaRenderer.cpp b/src/lua/LuaRenderer.cpp new file mode 100644 index 000000000..32d9d9735 --- /dev/null +++ b/src/lua/LuaRenderer.cpp @@ -0,0 +1,341 @@ +#include "LuaScriptInterface.h" +#include "gui/game/GameController.h" +#include "gui/game/GameModel.h" +#include "graphics/Renderer.h" +#include "simulation/ElementGraphics.h" + +static int renderModes(lua_State *L) +{ + auto *lsi = static_cast(commandInterface); + int args = lua_gettop(L); + if(args) + { + int size = 0; + luaL_checktype(L, 1, LUA_TTABLE); + size = lua_objlen(L, 1); + + std::vector renderModes; + for(int i = 1; i <= size; i++) + { + lua_rawgeti(L, 1, i); + renderModes.push_back(lua_tointeger(L, -1)); + lua_pop(L, 1); + } + lsi->ren->SetRenderMode(renderModes); + return 0; + } + else + { + lua_newtable(L); + std::vector renderModes = lsi->ren->GetRenderMode(); + int i = 1; + for(std::vector::iterator iter = renderModes.begin(), end = renderModes.end(); iter != end; ++iter) + { + lua_pushinteger(L, *iter); + lua_rawseti(L, -2, i++); + } + return 1; + } +} + +static int hud(lua_State *L) +{ + auto *lsi = static_cast(commandInterface); + int acount = lua_gettop(L); + if (acount == 0) + { + lua_pushboolean(L, lsi->gameController->GetHudEnable()); + return 1; + } + auto hudstate = lua_toboolean(L, 1); + lsi->gameController->SetHudEnable(hudstate); + return 0; +} + +static int debugHud(lua_State *L) +{ + auto *lsi = static_cast(commandInterface); + int acount = lua_gettop(L); + if (acount == 0) + { + lua_pushboolean(L, lsi->gameController->GetDebugHUD()); + return 1; + } + auto debug = lua_toboolean(L, 1); + lsi->gameController->SetDebugHUD(debug); + return 0; +} + +static int useDisplayPreset(lua_State *L) +{ + auto *lsi = static_cast(commandInterface); + int cmode = luaL_optint(L, 1, 3)+1; + if (cmode == 11) + cmode = 0; + if (cmode >= 0 && cmode <= 10) + lsi->gameController->LoadRenderPreset(cmode); + else + return luaL_error(L, "Invalid display mode"); + return 0; +} + +static int fireSize(lua_State *L) +{ + auto *lsi = static_cast(commandInterface); + if (lua_gettop(L) < 1) + { + lua_pushnumber(L, lsi->gameModel->GetRenderer()->GetFireIntensity()); + return 1; + } + float fireintensity = float(luaL_checknumber(L, 1)); + lsi->gameModel->GetRenderer()->prepare_alpha(CELL, fireintensity); + return 0; +} + +static int displayModes(lua_State *L) +{ + auto *lsi = static_cast(commandInterface); + int args = lua_gettop(L); + if(args) + { + int size = 0; + luaL_checktype(L, 1, LUA_TTABLE); + size = lua_objlen(L, 1); + + std::vector displayModes; + for(int i = 1; i <= size; i++) + { + lua_rawgeti(L, 1, i); + displayModes.push_back(lua_tointeger(L, -1)); + lua_pop(L, 1); + } + lsi->ren->SetDisplayMode(displayModes); + return 0; + } + else + { + lua_newtable(L); + std::vector displayModes = lsi->ren->GetDisplayMode(); + int i = 1; + for(std::vector::iterator iter = displayModes.begin(), end = displayModes.end(); iter != end; ++iter) + { + lua_pushinteger(L, *iter); + lua_rawseti(L, -2, i++); + } + return 1; + } +} + +static int colorMode(lua_State *L) +{ + auto *lsi = static_cast(commandInterface); + int args = lua_gettop(L); + if(args) + { + luaL_checktype(L, 1, LUA_TNUMBER); + lsi->ren->SetColourMode(lua_tointeger(L, 1)); + return 0; + } + else + { + lua_pushinteger(L, lsi->ren->GetColourMode()); + return 1; + } +} + +static int decorations(lua_State *L) +{ + auto *lsi = static_cast(commandInterface); + int acount = lua_gettop(L); + if (acount == 0) + { + lua_pushboolean(L, lsi->gameModel->GetDecoration()); + return 1; + } + int decostate = lua_toboolean(L, 1); + lsi->gameModel->SetDecoration(decostate); + lsi->gameModel->UpdateQuickOptions(); + return 0; +} + +static int grid(lua_State *L) +{ + auto *lsi = static_cast(commandInterface); + int acount = lua_gettop(L); + if (acount == 0) + { + lua_pushnumber(L, lsi->ren->GetGridSize()); + return 1; + } + int grid = luaL_optint(L, 1, -1); + lsi->ren->SetGridSize(grid); + return 0; +} + +static int showBrush(lua_State *L) +{ + auto *lsi = static_cast(commandInterface); + int acount = lua_gettop(L); + if (acount == 0) + { + lua_pushnumber(L, lsi->gameController->GetBrushEnable()); + return 1; + } + int brush = luaL_optint(L, 1, -1); + lsi->gameController->SetBrushEnable(brush); + return 0; +} + +static int depth3d(lua_State *L) +{ + return luaL_error(L, "This feature is no longer supported"); +} + +static int zoomEnabled(lua_State *L) +{ + auto *lsi = static_cast(commandInterface); + if (lua_gettop(L) == 0) + { + lua_pushboolean(L, lsi->ren->zoomEnabled); + return 1; + } + else + { + luaL_checktype(L, -1, LUA_TBOOLEAN); + lsi->ren->zoomEnabled = lua_toboolean(L, -1); + return 0; + } +} + +static int zoomWindow(lua_State *L) +{ + auto *lsi = static_cast(commandInterface); + auto *ren = lsi->ren; + if (lua_gettop(L) == 0) + { + ui::Point location = ren->zoomWindowPosition; + lua_pushnumber(L, location.X); + lua_pushnumber(L, location.Y); + lua_pushnumber(L, ren->ZFACTOR); + lua_pushnumber(L, ren->zoomScopeSize * ren->ZFACTOR); + return 4; + } + int x = luaL_optint(L, 1, 0); + int y = luaL_optint(L, 2, 0); + int f = luaL_optint(L, 3, 0); + if (f <= 0) + return luaL_error(L, "Zoom factor must be greater than 0"); + + // To prevent crash when zoom window is outside screen + if (x < 0 || y < 0 || ren->zoomScopeSize * f + x > XRES || ren->zoomScopeSize * f + y > YRES) + return luaL_error(L, "Zoom window outside of bounds"); + + ren->zoomWindowPosition = ui::Point(x, y); + ren->ZFACTOR = f; + return 0; +} + +static int zoomScope(lua_State *L) +{ + auto *lsi = static_cast(commandInterface); + auto *ren = lsi->ren; + if (lua_gettop(L) == 0) + { + ui::Point location = ren->zoomScopePosition; + lua_pushnumber(L, location.X); + lua_pushnumber(L, location.Y); + lua_pushnumber(L, ren->zoomScopeSize); + return 3; + } + int x = luaL_optint(L, 1, 0); + int y = luaL_optint(L, 2, 0); + int s = luaL_optint(L, 3, 0); + if (s <= 0) + return luaL_error(L, "Zoom scope size must be greater than 0"); + + // To prevent crash when zoom or scope window is outside screen + int windowEdgeRight = ren->ZFACTOR * s + ren->zoomWindowPosition.X; + int windowEdgeBottom = ren->ZFACTOR * s + ren->zoomWindowPosition.Y; + if (x < 0 || y < 0 || x + s > XRES || y + s > YRES) + return luaL_error(L, "Zoom scope outside of bounds"); + if (windowEdgeRight > XRES || windowEdgeBottom > YRES) + return luaL_error(L, "Zoom window outside of bounds"); + + ren->zoomScopePosition = ui::Point(x, y); + ren->zoomScopeSize = s; + return 0; +} + +void LuaRenderer::Open(lua_State *L) +{ + static const luaL_Reg reg[] = { +#define LFUNC(v) { #v, v } + LFUNC(renderModes), + LFUNC(displayModes), + LFUNC(colorMode), + LFUNC(decorations), + LFUNC(grid), + LFUNC(debugHud), + LFUNC(hud), + LFUNC(showBrush), + LFUNC(depth3d), + LFUNC(zoomEnabled), + LFUNC(zoomWindow), + LFUNC(zoomScope), + LFUNC(fireSize), + LFUNC(useDisplayPreset), +#undef LFUNC + { NULL, NULL } + }; + lua_newtable(L); + luaL_register(L, NULL, reg); +#define LCONST(v) lua_pushinteger(L, int(v)); lua_setfield(L, -2, #v) + LCONST(PMODE); + LCONST(PMODE_NONE); + LCONST(PMODE_FLAT); + LCONST(PMODE_BLOB); + LCONST(PMODE_BLUR); + LCONST(PMODE_GLOW); + LCONST(PMODE_SPARK); + LCONST(PMODE_FLARE); + LCONST(PMODE_LFLARE); + LCONST(PMODE_ADD); + LCONST(PMODE_BLEND); + LCONST(PSPEC_STICKMAN); + LCONST(OPTIONS); + LCONST(NO_DECO); + LCONST(DECO_FIRE); + LCONST(FIREMODE); + LCONST(FIRE_ADD); + LCONST(FIRE_BLEND); + LCONST(FIRE_SPARK); + LCONST(EFFECT); + LCONST(EFFECT_GRAVIN); + LCONST(EFFECT_GRAVOUT); + LCONST(EFFECT_LINES); + LCONST(EFFECT_DBGLINES); + LCONST(RENDER_EFFE); + LCONST(RENDER_FIRE); + LCONST(RENDER_GLOW); + LCONST(RENDER_BLUR); + LCONST(RENDER_BLOB); + LCONST(RENDER_BASC); + LCONST(RENDER_NONE); + LCONST(COLOUR_HEAT); + LCONST(COLOUR_LIFE); + LCONST(COLOUR_GRAD); + LCONST(COLOUR_BASC); + LCONST(COLOUR_DEFAULT); + LCONST(DISPLAY_AIRC); + LCONST(DISPLAY_AIRP); + LCONST(DISPLAY_AIRV); + LCONST(DISPLAY_AIRH); + LCONST(DISPLAY_AIR); + LCONST(DISPLAY_WARP); + LCONST(DISPLAY_PERS); + LCONST(DISPLAY_EFFE); +#undef LCONST + lua_pushvalue(L, -1); + lua_setglobal(L, "renderer"); + lua_setglobal(L, "ren"); +} diff --git a/src/lua/LuaSDLKeys.h b/src/lua/LuaSDLKeys.h index 2eb87d172..46b547403 100644 --- a/src/lua/LuaSDLKeys.h +++ b/src/lua/LuaSDLKeys.h @@ -2,517 +2,513 @@ #include "LuaCompat.h" #include -#define SETCONST(L, NAME)\ - lua_pushinteger(L, NAME);\ - lua_setfield(L, -2, #NAME) - -static void initLuaSDLKeys(lua_State *l) +static void initLuaSDLKeys(lua_State *L) { - SETCONST(l, SDL_SCANCODE_UNKNOWN); - SETCONST(l, SDL_SCANCODE_A); - SETCONST(l, SDL_SCANCODE_B); - SETCONST(l, SDL_SCANCODE_C); - SETCONST(l, SDL_SCANCODE_D); - SETCONST(l, SDL_SCANCODE_E); - SETCONST(l, SDL_SCANCODE_F); - SETCONST(l, SDL_SCANCODE_G); - SETCONST(l, SDL_SCANCODE_H); - SETCONST(l, SDL_SCANCODE_I); - SETCONST(l, SDL_SCANCODE_J); - SETCONST(l, SDL_SCANCODE_K); - SETCONST(l, SDL_SCANCODE_L); - SETCONST(l, SDL_SCANCODE_M); - SETCONST(l, SDL_SCANCODE_N); - SETCONST(l, SDL_SCANCODE_O); - SETCONST(l, SDL_SCANCODE_P); - SETCONST(l, SDL_SCANCODE_Q); - SETCONST(l, SDL_SCANCODE_R); - SETCONST(l, SDL_SCANCODE_S); - SETCONST(l, SDL_SCANCODE_T); - SETCONST(l, SDL_SCANCODE_U); - SETCONST(l, SDL_SCANCODE_V); - SETCONST(l, SDL_SCANCODE_W); - SETCONST(l, SDL_SCANCODE_X); - SETCONST(l, SDL_SCANCODE_Y); - SETCONST(l, SDL_SCANCODE_Z); - SETCONST(l, SDL_SCANCODE_1); - SETCONST(l, SDL_SCANCODE_2); - SETCONST(l, SDL_SCANCODE_3); - SETCONST(l, SDL_SCANCODE_4); - SETCONST(l, SDL_SCANCODE_5); - SETCONST(l, SDL_SCANCODE_6); - SETCONST(l, SDL_SCANCODE_7); - SETCONST(l, SDL_SCANCODE_8); - SETCONST(l, SDL_SCANCODE_9); - SETCONST(l, SDL_SCANCODE_0); - SETCONST(l, SDL_SCANCODE_RETURN); - SETCONST(l, SDL_SCANCODE_ESCAPE); - SETCONST(l, SDL_SCANCODE_BACKSPACE); - SETCONST(l, SDL_SCANCODE_TAB); - SETCONST(l, SDL_SCANCODE_SPACE); - SETCONST(l, SDL_SCANCODE_MINUS); - SETCONST(l, SDL_SCANCODE_EQUALS); - SETCONST(l, SDL_SCANCODE_LEFTBRACKET); - SETCONST(l, SDL_SCANCODE_RIGHTBRACKET); - SETCONST(l, SDL_SCANCODE_BACKSLASH); - SETCONST(l, SDL_SCANCODE_NONUSHASH); - SETCONST(l, SDL_SCANCODE_SEMICOLON); - SETCONST(l, SDL_SCANCODE_APOSTROPHE); - SETCONST(l, SDL_SCANCODE_GRAVE); - SETCONST(l, SDL_SCANCODE_COMMA); - SETCONST(l, SDL_SCANCODE_PERIOD); - SETCONST(l, SDL_SCANCODE_SLASH); - SETCONST(l, SDL_SCANCODE_CAPSLOCK); - SETCONST(l, SDL_SCANCODE_F1); - SETCONST(l, SDL_SCANCODE_F2); - SETCONST(l, SDL_SCANCODE_F3); - SETCONST(l, SDL_SCANCODE_F4); - SETCONST(l, SDL_SCANCODE_F5); - SETCONST(l, SDL_SCANCODE_F6); - SETCONST(l, SDL_SCANCODE_F7); - SETCONST(l, SDL_SCANCODE_F8); - SETCONST(l, SDL_SCANCODE_F9); - SETCONST(l, SDL_SCANCODE_F10); - SETCONST(l, SDL_SCANCODE_F11); - SETCONST(l, SDL_SCANCODE_F12); - SETCONST(l, SDL_SCANCODE_PRINTSCREEN); - SETCONST(l, SDL_SCANCODE_SCROLLLOCK); - SETCONST(l, SDL_SCANCODE_PAUSE); - SETCONST(l, SDL_SCANCODE_INSERT); - SETCONST(l, SDL_SCANCODE_HOME); - SETCONST(l, SDL_SCANCODE_PAGEUP); - SETCONST(l, SDL_SCANCODE_DELETE); - SETCONST(l, SDL_SCANCODE_END); - SETCONST(l, SDL_SCANCODE_PAGEDOWN); - SETCONST(l, SDL_SCANCODE_RIGHT); - SETCONST(l, SDL_SCANCODE_LEFT); - SETCONST(l, SDL_SCANCODE_DOWN); - SETCONST(l, SDL_SCANCODE_UP); - SETCONST(l, SDL_SCANCODE_NUMLOCKCLEAR); - SETCONST(l, SDL_SCANCODE_KP_DIVIDE); - SETCONST(l, SDL_SCANCODE_KP_MULTIPLY); - SETCONST(l, SDL_SCANCODE_KP_MINUS); - SETCONST(l, SDL_SCANCODE_KP_PLUS); - SETCONST(l, SDL_SCANCODE_KP_ENTER); - SETCONST(l, SDL_SCANCODE_KP_1); - SETCONST(l, SDL_SCANCODE_KP_2); - SETCONST(l, SDL_SCANCODE_KP_3); - SETCONST(l, SDL_SCANCODE_KP_4); - SETCONST(l, SDL_SCANCODE_KP_5); - SETCONST(l, SDL_SCANCODE_KP_6); - SETCONST(l, SDL_SCANCODE_KP_7); - SETCONST(l, SDL_SCANCODE_KP_8); - SETCONST(l, SDL_SCANCODE_KP_9); - SETCONST(l, SDL_SCANCODE_KP_0); - SETCONST(l, SDL_SCANCODE_KP_PERIOD); - SETCONST(l, SDL_SCANCODE_NONUSBACKSLASH); - SETCONST(l, SDL_SCANCODE_APPLICATION); - SETCONST(l, SDL_SCANCODE_POWER); - SETCONST(l, SDL_SCANCODE_KP_EQUALS); - SETCONST(l, SDL_SCANCODE_F13); - SETCONST(l, SDL_SCANCODE_F14); - SETCONST(l, SDL_SCANCODE_F15); - SETCONST(l, SDL_SCANCODE_F16); - SETCONST(l, SDL_SCANCODE_F17); - SETCONST(l, SDL_SCANCODE_F18); - SETCONST(l, SDL_SCANCODE_F19); - SETCONST(l, SDL_SCANCODE_F20); - SETCONST(l, SDL_SCANCODE_F21); - SETCONST(l, SDL_SCANCODE_F22); - SETCONST(l, SDL_SCANCODE_F23); - SETCONST(l, SDL_SCANCODE_F24); - SETCONST(l, SDL_SCANCODE_EXECUTE); - SETCONST(l, SDL_SCANCODE_HELP); - SETCONST(l, SDL_SCANCODE_MENU); - SETCONST(l, SDL_SCANCODE_SELECT); - SETCONST(l, SDL_SCANCODE_STOP); - SETCONST(l, SDL_SCANCODE_AGAIN); - SETCONST(l, SDL_SCANCODE_UNDO); - SETCONST(l, SDL_SCANCODE_CUT); - SETCONST(l, SDL_SCANCODE_COPY); - SETCONST(l, SDL_SCANCODE_PASTE); - SETCONST(l, SDL_SCANCODE_FIND); - SETCONST(l, SDL_SCANCODE_MUTE); - SETCONST(l, SDL_SCANCODE_VOLUMEUP); - SETCONST(l, SDL_SCANCODE_VOLUMEDOWN); - SETCONST(l, SDL_SCANCODE_KP_COMMA); - SETCONST(l, SDL_SCANCODE_KP_EQUALSAS400); - SETCONST(l, SDL_SCANCODE_INTERNATIONAL1); - SETCONST(l, SDL_SCANCODE_INTERNATIONAL2); - SETCONST(l, SDL_SCANCODE_INTERNATIONAL3); - SETCONST(l, SDL_SCANCODE_INTERNATIONAL4); - SETCONST(l, SDL_SCANCODE_INTERNATIONAL5); - SETCONST(l, SDL_SCANCODE_INTERNATIONAL6); - SETCONST(l, SDL_SCANCODE_INTERNATIONAL7); - SETCONST(l, SDL_SCANCODE_INTERNATIONAL8); - SETCONST(l, SDL_SCANCODE_INTERNATIONAL9); - SETCONST(l, SDL_SCANCODE_LANG1); - SETCONST(l, SDL_SCANCODE_LANG2); - SETCONST(l, SDL_SCANCODE_LANG3); - SETCONST(l, SDL_SCANCODE_LANG4); - SETCONST(l, SDL_SCANCODE_LANG5); - SETCONST(l, SDL_SCANCODE_LANG6); - SETCONST(l, SDL_SCANCODE_LANG7); - SETCONST(l, SDL_SCANCODE_LANG8); - SETCONST(l, SDL_SCANCODE_LANG9); - SETCONST(l, SDL_SCANCODE_ALTERASE); - SETCONST(l, SDL_SCANCODE_SYSREQ); - SETCONST(l, SDL_SCANCODE_CANCEL); - SETCONST(l, SDL_SCANCODE_CLEAR); - SETCONST(l, SDL_SCANCODE_PRIOR); - SETCONST(l, SDL_SCANCODE_RETURN2); - SETCONST(l, SDL_SCANCODE_SEPARATOR); - SETCONST(l, SDL_SCANCODE_OUT); - SETCONST(l, SDL_SCANCODE_OPER); - SETCONST(l, SDL_SCANCODE_CLEARAGAIN); - SETCONST(l, SDL_SCANCODE_CRSEL); - SETCONST(l, SDL_SCANCODE_EXSEL); - SETCONST(l, SDL_SCANCODE_KP_00); - SETCONST(l, SDL_SCANCODE_KP_000); - SETCONST(l, SDL_SCANCODE_THOUSANDSSEPARATOR); - SETCONST(l, SDL_SCANCODE_DECIMALSEPARATOR); - SETCONST(l, SDL_SCANCODE_CURRENCYUNIT); - SETCONST(l, SDL_SCANCODE_CURRENCYSUBUNIT); - SETCONST(l, SDL_SCANCODE_KP_LEFTPAREN); - SETCONST(l, SDL_SCANCODE_KP_RIGHTPAREN); - SETCONST(l, SDL_SCANCODE_KP_LEFTBRACE); - SETCONST(l, SDL_SCANCODE_KP_RIGHTBRACE); - SETCONST(l, SDL_SCANCODE_KP_TAB); - SETCONST(l, SDL_SCANCODE_KP_BACKSPACE); - SETCONST(l, SDL_SCANCODE_KP_A); - SETCONST(l, SDL_SCANCODE_KP_B); - SETCONST(l, SDL_SCANCODE_KP_C); - SETCONST(l, SDL_SCANCODE_KP_D); - SETCONST(l, SDL_SCANCODE_KP_E); - SETCONST(l, SDL_SCANCODE_KP_F); - SETCONST(l, SDL_SCANCODE_KP_XOR); - SETCONST(l, SDL_SCANCODE_KP_POWER); - SETCONST(l, SDL_SCANCODE_KP_PERCENT); - SETCONST(l, SDL_SCANCODE_KP_LESS); - SETCONST(l, SDL_SCANCODE_KP_GREATER); - SETCONST(l, SDL_SCANCODE_KP_AMPERSAND); - SETCONST(l, SDL_SCANCODE_KP_DBLAMPERSAND); - SETCONST(l, SDL_SCANCODE_KP_VERTICALBAR); - SETCONST(l, SDL_SCANCODE_KP_DBLVERTICALBAR); - SETCONST(l, SDL_SCANCODE_KP_COLON); - SETCONST(l, SDL_SCANCODE_KP_HASH); - SETCONST(l, SDL_SCANCODE_KP_SPACE); - SETCONST(l, SDL_SCANCODE_KP_AT); - SETCONST(l, SDL_SCANCODE_KP_EXCLAM); - SETCONST(l, SDL_SCANCODE_KP_MEMSTORE); - SETCONST(l, SDL_SCANCODE_KP_MEMRECALL); - SETCONST(l, SDL_SCANCODE_KP_MEMCLEAR); - SETCONST(l, SDL_SCANCODE_KP_MEMADD); - SETCONST(l, SDL_SCANCODE_KP_MEMSUBTRACT); - SETCONST(l, SDL_SCANCODE_KP_MEMMULTIPLY); - SETCONST(l, SDL_SCANCODE_KP_MEMDIVIDE); - SETCONST(l, SDL_SCANCODE_KP_PLUSMINUS); - SETCONST(l, SDL_SCANCODE_KP_CLEAR); - SETCONST(l, SDL_SCANCODE_KP_CLEARENTRY); - SETCONST(l, SDL_SCANCODE_KP_BINARY); - SETCONST(l, SDL_SCANCODE_KP_OCTAL); - SETCONST(l, SDL_SCANCODE_KP_DECIMAL); - SETCONST(l, SDL_SCANCODE_KP_HEXADECIMAL); - SETCONST(l, SDL_SCANCODE_LCTRL); - SETCONST(l, SDL_SCANCODE_LSHIFT); - SETCONST(l, SDL_SCANCODE_LALT); - SETCONST(l, SDL_SCANCODE_LGUI); - SETCONST(l, SDL_SCANCODE_RCTRL); - SETCONST(l, SDL_SCANCODE_RSHIFT); - SETCONST(l, SDL_SCANCODE_RALT); - SETCONST(l, SDL_SCANCODE_RGUI); - SETCONST(l, SDL_SCANCODE_MODE); - SETCONST(l, SDL_SCANCODE_AUDIONEXT); - SETCONST(l, SDL_SCANCODE_AUDIOPREV); - SETCONST(l, SDL_SCANCODE_AUDIOSTOP); - SETCONST(l, SDL_SCANCODE_AUDIOPLAY); - SETCONST(l, SDL_SCANCODE_AUDIOMUTE); - SETCONST(l, SDL_SCANCODE_MEDIASELECT); - SETCONST(l, SDL_SCANCODE_WWW); - SETCONST(l, SDL_SCANCODE_MAIL); - SETCONST(l, SDL_SCANCODE_CALCULATOR); - SETCONST(l, SDL_SCANCODE_COMPUTER); - SETCONST(l, SDL_SCANCODE_AC_SEARCH); - SETCONST(l, SDL_SCANCODE_AC_HOME); - SETCONST(l, SDL_SCANCODE_AC_BACK); - SETCONST(l, SDL_SCANCODE_AC_FORWARD); - SETCONST(l, SDL_SCANCODE_AC_STOP); - SETCONST(l, SDL_SCANCODE_AC_REFRESH); - SETCONST(l, SDL_SCANCODE_AC_BOOKMARKS); - SETCONST(l, SDL_SCANCODE_BRIGHTNESSDOWN); - SETCONST(l, SDL_SCANCODE_BRIGHTNESSUP); - SETCONST(l, SDL_SCANCODE_DISPLAYSWITCH); - SETCONST(l, SDL_SCANCODE_KBDILLUMTOGGLE); - SETCONST(l, SDL_SCANCODE_KBDILLUMDOWN); - SETCONST(l, SDL_SCANCODE_KBDILLUMUP); - SETCONST(l, SDL_SCANCODE_EJECT); - SETCONST(l, SDL_SCANCODE_SLEEP); - SETCONST(l, SDL_SCANCODE_APP1); - SETCONST(l, SDL_SCANCODE_APP2); - SETCONST(l, SDL_SCANCODE_AUDIOREWIND); - SETCONST(l, SDL_SCANCODE_AUDIOFASTFORWARD); - SETCONST(l, SDL_NUM_SCANCODES); - SETCONST(l, SDLK_UNKNOWN); - SETCONST(l, SDLK_RETURN); - SETCONST(l, SDLK_ESCAPE); - SETCONST(l, SDLK_BACKSPACE); - SETCONST(l, SDLK_TAB); - SETCONST(l, SDLK_SPACE); - SETCONST(l, SDLK_EXCLAIM); - SETCONST(l, SDLK_QUOTEDBL); - SETCONST(l, SDLK_HASH); - SETCONST(l, SDLK_PERCENT); - SETCONST(l, SDLK_DOLLAR); - SETCONST(l, SDLK_AMPERSAND); - SETCONST(l, SDLK_QUOTE); - SETCONST(l, SDLK_LEFTPAREN); - SETCONST(l, SDLK_RIGHTPAREN); - SETCONST(l, SDLK_ASTERISK); - SETCONST(l, SDLK_PLUS); - SETCONST(l, SDLK_COMMA); - SETCONST(l, SDLK_MINUS); - SETCONST(l, SDLK_PERIOD); - SETCONST(l, SDLK_SLASH); - SETCONST(l, SDLK_0); - SETCONST(l, SDLK_1); - SETCONST(l, SDLK_2); - SETCONST(l, SDLK_3); - SETCONST(l, SDLK_4); - SETCONST(l, SDLK_5); - SETCONST(l, SDLK_6); - SETCONST(l, SDLK_7); - SETCONST(l, SDLK_8); - SETCONST(l, SDLK_9); - SETCONST(l, SDLK_COLON); - SETCONST(l, SDLK_SEMICOLON); - SETCONST(l, SDLK_LESS); - SETCONST(l, SDLK_EQUALS); - SETCONST(l, SDLK_GREATER); - SETCONST(l, SDLK_QUESTION); - SETCONST(l, SDLK_AT); - SETCONST(l, SDLK_LEFTBRACKET); - SETCONST(l, SDLK_BACKSLASH); - SETCONST(l, SDLK_RIGHTBRACKET); - SETCONST(l, SDLK_CARET); - SETCONST(l, SDLK_UNDERSCORE); - SETCONST(l, SDLK_BACKQUOTE); - SETCONST(l, SDLK_a); - SETCONST(l, SDLK_b); - SETCONST(l, SDLK_c); - SETCONST(l, SDLK_d); - SETCONST(l, SDLK_e); - SETCONST(l, SDLK_f); - SETCONST(l, SDLK_g); - SETCONST(l, SDLK_h); - SETCONST(l, SDLK_i); - SETCONST(l, SDLK_j); - SETCONST(l, SDLK_k); - SETCONST(l, SDLK_l); - SETCONST(l, SDLK_m); - SETCONST(l, SDLK_n); - SETCONST(l, SDLK_o); - SETCONST(l, SDLK_p); - SETCONST(l, SDLK_q); - SETCONST(l, SDLK_r); - SETCONST(l, SDLK_s); - SETCONST(l, SDLK_t); - SETCONST(l, SDLK_u); - SETCONST(l, SDLK_v); - SETCONST(l, SDLK_w); - SETCONST(l, SDLK_x); - SETCONST(l, SDLK_y); - SETCONST(l, SDLK_z); - SETCONST(l, SDLK_CAPSLOCK); - SETCONST(l, SDLK_F1); - SETCONST(l, SDLK_F2); - SETCONST(l, SDLK_F3); - SETCONST(l, SDLK_F4); - SETCONST(l, SDLK_F5); - SETCONST(l, SDLK_F6); - SETCONST(l, SDLK_F7); - SETCONST(l, SDLK_F8); - SETCONST(l, SDLK_F9); - SETCONST(l, SDLK_F10); - SETCONST(l, SDLK_F11); - SETCONST(l, SDLK_F12); - SETCONST(l, SDLK_PRINTSCREEN); - SETCONST(l, SDLK_SCROLLLOCK); - SETCONST(l, SDLK_PAUSE); - SETCONST(l, SDLK_INSERT); - SETCONST(l, SDLK_HOME); - SETCONST(l, SDLK_PAGEUP); - SETCONST(l, SDLK_DELETE); - SETCONST(l, SDLK_END); - SETCONST(l, SDLK_PAGEDOWN); - SETCONST(l, SDLK_RIGHT); - SETCONST(l, SDLK_LEFT); - SETCONST(l, SDLK_DOWN); - SETCONST(l, SDLK_UP); - SETCONST(l, SDLK_NUMLOCKCLEAR); - SETCONST(l, SDLK_KP_DIVIDE); - SETCONST(l, SDLK_KP_MULTIPLY); - SETCONST(l, SDLK_KP_MINUS); - SETCONST(l, SDLK_KP_PLUS); - SETCONST(l, SDLK_KP_ENTER); - SETCONST(l, SDLK_KP_1); - SETCONST(l, SDLK_KP_2); - SETCONST(l, SDLK_KP_3); - SETCONST(l, SDLK_KP_4); - SETCONST(l, SDLK_KP_5); - SETCONST(l, SDLK_KP_6); - SETCONST(l, SDLK_KP_7); - SETCONST(l, SDLK_KP_8); - SETCONST(l, SDLK_KP_9); - SETCONST(l, SDLK_KP_0); - SETCONST(l, SDLK_KP_PERIOD); - SETCONST(l, SDLK_APPLICATION); - SETCONST(l, SDLK_POWER); - SETCONST(l, SDLK_KP_EQUALS); - SETCONST(l, SDLK_F13); - SETCONST(l, SDLK_F14); - SETCONST(l, SDLK_F15); - SETCONST(l, SDLK_F16); - SETCONST(l, SDLK_F17); - SETCONST(l, SDLK_F18); - SETCONST(l, SDLK_F19); - SETCONST(l, SDLK_F20); - SETCONST(l, SDLK_F21); - SETCONST(l, SDLK_F22); - SETCONST(l, SDLK_F23); - SETCONST(l, SDLK_F24); - SETCONST(l, SDLK_EXECUTE); - SETCONST(l, SDLK_HELP); - SETCONST(l, SDLK_MENU); - SETCONST(l, SDLK_SELECT); - SETCONST(l, SDLK_STOP); - SETCONST(l, SDLK_AGAIN); - SETCONST(l, SDLK_UNDO); - SETCONST(l, SDLK_CUT); - SETCONST(l, SDLK_COPY); - SETCONST(l, SDLK_PASTE); - SETCONST(l, SDLK_FIND); - SETCONST(l, SDLK_MUTE); - SETCONST(l, SDLK_VOLUMEUP); - SETCONST(l, SDLK_VOLUMEDOWN); - SETCONST(l, SDLK_KP_COMMA); - SETCONST(l, SDLK_KP_EQUALSAS400); - SETCONST(l, SDLK_ALTERASE); - SETCONST(l, SDLK_SYSREQ); - SETCONST(l, SDLK_CANCEL); - SETCONST(l, SDLK_CLEAR); - SETCONST(l, SDLK_PRIOR); - SETCONST(l, SDLK_RETURN2); - SETCONST(l, SDLK_SEPARATOR); - SETCONST(l, SDLK_OUT); - SETCONST(l, SDLK_OPER); - SETCONST(l, SDLK_CLEARAGAIN); - SETCONST(l, SDLK_CRSEL); - SETCONST(l, SDLK_EXSEL); - SETCONST(l, SDLK_KP_00); - SETCONST(l, SDLK_KP_000); - SETCONST(l, SDLK_THOUSANDSSEPARATOR); - SETCONST(l, SDLK_DECIMALSEPARATOR); - SETCONST(l, SDLK_CURRENCYUNIT); - SETCONST(l, SDLK_CURRENCYSUBUNIT); - SETCONST(l, SDLK_KP_LEFTPAREN); - SETCONST(l, SDLK_KP_RIGHTPAREN); - SETCONST(l, SDLK_KP_LEFTBRACE); - SETCONST(l, SDLK_KP_RIGHTBRACE); - SETCONST(l, SDLK_KP_TAB); - SETCONST(l, SDLK_KP_BACKSPACE); - SETCONST(l, SDLK_KP_A); - SETCONST(l, SDLK_KP_B); - SETCONST(l, SDLK_KP_C); - SETCONST(l, SDLK_KP_D); - SETCONST(l, SDLK_KP_E); - SETCONST(l, SDLK_KP_F); - SETCONST(l, SDLK_KP_XOR); - SETCONST(l, SDLK_KP_POWER); - SETCONST(l, SDLK_KP_PERCENT); - SETCONST(l, SDLK_KP_LESS); - SETCONST(l, SDLK_KP_GREATER); - SETCONST(l, SDLK_KP_AMPERSAND); - SETCONST(l, SDLK_KP_DBLAMPERSAND); - SETCONST(l, SDLK_KP_VERTICALBAR); - SETCONST(l, SDLK_KP_DBLVERTICALBAR); - SETCONST(l, SDLK_KP_COLON); - SETCONST(l, SDLK_KP_HASH); - SETCONST(l, SDLK_KP_SPACE); - SETCONST(l, SDLK_KP_AT); - SETCONST(l, SDLK_KP_EXCLAM); - SETCONST(l, SDLK_KP_MEMSTORE); - SETCONST(l, SDLK_KP_MEMRECALL); - SETCONST(l, SDLK_KP_MEMCLEAR); - SETCONST(l, SDLK_KP_MEMADD); - SETCONST(l, SDLK_KP_MEMSUBTRACT); - SETCONST(l, SDLK_KP_MEMMULTIPLY); - SETCONST(l, SDLK_KP_MEMDIVIDE); - SETCONST(l, SDLK_KP_PLUSMINUS); - SETCONST(l, SDLK_KP_CLEAR); - SETCONST(l, SDLK_KP_CLEARENTRY); - SETCONST(l, SDLK_KP_BINARY); - SETCONST(l, SDLK_KP_OCTAL); - SETCONST(l, SDLK_KP_DECIMAL); - SETCONST(l, SDLK_KP_HEXADECIMAL); - SETCONST(l, SDLK_LCTRL); - SETCONST(l, SDLK_LSHIFT); - SETCONST(l, SDLK_LALT); - SETCONST(l, SDLK_LGUI); - SETCONST(l, SDLK_RCTRL); - SETCONST(l, SDLK_RSHIFT); - SETCONST(l, SDLK_RALT); - SETCONST(l, SDLK_RGUI); - SETCONST(l, SDLK_MODE); - SETCONST(l, SDLK_AUDIONEXT); - SETCONST(l, SDLK_AUDIOPREV); - SETCONST(l, SDLK_AUDIOSTOP); - SETCONST(l, SDLK_AUDIOPLAY); - SETCONST(l, SDLK_AUDIOMUTE); - SETCONST(l, SDLK_MEDIASELECT); - SETCONST(l, SDLK_WWW); - SETCONST(l, SDLK_MAIL); - SETCONST(l, SDLK_CALCULATOR); - SETCONST(l, SDLK_COMPUTER); - SETCONST(l, SDLK_AC_SEARCH); - SETCONST(l, SDLK_AC_HOME); - SETCONST(l, SDLK_AC_BACK); - SETCONST(l, SDLK_AC_FORWARD); - SETCONST(l, SDLK_AC_STOP); - SETCONST(l, SDLK_AC_REFRESH); - SETCONST(l, SDLK_AC_BOOKMARKS); - SETCONST(l, SDLK_BRIGHTNESSDOWN); - SETCONST(l, SDLK_BRIGHTNESSUP); - SETCONST(l, SDLK_DISPLAYSWITCH); - SETCONST(l, SDLK_KBDILLUMTOGGLE); - SETCONST(l, SDLK_KBDILLUMDOWN); - SETCONST(l, SDLK_KBDILLUMUP); - SETCONST(l, SDLK_EJECT); - SETCONST(l, SDLK_SLEEP); - SETCONST(l, SDLK_APP1); - SETCONST(l, SDLK_APP2); - SETCONST(l, SDLK_AUDIOREWIND); - SETCONST(l, SDLK_AUDIOFASTFORWARD); - SETCONST(l, KMOD_NONE); - SETCONST(l, KMOD_LSHIFT); - SETCONST(l, KMOD_RSHIFT); - SETCONST(l, KMOD_LCTRL); - SETCONST(l, KMOD_RCTRL); - SETCONST(l, KMOD_LALT); - SETCONST(l, KMOD_RALT); - SETCONST(l, KMOD_LGUI); - SETCONST(l, KMOD_RGUI); - SETCONST(l, KMOD_NUM); - SETCONST(l, KMOD_CAPS); - SETCONST(l, KMOD_MODE); - SETCONST(l, KMOD_CTRL); - SETCONST(l, KMOD_SHIFT); - SETCONST(l, KMOD_ALT); - SETCONST(l, KMOD_GUI); - SETCONST(l, SDL_BUTTON_LEFT); - SETCONST(l, SDL_BUTTON_MIDDLE); - SETCONST(l, SDL_BUTTON_RIGHT); - SETCONST(l, SDL_BUTTON_X1); - SETCONST(l, SDL_BUTTON_X2); +#define LCONST(v) lua_pushinteger(L, int(v)); lua_setfield(L, -2, #v) + LCONST(SDL_SCANCODE_UNKNOWN); + LCONST(SDL_SCANCODE_A); + LCONST(SDL_SCANCODE_B); + LCONST(SDL_SCANCODE_C); + LCONST(SDL_SCANCODE_D); + LCONST(SDL_SCANCODE_E); + LCONST(SDL_SCANCODE_F); + LCONST(SDL_SCANCODE_G); + LCONST(SDL_SCANCODE_H); + LCONST(SDL_SCANCODE_I); + LCONST(SDL_SCANCODE_J); + LCONST(SDL_SCANCODE_K); + LCONST(SDL_SCANCODE_L); + LCONST(SDL_SCANCODE_M); + LCONST(SDL_SCANCODE_N); + LCONST(SDL_SCANCODE_O); + LCONST(SDL_SCANCODE_P); + LCONST(SDL_SCANCODE_Q); + LCONST(SDL_SCANCODE_R); + LCONST(SDL_SCANCODE_S); + LCONST(SDL_SCANCODE_T); + LCONST(SDL_SCANCODE_U); + LCONST(SDL_SCANCODE_V); + LCONST(SDL_SCANCODE_W); + LCONST(SDL_SCANCODE_X); + LCONST(SDL_SCANCODE_Y); + LCONST(SDL_SCANCODE_Z); + LCONST(SDL_SCANCODE_1); + LCONST(SDL_SCANCODE_2); + LCONST(SDL_SCANCODE_3); + LCONST(SDL_SCANCODE_4); + LCONST(SDL_SCANCODE_5); + LCONST(SDL_SCANCODE_6); + LCONST(SDL_SCANCODE_7); + LCONST(SDL_SCANCODE_8); + LCONST(SDL_SCANCODE_9); + LCONST(SDL_SCANCODE_0); + LCONST(SDL_SCANCODE_RETURN); + LCONST(SDL_SCANCODE_ESCAPE); + LCONST(SDL_SCANCODE_BACKSPACE); + LCONST(SDL_SCANCODE_TAB); + LCONST(SDL_SCANCODE_SPACE); + LCONST(SDL_SCANCODE_MINUS); + LCONST(SDL_SCANCODE_EQUALS); + LCONST(SDL_SCANCODE_LEFTBRACKET); + LCONST(SDL_SCANCODE_RIGHTBRACKET); + LCONST(SDL_SCANCODE_BACKSLASH); + LCONST(SDL_SCANCODE_NONUSHASH); + LCONST(SDL_SCANCODE_SEMICOLON); + LCONST(SDL_SCANCODE_APOSTROPHE); + LCONST(SDL_SCANCODE_GRAVE); + LCONST(SDL_SCANCODE_COMMA); + LCONST(SDL_SCANCODE_PERIOD); + LCONST(SDL_SCANCODE_SLASH); + LCONST(SDL_SCANCODE_CAPSLOCK); + LCONST(SDL_SCANCODE_F1); + LCONST(SDL_SCANCODE_F2); + LCONST(SDL_SCANCODE_F3); + LCONST(SDL_SCANCODE_F4); + LCONST(SDL_SCANCODE_F5); + LCONST(SDL_SCANCODE_F6); + LCONST(SDL_SCANCODE_F7); + LCONST(SDL_SCANCODE_F8); + LCONST(SDL_SCANCODE_F9); + LCONST(SDL_SCANCODE_F10); + LCONST(SDL_SCANCODE_F11); + LCONST(SDL_SCANCODE_F12); + LCONST(SDL_SCANCODE_PRINTSCREEN); + LCONST(SDL_SCANCODE_SCROLLLOCK); + LCONST(SDL_SCANCODE_PAUSE); + LCONST(SDL_SCANCODE_INSERT); + LCONST(SDL_SCANCODE_HOME); + LCONST(SDL_SCANCODE_PAGEUP); + LCONST(SDL_SCANCODE_DELETE); + LCONST(SDL_SCANCODE_END); + LCONST(SDL_SCANCODE_PAGEDOWN); + LCONST(SDL_SCANCODE_RIGHT); + LCONST(SDL_SCANCODE_LEFT); + LCONST(SDL_SCANCODE_DOWN); + LCONST(SDL_SCANCODE_UP); + LCONST(SDL_SCANCODE_NUMLOCKCLEAR); + LCONST(SDL_SCANCODE_KP_DIVIDE); + LCONST(SDL_SCANCODE_KP_MULTIPLY); + LCONST(SDL_SCANCODE_KP_MINUS); + LCONST(SDL_SCANCODE_KP_PLUS); + LCONST(SDL_SCANCODE_KP_ENTER); + LCONST(SDL_SCANCODE_KP_1); + LCONST(SDL_SCANCODE_KP_2); + LCONST(SDL_SCANCODE_KP_3); + LCONST(SDL_SCANCODE_KP_4); + LCONST(SDL_SCANCODE_KP_5); + LCONST(SDL_SCANCODE_KP_6); + LCONST(SDL_SCANCODE_KP_7); + LCONST(SDL_SCANCODE_KP_8); + LCONST(SDL_SCANCODE_KP_9); + LCONST(SDL_SCANCODE_KP_0); + LCONST(SDL_SCANCODE_KP_PERIOD); + LCONST(SDL_SCANCODE_NONUSBACKSLASH); + LCONST(SDL_SCANCODE_APPLICATION); + LCONST(SDL_SCANCODE_POWER); + LCONST(SDL_SCANCODE_KP_EQUALS); + LCONST(SDL_SCANCODE_F13); + LCONST(SDL_SCANCODE_F14); + LCONST(SDL_SCANCODE_F15); + LCONST(SDL_SCANCODE_F16); + LCONST(SDL_SCANCODE_F17); + LCONST(SDL_SCANCODE_F18); + LCONST(SDL_SCANCODE_F19); + LCONST(SDL_SCANCODE_F20); + LCONST(SDL_SCANCODE_F21); + LCONST(SDL_SCANCODE_F22); + LCONST(SDL_SCANCODE_F23); + LCONST(SDL_SCANCODE_F24); + LCONST(SDL_SCANCODE_EXECUTE); + LCONST(SDL_SCANCODE_HELP); + LCONST(SDL_SCANCODE_MENU); + LCONST(SDL_SCANCODE_SELECT); + LCONST(SDL_SCANCODE_STOP); + LCONST(SDL_SCANCODE_AGAIN); + LCONST(SDL_SCANCODE_UNDO); + LCONST(SDL_SCANCODE_CUT); + LCONST(SDL_SCANCODE_COPY); + LCONST(SDL_SCANCODE_PASTE); + LCONST(SDL_SCANCODE_FIND); + LCONST(SDL_SCANCODE_MUTE); + LCONST(SDL_SCANCODE_VOLUMEUP); + LCONST(SDL_SCANCODE_VOLUMEDOWN); + LCONST(SDL_SCANCODE_KP_COMMA); + LCONST(SDL_SCANCODE_KP_EQUALSAS400); + LCONST(SDL_SCANCODE_INTERNATIONAL1); + LCONST(SDL_SCANCODE_INTERNATIONAL2); + LCONST(SDL_SCANCODE_INTERNATIONAL3); + LCONST(SDL_SCANCODE_INTERNATIONAL4); + LCONST(SDL_SCANCODE_INTERNATIONAL5); + LCONST(SDL_SCANCODE_INTERNATIONAL6); + LCONST(SDL_SCANCODE_INTERNATIONAL7); + LCONST(SDL_SCANCODE_INTERNATIONAL8); + LCONST(SDL_SCANCODE_INTERNATIONAL9); + LCONST(SDL_SCANCODE_LANG1); + LCONST(SDL_SCANCODE_LANG2); + LCONST(SDL_SCANCODE_LANG3); + LCONST(SDL_SCANCODE_LANG4); + LCONST(SDL_SCANCODE_LANG5); + LCONST(SDL_SCANCODE_LANG6); + LCONST(SDL_SCANCODE_LANG7); + LCONST(SDL_SCANCODE_LANG8); + LCONST(SDL_SCANCODE_LANG9); + LCONST(SDL_SCANCODE_ALTERASE); + LCONST(SDL_SCANCODE_SYSREQ); + LCONST(SDL_SCANCODE_CANCEL); + LCONST(SDL_SCANCODE_CLEAR); + LCONST(SDL_SCANCODE_PRIOR); + LCONST(SDL_SCANCODE_RETURN2); + LCONST(SDL_SCANCODE_SEPARATOR); + LCONST(SDL_SCANCODE_OUT); + LCONST(SDL_SCANCODE_OPER); + LCONST(SDL_SCANCODE_CLEARAGAIN); + LCONST(SDL_SCANCODE_CRSEL); + LCONST(SDL_SCANCODE_EXSEL); + LCONST(SDL_SCANCODE_KP_00); + LCONST(SDL_SCANCODE_KP_000); + LCONST(SDL_SCANCODE_THOUSANDSSEPARATOR); + LCONST(SDL_SCANCODE_DECIMALSEPARATOR); + LCONST(SDL_SCANCODE_CURRENCYUNIT); + LCONST(SDL_SCANCODE_CURRENCYSUBUNIT); + LCONST(SDL_SCANCODE_KP_LEFTPAREN); + LCONST(SDL_SCANCODE_KP_RIGHTPAREN); + LCONST(SDL_SCANCODE_KP_LEFTBRACE); + LCONST(SDL_SCANCODE_KP_RIGHTBRACE); + LCONST(SDL_SCANCODE_KP_TAB); + LCONST(SDL_SCANCODE_KP_BACKSPACE); + LCONST(SDL_SCANCODE_KP_A); + LCONST(SDL_SCANCODE_KP_B); + LCONST(SDL_SCANCODE_KP_C); + LCONST(SDL_SCANCODE_KP_D); + LCONST(SDL_SCANCODE_KP_E); + LCONST(SDL_SCANCODE_KP_F); + LCONST(SDL_SCANCODE_KP_XOR); + LCONST(SDL_SCANCODE_KP_POWER); + LCONST(SDL_SCANCODE_KP_PERCENT); + LCONST(SDL_SCANCODE_KP_LESS); + LCONST(SDL_SCANCODE_KP_GREATER); + LCONST(SDL_SCANCODE_KP_AMPERSAND); + LCONST(SDL_SCANCODE_KP_DBLAMPERSAND); + LCONST(SDL_SCANCODE_KP_VERTICALBAR); + LCONST(SDL_SCANCODE_KP_DBLVERTICALBAR); + LCONST(SDL_SCANCODE_KP_COLON); + LCONST(SDL_SCANCODE_KP_HASH); + LCONST(SDL_SCANCODE_KP_SPACE); + LCONST(SDL_SCANCODE_KP_AT); + LCONST(SDL_SCANCODE_KP_EXCLAM); + LCONST(SDL_SCANCODE_KP_MEMSTORE); + LCONST(SDL_SCANCODE_KP_MEMRECALL); + LCONST(SDL_SCANCODE_KP_MEMCLEAR); + LCONST(SDL_SCANCODE_KP_MEMADD); + LCONST(SDL_SCANCODE_KP_MEMSUBTRACT); + LCONST(SDL_SCANCODE_KP_MEMMULTIPLY); + LCONST(SDL_SCANCODE_KP_MEMDIVIDE); + LCONST(SDL_SCANCODE_KP_PLUSMINUS); + LCONST(SDL_SCANCODE_KP_CLEAR); + LCONST(SDL_SCANCODE_KP_CLEARENTRY); + LCONST(SDL_SCANCODE_KP_BINARY); + LCONST(SDL_SCANCODE_KP_OCTAL); + LCONST(SDL_SCANCODE_KP_DECIMAL); + LCONST(SDL_SCANCODE_KP_HEXADECIMAL); + LCONST(SDL_SCANCODE_LCTRL); + LCONST(SDL_SCANCODE_LSHIFT); + LCONST(SDL_SCANCODE_LALT); + LCONST(SDL_SCANCODE_LGUI); + LCONST(SDL_SCANCODE_RCTRL); + LCONST(SDL_SCANCODE_RSHIFT); + LCONST(SDL_SCANCODE_RALT); + LCONST(SDL_SCANCODE_RGUI); + LCONST(SDL_SCANCODE_MODE); + LCONST(SDL_SCANCODE_AUDIONEXT); + LCONST(SDL_SCANCODE_AUDIOPREV); + LCONST(SDL_SCANCODE_AUDIOSTOP); + LCONST(SDL_SCANCODE_AUDIOPLAY); + LCONST(SDL_SCANCODE_AUDIOMUTE); + LCONST(SDL_SCANCODE_MEDIASELECT); + LCONST(SDL_SCANCODE_WWW); + LCONST(SDL_SCANCODE_MAIL); + LCONST(SDL_SCANCODE_CALCULATOR); + LCONST(SDL_SCANCODE_COMPUTER); + LCONST(SDL_SCANCODE_AC_SEARCH); + LCONST(SDL_SCANCODE_AC_HOME); + LCONST(SDL_SCANCODE_AC_BACK); + LCONST(SDL_SCANCODE_AC_FORWARD); + LCONST(SDL_SCANCODE_AC_STOP); + LCONST(SDL_SCANCODE_AC_REFRESH); + LCONST(SDL_SCANCODE_AC_BOOKMARKS); + LCONST(SDL_SCANCODE_BRIGHTNESSDOWN); + LCONST(SDL_SCANCODE_BRIGHTNESSUP); + LCONST(SDL_SCANCODE_DISPLAYSWITCH); + LCONST(SDL_SCANCODE_KBDILLUMTOGGLE); + LCONST(SDL_SCANCODE_KBDILLUMDOWN); + LCONST(SDL_SCANCODE_KBDILLUMUP); + LCONST(SDL_SCANCODE_EJECT); + LCONST(SDL_SCANCODE_SLEEP); + LCONST(SDL_SCANCODE_APP1); + LCONST(SDL_SCANCODE_APP2); + LCONST(SDL_SCANCODE_AUDIOREWIND); + LCONST(SDL_SCANCODE_AUDIOFASTFORWARD); + LCONST(SDL_NUM_SCANCODES); + LCONST(SDLK_UNKNOWN); + LCONST(SDLK_RETURN); + LCONST(SDLK_ESCAPE); + LCONST(SDLK_BACKSPACE); + LCONST(SDLK_TAB); + LCONST(SDLK_SPACE); + LCONST(SDLK_EXCLAIM); + LCONST(SDLK_QUOTEDBL); + LCONST(SDLK_HASH); + LCONST(SDLK_PERCENT); + LCONST(SDLK_DOLLAR); + LCONST(SDLK_AMPERSAND); + LCONST(SDLK_QUOTE); + LCONST(SDLK_LEFTPAREN); + LCONST(SDLK_RIGHTPAREN); + LCONST(SDLK_ASTERISK); + LCONST(SDLK_PLUS); + LCONST(SDLK_COMMA); + LCONST(SDLK_MINUS); + LCONST(SDLK_PERIOD); + LCONST(SDLK_SLASH); + LCONST(SDLK_0); + LCONST(SDLK_1); + LCONST(SDLK_2); + LCONST(SDLK_3); + LCONST(SDLK_4); + LCONST(SDLK_5); + LCONST(SDLK_6); + LCONST(SDLK_7); + LCONST(SDLK_8); + LCONST(SDLK_9); + LCONST(SDLK_COLON); + LCONST(SDLK_SEMICOLON); + LCONST(SDLK_LESS); + LCONST(SDLK_EQUALS); + LCONST(SDLK_GREATER); + LCONST(SDLK_QUESTION); + LCONST(SDLK_AT); + LCONST(SDLK_LEFTBRACKET); + LCONST(SDLK_BACKSLASH); + LCONST(SDLK_RIGHTBRACKET); + LCONST(SDLK_CARET); + LCONST(SDLK_UNDERSCORE); + LCONST(SDLK_BACKQUOTE); + LCONST(SDLK_a); + LCONST(SDLK_b); + LCONST(SDLK_c); + LCONST(SDLK_d); + LCONST(SDLK_e); + LCONST(SDLK_f); + LCONST(SDLK_g); + LCONST(SDLK_h); + LCONST(SDLK_i); + LCONST(SDLK_j); + LCONST(SDLK_k); + LCONST(SDLK_l); + LCONST(SDLK_m); + LCONST(SDLK_n); + LCONST(SDLK_o); + LCONST(SDLK_p); + LCONST(SDLK_q); + LCONST(SDLK_r); + LCONST(SDLK_s); + LCONST(SDLK_t); + LCONST(SDLK_u); + LCONST(SDLK_v); + LCONST(SDLK_w); + LCONST(SDLK_x); + LCONST(SDLK_y); + LCONST(SDLK_z); + LCONST(SDLK_CAPSLOCK); + LCONST(SDLK_F1); + LCONST(SDLK_F2); + LCONST(SDLK_F3); + LCONST(SDLK_F4); + LCONST(SDLK_F5); + LCONST(SDLK_F6); + LCONST(SDLK_F7); + LCONST(SDLK_F8); + LCONST(SDLK_F9); + LCONST(SDLK_F10); + LCONST(SDLK_F11); + LCONST(SDLK_F12); + LCONST(SDLK_PRINTSCREEN); + LCONST(SDLK_SCROLLLOCK); + LCONST(SDLK_PAUSE); + LCONST(SDLK_INSERT); + LCONST(SDLK_HOME); + LCONST(SDLK_PAGEUP); + LCONST(SDLK_DELETE); + LCONST(SDLK_END); + LCONST(SDLK_PAGEDOWN); + LCONST(SDLK_RIGHT); + LCONST(SDLK_LEFT); + LCONST(SDLK_DOWN); + LCONST(SDLK_UP); + LCONST(SDLK_NUMLOCKCLEAR); + LCONST(SDLK_KP_DIVIDE); + LCONST(SDLK_KP_MULTIPLY); + LCONST(SDLK_KP_MINUS); + LCONST(SDLK_KP_PLUS); + LCONST(SDLK_KP_ENTER); + LCONST(SDLK_KP_1); + LCONST(SDLK_KP_2); + LCONST(SDLK_KP_3); + LCONST(SDLK_KP_4); + LCONST(SDLK_KP_5); + LCONST(SDLK_KP_6); + LCONST(SDLK_KP_7); + LCONST(SDLK_KP_8); + LCONST(SDLK_KP_9); + LCONST(SDLK_KP_0); + LCONST(SDLK_KP_PERIOD); + LCONST(SDLK_APPLICATION); + LCONST(SDLK_POWER); + LCONST(SDLK_KP_EQUALS); + LCONST(SDLK_F13); + LCONST(SDLK_F14); + LCONST(SDLK_F15); + LCONST(SDLK_F16); + LCONST(SDLK_F17); + LCONST(SDLK_F18); + LCONST(SDLK_F19); + LCONST(SDLK_F20); + LCONST(SDLK_F21); + LCONST(SDLK_F22); + LCONST(SDLK_F23); + LCONST(SDLK_F24); + LCONST(SDLK_EXECUTE); + LCONST(SDLK_HELP); + LCONST(SDLK_MENU); + LCONST(SDLK_SELECT); + LCONST(SDLK_STOP); + LCONST(SDLK_AGAIN); + LCONST(SDLK_UNDO); + LCONST(SDLK_CUT); + LCONST(SDLK_COPY); + LCONST(SDLK_PASTE); + LCONST(SDLK_FIND); + LCONST(SDLK_MUTE); + LCONST(SDLK_VOLUMEUP); + LCONST(SDLK_VOLUMEDOWN); + LCONST(SDLK_KP_COMMA); + LCONST(SDLK_KP_EQUALSAS400); + LCONST(SDLK_ALTERASE); + LCONST(SDLK_SYSREQ); + LCONST(SDLK_CANCEL); + LCONST(SDLK_CLEAR); + LCONST(SDLK_PRIOR); + LCONST(SDLK_RETURN2); + LCONST(SDLK_SEPARATOR); + LCONST(SDLK_OUT); + LCONST(SDLK_OPER); + LCONST(SDLK_CLEARAGAIN); + LCONST(SDLK_CRSEL); + LCONST(SDLK_EXSEL); + LCONST(SDLK_KP_00); + LCONST(SDLK_KP_000); + LCONST(SDLK_THOUSANDSSEPARATOR); + LCONST(SDLK_DECIMALSEPARATOR); + LCONST(SDLK_CURRENCYUNIT); + LCONST(SDLK_CURRENCYSUBUNIT); + LCONST(SDLK_KP_LEFTPAREN); + LCONST(SDLK_KP_RIGHTPAREN); + LCONST(SDLK_KP_LEFTBRACE); + LCONST(SDLK_KP_RIGHTBRACE); + LCONST(SDLK_KP_TAB); + LCONST(SDLK_KP_BACKSPACE); + LCONST(SDLK_KP_A); + LCONST(SDLK_KP_B); + LCONST(SDLK_KP_C); + LCONST(SDLK_KP_D); + LCONST(SDLK_KP_E); + LCONST(SDLK_KP_F); + LCONST(SDLK_KP_XOR); + LCONST(SDLK_KP_POWER); + LCONST(SDLK_KP_PERCENT); + LCONST(SDLK_KP_LESS); + LCONST(SDLK_KP_GREATER); + LCONST(SDLK_KP_AMPERSAND); + LCONST(SDLK_KP_DBLAMPERSAND); + LCONST(SDLK_KP_VERTICALBAR); + LCONST(SDLK_KP_DBLVERTICALBAR); + LCONST(SDLK_KP_COLON); + LCONST(SDLK_KP_HASH); + LCONST(SDLK_KP_SPACE); + LCONST(SDLK_KP_AT); + LCONST(SDLK_KP_EXCLAM); + LCONST(SDLK_KP_MEMSTORE); + LCONST(SDLK_KP_MEMRECALL); + LCONST(SDLK_KP_MEMCLEAR); + LCONST(SDLK_KP_MEMADD); + LCONST(SDLK_KP_MEMSUBTRACT); + LCONST(SDLK_KP_MEMMULTIPLY); + LCONST(SDLK_KP_MEMDIVIDE); + LCONST(SDLK_KP_PLUSMINUS); + LCONST(SDLK_KP_CLEAR); + LCONST(SDLK_KP_CLEARENTRY); + LCONST(SDLK_KP_BINARY); + LCONST(SDLK_KP_OCTAL); + LCONST(SDLK_KP_DECIMAL); + LCONST(SDLK_KP_HEXADECIMAL); + LCONST(SDLK_LCTRL); + LCONST(SDLK_LSHIFT); + LCONST(SDLK_LALT); + LCONST(SDLK_LGUI); + LCONST(SDLK_RCTRL); + LCONST(SDLK_RSHIFT); + LCONST(SDLK_RALT); + LCONST(SDLK_RGUI); + LCONST(SDLK_MODE); + LCONST(SDLK_AUDIONEXT); + LCONST(SDLK_AUDIOPREV); + LCONST(SDLK_AUDIOSTOP); + LCONST(SDLK_AUDIOPLAY); + LCONST(SDLK_AUDIOMUTE); + LCONST(SDLK_MEDIASELECT); + LCONST(SDLK_WWW); + LCONST(SDLK_MAIL); + LCONST(SDLK_CALCULATOR); + LCONST(SDLK_COMPUTER); + LCONST(SDLK_AC_SEARCH); + LCONST(SDLK_AC_HOME); + LCONST(SDLK_AC_BACK); + LCONST(SDLK_AC_FORWARD); + LCONST(SDLK_AC_STOP); + LCONST(SDLK_AC_REFRESH); + LCONST(SDLK_AC_BOOKMARKS); + LCONST(SDLK_BRIGHTNESSDOWN); + LCONST(SDLK_BRIGHTNESSUP); + LCONST(SDLK_DISPLAYSWITCH); + LCONST(SDLK_KBDILLUMTOGGLE); + LCONST(SDLK_KBDILLUMDOWN); + LCONST(SDLK_KBDILLUMUP); + LCONST(SDLK_EJECT); + LCONST(SDLK_SLEEP); + LCONST(SDLK_APP1); + LCONST(SDLK_APP2); + LCONST(SDLK_AUDIOREWIND); + LCONST(SDLK_AUDIOFASTFORWARD); + LCONST(KMOD_NONE); + LCONST(KMOD_LSHIFT); + LCONST(KMOD_RSHIFT); + LCONST(KMOD_LCTRL); + LCONST(KMOD_RCTRL); + LCONST(KMOD_LALT); + LCONST(KMOD_RALT); + LCONST(KMOD_LGUI); + LCONST(KMOD_RGUI); + LCONST(KMOD_NUM); + LCONST(KMOD_CAPS); + LCONST(KMOD_MODE); + LCONST(KMOD_CTRL); + LCONST(KMOD_SHIFT); + LCONST(KMOD_ALT); + LCONST(KMOD_GUI); + LCONST(SDL_BUTTON_LEFT); + LCONST(SDL_BUTTON_MIDDLE); + LCONST(SDL_BUTTON_RIGHT); + LCONST(SDL_BUTTON_X1); + LCONST(SDL_BUTTON_X2); +#undef LCONST } - -#undef SETCONST diff --git a/src/lua/LuaScriptInterface.cpp b/src/lua/LuaScriptInterface.cpp index 9c9ed9aaa..415c144ff 100644 --- a/src/lua/LuaScriptInterface.cpp +++ b/src/lua/LuaScriptInterface.cpp @@ -1,731 +1,187 @@ -#include "bzip2/bz2wrap.h" -#include "common/VariantIndex.h" -#include "Config.h" -#include "prefs/GlobalPrefs.h" - #include "LuaScriptInterface.h" - -#include "Format.h" -#include "LuaLuna.h" -#include "LuaBit.h" -#include "LuaButton.h" -#include "LuaCheckbox.h" -#include "LuaLabel.h" -#include "LuaProgressBar.h" -#include "LuaSlider.h" -#include "LuaTextbox.h" -#include "LuaWindow.h" -#include "LuaSocket.h" -#include "LuaHttp.h" -#include "LuaSDLKeys.h" -#include "PowderToySDL.h" -#include "TPTScriptInterface.h" - -#include "client/Client.h" -#include "client/GameSave.h" -#include "client/SaveFile.h" -#include "client/SaveInfo.h" #include "client/http/Request.h" #include "common/platform/Platform.h" -#include "graphics/Graphics.h" -#include "graphics/Renderer.h" -#include "simulation/Air.h" -#include "simulation/gravity/Gravity.h" -#include "simulation/ElementCommon.h" -#include "simulation/ElementClasses.h" -#include "simulation/ElementGraphics.h" -#include "simulation/GOLString.h" -#include "simulation/Simulation.h" -#include "simulation/ToolClasses.h" -#include "simulation/SaveRenderer.h" -#include "simulation/Snapshot.h" - -#include "gui/dialogues/ConfirmPrompt.h" -#include "gui/dialogues/ErrorMessage.h" -#include "gui/dialogues/InformationMessage.h" -#include "gui/dialogues/TextPrompt.h" -#include "gui/interface/Window.h" -#include "gui/interface/Engine.h" -#include "gui/game/GameView.h" +#include "common/tpt-rand.h" +#include "compat.lua.h" #include "gui/game/GameController.h" #include "gui/game/GameModel.h" -#include "gui/game/Tool.h" -#include "gui/game/Brush.h" -#include "gui/dialogues/ConfirmPrompt.h" -#include "gui/dialogues/ErrorMessage.h" -#include "gui/dialogues/InformationMessage.h" +#include "gui/game/GameView.h" +#include "gui/interface/Engine.h" +#include "gui/interface/Window.h" +#include "LuaBit.h" +#include "LuaComponent.h" +#include "prefs/GlobalPrefs.h" +#include "simulation/Simulation.h" +#include "simulation/SimulationData.h" -#include "compat.lua.h" - -#include "Config.h" -#include -#include -#include -#include -#include -#include - -// idea from mniip, makes things much simpler -#define SETCONST(L, NAME)\ - lua_pushinteger(L, NAME);\ - lua_setfield(L, -2, #NAME) -#define SETCONSTAS(L, NAME, AS)\ - lua_pushinteger(L, NAME);\ - lua_setfield(L, -2, AS) -#define SETCONSTF(L, NAME)\ - lua_pushnumber(L, NAME);\ - lua_setfield(L, -2, #NAME) - -GameModel *luacon_model{}; -GameController *luacon_controller{}; -Simulation *luacon_sim{}; -static Graphics *luacon_g{}; -static Renderer *luacon_ren{}; - -static bool *luacon_currentCommand{}; -static String *luacon_lastError{}; -static bool luacon_hasLastError; -static String lastCode; - -static int *lua_el_mode{}; -static LuaSmartRef *lua_el_func{}, *lua_gr_func{}; -static std::vector luaCtypeDrawHandlers, luaCreateHandlers, luaCreateAllowedHandlers, luaChangeTypeHandlers; - -static int atPanic(lua_State *l) +static int atPanic(lua_State *L) { - throw std::runtime_error("Unprotected lua panic: " + tpt_lua_toByteString(l, -1)); + throw std::runtime_error("Unprotected lua panic: " + tpt_lua_toByteString(L, -1)); } -static int bz2_compress_wrapper(lua_State *L) +static int osExit(lua_State *L) { - auto src = tpt_lua_checkByteString(L, 1); - auto maxSize = size_t(luaL_optinteger(L, 2, 0)); - std::vector dest; - auto result = BZ2WCompress(dest, src.data(), src.size(), maxSize); -#define RETURN_ERR(str) lua_pushnil(L); lua_pushinteger(L, int(result)); lua_pushliteral(L, str); return 3 - switch (result) - { - case BZ2WCompressOk: break; - case BZ2WCompressNomem: RETURN_ERR("out of memory"); - case BZ2WCompressLimit: RETURN_ERR("size limit exceeded"); - } -#undef RETURN_ERR - tpt_lua_pushByteString(L, ByteString(dest.begin(), dest.end())); - return 1; -} - -static int bz2_decompress_wrapper(lua_State *L) -{ - auto src = tpt_lua_checkByteString(L, 1); - auto maxSize = size_t(luaL_optinteger(L, 2, 0)); - std::vector dest; - auto result = BZ2WDecompress(dest, src.data(), src.size(), maxSize); -#define RETURN_ERR(str) lua_pushnil(L); lua_pushinteger(L, int(result)); lua_pushliteral(L, str); return 3 - switch (result) - { - case BZ2WDecompressOk: break; - case BZ2WDecompressNomem: RETURN_ERR("out of memory"); - case BZ2WDecompressLimit: RETURN_ERR("size limit exceeded"); - case BZ2WDecompressType: - case BZ2WDecompressBad: - case BZ2WDecompressEof: RETURN_ERR("corrupted stream"); - } -#undef RETURN_ERR - tpt_lua_pushByteString(L, ByteString(dest.begin(), dest.end())); - return 1; -} - -static void initBZ2API(lua_State *L) -{ - luaL_Reg reg[] = { - { "compress", bz2_compress_wrapper }, - { "decompress", bz2_decompress_wrapper }, - { NULL, NULL }, - }; - lua_newtable(L); - luaL_register(L, NULL, reg); -#define BZ2_CONST(k, v) lua_pushinteger(L, int(v)); lua_setfield(L, -2, k) - BZ2_CONST("COMPRESS_NOMEM" , BZ2WCompressNomem ); - BZ2_CONST("COMPRESS_LIMIT" , BZ2WCompressLimit ); - BZ2_CONST("DECOMPRESS_NOMEM", BZ2WDecompressNomem); - BZ2_CONST("DECOMPRESS_LIMIT", BZ2WDecompressLimit); - BZ2_CONST("DECOMPRESS_TYPE" , BZ2WDecompressType ); - BZ2_CONST("DECOMPRESS_BAD" , BZ2WDecompressBad ); - BZ2_CONST("DECOMPRESS_EOF" , BZ2WDecompressEof ); -#undef BZ2_CONST - lua_setglobal(L, "bz2"); -} - -static int osExit(lua_State *l) -{ - Platform::Exit(luaL_optinteger(l, 1, 0)); + Platform::Exit(luaL_optinteger(L, 1, 0)); return 0; } -static EventTraits eventTraits = eventTraitNone; - -static int mathRandom(lua_State *l) +static int mathRandom(lua_State *L) { - // only thing that matters is that the rng not be luacon_sim->rng when !(eventTraits & eventTraitSimRng) - auto &rng = (eventTraits & eventTraitSimRng) ? luacon_sim->rng : interfaceRng; + auto *lsi = static_cast(commandInterface); + // only thing that matters is that the rng not be sim->rng when !(eventTraits & eventTraitSimRng) + auto &rng = (lsi->eventTraits & eventTraitSimRng) ? lsi->sim->rng : interfaceRng; int lower, upper; - switch (lua_gettop(l)) + switch (lua_gettop(L)) { case 0: - lua_pushnumber(l, rng.uniform01()); + lua_pushnumber(L, rng.uniform01()); return 1; case 1: lower = 1; - upper = luaL_checkinteger(l, 1); + upper = luaL_checkinteger(L, 1); break; default: - lower = luaL_checkinteger(l, 1); - upper = luaL_checkinteger(l, 2); + lower = luaL_checkinteger(L, 1); + upper = luaL_checkinteger(L, 2); break; } if (upper < lower) { - luaL_error(l, "interval is empty"); + luaL_error(L, "interval is empty"); } if ((unsigned int)(upper) - (unsigned int)(lower) + 1U) { - lua_pushinteger(l, rng.between(lower, upper)); + lua_pushinteger(L, rng.between(lower, upper)); } else { // The interval is *so* not empty that its size overflows 32-bit integers // (only possible if it's exactly 0x100000000); don't use between. - lua_pushinteger(l, int(rng())); + lua_pushinteger(L, int(rng())); } return 1; } -static int mathRandomseed(lua_State *l) +static int mathRandomseed(lua_State *L) { - interfaceRng.seed(luaL_checkinteger(l, 1)); + interfaceRng.seed(luaL_checkinteger(L, 1)); return 0; } -static int simRandomseed(lua_State *l) +static void hook(lua_State *L, lua_Debug * ar) { - if (lua_gettop(l)) + auto *lsi = static_cast(commandInterface); + if (ar->event == LUA_HOOKCOUNT && int(Platform::GetTime() - lsi->luaExecutionStart) > lsi->luaHookTimeout) { - luacon_sim->rng.state({ - uint32_t(luaL_checkinteger(l, 1)) | (uint64_t(uint32_t(luaL_checkinteger(l, 2))) << 32), - uint32_t(luaL_checkinteger(l, 3)) | (uint64_t(uint32_t(luaL_checkinteger(l, 4))) << 32), - }); - return 0; + luaL_error(L, "Error: Script not responding"); + lsi->luaExecutionStart = Platform::GetTime(); } - auto s = luacon_sim->rng.state(); - lua_pushinteger(l, s[0] & UINT32_C(0xFFFFFFFF)); - lua_pushinteger(l, (s[0] >> 32) & UINT32_C(0xFFFFFFFF)); - lua_pushinteger(l, s[1] & UINT32_C(0xFFFFFFFF)); - lua_pushinteger(l, (s[1] >> 32) & UINT32_C(0xFFFFFFFF)); - return 4; } -static int simHash(lua_State *l) +int LuaToLoggableString(lua_State *L, int n) { - lua_pushinteger(l, luacon_sim->CreateSnapshot()->Hash()); + luaL_checkany(L, n); + switch (lua_type(L, n)) + { + case LUA_TNUMBER: + lua_tostring(L, n); + lua_pushvalue(L, n); + break; + case LUA_TSTRING: + lua_pushvalue(L, n); + break; + case LUA_TBOOLEAN: + lua_pushstring(L, (lua_toboolean(L, n) ? "true" : "false")); + break; + case LUA_TNIL: + lua_pushliteral(L, "nil"); + break; + default: + lua_pushfstring(L, "%s: %p", luaL_typename(L, n), lua_topointer(L, n)); + break; + } return 1; } -static int simEnsureDeterminism(lua_State *l) +String LuaGetError() { - if (lua_gettop(l)) - { - luacon_sim->ensureDeterminism = lua_toboolean(l, 1); - return 0; - } - lua_pushboolean(l, luacon_sim->ensureDeterminism); - return 1; -} - -static int tpt_debug(lua_State* l) -{ - int acount = lua_gettop(l); - if (acount == 0) - { - lua_pushinteger(l, luacon_controller->GetDebugFlags()); - return 1; - } - int debugFlags = luaL_optint(l, 1, 0); - luacon_controller->SetDebugFlags(debugFlags); - return 0; -} - -static int tpt_fpsCap(lua_State* l) -{ - int acount = lua_gettop(l); - if (acount == 0) - { - auto fpsLimit = ui::Engine::Ref().GetFpsLimit(); - if (std::holds_alternative(fpsLimit)) - { - lua_pushliteral(l, "vsync"); - } - else if (std::holds_alternative(fpsLimit)) - { - lua_pushnumber(l, 2); - } - else - { - lua_pushnumber(l, std::get(fpsLimit).value); - } - return 1; - } - if (lua_isstring(l, 1) && byteStringEqualsLiteral(tpt_lua_toByteString(l, 1), "vsync")) - { - ui::Engine::Ref().SetFpsLimit(FpsLimitVsync{}); - return 0; - } - float fpscap = luaL_checknumber(l, 1); - if (fpscap < 2) - { - return luaL_error(l, "fps cap too small"); - } - if (fpscap == 2) - { - ui::Engine::Ref().SetFpsLimit(FpsLimitNone{}); - return 0; - } - ui::Engine::Ref().SetFpsLimit(FpsLimitExplicit{ fpscap }); - return 0; -} - -static int tpt_drawCap(lua_State* l) -{ - int acount = lua_gettop(l); - if (acount == 0) - { - lua_pushinteger(l, ui::Engine::Ref().GetDrawingFrequencyLimit()); - return 1; - } - int drawcap = luaL_checkint(l, 1); - if(drawcap < 0) - return luaL_error(l, "draw cap too small"); - ui::Engine::Ref().SetDrawingFrequencyLimit(drawcap); - return 0; -} - - -static void luacon_hook(lua_State * l, lua_Debug * ar) -{ - auto *luacon_ci = static_cast(commandInterface); - if (ar->event == LUA_HOOKCOUNT && int(Platform::GetTime() - luacon_ci->luaExecutionStart) > luacon_ci->luaHookTimeout) - { - luaL_error(l, "Error: Script not responding"); - luacon_ci->luaExecutionStart = Platform::GetTime(); - } -} - -static String luacon_geterror() -{ - auto *luacon_ci = static_cast(commandInterface); - luaL_tostring(luacon_ci->l, -1); - String err = tpt_lua_optString(luacon_ci->l, -1, "failed to execute"); - lua_pop(luacon_ci->l, 1); + auto *lsi = static_cast(commandInterface); + LuaToLoggableString(lsi->L, -1); + String err = tpt_lua_optString(lsi->L, -1, "failed to execute"); + lua_pop(lsi->L, 1); return err; } -static int tpt_log(lua_State* l) -{ - auto *luacon_ci = static_cast(commandInterface); - int args = lua_gettop(l); - String text; - bool hasText = false; - for(int i = 1; i <= args; i++) - { - luaL_tostring(l, -1); - if (hasText) - { - text = tpt_lua_optString(l, -1, "") + ", " + text; - } - else - { - text = tpt_lua_optString(l, -1, ""); - hasText = true; - } - lua_pop(l, 2); - } - if ((*luacon_currentCommand)) - { - if (luacon_hasLastError) - *luacon_lastError += "; "; - *luacon_lastError += text; - luacon_hasLastError = true; - } - else - luacon_ci->Log(CommandInterface::LogNotice, text); - return 0; -} - -static int tpt_reset_gravity_field(lua_State* l) -{ - int nx, ny; - int x1, y1, width, height; - x1 = abs(luaL_optint(l, 1, 0)); - y1 = abs(luaL_optint(l, 2, 0)); - width = abs(luaL_optint(l, 3, XCELLS)); - height = abs(luaL_optint(l, 4, YCELLS)); - if(x1 > XCELLS-1) - x1 = XCELLS-1; - if(y1 > YCELLS-1) - y1 = YCELLS-1; - if(x1+width > XCELLS-1) - width = XCELLS-x1; - if(y1+height > YCELLS-1) - height = YCELLS-y1; - for (nx = x1; nxgravx[ny*XCELLS+nx] = 0; - luacon_sim->gravy[ny*XCELLS+nx] = 0; - luacon_sim->gravp[ny*XCELLS+nx] = 0; - } - return 0; -} - -static int tpt_reset_velocity(lua_State* l) -{ - int nx, ny; - int x1, y1, width, height; - x1 = abs(luaL_optint(l, 1, 0)); - y1 = abs(luaL_optint(l, 2, 0)); - width = abs(luaL_optint(l, 3, XCELLS)); - height = abs(luaL_optint(l, 4, YCELLS)); - if(x1 > XCELLS-1) - x1 = XCELLS-1; - if(y1 > YCELLS-1) - y1 = YCELLS-1; - if(x1+width > XCELLS-1) - width = XCELLS-x1; - if(y1+height > YCELLS-1) - height = YCELLS-y1; - for (nx = x1; nxvx[ny][nx] = 0; - luacon_sim->vy[ny][nx] = 0; - } - return 0; -} - -static int tpt_reset_spark(lua_State* l) -{ - luacon_controller->ResetSpark(); - return 0; -} - -static int tpt_getUserName(lua_State* l) -{ - if (luacon_model->GetUser().UserID) - { - tpt_lua_pushByteString(l, luacon_model->GetUser().Username); - return 1; - } - lua_pushliteral(l, ""); - return 1; -} - -static int ui_activeMenu(lua_State* l) -{ - int acount = lua_gettop(l); - if (acount == 0) - { - lua_pushinteger(l, luacon_model->GetActiveMenu()); - return 1; - } - int menuid = luaL_checkint(l, 1); - if (menuid >= 0 && menuid < SC_TOTAL) - luacon_controller->SetActiveMenu(menuid); - else - return luaL_error(l, "Invalid menu"); - return 0; -} - -static int ui_menuEnabled(lua_State* l) -{ - int menusection = luaL_checkint(l, 1); - if (menusection < 0 || menusection >= SC_TOTAL) - return luaL_error(l, "Invalid menu"); - int acount = lua_gettop(l); - if (acount == 1) - { - lua_pushboolean(l, SimulationData::CRef().msections[menusection].doshow); - return 1; - } - luaL_checktype(l, 2, LUA_TBOOLEAN); - int enabled = lua_toboolean(l, 2); - { - auto &sd = SimulationData::Ref(); - sd.msections[menusection].doshow = enabled; - } - luacon_model->BuildMenus(); - return 0; -} - -static int ui_numMenus(lua_State* l) -{ - int acount = lua_gettop(l); - bool onlyEnabled = true; - if (acount > 0) - { - luaL_checktype(l, 1, LUA_TBOOLEAN); - onlyEnabled = lua_toboolean(l, 1); - } - lua_pushinteger(l, luacon_controller->GetNumMenus(onlyEnabled)); - return 1; -} - -static int ren_useDisplayPreset(lua_State* l) -{ - int cmode = luaL_optint(l, 1, 3)+1; - if (cmode == 11) - cmode = 0; - if (cmode >= 0 && cmode <= 10) - luacon_controller->LoadRenderPreset(cmode); - else - return luaL_error(l, "Invalid display mode"); - return 0; -} - -static int ren_fireSize(lua_State* l) -{ - if (lua_gettop(l) < 1) - { - lua_pushnumber(l, luacon_model->GetRenderer()->GetFireIntensity()); - return 1; - } - float fireintensity = float(luaL_checknumber(l, 1)); - luacon_model->GetRenderer()->prepare_alpha(CELL, fireintensity); - return 0; -} - -static int ui_windowSize(lua_State* l) -{ - auto &g = ui::Engine::Ref(); - if (lua_gettop(l) < 1) - { - lua_pushinteger(l, g.GetScale()); - lua_pushboolean(l, g.GetFullscreen()); - return 2; - } - int scale = luaL_optint(l,1,1); - auto kiosk = lua_toboolean(l,2); - // TODO: handle this the same way as it's handled in PowderToySDL.cpp - // > maybe bind the maximum allowed scale to screen size somehow - if (scale < 1 || scale > 10) - { - scale = 1; - } - { - auto &prefs = GlobalPrefs::Ref(); - Prefs::DeferWrite dw(prefs); - prefs.Set("Scale", scale); - prefs.Set("Fullscreen", kiosk); - } - g.SetScale(scale); - g.SetFullscreen(kiosk); - return 0; -} - -static int tpt_screenshot(lua_State* l) -{ - int captureUI = luaL_optint(l, 1, 0); - int fileType = luaL_optint(l, 2, 0); - - ByteString filename = luacon_controller->TakeScreenshot(captureUI, fileType); - if (filename.size()) - { - tpt_lua_pushByteString(l, filename); - return 1; - } - return 0; -} - -static int tpt_record(lua_State* l) -{ - if (!lua_isboolean(l, -1)) - return luaL_typerror(l, 1, lua_typename(l, LUA_TBOOLEAN)); - bool record = lua_toboolean(l, -1); - int recordingFolder = luacon_controller->Record(record); - lua_pushinteger(l, recordingFolder); - return 1; -} - -static int ui_perfectCircleBrush(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; -} - -LuaScriptInterface::LuaScriptInterface(GameController * c, GameModel * m): - TPTScriptInterface(c, m), - luacon_mousex(0), - luacon_mousey(0), - luacon_mousebutton(0), - luacon_selectedl(""), - luacon_selectedr(""), - luacon_selectedalt(""), - luacon_selectedreplace(""), - luacon_mousedown(false), - currentCommand(false), - textInputRefcount(0) +LuaScriptInterface::LuaScriptInterface(GameController *newGameController, GameModel *newGameModel) : + TPTScriptInterface(newGameController, newGameModel), + gameModel(newGameModel), + gameController(newGameController), + window(gameController->GetView()), + sim(gameModel->GetSimulation()), + g(ui::Engine::Ref().g), + ren(gameModel->GetRenderer()), + customElements(PT_NUM), + gameControllerEventHandlers(std::variant_size_v) { auto &prefs = GlobalPrefs::Ref(); luaHookTimeout = prefs.Get("LuaHookTimeout", 3000); - luacon_model = m; - luacon_controller = c; - luacon_sim = m->GetSimulation(); - luacon_g = ui::Engine::Ref().g; - luacon_ren = m->GetRenderer(); - for (auto moving = 0; moving < PT_NUM; ++moving) { for (auto into = 0; into < PT_NUM; ++into) { - custom_can_move[moving][into] = 0; + customCanMove[moving][into] = 0; } } - - //New TPT API - l = luaL_newstate(); - tpt_lua_setmainthread(l); - lua_atpanic(l, atPanic); - luaL_openlibs(l); - luaopen_bit(l); - lua_pop(l, 1); - - initSimulationAPI(); - initInterfaceAPI(); - SetWindow(c->GetView()); - initRendererAPI(); - initElementsAPI(); - initGraphicsAPI(); - initFileSystemAPI(); - initPlatformAPI(); - initEventAPI(); - initHttpAPI(); - initSocketAPI(); - - lua_getglobal(l, "os"); - lua_pushcfunction(l, osExit); - lua_setfield(l, -2, "exit"); - lua_pop(l, 1); - - lua_getglobal(l, "math"); - lua_pushcfunction(l, mathRandom); - lua_setfield(l, -2, "random"); - lua_pushcfunction(l, mathRandomseed); - lua_setfield(l, -2, "randomseed"); - lua_pop(l, 1); - - initBZ2API(l); - - //Old TPT API - const static struct luaL_Reg tptluaapi [] = { - {"log", tpt_log}, - {"getUserName", tpt_getUserName}, - {"installScriptManager",installScriptManager}, - {"screenshot",tpt_screenshot}, - {"record",tpt_record}, - {"debug", tpt_debug}, - {"fpsCap", tpt_fpsCap}, - {"drawCap", tpt_drawCap}, - {NULL,NULL} - }; - - luacon_mousedown = false; - luacon_mousebutton = 0; - - luacon_currentCommand = ¤tCommand; - luacon_lastError = &lastError; - luacon_hasLastError = false; - - lastCode = ""; - - //Replace print function with our screen logging thingy - lua_pushcfunction(l, tpt_log); - lua_setglobal(l, "print"); - - //Register all tpt functions - luaL_register(l, "tpt", tptluaapi); - - auto tptProperties = lua_gettop(l); - - lua_newtable(l); - auto tptPropertiesVersion = lua_gettop(l); - lua_pushinteger(l, DISPLAY_VERSION[0]); - lua_setfield(l, tptPropertiesVersion, "major"); - lua_pushinteger(l, DISPLAY_VERSION[1]); - lua_setfield(l, tptPropertiesVersion, "minor"); - lua_pushinteger(l, APP_VERSION.build); - lua_setfield(l, tptPropertiesVersion, "build"); - lua_pushinteger(l, UPSTREAM_VERSION.displayVersion[0]); - lua_setfield(l, tptPropertiesVersion, "upstreamMajor"); - lua_pushinteger(l, UPSTREAM_VERSION.displayVersion[1]); - lua_setfield(l, tptPropertiesVersion, "upstreamMinor"); - lua_pushinteger(l, UPSTREAM_VERSION.build); - lua_setfield(l, tptPropertiesVersion, "upstreamBuild"); - lua_pushboolean(l, SNAPSHOT); - lua_setfield(l, tptPropertiesVersion, "snapshot"); - lua_pushboolean(l, BETA); - lua_setfield(l, tptPropertiesVersion, "beta"); - lua_pushinteger(l, MOD_ID); - lua_setfield(l, tptPropertiesVersion, "modid"); - auto vcsTag = ByteString(VCS_TAG); - if (vcsTag.size()) + luaState = LuaStatePtr(luaL_newstate()); + L = luaState.get(); + lua_sethook(L, hook, LUA_MASKCOUNT, 200); + lua_atpanic(L, atPanic); + luaL_openlibs(L); { - tpt_lua_pushByteString(l, VCS_TAG); - lua_setfield(l, tptPropertiesVersion, "vcstag"); + luaopen_bit(L); + lua_pop(L, 1); + } + LuaBz2::Open(L); + LuaElements::Open(L); + LuaEvent::Open(L); + LuaFileSystem::Open(L); + LuaGraphics::Open(L); + LuaHttp::Open(L); + LuaInterface::Open(L); + LuaMisc::Open(L); + LuaPlatform::Open(L); + LuaRenderer::Open(L); + LuaSimulation::Open(L); + LuaSocket::Open(L); + { + lua_getglobal(L, "os"); + lua_pushcfunction(L, osExit); + lua_setfield(L, -2, "exit"); + lua_pop(L, 1); + } + { + lua_getglobal(L, "math"); + lua_pushcfunction(L, mathRandom); + lua_setfield(L, -2, "random"); + lua_pushcfunction(L, mathRandomseed); + lua_setfield(L, -2, "randomseed"); + lua_pop(L, 1); } - lua_setfield(l, tptProperties, "version"); - - lua_sethook(l, &luacon_hook, LUA_MASKCOUNT, 200); - - SETCONST(l, DEBUG_PARTS); - SETCONST(l, DEBUG_ELEMENTPOP); - SETCONST(l, DEBUG_LINES); - SETCONST(l, DEBUG_PARTICLE); - SETCONST(l, DEBUG_SURFNORM); - - lua_gr_func_v = std::vector(PT_NUM); - lua_gr_func = &lua_gr_func_v[0]; - lua_el_func_v = std::vector(PT_NUM); - lua_el_func = &lua_el_func_v[0]; - lua_el_mode_v = std::vector(PT_NUM, 0); - lua_el_mode = &lua_el_mode_v[0]; - - gameControllerEventHandlers = std::vector(std::variant_size::value); for (auto &ref : gameControllerEventHandlers) { - lua_newtable(l); - ref.Assign(l, -1); - lua_pop(l, 1); + lua_newtable(L); + ref.Assign(L, -1); + lua_pop(L, 1); } - - luaCtypeDrawHandlers = std::vector(PT_NUM); - luaCreateHandlers = std::vector(PT_NUM); - luaCreateAllowedHandlers = std::vector(PT_NUM); - luaChangeTypeHandlers = std::vector(PT_NUM); - - if (luaL_loadbuffer(l, (const char *)compat_lua, compat_lua_size, "@[built-in compat.lua]") || tpt_lua_pcall(l, 0, 0, 0, eventTraitNone)) + if (luaL_loadbuffer(L, (const char *)compat_lua, compat_lua_size, "@[built-in compat.lua]") || tpt_lua_pcall(L, 0, 0, 0, eventTraitNone)) { - throw std::runtime_error(ByteString("failed to load built-in compat: ") + tpt_lua_toByteString(l, -1)); + throw std::runtime_error(ByteString("failed to load built-in compat: ") + tpt_lua_toByteString(L, -1)); } - lua_pop(l, 1); } -void LuaScriptInterface::custom_init_can_move() +void LuaScriptInterface::InitCustomCanMove() { auto &sd = SimulationData::Ref(); sd.init_can_move(); @@ -733,9 +189,9 @@ void LuaScriptInterface::custom_init_can_move() { for (auto into = 0; into < PT_NUM; ++into) { - if (custom_can_move[moving][into] & 0x80) + if (customCanMove[moving][into] & 0x80) { - sd.can_move[moving][into] = custom_can_move[moving][into] & 0x7F; + sd.can_move[moving][into] = customCanMove[moving][into] & 0x7F; } } } @@ -745,2749 +201,46 @@ void LuaScriptInterface::Init() { if (Platform::FileExists("autorun.lua")) { - if(luaL_loadfile(l, "autorun.lua") || tpt_lua_pcall(l, 0, 0, 0, eventTraitNone)) - Log(CommandInterface::LogError, luacon_geterror()); + if(luaL_loadfile(L, "autorun.lua") || tpt_lua_pcall(L, 0, 0, 0, eventTraitNone)) + Log(CommandInterface::LogError, LuaGetError()); else Log(CommandInterface::LogWarning, "Loaded autorun.lua"); } } -void LuaScriptInterface::SetWindow(ui::Window * window) -{ - Window = window; -} - -template -struct PickIfTypeHelper; - -template<> -struct PickIfTypeHelper -{ - static constexpr auto LuaType = LUA_TSTRING; - static String Get(lua_State *l, int index) { return tpt_lua_checkString(l, index); } -}; - -template<> -struct PickIfTypeHelper -{ - static constexpr auto LuaType = LUA_TBOOLEAN; - static bool Get(lua_State *l, int index) { return lua_toboolean(l, index); } -}; - -template -static Type PickIfType(lua_State *l, int index, Type defaultValue) -{ - return lua_type(l, index) == PickIfTypeHelper::LuaType ? PickIfTypeHelper::Get(l, index) : defaultValue; -} - -static int beginMessageBox(lua_State* l) -{ - auto title = PickIfType(l, 1, String("Title")); - auto message = PickIfType(l, 2, String("Message")); - auto large = PickIfType(l, 3, false); - auto cb = std::make_shared(); // * Bind to main lua state (might be different from l). - cb->Assign(l, lua_gettop(l)); - new InformationMessage(title, message, large, { [cb]() { - auto *luacon_ci = static_cast(commandInterface); - auto l = luacon_ci->l; - cb->Push(l); - if (lua_isfunction(l, -1)) - { - if (tpt_lua_pcall(l, 0, 0, 0, eventTraitNone)) - { - luacon_ci->Log(CommandInterface::LogError, luacon_geterror()); - } - } - else - { - lua_pop(l, 1); - } - } }); - return 0; -} - -static int beginThrowError(lua_State* l) -{ - auto errorMessage = PickIfType(l, 1, String("Error text")); - auto cb = std::make_shared(); // * Bind to main lua state (might be different from l). - cb->Assign(l, lua_gettop(l)); - new ErrorMessage("Error", errorMessage, { [cb]() { - auto *luacon_ci = static_cast(commandInterface); - auto l = luacon_ci->l; - cb->Push(l); - if (lua_isfunction(l, -1)) - { - if (tpt_lua_pcall(l, 0, 0, 0, eventTraitNone)) - { - luacon_ci->Log(CommandInterface::LogError, luacon_geterror()); - } - } - else - { - lua_pop(l, 1); - } - } }); - return 0; -} - -static int beginInput(lua_State* l) -{ - auto title = PickIfType(l, 1, String("Title")); - auto prompt = PickIfType(l, 2, String("Enter some text:")); - auto text = PickIfType(l, 3, String("")); - auto shadow = PickIfType(l, 4, String("")); - auto cb = std::make_shared(); // * Bind to main lua state (might be different from l). - cb->Assign(l, lua_gettop(l)); - auto handle = [cb](std::optional input) { - auto *luacon_ci = static_cast(commandInterface); - auto l = luacon_ci->l; - cb->Push(l); - if (lua_isfunction(l, -1)) - { - if (input) - { - tpt_lua_pushString(l, *input); - } - else - { - lua_pushnil(l); - } - if (tpt_lua_pcall(l, 1, 0, 0, eventTraitNone)) - { - luacon_ci->Log(CommandInterface::LogError, luacon_geterror()); - } - } - else - { - lua_pop(l, 1); - } - }; - new TextPrompt(title, prompt, text, shadow, false, { [handle](const String &input) { - handle(input); - }, [handle]() { - handle(std::nullopt); - } }); - return 0; -} - -static int beginConfirm(lua_State *l) -{ - auto title = PickIfType(l, 1, String("Title")); - auto message = PickIfType(l, 2, String("Message")); - auto buttonText = PickIfType(l, 3, String("Confirm")); - auto cb = std::make_shared(); // * Bind to main lua state (might be different from l). - cb->Assign(l, lua_gettop(l)); - auto handle = [cb](int result) { - auto *luacon_ci = static_cast(commandInterface); - auto l = luacon_ci->l; - cb->Push(l); - if (lua_isfunction(l, -1)) - { - lua_pushboolean(l, result); - if (tpt_lua_pcall(l, 1, 0, 0, eventTraitNone)) - { - luacon_ci->Log(CommandInterface::LogError, luacon_geterror()); - } - } - else - { - lua_pop(l, 1); - } - }; - new ConfirmPrompt(title, message, { [handle]() { - handle(1); - }, [handle]() { - handle(0); - } }, buttonText); - return 0; -} - -static int interface_console(lua_State* l) -{ - auto *luacon_ci = static_cast(commandInterface); - int acount = lua_gettop(l); - if (acount == 0) - { - lua_pushboolean(l, luacon_ci->Window != ui::Engine::Ref().GetWindow()); - return 1; - } - if (lua_toboolean(l, 1)) - luacon_controller->ShowConsole(); - else - luacon_controller->HideConsole(); - return 0; -} - -static int ui_brushID(lua_State *L) -{ - if (lua_gettop(L) < 1) - { - lua_pushnumber(L, luacon_model->GetBrushID()); - return 1; - } - auto index = luaL_checkint(L, 1); - if (index < 0 || index >= int(luacon_model->BrushListSize())) - { - return luaL_error(L, "Invalid brush index %i", index); - } - luacon_model->SetBrushID(index); - return 0; -} - -static int ui_brushRadius(lua_State *L) -{ - if (lua_gettop(L) < 1) - { - auto radius = luacon_model->GetBrush().GetRadius(); - lua_pushnumber(L, radius.X); - lua_pushnumber(L, radius.Y); - return 2; - } - luacon_model->GetBrush().SetRadius({ luaL_checkint(L, 1), luaL_checkint(L, 2) }); - return 0; -} - -static int ui_mousePosition(lua_State *L) -{ - auto pos = luacon_controller->GetView()->GetMousePosition(); - lua_pushnumber(L, pos.X); - lua_pushnumber(L, pos.Y); - return 2; -} - -static int ui_activeTool(lua_State *L) -{ - auto index = luaL_checkint(L, 1); - if (index < 0 || index >= NUM_TOOLINDICES) - { - return luaL_error(L, "Invalid tool index %i", index); - } - if (lua_gettop(L) < 2) - { - tpt_lua_pushByteString(L, luacon_model->GetActiveTool(index)->Identifier); - return 1; - } - auto identifier = tpt_lua_checkByteString(L, 2); - auto *tool = luacon_model->GetToolFromIdentifier(identifier); - if (!tool) - { - return luaL_error(L, "Invalid tool identifier %s", identifier.c_str()); - } - luacon_controller->SetActiveTool(index, tool); - return 0; -} - -void LuaScriptInterface::initInterfaceAPI() -{ - struct luaL_Reg interfaceAPIMethods [] = { - {"showWindow", interface_showWindow}, - {"closeWindow", interface_closeWindow}, - {"addComponent", interface_addComponent}, - {"removeComponent", interface_removeComponent}, - {"grabTextInput", interface_grabTextInput}, - {"dropTextInput", interface_dropTextInput}, - {"textInputRect", interface_textInputRect}, - {"beginInput", beginInput}, - {"beginMessageBox", beginMessageBox}, - {"beginConfirm", beginConfirm}, - {"beginThrowError", beginThrowError}, - {"activeMenu", ui_activeMenu}, - {"menuEnabled", ui_menuEnabled}, - {"numMenus", ui_numMenus}, - {"perfectCircleBrush", ui_perfectCircleBrush}, - {"console", interface_console}, - {"windowSize",ui_windowSize}, - {"brushID",ui_brushID}, - {"brushRadius",ui_brushRadius}, - {"mousePosition",ui_mousePosition}, - {"activeTool",ui_activeTool}, - {NULL, NULL} - }; - luaL_register(l, "interface", interfaceAPIMethods); - initLuaSDLKeys(l); - lua_pushinteger(l, GameController::mouseUpNormal); - lua_setfield(l, -2, "MOUSEUP_NORMAL"); - lua_pushinteger(l, GameController::mouseUpBlur); - lua_setfield(l, -2, "MOUSEUP_BLUR"); - lua_pushinteger(l, GameController::mouseUpDrawEnd); - lua_setfield(l, -2, "MOUSEUP_DRAWEND"); - lua_pushinteger(l, NUM_TOOLINDICES); - lua_setfield(l, -2, "NUM_TOOLINDICES"); - lua_pop(l, 1); - - //ui shortcut - lua_getglobal(l, "interface"); - lua_setglobal(l, "ui"); - - Luna::Register(l); - Luna::Register(l); - Luna::Register(l); - Luna::Register(l); - Luna::Register(l); - Luna::Register(l); - Luna::Register(l); -} - -int LuaScriptInterface::interface_addComponent(lua_State * l) -{ - auto *luacon_ci = static_cast(commandInterface); - void *opaque = nullptr; - LuaComponent *luaComponent = nullptr; - if ((opaque = Luna::tryGet(l, 1))) - luaComponent = Luna::get(opaque); - else if ((opaque = Luna::tryGet(l, 1))) - luaComponent = Luna::get(opaque); - else if ((opaque = Luna::tryGet(l, 1))) - luaComponent = Luna::get(opaque); - else if ((opaque = Luna::tryGet(l, 1))) - luaComponent = Luna::get(opaque); - else if ((opaque = Luna::tryGet(l, 1))) - luaComponent = Luna::get(opaque); - else if ((opaque = Luna::tryGet(l, 1))) - luaComponent = Luna::get(opaque); - else - luaL_typerror(l, 1, "Component"); - if (luacon_ci->Window && luaComponent) - { - auto ok = luacon_ci->grabbed_components.insert(std::make_pair(luaComponent, LuaSmartRef())); - if (ok.second) - { - auto it = ok.first; - it->second.Assign(l, 1); - it->first->owner_ref = it->second; - } - luacon_ci->Window->AddComponent(luaComponent->GetComponent()); - } - return 0; -} - -int LuaScriptInterface::interface_removeComponent(lua_State * l) -{ - auto *luacon_ci = static_cast(commandInterface); - void *opaque = nullptr; - LuaComponent *luaComponent = nullptr; - if ((opaque = Luna::tryGet(l, 1))) - luaComponent = Luna::get(opaque); - else if ((opaque = Luna::tryGet(l, 1))) - luaComponent = Luna::get(opaque); - else if ((opaque = Luna::tryGet(l, 1))) - luaComponent = Luna::get(opaque); - else if ((opaque = Luna::tryGet(l, 1))) - luaComponent = Luna::get(opaque); - else if ((opaque = Luna::tryGet(l, 1))) - luaComponent = Luna::get(opaque); - else if ((opaque = Luna::tryGet(l, 1))) - luaComponent = Luna::get(opaque); - else - luaL_typerror(l, 1, "Component"); - if(luacon_ci->Window && luaComponent) - { - ui::Component *component = luaComponent->GetComponent(); - luacon_ci->Window->RemoveComponent(component); - auto it = luacon_ci->grabbed_components.find(luaComponent); - if (it != luacon_ci->grabbed_components.end()) - { - it->second.Clear(); - it->first->owner_ref = it->second; - luacon_ci->grabbed_components.erase(it); - } - } - return 0; -} - -int LuaScriptInterface::interface_grabTextInput(lua_State * l) -{ - auto *luacon_ci = static_cast(commandInterface); - luacon_ci->textInputRefcount += 1; - luacon_controller->GetView()->DoesTextInput = luacon_ci->textInputRefcount > 0; - return 0; -} - -int LuaScriptInterface::interface_dropTextInput(lua_State * l) -{ - auto *luacon_ci = static_cast(commandInterface); - luacon_ci->textInputRefcount -= 1; - luacon_controller->GetView()->DoesTextInput = luacon_ci->textInputRefcount > 0; - return 0; -} - -int LuaScriptInterface::interface_textInputRect(lua_State * l) -{ - int x = luaL_checkint(l, 1); - int y = luaL_checkint(l, 2); - int w = luaL_checkint(l, 3); - int h = luaL_checkint(l, 4); - ui::Engine::Ref().TextInputRect(ui::Point{ x, y }, ui::Point{ w, h }); - return 0; -} - -int LuaScriptInterface::interface_showWindow(lua_State * l) -{ - LuaWindow * window = Luna::check(l, 1); - - if(window && ui::Engine::Ref().GetWindow()!=window->GetWindow()) - ui::Engine::Ref().ShowWindow(window->GetWindow()); - return 0; -} - -int LuaScriptInterface::interface_closeWindow(lua_State * l) -{ - LuaWindow * window = Luna::check(l, 1); - if (window) - window->GetWindow()->CloseActiveWindow(); - return 0; -} - -//// Begin sim.signs API - -int LuaScriptInterface::simulation_signIndex(lua_State *l) -{ - ByteString key = tpt_lua_checkByteString(l, 2); - - //Get Raw Index value for element. Maybe there is a way to get the sign index some other way? - lua_pushliteral(l, "id"); - lua_rawget(l, 1); - int id = lua_tointeger(l, lua_gettop(l))-1; - - if (id < 0 || id >= MAXSIGNS) - { - luaL_error(l, "Invalid sign ID (stop messing with things): %i", id); - return 0; - } - if (id >= (int)luacon_sim->signs.size()) - { - return lua_pushnil(l), 1; - } - - int x, y, w, h; - if (byteStringEqualsLiteral(key, "text")) - return tpt_lua_pushString(l, luacon_sim->signs[id].text), 1; - else if (byteStringEqualsLiteral(key, "displayText")) - return tpt_lua_pushString(l, luacon_sim->signs[id].getDisplayText(luacon_sim, x, y, w, h, false)), 1; - else if (byteStringEqualsLiteral(key, "justification")) - return lua_pushnumber(l, (int)luacon_sim->signs[id].ju), 1; - else if (byteStringEqualsLiteral(key, "x")) - return lua_pushnumber(l, luacon_sim->signs[id].x), 1; - else if (byteStringEqualsLiteral(key, "y")) - return lua_pushnumber(l, luacon_sim->signs[id].y), 1; - else if (byteStringEqualsLiteral(key, "screenX")) - { - luacon_sim->signs[id].getDisplayText(luacon_sim, x, y, w, h); - lua_pushnumber(l, x); - return 1; - } - else if (byteStringEqualsLiteral(key, "screenY")) - { - luacon_sim->signs[id].getDisplayText(luacon_sim, x, y, w, h); - lua_pushnumber(l, y); - return 1; - } - else if (byteStringEqualsLiteral(key, "width")) - { - luacon_sim->signs[id].getDisplayText(luacon_sim, x, y, w, h); - lua_pushnumber(l, w); - return 1; - } - else if (byteStringEqualsLiteral(key, "height")) - { - luacon_sim->signs[id].getDisplayText(luacon_sim, x, y, w, h); - lua_pushnumber(l, h); - return 1; - } - else - return lua_pushnil(l), 1; -} - -int LuaScriptInterface::simulation_signNewIndex(lua_State *l) -{ - ByteString key = tpt_lua_checkByteString(l, 2); - - //Get Raw Index value for element. Maybe there is a way to get the sign index some other way? - lua_pushliteral(l, "id"); - lua_rawget(l, 1); - int id = lua_tointeger(l, lua_gettop(l))-1; - - if (id < 0 || id >= MAXSIGNS) - { - luaL_error(l, "Invalid sign ID (stop messing with things)"); - return 0; - } - if (id >= (int)luacon_sim->signs.size()) - { - luaL_error(l, "Sign doesn't exist"); - } - - if (byteStringEqualsLiteral(key, "text")) - { - auto temp = tpt_lua_checkString(l, 3); - String cleaned = format::CleanString(temp, false, true, true).Substr(0, 45); - if (!cleaned.empty()) - luacon_sim->signs[id].text = cleaned; - else - luaL_error(l, "Text is empty"); - return 0; - } - else if (byteStringEqualsLiteral(key, "justification")) - { - int ju = luaL_checkinteger(l, 3); - if (ju >= 0 && ju <= 3) - return luacon_sim->signs[id].ju = (sign::Justification)ju, 1; - else - luaL_error(l, "Invalid justification"); - return 0; - } - else if (byteStringEqualsLiteral(key, "x")) - { - int x = luaL_checkinteger(l, 3); - if (x >= 0 && x < XRES) - return luacon_sim->signs[id].x = x, 1; - else - luaL_error(l, "Invalid X coordinate"); - return 0; - } - else if (byteStringEqualsLiteral(key, "y")) - { - int y = luaL_checkinteger(l, 3); - if (y >= 0 && y < YRES) - return luacon_sim->signs[id].y = y, 1; - else - luaL_error(l, "Invalid Y coordinate"); - return 0; - } - else if (byteStringEqualsLiteral(key, "displayText") || - byteStringEqualsLiteral(key, "screenX") || - byteStringEqualsLiteral(key, "screenY") || - byteStringEqualsLiteral(key, "width") || - byteStringEqualsLiteral(key, "height")) - { - luaL_error(l, "That property can't be directly set"); - } - return 0; -} - -// Creates a new sign at the first open index -int LuaScriptInterface::simulation_newsign(lua_State *l) -{ - if (luacon_sim->signs.size() >= MAXSIGNS) - return lua_pushnil(l), 1; - - String text = format::CleanString(tpt_lua_checkString(l, 1), false, true, true).Substr(0, 45); - int x = luaL_checkinteger(l, 2); - int y = luaL_checkinteger(l, 3); - int ju = luaL_optinteger(l, 4, 1); - if (ju < 0 || ju > 3) - return luaL_error(l, "Invalid justification"); - if (x < 0 || x >= XRES) - return luaL_error(l, "Invalid X coordinate"); - if (y < 0 || y >= YRES) - return luaL_error(l, "Invalid Y coordinate"); - - luacon_sim->signs.push_back(sign(text, x, y, (sign::Justification)ju)); - - lua_pushinteger(l, luacon_sim->signs.size()); - return 1; -} - -// Deletes a sign -int simulation_deletesign(lua_State *l) -{ - int signID = luaL_checkinteger(l, 1); - if (signID <= 0 || signID > (int)luacon_sim->signs.size()) - return luaL_error(l, "Sign doesn't exist"); - - luacon_sim->signs.erase(luacon_sim->signs.begin()+signID-1); - return 1; - } - -//// Begin Simulation API - -static int simulation_listStamps(lua_State *l); - -static int sim_ambientHeatSim(lua_State *l) -{ - int acount = lua_gettop(l); - if (acount == 0) - { - lua_pushboolean(l, luacon_sim->aheat_enable); - return 1; - } - auto aheatstate = lua_toboolean(l, 1); - luacon_sim->aheat_enable = aheatstate; - luacon_model->UpdateQuickOptions(); - - return 0; -} - -static int sim_heatSim(lua_State *l) -{ - int acount = lua_gettop(l); - if (acount == 0) - { - lua_pushboolean(l, !luacon_sim->legacy_enable); - return 1; - } - auto heatstate = lua_toboolean(l, 1); - luacon_sim->legacy_enable = !heatstate; - return 0; -} - -static int sim_newtonianGravity(lua_State* l) -{ - int acount = lua_gettop(l); - if (acount == 0) - { - lua_pushboolean(l, luacon_sim->grav->IsEnabled()); - return 1; - } - int gravstate = lua_toboolean(l, 1); - if(gravstate) - luacon_sim->grav->start_grav_async(); - else - luacon_sim->grav->stop_grav_async(); - luacon_model->UpdateQuickOptions(); - return 0; -} - -static int sim_paused(lua_State* l) -{ - int acount = lua_gettop(l); - if (acount == 0) - { - lua_pushboolean(l, luacon_model->GetPaused()); - return 1; - } - auto pausestate = lua_toboolean(l, 1); - luacon_model->SetPaused(pausestate); - return 0; -} - -static int sim_partCount(lua_State *l) -{ - lua_pushinteger(l, luacon_sim->NUM_PARTS); - return 1; -} - -static int sim_decoSpace(lua_State *L) -{ - if (lua_gettop(L) < 1) - { - lua_pushnumber(L, luacon_model->GetDecoSpace()); - return 1; - } - auto index = luaL_checkint(L, 1); - if (index < 0 || index >= NUM_DECOSPACES) - { - return luaL_error(L, "Invalid deco space index %i", index); - } - luacon_model->SetDecoSpace(index); - return 0; -} - -template -struct LuaBlockMapHelper -{ - using ItemType = std::remove_reference_t>>; -}; - -template::ItemType> -static int LuaBlockMapImpl(lua_State *L, ItemType minValue, ItemType maxValue, Accessor accessor) -{ - auto pos = Vec2{ luaL_checkint(L, 1), luaL_checkint(L, 2) }; - if (!CELLS.OriginRect().Contains(pos)) - { - return luaL_error(L, "Coordinates (%i, %i) out of range", pos.X, pos.Y); - } - auto argc = lua_gettop(L); - if (argc == 2) - { - if constexpr (std::is_integral_v) - { - lua_pushinteger(L, lua_Integer(accessor(pos))); - } - else - { - lua_pushnumber(L, lua_Number(accessor(pos))); - } - return 1; - } - auto size = Vec2{ 1, 1 }; - auto valuePos = 3; - if (argc > 3) - { - size = Vec2{ luaL_checkint(L, 3), luaL_checkint(L, 4) }; - valuePos = 5; - } - ItemType value; - if constexpr (std::is_integral_v) - { - value = ItemType(luaL_checkint(L, valuePos)); - } - else - { - value = ItemType(luaL_checknumber(L, valuePos)); - } - if constexpr (Clamp) - { - if (value > maxValue) value = maxValue; - if (value < minValue) value = minValue; - } - for (auto p : CELLS.OriginRect() & RectSized(pos, size)) - { - accessor(p) = value; - } - return 0; -} - -template::ItemType> -static int LuaBlockMap(lua_State *L, ItemType minValue, ItemType maxValue, Accessor accessor) -{ - return LuaBlockMapImpl(L, minValue, maxValue, accessor); -} - -template::ItemType> -static int LuaBlockMap(lua_State *L, Accessor accessor) -{ - return LuaBlockMapImpl(L, ItemType(0), ItemType(0), accessor); -} - -static int sim_velocityX(lua_State *L) -{ - return LuaBlockMap(L, MIN_PRESSURE, MAX_PRESSURE, [](Vec2 p) -> float & { - return luacon_sim->vx[p.Y][p.X]; - }); -} - -static int sim_velocityY(lua_State *L) -{ - return LuaBlockMap(L, MIN_PRESSURE, MAX_PRESSURE, [](Vec2 p) -> float & { - return luacon_sim->vy[p.Y][p.X]; - }); -} - -static int sim_ambientHeat(lua_State *L) -{ - return LuaBlockMap(L, MIN_TEMP, MAX_TEMP, [](Vec2 p) -> float & { - return luacon_sim->hv[p.Y][p.X]; - }); -} - -static int sim_pressure(lua_State *L) -{ - return LuaBlockMap(L, MIN_PRESSURE, MAX_PRESSURE, [](Vec2 p) -> float & { - return luacon_sim->pv[p.Y][p.X]; - }); -} - -static int sim_gravityMass(lua_State *L) -{ - return LuaBlockMap(L, [](Vec2 p) -> float & { - return luacon_sim->gravmap[p.Y * XCELLS + p.X]; - }); -} - -static int sim_gravityField(lua_State *L) -{ - auto pos = Vec2{ luaL_checkint(L, 1), luaL_checkint(L, 2) }; - if (!CELLS.OriginRect().Contains(pos)) - { - return luaL_error(L, "Coordinates (%i, %i) out of range", pos.X, pos.Y); - } - lua_pushnumber(L, luacon_sim->gravx[pos.Y * XCELLS + pos.X]); - lua_pushnumber(L, luacon_sim->gravy[pos.Y * XCELLS + pos.X]); - return 2; -} - -static int sim_elecMap(lua_State *L) -{ - return LuaBlockMap(L, [](Vec2 p) -> unsigned char & { - return luacon_sim->emap[p.Y][p.X]; - }); -} - -static int sim_wallMap(lua_State *L) -{ - return LuaBlockMap(L, 0, UI_WALLCOUNT - 1, [](Vec2 p) -> unsigned char & { - return luacon_sim->bmap[p.Y][p.X]; - }); -} - -static int sim_fanVelocityX(lua_State *L) -{ - return LuaBlockMap(L, [](Vec2 p) -> float & { - return luacon_sim->fvx[p.Y][p.X]; - }); -} - -static int sim_fanVelocityY(lua_State *L) -{ - return LuaBlockMap(L, [](Vec2 p) -> float & { - return luacon_sim->fvy[p.Y][p.X]; - }); -} - -void LuaScriptInterface::initSimulationAPI() -{ - auto &sd = SimulationData::CRef(); - - //Methods - struct luaL_Reg simulationAPIMethods [] = { - {"partNeighbors", simulation_partNeighbours}, - {"partChangeType", simulation_partChangeType}, - {"partCreate", simulation_partCreate}, - {"partProperty", simulation_partProperty}, - {"partPosition", simulation_partPosition}, - {"partID", simulation_partID}, - {"partKill", simulation_partKill}, - {"partExists", simulation_partExists}, - {"pressure", sim_pressure}, - {"ambientHeat", sim_ambientHeat}, - {"ambientHeatSim", sim_ambientHeatSim}, - {"heatSim", sim_heatSim}, - {"newtonianGravity", sim_newtonianGravity}, - {"velocityX", sim_velocityX}, - {"velocityY", sim_velocityY}, - {"createParts", simulation_createParts}, - {"createLine", simulation_createLine}, - {"createBox", simulation_createBox}, - {"floodParts", simulation_floodParts}, - {"createWalls", simulation_createWalls}, - {"createWallLine", simulation_createWallLine}, - {"createWallBox", simulation_createWallBox}, - {"floodWalls", simulation_floodWalls}, - {"toolBrush", simulation_toolBrush}, - {"toolLine", simulation_toolLine}, - {"toolBox", simulation_toolBox}, - {"decoBrush", simulation_decoBrush}, - {"decoLine", simulation_decoLine}, - {"decoBox", simulation_decoBox}, - {"decoColor", simulation_decoColor}, - {"floodDeco", simulation_floodDeco}, - {"clearSim", simulation_clearSim}, - {"clearRect", simulation_clearRect}, - {"resetTemp", simulation_resetTemp}, - {"resetPressure", simulation_resetPressure}, - {"saveStamp", simulation_saveStamp}, - {"loadStamp", simulation_loadStamp}, - {"deleteStamp", simulation_deleteStamp}, - {"listStamps", simulation_listStamps}, - {"loadSave", simulation_loadSave}, - {"reloadSave", simulation_reloadSave}, - {"getSaveID", simulation_getSaveID}, - {"adjustCoords", simulation_adjustCoords}, - {"prettyPowders", simulation_prettyPowders}, - {"gravityGrid", simulation_gravityGrid}, - {"edgeMode", simulation_edgeMode}, - {"gravityMode", simulation_gravityMode}, - {"customGravity", simulation_customGravity}, - {"airMode", simulation_airMode}, - {"waterEqualization", simulation_waterEqualisation}, - {"ambientAirTemp", simulation_ambientAirTemp}, - {"elementCount", simulation_elementCount}, - {"canMove", simulation_canMove}, - {"brush", simulation_brush}, - {"parts", simulation_parts}, - {"pmap", simulation_pmap}, - {"photons", simulation_photons}, - {"neighbors", simulation_neighbours}, - {"frameRender", simulation_framerender}, - {"golSpeedRatio", simulation_gspeed}, - {"takeSnapshot", simulation_takeSnapshot}, - {"historyRestore", simulation_historyRestore}, - {"historyForward", simulation_historyForward}, - {"replaceModeFlags", simulation_replaceModeFlags}, - {"listCustomGol", simulation_listCustomGol}, - {"addCustomGol", simulation_addCustomGol}, - {"removeCustomGol", simulation_removeCustomGol}, - {"lastUpdatedID", simulation_lastUpdatedID}, - {"updateUpTo", simulation_updateUpTo}, - {"temperatureScale", simulation_temperatureScale}, - {"randomSeed", simRandomseed}, - {"hash", simHash}, - {"ensureDeterminism", simEnsureDeterminism}, - {"paused", sim_paused}, - {"gravityMass", sim_gravityMass}, - {"gravityField", sim_gravityField}, - {"resetGravityField", tpt_reset_gravity_field}, - {"resetSpark", tpt_reset_spark}, - {"resetVelocity", tpt_reset_velocity}, - {"wallMap", &sim_wallMap}, - {"elecMap", &sim_elecMap}, - {"partCount", sim_partCount}, - {"decoSpace", sim_decoSpace}, - {"fanVelocityX", sim_fanVelocityX}, - {"fanVelocityY", sim_fanVelocityY}, - {NULL, NULL} - }; - luaL_register(l, "simulation", simulationAPIMethods); - - //Static values - SETCONST(l, CELL); - SETCONST(l, XCELLS); - SETCONST(l, YCELLS); - SETCONST(l, NCELL); - SETCONST(l, XRES); - SETCONST(l, YRES); - SETCONST(l, XCNTR); - SETCONST(l, YCNTR); - SETCONSTAS(l, NPART, "MAX_PARTS"); - SETCONST(l, NT); - SETCONST(l, ST); - SETCONSTF(l, ITH); - SETCONSTF(l, ITL); - SETCONSTF(l, IPH); - SETCONSTF(l, IPL); - SETCONST(l, PT_NUM); - SETCONSTF(l, R_TEMP); - SETCONSTF(l, MAX_TEMP); - SETCONSTF(l, MIN_TEMP); - SETCONSTF(l, MAX_PRESSURE); - SETCONSTF(l, MIN_PRESSURE); - SETCONST(l, ISTP); - SETCONSTF(l, CFDS); - SETCONSTF(l, MAX_VELOCITY); - - SETCONST(l, TOOL_HEAT); - SETCONST(l, TOOL_COOL); - SETCONST(l, TOOL_VAC); - SETCONST(l, TOOL_AIR); - SETCONST(l, TOOL_PGRV); - SETCONST(l, TOOL_NGRV); - SETCONST(l, TOOL_MIX); - SETCONST(l, TOOL_CYCL); - lua_pushinteger(l, sd.tools.size()); lua_setfield(l, -2, "TOOL_WIND"); - - SETCONST(l, DECO_DRAW); - SETCONST(l, DECO_CLEAR); - SETCONST(l, DECO_ADD); - SETCONST(l, DECO_SUBTRACT); - SETCONST(l, DECO_MULTIPLY); - SETCONST(l, DECO_DIVIDE); - SETCONST(l, DECO_SMUDGE); - - SETCONST(l, FLAG_STAGNANT); - SETCONST(l, FLAG_SKIPMOVE); - SETCONST(l, FLAG_MOVABLE); - SETCONST(l, FLAG_PHOTDECO); - - SETCONST(l, PMAPBITS); - SETCONST(l, PMAPMASK); - - SETCONST(l, BRUSH_CIRCLE); - SETCONST(l, BRUSH_SQUARE); - SETCONST(l, BRUSH_TRIANGLE); - SETCONST(l, NUM_DEFAULTBRUSHES); - - lua_pushinteger(l, luacon_model->BrushListSize()); - lua_setfield(l, -2, "NUM_BRUSHES"); - - SETCONST(l, EDGE_VOID); - SETCONST(l, EDGE_SOLID); - SETCONST(l, EDGE_LOOP); - SETCONST(l, NUM_EDGEMODES); - - SETCONST(l, AIR_ON); - SETCONST(l, AIR_PRESSUREOFF); - SETCONST(l, AIR_VELOCITYOFF); - SETCONST(l, AIR_OFF); - SETCONST(l, AIR_NOUPDATE); - SETCONST(l, NUM_AIRMODES); - - SETCONST(l, GRAV_VERTICAL); - SETCONST(l, GRAV_OFF); - SETCONST(l, GRAV_RADIAL); - SETCONST(l, GRAV_CUSTOM); - SETCONST(l, NUM_GRAVMODES); - - lua_newtable(l); - for (int i = 0; i < UI_WALLCOUNT; i++) - { - tpt_lua_pushByteString(l, sd.wtypes[i].identifier); - lua_pushinteger(l, i); - lua_settable(l, -3); - - lua_pushinteger(l, i); - tpt_lua_pushByteString(l, sd.wtypes[i].identifier); - lua_settable(l, -3); - } - lua_setfield(l, -2, "walls"); - SETCONSTAS(l, UI_WALLCOUNT, "NUM_WALLS"); - - //Declare FIELD_BLAH constants - { - int particlePropertiesCount = 0; - for (auto &prop : Particle::GetProperties()) - { - tpt_lua_pushByteString(l, "FIELD_" + prop.Name.ToUpper()); - lua_pushinteger(l, particlePropertiesCount++); - lua_settable(l, -3); - } - for (auto &alias : Particle::GetPropertyAliases()) - { - tpt_lua_pushByteString(l, "FIELD_" + alias.from.ToUpper()); - tpt_lua_pushByteString(l, "FIELD_" + alias.to.ToUpper()); - lua_gettable(l, -3); - lua_settable(l, -3); - } - } - - lua_newtable(l); - for (int i = 1; i <= MAXSIGNS; i++) - { - lua_newtable(l); - lua_pushinteger(l, i); //set "id" to table index - lua_setfield(l, -2, "id"); - lua_newtable(l); - lua_pushcfunction(l, simulation_signIndex); - lua_setfield(l, -2, "__index"); - lua_pushcfunction(l, simulation_signNewIndex); - lua_setfield(l, -2, "__newindex"); - lua_setmetatable(l, -2); - lua_pushinteger(l, i); //table index - lua_insert(l, -2); //swap k and v - lua_settable(l, -3); //set metatable to signs[i] - } - lua_pushcfunction(l, simulation_newsign); - lua_setfield(l, -2, "new"); - lua_pushcfunction(l, simulation_deletesign); - lua_setfield(l, -2, "delete"); - lua_setfield(l, -2, "signs"); - - lua_pop(l, 1); - - //Sim shortcut - lua_getglobal(l, "simulation"); - lua_setglobal(l, "sim"); -} - -int LuaScriptInterface::simulation_partNeighbours(lua_State * l) -{ - lua_newtable(l); - int id = 1; - int x = lua_tointeger(l, 1), y = lua_tointeger(l, 2), r = lua_tointeger(l, 3), rx, ry, n; - if(lua_gettop(l) == 5) // this is one more than the number of arguments because a table has just been pushed onto the stack with lua_newtable(l); - { - int t = lua_tointeger(l, 4); - for (rx = -r; rx <= r; rx++) - for (ry = -r; ry <= r; ry++) - if (x+rx >= 0 && y+ry >= 0 && x+rx < XRES && y+ry < YRES && (rx || ry)) - { - n = luacon_sim->pmap[y+ry][x+rx]; - if (!n || TYP(n) != t) - n = luacon_sim->photons[y+ry][x+rx]; - if (n && TYP(n) == t) - { - lua_pushinteger(l, ID(n)); - lua_rawseti(l, -2, id++); - } - } - - } - else - { - for (rx = -r; rx <= r; rx++) - for (ry = -r; ry <= r; ry++) - if (x+rx >= 0 && y+ry >= 0 && x+rx < XRES && y+ry < YRES && (rx || ry)) - { - n = luacon_sim->pmap[y+ry][x+rx]; - if (!n) - n = luacon_sim->photons[y+ry][x+rx]; - if (n) - { - lua_pushinteger(l, ID(n)); - lua_rawseti(l, -2, id++); - } - } - } - return 1; -} - -int LuaScriptInterface::simulation_partChangeType(lua_State * l) -{ - int partIndex = lua_tointeger(l, 1); - if(partIndex < 0 || partIndex >= NPART || !luacon_sim->parts[partIndex].type) - return 0; - luacon_sim->part_change_type(partIndex, int(luacon_sim->parts[partIndex].x+0.5f), int(luacon_sim->parts[partIndex].y+0.5f), lua_tointeger(l, 2)); - return 0; -} - -int LuaScriptInterface::simulation_partCreate(lua_State * l) -{ - int newID = lua_tointeger(l, 1); - if (newID >= NPART || newID < -3) - { - lua_pushinteger(l, -1); - return 1; - } - if (newID >= 0 && !luacon_sim->parts[newID].type) - { - lua_pushinteger(l, -1); - return 1; - } - int type = lua_tointeger(l, 4); - int v = -1; - if (lua_gettop(l) >= 5) - { - v = lua_tointeger(l, 5); - } - else if (ID(type)) - { - v = ID(type); - type = TYP(type); - } - lua_pushinteger(l, luacon_sim->create_part(newID, lua_tointeger(l, 2), lua_tointeger(l, 3), type, v)); - return 1; -} - -int LuaScriptInterface::simulation_partID(lua_State * l) -{ - int x = lua_tointeger(l, 1); - int y = lua_tointeger(l, 2); - - if(x < 0 || x >= XRES || y < 0 || y >= YRES) - { - lua_pushnil(l); - return 1; - } - - int amalgam = luacon_sim->pmap[y][x]; - if(!amalgam) - amalgam = luacon_sim->photons[y][x]; - if (!amalgam) - lua_pushnil(l); - else - lua_pushinteger(l, ID(amalgam)); - return 1; -} - -int LuaScriptInterface::simulation_partPosition(lua_State * l) -{ - int particleID = lua_tointeger(l, 1); - int argCount = lua_gettop(l); - if (particleID < 0 || particleID >= NPART || !luacon_sim->parts[particleID].type) - { - if(argCount == 1) - { - lua_pushnil(l); - lua_pushnil(l); - return 2; - } else { - return 0; - } - } - - if (argCount == 3) - { - float x = luacon_sim->parts[particleID].x; - float y = luacon_sim->parts[particleID].y; - luacon_sim->move(particleID, (int)(x + 0.5f), (int)(y + 0.5f), lua_tonumber(l, 2), lua_tonumber(l, 3)); - - return 0; - } - else - { - lua_pushnumber(l, luacon_sim->parts[particleID].x); - lua_pushnumber(l, luacon_sim->parts[particleID].y); - return 2; - } -} - -int LuaScriptInterface::simulation_partProperty(lua_State * l) -{ - int argCount = lua_gettop(l); - int particleID = luaL_checkinteger(l, 1); - StructProperty property; - - if (particleID < 0 || particleID >= NPART || !luacon_sim->parts[particleID].type) - { - if (argCount == 3) - { - lua_pushnil(l); - return 1; - } - else - { - return 0; - } - } - - auto &properties = Particle::GetProperties(); - auto prop = properties.end(); - - //Get field - if (lua_type(l, 2) == LUA_TNUMBER) - { - int fieldID = lua_tointeger(l, 2); - if (fieldID < 0 || fieldID >= (int)properties.size()) - return luaL_error(l, "Invalid field ID (%d)", fieldID); - prop = properties.begin() + fieldID; - } - else if (lua_type(l, 2) == LUA_TSTRING) - { - ByteString fieldName = tpt_lua_toByteString(l, 2); - for (auto &alias : Particle::GetPropertyAliases()) - { - if (fieldName == alias.from) - { - fieldName = alias.to; - } - } - prop = std::find_if(properties.begin(), properties.end(), [&fieldName](StructProperty const &p) { - return p.Name == fieldName; - }); - if (prop == properties.end()) - return luaL_error(l, "Unknown field (%s)", fieldName.c_str()); - } - else - { - return luaL_error(l, "Field ID must be an name (string) or identifier (integer)"); - } - - //Calculate memory address of property - intptr_t propertyAddress = (intptr_t)(((unsigned char*)&luacon_sim->parts[particleID]) + prop->Offset); - - if (argCount == 3) - { - LuaSetParticleProperty(l, particleID, *prop, propertyAddress, 3); - return 0; - } - else - { - LuaGetProperty(l, *prop, propertyAddress); - return 1; - } -} - -int LuaScriptInterface::simulation_partKill(lua_State * l) -{ - if(lua_gettop(l)==2) - luacon_sim->delete_part(lua_tointeger(l, 1), lua_tointeger(l, 2)); - else - { - int i = lua_tointeger(l, 1); - if (i>=0 && ikill_part(i); - } - return 0; -} - -int LuaScriptInterface::simulation_partExists(lua_State * l) -{ - int i = luaL_checkinteger(l, 1); - lua_pushboolean(l, i >= 0 && i < NPART && luacon_sim->parts[i].type); - return 1; -} - -int LuaScriptInterface::simulation_createParts(lua_State * l) -{ - int x = luaL_optint(l,1,-1); - int y = luaL_optint(l,2,-1); - int rx = luaL_optint(l,3,5); - int ry = luaL_optint(l,4,5); - int c = luaL_optint(l,5,luacon_model->GetActiveTool(0)->ToolID); - int brushID = luaL_optint(l,6,BRUSH_CIRCLE); - int flags = luaL_optint(l,7,luacon_sim->replaceModeFlags); - - Brush *brush = luacon_model->GetBrushByID(brushID); - if (!brush) - return luaL_error(l, "Invalid brush id '%d'", brushID); - auto newBrush = brush->Clone(); - newBrush->SetRadius(ui::Point(rx, ry)); - - int ret = luacon_sim->CreateParts(x, y, c, *newBrush, flags); - lua_pushinteger(l, ret); - return 1; -} - -int LuaScriptInterface::simulation_createLine(lua_State * l) -{ - int x1 = luaL_optint(l,1,-1); - int y1 = luaL_optint(l,2,-1); - int x2 = luaL_optint(l,3,-1); - int y2 = luaL_optint(l,4,-1); - int rx = luaL_optint(l,5,5); - int ry = luaL_optint(l,6,5); - int c = luaL_optint(l,7,luacon_model->GetActiveTool(0)->ToolID); - int brushID = luaL_optint(l,8,BRUSH_CIRCLE); - int flags = luaL_optint(l,9,luacon_sim->replaceModeFlags); - - Brush *brush = luacon_model->GetBrushByID(brushID); - if (!brush) - return luaL_error(l, "Invalid brush id '%d'", brushID); - auto newBrush = brush->Clone(); - newBrush->SetRadius(ui::Point(rx, ry)); - - luacon_sim->CreateLine(x1, y1, x2, y2, c, *newBrush, flags); - return 0; -} - -int LuaScriptInterface::simulation_createBox(lua_State * l) -{ - int x1 = luaL_optint(l,1,-1); - int y1 = luaL_optint(l,2,-1); - int x2 = luaL_optint(l,3,-1); - int y2 = luaL_optint(l,4,-1); - int c = luaL_optint(l,5,luacon_model->GetActiveTool(0)->ToolID); - int flags = luaL_optint(l,6,luacon_sim->replaceModeFlags); - - luacon_sim->CreateBox(x1, y1, x2, y2, c, flags); - return 0; -} - -int LuaScriptInterface::simulation_floodParts(lua_State * l) -{ - int x = luaL_optint(l,1,-1); - int y = luaL_optint(l,2,-1); - int c = luaL_optint(l,3,luacon_model->GetActiveTool(0)->ToolID); - int cm = luaL_optint(l,4,-1); - int flags = luaL_optint(l,5,luacon_sim->replaceModeFlags); - - if (x < 0 || x >= XRES || y < 0 || y >= YRES) - return luaL_error(l, "coordinates out of range (%d,%d)", x, y); - - int ret = luacon_sim->FloodParts(x, y, c, cm, flags); - lua_pushinteger(l, ret); - return 1; -} - -int LuaScriptInterface::simulation_createWalls(lua_State * l) -{ - int x = luaL_optint(l,1,-1); - int y = luaL_optint(l,2,-1); - int rx = luaL_optint(l,3,0); - int ry = luaL_optint(l,4,0); - int c = luaL_optint(l,5,8); - - if (x < 0 || x >= XRES || y < 0 || y >= YRES) - return luaL_error(l, "coordinates out of range (%d,%d)", x, y); - if (c < 0 || c >= UI_WALLCOUNT) - return luaL_error(l, "Unrecognised wall id '%d'", c); - - int ret = luacon_sim->CreateWalls(x, y, rx, ry, c, NULL); - lua_pushinteger(l, ret); - return 1; -} - -int LuaScriptInterface::simulation_createWallLine(lua_State * l) -{ - int x1 = luaL_optint(l,1,-1); - int y1 = luaL_optint(l,2,-1); - int x2 = luaL_optint(l,3,-1); - int y2 = luaL_optint(l,4,-1); - int rx = luaL_optint(l,5,0); - int ry = luaL_optint(l,6,0); - int c = luaL_optint(l,7,8); - - 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 (c < 0 || c >= UI_WALLCOUNT) - return luaL_error(l, "Unrecognised wall id '%d'", c); - - luacon_sim->CreateWallLine(x1, y1, x2, y2, rx, ry, c, NULL); - return 0; -} - -int LuaScriptInterface::simulation_createWallBox(lua_State * l) -{ - int x1 = luaL_optint(l,1,-1); - int y1 = luaL_optint(l,2,-1); - int x2 = luaL_optint(l,3,-1); - int y2 = luaL_optint(l,4,-1); - int c = luaL_optint(l,5,8); - - 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 (c < 0 || c >= UI_WALLCOUNT) - return luaL_error(l, "Unrecognised wall id '%d'", c); - - luacon_sim->CreateWallBox(x1, y1, x2, y2, c); - return 0; -} - -int LuaScriptInterface::simulation_floodWalls(lua_State * l) -{ - int x = luaL_optint(l,1,-1); - int y = luaL_optint(l,2,-1); - int c = luaL_optint(l,3,8); - int bm = luaL_optint(l,4,-1); - if (x < 0 || x >= XRES || y < 0 || y >= YRES) - return luaL_error(l, "coordinates out of range (%d,%d)", x, y); - if (c < 0 || c >= UI_WALLCOUNT) - return luaL_error(l, "Unrecognised wall id '%d'", c); - if (c == WL_STREAM) - { - lua_pushinteger(l, 0); - return 1; - } - int ret = luacon_sim->FloodWalls(x, y, c, bm); - lua_pushinteger(l, ret); - return 1; -} - -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); - int ry = luaL_optint(l,4,5); - int tool = luaL_optint(l,5,0); - int brushID = luaL_optint(l,6,BRUSH_CIRCLE); - float strength = luaL_optnumber(l,7,1.0f); - if (tool == (int)sd.tools.size()) - { - lua_pushinteger(l, 0); - return 1; - } - else if (tool < 0 || tool > (int)sd.tools.size()) - return luaL_error(l, "Invalid tool id '%d'", tool); - - Brush *brush = luacon_model->GetBrushByID(brushID); - if (!brush) - return luaL_error(l, "Invalid brush id '%d'", brushID); - auto newBrush = brush->Clone(); - newBrush->SetRadius(ui::Point(rx, ry)); - - int ret = luacon_sim->ToolBrush(x, y, tool, *newBrush, strength); - lua_pushinteger(l, ret); - return 1; -} - -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); - int y2 = luaL_optint(l,4,-1); - int rx = luaL_optint(l,5,5); - int ry = luaL_optint(l,6,5); - int tool = luaL_optint(l,7,0); - int brushID = luaL_optint(l,8,BRUSH_CIRCLE); - float strength = luaL_optnumber(l,9,1.0f); - - 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)sd.tools.size()+1) - return luaL_error(l, "Invalid tool id '%d'", tool); - - Brush *brush = luacon_model->GetBrushByID(brushID); - if (!brush) - return luaL_error(l, "Invalid brush id '%d'", brushID); - auto newBrush = brush->Clone(); - newBrush->SetRadius(ui::Point(rx, ry)); - - if (tool == (int)sd.tools.size()) - { - Tool *windTool = luacon_model->GetToolFromIdentifier("DEFAULT_UI_WIND"); - float oldStrength = windTool->Strength; - windTool->Strength = strength; - windTool->DrawLine(luacon_sim, *newBrush, ui::Point(x1, y1), ui::Point(x2, y2)); - windTool->Strength = oldStrength; - } - else - luacon_sim->ToolLine(x1, y1, x2, y2, tool, *newBrush, strength); - return 0; -} - -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); - int y2 = luaL_optint(l,4,-1); - 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); - int tool = luaL_optint(l,5,0); - float strength = luaL_optnumber(l,6,1.0f); - if (tool == (int)sd.tools.size()) - { - lua_pushinteger(l, 0); - return 1; - } - 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); - return 0; -} - -int LuaScriptInterface::simulation_decoBrush(lua_State * l) -{ - int x = luaL_optint(l,1,-1); - int y = luaL_optint(l,2,-1); - int rx = luaL_optint(l,3,5); - int ry = luaL_optint(l,4,5); - int r = luaL_optint(l,5,255); - int g = luaL_optint(l,6,255); - int b = luaL_optint(l,7,255); - int a = luaL_optint(l,8,255); - int tool = luaL_optint(l,9,DECO_DRAW); - int brushID = luaL_optint(l,10,BRUSH_CIRCLE); - - Brush *brush = luacon_model->GetBrushByID(brushID); - if (!brush) - return luaL_error(l, "Invalid brush id '%d'", brushID); - auto newBrush = brush->Clone(); - newBrush->SetRadius(ui::Point(rx, ry)); - - luacon_sim->ApplyDecorationPoint(x, y, r, g, b, a, tool, *newBrush); - return 0; -} - -int LuaScriptInterface::simulation_decoLine(lua_State * l) -{ - int x1 = luaL_optint(l,1,-1); - int y1 = luaL_optint(l,2,-1); - int x2 = luaL_optint(l,3,-1); - int y2 = luaL_optint(l,4,-1); - int rx = luaL_optint(l,5,5); - int ry = luaL_optint(l,6,5); - int r = luaL_optint(l,7,255); - int g = luaL_optint(l,8,255); - int b = luaL_optint(l,9,255); - int a = luaL_optint(l,10,255); - int tool = luaL_optint(l,11,DECO_DRAW); - int brushID = luaL_optint(l,12,BRUSH_CIRCLE); - - 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); - - Brush *brush = luacon_model->GetBrushByID(brushID); - if (!brush) - return luaL_error(l, "Invalid brush id '%d'", brushID); - auto newBrush = brush->Clone(); - newBrush->SetRadius(ui::Point(rx, ry)); - - luacon_sim->ApplyDecorationLine(x1, y1, x2, y2, r, g, b, a, tool, *newBrush); - return 0; -} - -int LuaScriptInterface::simulation_decoBox(lua_State * l) -{ - int x1 = luaL_optint(l,1,-1); - int y1 = luaL_optint(l,2,-1); - int x2 = luaL_optint(l,3,-1); - int y2 = luaL_optint(l,4,-1); - int r = luaL_optint(l,5,255); - int g = luaL_optint(l,6,255); - int b = luaL_optint(l,7,255); - int a = luaL_optint(l,8,255); - int tool = luaL_optint(l,9,0); - - 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); - - luacon_sim->ApplyDecorationBox(x1, y1, x2, y2, r, g, b, a, tool); - return 0; -} - -int LuaScriptInterface::simulation_decoColor(lua_State * l) -{ - int acount = lua_gettop(l); - RGBA color(0, 0, 0, 0); - if (acount == 0) - { - lua_pushnumber(l, luacon_model->GetColourSelectorColour().Pack()); - return 1; - } - else if (acount == 1) - color = RGBA::Unpack(pixel_rgba(luaL_optnumber(l, 1, 0xFFFF0000))); - else - { - color.Red = std::clamp(luaL_optint(l, 1, 255), 0, 255); - color.Green = std::clamp(luaL_optint(l, 2, 255), 0, 255); - color.Blue = std::clamp(luaL_optint(l, 3, 255), 0, 255); - color.Alpha = std::clamp(luaL_optint(l, 4, 255), 0, 255); - } - luacon_model->SetColourSelectorColour(color); - 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 - auto loc = RGB::Unpack(luacon_ren->GetPixel({ x, y })); - luacon_sim->ApplyDecorationFill(luacon_ren, x, y, r, g, b, a, loc.Red, loc.Green, loc.Blue); - return 0; -} - -int LuaScriptInterface::simulation_clearSim(lua_State * l) -{ - luacon_controller->ClearSim(); - return 0; -} - -int LuaScriptInterface::simulation_clearRect(lua_State * l) -{ - int x = luaL_checkint(l,1); - int y = luaL_checkint(l,2); - int w = luaL_checkint(l,3)-1; - int h = luaL_checkint(l,4)-1; - luacon_sim->clear_area(x, y, w, h); - return 0; -} - -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 && (elements[luacon_sim->parts[i].type].HeatConduct || !onlyConductors)) - { - luacon_sim->parts[i].temp = elements[luacon_sim->parts[i].type].DefaultProperties.temp; - } - } - return 0; -} - -int LuaScriptInterface::simulation_resetPressure(lua_State * l) -{ - int aCount = lua_gettop(l), width = XCELLS, height = YCELLS; - int x1 = abs(luaL_optint(l, 1, 0)); - int y1 = abs(luaL_optint(l, 2, 0)); - if (aCount > 2) - { - width = abs(luaL_optint(l, 3, XCELLS)); - height = abs(luaL_optint(l, 4, YCELLS)); - } - else if (aCount) - { - width = 1; - height = 1; - } - if(x1 > XCELLS-1) - x1 = XCELLS-1; - if(y1 > YCELLS-1) - y1 = YCELLS-1; - if(x1+width > XCELLS-1) - width = XCELLS-x1; - if(y1+height > YCELLS-1) - height = YCELLS-y1; - for (int nx = x1; nxair->pv[ny][nx] = 0; - } - return 0; -} - -int LuaScriptInterface::simulation_saveStamp(lua_State * l) -{ - int x = luaL_optint(l,1,0); - int y = luaL_optint(l,2,0); - int w = luaL_optint(l,3,XRES-1); - int h = luaL_optint(l,4,YRES-1); - bool includePressure = luaL_optint(l, 5, 1); - ByteString name = luacon_controller->StampRegion(ui::Point(x, y), ui::Point(x+w, y+h), includePressure); - tpt_lua_pushByteString(l, name); - return 1; -} - -int LuaScriptInterface::simulation_loadStamp(lua_State * l) -{ - int i = -1; - int pushed = 1; - std::unique_ptr tempfile; - Vec2 partP = { - luaL_optint(l, 2, 0), - luaL_optint(l, 3, 0), - }; - auto hflip = lua_toboolean(l, 4); - auto rotation = luaL_optint(l, 5, 0) & 3; // [0, 3] rotations - bool includePressure = luaL_optint(l, 6, 1); - auto &client = Client::Ref(); - if (lua_isstring(l, 1)) //Load from 10 char name, or full filename - { - auto filename = tpt_lua_optByteString(l, 1, ""); - tempfile = client.GetStamp(filename); - } - if ((!tempfile || !tempfile->GetGameSave()) && lua_isnumber(l, 1)) //Load from stamp ID - { - i = luaL_optint(l, 1, 0); - auto &stampIDs = client.GetStamps(); - if (i < 0 || i >= int(stampIDs.size())) - return luaL_error(l, "Invalid stamp ID: %d", i); - tempfile = client.GetStamp(stampIDs[i]); - } - - if (tempfile && tempfile->GetGameSave()) - { - auto gameSave = tempfile->TakeGameSave(); - auto [ quoX, remX ] = floorDiv(partP.X, CELL); - auto [ quoY, remY ] = floorDiv(partP.Y, CELL); - if (remX || remY || hflip || rotation) - { - auto transform = Mat2::Identity; - if (hflip) - { - transform = Mat2::MirrorX * transform; - } - for (auto i = 0; i < rotation; ++i) - { - transform = Mat2::CCW * transform; - } - gameSave->Transform(transform, { remX, remY }); - } - luacon_sim->Load(gameSave.get(), includePressure, { quoX, quoY }); - lua_pushinteger(l, 1); - - if (gameSave->authors.size()) - { - gameSave->authors["type"] = "luastamp"; - client.MergeStampAuthorInfo(gameSave->authors); - } - } - else - { - pushed = 2; - lua_pushnil(l); - tpt_lua_pushString(l, tempfile ? tempfile->GetError() : "does not exist"); - } - return pushed; -} - -int LuaScriptInterface::simulation_deleteStamp(lua_State * l) -{ - auto &client = Client::Ref(); - auto &stampIDs = client.GetStamps(); - - if (lua_isstring(l, 1)) //note: lua_isstring returns true on numbers too - { - auto filename = tpt_lua_optByteString(l, 1, ""); - for (auto &stampID : stampIDs) - { - if (stampID == filename) - { - client.DeleteStamp(stampID); - return 0; - } - } - } - if (lua_isnumber(l, 1)) //Load from stamp ID - { - int i = luaL_optint(l, 1, 0); - if (i < 0 || i >= int(stampIDs.size())) - return luaL_error(l, "Invalid stamp ID: %d", i); - client.DeleteStamp(stampIDs[i]); - return 0; - } - lua_pushnumber(l, -1); - return 1; -} - -static int simulation_listStamps(lua_State *l) -{ - lua_newtable(l); - auto &client = Client::Ref(); - auto &stampIDs = client.GetStamps(); - auto i = 0; - for (auto &stampID : stampIDs) - { - tpt_lua_pushByteString(l, stampID); - i += 1; - lua_rawseti(l, -2, i); - } - return 1; -} - -int LuaScriptInterface::simulation_loadSave(lua_State * l) -{ - int saveID = luaL_optint(l,1,0); - int instant = luaL_optint(l,2,0); - int history = luaL_optint(l,3,0); //Exact second a previous save was saved - luacon_controller->OpenSavePreview(saveID, history, instant ? savePreviewInstant : savePreviewNormal); - return 0; -} - -int LuaScriptInterface::simulation_reloadSave(lua_State * l) -{ - luacon_controller->ReloadSim(); - return 0; -} - -int LuaScriptInterface::simulation_getSaveID(lua_State *l) -{ - auto *tempSave = luacon_model->GetSave(); - if (tempSave) - { - lua_pushinteger(l, tempSave->GetID()); - lua_pushinteger(l, tempSave->Version); - return 2; - } - return 0; -} - -int LuaScriptInterface::simulation_adjustCoords(lua_State * l) -{ - int x = luaL_optint(l,1,0); - int y = luaL_optint(l,2,0); - ui::Point Coords = luacon_controller->PointTranslate(ui::Point(x, y)); - lua_pushinteger(l, Coords.X); - lua_pushinteger(l, Coords.Y); - return 2; -} - -int LuaScriptInterface::simulation_prettyPowders(lua_State * l) -{ - int acount = lua_gettop(l); - if (acount == 0) - { - lua_pushnumber(l, luacon_sim->pretty_powder); - return 1; - } - int prettyPowder = luaL_optint(l, 1, 0); - luacon_sim->pretty_powder = prettyPowder; - luacon_model->UpdateQuickOptions(); - return 0; -} - -int LuaScriptInterface::simulation_gravityGrid(lua_State * l) -{ - int acount = lua_gettop(l); - if (acount == 0) - { - lua_pushnumber(l, luacon_model->GetGravityGrid()); - return 1; - } - int gravityGrid = luaL_optint(l, 1, 0); - luacon_model->ShowGravityGrid(gravityGrid); - luacon_model->UpdateQuickOptions(); - return 0; -} - -int LuaScriptInterface::simulation_edgeMode(lua_State * l) -{ - int acount = lua_gettop(l); - if (acount == 0) - { - lua_pushnumber(l, luacon_model->GetEdgeMode()); - return 1; - } - int edgeMode = luaL_optint(l, 1, EDGE_VOID); - luacon_model->SetEdgeMode(edgeMode); - return 0; -} - -int LuaScriptInterface::simulation_gravityMode(lua_State * l) -{ - int acount = lua_gettop(l); - if (acount == 0) - { - lua_pushnumber(l, luacon_sim->gravityMode); - return 1; - } - int gravityMode = luaL_optint(l, 1, GRAV_VERTICAL); - luacon_sim->gravityMode = gravityMode; - return 0; -} - -int LuaScriptInterface::simulation_customGravity(lua_State * l) -{ - int acount = lua_gettop(l); - if (acount == 0) - { - lua_pushnumber(l, luacon_sim->customGravityX); - lua_pushnumber(l, luacon_sim->customGravityY); - return 2; - } - else if (acount == 1) - { - luacon_sim->customGravityX = 0.0f; - luacon_sim->customGravityY = luaL_optnumber(l, 1, 0.0f); - return 0; - } - luacon_sim->customGravityX = luaL_optnumber(l, 1, 0.0f); - luacon_sim->customGravityY = luaL_optnumber(l, 2, 0.0f); - return 0; -} - -int LuaScriptInterface::simulation_airMode(lua_State * l) -{ - int acount = lua_gettop(l); - if (acount == 0) - { - lua_pushnumber(l, luacon_sim->air->airMode); - return 1; - } - int airMode = luaL_optint(l, 1, AIR_ON); - luacon_sim->air->airMode = airMode; - return 0; -} - -int LuaScriptInterface::simulation_waterEqualisation(lua_State * l) -{ - int acount = lua_gettop(l); - if (acount == 0) - { - lua_pushnumber(l, luacon_sim->water_equal_test); - return 1; - } - int waterMode = luaL_optint(l, 1, 0); - luacon_sim->water_equal_test = waterMode; - return 0; -} - -int LuaScriptInterface::simulation_ambientAirTemp(lua_State * l) -{ - int acount = lua_gettop(l); - if (acount == 0) - { - lua_pushnumber(l, luacon_sim->air->ambientAirTemp); - return 1; - } - float ambientAirTemp = restrict_flt(luaL_optnumber(l, 1, R_TEMP + 273.15f), MIN_TEMP, MAX_TEMP); - luacon_model->SetAmbientAirTemperature(ambientAirTemp); - return 0; -} - -int LuaScriptInterface::simulation_elementCount(lua_State * l) -{ - int element = luaL_optint(l, 1, 0); - if (element < 0 || element >= PT_NUM) - return luaL_error(l, "Invalid element ID (%d)", element); - - lua_pushnumber(l, luacon_sim->elementCount[element]); - return 1; -} - -int LuaScriptInterface::simulation_canMove(lua_State * l) -{ - auto *luacon_ci = static_cast(commandInterface); - int movingElement = luaL_checkint(l, 1); - int destinationElement = luaL_checkint(l, 2); - if (movingElement < 0 || movingElement >= PT_NUM) - return luaL_error(l, "Invalid element ID (%d)", movingElement); - if (destinationElement < 0 || destinationElement >= PT_NUM) - return luaL_error(l, "Invalid element ID (%d)", destinationElement); - - if (lua_gettop(l) < 3) - { - 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; - auto &sd = SimulationData::Ref(); - sd.can_move[movingElement][destinationElement] = setting; - return 0; - } -} - -int BrushClosure(lua_State * l) -{ - // see Simulation::ToolBrush - int positionX = lua_tointeger(l, lua_upvalueindex(1)); - int positionY = lua_tointeger(l, lua_upvalueindex(2)); - int i = lua_tointeger(l, lua_upvalueindex(3)); - int size = lua_tointeger(l, lua_upvalueindex(4)); - auto points = reinterpret_cast(lua_touserdata(l, lua_upvalueindex(5))); - - if (i == size) - return 0; - - lua_pushnumber(l, i + 1); - lua_replace(l, lua_upvalueindex(3)); - - lua_pushnumber(l, points[i].X + positionX); - lua_pushnumber(l, points[i].Y + positionY); - return 2; -} - -int LuaScriptInterface::simulation_brush(lua_State * l) -{ - int argCount = lua_gettop(l); - int positionX = luaL_checkint(l, 1); - int positionY = luaL_checkint(l, 2); - int brushradiusX, brushradiusY; - if (argCount >= 4) - { - brushradiusX = luaL_checkint(l, 3); - brushradiusY = luaL_checkint(l, 4); - } - else - { - ui::Point radius = luacon_model->GetBrush().GetRadius(); - brushradiusX = radius.X; - brushradiusY = radius.Y; - } - int brushID = luaL_optint(l, 5, luacon_model->GetBrushID()); - - Brush *brush = luacon_model->GetBrushByID(brushID); - if (!brush) - return luaL_error(l, "Invalid brush id '%d'", brushID); - auto newBrush = brush->Clone(); - newBrush->SetRadius(ui::Point(brushradiusX, brushradiusY)); - lua_pushnumber(l, positionX); - lua_pushnumber(l, positionY); - std::vector points; - std::copy(newBrush->begin(), newBrush->end(), std::back_inserter(points)); - lua_pushnumber(l, 0); // index - lua_pushnumber(l, int(points.size())); - auto points_ud = reinterpret_cast(lua_newuserdata(l, points.size() * sizeof(ui::Point))); - std::copy(points.begin(), points.end(), points_ud); - - lua_pushcclosure(l, BrushClosure, 5); - return 1; -} - -int PartsClosure(lua_State *l) -{ - for (int i = lua_tointeger(l, lua_upvalueindex(1)); i <= luacon_sim->parts_lastActiveIndex; ++i) - { - if (luacon_sim->parts[i].type) - { - lua_pushnumber(l, i + 1); - lua_replace(l, lua_upvalueindex(1)); - lua_pushnumber(l, i); - return 1; - } - } - return 0; -} - -static int NeighboursClosure(lua_State *l) -{ - int cx = lua_tointeger(l, lua_upvalueindex(1)); - int cy = lua_tointeger(l, lua_upvalueindex(2)); - int rx = lua_tointeger(l, lua_upvalueindex(3)); - int ry = lua_tointeger(l, lua_upvalueindex(4)); - int t = lua_tointeger(l, lua_upvalueindex(5)); - int x = lua_tointeger(l, lua_upvalueindex(6)); - int y = lua_tointeger(l, lua_upvalueindex(7)); - while (y <= cy + ry) - { - int px = x; - int py = y; - x += 1; - if (x > cx + rx) - { - x = cx - rx; - y += 1; - } - int r = luacon_sim->pmap[py][px]; - if (!(r && (!t || TYP(r) == t))) // * If not [exists and is of the correct type] - { - r = 0; - } - if (!r) - { - r = luacon_sim->photons[py][px]; - if (!(r && (!t || TYP(r) == t))) // * If not [exists and is of the correct type] - { - r = 0; - } - } - if (cx == px && cy == py) - { - r = 0; - } - if (r) - { - lua_pushnumber(l, x); - lua_replace(l, lua_upvalueindex(6)); - lua_pushnumber(l, y); - lua_replace(l, lua_upvalueindex(7)); - lua_pushnumber(l, ID(r)); - lua_pushnumber(l, px); - lua_pushnumber(l, py); - return 3; - } - } - return 0; -} - -int LuaScriptInterface::simulation_neighbours(lua_State * l) -{ - int cx = luaL_checkint(l, 1); - int cy = luaL_checkint(l, 2); - int rx = luaL_optint(l, 3, 2); - int ry = luaL_optint(l, 4, 2); - int t = luaL_optint(l, 5, PT_NONE); - if (rx < 0 || ry < 0) - { - luaL_error(l, "Invalid radius"); - } - lua_pushnumber(l, cx); - lua_pushnumber(l, cy); - lua_pushnumber(l, rx); - lua_pushnumber(l, ry); - lua_pushnumber(l, t); - lua_pushnumber(l, cx - rx); - lua_pushnumber(l, cy - ry); - lua_pushcclosure(l, NeighboursClosure, 7); - return 1; -} - -int LuaScriptInterface::simulation_parts(lua_State *l) -{ - lua_pushnumber(l, 0); - lua_pushcclosure(l, PartsClosure, 1); - return 1; -} - -int LuaScriptInterface::simulation_pmap(lua_State * l) -{ - int x = luaL_checkint(l, 1); - int y = luaL_checkint(l, 2); - if (x < 0 || x >= XRES || y < 0 || y >= YRES) - return luaL_error(l, "coordinates out of range (%d,%d)", x, y); - int r = luacon_sim->pmap[y][x]; - if (!TYP(r)) - return 0; - lua_pushnumber(l, ID(r)); - return 1; -} - -int LuaScriptInterface::simulation_photons(lua_State * l) -{ - int x = luaL_checkint(l, 1); - int y = luaL_checkint(l, 2); - if (x < 0 || x >= XRES || y < 0 || y >= YRES) - return luaL_error(l, "coordinates out of range (%d,%d)", x, y); - int r = luacon_sim->photons[y][x]; - if (!TYP(r)) - return 0; - lua_pushnumber(l, ID(r)); - return 1; -} - -int LuaScriptInterface::simulation_framerender(lua_State * l) -{ - if (lua_gettop(l) == 0) - { - lua_pushinteger(l, luacon_sim->framerender); - return 1; - } - int frames = luaL_checkinteger(l, 1); - if (frames < 0) - return luaL_error(l, "Can't simulate a negative number of frames"); - luacon_sim->framerender = frames; - return 0; -} - -int LuaScriptInterface::simulation_gspeed(lua_State * l) -{ - if (lua_gettop(l) == 0) - { - lua_pushinteger(l, luacon_sim->GSPEED); - return 1; - } - int gspeed = luaL_checkinteger(l, 1); - if (gspeed < 1) - return luaL_error(l, "GSPEED must be at least 1"); - luacon_sim->GSPEED = gspeed; - return 0; -} - -int LuaScriptInterface::simulation_takeSnapshot(lua_State * l) -{ - luacon_controller->HistorySnapshot(); - return 0; -} - - -int LuaScriptInterface::simulation_historyRestore(lua_State *l) -{ - bool successful = luacon_controller->HistoryRestore(); - lua_pushboolean(l, successful); - return 1; -} - -int LuaScriptInterface::simulation_historyForward(lua_State *l) -{ - bool successful = luacon_controller->HistoryForward(); - lua_pushboolean(l, successful); - return 1; -} - -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) -{ - auto &sd = SimulationData::CRef(); - int i = 0; - lua_newtable(l); - for (auto &cgol : sd.GetCustomGol()) - { - lua_newtable(l); - tpt_lua_pushString(l, cgol.nameString); - lua_setfield(l, -2, "name"); - tpt_lua_pushString(l, cgol.ruleString); - 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) -{ - auto &sd = SimulationData::CRef(); - int rule; - String ruleString; - if (lua_isnumber(l, 1)) - { - rule = luaL_checkinteger(l, 1); - ruleString = SerialiseGOLRule(rule); - rule = ParseGOLString(ruleString); - } - else - { - ruleString = tpt_lua_checkString(l, 1); - rule = ParseGOLString(ruleString); - } - String nameString = tpt_lua_checkString(l, 2); - 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 (sd.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 = tpt_lua_checkByteString(l, 1); - bool removedAny = luacon_model->RemoveCustomGOLType("DEFAULT_PT_LIFECUST_" + nameString); - if (removedAny) - luacon_model->BuildMenus(); - lua_pushboolean(l, removedAny); - return 1; -} - -int LuaScriptInterface::simulation_lastUpdatedID(lua_State *l) -{ - if (luacon_sim->debug_mostRecentlyUpdated != -1) - { - lua_pushinteger(l, luacon_sim->debug_mostRecentlyUpdated); - } - else - { - lua_pushnil(l); - } - return 1; -} - -int LuaScriptInterface::simulation_updateUpTo(lua_State *l) -{ - // sim.updateUpTo dispatches an update to the range [current, upTo], but GameModel::UpdateUpTo takes a range [current, upTo). - // As a result, upTo here will be one smaller than it's logical for the duration of this function. - int upTo = NPART - 1; - if (lua_gettop(l) > 0) - { - upTo = luaL_checkinteger(l, 1); - } - if (upTo < -1 || upTo >= NPART) // -1 instead of 0 to allow for the empty range [0, -1] aka [0, 0) - { - return luaL_error(l, "ID not in valid range"); - } - luacon_sim->framerender = 1; - luacon_model->UpdateUpTo(upTo + 1); - return 0; -} - -int LuaScriptInterface::simulation_temperatureScale(lua_State *l) -{ - if (lua_gettop(l) == 0) - { - lua_pushinteger(l, luacon_model->GetTemperatureScale()); - return 1; - } - int temperatureScale = luaL_checkinteger(l, 1); - if (temperatureScale < 0 || temperatureScale > 2) - return luaL_error(l, "Invalid temperature scale"); - luacon_model->SetTemperatureScale(temperatureScale); - return 0; -} - -//// Begin Renderer API - -static int ren_hud(lua_State* l) -{ - int acount = lua_gettop(l); - if (acount == 0) - { - lua_pushboolean(l, luacon_controller->GetHudEnable()); - return 1; - } - auto hudstate = lua_toboolean(l, 1); - luacon_controller->SetHudEnable(hudstate); - return 0; -} - -static int ren_debugHud(lua_State * l) -{ - int acount = lua_gettop(l); - if (acount == 0) - { - lua_pushboolean(l, luacon_controller->GetDebugHUD()); - return 1; - } - auto debug = lua_toboolean(l, 1); - luacon_controller->SetDebugHUD(debug); - return 0; -} - -void LuaScriptInterface::initRendererAPI() -{ - //Methods - struct luaL_Reg rendererAPIMethods [] = { - {"renderModes", renderer_renderModes}, - {"displayModes", renderer_displayModes}, - {"colorMode", renderer_colourMode}, //Duplicate of above to make Americans happy - {"decorations", renderer_decorations}, - {"grid", renderer_grid}, - {"debugHud", ren_debugHud}, - {"hud", ren_hud}, - {"showBrush", renderer_showBrush}, - {"depth3d", renderer_depth3d}, - {"zoomEnabled", renderer_zoomEnabled}, - {"zoomWindow", renderer_zoomWindowInfo}, - {"zoomScope", renderer_zoomScopeInfo}, - {"fireSize", ren_fireSize}, - {"useDisplayPreset", ren_useDisplayPreset}, - {NULL, NULL} - }; - luaL_register(l, "renderer", rendererAPIMethods); - - //Static values - //Particle pixel modes/fire mode/effects - SETCONST(l, PMODE); - SETCONST(l, PMODE_NONE); - SETCONST(l, PMODE_FLAT); - SETCONST(l, PMODE_BLOB); - SETCONST(l, PMODE_BLUR); - SETCONST(l, PMODE_GLOW); - SETCONST(l, PMODE_SPARK); - SETCONST(l, PMODE_FLARE); - SETCONST(l, PMODE_LFLARE); - SETCONST(l, PMODE_ADD); - SETCONST(l, PMODE_BLEND); - SETCONST(l, PSPEC_STICKMAN); - SETCONST(l, OPTIONS); - SETCONST(l, NO_DECO); - SETCONST(l, DECO_FIRE); - SETCONST(l, FIREMODE); - SETCONST(l, FIRE_ADD); - SETCONST(l, FIRE_BLEND); - SETCONST(l, FIRE_SPARK); - SETCONST(l, EFFECT); - SETCONST(l, EFFECT_GRAVIN); - SETCONST(l, EFFECT_GRAVOUT); - SETCONST(l, EFFECT_LINES); - SETCONST(l, EFFECT_DBGLINES); - - //Display/Render/Colour modes - SETCONST(l, RENDER_EFFE); - SETCONST(l, RENDER_FIRE); - SETCONST(l, RENDER_GLOW); - SETCONST(l, RENDER_BLUR); - SETCONST(l, RENDER_BLOB); - SETCONST(l, RENDER_BASC); - SETCONST(l, RENDER_NONE); - SETCONST(l, COLOUR_HEAT); - SETCONST(l, COLOUR_LIFE); - SETCONST(l, COLOUR_GRAD); - SETCONST(l, COLOUR_BASC); - SETCONST(l, COLOUR_DEFAULT); - SETCONST(l, DISPLAY_AIRC); - SETCONST(l, DISPLAY_AIRP); - SETCONST(l, DISPLAY_AIRV); - SETCONST(l, DISPLAY_AIRH); - SETCONST(l, DISPLAY_AIR); - SETCONST(l, DISPLAY_WARP); - SETCONST(l, DISPLAY_PERS); - SETCONST(l, DISPLAY_EFFE); - - lua_pop(l, 1); - - //Ren shortcut - lua_getglobal(l, "renderer"); - lua_setglobal(l, "ren"); -} - -//get/set render modes list -int LuaScriptInterface::renderer_renderModes(lua_State * l) -{ - int args = lua_gettop(l); - if(args) - { - int size = 0; - luaL_checktype(l, 1, LUA_TTABLE); - size = lua_objlen(l, 1); - - std::vector renderModes; - for(int i = 1; i <= size; i++) - { - lua_rawgeti(l, 1, i); - renderModes.push_back(lua_tointeger(l, -1)); - lua_pop(l, 1); - } - luacon_ren->SetRenderMode(renderModes); - return 0; - } - else - { - lua_newtable(l); - std::vector renderModes = luacon_ren->GetRenderMode(); - int i = 1; - for(std::vector::iterator iter = renderModes.begin(), end = renderModes.end(); iter != end; ++iter) - { - lua_pushinteger(l, *iter); - lua_rawseti(l, -2, i++); - } - return 1; - } -} - -int LuaScriptInterface::renderer_displayModes(lua_State * l) -{ - int args = lua_gettop(l); - if(args) - { - int size = 0; - luaL_checktype(l, 1, LUA_TTABLE); - size = lua_objlen(l, 1); - - std::vector displayModes; - for(int i = 1; i <= size; i++) - { - lua_rawgeti(l, 1, i); - displayModes.push_back(lua_tointeger(l, -1)); - lua_pop(l, 1); - } - luacon_ren->SetDisplayMode(displayModes); - return 0; - } - else - { - lua_newtable(l); - std::vector displayModes = luacon_ren->GetDisplayMode(); - int i = 1; - for(std::vector::iterator iter = displayModes.begin(), end = displayModes.end(); iter != end; ++iter) - { - lua_pushinteger(l, *iter); - lua_rawseti(l, -2, i++); - } - return 1; - } -} - -int LuaScriptInterface::renderer_colourMode(lua_State * l) -{ - int args = lua_gettop(l); - if(args) - { - luaL_checktype(l, 1, LUA_TNUMBER); - luacon_ren->SetColourMode(lua_tointeger(l, 1)); - return 0; - } - else - { - lua_pushinteger(l, luacon_ren->GetColourMode()); - return 1; - } -} - -int LuaScriptInterface::renderer_decorations(lua_State * l) -{ - int acount = lua_gettop(l); - if (acount == 0) - { - lua_pushboolean(l, luacon_model->GetDecoration()); - return 1; - } - int decostate = lua_toboolean(l, 1); - luacon_model->SetDecoration(decostate); - luacon_model->UpdateQuickOptions(); - return 0; -} - -int LuaScriptInterface::renderer_grid(lua_State * l) -{ - int acount = lua_gettop(l); - if (acount == 0) - { - lua_pushnumber(l, luacon_ren->GetGridSize()); - return 1; - } - int grid = luaL_optint(l, 1, -1); - luacon_ren->SetGridSize(grid); - return 0; -} - -int LuaScriptInterface::renderer_showBrush(lua_State * l) -{ - int acount = lua_gettop(l); - if (acount == 0) - { - lua_pushnumber(l, luacon_controller->GetBrushEnable()); - return 1; - } - int brush = luaL_optint(l, 1, -1); - luacon_controller->SetBrushEnable(brush); - return 0; -} - -int LuaScriptInterface::renderer_depth3d(lua_State * l) -{ - return luaL_error(l, "This feature is no longer supported"); -} - -int LuaScriptInterface::renderer_zoomEnabled(lua_State * l) -{ - if (lua_gettop(l) == 0) - { - lua_pushboolean(l, luacon_ren->zoomEnabled); - return 1; - } - else - { - luaL_checktype(l, -1, LUA_TBOOLEAN); - luacon_ren->zoomEnabled = lua_toboolean(l, -1); - return 0; - } -} -int LuaScriptInterface::renderer_zoomWindowInfo(lua_State * l) -{ - if (lua_gettop(l) == 0) - { - ui::Point location = luacon_ren->zoomWindowPosition; - lua_pushnumber(l, location.X); - lua_pushnumber(l, location.Y); - lua_pushnumber(l, luacon_ren->ZFACTOR); - lua_pushnumber(l, luacon_ren->zoomScopeSize * luacon_ren->ZFACTOR); - return 4; - } - int x = luaL_optint(l, 1, 0); - int y = luaL_optint(l, 2, 0); - int f = luaL_optint(l, 3, 0); - if (f <= 0) - return luaL_error(l, "Zoom factor must be greater than 0"); - - // To prevent crash when zoom window is outside screen - if (x < 0 || y < 0 || luacon_ren->zoomScopeSize * f + x > XRES || luacon_ren->zoomScopeSize * f + y > YRES) - return luaL_error(l, "Zoom window outside of bounds"); - - luacon_ren->zoomWindowPosition = ui::Point(x, y); - luacon_ren->ZFACTOR = f; - return 0; -} -int LuaScriptInterface::renderer_zoomScopeInfo(lua_State * l) -{ - if (lua_gettop(l) == 0) - { - ui::Point location = luacon_ren->zoomScopePosition; - lua_pushnumber(l, location.X); - lua_pushnumber(l, location.Y); - lua_pushnumber(l, luacon_ren->zoomScopeSize); - return 3; - } - int x = luaL_optint(l, 1, 0); - int y = luaL_optint(l, 2, 0); - int s = luaL_optint(l, 3, 0); - if (s <= 0) - return luaL_error(l, "Zoom scope size must be greater than 0"); - - // To prevent crash when zoom or scope window is outside screen - int windowEdgeRight = luacon_ren->ZFACTOR * s + luacon_ren->zoomWindowPosition.X; - int windowEdgeBottom = luacon_ren->ZFACTOR * s + luacon_ren->zoomWindowPosition.Y; - if (x < 0 || y < 0 || x + s > XRES || y + s > YRES) - return luaL_error(l, "Zoom scope outside of bounds"); - if (windowEdgeRight > XRES || windowEdgeBottom > YRES) - return luaL_error(l, "Zoom window outside of bounds"); - - luacon_ren->zoomScopePosition = ui::Point(x, y); - luacon_ren->zoomScopeSize = s; - return 0; -} - -static int elem_getByName(lua_State *L) -{ - lua_pushinteger(L, SimulationData::CRef().GetParticleType(tpt_lua_checkByteString(L, 1))); - return 1; -} - -static void manageElementIdentifier(lua_State *l, int id, bool add) -{ - auto &sd = SimulationData::CRef(); - auto &elements = sd.elements; - if (elements[id].Enabled) - { - lua_getglobal(l, "elements"); - tpt_lua_pushByteString(l, elements[id].Identifier); - if (add) - { - lua_pushinteger(l, id); - } - else - { - lua_pushnil(l); - } - lua_settable(l, -3); - if (elements[id].Identifier.BeginsWith("DEFAULT_PT_")) - { - ByteString realIdentifier = ByteString::Build("DEFAULT_PT_", elements[id].Name.ToUtf8()); - if (id != 0 && id != PT_NBHL && id != PT_NWHL && elements[id].Identifier != realIdentifier) - { - tpt_lua_pushByteString(l, realIdentifier); - if (add) - { - lua_pushinteger(l, id); - } - else - { - lua_pushnil(l); - } - lua_settable(l, -3); - } - } - lua_pop(l, 1); - } -} - -void LuaScriptInterface::initElementsAPI() -{ - //Methods - struct luaL_Reg elementsAPIMethods [] = { - {"allocate", elements_allocate}, - {"element", elements_element}, - {"property", elements_property}, - {"free", elements_free}, - {"exists", elements_exists}, - {"loadDefault", elements_loadDefault}, - {"getByName", elem_getByName}, - {NULL, NULL} - }; - luaL_register(l, "elements", elementsAPIMethods); - - //Static values - //Element types/properties/states - SETCONST(l, TYPE_PART); - SETCONST(l, TYPE_LIQUID); - SETCONST(l, TYPE_SOLID); - SETCONST(l, TYPE_GAS); - SETCONST(l, TYPE_ENERGY); - SETCONST(l, PROP_CONDUCTS); - SETCONST(l, PROP_BLACK); - SETCONST(l, PROP_NEUTPENETRATE); - SETCONST(l, PROP_NEUTABSORB); - SETCONST(l, PROP_NEUTPASS); - SETCONST(l, PROP_DEADLY); - SETCONST(l, PROP_HOT_GLOW); - SETCONST(l, PROP_LIFE); - SETCONST(l, PROP_RADIOACTIVE); - SETCONST(l, PROP_LIFE_DEC); - SETCONST(l, PROP_LIFE_KILL); - SETCONST(l, PROP_LIFE_KILL_DEC); - SETCONST(l, PROP_SPARKSETTLE); - SETCONST(l, PROP_NOAMBHEAT); - SETCONST(l, PROP_NOCTYPEDRAW); - - SETCONST(l, SC_WALL); - SETCONST(l, SC_ELEC); - SETCONST(l, SC_POWERED); - SETCONST(l, SC_SENSOR); - SETCONST(l, SC_FORCE); - SETCONST(l, SC_EXPLOSIVE); - SETCONST(l, SC_GAS); - SETCONST(l, SC_LIQUID); - SETCONST(l, SC_POWDERS); - SETCONST(l, SC_SOLIDS); - SETCONST(l, SC_NUCLEAR); - SETCONST(l, SC_SPECIAL); - SETCONST(l, SC_LIFE); - SETCONST(l, SC_TOOL); - SETCONST(l, SC_DECO); - - lua_pop(l, 1); - - //elem shortcut - lua_getglobal(l, "elements"); - lua_setglobal(l, "elem"); - - for (int i = 0; i < PT_NUM; i++) - { - manageElementIdentifier(l, i, true); - } -} - -void LuaScriptInterface::LuaGetProperty(lua_State* l, StructProperty property, intptr_t propertyAddress) +void LuaGetProperty(lua_State *L, StructProperty property, intptr_t propertyAddress) { switch (property.Type) { case StructProperty::TransitionType: case StructProperty::ParticleType: case StructProperty::Integer: - lua_pushnumber(l, *((int*)propertyAddress)); + lua_pushnumber(L, *((int*)propertyAddress)); break; case StructProperty::UInteger: - lua_pushnumber(l, *((unsigned int*)propertyAddress)); + lua_pushnumber(L, *((unsigned int*)propertyAddress)); break; case StructProperty::Float: - lua_pushnumber(l, *((float*)propertyAddress)); + lua_pushnumber(L, *((float*)propertyAddress)); break; case StructProperty::UChar: - lua_pushnumber(l, *((unsigned char*)propertyAddress)); + lua_pushnumber(L, *((unsigned char*)propertyAddress)); break; case StructProperty::BString: { - tpt_lua_pushByteString(l, *((ByteString*)propertyAddress)); + tpt_lua_pushByteString(L, *((ByteString*)propertyAddress)); break; } case StructProperty::String: { - tpt_lua_pushString(l, *((String*)propertyAddress)); + tpt_lua_pushString(L, *((String*)propertyAddress)); break; } case StructProperty::Colour: - lua_pushinteger(l, *((unsigned int*)propertyAddress)); + lua_pushinteger(L, *((unsigned int*)propertyAddress)); break; case StructProperty::Removed: - lua_pushnil(l); + lua_pushnil(L); } } @@ -3500,1474 +253,121 @@ static int32_t int32_truncate(double n) return int32_t(n); } -void LuaScriptInterface::LuaSetProperty(lua_State* l, StructProperty property, intptr_t propertyAddress, int stackPos) +void LuaSetProperty(lua_State *L, StructProperty property, intptr_t propertyAddress, int stackPos) { switch (property.Type) { case StructProperty::TransitionType: case StructProperty::ParticleType: case StructProperty::Integer: - *((int*)propertyAddress) = int32_truncate(luaL_checknumber(l, stackPos)); + *((int*)propertyAddress) = int32_truncate(luaL_checknumber(L, stackPos)); break; case StructProperty::UInteger: - *((unsigned int*)propertyAddress) = int32_truncate(luaL_checknumber(l, stackPos)); + *((unsigned int*)propertyAddress) = int32_truncate(luaL_checknumber(L, stackPos)); break; case StructProperty::Float: - *((float*)propertyAddress) = luaL_checknumber(l, stackPos); + *((float*)propertyAddress) = luaL_checknumber(L, stackPos); break; case StructProperty::UChar: - *((unsigned char*)propertyAddress) = int32_truncate(luaL_checknumber(l, stackPos)); + *((unsigned char*)propertyAddress) = int32_truncate(luaL_checknumber(L, stackPos)); break; case StructProperty::BString: - *((ByteString*)propertyAddress) = tpt_lua_checkByteString(l, stackPos); + *((ByteString*)propertyAddress) = tpt_lua_checkByteString(L, stackPos); break; case StructProperty::String: - *((String*)propertyAddress) = tpt_lua_checkString(l, stackPos); + *((String*)propertyAddress) = tpt_lua_checkString(L, stackPos); break; case StructProperty::Colour: - *((unsigned int*)propertyAddress) = int32_truncate(luaL_checknumber(l, stackPos)); + *((unsigned int*)propertyAddress) = int32_truncate(luaL_checknumber(L, stackPos)); break; case StructProperty::Removed: break; } } - -void LuaScriptInterface::LuaSetParticleProperty(lua_State* l, int particleID, StructProperty property, intptr_t propertyAddress, int stackPos) +void LuaSetParticleProperty(lua_State *L, int particleID, StructProperty property, intptr_t propertyAddress, int stackPos) { + auto *lsi = static_cast(commandInterface); + auto *sim = lsi->sim; if (property.Name == "type") { - luacon_sim->part_change_type(particleID, int(luacon_sim->parts[particleID].x+0.5f), int(luacon_sim->parts[particleID].y+0.5f), luaL_checkinteger(l, 3)); + sim->part_change_type(particleID, int(sim->parts[particleID].x+0.5f), int(sim->parts[particleID].y+0.5f), luaL_checkinteger(L, 3)); } else if (property.Name == "x" || property.Name == "y") { - float val = luaL_checknumber(l, 3); - float x = luacon_sim->parts[particleID].x; - float y = luacon_sim->parts[particleID].y; + float val = luaL_checknumber(L, 3); + float x = sim->parts[particleID].x; + float y = sim->parts[particleID].y; float nx = property.Name == "x" ? val : x; float ny = property.Name == "y" ? val : y; - luacon_sim->move(particleID, (int)(x + 0.5f), (int)(y + 0.5f), nx, ny); + sim->move(particleID, (int)(x + 0.5f), (int)(y + 0.5f), nx, ny); } else { - LuaSetProperty(l, property, propertyAddress, 3); + LuaSetProperty(L, property, propertyAddress, 3); } } -int LuaScriptInterface::elements_loadDefault(lua_State * l) -{ - auto &sd = SimulationData::Ref(); - std::unique_lock lk(sd.elementGraphicsMx); - auto &elements = sd.elements; - auto &builtinElements = GetElements(); - auto *luacon_ci = static_cast(commandInterface); - { - auto loadDefaultOne = [l, &elements, &builtinElements](int id) { - lua_getglobal(l, "elements"); - ByteString identifier = elements[id].Identifier; - tpt_lua_pushByteString(l, identifier); - lua_pushnil(l); - lua_settable(l, -3); - - manageElementIdentifier(l, id, false); - if (id < (int)builtinElements.size()) - elements[id] = builtinElements[id]; - else - elements[id] = Element(); - manageElementIdentifier(l, id, true); - - tpt_lua_pushByteString(l, identifier); - lua_pushinteger(l, id); - lua_settable(l, -3); - lua_pop(l, 1); - }; - 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"); - loadDefaultOne(id); - } - else - { - for (int i = 0; i < PT_NUM; i++) - { - loadDefaultOne(i); - } - } - } - - luacon_model->BuildMenus(); - for (auto moving = 0; moving < PT_NUM; ++moving) - { - for (auto into = 0; into < PT_NUM; ++into) - { - luacon_ci->custom_can_move[moving][into] = 0; - } - } - luacon_ci->custom_init_can_move(); - sd.graphicscache = std::array(); - return 0; -} - -int LuaScriptInterface::elements_allocate(lua_State * l) -{ - auto *luacon_ci = static_cast(commandInterface); - luaL_checktype(l, 1, LUA_TSTRING); - luaL_checktype(l, 2, LUA_TSTRING); - auto group = tpt_lua_toByteString(l, 1).ToUpper(); - auto id = tpt_lua_toByteString(l, 2).ToUpper(); - - if (id.Contains("_")) - { - return luaL_error(l, "The element name may not contain '_'."); - } - if (group.Contains("_")) - { - return luaL_error(l, "The group name may not contain '_'."); - } - if (group == "DEFAULT") - { - return luaL_error(l, "You cannot create elements in the 'DEFAULT' group."); - } - - auto identifier = group + "_PT_" + id; - - int newID = -1; - { - auto &sd = SimulationData::CRef(); - auto &elements = sd.elements; - for(int i = 0; i < PT_NUM; i++) - { - if(elements[i].Enabled && ByteString(elements[i].Identifier) == identifier) - return luaL_error(l, "Element identifier already in use"); - } - - // 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 (!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) - { - { - 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); - lua_pushinteger(l, newID); - lua_settable(l, -3); - lua_pop(l, 1); - - for (auto elem = 0; elem < PT_NUM; ++elem) - { - luacon_ci->custom_can_move[elem][newID] = 0; - luacon_ci->custom_can_move[newID][elem] = 0; - } - luacon_model->BuildMenus(); - luacon_ci->custom_init_can_move(); - } - - lua_pushinteger(l, newID); - return 1; -} - -static int luaUpdateWrapper(UPDATE_FUNC_ARGS) -{ - if (!sim->useLuaCallbacks) - { - return 0; - } - auto *luacon_ci = static_cast(commandInterface); - 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)) - return 1; - x = (int)(parts[i].x+0.5f); - y = (int)(parts[i].y+0.5f); - } - if (lua_el_func[parts[i].type]) - { - int retval = 0, callret; - lua_rawgeti(luacon_ci->l, LUA_REGISTRYINDEX, lua_el_func[parts[i].type]); - lua_pushinteger(luacon_ci->l, i); - lua_pushinteger(luacon_ci->l, x); - lua_pushinteger(luacon_ci->l, y); - lua_pushinteger(luacon_ci->l, surround_space); - lua_pushinteger(luacon_ci->l, nt); - callret = tpt_lua_pcall(luacon_ci->l, 5, 1, 0, eventTraitSimRng); - if (callret) - luacon_ci->Log(CommandInterface::LogError, luacon_geterror()); - if(lua_isboolean(luacon_ci->l, -1)){ - retval = lua_toboolean(luacon_ci->l, -1); - } - lua_pop(luacon_ci->l, 1); - if (retval) - { - return 1; - } - x = (int)(parts[i].x+0.5f); - y = (int)(parts[i].y+0.5f); - } - if (builtinUpdate && lua_el_mode[parts[i].type] == 3) - { - if (builtinUpdate(UPDATE_FUNC_SUBCALL_ARGS)) - return 1; - x = (int)(parts[i].x+0.5f); - y = (int)(parts[i].y+0.5f); - } - return 0; -} - -static int luaGraphicsWrapper(GRAPHICS_FUNC_ARGS) -{ - if (!gfctx.sim->useLuaCallbacks) - { - return Element::defaultGraphics(GRAPHICS_FUNC_SUBCALL_ARGS); - } - auto *luacon_ci = static_cast(commandInterface); - if (lua_gr_func[cpart->type]) - { - auto *pipeSubcallWcpart = gfctx.pipeSubcallCpart ? luacon_sim->parts + (gfctx.pipeSubcallCpart - gfctx.sim->parts) : nullptr; - if (pipeSubcallWcpart) - { - std::swap(*pipeSubcallWcpart, *gfctx.pipeSubcallTpart); - cpart = pipeSubcallWcpart; - } - int cache = 0, callret; - int i = cpart - gfctx.sim->parts; // pointer arithmetic be like - lua_rawgeti(luacon_ci->l, LUA_REGISTRYINDEX, lua_gr_func[cpart->type]); - lua_pushinteger(luacon_ci->l, i); - lua_pushinteger(luacon_ci->l, *colr); - lua_pushinteger(luacon_ci->l, *colg); - lua_pushinteger(luacon_ci->l, *colb); - callret = tpt_lua_pcall(luacon_ci->l, 4, 10, 0, eventTraitSimGraphics); - if (callret) - { - luacon_ci->Log(CommandInterface::LogError, luacon_geterror()); - lua_pop(luacon_ci->l, 1); - } - else - { - bool valid = true; - for (int i = -10; i < 0; i++) - if (!lua_isnumber(luacon_ci->l, i) && !lua_isnil(luacon_ci->l, i)) - { - valid = false; - break; - } - if (valid) - { - cache = luaL_optint(luacon_ci->l, -10, 0); - *pixel_mode = luaL_optint(luacon_ci->l, -9, *pixel_mode); - *cola = luaL_optint(luacon_ci->l, -8, *cola); - *colr = luaL_optint(luacon_ci->l, -7, *colr); - *colg = luaL_optint(luacon_ci->l, -6, *colg); - *colb = luaL_optint(luacon_ci->l, -5, *colb); - *firea = luaL_optint(luacon_ci->l, -4, *firea); - *firer = luaL_optint(luacon_ci->l, -3, *firer); - *fireg = luaL_optint(luacon_ci->l, -2, *fireg); - *fireb = luaL_optint(luacon_ci->l, -1, *fireb); - } - lua_pop(luacon_ci->l, 10); - } - if (pipeSubcallWcpart) - { - std::swap(*pipeSubcallWcpart, *gfctx.pipeSubcallTpart); - } - return cache; - } - return 0; -} - -static void luaCreateWrapper(ELEMENT_CREATE_FUNC_ARGS) -{ - if (!sim->useLuaCallbacks) - { - return; - } - auto *luacon_ci = static_cast(commandInterface); - if (luaCreateHandlers[sim->parts[i].type]) - { - lua_rawgeti(luacon_ci->l, LUA_REGISTRYINDEX, luaCreateHandlers[sim->parts[i].type]); - lua_pushinteger(luacon_ci->l, i); - lua_pushinteger(luacon_ci->l, x); - lua_pushinteger(luacon_ci->l, y); - lua_pushinteger(luacon_ci->l, t); - lua_pushinteger(luacon_ci->l, v); - if (tpt_lua_pcall(luacon_ci->l, 5, 0, 0, eventTraitSimRng)) - { - luacon_ci->Log(CommandInterface::LogError, "In create func: " + luacon_geterror()); - lua_pop(luacon_ci->l, 1); - } - } -} - -static bool luaCreateAllowedWrapper(ELEMENT_CREATE_ALLOWED_FUNC_ARGS) -{ - if (!sim->useLuaCallbacks) - { - // Nothing really bad can happen, no callbacks are allowed anyway. The worst thing that can happen - // is that a well-crafted save looks odd in previews because it has multiple Element::defaultGraphics-rendered - // instances of something that should be limited to one instance. - return 1; - } - auto *luacon_ci = static_cast(commandInterface); - bool ret = false; - if (luaCreateAllowedHandlers[t]) - { - lua_rawgeti(luacon_ci->l, LUA_REGISTRYINDEX, luaCreateAllowedHandlers[t]); - lua_pushinteger(luacon_ci->l, i); - lua_pushinteger(luacon_ci->l, x); - lua_pushinteger(luacon_ci->l, y); - lua_pushinteger(luacon_ci->l, t); - if (tpt_lua_pcall(luacon_ci->l, 4, 1, 0, eventTraitSimRng)) - { - luacon_ci->Log(CommandInterface::LogError, "In create allowed: " + luacon_geterror()); - lua_pop(luacon_ci->l, 1); - } - else - { - if (lua_isboolean(luacon_ci->l, -1)) - ret = lua_toboolean(luacon_ci->l, -1); - lua_pop(luacon_ci->l, 1); - } - } - return ret; -} - -static void luaChangeTypeWrapper(ELEMENT_CHANGETYPE_FUNC_ARGS) -{ - if (!sim->useLuaCallbacks) - { - return; - } - auto *luacon_ci = static_cast(commandInterface); - if (luaChangeTypeHandlers[sim->parts[i].type]) - { - lua_rawgeti(luacon_ci->l, LUA_REGISTRYINDEX, luaChangeTypeHandlers[sim->parts[i].type]); - lua_pushinteger(luacon_ci->l, i); - lua_pushinteger(luacon_ci->l, x); - lua_pushinteger(luacon_ci->l, y); - lua_pushinteger(luacon_ci->l, from); - lua_pushinteger(luacon_ci->l, to); - if (tpt_lua_pcall(luacon_ci->l, 5, 0, 0, eventTraitSimRng)) - { - luacon_ci->Log(CommandInterface::LogError, "In change type: " + luacon_geterror()); - lua_pop(luacon_ci->l, 1); - } - } -} - -static bool luaCtypeDrawWrapper(CTYPEDRAW_FUNC_ARGS) -{ - if (!sim->useLuaCallbacks) - { - return false; - } - auto *luacon_ci = static_cast(commandInterface); - bool ret = false; - if (luaCtypeDrawHandlers[sim->parts[i].type]) - { - lua_rawgeti(luacon_ci->l, LUA_REGISTRYINDEX, luaCtypeDrawHandlers[sim->parts[i].type]); - lua_pushinteger(luacon_ci->l, i); - lua_pushinteger(luacon_ci->l, t); - lua_pushinteger(luacon_ci->l, v); - if (tpt_lua_pcall(luacon_ci->l, 3, 1, 0, eventTraitSimRng)) - { - luacon_ci->Log(CommandInterface::LogError, luacon_geterror()); - lua_pop(luacon_ci->l, 1); - } - else - { - if (lua_isboolean(luacon_ci->l, -1)) - ret = lua_toboolean(luacon_ci->l, -1); - lua_pop(luacon_ci->l, 1); - } - } - return ret; -} - -int LuaScriptInterface::elements_element(lua_State * l) -{ - auto &builtinElements = GetElements(); - auto *luacon_ci = static_cast(commandInterface); - int id = luaL_checkinteger(l, 1); - if (!SimulationData::CRef().IsElementOrNone(id)) - { - return luaL_error(l, "Invalid element"); - } - - if (lua_gettop(l) > 1) - { - { - 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()) - { - 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, "DefaultProperties"); - SetDefaultProperties(l, id, lua_gettop(l)); - lua_pop(l, 1); - - sd.graphicscache[id].isready = 0; - } - luacon_model->BuildMenus(); - luacon_ci->custom_init_can_move(); - - return 0; - } - else - { - auto &sd = SimulationData::CRef(); - auto &elements = sd.elements; - //Write values from native data to a table - lua_newtable(l); - for (auto &prop : Element::GetProperties()) - { - tpt_lua_pushByteString(l, prop.Name); - intptr_t propertyAddress = (intptr_t)(((unsigned char*)&elements[id]) + prop.Offset); - LuaGetProperty(l, prop, propertyAddress); - lua_settable(l, -3); - } - - tpt_lua_pushByteString(l, elements[id].Identifier); - lua_setfield(l, -2, "Identifier"); - - GetDefaultProperties(l, id); - lua_setfield(l, -2, "DefaultProperties"); - - return 1; - } -} - -void LuaScriptInterface::GetDefaultProperties(lua_State * l, int id) -{ - auto &sd = SimulationData::CRef(); - auto &elements = sd.elements; - lua_newtable(l); - for (auto &prop : Particle::GetProperties()) - { - auto propertyAddress = reinterpret_cast((reinterpret_cast(&elements[id].DefaultProperties)) + prop.Offset); - tpt_lua_pushByteString(l, prop.Name); - LuaGetProperty(l, prop, propertyAddress); - lua_settable(l, -3); - } - for (auto &alias : Particle::GetPropertyAliases()) - { - tpt_lua_pushByteString(l, alias.from); - tpt_lua_pushByteString(l, alias.to); - lua_gettable(l, -3); - lua_settable(l, -3); - } -} - -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()) - { - tpt_lua_pushByteString(l, prop.Name); - lua_gettable(l, stackPos); - if (lua_type(l, -1) == LUA_TNIL) - { - for (auto &alias : Particle::GetPropertyAliases()) - { - if (alias.to == prop.Name) - { - lua_pop(l, 1); - tpt_lua_pushByteString(l, alias.from); - lua_gettable(l, stackPos); - } - } - } - if (lua_type(l, -1) != LUA_TNIL) - { - auto propertyAddress = reinterpret_cast((reinterpret_cast(&elements[id].DefaultProperties)) + prop.Offset); - LuaSetProperty(l, prop, propertyAddress, -1); - } - lua_pop(l, 1); - } - } -} - -int LuaScriptInterface::elements_property(lua_State * l) -{ - auto &builtinElements = GetElements(); - auto *luacon_ci = static_cast(commandInterface); - int id = luaL_checkinteger(l, 1); - if (!SimulationData::CRef().IsElementOrNone(id)) - { - return luaL_error(l, "Invalid element"); - } - ByteString propertyName = tpt_lua_checkByteString(l, 2); - - auto &properties = Element::GetProperties(); - auto prop = std::find_if(properties.begin(), properties.end(), [&propertyName](StructProperty const &p) { - return p.Name == propertyName; - }); - - if (lua_gettop(l) > 2) - { - auto &sd = SimulationData::Ref(); - std::unique_lock lk(sd.elementGraphicsMx); - auto &elements = sd.elements; - if (prop != properties.end()) - { - if (lua_type(l, 3) != LUA_TNIL) - { - if (prop->Type == StructProperty::TransitionType) - { - int type = luaL_checkinteger(l, 3); - if (!SimulationData::CRef().IsElementOrNone(type) && type != NT && type != ST) - { - return luaL_error(l, "Invalid element"); - } - } - intptr_t propertyAddress = (intptr_t)(((unsigned char*)&elements[id]) + prop->Offset); - manageElementIdentifier(l, id, false); - LuaSetProperty(l, *prop, propertyAddress, 3); - manageElementIdentifier(l, id, true); - luacon_model->BuildMenus(); - luacon_ci->custom_init_can_move(); - sd.graphicscache[id].isready = 0; - } - } - else if (propertyName == "Update") - { - if (lua_type(l, 3) == LUA_TFUNCTION) - { - switch (luaL_optint(l, 4, 0)) - { - case 2: - lua_el_mode[id] = 3; //update before - break; - - case 1: - lua_el_mode[id] = 2; //replace - break; - - default: - lua_el_mode[id] = 1; //update after - break; - } - lua_el_func[id].Assign(l, 3); - 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; - elements[id].Update = builtinElements[id].Update; - } - } - else if (propertyName == "Graphics") - { - if (lua_type(l, 3) == LUA_TFUNCTION) - { - lua_gr_func[id].Assign(l, 3); - elements[id].Graphics = luaGraphicsWrapper; - } - else if (lua_type(l, 3) == LUA_TBOOLEAN && !lua_toboolean(l, 3)) - { - lua_gr_func[id].Clear(); - elements[id].Graphics = builtinElements[id].Graphics; - } - sd.graphicscache[id].isready = 0; - } - else if (propertyName == "Create") - { - if (lua_type(l, 3) == LUA_TFUNCTION) - { - luaCreateHandlers[id].Assign(l, 3); - elements[id].Create = luaCreateWrapper; - } - else if (lua_type(l, 3) == LUA_TBOOLEAN && !lua_toboolean(l, 3)) - { - luaCreateHandlers[id].Clear(); - elements[id].Create = builtinElements[id].Create; - } - } - else if (propertyName == "CreateAllowed") - { - if (lua_type(l, 3) == LUA_TFUNCTION) - { - luaCreateAllowedHandlers[id].Assign(l, 3); - elements[id].CreateAllowed = luaCreateAllowedWrapper; - } - else if (lua_type(l, 3) == LUA_TBOOLEAN && !lua_toboolean(l, 3)) - { - luaCreateAllowedHandlers[id].Clear(); - elements[id].CreateAllowed = builtinElements[id].CreateAllowed; - } - } - else if (propertyName == "ChangeType") - { - if (lua_type(l, 3) == LUA_TFUNCTION) - { - luaChangeTypeHandlers[id].Assign(l, 3); - elements[id].ChangeType = luaChangeTypeWrapper; - } - else if (lua_type(l, 3) == LUA_TBOOLEAN && !lua_toboolean(l, 3)) - { - luaChangeTypeHandlers[id].Clear(); - elements[id].ChangeType = builtinElements[id].ChangeType; - } - } - else if (propertyName == "CtypeDraw") - { - if (lua_type(l, 3) == LUA_TFUNCTION) - { - luaCtypeDrawHandlers[id].Assign(l, 3); - elements[id].CtypeDraw = luaCtypeDrawWrapper; - } - else if (lua_type(l, 3) == LUA_TBOOLEAN && !lua_toboolean(l, 3)) - { - luaCtypeDrawHandlers[id].Clear(); - elements[id].CtypeDraw = builtinElements[id].CtypeDraw; - } - } - else if (propertyName == "DefaultProperties") - { - SetDefaultProperties(l, id, 3); - } - else - { - return luaL_error(l, "Invalid element property"); - } - return 0; - } - else - { - auto &sd = SimulationData::CRef(); - auto &elements = sd.elements; - if (prop != properties.end()) - { - 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, elements[id].Identifier); - return 1; - } - else if (propertyName == "DefaultProperties") - { - GetDefaultProperties(l, id); - return 1; - } - else - { - return luaL_error(l, "Invalid element property"); - } - } -} - -int LuaScriptInterface::elements_free(lua_State * l) -{ - int id = luaL_checkinteger(l, 1); - ByteString identifier; - { - 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"); - } - } - - { - auto &sd = SimulationData::Ref(); - std::unique_lock lk(sd.elementGraphicsMx); - sd.elements[id].Enabled = false; - } - luacon_model->BuildMenus(); - - lua_getglobal(l, "elements"); - tpt_lua_pushByteString(l, identifier); - lua_pushnil(l); - lua_settable(l, -3); - lua_pop(l, 1); - - return 0; -} - -int LuaScriptInterface::elements_exists(lua_State * l) -{ - auto &sd = SimulationData::CRef(); - lua_pushboolean(l, sd.IsElement(luaL_checkinteger(l, 1))); - return 1; -} - -static int graphics_drawPixel(lua_State *L); - -void LuaScriptInterface::initGraphicsAPI() -{ - //Methods - struct luaL_Reg graphicsAPIMethods [] = { - {"textSize", graphics_textSize}, - {"drawText", graphics_drawText}, - {"drawPixel", graphics_drawPixel}, - {"drawLine", graphics_drawLine}, - {"drawRect", graphics_drawRect}, - {"fillRect", graphics_fillRect}, - {"drawCircle", graphics_drawCircle}, - {"fillCircle", graphics_fillCircle}, - {"getColors", graphics_getColors}, - {"getHexColor", graphics_getHexColor}, - {"setClipRect", graphics_setClipRect}, - {NULL, NULL} - }; - luaL_register(l, "graphics", graphicsAPIMethods); - - lua_pushinteger(l, WINDOWW); lua_setfield(l, -2, "WIDTH"); - lua_pushinteger(l, WINDOWH); lua_setfield(l, -2, "HEIGHT"); - - lua_pop(l, 1); - - //elem shortcut - lua_getglobal(l, "graphics"); - lua_setglobal(l, "gfx"); -} - -int LuaScriptInterface::graphics_textSize(lua_State * l) -{ - auto text = tpt_lua_optString(l, 1, ""); - auto size = Graphics::TextSize(text); - - lua_pushinteger(l, size.X); - lua_pushinteger(l, size.Y); - return 2; -} - -static std::variant currentGraphics() -{ - if (eventTraits & eventTraitSimGraphics) - { - return luacon_ren; - } - return luacon_g; -} - -static int graphics_drawPixel(lua_State *L) -{ - auto x = luaL_optint(L, 1, 0); - auto y = luaL_optint(L, 2, 0); - auto r = luaL_optint(L, 3, 255); - auto g = luaL_optint(L, 4, 255); - auto b = luaL_optint(L, 5, 255); - auto a = luaL_optint(L, 6, 255); - if (r < 0 ) r = 0 ; - else if (r > 255) r = 255; - if (g < 0 ) g = 0 ; - else if (g > 255) g = 255; - if (b < 0 ) b = 0 ; - else if (b > 255) b = 255; - if (a < 0 ) a = 0 ; - else if (a > 255) a = 255; - luacon_g->BlendPixel({ x, y }, RGBA(r, g, b, a)); - return 0; -} - -int LuaScriptInterface::graphics_drawText(lua_State * l) -{ - int x = lua_tointeger(l, 1); - int y = lua_tointeger(l, 2); - auto text = tpt_lua_optString(l, 3, ""); - int r = luaL_optint(l, 4, 255); - int g = luaL_optint(l, 5, 255); - int b = luaL_optint(l, 6, 255); - int a = luaL_optint(l, 7, 255); - - if (r<0) r = 0; - else if (r>255) r = 255; - if (g<0) g = 0; - else if (g>255) g = 255; - if (b<0) b = 0; - else if (b>255) b = 255; - if (a<0) a = 0; - else if (a>255) a = 255; - - std::visit([x, y, r, g, b, a, &text](auto p) { - p->BlendText({ x, y }, text, RGBA(r, g, b, a)); - }, currentGraphics()); - return 0; -} - -int LuaScriptInterface::graphics_drawLine(lua_State * l) -{ - int x1 = lua_tointeger(l, 1); - int y1 = lua_tointeger(l, 2); - int x2 = lua_tointeger(l, 3); - int y2 = lua_tointeger(l, 4); - int r = luaL_optint(l, 5, 255); - int g = luaL_optint(l, 6, 255); - int b = luaL_optint(l, 7, 255); - int a = luaL_optint(l, 8, 255); - - if (r<0) r = 0; - else if (r>255) r = 255; - if (g<0) g = 0; - else if (g>255) g = 255; - if (b<0) b = 0; - else if (b>255) b = 255; - if (a<0) a = 0; - else if (a>255) a = 255; - - std::visit([x1, y1, x2, y2, r, g, b, a](auto p) { - if (a == 255) - { - p->DrawLine({ x1, y1 }, { x2, y2 }, RGB(r, g, b)); - } - else - { - p->BlendLine({ x1, y1 }, { x2, y2 }, RGBA(r, g, b, a)); - } - }, currentGraphics()); - return 0; -} - -int LuaScriptInterface::graphics_drawRect(lua_State * l) -{ - int x = lua_tointeger(l, 1); - int y = lua_tointeger(l, 2); - int width = lua_tointeger(l, 3); - int height = lua_tointeger(l, 4); - int r = luaL_optint(l, 5, 255); - int g = luaL_optint(l, 6, 255); - int b = luaL_optint(l, 7, 255); - int a = luaL_optint(l, 8, 255); - - if (r<0) r = 0; - else if (r>255) r = 255; - if (g<0) g = 0; - else if (g>255) g = 255; - if (b<0) b = 0; - else if (b>255) b = 255; - if (a<0) a = 0; - else if (a>255) a = 255; - - std::visit([x, y, width, height, r, g, b, a](auto p) { - if (a == 255) - { - p->DrawRect(RectSized(Vec2{ x, y }, Vec2{ width, height }), RGB(r, g, b)); - } - else - { - p->BlendRect(RectSized(Vec2{ x, y }, Vec2{ width, height }), RGBA(r, g, b, a)); - } - }, currentGraphics()); - return 0; -} - -int LuaScriptInterface::graphics_fillRect(lua_State * l) -{ - int x = lua_tointeger(l, 1); - int y = lua_tointeger(l, 2); - int width = lua_tointeger(l, 3); - int height = lua_tointeger(l, 4); - int r = luaL_optint(l, 5, 255); - int g = luaL_optint(l, 6, 255); - int b = luaL_optint(l, 7, 255); - int a = luaL_optint(l, 8, 255); - - if (r<0) r = 0; - else if (r>255) r = 255; - if (g<0) g = 0; - else if (g>255) g = 255; - if (b<0) b = 0; - else if (b>255) b = 255; - if (a<0) a = 0; - else if (a>255) a = 255; - - std::visit([x, y, width, height, r, g, b, a](auto p) { - if (a == 255) - { - p->DrawFilledRect(RectSized(Vec2{ x, y }, Vec2{ width, height }), RGB(r, g, b)); - } - else - { - p->BlendFilledRect(RectSized(Vec2{ x, y }, Vec2{ width, height }), RGBA(r, g, b, a)); - } - }, currentGraphics()); - return 0; -} - -int LuaScriptInterface::graphics_drawCircle(lua_State * l) -{ - int x = lua_tointeger(l, 1); - int y = lua_tointeger(l, 2); - int rx = lua_tointeger(l, 3); - int ry = lua_tointeger(l, 4); - int r = luaL_optint(l, 5, 255); - int g = luaL_optint(l, 6, 255); - int b = luaL_optint(l, 7, 255); - int a = luaL_optint(l, 8, 255); - - if (r<0) r = 0; - else if (r>255) r = 255; - if (g<0) g = 0; - else if (g>255) g = 255; - if (b<0) b = 0; - else if (b>255) b = 255; - if (a<0) a = 0; - else if (a>255) a = 255; - - std::visit([x, y, rx, ry, r, g, b, a](auto p) { - p->BlendEllipse({ x, y }, { abs(rx), abs(ry) }, RGBA(r, g, b, a)); - }, currentGraphics()); - return 0; -} - -int LuaScriptInterface::graphics_fillCircle(lua_State * l) -{ - int x = lua_tointeger(l, 1); - int y = lua_tointeger(l, 2); - int rx = lua_tointeger(l, 3); - int ry = lua_tointeger(l, 4); - int r = luaL_optint(l, 5, 255); - int g = luaL_optint(l, 6, 255); - int b = luaL_optint(l, 7, 255); - int a = luaL_optint(l, 8, 255); - - if (r<0) r = 0; - else if (r>255) r = 255; - if (g<0) g = 0; - else if (g>255) g = 255; - if (b<0) b = 0; - else if (b>255) b = 255; - if (a<0) a = 0; - else if (a>255) a = 255; - - std::visit([x, y, rx, ry, r, g, b, a](auto p) { - p->BlendFilledEllipse({ x, y }, { abs(rx), abs(ry) }, RGBA(r, g, b, a)); - }, currentGraphics()); - return 0; -} - -int LuaScriptInterface::graphics_getColors(lua_State * l) -{ - unsigned int color = int32_truncate(lua_tonumber(l, 1)); - - int a = color >> 24; - int r = (color >> 16)&0xFF; - int g = (color >> 8)&0xFF; - int b = color&0xFF; - - lua_pushinteger(l, r); - lua_pushinteger(l, g); - lua_pushinteger(l, b); - lua_pushinteger(l, a); - return 4; -} - -int LuaScriptInterface::graphics_getHexColor(lua_State * l) -{ - int r = lua_tointeger(l, 1); - int g = lua_tointeger(l, 2); - int b = lua_tointeger(l, 3); - int a = 0; - if (lua_gettop(l) >= 4) - a = lua_tointeger(l, 4); - unsigned int color = (a<<24) + (r<<16) + (g<<8) + b; - - lua_pushinteger(l, color); - return 1; -} - -int LuaScriptInterface::graphics_setClipRect(lua_State * l) -{ - if (eventTraits & eventTraitSimGraphics) - { - return luaL_error(l, "simulation graphics do not support clip rects"); - } - int x = luaL_optinteger(l, 1, 0); - int y = luaL_optinteger(l, 2, 0); - int w = luaL_optinteger(l, 3, WINDOWW); - int h = luaL_optinteger(l, 4, WINDOWH); - auto rect = RectSized(Vec2(x, y), Vec2(w, h)); - luacon_g->SwapClipRect(rect); - lua_pushinteger(l, rect.TopLeft.X); - lua_pushinteger(l, rect.TopLeft.Y); - lua_pushinteger(l, rect.Size().X); - lua_pushinteger(l, rect.Size().Y); - return 4; -} - -static int fsIsLink(lua_State * l) -{ - auto dirname = tpt_lua_checkByteString(l, 1); - bool ret = Platform::IsLink(dirname); - lua_pushboolean(l, ret); - return 1; -} - -void LuaScriptInterface::initFileSystemAPI() -{ - //Methods - struct luaL_Reg fileSystemAPIMethods [] = { - {"list", fileSystem_list}, - {"exists", fileSystem_exists}, - {"isFile", fileSystem_isFile}, - {"isDirectory", fileSystem_isDirectory}, - {"isLink", fsIsLink}, - {"makeDirectory", fileSystem_makeDirectory}, - {"removeDirectory", fileSystem_removeDirectory}, - {"removeFile", fileSystem_removeFile}, - {"move", fileSystem_move}, - {"copy", fileSystem_copy}, - {NULL, NULL} - }; - luaL_register(l, "fileSystem", fileSystemAPIMethods); - lua_pop(l, 1); - - //elem shortcut - lua_getglobal(l, "fileSystem"); - lua_setglobal(l, "fs"); -} - -int LuaScriptInterface::fileSystem_list(lua_State * l) -{ - auto directoryName = tpt_lua_checkByteString(l, 1); - lua_newtable(l); - int index = 0; - for (auto &name : Platform::DirectorySearch(directoryName, "", {})) - { - if (name != "." && name != "..") - { - index += 1; - tpt_lua_pushByteString(l, name); - lua_rawseti(l, -2, index); - } - } - return 1; -} - -int LuaScriptInterface::fileSystem_exists(lua_State * l) -{ - auto filename = tpt_lua_checkByteString(l, 1); - - bool ret = Platform::Stat(filename); - lua_pushboolean(l, ret); - return 1; -} - -int LuaScriptInterface::fileSystem_isFile(lua_State * l) -{ - auto filename = tpt_lua_checkByteString(l, 1); - - bool ret = Platform::FileExists(filename); - lua_pushboolean(l, ret); - return 1; -} - -int LuaScriptInterface::fileSystem_isDirectory(lua_State * l) -{ - auto dirname = tpt_lua_checkByteString(l, 1); - - bool ret = Platform::DirectoryExists(dirname); - lua_pushboolean(l, ret); - return 1; -} - -int LuaScriptInterface::fileSystem_makeDirectory(lua_State * l) -{ - auto dirname = tpt_lua_checkByteString(l, 1); - - int ret = 0; - ret = Platform::MakeDirectory(dirname); - lua_pushboolean(l, ret); - return 1; -} - -int LuaScriptInterface::fileSystem_removeDirectory(lua_State * l) -{ - auto directory = tpt_lua_checkByteString(l, 1); - - bool ret = Platform::DeleteDirectory(directory); - lua_pushboolean(l, ret); - return 1; -} - -int LuaScriptInterface::fileSystem_removeFile(lua_State * l) -{ - auto filename = tpt_lua_checkByteString(l, 1); - lua_pushboolean(l, Platform::RemoveFile(filename)); - return 1; -} - -int LuaScriptInterface::fileSystem_move(lua_State * l) -{ - auto filename = tpt_lua_checkByteString(l, 1); - auto newFilename = tpt_lua_checkByteString(l, 2); - bool replace = lua_toboolean(l, 3); - lua_pushboolean(l, Platform::RenameFile(filename, newFilename, replace)); - return 1; -} - -int LuaScriptInterface::fileSystem_copy(lua_State * l) -{ - auto filename = tpt_lua_checkByteString(l, 1); - auto newFilename = tpt_lua_checkByteString(l, 2); - std::vector fileData; - lua_pushboolean(l, Platform::ReadFile(fileData, filename) && Platform::WriteFile(fileData, newFilename)); - return 1; -} - -void LuaScriptInterface::initPlatformAPI() -{ - //Methods - struct luaL_Reg platformAPIMethods [] = { - {"platform", platform_platform}, - {"ident", platform_ident}, - {"releaseType", platform_releaseType}, - {"exeName", platform_exeName}, - {"restart", platform_restart}, - {"openLink", platform_openLink}, - {"clipboardCopy", platform_clipboardCopy}, - {"clipboardPaste", platform_clipboardPaste}, - {NULL, NULL} - }; - luaL_register(l, "platform", platformAPIMethods); - lua_pop(l, 1); - - //elem shortcut - lua_getglobal(l, "platform"); - lua_setglobal(l, "plat"); -} - -int LuaScriptInterface::platform_platform(lua_State * l) -{ - tpt_lua_pushByteString(l, IDENT_PLATFORM); - return 1; -} - -int LuaScriptInterface::platform_ident(lua_State * l) -{ - tpt_lua_pushByteString(l, IDENT); - return 1; -} - -int LuaScriptInterface::platform_releaseType(lua_State * l) -{ - tpt_lua_pushByteString(l, ByteString(1, IDENT_RELTYPE)); - return 1; -} - -int LuaScriptInterface::platform_exeName(lua_State * l) -{ - ByteString name = Platform::ExecutableName(); - if (name.length()) - tpt_lua_pushByteString(l, name); - else - luaL_error(l, "Error, could not get executable name"); - return 1; -} - -int LuaScriptInterface::platform_restart(lua_State * l) -{ - Platform::DoRestart(); - return 0; -} - -int LuaScriptInterface::platform_openLink(lua_State * l) -{ - auto uri = tpt_lua_checkByteString(l, 1); - Platform::OpenURI(uri); - return 0; -} - -int LuaScriptInterface::platform_clipboardCopy(lua_State * l) -{ - tpt_lua_pushByteString(l, ClipboardPull()); - return 1; -} - -int LuaScriptInterface::platform_clipboardPaste(lua_State * l) -{ - luaL_checktype(l, 1, LUA_TSTRING); - ClipboardPush(tpt_lua_optByteString(l, 1, "")); - return 0; -} - - -//// Begin Event API - -void LuaScriptInterface::initEventAPI() -{ - struct luaL_Reg eventAPIMethods [] = { - {"register", event_register}, - {"unregister", event_unregister}, - {"getModifiers", event_getmodifiers}, - {NULL, NULL} - }; - luaL_register(l, "event", eventAPIMethods); - - lua_pushinteger(l, VariantIndex()); lua_setfield(l, -2, "TEXTINPUT" ); - lua_pushinteger(l, VariantIndex()); lua_setfield(l, -2, "TEXTEDITING" ); - lua_pushinteger(l, VariantIndex()); lua_setfield(l, -2, "KEYPRESS" ); - lua_pushinteger(l, VariantIndex()); lua_setfield(l, -2, "KEYRELEASE" ); - lua_pushinteger(l, VariantIndex()); lua_setfield(l, -2, "MOUSEDOWN" ); - lua_pushinteger(l, VariantIndex()); lua_setfield(l, -2, "MOUSEUP" ); - lua_pushinteger(l, VariantIndex()); lua_setfield(l, -2, "MOUSEMOVE" ); - lua_pushinteger(l, VariantIndex()); lua_setfield(l, -2, "MOUSEWHEEL" ); - lua_pushinteger(l, VariantIndex()); lua_setfield(l, -2, "TICK" ); - lua_pushinteger(l, VariantIndex()); lua_setfield(l, -2, "BLUR" ); - lua_pushinteger(l, VariantIndex()); lua_setfield(l, -2, "CLOSE" ); - lua_pushinteger(l, VariantIndex()); lua_setfield(l, -2, "BEFORESIM" ); - lua_pushinteger(l, VariantIndex()); lua_setfield(l, -2, "AFTERSIM" ); - lua_pushinteger(l, VariantIndex()); lua_setfield(l, -2, "BEFORESIMDRAW"); - lua_pushinteger(l, VariantIndex()); lua_setfield(l, -2, "AFTERSIMDRAW" ); - - lua_pop(l, 1); - - lua_getglobal(l, "event"); - lua_setglobal(l, "evt"); -} - -int LuaScriptInterface::event_register(lua_State * l) -{ - auto *luacon_ci = static_cast(commandInterface); - int eventType = luaL_checkinteger(l, 1); - luaL_checktype(l, 2, LUA_TFUNCTION); - if (eventType < 0 || eventType >= int(luacon_ci->gameControllerEventHandlers.size())) - { - luaL_error(l, "Invalid event type: %i", lua_tointeger(l, 1)); - } - luacon_ci->gameControllerEventHandlers[eventType].Push(l); - auto length = lua_objlen(l, -1); - lua_pushvalue(l, 2); - lua_rawseti(l, -2, length + 1); - lua_pushvalue(l, 2); - return 1; -} - -int LuaScriptInterface::event_unregister(lua_State * l) -{ - auto *luacon_ci = static_cast(commandInterface); - int eventType = luaL_checkinteger(l, 1); - luaL_checktype(l, 2, LUA_TFUNCTION); - if (eventType < 0 || eventType >= int(luacon_ci->gameControllerEventHandlers.size())) - { - luaL_error(l, "Invalid event type: %i", lua_tointeger(l, 1)); - } - luacon_ci->gameControllerEventHandlers[eventType].Push(l); - auto length = lua_objlen(l, -1); - int skip = 0; - for (auto i = 1U; i <= length; ++i) - { - lua_rawgeti(l, -1, i); - if (!skip && lua_equal(l, -1, 2)) - { - skip = 1; - } - lua_pop(l, 1); - lua_rawgeti(l, -1, i + skip); - lua_rawseti(l, -2, i); - } - return 0; -} - -int LuaScriptInterface::event_getmodifiers(lua_State * l) -{ - lua_pushnumber(l, GetModifiers()); - return 1; -} - -void LuaScriptInterface::initHttpAPI() -{ - LuaHttp::Open(l); -} - -static int PushGameControllerEvent(lua_State * l, const GameControllerEvent &event) +static int pushGameControllerEvent(lua_State *L, const GameControllerEvent &event) { if (auto *textInputEvent = std::get_if(&event)) { - tpt_lua_pushString(l, textInputEvent->text); + tpt_lua_pushString(L, textInputEvent->text); return 1; } else if (auto *textEditingEvent = std::get_if(&event)) { - tpt_lua_pushString(l, textEditingEvent->text); + tpt_lua_pushString(L, textEditingEvent->text); return 1; } else if (auto *keyPressEvent = std::get_if(&event)) { - lua_pushinteger(l, keyPressEvent->key); - lua_pushinteger(l, keyPressEvent->scan); - lua_pushboolean(l, keyPressEvent->repeat); - lua_pushboolean(l, keyPressEvent->shift); - lua_pushboolean(l, keyPressEvent->ctrl); - lua_pushboolean(l, keyPressEvent->alt); + lua_pushinteger(L, keyPressEvent->key); + lua_pushinteger(L, keyPressEvent->scan); + lua_pushboolean(L, keyPressEvent->repeat); + lua_pushboolean(L, keyPressEvent->shift); + lua_pushboolean(L, keyPressEvent->ctrl); + lua_pushboolean(L, keyPressEvent->alt); return 6; } else if (auto *keyReleaseEvent = std::get_if(&event)) { - lua_pushinteger(l, keyReleaseEvent->key); - lua_pushinteger(l, keyReleaseEvent->scan); - lua_pushboolean(l, keyReleaseEvent->repeat); - lua_pushboolean(l, keyReleaseEvent->shift); - lua_pushboolean(l, keyReleaseEvent->ctrl); - lua_pushboolean(l, keyReleaseEvent->alt); + lua_pushinteger(L, keyReleaseEvent->key); + lua_pushinteger(L, keyReleaseEvent->scan); + lua_pushboolean(L, keyReleaseEvent->repeat); + lua_pushboolean(L, keyReleaseEvent->shift); + lua_pushboolean(L, keyReleaseEvent->ctrl); + lua_pushboolean(L, keyReleaseEvent->alt); return 6; } else if (auto *mouseDownEvent = std::get_if(&event)) { - lua_pushinteger(l, mouseDownEvent->x); - lua_pushinteger(l, mouseDownEvent->y); - lua_pushinteger(l, mouseDownEvent->button); + lua_pushinteger(L, mouseDownEvent->x); + lua_pushinteger(L, mouseDownEvent->y); + lua_pushinteger(L, mouseDownEvent->button); return 3; } else if (auto *mouseUpEvent = std::get_if(&event)) { - lua_pushinteger(l, mouseUpEvent->x); - lua_pushinteger(l, mouseUpEvent->y); - lua_pushinteger(l, mouseUpEvent->button); - lua_pushinteger(l, mouseUpEvent->reason); + lua_pushinteger(L, mouseUpEvent->x); + lua_pushinteger(L, mouseUpEvent->y); + lua_pushinteger(L, mouseUpEvent->button); + lua_pushinteger(L, mouseUpEvent->reason); return 4; } else if (auto *mouseMoveEvent = std::get_if(&event)) { - lua_pushinteger(l, mouseMoveEvent->x); - lua_pushinteger(l, mouseMoveEvent->y); - lua_pushinteger(l, mouseMoveEvent->dx); - lua_pushinteger(l, mouseMoveEvent->dy); + lua_pushinteger(L, mouseMoveEvent->x); + lua_pushinteger(L, mouseMoveEvent->y); + lua_pushinteger(L, mouseMoveEvent->dx); + lua_pushinteger(L, mouseMoveEvent->dy); return 4; } else if (auto *mouseWheelEvent = std::get_if(&event)) { - lua_pushinteger(l, mouseWheelEvent->x); - lua_pushinteger(l, mouseWheelEvent->y); - lua_pushinteger(l, mouseWheelEvent->d); + lua_pushinteger(L, mouseWheelEvent->x); + lua_pushinteger(L, mouseWheelEvent->y); + lua_pushinteger(L, mouseWheelEvent->d); return 3; } return 0; @@ -4976,114 +376,46 @@ static int PushGameControllerEvent(lua_State * l, const GameControllerEvent &eve bool LuaScriptInterface::HandleEvent(const GameControllerEvent &event) { bool cont = true; - gameControllerEventHandlers[event.index()].Push(l); - int len = lua_objlen(l, -1); + gameControllerEventHandlers[event.index()].Push(L); + int len = lua_objlen(L, -1); for (int i = 1; i <= len && cont; i++) { - lua_rawgeti(l, -1, i); - int numArgs = PushGameControllerEvent(l, event); - int callret = tpt_lua_pcall(l, numArgs, 1, 0, std::visit([](auto &event) { + lua_rawgeti(L, -1, i); + int numArgs = pushGameControllerEvent(L, event); + int callret = tpt_lua_pcall(L, numArgs, 1, 0, std::visit([](auto &event) { return event.traits; }, event)); if (callret) { - if (luacon_geterror() == "Error: Script not responding") + if (LuaGetError() == "Error: Script not responding") { for (int j = i; j <= len - 1; j++) { - lua_rawgeti(l, -2, j + 1); - lua_rawseti(l, -3, j); + lua_rawgeti(L, -2, j + 1); + lua_rawseti(L, -3, j); } - lua_pushnil(l); - lua_rawseti(l, -3, len); + lua_pushnil(L); + lua_rawseti(L, -3, len); i--; } - Log(CommandInterface::LogError, luacon_geterror()); - lua_pop(l, 1); + Log(CommandInterface::LogError, LuaGetError()); + lua_pop(L, 1); } else { - if (!lua_isnoneornil(l, -1)) - cont = lua_toboolean(l, -1); - lua_pop(l, 1); + if (!lua_isnoneornil(L, -1)) + cont = lua_toboolean(L, -1); + lua_pop(L, 1); } - len = lua_objlen(l, -1); + len = lua_objlen(L, -1); } - lua_pop(l, 1); + lua_pop(L, 1); return cont; } void LuaScriptInterface::OnTick() { - if (scriptManagerDownload && scriptManagerDownload->CheckDone()) - { - struct Status - { - struct Ok - { - }; - struct GetFailed - { - String error; - }; - struct RunFailed - { - String error; - }; - using Value = std::variant< - Ok, - GetFailed, - RunFailed - >; - Value value; - }; - auto complete = [](Status status) { - if (std::get_if(&status.value)) - { - new InformationMessage("Install script manager", "Script manager successfully installed", false); - } - if (auto *requestFailed = std::get_if(&status.value)) - { - new ErrorMessage("Install script manager", "Failed to get script manager: " + requestFailed->error); - } - if (auto *runFailed = std::get_if(&status.value)) - { - new ErrorMessage("Install script manager", "Failed to run script manager: " + runFailed->error); - } - }; - try - { - auto ret = scriptManagerDownload->StatusCode(); - auto scriptData = scriptManagerDownload->Finish().second; - if (!scriptData.size()) - { - complete({ Status::GetFailed{ "Server did not return data" } }); - return; - } - if (ret != 200) - { - complete({ Status::GetFailed{ ByteString(http::StatusText(ret)).FromUtf8() } }); - return; - } - ByteString filename = "autorun.lua"; - if (!Platform::WriteFile(std::vector(scriptData.begin(), scriptData.end()), filename)) - { - complete({ Status::GetFailed{ String::Build("Unable to write to ", filename.FromUtf8()) } }); - return; - } - if (tpt_lua_dostring(l, ByteString::Build("dofile('", filename, "')"))) - { - complete({ Status::RunFailed{ luacon_geterror() } }); - return; - } - complete({ Status::Ok{} }); - } - catch (const http::RequestError &ex) - { - complete({ Status::GetFailed{ ByteString(ex.what()).FromUtf8() } }); - } - scriptManagerDownload.reset(); - } + LuaMisc::Tick(L); HandleEvent(TickEvent{}); } @@ -5099,22 +431,22 @@ int LuaScriptInterface::Command(String command) } else { - int level = lua_gettop(l), ret = -1; + int level = lua_gettop(L), ret = -1; currentCommand = true; if (lastCode.length()) lastCode += "\n"; lastCode += command; ByteString tmp = ("return " + lastCode).ToUtf8(); - luaL_loadbuffer(l, tmp.data(), tmp.size(), "@console"); - if (lua_type(l, -1) != LUA_TFUNCTION) + luaL_loadbuffer(L, tmp.data(), tmp.size(), "@console"); + if (lua_type(L, -1) != LUA_TFUNCTION) { - lua_pop(l, 1); + lua_pop(L, 1); ByteString lastCodeUtf8 = lastCode.ToUtf8(); - luaL_loadbuffer(l, lastCodeUtf8.data(), lastCodeUtf8.size(), "@console"); + luaL_loadbuffer(L, lastCodeUtf8.data(), lastCodeUtf8.size(), "@console"); } - if (lua_type(l, -1) != LUA_TFUNCTION) + if (lua_type(L, -1) != LUA_TFUNCTION) { - lastError = luacon_geterror(); + lastError = LuaGetError(); String err = lastError; if (err.Contains("near ''")) //the idea stolen from lua-5.1.5/lua.c lastError = "..."; @@ -5124,28 +456,28 @@ int LuaScriptInterface::Command(String command) else { lastCode = ""; - ret = tpt_lua_pcall(l, 0, LUA_MULTRET, 0, eventTraitNone); + ret = tpt_lua_pcall(L, 0, LUA_MULTRET, 0, eventTraitNone); if (ret) { - lastError = luacon_geterror(); + lastError = LuaGetError(); } else { String text = ""; bool hasText = false; - for (level++; level <= lua_gettop(l); level++) + for (level++; level <= lua_gettop(L); level++) { - luaL_tostring(l, level); + LuaToLoggableString(L, level); if (hasText) { - text += ", " + tpt_lua_optString(l, -1, ""); + text += ", " + tpt_lua_optString(L, -1, ""); } else { - text = tpt_lua_optString(l, -1, ""); + text = tpt_lua_optString(L, -1, ""); hasText = true; } - lua_pop(l, 1); + lua_pop(L, 1); } if (text.length()) { @@ -5162,26 +494,7 @@ int LuaScriptInterface::Command(String command) } } -int strlcmp(const char* a, const char* b, int len) -{ - while(len) - { - if(!*b) - return 1; - if(*a>*b) - return -1; - if(*a<*b) - return 1; - a++; - b++; - len--; - } - if(!*b) - return 0; - return -1; -} - -String highlight(String command) +static String highlight(String command) { StringBuilder result; int pos = 0; @@ -5369,28 +682,13 @@ String LuaScriptInterface::FormatCommand(String command) LuaScriptInterface::~LuaScriptInterface() { - for (auto &component_and_ref : grabbed_components) + for (auto &[ component, ref ] : grabbedComponents) { - Window->RemoveComponent(component_and_ref.first->GetComponent()); - component_and_ref.second.Clear(); - component_and_ref.first->owner_ref = component_and_ref.second; - component_and_ref.first->SetParentWindow(nullptr); + window->RemoveComponent(component->GetComponent()); + ref.Clear(); + component->owner_ref = ref; + component->SetParentWindow(nullptr); } - luaChangeTypeHandlers.clear(); - luaCreateAllowedHandlers.clear(); - luaCreateHandlers.clear(); - luaCtypeDrawHandlers.clear(); - gameControllerEventHandlers.clear(); - lua_el_mode_v.clear(); - lua_el_func_v.clear(); - lua_gr_func_v.clear(); - lua_cd_func_v.clear(); - lua_close(l); -} - -void LuaScriptInterface::initSocketAPI() -{ - LuaSocket::Open(l); } void tpt_lua_pushByteString(lua_State *L, const ByteString &str) @@ -5468,46 +766,29 @@ bool tpt_lua_equalsString(lua_State *L, int index, const char *data, size_t size int tpt_lua_pcall(lua_State *L, int numArgs, int numResults, int errorFunc, EventTraits newEventTraits) { - auto *luacon_ci = static_cast(commandInterface); - luacon_ci->luaExecutionStart = Platform::GetTime(); + auto *lsi = static_cast(commandInterface); + lsi->luaExecutionStart = Platform::GetTime(); struct AtReturn { EventTraits oldEventTraits; AtReturn(EventTraits newEventTraits) { - oldEventTraits = eventTraits; - eventTraits = newEventTraits; + auto *lsi = static_cast(commandInterface); + oldEventTraits = lsi->eventTraits; + lsi->eventTraits = newEventTraits; } ~AtReturn() { - eventTraits = oldEventTraits; + auto *lsi = static_cast(commandInterface); + lsi->eventTraits = oldEventTraits; } } atReturn(newEventTraits); return lua_pcall(L, numArgs, numResults, errorFunc); } -CommandInterface *CommandInterface::Create(GameController * c, GameModel * m) +CommandInterface *CommandInterface::Create(GameController *newGameController, GameModel *newGameModel) { - return new LuaScriptInterface(c, m); -} - -int LuaScriptInterface::installScriptManager(lua_State* l) -{ - auto *luacon_ci = static_cast(commandInterface); - if (luacon_ci->scriptManagerDownload) - { - new ErrorMessage("Script download", "A script download is already pending"); - return 0; - } - luacon_controller->HideConsole(); - if (ui::Engine::Ref().GetWindow() != luacon_controller->GetView()) - { - new ErrorMessage("Script download", "You must run this function from the console"); - return 0; - } - luacon_ci->scriptManagerDownload = std::make_unique(ByteString::Build(SCHEME, "starcatcher.us/scripts/main.lua?get=1")); - luacon_ci->scriptManagerDownload->Start(); - return 0; + return new LuaScriptInterface(newGameController, newGameModel); } diff --git a/src/lua/LuaScriptInterface.h b/src/lua/LuaScriptInterface.h index 2f46159d7..af49089d3 100644 --- a/src/lua/LuaScriptInterface.h +++ b/src/lua/LuaScriptInterface.h @@ -6,6 +6,7 @@ #include "TPTScriptInterface.h" #include "simulation/StructProperty.h" #include "simulation/ElementDefs.h" +#include #include #include @@ -19,201 +20,88 @@ namespace ui class Window; } -class Tool; - -//Because lua only has bindings for C, we're going to have to go outside "outside" the LuaScriptInterface, this means we can only have one instance :( - +class Graphics; +class Renderer; class Simulation; class LuaComponent; -class LuaScriptInterface: public TPTScriptInterface +int LuaToLoggableString(lua_State *L, int n); +String LuaGetError(); +void LuaGetProperty(lua_State *L, StructProperty property, intptr_t propertyAddress); +void LuaSetProperty(lua_State *L, StructProperty property, intptr_t propertyAddress, int stackPos); +void LuaSetParticleProperty(lua_State *L, int particleID, StructProperty property, intptr_t propertyAddress, int stackPos); + +struct LuaStateDeleter { - std::unique_ptr scriptManagerDownload; + void operator ()(lua_State *L) const + { + lua_close(L); + } +}; +using LuaStatePtr = std::unique_ptr; - int luacon_mousex, luacon_mousey, luacon_mousebutton; - ByteString luacon_selectedl, luacon_selectedr, luacon_selectedalt, luacon_selectedreplace; - bool luacon_mousedown; - bool currentCommand; - int textInputRefcount; +enum UpdateMode +{ + UPDATE_AFTER, + UPDATE_REPLACE, + UPDATE_BEFORE, + NUM_UPDATEMODES, +}; - // signs - static int simulation_signIndex(lua_State *l); - static int simulation_signNewIndex(lua_State *l); - static int simulation_newsign(lua_State *l); +struct CustomElement +{ + UpdateMode updateMode = UPDATE_AFTER; + LuaSmartRef update; + LuaSmartRef graphics; + LuaSmartRef ctypeDraw; + LuaSmartRef create; + LuaSmartRef createAllowed; + LuaSmartRef changeType; +}; - //Simulation - - void initSimulationAPI(); - static int simulation_partNeighbours(lua_State * l); - static int simulation_partChangeType(lua_State * l); - static int simulation_partCreate(lua_State * l); - static int simulation_partProperty(lua_State * l); - static int simulation_partPosition(lua_State * l); - static int simulation_partID(lua_State * l); - static int simulation_partKill(lua_State * l); - static int simulation_partExists(lua_State * l); - static int simulation_createParts(lua_State * l); - static int simulation_createLine(lua_State * l); - static int simulation_createBox(lua_State * l); - static int simulation_floodParts(lua_State * l); - static int simulation_createWalls(lua_State * l); - static int simulation_createWallLine(lua_State * l); - static int simulation_createWallBox(lua_State * l); - static int simulation_floodWalls(lua_State * l); - static int simulation_toolBrush(lua_State * l); - static int simulation_toolLine(lua_State * l); - static int simulation_toolBox(lua_State * l); - static int simulation_floodProp(lua_State * l); - static int simulation_decoBrush(lua_State * l); - 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); - static int simulation_resetPressure(lua_State * l); - static int simulation_saveStamp(lua_State * l); - static int simulation_loadStamp(lua_State * l); - static int simulation_deleteStamp(lua_State * l); - static int simulation_loadSave(lua_State * l); - static int simulation_reloadSave(lua_State * l); - static int simulation_getSaveID(lua_State * l); - static int simulation_adjustCoords(lua_State * l); - static int simulation_prettyPowders(lua_State * l); - static int simulation_gravityGrid(lua_State * l); - static int simulation_edgeMode(lua_State * l); - static int simulation_gravityMode(lua_State * l); - static int simulation_customGravity(lua_State * l); - static int simulation_airMode(lua_State * l); - static int simulation_waterEqualisation(lua_State * l); - static int simulation_ambientAirTemp(lua_State * l); - static int simulation_elementCount(lua_State * l); - static int simulation_canMove(lua_State * l); - static int simulation_parts(lua_State * l); - static int simulation_brush(lua_State * l); - static int simulation_pmap(lua_State * l); - static int simulation_photons(lua_State * l); - static int simulation_neighbours(lua_State * l); - static int simulation_framerender(lua_State * l); - static int simulation_gspeed(lua_State * l); - static int simulation_takeSnapshot(lua_State *l); - static int simulation_historyRestore(lua_State *l); - static int simulation_historyForward(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); - static int simulation_lastUpdatedID(lua_State *l); - static int simulation_updateUpTo(lua_State *l); - static int simulation_temperatureScale(lua_State *l); - - - //Renderer - void initRendererAPI(); - static int renderer_renderModes(lua_State * l); - static int renderer_displayModes(lua_State * l); - static int renderer_colourMode(lua_State * l); - static int renderer_decorations(lua_State * l); - static int renderer_grid(lua_State * l); - static int renderer_showBrush(lua_State * l); - static int renderer_depth3d(lua_State * l); - static int renderer_zoomEnabled(lua_State *l); - static int renderer_zoomWindowInfo(lua_State *l); - static int renderer_zoomScopeInfo(lua_State *l); - - //Elements - void initElementsAPI(); - static int elements_allocate(lua_State * l); - static int elements_element(lua_State * l); - static int elements_property(lua_State * l); - static int elements_loadDefault(lua_State * l); - static int elements_free(lua_State * l); - static int elements_exists(lua_State * l); - - static void GetDefaultProperties(lua_State * l, int id); - static void SetDefaultProperties(lua_State * l, int id, int stackPos); - - //Interface - void initInterfaceAPI(); - static int interface_showWindow(lua_State * l); - static int interface_closeWindow(lua_State * l); - static int interface_addComponent(lua_State * l); - static int interface_removeComponent(lua_State * l); - static int interface_grabTextInput(lua_State * l); - static int interface_dropTextInput(lua_State * l); - static int interface_textInputRect(lua_State * l); - - void initGraphicsAPI(); - static int graphics_textSize(lua_State * l); - static int graphics_drawText(lua_State * l); - static int graphics_drawLine(lua_State * l); - static int graphics_drawRect(lua_State * l); - static int graphics_fillRect(lua_State * l); - static int graphics_drawCircle(lua_State * l); - static int graphics_fillCircle(lua_State * l); - static int graphics_getColors(lua_State * l); - static int graphics_getHexColor(lua_State * l); - static int graphics_setClipRect(lua_State * l); - - void initFileSystemAPI(); - static int fileSystem_list(lua_State * l); - static int fileSystem_exists(lua_State * l); - static int fileSystem_isFile(lua_State * l); - static int fileSystem_isDirectory(lua_State * l); - static int fileSystem_makeDirectory(lua_State * l); - static int fileSystem_removeDirectory(lua_State * l); - static int fileSystem_removeFile(lua_State * l); - static int fileSystem_move(lua_State * l); - static int fileSystem_copy(lua_State * l); - - void initPlatformAPI(); - static int platform_platform(lua_State * l); - static int platform_ident(lua_State * l); - static int platform_releaseType(lua_State * l); - static int platform_exeName(lua_State * l); - static int platform_restart(lua_State * l); - static int platform_openLink(lua_State * l); - static int platform_clipboardCopy(lua_State * l); - static int platform_clipboardPaste(lua_State * l); - - void initEventAPI(); - static int event_register(lua_State * l); - static int event_unregister(lua_State * l); - static int event_getmodifiers(lua_State * l); - - static int installScriptManager(lua_State * l); - - void initHttpAPI(); - void initSocketAPI(); - - std::vector lua_el_func_v, lua_gr_func_v, lua_cd_func_v; - std::vector lua_el_mode_v; - std::vector gameControllerEventHandlers; +class LuaScriptInterface : public TPTScriptInterface +{ + LuaStatePtr luaState; public: - static void LuaGetProperty(lua_State* l, StructProperty property, intptr_t propertyAddress); - static void LuaSetProperty(lua_State* l, StructProperty property, intptr_t propertyAddress, int stackPos); - static void LuaSetParticleProperty(lua_State* l, int particleID, StructProperty property, intptr_t propertyAddress, int stackPos); + lua_State *L{}; - int luaHookTimeout; - ui::Window * Window; - lua_State *l; + GameModel *gameModel; + GameController *gameController; + ui::Window *window; + Simulation *sim; + Graphics *g; + Renderer *ren; + + std::vector customElements; // must come after luaState + + EventTraits eventTraits = eventTraitNone; + + bool luacon_hasLastError = false; + String lastCode; + + bool currentCommand = false; + int textInputRefcount = 0; long unsigned int luaExecutionStart = 0; - std::map grabbed_components; - LuaScriptInterface(GameController * c, GameModel * m); - char custom_can_move[PT_NUM][PT_NUM]; - void custom_init_can_move(); + std::vector gameControllerEventHandlers; // must come after luaState + std::unique_ptr scriptManagerDownload; + int luaHookTimeout; + + std::map grabbedComponents; // must come after luaState + + LuaScriptInterface(GameController *newGameController, GameModel *newGameModel); + ~LuaScriptInterface(); + + char customCanMove[PT_NUM][PT_NUM]; + void InitCustomCanMove(); void OnTick() override; bool HandleEvent(const GameControllerEvent &event) override; void Init() override; - void SetWindow(ui::Window * window); int Command(String command) override; String FormatCommand(String command) override; - virtual ~LuaScriptInterface(); }; void tpt_lua_pushByteString(lua_State *L, const ByteString &str); @@ -235,11 +123,78 @@ int tpt_lua_loadstring(lua_State *L, const ByteString &str); int tpt_lua_dostring(lua_State *L, const ByteString &str); bool tpt_lua_equalsString(lua_State *L, int index, const char *data, size_t size); -template + // TODO: use std::literals::string_literals::operator""s if we get rid of ByteString +template bool tpt_lua_equalsLiteral(lua_State *L, int index, const char (&lit)[N]) { return tpt_lua_equalsString(L, index, lit, N - 1U); } int tpt_lua_pcall(lua_State *L, int numArgs, int numResults, int errorFunc, EventTraits eventTraits); + +namespace LuaHttp +{ + void Open(lua_State *L); +} + +namespace LuaBz2 +{ + void Open(lua_State *L); +} + +namespace LuaElements +{ + void Open(lua_State *L); +} + +namespace LuaEvent +{ + void Open(lua_State *L); +} + +namespace LuaFileSystem +{ + void Open(lua_State *L); +} + +namespace LuaGraphics +{ + void Open(lua_State *L); +} + +namespace LuaInterface +{ + void Open(lua_State *L); +} + +namespace LuaMisc +{ + void Open(lua_State *L); + void Tick(lua_State *L); +} + +namespace LuaPlatform +{ + void Open(lua_State *L); +} + +namespace LuaRenderer +{ + void Open(lua_State *L); +} + +namespace LuaSimulation +{ + void Open(lua_State *L); +} + +namespace LuaSocket +{ + int GetTime(lua_State *L); + int Sleep(lua_State *L); + double Now(); + void Timeout(double timeout); + void Open(lua_State *L); + void OpenTCP(lua_State *L); +} diff --git a/src/lua/LuaSimulation.cpp b/src/lua/LuaSimulation.cpp new file mode 100644 index 000000000..574aabc11 --- /dev/null +++ b/src/lua/LuaSimulation.cpp @@ -0,0 +1,2091 @@ +#include "LuaScriptInterface.h" +#include "client/Client.h" +#include "client/GameSave.h" +#include "client/SaveFile.h" +#include "client/SaveInfo.h" +#include "Format.h" +#include "gui/game/GameController.h" +#include "gui/game/GameModel.h" +#include "gui/game/Brush.h" +#include "gui/game/Tool.h" +#include "simulation/Air.h" +#include "simulation/ElementCommon.h" +#include "simulation/GOLString.h" +#include "simulation/gravity/Gravity.h" +#include "simulation/Snapshot.h" +#include "simulation/ToolClasses.h" +#include + +static int ambientHeatSim(lua_State *L) +{ + auto *lsi = static_cast(commandInterface); + int acount = lua_gettop(L); + if (acount == 0) + { + lua_pushboolean(L, lsi->sim->aheat_enable); + return 1; + } + auto aheatstate = lua_toboolean(L, 1); + lsi->sim->aheat_enable = aheatstate; + lsi->gameModel->UpdateQuickOptions(); + + return 0; +} + +static int heatSim(lua_State *L) +{ + auto *lsi = static_cast(commandInterface); + int acount = lua_gettop(L); + if (acount == 0) + { + lua_pushboolean(L, !lsi->sim->legacy_enable); + return 1; + } + auto heatstate = lua_toboolean(L, 1); + lsi->sim->legacy_enable = !heatstate; + return 0; +} + +static int newtonianGravity(lua_State *L) +{ + auto *lsi = static_cast(commandInterface); + int acount = lua_gettop(L); + if (acount == 0) + { + lua_pushboolean(L, lsi->sim->grav->IsEnabled()); + return 1; + } + int gravstate = lua_toboolean(L, 1); + if(gravstate) + lsi->sim->grav->start_grav_async(); + else + lsi->sim->grav->stop_grav_async(); + lsi->gameModel->UpdateQuickOptions(); + return 0; +} + +static int paused(lua_State *L) +{ + auto *lsi = static_cast(commandInterface); + int acount = lua_gettop(L); + if (acount == 0) + { + lua_pushboolean(L, lsi->gameModel->GetPaused()); + return 1; + } + auto pausestate = lua_toboolean(L, 1); + lsi->gameModel->SetPaused(pausestate); + return 0; +} + +static int partCount(lua_State *L) +{ + auto *lsi = static_cast(commandInterface); + lua_pushinteger(L, lsi->sim->NUM_PARTS); + return 1; +} + +static int decoSpace(lua_State *L) +{ + auto *lsi = static_cast(commandInterface); + if (lua_gettop(L) < 1) + { + lua_pushnumber(L, lsi->gameModel->GetDecoSpace()); + return 1; + } + auto index = luaL_checkint(L, 1); + if (index < 0 || index >= NUM_DECOSPACES) + { + return luaL_error(L, "Invalid deco space index %i", index); + } + lsi->gameModel->SetDecoSpace(index); + return 0; +} + +template +struct LuaBlockMapHelper +{ + using ItemType = std::remove_reference_t>>; +}; + +template::ItemType> +static int LuaBlockMapImpl(lua_State *L, ItemType minValue, ItemType maxValue, Accessor accessor) +{ + auto pos = Vec2{ luaL_checkint(L, 1), luaL_checkint(L, 2) }; + if (!CELLS.OriginRect().Contains(pos)) + { + return luaL_error(L, "Coordinates (%i, %i) out of range", pos.X, pos.Y); + } + auto argc = lua_gettop(L); + if (argc == 2) + { + if constexpr (std::is_integral_v) + { + lua_pushinteger(L, lua_Integer(accessor(pos))); + } + else + { + lua_pushnumber(L, lua_Number(accessor(pos))); + } + return 1; + } + auto size = Vec2{ 1, 1 }; + auto valuePos = 3; + if (argc > 3) + { + size = Vec2{ luaL_checkint(L, 3), luaL_checkint(L, 4) }; + valuePos = 5; + } + ItemType value; + if constexpr (std::is_integral_v) + { + value = ItemType(luaL_checkint(L, valuePos)); + } + else + { + value = ItemType(luaL_checknumber(L, valuePos)); + } + if constexpr (Clamp) + { + if (value > maxValue) value = maxValue; + if (value < minValue) value = minValue; + } + for (auto p : CELLS.OriginRect() & RectSized(pos, size)) + { + accessor(p) = value; + } + return 0; +} + +template::ItemType> +static int LuaBlockMap(lua_State *L, ItemType minValue, ItemType maxValue, Accessor accessor) +{ + return LuaBlockMapImpl(L, minValue, maxValue, accessor); +} + +template::ItemType> +static int LuaBlockMap(lua_State *L, Accessor accessor) +{ + return LuaBlockMapImpl(L, ItemType(0), ItemType(0), accessor); +} + +static int velocityX(lua_State *L) +{ + auto *lsi = static_cast(commandInterface); + return LuaBlockMap(L, MIN_PRESSURE, MAX_PRESSURE, [lsi](Vec2 p) -> float & { + return lsi->sim->vx[p.Y][p.X]; + }); +} + +static int velocityY(lua_State *L) +{ + auto *lsi = static_cast(commandInterface); + return LuaBlockMap(L, MIN_PRESSURE, MAX_PRESSURE, [lsi](Vec2 p) -> float & { + return lsi->sim->vy[p.Y][p.X]; + }); +} + +static int ambientHeat(lua_State *L) +{ + auto *lsi = static_cast(commandInterface); + return LuaBlockMap(L, MIN_TEMP, MAX_TEMP, [lsi](Vec2 p) -> float & { + return lsi->sim->hv[p.Y][p.X]; + }); +} + +static int pressure(lua_State *L) +{ + auto *lsi = static_cast(commandInterface); + return LuaBlockMap(L, MIN_PRESSURE, MAX_PRESSURE, [lsi](Vec2 p) -> float & { + return lsi->sim->pv[p.Y][p.X]; + }); +} + +static int gravityMass(lua_State *L) +{ + auto *lsi = static_cast(commandInterface); + return LuaBlockMap(L, [lsi](Vec2 p) -> float & { + return lsi->sim->gravmap[p.Y * XCELLS + p.X]; + }); +} + +static int gravityField(lua_State *L) +{ + auto *lsi = static_cast(commandInterface); + auto pos = Vec2{ luaL_checkint(L, 1), luaL_checkint(L, 2) }; + if (!CELLS.OriginRect().Contains(pos)) + { + return luaL_error(L, "Coordinates (%i, %i) out of range", pos.X, pos.Y); + } + lua_pushnumber(L, lsi->sim->gravx[pos.Y * XCELLS + pos.X]); + lua_pushnumber(L, lsi->sim->gravy[pos.Y * XCELLS + pos.X]); + return 2; +} + +static int elecMap(lua_State *L) +{ + auto *lsi = static_cast(commandInterface); + return LuaBlockMap(L, [lsi](Vec2 p) -> unsigned char & { + return lsi->sim->emap[p.Y][p.X]; + }); +} + +static int wallMap(lua_State *L) +{ + auto *lsi = static_cast(commandInterface); + return LuaBlockMap(L, 0, UI_WALLCOUNT - 1, [lsi](Vec2 p) -> unsigned char & { + return lsi->sim->bmap[p.Y][p.X]; + }); +} + +static int fanVelocityX(lua_State *L) +{ + auto *lsi = static_cast(commandInterface); + return LuaBlockMap(L, [lsi](Vec2 p) -> float & { + return lsi->sim->fvx[p.Y][p.X]; + }); +} + +static int fanVelocityY(lua_State *L) +{ auto *lsi = static_cast(commandInterface); + return LuaBlockMap(L, [lsi](Vec2 p) -> float & { + return lsi->sim->fvy[p.Y][p.X]; + }); +} + +static int partNeighbors(lua_State *L) +{ + auto *lsi = static_cast(commandInterface); + auto *sim = lsi->sim; + lua_newtable(L); + int id = 1; + int x = lua_tointeger(L, 1), y = lua_tointeger(L, 2), r = lua_tointeger(L, 3), rx, ry, n; + if(lua_gettop(L) == 5) // this is one more than the number of arguments because a table has just been pushed onto the stack with lua_newtable(L); + { + int t = lua_tointeger(L, 4); + for (rx = -r; rx <= r; rx++) + for (ry = -r; ry <= r; ry++) + if (x+rx >= 0 && y+ry >= 0 && x+rx < XRES && y+ry < YRES && (rx || ry)) + { + n = sim->pmap[y+ry][x+rx]; + if (!n || TYP(n) != t) + n = sim->photons[y+ry][x+rx]; + if (n && TYP(n) == t) + { + lua_pushinteger(L, ID(n)); + lua_rawseti(L, -2, id++); + } + } + + } + else + { + for (rx = -r; rx <= r; rx++) + for (ry = -r; ry <= r; ry++) + if (x+rx >= 0 && y+ry >= 0 && x+rx < XRES && y+ry < YRES && (rx || ry)) + { + n = sim->pmap[y+ry][x+rx]; + if (!n) + n = sim->photons[y+ry][x+rx]; + if (n) + { + lua_pushinteger(L, ID(n)); + lua_rawseti(L, -2, id++); + } + } + } + return 1; +} + +static int partChangeType(lua_State *L) +{ + auto *lsi = static_cast(commandInterface); + int partIndex = lua_tointeger(L, 1); + if(partIndex < 0 || partIndex >= NPART || !lsi->sim->parts[partIndex].type) + return 0; + lsi->sim->part_change_type(partIndex, int(lsi->sim->parts[partIndex].x+0.5f), int(lsi->sim->parts[partIndex].y+0.5f), lua_tointeger(L, 2)); + return 0; +} + +static int partCreate(lua_State *L) +{ + auto *lsi = static_cast(commandInterface); + int newID = lua_tointeger(L, 1); + if (newID >= NPART || newID < -3) + { + lua_pushinteger(L, -1); + return 1; + } + if (newID >= 0 && !lsi->sim->parts[newID].type) + { + lua_pushinteger(L, -1); + return 1; + } + int type = lua_tointeger(L, 4); + int v = -1; + if (lua_gettop(L) >= 5) + { + v = lua_tointeger(L, 5); + } + else if (ID(type)) + { + v = ID(type); + type = TYP(type); + } + lua_pushinteger(L, lsi->sim->create_part(newID, lua_tointeger(L, 2), lua_tointeger(L, 3), type, v)); + return 1; +} + +static int partID(lua_State *L) +{ + auto *lsi = static_cast(commandInterface); + int x = lua_tointeger(L, 1); + int y = lua_tointeger(L, 2); + + if(x < 0 || x >= XRES || y < 0 || y >= YRES) + { + lua_pushnil(L); + return 1; + } + + int amalgam = lsi->sim->pmap[y][x]; + if(!amalgam) + amalgam = lsi->sim->photons[y][x]; + if (!amalgam) + lua_pushnil(L); + else + lua_pushinteger(L, ID(amalgam)); + return 1; +} + +static int partPosition(lua_State *L) +{ + auto *lsi = static_cast(commandInterface); + auto *sim = lsi->sim; + int particleID = lua_tointeger(L, 1); + int argCount = lua_gettop(L); + if (particleID < 0 || particleID >= NPART || !sim->parts[particleID].type) + { + if(argCount == 1) + { + lua_pushnil(L); + lua_pushnil(L); + return 2; + } else { + return 0; + } + } + + if (argCount == 3) + { + float x = sim->parts[particleID].x; + float y = sim->parts[particleID].y; + sim->move(particleID, (int)(x + 0.5f), (int)(y + 0.5f), lua_tonumber(L, 2), lua_tonumber(L, 3)); + + return 0; + } + else + { + lua_pushnumber(L, sim->parts[particleID].x); + lua_pushnumber(L, sim->parts[particleID].y); + return 2; + } +} + +static int partProperty(lua_State *L) +{ + auto *lsi = static_cast(commandInterface); + int argCount = lua_gettop(L); + int particleID = luaL_checkinteger(L, 1); + StructProperty property; + + if (particleID < 0 || particleID >= NPART || !lsi->sim->parts[particleID].type) + { + if (argCount == 3) + { + lua_pushnil(L); + return 1; + } + else + { + return 0; + } + } + + auto &properties = Particle::GetProperties(); + auto prop = properties.end(); + + //Get field + if (lua_type(L, 2) == LUA_TNUMBER) + { + int fieldID = lua_tointeger(L, 2); + if (fieldID < 0 || fieldID >= (int)properties.size()) + return luaL_error(L, "Invalid field ID (%d)", fieldID); + prop = properties.begin() + fieldID; + } + else if (lua_type(L, 2) == LUA_TSTRING) + { + ByteString fieldName = tpt_lua_toByteString(L, 2); + for (auto &alias : Particle::GetPropertyAliases()) + { + if (fieldName == alias.from) + { + fieldName = alias.to; + } + } + prop = std::find_if(properties.begin(), properties.end(), [&fieldName](StructProperty const &p) { + return p.Name == fieldName; + }); + if (prop == properties.end()) + return luaL_error(L, "Unknown field (%s)", fieldName.c_str()); + } + else + { + return luaL_error(L, "Field ID must be an name (string) or identifier (integer)"); + } + + //Calculate memory address of property + intptr_t propertyAddress = (intptr_t)(((unsigned char*)&lsi->sim->parts[particleID]) + prop->Offset); + + if (argCount == 3) + { + LuaSetParticleProperty(L, particleID, *prop, propertyAddress, 3); + return 0; + } + else + { + LuaGetProperty(L, *prop, propertyAddress); + return 1; + } +} + +static int partKill(lua_State *L) +{ + auto *lsi = static_cast(commandInterface); + if(lua_gettop(L)==2) + lsi->sim->delete_part(lua_tointeger(L, 1), lua_tointeger(L, 2)); + else + { + int i = lua_tointeger(L, 1); + if (i>=0 && isim->kill_part(i); + } + return 0; +} + +static int partExists(lua_State *L) +{ + auto *lsi = static_cast(commandInterface); + int i = luaL_checkinteger(L, 1); + lua_pushboolean(L, i >= 0 && i < NPART && lsi->sim->parts[i].type); + return 1; +} + +static int createParts(lua_State *L) +{ + auto *lsi = static_cast(commandInterface); + int x = luaL_optint(L,1,-1); + int y = luaL_optint(L,2,-1); + int rx = luaL_optint(L,3,5); + int ry = luaL_optint(L,4,5); + int c = luaL_optint(L,5,lsi->gameModel->GetActiveTool(0)->ToolID); + int brushID = luaL_optint(L,6,BRUSH_CIRCLE); + int flags = luaL_optint(L,7,lsi->sim->replaceModeFlags); + + Brush *brush = lsi->gameModel->GetBrushByID(brushID); + if (!brush) + return luaL_error(L, "Invalid brush id '%d'", brushID); + auto newBrush = brush->Clone(); + newBrush->SetRadius(ui::Point(rx, ry)); + + int ret = lsi->sim->CreateParts(x, y, c, *newBrush, flags); + lua_pushinteger(L, ret); + return 1; +} + +static int createLine(lua_State *L) +{ + auto *lsi = static_cast(commandInterface); + int x1 = luaL_optint(L,1,-1); + int y1 = luaL_optint(L,2,-1); + int x2 = luaL_optint(L,3,-1); + int y2 = luaL_optint(L,4,-1); + int rx = luaL_optint(L,5,5); + int ry = luaL_optint(L,6,5); + int c = luaL_optint(L,7,lsi->gameModel->GetActiveTool(0)->ToolID); + int brushID = luaL_optint(L,8,BRUSH_CIRCLE); + int flags = luaL_optint(L,9,lsi->sim->replaceModeFlags); + + Brush *brush = lsi->gameModel->GetBrushByID(brushID); + if (!brush) + return luaL_error(L, "Invalid brush id '%d'", brushID); + auto newBrush = brush->Clone(); + newBrush->SetRadius(ui::Point(rx, ry)); + + lsi->sim->CreateLine(x1, y1, x2, y2, c, *newBrush, flags); + return 0; +} + +static int createBox(lua_State *L) +{ + auto *lsi = static_cast(commandInterface); + int x1 = luaL_optint(L,1,-1); + int y1 = luaL_optint(L,2,-1); + int x2 = luaL_optint(L,3,-1); + int y2 = luaL_optint(L,4,-1); + int c = luaL_optint(L,5,lsi->gameModel->GetActiveTool(0)->ToolID); + int flags = luaL_optint(L,6,lsi->sim->replaceModeFlags); + + lsi->sim->CreateBox(x1, y1, x2, y2, c, flags); + return 0; +} + +static int floodParts(lua_State *L) +{ + auto *lsi = static_cast(commandInterface); + int x = luaL_optint(L,1,-1); + int y = luaL_optint(L,2,-1); + int c = luaL_optint(L,3,lsi->gameModel->GetActiveTool(0)->ToolID); + int cm = luaL_optint(L,4,-1); + int flags = luaL_optint(L,5,lsi->sim->replaceModeFlags); + + if (x < 0 || x >= XRES || y < 0 || y >= YRES) + return luaL_error(L, "coordinates out of range (%d,%d)", x, y); + + int ret = lsi->sim->FloodParts(x, y, c, cm, flags); + lua_pushinteger(L, ret); + return 1; +} + +static int createWalls(lua_State *L) +{ + int x = luaL_optint(L,1,-1); + int y = luaL_optint(L,2,-1); + int rx = luaL_optint(L,3,0); + int ry = luaL_optint(L,4,0); + int c = luaL_optint(L,5,8); + + if (x < 0 || x >= XRES || y < 0 || y >= YRES) + return luaL_error(L, "coordinates out of range (%d,%d)", x, y); + if (c < 0 || c >= UI_WALLCOUNT) + return luaL_error(L, "Unrecognised wall id '%d'", c); + + auto *lsi = static_cast(commandInterface); + int ret = lsi->sim->CreateWalls(x, y, rx, ry, c, NULL); + lua_pushinteger(L, ret); + return 1; +} + +static int createWallLine(lua_State *L) +{ + int x1 = luaL_optint(L,1,-1); + int y1 = luaL_optint(L,2,-1); + int x2 = luaL_optint(L,3,-1); + int y2 = luaL_optint(L,4,-1); + int rx = luaL_optint(L,5,0); + int ry = luaL_optint(L,6,0); + int c = luaL_optint(L,7,8); + + 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 (c < 0 || c >= UI_WALLCOUNT) + return luaL_error(L, "Unrecognised wall id '%d'", c); + + auto *lsi = static_cast(commandInterface); + lsi->sim->CreateWallLine(x1, y1, x2, y2, rx, ry, c, NULL); + return 0; +} + +static int createWallBox(lua_State *L) +{ + int x1 = luaL_optint(L,1,-1); + int y1 = luaL_optint(L,2,-1); + int x2 = luaL_optint(L,3,-1); + int y2 = luaL_optint(L,4,-1); + int c = luaL_optint(L,5,8); + + 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 (c < 0 || c >= UI_WALLCOUNT) + return luaL_error(L, "Unrecognised wall id '%d'", c); + + auto *lsi = static_cast(commandInterface); + lsi->sim->CreateWallBox(x1, y1, x2, y2, c); + return 0; +} + +static int floodWalls(lua_State *L) +{ + int x = luaL_optint(L,1,-1); + int y = luaL_optint(L,2,-1); + int c = luaL_optint(L,3,8); + int bm = luaL_optint(L,4,-1); + if (x < 0 || x >= XRES || y < 0 || y >= YRES) + return luaL_error(L, "coordinates out of range (%d,%d)", x, y); + if (c < 0 || c >= UI_WALLCOUNT) + return luaL_error(L, "Unrecognised wall id '%d'", c); + if (c == WL_STREAM) + { + lua_pushinteger(L, 0); + return 1; + } + auto *lsi = static_cast(commandInterface); + int ret = lsi->sim->FloodWalls(x, y, c, bm); + lua_pushinteger(L, ret); + return 1; +} + +static int 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); + int ry = luaL_optint(L,4,5); + int tool = luaL_optint(L,5,0); + int brushID = luaL_optint(L,6,BRUSH_CIRCLE); + float strength = luaL_optnumber(L,7,1.0f); + if (tool == (int)sd.tools.size()) + { + lua_pushinteger(L, 0); + return 1; + } + else if (tool < 0 || tool > (int)sd.tools.size()) + return luaL_error(L, "Invalid tool id '%d'", tool); + + auto *lsi = static_cast(commandInterface); + Brush *brush = lsi->gameModel->GetBrushByID(brushID); + if (!brush) + return luaL_error(L, "Invalid brush id '%d'", brushID); + auto newBrush = brush->Clone(); + newBrush->SetRadius(ui::Point(rx, ry)); + + int ret = lsi->sim->ToolBrush(x, y, tool, *newBrush, strength); + lua_pushinteger(L, ret); + return 1; +} + +static int 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); + int y2 = luaL_optint(L,4,-1); + int rx = luaL_optint(L,5,5); + int ry = luaL_optint(L,6,5); + int tool = luaL_optint(L,7,0); + int brushID = luaL_optint(L,8,BRUSH_CIRCLE); + float strength = luaL_optnumber(L,9,1.0f); + + 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)sd.tools.size()+1) + return luaL_error(L, "Invalid tool id '%d'", tool); + + auto *lsi = static_cast(commandInterface); + Brush *brush = lsi->gameModel->GetBrushByID(brushID); + if (!brush) + return luaL_error(L, "Invalid brush id '%d'", brushID); + auto newBrush = brush->Clone(); + newBrush->SetRadius(ui::Point(rx, ry)); + + if (tool == (int)sd.tools.size()) + { + Tool *windTool = lsi->gameModel->GetToolFromIdentifier("DEFAULT_UI_WIND"); + float oldStrength = windTool->Strength; + windTool->Strength = strength; + windTool->DrawLine(lsi->sim, *newBrush, ui::Point(x1, y1), ui::Point(x2, y2)); + windTool->Strength = oldStrength; + } + else + lsi->sim->ToolLine(x1, y1, x2, y2, tool, *newBrush, strength); + return 0; +} + +static int 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); + int y2 = luaL_optint(L,4,-1); + 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); + int tool = luaL_optint(L,5,0); + float strength = luaL_optnumber(L,6,1.0f); + if (tool == (int)sd.tools.size()) + { + lua_pushinteger(L, 0); + return 1; + } + else if (tool < 0 || tool >= (int)sd.tools.size()) + return luaL_error(L, "Invalid tool id '%d'", tool); + + auto *lsi = static_cast(commandInterface); + lsi->sim->ToolBox(x1, y1, x2, y2, tool, strength); + return 0; +} + +static int decoBrush(lua_State *L) +{ + int x = luaL_optint(L,1,-1); + int y = luaL_optint(L,2,-1); + int rx = luaL_optint(L,3,5); + int ry = luaL_optint(L,4,5); + int r = luaL_optint(L,5,255); + int g = luaL_optint(L,6,255); + int b = luaL_optint(L,7,255); + int a = luaL_optint(L,8,255); + int tool = luaL_optint(L,9,DECO_DRAW); + int brushID = luaL_optint(L,10,BRUSH_CIRCLE); + + auto *lsi = static_cast(commandInterface); + Brush *brush = lsi->gameModel->GetBrushByID(brushID); + if (!brush) + return luaL_error(L, "Invalid brush id '%d'", brushID); + auto newBrush = brush->Clone(); + newBrush->SetRadius(ui::Point(rx, ry)); + + lsi->sim->ApplyDecorationPoint(x, y, r, g, b, a, tool, *newBrush); + return 0; +} + +static int decoLine(lua_State *L) +{ + int x1 = luaL_optint(L,1,-1); + int y1 = luaL_optint(L,2,-1); + int x2 = luaL_optint(L,3,-1); + int y2 = luaL_optint(L,4,-1); + int rx = luaL_optint(L,5,5); + int ry = luaL_optint(L,6,5); + int r = luaL_optint(L,7,255); + int g = luaL_optint(L,8,255); + int b = luaL_optint(L,9,255); + int a = luaL_optint(L,10,255); + int tool = luaL_optint(L,11,DECO_DRAW); + int brushID = luaL_optint(L,12,BRUSH_CIRCLE); + + 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); + + auto *lsi = static_cast(commandInterface); + Brush *brush = lsi->gameModel->GetBrushByID(brushID); + if (!brush) + return luaL_error(L, "Invalid brush id '%d'", brushID); + auto newBrush = brush->Clone(); + newBrush->SetRadius(ui::Point(rx, ry)); + + lsi->sim->ApplyDecorationLine(x1, y1, x2, y2, r, g, b, a, tool, *newBrush); + return 0; +} + +static int decoBox(lua_State *L) +{ + int x1 = luaL_optint(L,1,-1); + int y1 = luaL_optint(L,2,-1); + int x2 = luaL_optint(L,3,-1); + int y2 = luaL_optint(L,4,-1); + int r = luaL_optint(L,5,255); + int g = luaL_optint(L,6,255); + int b = luaL_optint(L,7,255); + int a = luaL_optint(L,8,255); + int tool = luaL_optint(L,9,0); + + 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); + + auto *lsi = static_cast(commandInterface); + lsi->sim->ApplyDecorationBox(x1, y1, x2, y2, r, g, b, a, tool); + return 0; +} + +static int decoColor(lua_State *L) +{ + auto *lsi = static_cast(commandInterface); + int acount = lua_gettop(L); + RGBA color(0, 0, 0, 0); + if (acount == 0) + { + lua_pushnumber(L, lsi->gameModel->GetColourSelectorColour().Pack()); + return 1; + } + else if (acount == 1) + color = RGBA::Unpack(pixel_rgba(luaL_optnumber(L, 1, 0xFFFF0000))); + else + { + color.Red = std::clamp(luaL_optint(L, 1, 255), 0, 255); + color.Green = std::clamp(luaL_optint(L, 2, 255), 0, 255); + color.Blue = std::clamp(luaL_optint(L, 3, 255), 0, 255); + color.Alpha = std::clamp(luaL_optint(L, 4, 255), 0, 255); + } + lsi->gameModel->SetColourSelectorColour(color); + return 0; +} + +static int 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); + + auto *lsi = static_cast(commandInterface); + // hilariously broken, intersects with console and all Lua graphics + auto loc = RGB::Unpack(lsi->ren->GetPixel({ x, y })); + lsi->sim->ApplyDecorationFill(lsi->ren, x, y, r, g, b, a, loc.Red, loc.Green, loc.Blue); + return 0; +} + +static int clearSim(lua_State *L) +{ + auto *lsi = static_cast(commandInterface); + lsi->gameController->ClearSim(); + return 0; +} + +static int clearRect(lua_State *L) +{ + auto *lsi = static_cast(commandInterface); + int x = luaL_checkint(L,1); + int y = luaL_checkint(L,2); + int w = luaL_checkint(L,3)-1; + int h = luaL_checkint(L,4)-1; + lsi->sim->clear_area(x, y, w, h); + return 0; +} + +static int resetTemp(lua_State *L) +{ + auto *lsi = static_cast(commandInterface); + auto *sim = lsi->sim; + auto &sd = SimulationData::CRef(); + auto &elements = sd.elements; + bool onlyConductors = luaL_optint(L, 1, 0); + for (int i = 0; i < sim->parts_lastActiveIndex; i++) + { + if (sim->parts[i].type && (elements[sim->parts[i].type].HeatConduct || !onlyConductors)) + { + sim->parts[i].temp = elements[sim->parts[i].type].DefaultProperties.temp; + } + } + return 0; +} + +static int resetPressure(lua_State *L) +{ + int aCount = lua_gettop(L), width = XCELLS, height = YCELLS; + int x1 = abs(luaL_optint(L, 1, 0)); + int y1 = abs(luaL_optint(L, 2, 0)); + if (aCount > 2) + { + width = abs(luaL_optint(L, 3, XCELLS)); + height = abs(luaL_optint(L, 4, YCELLS)); + } + else if (aCount) + { + width = 1; + height = 1; + } + if(x1 > XCELLS-1) + x1 = XCELLS-1; + if(y1 > YCELLS-1) + y1 = YCELLS-1; + if(x1+width > XCELLS-1) + width = XCELLS-x1; + if(y1+height > YCELLS-1) + height = YCELLS-y1; + auto *lsi = static_cast(commandInterface); + for (int nx = x1; nxsim->air->pv[ny][nx] = 0; + } + return 0; +} + +static int saveStamp(lua_State *L) +{ + int x = luaL_optint(L,1,0); + int y = luaL_optint(L,2,0); + int w = luaL_optint(L,3,XRES-1); + int h = luaL_optint(L,4,YRES-1); + bool includePressure = luaL_optint(L, 5, 1); + auto *lsi = static_cast(commandInterface); + ByteString name = lsi->gameController->StampRegion(ui::Point(x, y), ui::Point(x+w, y+h), includePressure); + tpt_lua_pushByteString(L, name); + return 1; +} + +static int loadStamp(lua_State *L) +{ + int i = -1; + int pushed = 1; + std::unique_ptr tempfile; + Vec2 partP = { + luaL_optint(L, 2, 0), + luaL_optint(L, 3, 0), + }; + auto hflip = lua_toboolean(L, 4); + auto rotation = luaL_optint(L, 5, 0) & 3; // [0, 3] rotations + bool includePressure = luaL_optint(L, 6, 1); + auto &client = Client::Ref(); + if (lua_isstring(L, 1)) //Load from 10 char name, or full filename + { + auto filename = tpt_lua_optByteString(L, 1, ""); + tempfile = client.GetStamp(filename); + } + if ((!tempfile || !tempfile->GetGameSave()) && lua_isnumber(L, 1)) //Load from stamp ID + { + i = luaL_optint(L, 1, 0); + auto &stampIDs = client.GetStamps(); + if (i < 0 || i >= int(stampIDs.size())) + return luaL_error(L, "Invalid stamp ID: %d", i); + tempfile = client.GetStamp(stampIDs[i]); + } + + if (tempfile && tempfile->GetGameSave()) + { + auto gameSave = tempfile->TakeGameSave(); + auto [ quoX, remX ] = floorDiv(partP.X, CELL); + auto [ quoY, remY ] = floorDiv(partP.Y, CELL); + if (remX || remY || hflip || rotation) + { + auto transform = Mat2::Identity; + if (hflip) + { + transform = Mat2::MirrorX * transform; + } + for (auto i = 0; i < rotation; ++i) + { + transform = Mat2::CCW * transform; + } + gameSave->Transform(transform, { remX, remY }); + } + auto *lsi = static_cast(commandInterface); + lsi->sim->Load(gameSave.get(), includePressure, { quoX, quoY }); + lua_pushinteger(L, 1); + + if (gameSave->authors.size()) + { + gameSave->authors["type"] = "luastamp"; + client.MergeStampAuthorInfo(gameSave->authors); + } + } + else + { + pushed = 2; + lua_pushnil(L); + tpt_lua_pushString(L, tempfile ? tempfile->GetError() : "does not exist"); + } + return pushed; +} + +static int deleteStamp(lua_State *L) +{ + auto &client = Client::Ref(); + auto &stampIDs = client.GetStamps(); + + if (lua_isstring(L, 1)) //note: lua_isstring returns true on numbers too + { + auto filename = tpt_lua_optByteString(L, 1, ""); + for (auto &stampID : stampIDs) + { + if (stampID == filename) + { + client.DeleteStamp(stampID); + return 0; + } + } + } + if (lua_isnumber(L, 1)) //Load from stamp ID + { + int i = luaL_optint(L, 1, 0); + if (i < 0 || i >= int(stampIDs.size())) + return luaL_error(L, "Invalid stamp ID: %d", i); + client.DeleteStamp(stampIDs[i]); + return 0; + } + lua_pushnumber(L, -1); + return 1; +} + +static int listStamps(lua_State *L) +{ + lua_newtable(L); + auto &client = Client::Ref(); + auto &stampIDs = client.GetStamps(); + auto i = 0; + for (auto &stampID : stampIDs) + { + tpt_lua_pushByteString(L, stampID); + i += 1; + lua_rawseti(L, -2, i); + } + return 1; +} + +static int loadSave(lua_State *L) +{ + int saveID = luaL_optint(L,1,0); + int instant = luaL_optint(L,2,0); + int history = luaL_optint(L,3,0); //Exact second a previous save was saved + auto *lsi = static_cast(commandInterface); + lsi->gameController->OpenSavePreview(saveID, history, instant ? savePreviewInstant : savePreviewNormal); + return 0; +} + +static int reloadSave(lua_State *L) +{ + auto *lsi = static_cast(commandInterface); + lsi->gameController->ReloadSim(); + return 0; +} + +static int getSaveID(lua_State *L) +{ + auto *lsi = static_cast(commandInterface); + auto *tempSave = lsi->gameModel->GetSave(); + if (tempSave) + { + lua_pushinteger(L, tempSave->GetID()); + lua_pushinteger(L, tempSave->Version); + return 2; + } + return 0; +} + +static int adjustCoords(lua_State *L) +{ + auto *lsi = static_cast(commandInterface); + int x = luaL_optint(L,1,0); + int y = luaL_optint(L,2,0); + ui::Point Coords = lsi->gameController->PointTranslate(ui::Point(x, y)); + lua_pushinteger(L, Coords.X); + lua_pushinteger(L, Coords.Y); + return 2; +} + +static int prettyPowders(lua_State *L) +{ + auto *lsi = static_cast(commandInterface); + int acount = lua_gettop(L); + if (acount == 0) + { + lua_pushnumber(L, lsi->sim->pretty_powder); + return 1; + } + int prettyPowder = luaL_optint(L, 1, 0); + lsi->sim->pretty_powder = prettyPowder; + lsi->gameModel->UpdateQuickOptions(); + return 0; +} + +static int gravityGrid(lua_State *L) +{ + auto *lsi = static_cast(commandInterface); + int acount = lua_gettop(L); + if (acount == 0) + { + lua_pushnumber(L, lsi->gameModel->GetGravityGrid()); + return 1; + } + int gravityGrid = luaL_optint(L, 1, 0); + lsi->gameModel->ShowGravityGrid(gravityGrid); + lsi->gameModel->UpdateQuickOptions(); + return 0; +} + +static int edgeMode(lua_State *L) +{ + auto *lsi = static_cast(commandInterface); + int acount = lua_gettop(L); + if (acount == 0) + { + lua_pushnumber(L, lsi->gameModel->GetEdgeMode()); + return 1; + } + int edgeMode = luaL_optint(L, 1, EDGE_VOID); + lsi->gameModel->SetEdgeMode(edgeMode); + return 0; +} + +static int gravityMode(lua_State *L) +{ + auto *lsi = static_cast(commandInterface); + int acount = lua_gettop(L); + if (acount == 0) + { + lua_pushnumber(L, lsi->sim->gravityMode); + return 1; + } + int gravityMode = luaL_optint(L, 1, GRAV_VERTICAL); + lsi->sim->gravityMode = gravityMode; + return 0; +} + +static int customGravity(lua_State *L) +{ + auto *lsi = static_cast(commandInterface); + auto *sim = lsi->sim; + int acount = lua_gettop(L); + if (acount == 0) + { + lua_pushnumber(L, sim->customGravityX); + lua_pushnumber(L, sim->customGravityY); + return 2; + } + else if (acount == 1) + { + sim->customGravityX = 0.0f; + sim->customGravityY = luaL_optnumber(L, 1, 0.0f); + return 0; + } + sim->customGravityX = luaL_optnumber(L, 1, 0.0f); + sim->customGravityY = luaL_optnumber(L, 2, 0.0f); + return 0; +} + +static int airMode(lua_State *L) +{ + auto *lsi = static_cast(commandInterface); + int acount = lua_gettop(L); + if (acount == 0) + { + lua_pushnumber(L, lsi->sim->air->airMode); + return 1; + } + int airMode = luaL_optint(L, 1, AIR_ON); + lsi->sim->air->airMode = airMode; + return 0; +} + +static int waterEqualization(lua_State *L) +{ + auto *lsi = static_cast(commandInterface); + int acount = lua_gettop(L); + if (acount == 0) + { + lua_pushnumber(L, lsi->sim->water_equal_test); + return 1; + } + int waterMode = luaL_optint(L, 1, 0); + lsi->sim->water_equal_test = waterMode; + return 0; +} + +static int ambientAirTemp(lua_State *L) +{ + auto *lsi = static_cast(commandInterface); + int acount = lua_gettop(L); + if (acount == 0) + { + lua_pushnumber(L, lsi->sim->air->ambientAirTemp); + return 1; + } + float ambientAirTemp = restrict_flt(luaL_optnumber(L, 1, R_TEMP + 273.15f), MIN_TEMP, MAX_TEMP); + lsi->gameModel->SetAmbientAirTemperature(ambientAirTemp); + return 0; +} + +static int elementCount(lua_State *L) +{ + int element = luaL_optint(L, 1, 0); + if (element < 0 || element >= PT_NUM) + return luaL_error(L, "Invalid element ID (%d)", element); + + auto *lsi = static_cast(commandInterface); + lua_pushnumber(L, lsi->sim->elementCount[element]); + return 1; +} + +static int canMove(lua_State *L) +{ + auto *lsi = static_cast(commandInterface); + int movingElement = luaL_checkint(L, 1); + int destinationElement = luaL_checkint(L, 2); + if (movingElement < 0 || movingElement >= PT_NUM) + return luaL_error(L, "Invalid element ID (%d)", movingElement); + if (destinationElement < 0 || destinationElement >= PT_NUM) + return luaL_error(L, "Invalid element ID (%d)", destinationElement); + + if (lua_gettop(L) < 3) + { + auto &sd = SimulationData::CRef(); + lua_pushnumber(L, sd.can_move[movingElement][destinationElement]); + return 1; + } + else + { + int setting = luaL_checkint(L, 3) & 0x7F; + lsi->customCanMove[movingElement][destinationElement] = setting | 0x80; + auto &sd = SimulationData::Ref(); + sd.can_move[movingElement][destinationElement] = setting; + return 0; + } +} + +static int brushClosure(lua_State *L) +{ + // see Simulation::ToolBrush + int positionX = lua_tointeger(L, lua_upvalueindex(1)); + int positionY = lua_tointeger(L, lua_upvalueindex(2)); + int i = lua_tointeger(L, lua_upvalueindex(3)); + int size = lua_tointeger(L, lua_upvalueindex(4)); + auto points = reinterpret_cast(lua_touserdata(L, lua_upvalueindex(5))); + + if (i == size) + return 0; + + lua_pushnumber(L, i + 1); + lua_replace(L, lua_upvalueindex(3)); + + lua_pushnumber(L, points[i].X + positionX); + lua_pushnumber(L, points[i].Y + positionY); + return 2; +} + +static int brush(lua_State *L) +{ + auto *lsi = static_cast(commandInterface); + int argCount = lua_gettop(L); + int positionX = luaL_checkint(L, 1); + int positionY = luaL_checkint(L, 2); + int brushradiusX, brushradiusY; + if (argCount >= 4) + { + brushradiusX = luaL_checkint(L, 3); + brushradiusY = luaL_checkint(L, 4); + } + else + { + ui::Point radius = lsi->gameModel->GetBrush().GetRadius(); + brushradiusX = radius.X; + brushradiusY = radius.Y; + } + int brushID = luaL_optint(L, 5, lsi->gameModel->GetBrushID()); + + Brush *brush = lsi->gameModel->GetBrushByID(brushID); + if (!brush) + return luaL_error(L, "Invalid brush id '%d'", brushID); + auto newBrush = brush->Clone(); + newBrush->SetRadius(ui::Point(brushradiusX, brushradiusY)); + lua_pushnumber(L, positionX); + lua_pushnumber(L, positionY); + std::vector points; + std::copy(newBrush->begin(), newBrush->end(), std::back_inserter(points)); + lua_pushnumber(L, 0); // index + lua_pushnumber(L, int(points.size())); + auto points_ud = reinterpret_cast(lua_newuserdata(L, points.size() * sizeof(ui::Point))); + std::copy(points.begin(), points.end(), points_ud); + + lua_pushcclosure(L, brushClosure, 5); + return 1; +} + +static int partsClosure(lua_State *L) +{ + auto *lsi = static_cast(commandInterface); + for (int i = lua_tointeger(L, lua_upvalueindex(1)); i <= lsi->sim->parts_lastActiveIndex; ++i) + { + if (lsi->sim->parts[i].type) + { + lua_pushnumber(L, i + 1); + lua_replace(L, lua_upvalueindex(1)); + lua_pushnumber(L, i); + return 1; + } + } + return 0; +} + +static int neighboursClosure(lua_State *L) +{ + auto *lsi = static_cast(commandInterface); + int cx = lua_tointeger(L, lua_upvalueindex(1)); + int cy = lua_tointeger(L, lua_upvalueindex(2)); + int rx = lua_tointeger(L, lua_upvalueindex(3)); + int ry = lua_tointeger(L, lua_upvalueindex(4)); + int t = lua_tointeger(L, lua_upvalueindex(5)); + int x = lua_tointeger(L, lua_upvalueindex(6)); + int y = lua_tointeger(L, lua_upvalueindex(7)); + while (y <= cy + ry) + { + int px = x; + int py = y; + x += 1; + if (x > cx + rx) + { + x = cx - rx; + y += 1; + } + int r = lsi->sim->pmap[py][px]; + if (!(r && (!t || TYP(r) == t))) // * If not [exists and is of the correct type] + { + r = 0; + } + if (!r) + { + r = lsi->sim->photons[py][px]; + if (!(r && (!t || TYP(r) == t))) // * If not [exists and is of the correct type] + { + r = 0; + } + } + if (cx == px && cy == py) + { + r = 0; + } + if (r) + { + lua_pushnumber(L, x); + lua_replace(L, lua_upvalueindex(6)); + lua_pushnumber(L, y); + lua_replace(L, lua_upvalueindex(7)); + lua_pushnumber(L, ID(r)); + lua_pushnumber(L, px); + lua_pushnumber(L, py); + return 3; + } + } + return 0; +} + +static int neighbors(lua_State *L) +{ + int cx = luaL_checkint(L, 1); + int cy = luaL_checkint(L, 2); + int rx = luaL_optint(L, 3, 2); + int ry = luaL_optint(L, 4, 2); + int t = luaL_optint(L, 5, PT_NONE); + if (rx < 0 || ry < 0) + { + luaL_error(L, "Invalid radius"); + } + lua_pushnumber(L, cx); + lua_pushnumber(L, cy); + lua_pushnumber(L, rx); + lua_pushnumber(L, ry); + lua_pushnumber(L, t); + lua_pushnumber(L, cx - rx); + lua_pushnumber(L, cy - ry); + lua_pushcclosure(L, neighboursClosure, 7); + return 1; +} + +static int parts(lua_State *L) +{ + lua_pushnumber(L, 0); + lua_pushcclosure(L, partsClosure, 1); + return 1; +} + +static int pmap(lua_State *L) +{ + auto *lsi = static_cast(commandInterface); + int x = luaL_checkint(L, 1); + int y = luaL_checkint(L, 2); + if (x < 0 || x >= XRES || y < 0 || y >= YRES) + return luaL_error(L, "coordinates out of range (%d,%d)", x, y); + int r = lsi->sim->pmap[y][x]; + if (!TYP(r)) + return 0; + lua_pushnumber(L, ID(r)); + return 1; +} + +static int photons(lua_State *L) +{ + auto *lsi = static_cast(commandInterface); + int x = luaL_checkint(L, 1); + int y = luaL_checkint(L, 2); + if (x < 0 || x >= XRES || y < 0 || y >= YRES) + return luaL_error(L, "coordinates out of range (%d,%d)", x, y); + int r = lsi->sim->photons[y][x]; + if (!TYP(r)) + return 0; + lua_pushnumber(L, ID(r)); + return 1; +} + +static int frameRender(lua_State *L) +{ + auto *lsi = static_cast(commandInterface); + if (lua_gettop(L) == 0) + { + lua_pushinteger(L, lsi->sim->framerender); + return 1; + } + int frames = luaL_checkinteger(L, 1); + if (frames < 0) + return luaL_error(L, "Can't simulate a negative number of frames"); + lsi->sim->framerender = frames; + return 0; +} + +static int golSpeedRatio(lua_State *L) +{ + auto *lsi = static_cast(commandInterface); + if (lua_gettop(L) == 0) + { + lua_pushinteger(L, lsi->sim->GSPEED); + return 1; + } + int gspeed = luaL_checkinteger(L, 1); + if (gspeed < 1) + return luaL_error(L, "GSPEED must be at least 1"); + lsi->sim->GSPEED = gspeed; + return 0; +} + +static int takeSnapshot(lua_State *L) +{ + auto *lsi = static_cast(commandInterface); + lsi->gameController->HistorySnapshot(); + return 0; +} + + +static int historyRestore(lua_State *L) +{ + auto *lsi = static_cast(commandInterface); + bool successful = lsi->gameController->HistoryRestore(); + lua_pushboolean(L, successful); + return 1; +} + +static int historyForward(lua_State *L) +{ + auto *lsi = static_cast(commandInterface); + bool successful = lsi->gameController->HistoryForward(); + lua_pushboolean(L, successful); + return 1; +} + +static int replaceModeFlags(lua_State *L) +{ + auto *lsi = static_cast(commandInterface); + if (lua_gettop(L) == 0) + { + lua_pushinteger(L, lsi->gameController->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"); + lsi->gameController->SetReplaceModeFlags(flags); + return 0; +} + +static int listCustomGol(lua_State *L) +{ + auto &sd = SimulationData::CRef(); + int i = 0; + lua_newtable(L); + for (auto &cgol : sd.GetCustomGol()) + { + lua_newtable(L); + tpt_lua_pushString(L, cgol.nameString); + lua_setfield(L, -2, "name"); + tpt_lua_pushString(L, cgol.ruleString); + 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; +} + +static int addCustomGol(lua_State *L) +{ + auto &sd = SimulationData::CRef(); + int rule; + String ruleString; + if (lua_isnumber(L, 1)) + { + rule = luaL_checkinteger(L, 1); + ruleString = SerialiseGOLRule(rule); + rule = ParseGOLString(ruleString); + } + else + { + ruleString = tpt_lua_checkString(L, 1); + rule = ParseGOLString(ruleString); + } + String nameString = tpt_lua_checkString(L, 2); + 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 (sd.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"); + auto *lsi = static_cast(commandInterface); + lsi->gameModel->BuildMenus(); + return 0; +} + +static int removeCustomGol(lua_State *L) +{ + auto *lsi = static_cast(commandInterface); + ByteString nameString = tpt_lua_checkByteString(L, 1); + bool removedAny = lsi->gameModel->RemoveCustomGOLType("DEFAULT_PT_LIFECUST_" + nameString); + if (removedAny) + lsi->gameModel->BuildMenus(); + lua_pushboolean(L, removedAny); + return 1; +} + +static int lastUpdatedID(lua_State *L) +{ + auto *lsi = static_cast(commandInterface); + if (lsi->sim->debug_mostRecentlyUpdated != -1) + { + lua_pushinteger(L, lsi->sim->debug_mostRecentlyUpdated); + } + else + { + lua_pushnil(L); + } + return 1; +} + +static int updateUpTo(lua_State *L) +{ + // sim.updateUpTo dispatches an update to the range [current, upTo], but GameModel::UpdateUpTo takes a range [current, upTo). + // As a result, upTo here will be one smaller than it's logical for the duration of this function. + int upTo = NPART - 1; + if (lua_gettop(L) > 0) + { + upTo = luaL_checkinteger(L, 1); + } + if (upTo < -1 || upTo >= NPART) // -1 instead of 0 to allow for the empty range [0, -1] aka [0, 0) + { + return luaL_error(L, "ID not in valid range"); + } + auto *lsi = static_cast(commandInterface); + lsi->sim->framerender = 1; + lsi->gameModel->UpdateUpTo(upTo + 1); + return 0; +} + +static int temperatureScale(lua_State *L) +{ + auto *lsi = static_cast(commandInterface); + if (lua_gettop(L) == 0) + { + lua_pushinteger(L, lsi->gameModel->GetTemperatureScale()); + return 1; + } + int temperatureScale = luaL_checkinteger(L, 1); + if (temperatureScale < 0 || temperatureScale > 2) + return luaL_error(L, "Invalid temperature scale"); + lsi->gameModel->SetTemperatureScale(temperatureScale); + return 0; +} + +static int signsIndex(lua_State *L) +{ + ByteString key = tpt_lua_checkByteString(L, 2); + + //Get Raw Index value for element. Maybe there is a way to get the sign index some other way? + lua_pushliteral(L, "id"); + lua_rawget(L, 1); + int id = lua_tointeger(L, lua_gettop(L))-1; + + if (id < 0 || id >= MAXSIGNS) + { + luaL_error(L, "Invalid sign ID (stop messing with things): %i", id); + return 0; + } + auto *lsi = static_cast(commandInterface); + auto *sim = lsi->sim; + if (id >= (int)sim->signs.size()) + { + return lua_pushnil(L), 1; + } + + int x, y, w, h; + if (byteStringEqualsLiteral(key, "text")) + return tpt_lua_pushString(L, sim->signs[id].text), 1; + else if (byteStringEqualsLiteral(key, "displayText")) + return tpt_lua_pushString(L, sim->signs[id].getDisplayText(sim, x, y, w, h, false)), 1; + else if (byteStringEqualsLiteral(key, "justification")) + return lua_pushnumber(L, (int)sim->signs[id].ju), 1; + else if (byteStringEqualsLiteral(key, "x")) + return lua_pushnumber(L, sim->signs[id].x), 1; + else if (byteStringEqualsLiteral(key, "y")) + return lua_pushnumber(L, sim->signs[id].y), 1; + else if (byteStringEqualsLiteral(key, "screenX")) + { + sim->signs[id].getDisplayText(sim, x, y, w, h); + lua_pushnumber(L, x); + return 1; + } + else if (byteStringEqualsLiteral(key, "screenY")) + { + sim->signs[id].getDisplayText(sim, x, y, w, h); + lua_pushnumber(L, y); + return 1; + } + else if (byteStringEqualsLiteral(key, "width")) + { + sim->signs[id].getDisplayText(sim, x, y, w, h); + lua_pushnumber(L, w); + return 1; + } + else if (byteStringEqualsLiteral(key, "height")) + { + sim->signs[id].getDisplayText(sim, x, y, w, h); + lua_pushnumber(L, h); + return 1; + } + else + return lua_pushnil(L), 1; +} + +static int signsNewIndex(lua_State *L) +{ + auto *lsi = static_cast(commandInterface); + auto *sim = lsi->sim; + ByteString key = tpt_lua_checkByteString(L, 2); + + //Get Raw Index value for element. Maybe there is a way to get the sign index some other way? + lua_pushliteral(L, "id"); + lua_rawget(L, 1); + int id = lua_tointeger(L, lua_gettop(L))-1; + + if (id < 0 || id >= MAXSIGNS) + { + luaL_error(L, "Invalid sign ID (stop messing with things)"); + return 0; + } + if (id >= (int)sim->signs.size()) + { + luaL_error(L, "Sign doesn't exist"); + } + + if (byteStringEqualsLiteral(key, "text")) + { + auto temp = tpt_lua_checkString(L, 3); + String cleaned = format::CleanString(temp, false, true, true).Substr(0, 45); + if (!cleaned.empty()) + sim->signs[id].text = cleaned; + else + luaL_error(L, "Text is empty"); + return 0; + } + else if (byteStringEqualsLiteral(key, "justification")) + { + int ju = luaL_checkinteger(L, 3); + if (ju >= 0 && ju <= 3) + return sim->signs[id].ju = (sign::Justification)ju, 1; + else + luaL_error(L, "Invalid justification"); + return 0; + } + else if (byteStringEqualsLiteral(key, "x")) + { + int x = luaL_checkinteger(L, 3); + if (x >= 0 && x < XRES) + return sim->signs[id].x = x, 1; + else + luaL_error(L, "Invalid X coordinate"); + return 0; + } + else if (byteStringEqualsLiteral(key, "y")) + { + int y = luaL_checkinteger(L, 3); + if (y >= 0 && y < YRES) + return sim->signs[id].y = y, 1; + else + luaL_error(L, "Invalid Y coordinate"); + return 0; + } + else if (byteStringEqualsLiteral(key, "displayText") || + byteStringEqualsLiteral(key, "screenX") || + byteStringEqualsLiteral(key, "screenY") || + byteStringEqualsLiteral(key, "width") || + byteStringEqualsLiteral(key, "height")) + { + luaL_error(L, "That property can't be directly set"); + } + return 0; +} + +// Creates a new sign at the first open index +static int Sign_new(lua_State *L) +{ + auto *lsi = static_cast(commandInterface); + if (lsi->sim->signs.size() >= MAXSIGNS) + return lua_pushnil(L), 1; + + String text = format::CleanString(tpt_lua_checkString(L, 1), false, true, true).Substr(0, 45); + int x = luaL_checkinteger(L, 2); + int y = luaL_checkinteger(L, 3); + int ju = luaL_optinteger(L, 4, 1); + if (ju < 0 || ju > 3) + return luaL_error(L, "Invalid justification"); + if (x < 0 || x >= XRES) + return luaL_error(L, "Invalid X coordinate"); + if (y < 0 || y >= YRES) + return luaL_error(L, "Invalid Y coordinate"); + + lsi->sim->signs.push_back(sign(text, x, y, (sign::Justification)ju)); + + lua_pushinteger(L, lsi->sim->signs.size()); + return 1; +} + +// Deletes a sign +static int Sign_delete(lua_State *L) +{ + auto *lsi = static_cast(commandInterface); + int signID = luaL_checkinteger(L, 1); + if (signID <= 0 || signID > (int)lsi->sim->signs.size()) + return luaL_error(L, "Sign doesn't exist"); + + lsi->sim->signs.erase(lsi->sim->signs.begin()+signID-1); + return 1; +} + +static int resetVelocity(lua_State *L) +{ + int nx, ny; + int x1, y1, width, height; + x1 = abs(luaL_optint(L, 1, 0)); + y1 = abs(luaL_optint(L, 2, 0)); + width = abs(luaL_optint(L, 3, XCELLS)); + height = abs(luaL_optint(L, 4, YCELLS)); + if(x1 > XCELLS-1) + x1 = XCELLS-1; + if(y1 > YCELLS-1) + y1 = YCELLS-1; + if(x1+width > XCELLS-1) + width = XCELLS-x1; + if(y1+height > YCELLS-1) + height = YCELLS-y1; + auto *lsi = static_cast(commandInterface); + for (nx = x1; nxsim->vx[ny][nx] = 0; + lsi->sim->vy[ny][nx] = 0; + } + return 0; +} + +static int resetSpark(lua_State *L) +{ + auto *lsi = static_cast(commandInterface); + lsi->gameController->ResetSpark(); + return 0; +} + +static int resetGravityField(lua_State *L) +{ + int nx, ny; + int x1, y1, width, height; + x1 = abs(luaL_optint(L, 1, 0)); + y1 = abs(luaL_optint(L, 2, 0)); + width = abs(luaL_optint(L, 3, XCELLS)); + height = abs(luaL_optint(L, 4, YCELLS)); + if(x1 > XCELLS-1) + x1 = XCELLS-1; + if(y1 > YCELLS-1) + y1 = YCELLS-1; + if(x1+width > XCELLS-1) + width = XCELLS-x1; + if(y1+height > YCELLS-1) + height = YCELLS-y1; + auto *lsi = static_cast(commandInterface); + auto *sim = lsi->sim; + for (nx = x1; nxgravx[ny*XCELLS+nx] = 0; + sim->gravy[ny*XCELLS+nx] = 0; + sim->gravp[ny*XCELLS+nx] = 0; + } + return 0; +} + +static int randomSeed(lua_State *L) +{ + auto *lsi = static_cast(commandInterface); + if (lua_gettop(L)) + { + lsi->sim->rng.state({ + uint32_t(luaL_checkinteger(L, 1)) | (uint64_t(uint32_t(luaL_checkinteger(L, 2))) << 32), + uint32_t(luaL_checkinteger(L, 3)) | (uint64_t(uint32_t(luaL_checkinteger(L, 4))) << 32), + }); + return 0; + } + auto s = lsi->sim->rng.state(); + lua_pushinteger(L, s[0] & UINT32_C(0xFFFFFFFF)); + lua_pushinteger(L, (s[0] >> 32) & UINT32_C(0xFFFFFFFF)); + lua_pushinteger(L, s[1] & UINT32_C(0xFFFFFFFF)); + lua_pushinteger(L, (s[1] >> 32) & UINT32_C(0xFFFFFFFF)); + return 4; +} + +static int hash(lua_State *L) +{ + auto *lsi = static_cast(commandInterface); + lua_pushinteger(L, lsi->sim->CreateSnapshot()->Hash()); + return 1; +} + +static int ensureDeterminism(lua_State *L) +{ + auto *lsi = static_cast(commandInterface); + if (lua_gettop(L)) + { + lsi->sim->ensureDeterminism = lua_toboolean(L, 1); + return 0; + } + lua_pushboolean(L, lsi->sim->ensureDeterminism); + return 1; +} + +void LuaSimulation::Open(lua_State *L) +{ + auto *lsi = static_cast(commandInterface); + auto &sd = SimulationData::CRef(); + static const luaL_Reg reg[] = { +#define LFUNC(v) { #v, v } + LFUNC(partNeighbors), + LFUNC(partChangeType), + LFUNC(partCreate), + LFUNC(partProperty), + LFUNC(partPosition), + LFUNC(partID), + LFUNC(partKill), + LFUNC(partExists), + LFUNC(pressure), + LFUNC(ambientHeat), + LFUNC(ambientHeatSim), + LFUNC(heatSim), + LFUNC(newtonianGravity), + LFUNC(velocityX), + LFUNC(velocityY), + LFUNC(createParts), + LFUNC(createLine), + LFUNC(createBox), + LFUNC(floodParts), + LFUNC(createWalls), + LFUNC(createWallLine), + LFUNC(createWallBox), + LFUNC(floodWalls), + LFUNC(toolBrush), + LFUNC(toolLine), + LFUNC(toolBox), + LFUNC(decoBrush), + LFUNC(decoLine), + LFUNC(decoBox), + LFUNC(decoColor), + LFUNC(floodDeco), + LFUNC(clearSim), + LFUNC(clearRect), + LFUNC(resetTemp), + LFUNC(resetPressure), + LFUNC(saveStamp), + LFUNC(loadStamp), + LFUNC(deleteStamp), + LFUNC(listStamps), + LFUNC(loadSave), + LFUNC(reloadSave), + LFUNC(getSaveID), + LFUNC(adjustCoords), + LFUNC(prettyPowders), + LFUNC(gravityGrid), + LFUNC(edgeMode), + LFUNC(gravityMode), + LFUNC(customGravity), + LFUNC(airMode), + LFUNC(waterEqualization), + LFUNC(ambientAirTemp), + LFUNC(elementCount), + LFUNC(canMove), + LFUNC(brush), + LFUNC(parts), + LFUNC(pmap), + LFUNC(photons), + LFUNC(neighbors), + LFUNC(frameRender), + LFUNC(golSpeedRatio), + LFUNC(takeSnapshot), + LFUNC(historyRestore), + LFUNC(historyForward), + LFUNC(replaceModeFlags), + LFUNC(listCustomGol), + LFUNC(addCustomGol), + LFUNC(removeCustomGol), + LFUNC(lastUpdatedID), + LFUNC(updateUpTo), + LFUNC(temperatureScale), + LFUNC(randomSeed), + LFUNC(hash), + LFUNC(ensureDeterminism), + LFUNC(paused), + LFUNC(gravityMass), + LFUNC(gravityField), + LFUNC(resetGravityField), + LFUNC(resetSpark), + LFUNC(resetVelocity), + LFUNC(wallMap), + LFUNC(elecMap), + LFUNC(partCount), + LFUNC(decoSpace), + LFUNC(fanVelocityX), + LFUNC(fanVelocityY), +#undef LFUNC + { NULL, NULL } + }; + lua_newtable(L); + luaL_register(L, NULL, reg); +#define LCONST(v) lua_pushinteger(L, int(v)); lua_setfield(L, -2, #v) +#define LCONSTF(v) lua_pushnumber(L, float(v)); lua_setfield(L, -2, #v) +#define LCONSTAS(k, v) lua_pushinteger(L, int(v)); lua_setfield(L, -2, k) + LCONST(CELL); + LCONST(XCELLS); + LCONST(YCELLS); + LCONST(NCELL); + LCONST(XRES); + LCONST(YRES); + LCONST(XCNTR); + LCONST(YCNTR); + LCONSTAS("MAX_PARTS", NPART); + LCONST(NT); + LCONST(ST); + LCONSTF(ITH); + LCONSTF(ITL); + LCONSTF(IPH); + LCONSTF(IPL); + LCONST(PT_NUM); + LCONSTF(R_TEMP); + LCONSTF(MAX_TEMP); + LCONSTF(MIN_TEMP); + LCONSTF(MAX_PRESSURE); + LCONSTF(MIN_PRESSURE); + LCONST(ISTP); + LCONSTF(CFDS); + LCONSTF(MAX_VELOCITY); + LCONST(TOOL_HEAT); + LCONST(TOOL_COOL); + LCONST(TOOL_VAC); + LCONST(TOOL_PGRV); + LCONST(TOOL_AIR); + LCONST(TOOL_NGRV); + LCONST(TOOL_MIX); + LCONST(TOOL_CYCL); + LCONSTAS("TOOL_WIND", sd.tools.size()); + LCONST(DECO_DRAW); + LCONST(DECO_CLEAR); + LCONST(DECO_ADD); + LCONST(DECO_SUBTRACT); + LCONST(DECO_MULTIPLY); + LCONST(DECO_DIVIDE); + LCONST(DECO_SMUDGE); + LCONST(FLAG_STAGNANT); + LCONST(FLAG_SKIPMOVE); + LCONST(FLAG_MOVABLE); + LCONST(FLAG_PHOTDECO); + LCONST(PMAPBITS); + LCONST(PMAPMASK); + LCONST(BRUSH_CIRCLE); + LCONST(BRUSH_SQUARE); + LCONST(BRUSH_TRIANGLE); + LCONST(NUM_DEFAULTBRUSHES); + LCONSTAS("NUM_BRUSHES", lsi->gameModel->BrushListSize()); + LCONST(EDGE_VOID); + LCONST(EDGE_SOLID); + LCONST(EDGE_LOOP); + LCONST(NUM_EDGEMODES); + LCONST(AIR_ON); + LCONST(AIR_PRESSUREOFF); + LCONST(AIR_VELOCITYOFF); + LCONST(AIR_OFF); + LCONST(AIR_NOUPDATE); + LCONST(NUM_AIRMODES); + LCONST(GRAV_VERTICAL); + LCONST(GRAV_OFF); + LCONST(GRAV_RADIAL); + LCONST(GRAV_CUSTOM); + LCONST(NUM_GRAVMODES); + { + lua_newtable(L); + for (int i = 0; i < UI_WALLCOUNT; i++) + { + tpt_lua_pushByteString(L, sd.wtypes[i].identifier); + lua_pushinteger(L, i); + lua_settable(L, -3); + lua_pushinteger(L, i); + tpt_lua_pushByteString(L, sd.wtypes[i].identifier); + lua_settable(L, -3); + } + lua_setfield(L, -2, "walls"); + LCONSTAS("NUM_WALLS", UI_WALLCOUNT); + } +#undef LCONSTAS +#undef LCONSTF +#undef LCONST + { + int particlePropertiesCount = 0; + for (auto &prop : Particle::GetProperties()) + { + tpt_lua_pushByteString(L, "FIELD_" + prop.Name.ToUpper()); + lua_pushinteger(L, particlePropertiesCount++); + lua_settable(L, -3); + } + for (auto &alias : Particle::GetPropertyAliases()) + { + tpt_lua_pushByteString(L, "FIELD_" + alias.from.ToUpper()); + tpt_lua_pushByteString(L, "FIELD_" + alias.to.ToUpper()); + lua_gettable(L, -3); + lua_settable(L, -3); + } + } + { + lua_newtable(L); + for (int i = 1; i <= MAXSIGNS; i++) + { + lua_newtable(L); + lua_pushinteger(L, i); //set "id" to table index + lua_setfield(L, -2, "id"); + lua_newtable(L); + lua_pushcfunction(L, signsIndex); + lua_setfield(L, -2, "__index"); + lua_pushcfunction(L, signsNewIndex); + lua_setfield(L, -2, "__newindex"); + lua_setmetatable(L, -2); + lua_pushinteger(L, i); //table index + lua_insert(L, -2); //swap k and v + lua_settable(L, -3); //set metatable to signs[i] + } + lua_pushcfunction(L, Sign_new); + lua_setfield(L, -2, "new"); + lua_pushcfunction(L, Sign_delete); + lua_setfield(L, -2, "delete"); + lua_setfield(L, -2, "signs"); + } + lua_pushvalue(L, -1); + lua_setglobal(L, "simulation"); + lua_setglobal(L, "sim"); +} diff --git a/src/lua/LuaSlider.cpp b/src/lua/LuaSlider.cpp index ac48d0bd6..df4252743 100644 --- a/src/lua/LuaSlider.cpp +++ b/src/lua/LuaSlider.cpp @@ -15,51 +15,51 @@ Luna::RegType LuaSlider::methods[] = { {0, 0} }; -LuaSlider::LuaSlider(lua_State * l) : - LuaComponent(l) +LuaSlider::LuaSlider(lua_State *L) : + LuaComponent(L) { - int posX = luaL_optinteger(l, 1, 0); - int posY = luaL_optinteger(l, 2, 0); - int sizeX = luaL_optinteger(l, 3, 10); - int sizeY = luaL_optinteger(l, 4, 10); - int steps = luaL_optinteger(l, 5, 10); + int posX = luaL_optinteger(L, 1, 0); + int posY = luaL_optinteger(L, 2, 0); + int sizeX = luaL_optinteger(L, 3, 10); + int sizeY = luaL_optinteger(L, 4, 10); + int steps = luaL_optinteger(L, 5, 10); slider = new ui::Slider(ui::Point(posX, posY), ui::Point(sizeX, sizeY), steps); component = slider; slider->SetActionCallback({ [this] { triggerOnValueChanged(); } }); } -int LuaSlider::steps(lua_State * l) +int LuaSlider::steps(lua_State *L) { - int args = lua_gettop(l); + int args = lua_gettop(L); if(args) { - slider->SetSteps(lua_tointeger(l, 1)); + slider->SetSteps(lua_tointeger(L, 1)); return 0; } else { - lua_pushinteger(l, slider->GetSteps()); + lua_pushinteger(L, slider->GetSteps()); return 1; } } -int LuaSlider::onValueChanged(lua_State * l) +int LuaSlider::onValueChanged(lua_State *L) { - return onValueChangedFunction.CheckAndAssignArg1(l); + return onValueChangedFunction.CheckAndAssignArg1(L); } -int LuaSlider::value(lua_State * l) +int LuaSlider::value(lua_State *L) { - int args = lua_gettop(l); + int args = lua_gettop(L); if(args) { - slider->SetValue(lua_tointeger(l, 1)); + slider->SetValue(lua_tointeger(L, 1)); return 0; } else { - lua_pushinteger(l, slider->GetValue()); + lua_pushinteger(L, slider->GetValue()); return 1; } } @@ -68,12 +68,12 @@ void LuaSlider::triggerOnValueChanged() { if(onValueChangedFunction) { - lua_rawgeti(l, LUA_REGISTRYINDEX, onValueChangedFunction); - lua_rawgeti(l, LUA_REGISTRYINDEX, owner_ref); - lua_pushinteger(l, slider->GetValue()); - if (tpt_lua_pcall(l, 2, 0, 0, eventTraitNone)) + lua_rawgeti(L, LUA_REGISTRYINDEX, onValueChangedFunction); + lua_rawgeti(L, LUA_REGISTRYINDEX, owner_ref); + lua_pushinteger(L, slider->GetValue()); + if (tpt_lua_pcall(L, 2, 0, 0, eventTraitNone)) { - ci->Log(CommandInterface::LogError, tpt_lua_toString(l, -1)); + ci->Log(CommandInterface::LogError, tpt_lua_toString(L, -1)); } } } diff --git a/src/lua/LuaSlider.h b/src/lua/LuaSlider.h index caa20a340..34a075f28 100644 --- a/src/lua/LuaSlider.h +++ b/src/lua/LuaSlider.h @@ -15,13 +15,13 @@ class LuaSlider: public LuaComponent ui::Slider * slider; LuaComponentCallback onValueChangedFunction; void triggerOnValueChanged(); - int onValueChanged(lua_State * l); - int steps(lua_State * l); - int value(lua_State * l); + int onValueChanged(lua_State *L); + int steps(lua_State *L); + int value(lua_State *L); public: static const char className[]; static Luna::RegType methods[]; - LuaSlider(lua_State * l); + LuaSlider(lua_State *L); ~LuaSlider(); }; diff --git a/src/lua/LuaSmartRef.cpp b/src/lua/LuaSmartRef.cpp index 36254b3c3..a907c81f5 100644 --- a/src/lua/LuaSmartRef.cpp +++ b/src/lua/LuaSmartRef.cpp @@ -3,10 +3,10 @@ void LuaSmartRef::Clear() { - auto *luacon_ci = static_cast(commandInterface); - if (luacon_ci) + auto *lsi = static_cast(commandInterface); + if (lsi) { - luaL_unref(luacon_ci->l, LUA_REGISTRYINDEX, ref); + luaL_unref(lsi->L, LUA_REGISTRYINDEX, ref); ref = LUA_REFNIL; } } @@ -16,19 +16,19 @@ LuaSmartRef::~LuaSmartRef() Clear(); } -void LuaSmartRef::Assign(lua_State *l, int index) +void LuaSmartRef::Assign(lua_State *L, int index) { if (index < 0) { - index = lua_gettop(l) + index + 1; + index = lua_gettop(L) + index + 1; } Clear(); - lua_pushvalue(l, index); - ref = luaL_ref(l, LUA_REGISTRYINDEX); + lua_pushvalue(L, index); + ref = luaL_ref(L, LUA_REGISTRYINDEX); } -int LuaSmartRef::Push(lua_State *l) +int LuaSmartRef::Push(lua_State *L) { - lua_rawgeti(l, LUA_REGISTRYINDEX, ref); - return lua_type(l, -1); + lua_rawgeti(L, LUA_REGISTRYINDEX, ref); + return lua_type(L, -1); } diff --git a/src/lua/LuaSmartRef.h b/src/lua/LuaSmartRef.h index 96cfbbaf1..b00c455c0 100644 --- a/src/lua/LuaSmartRef.h +++ b/src/lua/LuaSmartRef.h @@ -7,9 +7,9 @@ class LuaSmartRef public: ~LuaSmartRef(); - void Assign(lua_State *l, int index); // Copies the value before getting reference, stack unchanged. + void Assign(lua_State *L, int index); // Copies the value before getting reference, stack unchanged. void Clear(); - int Push(lua_State *l); // Always pushes exactly one value, possibly nil. + int Push(lua_State *L); // Always pushes exactly one value, possibly nil. inline operator int() const { diff --git a/src/lua/LuaSocket.cpp b/src/lua/LuaSocket.cpp index 2b58b49f8..a6f44002c 100644 --- a/src/lua/LuaSocket.cpp +++ b/src/lua/LuaSocket.cpp @@ -1,33 +1,27 @@ -#include "LuaSocket.h" #include "LuaScriptInterface.h" #include "Misc.h" -#include -#include -namespace LuaSocket +int LuaSocket::GetTime(lua_State *L) { - static int GetTime(lua_State *l) - { - lua_pushnumber(l, Now()); - return 1; - } - - static int Sleep(lua_State *l) - { - Timeout(luaL_checknumber(l, 1)); - return 0; - } - - void Open(lua_State *l) - { - lua_newtable(l); - struct luaL_Reg socketMethods[] = { - { "sleep", LuaSocket::Sleep }, - { "getTime", LuaSocket::GetTime }, - { NULL, NULL }, - }; - luaL_register(l, NULL, socketMethods); - lua_setglobal(l, "socket"); - OpenTCP(l); - } + lua_pushnumber(L, LuaSocket::Now()); + return 1; +} + +int LuaSocket::Sleep(lua_State *L) +{ + LuaSocket::Timeout(luaL_checknumber(L, 1)); + return 0; +} + +void LuaSocket::Open(lua_State *L) +{ + static const luaL_Reg reg[] = { + { "sleep", LuaSocket::Sleep }, + { "getTime", LuaSocket::GetTime }, + { NULL, NULL } + }; + lua_newtable(L); + luaL_register(L, NULL, reg); + lua_setglobal(L, "socket"); + OpenTCP(L); } diff --git a/src/lua/LuaSocket.h b/src/lua/LuaSocket.h deleted file mode 100644 index b0be94116..000000000 --- a/src/lua/LuaSocket.h +++ /dev/null @@ -1,10 +0,0 @@ -#pragma once -#include "LuaCompat.h" - -namespace LuaSocket -{ - double Now(); - void Timeout(double timeout); - void Open(lua_State *l); - void OpenTCP(lua_State *l); -} diff --git a/src/lua/LuaSocketDefault.cpp b/src/lua/LuaSocketDefault.cpp index 6c4723425..43385166a 100644 --- a/src/lua/LuaSocketDefault.cpp +++ b/src/lua/LuaSocketDefault.cpp @@ -1,4 +1,3 @@ -#include "LuaSocket.h" #include "LuaScriptInterface.h" #include "Misc.h" #include diff --git a/src/lua/LuaSocketTCPHttp.cpp b/src/lua/LuaSocketTCPHttp.cpp index 3c58c0de1..176b2f0e6 100644 --- a/src/lua/LuaSocketTCPHttp.cpp +++ b/src/lua/LuaSocketTCPHttp.cpp @@ -1,5 +1,7 @@ -#include "LuaSocket.h" - +#include "LuaScriptInterface.h" +#include "client/http/requestmanager/CurlError.h" +#include "client/http/requestmanager/RequestManager.h" +#include "Misc.h" #include "common/String.h" #include #include @@ -8,11 +10,6 @@ #include #include -#include "LuaScriptInterface.h" -#include "client/http/requestmanager/RequestManager.h" -#include "client/http/requestmanager/CurlError.h" -#include "Misc.h" - namespace LuaSocket { enum Status @@ -80,14 +77,14 @@ namespace LuaSocket return false; } - static int New(lua_State *l) + static int New(lua_State *L) { using http::HandleCURLMcode; if (http::RequestManager::Ref().DisableNetwork()) { - return luaL_error(l, "network disabled"); + return luaL_error(L, "network disabled"); } - auto *tcps = (TCPSocket *)lua_newuserdata(l, sizeof(TCPSocket)); + auto *tcps = (TCPSocket *)lua_newuserdata(L, sizeof(TCPSocket)); new(tcps) TCPSocket; tcps->errorBuf[0] = 0; tcps->easy = curl_easy_init(); @@ -100,47 +97,47 @@ namespace LuaSocket if (!tcps->easy) { Reset(tcps); - return luaL_error(l, "curl_easy_init failed"); + return luaL_error(L, "curl_easy_init failed"); } tcps->multi = curl_multi_init(); if (!tcps->multi) { Reset(tcps); - return luaL_error(l, "curl_multi_init failed"); + return luaL_error(L, "curl_multi_init failed"); } HandleCURLMcode(curl_multi_add_handle(tcps->multi, tcps->easy)); - luaL_newmetatable(l, "TCPSocket"); - lua_setmetatable(l, -2); + luaL_newmetatable(L, "TCPSocket"); + lua_setmetatable(L, -2); return 1; } - static int GC(lua_State *l) + static int GC(lua_State *L) { - auto *tcps = (TCPSocket *)luaL_checkudata(l, 1, "TCPSocket"); + auto *tcps = (TCPSocket *)luaL_checkudata(L, 1, "TCPSocket"); Reset(tcps); tcps->~TCPSocket(); return 0; } - static int Close(lua_State *l) + static int Close(lua_State *L) { - auto *tcps = (TCPSocket *)luaL_checkudata(l, 1, "TCPSocket"); + auto *tcps = (TCPSocket *)luaL_checkudata(L, 1, "TCPSocket"); Reset(tcps); return 0; } - static int Send(lua_State *l) + static int Send(lua_State *L) { - auto *tcps = (TCPSocket *)luaL_checkudata(l, 1, "TCPSocket"); + auto *tcps = (TCPSocket *)luaL_checkudata(L, 1, "TCPSocket"); if (tcps->status != StatusConnected) { - return luaL_error(l, "attempt to send on socket while not connected"); + return luaL_error(L, "attempt to send on socket while not connected"); } size_t dlenu; - auto *data = luaL_checklstring(l, 2, &dlenu); + auto *data = luaL_checklstring(L, 2, &dlenu); auto dlen = int(dlenu); - auto first = luaL_optinteger(l, 3, 1); - auto last = luaL_optinteger(l, 4, -1); + auto first = luaL_optinteger(L, 3, 1); + auto last = luaL_optinteger(L, 4, -1); if (first < 0) first += dlen + 1; if (last < 0) last += dlen + 1; if (first < 1) first = 1; @@ -179,9 +176,9 @@ namespace LuaSocket if (tcps->writeClosed) { Reset(tcps); - lua_pushnil(l); - lua_pushliteral(l, "closed"); - lua_pushinteger(l, writtenTotal + begin); + lua_pushnil(L); + lua_pushliteral(L, "closed"); + lua_pushinteger(L, writtenTotal + begin); return 3; } if (res == CURLE_AGAIN) @@ -194,22 +191,22 @@ namespace LuaSocket Timeout(0.01); continue; } - lua_pushnil(l); - lua_pushliteral(l, "timeout"); - lua_pushinteger(l, writtenTotal + begin); + lua_pushnil(L); + lua_pushliteral(L, "timeout"); + lua_pushinteger(L, writtenTotal + begin); return 3; } } - lua_pushinteger(l, writtenTotal + begin); + lua_pushinteger(L, writtenTotal + begin); return 1; } - static int ReceiveNoPrefix(lua_State *l) + static int ReceiveNoPrefix(lua_State *L) { - auto *tcps = (TCPSocket *)luaL_checkudata(l, 1, "TCPSocket"); + auto *tcps = (TCPSocket *)luaL_checkudata(L, 1, "TCPSocket"); if (tcps->status != StatusConnected) { - return luaL_error(l, "attempt to receive on socket while not connected"); + return luaL_error(L, "attempt to receive on socket while not connected"); } enum { @@ -218,17 +215,17 @@ namespace LuaSocket readLine, } pattern = readN; size_t len = 4096; - if (tpt_lua_equalsLiteral(l, 2, "*a")) + if (tpt_lua_equalsLiteral(L, 2, "*a")) { pattern = readAll; } - else if (tpt_lua_equalsLiteral(l, 2, "*l")) + else if (tpt_lua_equalsLiteral(L, 2, "*L")) { pattern = readLine; } else { - len = size_t(luaL_checkinteger(l, 2)); + len = size_t(luaL_checkinteger(L, 2)); } if (pattern == readAll || pattern == readLine) { @@ -303,11 +300,11 @@ namespace LuaSocket // * Closed "*a" patterns don't return an error. break; } - lua_pushnil(l); - lua_pushliteral(l, "closed"); + lua_pushnil(L); + lua_pushliteral(L, "closed"); if (pattern == readLine) { - // * Closed "*l" patterns don't return partial lines. + // * Closed "*L" patterns don't return partial lines. returning = 0; } retn = 3; @@ -331,11 +328,11 @@ namespace LuaSocket Timeout(0.01); continue; } - lua_pushnil(l); - lua_pushliteral(l, "timeout"); + lua_pushnil(L); + lua_pushliteral(L, "timeout"); if (pattern == readLine) { - // * Timed-out "*l" patterns don't return partial lines. + // * Timed-out "*L" patterns don't return partial lines. returning = 0; } retn = 3; @@ -356,12 +353,12 @@ namespace LuaSocket } returning = curOut; } - lua_pushlstring(l, &tcps->recvBuf[0], returning); + lua_pushlstring(L, &tcps->recvBuf[0], returning); // * This copy makes ReceiveNoPrefix quadratic if there's a lot of stuff in - // the stash (as a result of a *very* long line being returned by an "*l" + // the stash (as a result of a *very* long line being returned by an "*L" // pattern and then whatever was left being stashed) and it's all *very* // short lines (compared to the previous *very* long one, from the point - // of view of an "*l" pattern). Handling this edge case in a special, + // of view of an "*L" pattern). Handling this edge case in a special, // sub-quadratic way isn't worth the effort. std::copy( &tcps->recvBuf[0] + readTotal - tcps->stashedLen, @@ -371,35 +368,35 @@ namespace LuaSocket return retn; } - static int Receive(lua_State *l) + static int Receive(lua_State *L) { bool prefix = false; - if (lua_gettop(l) >= 3) + if (lua_gettop(L) >= 3) { prefix = true; - lua_tostring(l, 3); + lua_tostring(L, 3); } - int ret = ReceiveNoPrefix(l); + int ret = ReceiveNoPrefix(L); if (prefix) { - lua_pushvalue(l, 3); - lua_insert(l, -2); - lua_concat(l, 2); + lua_pushvalue(L, 3); + lua_insert(L, -2); + lua_concat(L, 2); } return ret; } - static int Connect(lua_State *l) + static int Connect(lua_State *L) { using http::HandleCURLcode; - auto *tcps = (TCPSocket *)luaL_checkudata(l, 1, "TCPSocket"); + auto *tcps = (TCPSocket *)luaL_checkudata(L, 1, "TCPSocket"); if (tcps->status == StatusDead) { - return luaL_error(l, "attempt to connect dead socket"); + return luaL_error(L, "attempt to connect dead socket"); } if (tcps->status == StatusConnected) { - return luaL_error(l, "attempt to connect connected socket"); + return luaL_error(L, "attempt to connect connected socket"); } auto startedAt = Now(); while (true) @@ -416,11 +413,11 @@ namespace LuaSocket // the hostnames. HandleCURLcode(curl_easy_setopt(tcps->easy, CURLOPT_ERRORBUFFER, tcps->errorBuf)); HandleCURLcode(curl_easy_setopt(tcps->easy, CURLOPT_CONNECT_ONLY, 1L)); - ByteString address = tpt_lua_checkByteString(l, 2); - HandleCURLcode(curl_easy_setopt(tcps->easy, CURLOPT_PORT, long(luaL_checkinteger(l, 3)))); + ByteString address = tpt_lua_checkByteString(L, 2); + HandleCURLcode(curl_easy_setopt(tcps->easy, CURLOPT_PORT, long(luaL_checkinteger(L, 3)))); HandleCURLcode(curl_easy_setopt(tcps->easy, CURLOPT_NOSIGNAL, 1L)); HandleCURLcode(curl_easy_setopt(tcps->easy, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0)); - if (lua_toboolean(l, 4)) + if (lua_toboolean(L, 4)) { #if defined(CURL_AT_LEAST_VERSION) && CURL_AT_LEAST_VERSION(7, 85, 0) HandleCURLcode(curl_easy_setopt(tcps->easy, CURLOPT_PROTOCOLS_STR, "https")); @@ -447,7 +444,7 @@ namespace LuaSocket } catch (const http::CurlError &ex) { - return luaL_error(l, ex.what()); + return luaL_error(L, ex.what()); } } @@ -462,73 +459,73 @@ namespace LuaSocket Timeout(0.01); continue; } - lua_pushnil(l); - lua_pushliteral(l, "timeout"); + lua_pushnil(L); + lua_pushliteral(L, "timeout"); return 2; } if (res != CURLE_OK) { Reset(tcps); - lua_pushnil(l); - lua_pushstring(l, tcps->errorBuf); + lua_pushnil(L); + lua_pushstring(L, tcps->errorBuf); return 2; } break; } tcps->status = StatusConnected; - lua_pushinteger(l, 1); + lua_pushinteger(L, 1); return 1; } - static int LastError(lua_State *l) + static int LastError(lua_State *L) { - auto *tcps = (TCPSocket *)luaL_checkudata(l, 1, "TCPSocket"); - lua_pushstring(l, tcps->errorBuf); + auto *tcps = (TCPSocket *)luaL_checkudata(L, 1, "TCPSocket"); + lua_pushstring(L, tcps->errorBuf); return 1; } - static int GetStatus(lua_State *l) + static int GetStatus(lua_State *L) { - auto *tcps = (TCPSocket *)luaL_checkudata(l, 1, "TCPSocket"); + auto *tcps = (TCPSocket *)luaL_checkudata(L, 1, "TCPSocket"); switch (tcps->status) { - case StatusReady: lua_pushliteral(l, "ready"); break; - case StatusConnecting: lua_pushliteral(l, "connecting"); break; - case StatusConnected: lua_pushliteral(l, "connected"); break; - case StatusDead: lua_pushliteral(l, "dead"); break; + case StatusReady: lua_pushliteral(L, "ready"); break; + case StatusConnecting: lua_pushliteral(L, "connecting"); break; + case StatusConnected: lua_pushliteral(L, "connected"); break; + case StatusDead: lua_pushliteral(L, "dead"); break; } return 1; } - static int GetPeerName(lua_State *l) + static int GetPeerName(lua_State *L) { using http::HandleCURLcode; - auto *tcps = (TCPSocket *)luaL_checkudata(l, 1, "TCPSocket"); + auto *tcps = (TCPSocket *)luaL_checkudata(L, 1, "TCPSocket"); if (tcps->status != StatusConnected) { - return luaL_error(l, "attempt to get remote socket info while not connected"); + return luaL_error(L, "attempt to get remote socket info while not connected"); } char *address; HandleCURLcode(curl_easy_getinfo(tcps->easy, CURLINFO_PRIMARY_IP, &address)); - lua_pushstring(l, address); + lua_pushstring(L, address); long port; HandleCURLcode(curl_easy_getinfo(tcps->easy, CURLINFO_PRIMARY_PORT, &port)); - lua_pushinteger(l, port); + lua_pushinteger(L, port); return 2; } - static int SetTimeout(lua_State *l) + static int SetTimeout(lua_State *L) { - auto *tcps = (TCPSocket *)luaL_checkudata(l, 1, "TCPSocket"); + auto *tcps = (TCPSocket *)luaL_checkudata(L, 1, "TCPSocket"); tcps->blocking = true; - if (lua_isnoneornil(l, 2)) + if (lua_isnoneornil(L, 2)) { tcps->timeoutIndefinite = true; } else { tcps->timeoutIndefinite = false; - tcps->timeout = luaL_checknumber(l, 2); + tcps->timeout = luaL_checknumber(L, 2); if (int(tcps->timeout) == 0) { tcps->blocking = false; @@ -537,57 +534,57 @@ namespace LuaSocket return 0; } - static int GetSockName(lua_State *l) + static int GetSockName(lua_State *L) { using http::HandleCURLcode; - auto *tcps = (TCPSocket *)luaL_checkudata(l, 1, "TCPSocket"); + auto *tcps = (TCPSocket *)luaL_checkudata(L, 1, "TCPSocket"); if (tcps->status != StatusConnected) { - return luaL_error(l, "attempt to get local socket info while not connected"); + return luaL_error(L, "attempt to get local socket info while not connected"); } char *address; HandleCURLcode(curl_easy_getinfo(tcps->easy, CURLINFO_LOCAL_IP, &address)); - lua_pushstring(l, address); + lua_pushstring(L, address); long port; HandleCURLcode(curl_easy_getinfo(tcps->easy, CURLINFO_LOCAL_PORT, &port)); - lua_pushinteger(l, port); + lua_pushinteger(L, port); return 2; } - static int SetOption(lua_State *l) + static int SetOption(lua_State *L) { using http::HandleCURLcode; - auto *tcps = (TCPSocket *)luaL_checkudata(l, 1, "TCPSocket"); - auto option = tpt_lua_checkByteString(l, 2); + auto *tcps = (TCPSocket *)luaL_checkudata(L, 1, "TCPSocket"); + auto option = tpt_lua_checkByteString(L, 2); try { if (byteStringEqualsLiteral(option, "keepalive")) { - HandleCURLcode(curl_easy_setopt(tcps->easy, CURLOPT_TCP_KEEPALIVE, long(lua_toboolean(l, 3)))); + HandleCURLcode(curl_easy_setopt(tcps->easy, CURLOPT_TCP_KEEPALIVE, long(lua_toboolean(L, 3)))); return 0; } else if (byteStringEqualsLiteral(option, "tcp-nodelay")) { - HandleCURLcode(curl_easy_setopt(tcps->easy, CURLOPT_TCP_NODELAY, long(lua_toboolean(l, 3)))); + HandleCURLcode(curl_easy_setopt(tcps->easy, CURLOPT_TCP_NODELAY, long(lua_toboolean(L, 3)))); return 0; } else if (byteStringEqualsLiteral(option, "verify-peer")) { - HandleCURLcode(curl_easy_setopt(tcps->easy, CURLOPT_SSL_VERIFYPEER, long(lua_toboolean(l, 3)))); + HandleCURLcode(curl_easy_setopt(tcps->easy, CURLOPT_SSL_VERIFYPEER, long(lua_toboolean(L, 3)))); return 0; } } catch (const http::CurlError &ex) { - return luaL_error(l, ex.what()); + return luaL_error(L, ex.what()); } - return luaL_error(l, "unknown option"); + return luaL_error(L, "unknown option"); } - static int Shutdown(lua_State *l) + static int Shutdown(lua_State *L) { - auto *tcps = (TCPSocket *)luaL_checkudata(l, 1, "TCPSocket"); - auto direction = tpt_lua_optByteString(l, 2, "both"); + auto *tcps = (TCPSocket *)luaL_checkudata(L, 1, "TCPSocket"); + auto direction = tpt_lua_optByteString(L, 2, "both"); if (byteStringEqualsLiteral(direction, "receive")) { tcps->readClosed = true; @@ -604,15 +601,15 @@ namespace LuaSocket tcps->writeClosed = true; return 0; } - return luaL_error(l, "unknown direction"); + return luaL_error(L, "unknown direction"); } - void OpenTCP(lua_State *l) + void OpenTCP(lua_State *L) { - luaL_newmetatable(l, "TCPSocket"); - lua_pushcfunction(l, LuaSocket::GC); - lua_setfield(l, -2, "__gc"); - lua_newtable(l); + luaL_newmetatable(L, "TCPSocket"); + lua_pushcfunction(L, LuaSocket::GC); + lua_setfield(L, -2, "__gc"); + lua_newtable(L); struct luaL_Reg tcpSocketIndexMethods[] = { { "connect", LuaSocket::Connect }, { "close", LuaSocket::Close }, @@ -627,12 +624,12 @@ namespace LuaSocket { "shutdown", LuaSocket::Shutdown }, { NULL, NULL }, }; - luaL_register(l, NULL, tcpSocketIndexMethods); - lua_setfield(l, -2, "__index"); - lua_pop(l, 1); - lua_getglobal(l, "socket"); - lua_pushcfunction(l, LuaSocket::New); - lua_setfield(l, -2, "tcp"); - lua_pop(l, 1); + luaL_register(L, NULL, tcpSocketIndexMethods); + lua_setfield(L, -2, "__index"); + lua_pop(L, 1); + lua_getglobal(L, "socket"); + lua_pushcfunction(L, LuaSocket::New); + lua_setfield(L, -2, "tcp"); + lua_pop(L, 1); } } diff --git a/src/lua/LuaSocketTCPNoHttp.cpp b/src/lua/LuaSocketTCPNoHttp.cpp index 77b242c05..1bd1a6fba 100644 --- a/src/lua/LuaSocketTCPNoHttp.cpp +++ b/src/lua/LuaSocketTCPNoHttp.cpp @@ -1,8 +1,8 @@ -#include "LuaSocket.h" +#include "LuaScriptInterface.h" namespace LuaSocket { - void OpenTCP(lua_State *l) + void OpenTCP(lua_State *L) { } } diff --git a/src/lua/LuaSocketWindows.cpp b/src/lua/LuaSocketWindows.cpp index 0679febd5..85e840553 100644 --- a/src/lua/LuaSocketWindows.cpp +++ b/src/lua/LuaSocketWindows.cpp @@ -1,4 +1,3 @@ -#include "LuaSocket.h" #include "LuaScriptInterface.h" #include "Misc.h" #include diff --git a/src/lua/LuaTextbox.cpp b/src/lua/LuaTextbox.cpp index 7f476862d..f517ef7f7 100644 --- a/src/lua/LuaTextbox.cpp +++ b/src/lua/LuaTextbox.cpp @@ -15,16 +15,16 @@ Luna::RegType LuaTextbox::methods[] = { {0, 0} }; -LuaTextbox::LuaTextbox(lua_State * l) : - LuaComponent(l) +LuaTextbox::LuaTextbox(lua_State *L) : + LuaComponent(L) { - this->l = l; - int posX = luaL_optinteger(l, 1, 0); - int posY = luaL_optinteger(l, 2, 0); - int sizeX = luaL_optinteger(l, 3, 10); - int sizeY = luaL_optinteger(l, 4, 10); - String text = tpt_lua_optString(l, 5, ""); - String placeholder = tpt_lua_optString(l, 6, ""); + this->L = L; + int posX = luaL_optinteger(L, 1, 0); + int posY = luaL_optinteger(L, 2, 0); + int sizeX = luaL_optinteger(L, 3, 10); + int sizeY = luaL_optinteger(L, 4, 10); + String text = tpt_lua_optString(L, 5, ""); + String placeholder = tpt_lua_optString(L, 6, ""); textbox = new ui::Textbox(ui::Point(posX, posY), ui::Point(sizeX, sizeY), text, placeholder); textbox->Appearance.HorizontalAlign = ui::Appearance::AlignLeft; @@ -32,51 +32,51 @@ LuaTextbox::LuaTextbox(lua_State * l) : component = textbox; } -int LuaTextbox::readonly(lua_State * l) +int LuaTextbox::readonly(lua_State *L) { - int args = lua_gettop(l); + int args = lua_gettop(L); if(args) { - luaL_checktype(l, 1, LUA_TBOOLEAN); - textbox->ReadOnly = lua_toboolean(l, 1); + luaL_checktype(L, 1, LUA_TBOOLEAN); + textbox->ReadOnly = lua_toboolean(L, 1); return 0; } else { - lua_pushboolean(l, textbox->ReadOnly); + lua_pushboolean(L, textbox->ReadOnly); return 1; } } -int LuaTextbox::onTextChanged(lua_State * l) +int LuaTextbox::onTextChanged(lua_State *L) { - return onTextChangedFunction.CheckAndAssignArg1(l); + return onTextChangedFunction.CheckAndAssignArg1(L); } void LuaTextbox::triggerOnTextChanged() { if(onTextChangedFunction) { - lua_rawgeti(l, LUA_REGISTRYINDEX, onTextChangedFunction); - lua_rawgeti(l, LUA_REGISTRYINDEX, owner_ref); - if (tpt_lua_pcall(l, 1, 0, 0, eventTraitNone)) + lua_rawgeti(L, LUA_REGISTRYINDEX, onTextChangedFunction); + lua_rawgeti(L, LUA_REGISTRYINDEX, owner_ref); + if (tpt_lua_pcall(L, 1, 0, 0, eventTraitNone)) { - ci->Log(CommandInterface::LogError, tpt_lua_optString(l, -1)); + ci->Log(CommandInterface::LogError, tpt_lua_optString(L, -1)); } } } -int LuaTextbox::text(lua_State * l) +int LuaTextbox::text(lua_State *L) { - int args = lua_gettop(l); + int args = lua_gettop(L); if(args) { - textbox->SetText(tpt_lua_checkString(l, 1)); + textbox->SetText(tpt_lua_checkString(L, 1)); return 0; } else { - tpt_lua_pushString(l, textbox->GetText()); + tpt_lua_pushString(L, textbox->GetText()); return 1; } } diff --git a/src/lua/LuaTextbox.h b/src/lua/LuaTextbox.h index 9c8081fc4..60d3fde79 100644 --- a/src/lua/LuaTextbox.h +++ b/src/lua/LuaTextbox.h @@ -14,14 +14,14 @@ class LuaTextbox: public LuaComponent { LuaComponentCallback onTextChangedFunction; ui::Textbox * textbox; - int text(lua_State * l); - int readonly(lua_State * l); - int onTextChanged(lua_State * l); + int text(lua_State *L); + int readonly(lua_State *L); + int onTextChanged(lua_State *L); void triggerOnTextChanged(); public: static const char className[]; static Luna::RegType methods[]; - LuaTextbox(lua_State * l); + LuaTextbox(lua_State *L); ~LuaTextbox(); }; diff --git a/src/lua/LuaWindow.cpp b/src/lua/LuaWindow.cpp index 77fcf764c..b6e182eeb 100644 --- a/src/lua/LuaWindow.cpp +++ b/src/lua/LuaWindow.cpp @@ -35,13 +35,13 @@ Luna::RegType LuaWindow::methods[] = { {0, 0} }; -LuaWindow::LuaWindow(lua_State * l) +LuaWindow::LuaWindow(lua_State *L) { - this->l = l; - int posX = luaL_optinteger(l, 1, 1); - int posY = luaL_optinteger(l, 2, 1); - int sizeX = luaL_optinteger(l, 3, 10); - int sizeY = luaL_optinteger(l, 4, 10); + this->L = L; + int posX = luaL_optinteger(L, 1, 1); + int posY = luaL_optinteger(L, 2, 1); + int sizeX = luaL_optinteger(L, 3, 10); + int sizeY = luaL_optinteger(L, 4, 10); // We should replace this with errors if (posX < 1 && posX != -1) @@ -85,31 +85,31 @@ LuaWindow::LuaWindow(lua_State * l) window = new DrawnWindow(ui::Point(posX, posY), ui::Point(sizeX, sizeY), this); } -int LuaWindow::addComponent(lua_State * l) +int LuaWindow::addComponent(lua_State *L) { void *opaque = nullptr; LuaComponent *luaComponent = nullptr; - if ((opaque = Luna::tryGet(l, 1))) + if ((opaque = Luna::tryGet(L, 1))) luaComponent = Luna::get(opaque); - else if ((opaque = Luna::tryGet(l, 1))) + else if ((opaque = Luna::tryGet(L, 1))) luaComponent = Luna::get(opaque); - else if ((opaque = Luna::tryGet(l, 1))) + else if ((opaque = Luna::tryGet(L, 1))) luaComponent = Luna::get(opaque); - else if ((opaque = Luna::tryGet(l, 1))) + else if ((opaque = Luna::tryGet(L, 1))) luaComponent = Luna::get(opaque); - else if ((opaque = Luna::tryGet(l, 1))) + else if ((opaque = Luna::tryGet(L, 1))) luaComponent = Luna::get(opaque); - else if ((opaque = Luna::tryGet(l, 1))) + else if ((opaque = Luna::tryGet(L, 1))) luaComponent = Luna::get(opaque); else - luaL_typerror(l, 1, "Component"); + luaL_typerror(L, 1, "Component"); if (luaComponent) { - auto ok = grabbed_components.insert(std::make_pair(luaComponent, LuaSmartRef())); + auto ok = grabbedComponents.insert(std::make_pair(luaComponent, LuaSmartRef())); if (ok.second) { auto it = ok.first; - it->second.Assign(l, 1); + it->second.Assign(L, 1); it->first->owner_ref = it->second; } window->AddComponent(luaComponent->GetComponent()); @@ -118,86 +118,86 @@ int LuaWindow::addComponent(lua_State * l) return 0; } -int LuaWindow::removeComponent(lua_State * l) +int LuaWindow::removeComponent(lua_State *L) { void *opaque = nullptr; LuaComponent *luaComponent = nullptr; - if ((opaque = Luna::tryGet(l, 1))) + if ((opaque = Luna::tryGet(L, 1))) luaComponent = Luna::get(opaque); - else if ((opaque = Luna::tryGet(l, 1))) + else if ((opaque = Luna::tryGet(L, 1))) luaComponent = Luna::get(opaque); - else if ((opaque = Luna::tryGet(l, 1))) + else if ((opaque = Luna::tryGet(L, 1))) luaComponent = Luna::get(opaque); - else if ((opaque = Luna::tryGet(l, 1))) + else if ((opaque = Luna::tryGet(L, 1))) luaComponent = Luna::get(opaque); - else if ((opaque = Luna::tryGet(l, 1))) + else if ((opaque = Luna::tryGet(L, 1))) luaComponent = Luna::get(opaque); - else if ((opaque = Luna::tryGet(l, 1))) + else if ((opaque = Luna::tryGet(L, 1))) luaComponent = Luna::get(opaque); else - luaL_typerror(l, 1, "Component"); + luaL_typerror(L, 1, "Component"); if (luaComponent) { ui::Component *component = luaComponent->GetComponent(); window->RemoveComponent(component); - auto it = grabbed_components.find(luaComponent); - if (it != grabbed_components.end()) + auto it = grabbedComponents.find(luaComponent); + if (it != grabbedComponents.end()) { it->second.Clear(); it->first->owner_ref = it->second; - grabbed_components.erase(it); + grabbedComponents.erase(it); luaComponent->SetParentWindow(nullptr); } } return 0; } -int LuaWindow::position(lua_State * l) +int LuaWindow::position(lua_State *L) { - int args = lua_gettop(l); + int args = lua_gettop(L); if(args) { - luaL_checktype(l, 1, LUA_TNUMBER); - luaL_checktype(l, 2, LUA_TNUMBER); - int posX = lua_tointeger(l, 1); - int posY = lua_tointeger(l, 2); + luaL_checktype(L, 1, LUA_TNUMBER); + luaL_checktype(L, 2, LUA_TNUMBER); + int posX = lua_tointeger(L, 1); + int posY = lua_tointeger(L, 2); if (posX < 1 || posY < 1) { - return luaL_error(l, "Invalid position: '%d,%d'", posX, posY); + return luaL_error(L, "Invalid position: '%d,%d'", posX, posY); } window->Position = ui::Point(posX, posY); return 0; } else { - lua_pushinteger(l, window->Position.X); - lua_pushinteger(l, window->Position.Y); + lua_pushinteger(L, window->Position.X); + lua_pushinteger(L, window->Position.Y); return 2; } } -int LuaWindow::size(lua_State * l) +int LuaWindow::size(lua_State *L) { - int args = lua_gettop(l); + int args = lua_gettop(L); if(args) { - luaL_checktype(l, 1, LUA_TNUMBER); - luaL_checktype(l, 2, LUA_TNUMBER); - int sizeX = lua_tointeger(l, 1); - int sizeY = lua_tointeger(l, 2); + luaL_checktype(L, 1, LUA_TNUMBER); + luaL_checktype(L, 2, LUA_TNUMBER); + int sizeX = lua_tointeger(L, 1); + int sizeY = lua_tointeger(L, 2); if (sizeX < 10 || sizeY < 10) { - return luaL_error(l, "Invalid size: '%d,%d'", sizeX, sizeY); + return luaL_error(L, "Invalid size: '%d,%d'", sizeX, sizeY); } window->Size = ui::Point(sizeX, sizeY); return 0; } else { - lua_pushinteger(l, window->Size.X); - lua_pushinteger(l, window->Size.Y); + lua_pushinteger(L, window->Size.X); + lua_pushinteger(L, window->Size.Y); return 2; } } @@ -206,10 +206,10 @@ void LuaWindow::triggerOnInitialized() { if(onInitializedFunction) { - lua_rawgeti(l, LUA_REGISTRYINDEX, onInitializedFunction); - if(tpt_lua_pcall(l, 0, 0, 0, eventTraitNone)) + lua_rawgeti(L, LUA_REGISTRYINDEX, onInitializedFunction); + if(tpt_lua_pcall(L, 0, 0, 0, eventTraitNone)) { - ci->Log(CommandInterface::LogError, tpt_lua_toString(l, -1)); + ci->Log(CommandInterface::LogError, tpt_lua_toString(L, -1)); } } } @@ -218,10 +218,10 @@ void LuaWindow::triggerOnExit() { if(onExitFunction) { - lua_rawgeti(l, LUA_REGISTRYINDEX, onExitFunction); - if(tpt_lua_pcall(l, 0, 0, 0, eventTraitNone)) + lua_rawgeti(L, LUA_REGISTRYINDEX, onExitFunction); + if(tpt_lua_pcall(L, 0, 0, 0, eventTraitNone)) { - ci->Log(CommandInterface::LogError, tpt_lua_toString(l, -1)); + ci->Log(CommandInterface::LogError, tpt_lua_toString(L, -1)); } } } @@ -230,11 +230,11 @@ void LuaWindow::triggerOnTick(float dt) { if(onTickFunction) { - lua_rawgeti(l, LUA_REGISTRYINDEX, onTickFunction); - lua_pushnumber(l, dt); - if(tpt_lua_pcall(l, 1, 0, 0, eventTraitNone)) + lua_rawgeti(L, LUA_REGISTRYINDEX, onTickFunction); + lua_pushnumber(L, dt); + if(tpt_lua_pcall(L, 1, 0, 0, eventTraitNone)) { - ci->Log(CommandInterface::LogError, tpt_lua_toString(l, -1)); + ci->Log(CommandInterface::LogError, tpt_lua_toString(L, -1)); } } } @@ -243,10 +243,10 @@ void LuaWindow::triggerOnDraw() { if(onDrawFunction) { - lua_rawgeti(l, LUA_REGISTRYINDEX, onDrawFunction); - if(tpt_lua_pcall(l, 0, 0, 0, eventTraitNone)) + lua_rawgeti(L, LUA_REGISTRYINDEX, onDrawFunction); + if(tpt_lua_pcall(L, 0, 0, 0, eventTraitNone)) { - ci->Log(CommandInterface::LogError, tpt_lua_toString(l, -1)); + ci->Log(CommandInterface::LogError, tpt_lua_toString(L, -1)); } } } @@ -255,10 +255,10 @@ void LuaWindow::triggerOnFocus() { if(onFocusFunction) { - lua_rawgeti(l, LUA_REGISTRYINDEX, onFocusFunction); - if(tpt_lua_pcall(l, 0, 0, 0, eventTraitNone)) + lua_rawgeti(L, LUA_REGISTRYINDEX, onFocusFunction); + if(tpt_lua_pcall(L, 0, 0, 0, eventTraitNone)) { - ci->Log(CommandInterface::LogError, tpt_lua_toString(l, -1)); + ci->Log(CommandInterface::LogError, tpt_lua_toString(L, -1)); } } } @@ -267,10 +267,10 @@ void LuaWindow::triggerOnBlur() { if(onBlurFunction) { - lua_rawgeti(l, LUA_REGISTRYINDEX, onBlurFunction); - if(tpt_lua_pcall(l, 0, 0, 0, eventTraitNone)) + lua_rawgeti(L, LUA_REGISTRYINDEX, onBlurFunction); + if(tpt_lua_pcall(L, 0, 0, 0, eventTraitNone)) { - ci->Log(CommandInterface::LogError, tpt_lua_toString(l, -1)); + ci->Log(CommandInterface::LogError, tpt_lua_toString(L, -1)); } } } @@ -279,10 +279,10 @@ void LuaWindow::triggerOnTryExit() { if(onTryExitFunction) { - lua_rawgeti(l, LUA_REGISTRYINDEX, onTryExitFunction); - if(tpt_lua_pcall(l, 0, 0, 0, eventTraitNone)) + lua_rawgeti(L, LUA_REGISTRYINDEX, onTryExitFunction); + if(tpt_lua_pcall(L, 0, 0, 0, eventTraitNone)) { - ci->Log(CommandInterface::LogError, tpt_lua_toString(l, -1)); + ci->Log(CommandInterface::LogError, tpt_lua_toString(L, -1)); } } } @@ -291,10 +291,10 @@ void LuaWindow::triggerOnTryOkay() { if(onTryOkayFunction) { - lua_rawgeti(l, LUA_REGISTRYINDEX, onTryOkayFunction); - if(tpt_lua_pcall(l, 0, 0, 0, eventTraitNone)) + lua_rawgeti(L, LUA_REGISTRYINDEX, onTryOkayFunction); + if(tpt_lua_pcall(L, 0, 0, 0, eventTraitNone)) { - ci->Log(CommandInterface::LogError, tpt_lua_toString(l, -1)); + ci->Log(CommandInterface::LogError, tpt_lua_toString(L, -1)); } } } @@ -303,14 +303,14 @@ void LuaWindow::triggerOnMouseMove(int x, int y, int dx, int dy) { if(onMouseMoveFunction) { - lua_rawgeti(l, LUA_REGISTRYINDEX, onMouseMoveFunction); - lua_pushinteger(l, x); - lua_pushinteger(l, y); - lua_pushinteger(l, dx); - lua_pushinteger(l, dy); - if(tpt_lua_pcall(l, 4, 0, 0, eventTraitNone)) + lua_rawgeti(L, LUA_REGISTRYINDEX, onMouseMoveFunction); + lua_pushinteger(L, x); + lua_pushinteger(L, y); + lua_pushinteger(L, dx); + lua_pushinteger(L, dy); + if(tpt_lua_pcall(L, 4, 0, 0, eventTraitNone)) { - ci->Log(CommandInterface::LogError, tpt_lua_toString(l, -1)); + ci->Log(CommandInterface::LogError, tpt_lua_toString(L, -1)); } } } @@ -319,13 +319,13 @@ void LuaWindow::triggerOnMouseDown(int x, int y, unsigned button) { if(onMouseDownFunction) { - lua_rawgeti(l, LUA_REGISTRYINDEX, onMouseDownFunction); - lua_pushinteger(l, x); - lua_pushinteger(l, y); - lua_pushinteger(l, button); - if(tpt_lua_pcall(l, 3, 0, 0, eventTraitNone)) + lua_rawgeti(L, LUA_REGISTRYINDEX, onMouseDownFunction); + lua_pushinteger(L, x); + lua_pushinteger(L, y); + lua_pushinteger(L, button); + if(tpt_lua_pcall(L, 3, 0, 0, eventTraitNone)) { - ci->Log(CommandInterface::LogError, tpt_lua_toString(l, -1)); + ci->Log(CommandInterface::LogError, tpt_lua_toString(L, -1)); } } } @@ -334,13 +334,13 @@ void LuaWindow::triggerOnMouseUp(int x, int y, unsigned button) { if(onMouseUpFunction) { - lua_rawgeti(l, LUA_REGISTRYINDEX, onMouseUpFunction); - lua_pushinteger(l, x); - lua_pushinteger(l, y); - lua_pushinteger(l, button); - if(tpt_lua_pcall(l, 3, 0, 0, eventTraitNone)) + lua_rawgeti(L, LUA_REGISTRYINDEX, onMouseUpFunction); + lua_pushinteger(L, x); + lua_pushinteger(L, y); + lua_pushinteger(L, button); + if(tpt_lua_pcall(L, 3, 0, 0, eventTraitNone)) { - ci->Log(CommandInterface::LogError, tpt_lua_toString(l, -1)); + ci->Log(CommandInterface::LogError, tpt_lua_toString(L, -1)); } } } @@ -349,13 +349,13 @@ void LuaWindow::triggerOnMouseWheel(int x, int y, int d) { if(onMouseWheelFunction) { - lua_rawgeti(l, LUA_REGISTRYINDEX, onMouseWheelFunction); - lua_pushinteger(l, x); - lua_pushinteger(l, y); - lua_pushinteger(l, d); - if(tpt_lua_pcall(l, 3, 0, 0, eventTraitNone)) + lua_rawgeti(L, LUA_REGISTRYINDEX, onMouseWheelFunction); + lua_pushinteger(L, x); + lua_pushinteger(L, y); + lua_pushinteger(L, d); + if(tpt_lua_pcall(L, 3, 0, 0, eventTraitNone)) { - ci->Log(CommandInterface::LogError, tpt_lua_toString(l, -1)); + ci->Log(CommandInterface::LogError, tpt_lua_toString(L, -1)); } } } @@ -364,15 +364,15 @@ void LuaWindow::triggerOnKeyPress(int key, int scan, bool repeat, bool shift, bo { if(onKeyPressFunction) { - lua_rawgeti(l, LUA_REGISTRYINDEX, onKeyPressFunction); - lua_pushinteger(l, key); - lua_pushinteger(l, scan); - lua_pushboolean(l, shift); - lua_pushboolean(l, ctrl); - lua_pushboolean(l, alt); - if(tpt_lua_pcall(l, 5, 0, 0, eventTraitNone)) + lua_rawgeti(L, LUA_REGISTRYINDEX, onKeyPressFunction); + lua_pushinteger(L, key); + lua_pushinteger(L, scan); + lua_pushboolean(L, shift); + lua_pushboolean(L, ctrl); + lua_pushboolean(L, alt); + if(tpt_lua_pcall(L, 5, 0, 0, eventTraitNone)) { - ci->Log(CommandInterface::LogError, tpt_lua_toString(l, -1)); + ci->Log(CommandInterface::LogError, tpt_lua_toString(L, -1)); } } } @@ -381,104 +381,104 @@ void LuaWindow::triggerOnKeyRelease(int key, int scan, bool repeat, bool shift, { if(onKeyReleaseFunction) { - lua_rawgeti(l, LUA_REGISTRYINDEX, onKeyReleaseFunction); - lua_pushinteger(l, key); - lua_pushinteger(l, scan); - lua_pushboolean(l, shift); - lua_pushboolean(l, ctrl); - lua_pushboolean(l, alt); - if(tpt_lua_pcall(l, 5, 0, 0, eventTraitNone)) + lua_rawgeti(L, LUA_REGISTRYINDEX, onKeyReleaseFunction); + lua_pushinteger(L, key); + lua_pushinteger(L, scan); + lua_pushboolean(L, shift); + lua_pushboolean(L, ctrl); + lua_pushboolean(L, alt); + if(tpt_lua_pcall(L, 5, 0, 0, eventTraitNone)) { - ci->Log(CommandInterface::LogError, tpt_lua_toString(l, -1)); + ci->Log(CommandInterface::LogError, tpt_lua_toString(L, -1)); } } } -int LuaWindow::onInitialized(lua_State * l) +int LuaWindow::onInitialized(lua_State *L) { - return onInitializedFunction.CheckAndAssignArg1(l); + return onInitializedFunction.CheckAndAssignArg1(L); } -int LuaWindow::onExit(lua_State * l) +int LuaWindow::onExit(lua_State *L) { - return onExitFunction.CheckAndAssignArg1(l); + return onExitFunction.CheckAndAssignArg1(L); } -int LuaWindow::onTick(lua_State * l) +int LuaWindow::onTick(lua_State *L) { - return onTickFunction.CheckAndAssignArg1(l); + return onTickFunction.CheckAndAssignArg1(L); } -int LuaWindow::onDraw(lua_State * l) +int LuaWindow::onDraw(lua_State *L) { - return onDrawFunction.CheckAndAssignArg1(l); + return onDrawFunction.CheckAndAssignArg1(L); } -int LuaWindow::onFocus(lua_State * l) +int LuaWindow::onFocus(lua_State *L) { - return onFocusFunction.CheckAndAssignArg1(l); + return onFocusFunction.CheckAndAssignArg1(L); } -int LuaWindow::onBlur(lua_State * l) +int LuaWindow::onBlur(lua_State *L) { - return onBlurFunction.CheckAndAssignArg1(l); + return onBlurFunction.CheckAndAssignArg1(L); } -int LuaWindow::onTryExit(lua_State * l) +int LuaWindow::onTryExit(lua_State *L) { - return onTryExitFunction.CheckAndAssignArg1(l); + return onTryExitFunction.CheckAndAssignArg1(L); } -int LuaWindow::onTryOkay(lua_State * l) +int LuaWindow::onTryOkay(lua_State *L) { - return onTryOkayFunction.CheckAndAssignArg1(l); + return onTryOkayFunction.CheckAndAssignArg1(L); } -int LuaWindow::onMouseMove(lua_State * l) +int LuaWindow::onMouseMove(lua_State *L) { - return onMouseMoveFunction.CheckAndAssignArg1(l); + return onMouseMoveFunction.CheckAndAssignArg1(L); } -int LuaWindow::onMouseDown(lua_State * l) +int LuaWindow::onMouseDown(lua_State *L) { - return onMouseDownFunction.CheckAndAssignArg1(l); + return onMouseDownFunction.CheckAndAssignArg1(L); } -int LuaWindow::onMouseUp(lua_State * l) +int LuaWindow::onMouseUp(lua_State *L) { - return onMouseUpFunction.CheckAndAssignArg1(l); + return onMouseUpFunction.CheckAndAssignArg1(L); } -int LuaWindow::onMouseWheel(lua_State * l) +int LuaWindow::onMouseWheel(lua_State *L) { - return onMouseWheelFunction.CheckAndAssignArg1(l); + return onMouseWheelFunction.CheckAndAssignArg1(L); } -int LuaWindow::onKeyPress(lua_State * l) +int LuaWindow::onKeyPress(lua_State *L) { - return onKeyPressFunction.CheckAndAssignArg1(l); + return onKeyPressFunction.CheckAndAssignArg1(L); } -int LuaWindow::onKeyRelease(lua_State * l) +int LuaWindow::onKeyRelease(lua_State *L) { - return onKeyReleaseFunction.CheckAndAssignArg1(l); + return onKeyReleaseFunction.CheckAndAssignArg1(L); } void LuaWindow::ClearRef(LuaComponent *luaComponent) { - auto it = grabbed_components.find(luaComponent); - if (it != grabbed_components.end()) + auto it = grabbedComponents.find(luaComponent); + if (it != grabbedComponents.end()) { it->second.Clear(); it->first->owner_ref = it->second; it->first->SetParentWindow(nullptr); - grabbed_components.erase(it); + grabbedComponents.erase(it); } } LuaWindow::~LuaWindow() { - for (auto &component_and_ref : grabbed_components) + for (auto &component_and_ref : grabbedComponents) { window->RemoveComponent(component_and_ref.first->GetComponent()); component_and_ref.second.Clear(); diff --git a/src/lua/LuaWindow.h b/src/lua/LuaWindow.h index fe847e101..812101aa1 100644 --- a/src/lua/LuaWindow.h +++ b/src/lua/LuaWindow.h @@ -27,30 +27,30 @@ class LuaWindow LuaComponentCallback onKeyPressFunction; LuaComponentCallback onKeyReleaseFunction; - std::map grabbed_components; + std::map grabbedComponents; ui::Window * window; - lua_State * l; - int position(lua_State * l); - int size(lua_State * l); - int addComponent(lua_State * l); - int removeComponent(lua_State * l); + lua_State *L; + int position(lua_State *L); + int size(lua_State *L); + int addComponent(lua_State *L); + int removeComponent(lua_State *L); //Set event handlers - int onInitialized(lua_State * l); - int onExit(lua_State * l); - int onTick(lua_State * l); - int onDraw(lua_State * l); - int onFocus(lua_State * l); - int onBlur(lua_State * l); - int onTryExit(lua_State * l); - int onTryOkay(lua_State * l); - int onMouseMove(lua_State * l); - int onMouseDown(lua_State * l); - int onMouseUp(lua_State * l); - int onMouseWheel(lua_State * l); - int onKeyPress(lua_State * l); - int onKeyRelease(lua_State * l); + int onInitialized(lua_State *L); + int onExit(lua_State *L); + int onTick(lua_State *L); + int onDraw(lua_State *L); + int onFocus(lua_State *L); + int onBlur(lua_State *L); + int onTryExit(lua_State *L); + int onTryOkay(lua_State *L); + int onMouseMove(lua_State *L); + int onMouseDown(lua_State *L); + int onMouseUp(lua_State *L); + int onMouseWheel(lua_State *L); + int onKeyPress(lua_State *L); + int onKeyRelease(lua_State *L); void triggerOnInitialized(); void triggerOnExit(); @@ -75,6 +75,6 @@ public: ui::Window * GetWindow() { return window; } void ClearRef(LuaComponent *luaComponent); - LuaWindow(lua_State * l); + LuaWindow(lua_State *L); ~LuaWindow(); }; diff --git a/src/lua/TPTScriptInterface.cpp b/src/lua/TPTScriptInterface.cpp index b03995292..37e86904f 100644 --- a/src/lua/TPTScriptInterface.cpp +++ b/src/lua/TPTScriptInterface.cpp @@ -11,10 +11,6 @@ #include #include -TPTScriptInterface::TPTScriptInterface(GameController * c, GameModel * m): CommandInterface(c, m) -{ -} - int TPTScriptInterface::Command(String command) { lastError = ""; diff --git a/src/lua/TPTScriptInterface.h b/src/lua/TPTScriptInterface.h index 79f049b9c..8b0ab5b97 100644 --- a/src/lua/TPTScriptInterface.h +++ b/src/lua/TPTScriptInterface.h @@ -15,7 +15,8 @@ class TPTScriptInterface: public CommandInterface { AnyType tptS_quit(std::deque * words); ValueType testType(String word); public: - TPTScriptInterface(GameController * c, GameModel * m); + using CommandInterface::CommandInterface; + int Command(String command) override; String FormatCommand(String command) override; }; diff --git a/src/lua/luascripts/compat.lua b/src/lua/luascripts/compat.lua index 7fe0585c2..c0cb9fd6a 100644 --- a/src/lua/luascripts/compat.lua +++ b/src/lua/luascripts/compat.lua @@ -58,6 +58,7 @@ ui.MOUSE_UP_NORMAL = ui.MOUSEUP_NORMAL if socket then socket.gettime = socket.getTime end +print = tpt.log local function fake_boolean_wrapper(func, true_is_1) return function(param) diff --git a/src/lua/meson.build b/src/lua/meson.build index fcb250e42..a713fb21c 100644 --- a/src/lua/meson.build +++ b/src/lua/meson.build @@ -1,12 +1,22 @@ luaconsole_files = files( 'LuaButton.cpp', + 'LuaBz2.cpp', 'LuaCheckbox.cpp', 'LuaCompat.c', 'LuaComponent.cpp', + 'LuaElements.cpp', + 'LuaEvent.cpp', + 'LuaFileSystem.cpp', + 'LuaGraphics.cpp', 'LuaHttp.cpp', + 'LuaInterface.cpp', 'LuaLabel.cpp', + 'LuaMisc.cpp', + 'LuaPlatform.cpp', 'LuaProgressBar.cpp', + 'LuaRenderer.cpp', 'LuaScriptInterface.cpp', + 'LuaSimulation.cpp', 'LuaSlider.cpp', 'LuaSocket.cpp', 'LuaSmartRef.cpp',