diff --git a/src/deh_lua.c b/src/deh_lua.c index a2ffca95b..43e25a49d 100644 --- a/src/deh_lua.c +++ b/src/deh_lua.c @@ -195,25 +195,32 @@ static inline int lib_freeslot(lua_State *L) // Arguments: mobj_t actor, int var1, int var2 static int action_call(lua_State *L) { - //actionf_t *action = lua_touserdata(L,lua_upvalueindex(1)); actionf_t *action = *((actionf_t **)luaL_checkudata(L, 1, META_ACTION)); mobj_t *actor = *((mobj_t **)luaL_checkudata(L, 2, META_MOBJ)); + var1 = (INT32)luaL_optinteger(L, 3, 0); var2 = (INT32)luaL_optinteger(L, 4, 0); + if (!actor) + { return LUA_ErrInvalid(L, "mobj_t"); + } + action->acp1(actor); return 0; } // Hardcoded A_Action name to call for super() or NULL if super() would be invalid. // Set in lua_infolib. -const char *superactions[MAXRECURSION]; +const char *luaactions[MAX_ACTION_RECURSION]; +UINT8 luaactionstack = 0; UINT8 superstack = 0; static int lib_dummysuper(lua_State *L) { - return luaL_error(L, "Can't call super() outside of hardcode-replacing A_Action functions being called by state changes!"); // convoluted, I know. @_@;; + // TODO: Now that the restriction on only being allowed in state changes was lifted, + // it'd be nice to have super extend to Lua A_ functions too :) + return luaL_error(L, "Can't call super() outside of hardcode-replacing A_Action functions!"); } static inline int lib_getenum(lua_State *L) @@ -500,42 +507,62 @@ static inline int lib_getenum(lua_State *L) } else if (!mathlib && fastncmp("A_",word,2)) { char *caps; - // Try to get a Lua action first. - /// \todo Push a closure that sets superactions[] and superstack. + + // Hardcoded actions come first. + // Trying to call them will invoke LUA_CallAction, which will handle super properly. + // Retrieving them from this metatable allows them to be case-insensitive! + for (i = 0; actionpointers[i].name; i++) + { + if (fasticmp(word, actionpointers[i].name)) + { + // We push the actionf_t* itself as userdata! + LUA_PushUserdata(L, &actionpointers[i].action, META_ACTION); + return 1; + } + } + + // Now try to get Lua actions. + /// \todo Push a closure that sets luaactions[] and luaactionstack. + /// This would be part one of a step to get super functions working for custom A_ functions. + /// Custom functions. lua_getfield(L, LUA_REGISTRYINDEX, LREG_ACTIONS); + // actions are stored in all uppercase. caps = Z_StrDup(word); strupr(caps); lua_getfield(L, -1, caps); Z_Free(caps); + if (!lua_isnil(L, -1)) + { return 1; // Success! :D That was easy. + } + // Welp, that failed. lua_pop(L, 2); // pop nil and LREG_ACTIONS - - // Hardcoded actions as callable Lua functions! - // Retrieving them from this metatable allows them to be case-insensitive! - for (i = 0; actionpointers[i].name; i++) - if (fasticmp(word, actionpointers[i].name)) { - // We push the actionf_t* itself as userdata! - LUA_PushUserdata(L, &actionpointers[i].action, META_ACTION); - return 1; - } return 0; } else if (!mathlib && fastcmp("super",word)) { - if (!superstack) + if (!luaactionstack) { + // Not in A_ action routine lua_pushcfunction(L, lib_dummysuper); return 1; } + for (i = 0; actionpointers[i].name; i++) - if (fasticmp(superactions[superstack-1], actionpointers[i].name)) { + { + if (fasticmp(luaactions[luaactionstack-1], actionpointers[i].name)) + { LUA_PushUserdata(L, &actionpointers[i].action, META_ACTION); return 1; } - return 0; + } + + // Not a hardcoded A_ action. + lua_pushcfunction(L, lib_dummysuper); + return 1; } if (fastcmp(word, "BT_USE")) // Remove case when 2.3 nears release... diff --git a/src/deh_tables.h b/src/deh_tables.h index 1f265cc99..70347f7dd 100644 --- a/src/deh_tables.h +++ b/src/deh_tables.h @@ -30,6 +30,7 @@ extern UINT8 used_spr[(NUMSPRITEFREESLOTS / 8) + 1]; // Bitwise flag for sprite memset(FREE_MOBJS,0,sizeof(char *) * NUMMOBJFREESLOTS);\ memset(FREE_SKINCOLORS,0,sizeof(char *) * NUMCOLORFREESLOTS);\ memset(used_spr,0,sizeof(UINT8) * ((NUMSPRITEFREESLOTS / 8) + 1));\ + memset(actionsoverridden, LUA_REFNIL, sizeof(actionsoverridden));\ } struct flickytypes_s { diff --git a/src/dehacked.h b/src/dehacked.h index 1b200e246..e29aef6ff 100644 --- a/src/dehacked.h +++ b/src/dehacked.h @@ -40,8 +40,9 @@ extern boolean gamedataadded; extern boolean titlechanged; extern boolean introchanged; -#define MAXRECURSION 30 -extern const char *superactions[MAXRECURSION]; +#define MAX_ACTION_RECURSION 30 +extern const char *luaactions[MAX_ACTION_RECURSION]; +extern UINT8 luaactionstack; extern UINT8 superstack; // If the dehacked patch does not match this version, we throw a warning diff --git a/src/info.h b/src/info.h index 031a08b43..6e9460bec 100644 --- a/src/info.h +++ b/src/info.h @@ -18,6 +18,7 @@ #include "d_think.h" #include "sounds.h" #include "m_fixed.h" +#include "dehacked.h" // MAX_ACTION_RECURSION // deh_tables.c now has lists for the more named enums! PLEASE keep them up to date! // For great modding!! @@ -554,7 +555,7 @@ void A_DragonWing(); void A_DragonSegment(); void A_ChangeHeight(); -extern boolean actionsoverridden[NUMACTIONS]; +extern int actionsoverridden[NUMACTIONS][MAX_ACTION_RECURSION]; // ratio of states to sprites to mobj types is roughly 6 : 1 : 1 #define NUMMOBJFREESLOTS 512 diff --git a/src/lua_infolib.c b/src/lua_infolib.c index af2d99a0c..e20202495 100644 --- a/src/lua_infolib.c +++ b/src/lua_infolib.c @@ -66,7 +66,7 @@ const char *const sfxinfo_wopt[] = { "caption", NULL}; -boolean actionsoverridden[NUMACTIONS] = {false}; +int actionsoverridden[NUMACTIONS][MAX_ACTION_RECURSION]; // // Sprite Names @@ -645,8 +645,8 @@ static void A_Lua(mobj_t *actor) if (lua_rawequal(gL, -1, -4)) { found = true; - superactions[superstack] = lua_tostring(gL, -2); // "A_ACTION" - ++superstack; + luaactions[luaactionstack] = lua_tostring(gL, -2); // "A_ACTION" + ++luaactionstack; lua_pop(gL, 2); // pop the name and function break; } @@ -661,8 +661,8 @@ static void A_Lua(mobj_t *actor) if (found) { - --superstack; - superactions[superstack] = NULL; + --luaactionstack; + luaactions[luaactionstack] = NULL; } } @@ -816,18 +816,46 @@ boolean LUA_CallAction(enum actionnum actionnum, mobj_t *actor) { I_Assert(actor != NULL); - if (!actionsoverridden[actionnum]) // The action is not overriden, - return false; // action not called. + if (actionsoverridden[actionnum][0] == LUA_REFNIL) + { + // The action was not overridden at all, + // so call the hardcoded version. + return false; + } - if (superstack && fasticmp(actionpointers[actionnum].name, superactions[superstack-1])) // the action is calling itself, - return false; // let it call the hardcoded function instead. + if (luaactionstack && fasticmp(actionpointers[actionnum].name, luaactions[luaactionstack-1])) + { + // The action is calling itself, + // so look up the next Lua reference in its stack. + // 0 is just the reference to the one we're calling, + // so we increment here. + superstack++; + + if (superstack >= MAX_ACTION_RECURSION) + { + CONS_Alert(CONS_WARNING, "Max Lua super recursion reached! Cool it on calling super!\n"); + return false; + } + } + else + { + // Not calling itself, reset the super counter. + superstack = 0; + } + + if (actionsoverridden[actionnum][superstack] == LUA_REFNIL) + { + // No Lua reference beyond this point. + // Let it call the hardcoded function instead. + return false; + } + + // Push error function lua_pushcfunction(gL, LUA_GetErrorMessage); - // grab function by uppercase name. - lua_getfield(gL, LUA_REGISTRYINDEX, LREG_ACTIONS); - lua_getfield(gL, -1, actionpointers[actionnum].name); - lua_remove(gL, -2); // pop LREG_ACTIONS + // Push function by reference. + lua_getref(gL, actionsoverridden[actionnum][superstack]); if (lua_isnil(gL, -1)) // no match { @@ -835,7 +863,7 @@ boolean LUA_CallAction(enum actionnum actionnum, mobj_t *actor) return false; // action not called. } - if (superstack == MAXRECURSION) + if (luaactionstack >= MAX_ACTION_RECURSION) { CONS_Alert(CONS_WARNING, "Max Lua Action recursion reached! Cool it on the calling A_Action functions from inside A_Action functions!\n"); lua_pop(gL, 2); // pop function and error handler @@ -849,14 +877,14 @@ boolean LUA_CallAction(enum actionnum actionnum, mobj_t *actor) lua_pushinteger(gL, var1); lua_pushinteger(gL, var2); - superactions[superstack] = actionpointers[actionnum].name; - ++superstack; + luaactions[luaactionstack] = actionpointers[actionnum].name; + ++luaactionstack; LUA_Call(gL, 3, 0, -(2 + 3)); lua_pop(gL, -1); // Error handler - --superstack; - superactions[superstack] = NULL; + --luaactionstack; + luaactions[luaactionstack] = NULL; return true; // action successfully called. } diff --git a/src/lua_script.c b/src/lua_script.c index a1376ca2e..5441d315e 100644 --- a/src/lua_script.c +++ b/src/lua_script.c @@ -485,7 +485,19 @@ static int setglobals(lua_State *L) actionnum = LUA_GetActionNumByName(name); if (actionnum < NUMACTIONS) - actionsoverridden[actionnum] = true; + { + int i; + + for (i = MAX_ACTION_RECURSION-1; i > 0; i--) + { + // Move other references deeper. + actionsoverridden[actionnum][i] = actionsoverridden[actionnum][i - 1]; + } + + // Add the new reference. + lua_pushvalue(L, 2); + actionsoverridden[actionnum][0] = luaL_ref(L, LUA_REGISTRYINDEX); + } Z_Free(name); return 0;