diff --git a/src/lua_hook.h b/src/lua_hook.h index fae3bb7e6..da2dcdc38 100644 --- a/src/lua_hook.h +++ b/src/lua_hook.h @@ -41,7 +41,7 @@ enum hook { hook_BotAI, hook_LinedefExecute, hook_PlayerMsg, - hook_DeathMsg, + hook_HurtMsg, hook_MAX // last hook }; @@ -54,8 +54,9 @@ void LUAh_ThinkFrame(void); // Hook for frame (after mobj and player thinkers) boolean LUAh_MobjHook(mobj_t *mo, enum hook which); boolean LUAh_PlayerHook(player_t *plr, enum hook which); #define LUAh_MobjSpawn(mo) LUAh_MobjHook(mo, hook_MobjSpawn) // Hook for P_SpawnMobj by mobj type -UINT8 LUAh_MobjCollide(mobj_t *thing1, mobj_t *thing2); // Hook for PIT_CheckThing by (thing) mobj type -UINT8 LUAh_MobjMoveCollide(mobj_t *thing1, mobj_t *thing2); // Hook for PIT_CheckThing by (tmthing) mobj type +UINT8 LUAh_MobjCollideHook(mobj_t *thing1, mobj_t *thing2, enum hook which); +#define LUAh_MobjCollide(thing1, thing2) LUAh_MobjCollideHook(thing1, thing2, hook_MobjCollide) // Hook for PIT_CheckThing by (thing) mobj type +#define LUAh_MobjMoveCollide(thing1, thing2) LUAh_MobjCollideHook(thing1, thing2, hook_MobjMoveCollide) // Hook for PIT_CheckThing by (tmthing) mobj type boolean LUAh_TouchSpecial(mobj_t *special, mobj_t *toucher); // Hook for P_TouchSpecialThing by mobj type #define LUAh_MobjFuse(mo) LUAh_MobjHook(mo, hook_MobjFuse) // Hook for mobj->fuse == 0 by mobj type #define LUAh_MobjThinker(mo) LUAh_MobjHook(mo, hook_MobjThinker) // Hook for P_MobjThinker or P_SceneryThinker by mobj type @@ -73,6 +74,6 @@ boolean LUAh_BotTiccmd(player_t *bot, ticcmd_t *cmd); // Hook for B_BuildTiccmd boolean LUAh_BotAI(mobj_t *sonic, mobj_t *tails, ticcmd_t *cmd); // Hook for B_BuildTailsTiccmd by skin name boolean LUAh_LinedefExecute(line_t *line, mobj_t *mo, sector_t *sector); // Hook for linedef executors boolean LUAh_PlayerMsg(int source, int target, int flags, char *msg); // Hook for chat messages -boolean LUAh_DeathMsg(player_t *player, mobj_t *inflictor, mobj_t *source); // Hook for hurt messages +boolean LUAh_HurtMsg(player_t *player, mobj_t *inflictor, mobj_t *source); // Hook for hurt messages #endif diff --git a/src/lua_hooklib.c b/src/lua_hooklib.c index 532726ac2..c314ed045 100644 --- a/src/lua_hooklib.c +++ b/src/lua_hooklib.c @@ -56,23 +56,40 @@ const char *const hookNames[hook_MAX+1] = { NULL }; +// Hook metadata +struct hook_s +{ + struct hook_s *next; + enum hook type; + UINT16 id; + union { + mobjtype_t mt; + char *skinname; + char *funcname; + } s; + boolean error; +}; +typedef struct hook_s* hook_p; + +#define FMT_HOOKID "hook_%04x" + +hook_p roothook; + // Takes hook, function, and additional arguments (mobj type to act on, etc.) static int lib_addHook(lua_State *L) { - UINT16 hook; - boolean notable = false; - boolean subtable = false; - UINT32 subindex = 0; - char *subfield = NULL; - const char *lsubfield = NULL; + static struct hook_s hook = {NULL, 0, 0, {0}, false}; + hook_p hookp, *lastp; - hook = (UINT16)luaL_checkoption(L, 1, NULL, hookNames); - luaL_checktype(L, 2, LUA_TFUNCTION); + hook.type = luaL_checkoption(L, 1, NULL, hookNames); + lua_remove(L, 1); + + luaL_checktype(L, 1, LUA_TFUNCTION); if (hud_running) return luaL_error(L, "HUD rendering code should not call this function!"); - switch(hook) + switch(hook.type) { // Take a mobjtype enum which this hook is specifically for. case hook_MobjSpawn: @@ -87,277 +104,140 @@ static int lib_addHook(lua_State *L) case hook_MobjDeath: case hook_BossDeath: case hook_MobjRemoved: - subtable = true; - if (lua_isnumber(L, 3)) - subindex = (UINT32)luaL_checkinteger(L, 3); - else - lsubfield = "a"; - lua_settop(L, 2); + case hook_HurtMsg: + hook.s.mt = MT_NULL; + if (lua_isnumber(L, 2)) + hook.s.mt = lua_tonumber(L, 2); break; - case hook_BotAI: // Only one AI function per skin, please! - notable = true; - subtable = true; - subfield = ZZ_Alloc(strlen(luaL_checkstring(L, 3))+1); + case hook_BotAI: + hook.s.skinname = NULL; + if (lua_isstring(L, 2)) { // lowercase copy - char *p = subfield; - const char *s = luaL_checkstring(L, 3); + const char *s = lua_tostring(L, 2); + char *p = hook.s.skinname = ZZ_Alloc(strlen(s)+1); do { *p = tolower(*s); ++p; } while(*(++s)); *p = 0; } - lua_settop(L, 3); break; - case hook_LinedefExecute: // Get one linedef executor function by name - notable = true; - subtable = true; - subfield = ZZ_Alloc(strlen(luaL_checkstring(L, 3))+1); + case hook_LinedefExecute: // Linedef executor functions { // uppercase copy - char *p = subfield; - const char *s = luaL_checkstring(L, 3); + const char *s = luaL_checkstring(L, 2); + char *p = hook.s.funcname = ZZ_Alloc(strlen(s)+1); do { *p = toupper(*s); ++p; } while(*(++s)); *p = 0; } - lua_settop(L, 3); break; default: - lua_settop(L, 2); break; } + lua_settop(L, 1); // lua stack contains only the function now. - lua_getfield(L, LUA_REGISTRYINDEX, "hook"); - I_Assert(lua_istable(L, -1)); + hooksAvailable[hook.type/8] |= 1<<(hook.type%8); - // This hook type only allows one entry, not an array of hooks. - // New hooks will overwrite the previous ones, and the stack is one table shorter. - if (notable) + // iterate the hook metadata structs + // set hook.id to the highest id + 1 + // set lastp to the last hook struct's "next" pointer. + lastp = &roothook; + hook.id = 0; + for (hookp = roothook; hookp; hookp = hookp->next) { - if (subtable) - { - lua_rawgeti(L, -1, hook); - lua_remove(L, -2); // pop "hook" - I_Assert(lua_istable(L, -1)); - lua_pushvalue(L, 2); - if (subfield) - lua_setfield(L, -2, subfield); - else if (lsubfield) - lua_setfield(L, -2, lsubfield); - else - lua_rawseti(L, -2, subindex); - } else { - lua_pushvalue(L, 2); - lua_rawseti(L, -2, hook); - } - hooksAvailable[hook/8] |= 1<<(hook%8); - return 0; + if (hookp->id >= hook.id) + hook.id = hookp->id+1; + lastp = &hookp->next; } - // Fetch the hook's table from the registry. - // It should always exist, since LUA_HookLib creates a table for every hook. - lua_rawgeti(L, -1, hook); - lua_remove(L, -2); // pop "hook" - I_Assert(lua_istable(L, -1)); - if (subtable) - { - // Fetch a subtable based on index - if (subfield) - lua_getfield(L, -1, subfield); - else if (lsubfield) - lua_getfield(L, -1, lsubfield); - else - lua_rawgeti(L, -1, subindex); + // allocate a permanent memory struct to stuff hook. + hookp = ZZ_Alloc(sizeof(struct hook_s)); + memcpy(hookp, &hook, sizeof(struct hook_s)); + // tack it onto the end of the linked list. + *lastp = hookp; - // Subtable doesn't exist, make one now. - if (lua_isnil(L, -1)) - { - lua_pop(L, 1); - lua_newtable(L); - - // Store a link to the subtable for later. - lua_pushvalue(L, -1); - if (subfield) - lua_setfield(L, -3, subfield); - else if (lsubfield) - lua_setfield(L, -3, lsubfield); - else - lua_rawseti(L, -3, subindex); - } } - - // Add function to the table. - lua_pushvalue(L, 2); - lua_rawseti(L, -2, (int)(lua_objlen(L, -2) + 1)); - - if (subfield) - Z_Free(subfield); - - hooksAvailable[hook/8] |= 1<<(hook%8); + // set the hook function in the registry. + lua_pushfstring(L, FMT_HOOKID, hook.id); + lua_pushvalue(L, 1); + lua_settable(L, LUA_REGISTRYINDEX); return 0; } int LUA_HookLib(lua_State *L) { - // Create all registry tables - enum hook i; memset(hooksAvailable,0,sizeof(UINT8[(hook_MAX/8)+1])); - - lua_newtable(L); - for (i = 0; i < hook_MAX; i++) - { - lua_newtable(L); - switch(i) - { - default: - break; - case hook_MobjSpawn: - case hook_MobjCollide: - case hook_MobjMoveCollide: - case hook_TouchSpecial: - case hook_MobjFuse: - case hook_MobjThinker: - case hook_BossThinker: - case hook_ShouldDamage: - case hook_MobjDamage: - case hook_MobjDeath: - case hook_BossDeath: - case hook_MobjRemoved: - lua_pushstring(L, "a"); - lua_newtable(L); - lua_rawset(L, -3); - break; - } - lua_rawseti(L, -2, i); - } - lua_setfield(L, LUA_REGISTRYINDEX, "hook"); + roothook = NULL; lua_register(L, "addHook", lib_addHook); return 0; } boolean LUAh_MobjHook(mobj_t *mo, enum hook which) { + hook_p hookp; boolean hooked = false; if (!gL || !(hooksAvailable[which/8] & (1<<(which%8)))) return false; - // clear the stack (just in case) lua_pop(gL, -1); - - // hook table - lua_getfield(gL, LUA_REGISTRYINDEX, "hook"); - I_Assert(lua_istable(gL, -1)); - lua_rawgeti(gL, -1, which); - lua_remove(gL, -2); - I_Assert(lua_istable(gL, -1)); - - // generic subtable - lua_pushstring(gL, "a"); - lua_rawget(gL, -2); - I_Assert(lua_istable(gL, -1)); - LUA_PushUserdata(gL, mo, META_MOBJ); - lua_pushnil(gL); - while (lua_next(gL, -3)) { - CONS_Debug(DBG_LUA, "MobjHook: Calling hook_%s for generic mobj types\n", hookNames[which]); - lua_pushvalue(gL, -3); // mo - // stack is: hook_Mobj table, subtable "a", mobj, i, function, mobj - if (lua_pcall(gL, 1, 1, 0)) { - // A run-time error occurred. - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL,-1)); - lua_pop(gL, 1); - // Remove this function from the hook table to prevent further errors. - lua_pushvalue(gL, -1); // key - lua_pushnil(gL); // value - lua_rawset(gL, -5); // table - CONS_Printf("Hook removed.\n"); - } - else + + for (hookp = roothook; hookp; hookp = hookp->next) + if (hookp->type == which + && (hookp->s.mt == MT_NULL || hookp->s.mt == mo->type)) { + lua_pushfstring(gL, FMT_HOOKID, hookp->id); + lua_gettable(gL, LUA_REGISTRYINDEX); + lua_pushvalue(gL, -2); + if (lua_pcall(gL, 1, 1, 0)) { + if (!hookp->error || cv_debug & DBG_LUA) + CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); + lua_pop(gL, 1); + hookp->error = true; + continue; + } if (lua_toboolean(gL, -1)) hooked = true; lua_pop(gL, 1); } - } - // stack is: hook_Mobj table, subtable "a", mobj - lua_remove(gL, -2); // pop subtable, leave mobj - // mobjtype subtable - // stack is: hook_Mobj table, mobj - lua_rawgeti(gL, -2, mo->type); - if (lua_isnil(gL, -1)) { - lua_pop(gL, 3); // pop hook_Mobj table, mobj, and nil - // the stack should now be empty. - return false; - } - lua_remove(gL, -3); // remove hook table - // stack is: mobj, mobjtype subtable - lua_insert(gL, lua_gettop(gL)-1); // swap subtable with mobj - // stack is: mobjtype subtable, mobj + lua_pop(gL, 1); - lua_pushnil(gL); - while (lua_next(gL, -3)) { - CONS_Debug(DBG_LUA, "MobjHook: Calling hook_%s for mobj type %d\n", hookNames[which], mo->type); - lua_pushvalue(gL, -3); // mo - // stack is: mobjtype subtable, mobj, i, function, mobj - if (lua_pcall(gL, 1, 1, 0)) { - // A run-time error occurred. - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL,-1)); - lua_pop(gL, 1); - // Remove this function from the hook table to prevent further errors. - lua_pushvalue(gL, -1); // key - lua_pushnil(gL); // value - lua_rawset(gL, -5); // table - CONS_Printf("Hook removed.\n"); - } - else - { - if (lua_toboolean(gL, -1)) - hooked = true; - lua_pop(gL, 1); - } - } - - lua_pop(gL, 2); // pop mobj and subtable - // the stack should now be empty. - - lua_gc(gL, LUA_GCSTEP, 3); + lua_gc(gL, LUA_GCSTEP, 1); return hooked; } boolean LUAh_PlayerHook(player_t *plr, enum hook which) { + hook_p hookp; boolean hooked = false; if (!gL || !(hooksAvailable[which/8] & (1<<(which%8)))) return false; - // clear the stack (just in case) lua_pop(gL, -1); - - // hook table - lua_getfield(gL, LUA_REGISTRYINDEX, "hook"); - I_Assert(lua_istable(gL, -1)); - lua_rawgeti(gL, -1, which); - lua_remove(gL, -2); - I_Assert(lua_istable(gL, -1)); - LUA_PushUserdata(gL, plr, META_PLAYER); - lua_pushnil(gL); - while (lua_next(gL, -3) != 0) { - lua_pushvalue(gL, -3); // player - if (lua_pcall(gL, 1, 1, 0)) { // pops hook function, player, pushes 1 return result - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL,-1)); + for (hookp = roothook; hookp; hookp = hookp->next) + if (hookp->type == which) + { + lua_pushfstring(gL, FMT_HOOKID, hookp->id); + lua_gettable(gL, LUA_REGISTRYINDEX); + lua_pushvalue(gL, -2); + if (lua_pcall(gL, 1, 1, 0)) { + if (!hookp->error || cv_debug & DBG_LUA) + CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); + lua_pop(gL, 1); + hookp->error = true; + continue; + } + if (lua_toboolean(gL, -1)) + hooked = true; lua_pop(gL, 1); - continue; } - if (lua_toboolean(gL, -1)) // if return true, - hooked = true; // override vanilla behavior - lua_pop(gL, 1); // pop return value - } - lua_pop(gL, -1); + lua_pop(gL, 1); + lua_gc(gL, LUA_GCSTEP, 1); return hooked; } @@ -365,21 +245,22 @@ boolean LUAh_PlayerHook(player_t *plr, enum hook which) // Hook for map change (before load) void LUAh_MapChange(void) { + hook_p hookp; if (!gL || !(hooksAvailable[hook_MapChange/8] & (1<<(hook_MapChange%8)))) return; - lua_getfield(gL, LUA_REGISTRYINDEX, "hook"); - I_Assert(lua_istable(gL, -1)); - lua_rawgeti(gL, -1, hook_MapChange); - lua_remove(gL, -2); - I_Assert(lua_istable(gL, -1)); - + lua_pop(gL, -1); lua_pushinteger(gL, gamemap); - lua_pushnil(gL); - while (lua_next(gL, -3) != 0) { - lua_pushvalue(gL, -3); // gamemap - LUA_Call(gL, 1); - } + + for (hookp = roothook; hookp; hookp = hookp->next) + if (hookp->type == hook_MapChange) + { + lua_pushfstring(gL, FMT_HOOKID, hookp->id); + lua_gettable(gL, LUA_REGISTRYINDEX); + lua_pushvalue(gL, -2); + LUA_Call(gL, 1); + } + lua_pop(gL, 1); lua_gc(gL, LUA_GCSTEP, 1); } @@ -387,182 +268,112 @@ void LUAh_MapChange(void) // Hook for map load void LUAh_MapLoad(void) { + hook_p hookp; if (!gL || !(hooksAvailable[hook_MapLoad/8] & (1<<(hook_MapLoad%8)))) return; lua_pop(gL, -1); - - lua_getfield(gL, LUA_REGISTRYINDEX, "hook"); - I_Assert(lua_istable(gL, -1)); - lua_rawgeti(gL, -1, hook_MapLoad); - lua_remove(gL, -2); - I_Assert(lua_istable(gL, -1)); - lua_pushinteger(gL, gamemap); - lua_pushnil(gL); - while (lua_next(gL, -3) != 0) { - lua_pushvalue(gL, -3); // gamemap - LUA_Call(gL, 1); - } - lua_pop(gL, -1); - lua_gc(gL, LUA_GCCOLLECT, 0); + + for (hookp = roothook; hookp; hookp = hookp->next) + if (hookp->type == hook_MapLoad) + { + lua_pushfstring(gL, FMT_HOOKID, hookp->id); + lua_gettable(gL, LUA_REGISTRYINDEX); + lua_pushvalue(gL, -2); + LUA_Call(gL, 1); + } + + lua_pop(gL, 1); + lua_gc(gL, LUA_GCSTEP, 1); } // Hook for Got_AddPlayer void LUAh_PlayerJoin(int playernum) { + hook_p hookp; if (!gL || !(hooksAvailable[hook_PlayerJoin/8] & (1<<(hook_PlayerJoin%8)))) return; lua_pop(gL, -1); - - lua_getfield(gL, LUA_REGISTRYINDEX, "hook"); - I_Assert(lua_istable(gL, -1)); - lua_rawgeti(gL, -1, hook_PlayerJoin); - lua_remove(gL, -2); - I_Assert(lua_istable(gL, -1)); - lua_pushinteger(gL, playernum); - lua_pushnil(gL); - while (lua_next(gL, -3) != 0) { - lua_pushvalue(gL, -3); // playernum - LUA_Call(gL, 1); - } - lua_pop(gL, -1); + + for (hookp = roothook; hookp; hookp = hookp->next) + if (hookp->type == hook_PlayerJoin) + { + lua_pushfstring(gL, FMT_HOOKID, hookp->id); + lua_gettable(gL, LUA_REGISTRYINDEX); + lua_pushvalue(gL, -2); + LUA_Call(gL, 1); + } + + lua_pop(gL, 1); lua_gc(gL, LUA_GCCOLLECT, 0); } // Hook for frame (after mobj and player thinkers) void LUAh_ThinkFrame(void) { + hook_p hookp; if (!gL || !(hooksAvailable[hook_ThinkFrame/8] & (1<<(hook_ThinkFrame%8)))) return; lua_pop(gL, -1); - lua_getfield(gL, LUA_REGISTRYINDEX, "hook"); - I_Assert(lua_istable(gL, -1)); - lua_rawgeti(gL, -1, hook_ThinkFrame); - lua_remove(gL, -2); - I_Assert(lua_istable(gL, -1)); - - lua_pushnil(gL); - while (lua_next(gL, -2) != 0) - { - //LUA_Call(gL, 0); - if (lua_pcall(gL, 0, 0, 0)) + for (hookp = roothook; hookp; hookp = hookp->next) + if (hookp->type == hook_ThinkFrame) { - // A run-time error occurred. - CONS_Alert(CONS_WARNING,"%s\n", lua_tostring(gL, -1)); - lua_pop(gL, 1); - // Remove this function from the hook table to prevent further errors. - lua_pushvalue(gL, -1); // key - lua_pushnil(gL); // value - lua_rawset(gL, -4); // table - CONS_Printf("Hook removed.\n"); + lua_pushfstring(gL, FMT_HOOKID, hookp->id); + lua_gettable(gL, LUA_REGISTRYINDEX); + if (lua_pcall(gL, 0, 0, 0)) { + if (!hookp->error || cv_debug & DBG_LUA) + CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); + lua_pop(gL, 1); + hookp->error = true; + } } - } - lua_pop(gL, -1); - lua_gc(gL, LUA_GCCOLLECT, 0); -} - -// Hook for PIT_CheckThing by (thing) mobj type (thing1 = thing, thing2 = tmthing) -UINT8 LUAh_MobjCollide(mobj_t *thing1, mobj_t *thing2) -{ - UINT8 shouldCollide = 0; // 0 = default, 1 = force yes, 2 = force no. - if (!gL || !(hooksAvailable[hook_MobjCollide/8] & (1<<(hook_MobjCollide%8)))) - return 0; - - // clear the stack - lua_pop(gL, -1); - - // hook table - lua_getfield(gL, LUA_REGISTRYINDEX, "hook"); - I_Assert(lua_istable(gL, -1)); - lua_rawgeti(gL, -1, hook_MobjCollide); - lua_remove(gL, -2); - I_Assert(lua_istable(gL, -1)); - - // mobjtype subtable - lua_rawgeti(gL, -1, thing1->type); - if (lua_isnil(gL, -1)) { - lua_pop(gL, 2); - return 0; - } - lua_remove(gL, -2); // remove hook table - - LUA_PushUserdata(gL, thing1, META_MOBJ); - LUA_PushUserdata(gL, thing2, META_MOBJ); - lua_pushnil(gL); - while (lua_next(gL, -4)) { - lua_pushvalue(gL, -4); // thing1 - lua_pushvalue(gL, -4); // thing2 - if (lua_pcall(gL, 2, 1, 0)) { - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL,-1)); - lua_pop(gL, 1); - continue; - } - if (!lua_isnil(gL, -1)) - { // if nil, leave shouldCollide = 0. - if (lua_toboolean(gL, -1)) - shouldCollide = 1; // Force yes - else - shouldCollide = 2; // Force no - } - lua_pop(gL, 1); // pop return value - } - lua_pop(gL, 3); // pop arguments and mobjtype table lua_gc(gL, LUA_GCSTEP, 1); - return shouldCollide; } -// Hook for PIT_CheckThing by (tmthing) mobj type (thing1 = tmthing, thing2 = thing) -UINT8 LUAh_MobjMoveCollide(mobj_t *thing1, mobj_t *thing2) +// Hook for mobj collisions +UINT8 LUAh_MobjCollideHook(mobj_t *thing1, mobj_t *thing2, enum hook which) { + hook_p hookp; UINT8 shouldCollide = 0; // 0 = default, 1 = force yes, 2 = force no. - if (!gL || !(hooksAvailable[hook_MobjMoveCollide/8] & (1<<(hook_MobjMoveCollide%8)))) + if (!gL || !(hooksAvailable[which/8] & (1<<(which%8)))) return 0; - // clear the stack lua_pop(gL, -1); - - // hook table - lua_getfield(gL, LUA_REGISTRYINDEX, "hook"); - I_Assert(lua_istable(gL, -1)); - lua_rawgeti(gL, -1, hook_MobjMoveCollide); - lua_remove(gL, -2); - I_Assert(lua_istable(gL, -1)); - - // mobjtype subtable - lua_rawgeti(gL, -1, thing1->type); - if (lua_isnil(gL, -1)) { - lua_pop(gL, 2); - return 0; - } - lua_remove(gL, -2); // remove hook table - LUA_PushUserdata(gL, thing1, META_MOBJ); LUA_PushUserdata(gL, thing2, META_MOBJ); - lua_pushnil(gL); - while (lua_next(gL, -4)) { - lua_pushvalue(gL, -4); // thing1 - lua_pushvalue(gL, -4); // thing2 - if (lua_pcall(gL, 2, 1, 0)) { - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL,-1)); + + for (hookp = roothook; hookp; hookp = hookp->next) + if (hookp->type == which + && (hookp->s.mt == MT_NULL || hookp->s.mt == thing1->type)) + { + lua_pushfstring(gL, FMT_HOOKID, hookp->id); + lua_gettable(gL, LUA_REGISTRYINDEX); + lua_pushvalue(gL, -3); + lua_pushvalue(gL, -3); + if (lua_pcall(gL, 2, 1, 0)) { + if (!hookp->error || cv_debug & DBG_LUA) + CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); + lua_pop(gL, 1); + hookp->error = true; + continue; + } + if (!lua_isnil(gL, -1)) + { // if nil, leave shouldCollide = 0. + if (lua_toboolean(gL, -1)) + shouldCollide = 1; // Force yes + else + shouldCollide = 2; // Force no + } lua_pop(gL, 1); - continue; } - if (!lua_isnil(gL, -1)) - { // if nil, leave shouldCollide = 0. - if (lua_toboolean(gL, -1)) - shouldCollide = 1; // Force yes - else - shouldCollide = 2; // Force no - } - lua_pop(gL, 1); // pop return value - } - lua_pop(gL, 3); // pop arguments and mobjtype table + + lua_pop(gL, 2); lua_gc(gL, LUA_GCSTEP, 1); return shouldCollide; @@ -571,47 +382,37 @@ UINT8 LUAh_MobjMoveCollide(mobj_t *thing1, mobj_t *thing2) // Hook for P_TouchSpecialThing by mobj type boolean LUAh_TouchSpecial(mobj_t *special, mobj_t *toucher) { + hook_p hookp; boolean hooked = false; if (!gL || !(hooksAvailable[hook_TouchSpecial/8] & (1<<(hook_TouchSpecial%8)))) - return false; + return 0; - // clear the stack lua_pop(gL, -1); - - // get hook table - lua_getfield(gL, LUA_REGISTRYINDEX, "hook"); - I_Assert(lua_istable(gL, -1)); - lua_rawgeti(gL, -1, hook_TouchSpecial); - lua_remove(gL, -2); - I_Assert(lua_istable(gL, -1)); - - // get mobjtype subtable - lua_pushinteger(gL, special->type); - lua_rawget(gL, 1); - if (lua_isnil(gL, -1)) { - lua_pop(gL, 2); - return false; - } - lua_remove(gL, 1); // pop hook table off the stack - LUA_PushUserdata(gL, special, META_MOBJ); LUA_PushUserdata(gL, toucher, META_MOBJ); - lua_pushnil(gL); - while (lua_next(gL, 1) != 0) { - lua_pushvalue(gL, 2); // special - lua_pushvalue(gL, 3); // toucher - if (lua_pcall(gL, 2, 1, 0)) { // pops hook function, special, toucher, pushes 1 return result - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL,-1)); + for (hookp = roothook; hookp; hookp = hookp->next) + if (hookp->type == hook_TouchSpecial + && (hookp->s.mt == MT_NULL || hookp->s.mt == special->type)) + { + lua_pushfstring(gL, FMT_HOOKID, hookp->id); + lua_gettable(gL, LUA_REGISTRYINDEX); + lua_pushvalue(gL, -3); + lua_pushvalue(gL, -3); + if (lua_pcall(gL, 2, 1, 0)) { + if (!hookp->error || cv_debug & DBG_LUA) + CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); + lua_pop(gL, 1); + hookp->error = true; + continue; + } + if (lua_toboolean(gL, -1)) + hooked = true; lua_pop(gL, 1); - continue; } - if (lua_toboolean(gL, -1)) // if return true, - hooked = true; // override vanilla behavior - lua_pop(gL, 1); // pop return value - } - lua_pop(gL, -1); + lua_pop(gL, 2); + lua_gc(gL, LUA_GCSTEP, 1); return hooked; } @@ -619,53 +420,45 @@ boolean LUAh_TouchSpecial(mobj_t *special, mobj_t *toucher) // Hook for P_DamageMobj by mobj type (Should mobj take damage?) UINT8 LUAh_ShouldDamage(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 damage) { + hook_p hookp; UINT8 shouldDamage = 0; // 0 = default, 1 = force yes, 2 = force no. if (!gL || !(hooksAvailable[hook_ShouldDamage/8] & (1<<(hook_ShouldDamage%8)))) return 0; - // clear the stack lua_pop(gL, -1); - - // hook table - lua_getfield(gL, LUA_REGISTRYINDEX, "hook"); - I_Assert(lua_istable(gL, -1)); - lua_rawgeti(gL, -1, hook_ShouldDamage); - lua_remove(gL, -2); - I_Assert(lua_istable(gL, -1)); - - // mobjtype subtable - lua_rawgeti(gL, -1, target->type); - if (lua_isnil(gL, -1)) { - lua_pop(gL, 2); - return 0; - } - lua_remove(gL, -2); // remove hook table - LUA_PushUserdata(gL, target, META_MOBJ); LUA_PushUserdata(gL, inflictor, META_MOBJ); LUA_PushUserdata(gL, source, META_MOBJ); lua_pushinteger(gL, damage); - lua_pushnil(gL); - while (lua_next(gL, -6)) { - lua_pushvalue(gL, -6); // target - lua_pushvalue(gL, -6); // inflictor - lua_pushvalue(gL, -6); // source - lua_pushvalue(gL, -6); // damage - if (lua_pcall(gL, 4, 1, 0)) { - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL,-1)); + + for (hookp = roothook; hookp; hookp = hookp->next) + if (hookp->type == hook_ShouldDamage + && (hookp->s.mt == MT_NULL || hookp->s.mt == target->type)) + { + lua_pushfstring(gL, FMT_HOOKID, hookp->id); + lua_gettable(gL, LUA_REGISTRYINDEX); + lua_pushvalue(gL, -5); + lua_pushvalue(gL, -5); + lua_pushvalue(gL, -5); + lua_pushvalue(gL, -5); + if (lua_pcall(gL, 4, 1, 0)) { + if (!hookp->error || cv_debug & DBG_LUA) + CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); + lua_pop(gL, 1); + hookp->error = true; + continue; + } + if (!lua_isnil(gL, -1)) + { + if (lua_toboolean(gL, -1)) + shouldDamage = 1; // Force yes + else + shouldDamage = 2; // Force no + } lua_pop(gL, 1); - continue; } - if (!lua_isnil(gL, -1)) - { // if nil, leave shouldDamage = 0. - if (lua_toboolean(gL, -1)) - shouldDamage = 1; // Force yes - else - shouldDamage = 2; // Force no - } - lua_pop(gL, 1); // pop return value - } - lua_pop(gL, 5); // pop arguments and mobjtype table + + lua_pop(gL, 4); lua_gc(gL, LUA_GCSTEP, 1); return shouldDamage; @@ -674,136 +467,118 @@ UINT8 LUAh_ShouldDamage(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 // Hook for P_DamageMobj by mobj type (Mobj actually takes damage!) boolean LUAh_MobjDamage(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 damage) { - boolean handled = false; + hook_p hookp; + boolean hooked = false; if (!gL || !(hooksAvailable[hook_MobjDamage/8] & (1<<(hook_MobjDamage%8)))) - return false; + return 0; - // clear the stack lua_pop(gL, -1); - - // hook table - lua_getfield(gL, LUA_REGISTRYINDEX, "hook"); - I_Assert(lua_istable(gL, -1)); - lua_rawgeti(gL, -1, hook_MobjDamage); - lua_remove(gL, -2); - I_Assert(lua_istable(gL, -1)); - - // mobjtype subtable - lua_rawgeti(gL, -1, target->type); - if (lua_isnil(gL, -1)) { - lua_pop(gL, 2); - return false; - } - lua_remove(gL, -2); // remove hook table - LUA_PushUserdata(gL, target, META_MOBJ); LUA_PushUserdata(gL, inflictor, META_MOBJ); LUA_PushUserdata(gL, source, META_MOBJ); lua_pushinteger(gL, damage); - lua_pushnil(gL); - while (lua_next(gL, -6)) { - lua_pushvalue(gL, -6); // target - lua_pushvalue(gL, -6); // inflictor - lua_pushvalue(gL, -6); // source - lua_pushvalue(gL, -6); // damage - if (lua_pcall(gL, 4, 1, 0)) { - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL,-1)); + + for (hookp = roothook; hookp; hookp = hookp->next) + if (hookp->type == hook_MobjDamage + && (hookp->s.mt == MT_NULL || hookp->s.mt == target->type)) + { + lua_pushfstring(gL, FMT_HOOKID, hookp->id); + lua_gettable(gL, LUA_REGISTRYINDEX); + lua_pushvalue(gL, -5); + lua_pushvalue(gL, -5); + lua_pushvalue(gL, -5); + lua_pushvalue(gL, -5); + if (lua_pcall(gL, 4, 1, 0)) { + if (!hookp->error || cv_debug & DBG_LUA) + CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); + lua_pop(gL, 1); + hookp->error = true; + continue; + } + if (lua_toboolean(gL, -1)) + hooked = true; lua_pop(gL, 1); - continue; } - if (lua_toboolean(gL, -1)) - handled = true; - lua_pop(gL, 1); // pop return value - } - lua_pop(gL, 5); // pop arguments and mobjtype table + + lua_pop(gL, 4); lua_gc(gL, LUA_GCSTEP, 1); - return handled; + return hooked; } // Hook for P_KillMobj by mobj type boolean LUAh_MobjDeath(mobj_t *target, mobj_t *inflictor, mobj_t *source) { - boolean handled = false; + hook_p hookp; + boolean hooked = false; if (!gL || !(hooksAvailable[hook_MobjDeath/8] & (1<<(hook_MobjDeath%8)))) - return false; + return 0; - // clear the stack lua_pop(gL, -1); - - // hook table - lua_getfield(gL, LUA_REGISTRYINDEX, "hook"); - I_Assert(lua_istable(gL, -1)); - lua_rawgeti(gL, -1, hook_MobjDeath); - lua_remove(gL, -2); - I_Assert(lua_istable(gL, -1)); - - // mobjtype subtable - lua_rawgeti(gL, -1, target->type); - if (lua_isnil(gL, -1)) { - lua_pop(gL, 2); - return false; - } - lua_remove(gL, -2); // remove hook table - LUA_PushUserdata(gL, target, META_MOBJ); LUA_PushUserdata(gL, inflictor, META_MOBJ); LUA_PushUserdata(gL, source, META_MOBJ); - lua_pushnil(gL); - while (lua_next(gL, -5)) { - lua_pushvalue(gL, -5); // target - lua_pushvalue(gL, -5); // inflictor - lua_pushvalue(gL, -5); // source - if (lua_pcall(gL, 3, 1, 0)) { - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL,-1)); + + for (hookp = roothook; hookp; hookp = hookp->next) + if (hookp->type == hook_MobjDeath + && (hookp->s.mt == MT_NULL || hookp->s.mt == target->type)) + { + lua_pushfstring(gL, FMT_HOOKID, hookp->id); + lua_gettable(gL, LUA_REGISTRYINDEX); + lua_pushvalue(gL, -4); + lua_pushvalue(gL, -4); + lua_pushvalue(gL, -4); + if (lua_pcall(gL, 3, 1, 0)) { + if (!hookp->error || cv_debug & DBG_LUA) + CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); + lua_pop(gL, 1); + hookp->error = true; + continue; + } + if (lua_toboolean(gL, -1)) + hooked = true; lua_pop(gL, 1); - continue; } - if (lua_toboolean(gL, -1)) - handled = true; - lua_pop(gL, 1); // pop return value - } - lua_pop(gL, 4); // pop arguments and mobjtype table + + lua_pop(gL, 3); lua_gc(gL, LUA_GCSTEP, 1); - return handled; + return hooked; } // Hook for B_BuildTiccmd boolean LUAh_BotTiccmd(player_t *bot, ticcmd_t *cmd) { + hook_p hookp; boolean hooked = false; if (!gL || !(hooksAvailable[hook_BotTiccmd/8] & (1<<(hook_BotTiccmd%8)))) return false; - // clear the stack lua_pop(gL, -1); - - // hook table - lua_getfield(gL, LUA_REGISTRYINDEX, "hook"); - I_Assert(lua_istable(gL, -1)); - lua_rawgeti(gL, -1, hook_BotTiccmd); - lua_remove(gL, -2); - I_Assert(lua_istable(gL, -1)); - LUA_PushUserdata(gL, bot, META_PLAYER); LUA_PushUserdata(gL, cmd, META_TICCMD); - lua_pushnil(gL); - while (lua_next(gL, 1)) { - lua_pushvalue(gL, 2); // bot - lua_pushvalue(gL, 3); // cmd - if (lua_pcall(gL, 2, 1, 0)) { - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL,-1)); + for (hookp = roothook; hookp; hookp = hookp->next) + if (hookp->type == hook_BotTiccmd) + { + lua_pushfstring(gL, FMT_HOOKID, hookp->id); + lua_gettable(gL, LUA_REGISTRYINDEX); + lua_pushvalue(gL, -3); + lua_pushvalue(gL, -3); + if (lua_pcall(gL, 2, 1, 0)) { + if (!hookp->error || cv_debug & DBG_LUA) + CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); + lua_pop(gL, 1); + hookp->error = true; + continue; + } + if (lua_toboolean(gL, -1)) + hooked = true; lua_pop(gL, 1); - continue; } - if (lua_toboolean(gL, -1)) - hooked = true; - lua_pop(gL, 1); // pop return value - } - lua_pop(gL, -1); + lua_pop(gL, 2); + lua_gc(gL, LUA_GCSTEP, 1); return hooked; } @@ -811,117 +586,107 @@ boolean LUAh_BotTiccmd(player_t *bot, ticcmd_t *cmd) // Hook for B_BuildTailsTiccmd by skin name boolean LUAh_BotAI(mobj_t *sonic, mobj_t *tails, ticcmd_t *cmd) { - if (!gL || !tails->skin || !(hooksAvailable[hook_BotAI/8] & (1<<(hook_BotAI%8)))) + hook_p hookp; + boolean hooked = false; + int n; + if (!gL || !(hooksAvailable[hook_BotAI/8] & (1<<(hook_BotAI%8)))) return false; - // clear the stack lua_pop(gL, -1); - - // hook table - lua_getfield(gL, LUA_REGISTRYINDEX, "hook"); - I_Assert(lua_istable(gL, -1)); - lua_rawgeti(gL, -1, hook_BotAI); - lua_remove(gL, -2); - I_Assert(lua_istable(gL, -1)); - - // bot skin ai function - lua_getfield(gL, 1, ((skin_t *)tails->skin)->name); - if (lua_isnil(gL, -1)) { - lua_pop(gL, 2); - return false; - } - lua_remove(gL, 1); // pop the hook table - - // Takes sonic, tails - // Returns forward, backward, left, right, jump, spin LUA_PushUserdata(gL, sonic, META_MOBJ); LUA_PushUserdata(gL, tails, META_MOBJ); - if (lua_pcall(gL, 2, 8, 0)) { - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL,-1)); - lua_pop(gL,-1); - return false; - } + n = lua_gettop(gL); - // This turns forward, backward, left, right, jump, and spin into a proper ticcmd for tails. - if (lua_istable(gL, 1)) { - boolean forward=false, backward=false, left=false, right=false, strafeleft=false, straferight=false, jump=false, spin=false; + for (hookp = roothook; hookp; hookp = hookp->next) + if (hookp->type == hook_BotAI + && (hookp->s.skinname == NULL || !strcmp(hookp->s.skinname, ((skin_t*)tails->skin)->name))) + { + lua_pushfstring(gL, FMT_HOOKID, hookp->id); + lua_gettable(gL, LUA_REGISTRYINDEX); + lua_pushvalue(gL, -3); + lua_pushvalue(gL, -3); + if (lua_pcall(gL, 2, 8, 0)) { + if (!hookp->error || cv_debug & DBG_LUA) + CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); + lua_pop(gL, 1); + hookp->error = true; + continue; + } + // This turns forward, backward, left, right, jump, and spin into a proper ticcmd for tails. + if (lua_istable(gL, n+1)) { + boolean forward=false, backward=false, left=false, right=false, strafeleft=false, straferight=false, jump=false, spin=false; #define CHECKFIELD(field) \ - lua_getfield(gL, 1, #field);\ - if (lua_toboolean(gL, -1))\ - field = true;\ - lua_pop(gL, 1); - - CHECKFIELD(forward) - CHECKFIELD(backward) - CHECKFIELD(left) - CHECKFIELD(right) - CHECKFIELD(strafeleft) - CHECKFIELD(straferight) - CHECKFIELD(jump) - CHECKFIELD(spin) + lua_getfield(gL, n+1, #field);\ + if (lua_toboolean(gL, -1))\ + field = true;\ + lua_pop(gL, 1); + CHECKFIELD(forward) + CHECKFIELD(backward) + CHECKFIELD(left) + CHECKFIELD(right) + CHECKFIELD(strafeleft) + CHECKFIELD(straferight) + CHECKFIELD(jump) + CHECKFIELD(spin) #undef CHECKFIELD + B_KeysToTiccmd(tails, cmd, forward, backward, left, right, strafeleft, straferight, jump, spin); + } else + B_KeysToTiccmd(tails, cmd, lua_toboolean(gL, n+1), lua_toboolean(gL, n+2), lua_toboolean(gL, n+3), lua_toboolean(gL, n+4), lua_toboolean(gL, n+5), lua_toboolean(gL, n+6), lua_toboolean(gL, n+7), lua_toboolean(gL, n+8)); - B_KeysToTiccmd(tails, cmd, forward, backward, left, right, strafeleft, straferight, jump, spin); - } else - B_KeysToTiccmd(tails, cmd, lua_toboolean(gL, 1), lua_toboolean(gL, 2), lua_toboolean(gL, 3), lua_toboolean(gL, 4), lua_toboolean(gL, 5), lua_toboolean(gL, 6), lua_toboolean(gL, 7), lua_toboolean(gL, 8)); + lua_pop(gL, 8); + hooked = true; + } + + lua_pop(gL, 2); - lua_pop(gL, -1); lua_gc(gL, LUA_GCSTEP, 1); - return true; + return hooked; } // Hook for linedef executors boolean LUAh_LinedefExecute(line_t *line, mobj_t *mo, sector_t *sector) { + hook_p hookp; + boolean hooked = false; if (!gL || !(hooksAvailable[hook_LinedefExecute/8] & (1<<(hook_LinedefExecute%8)))) - return false; + return 0; - // clear the stack lua_pop(gL, -1); - - // get hook table - lua_getfield(gL, LUA_REGISTRYINDEX, "hook"); - I_Assert(lua_istable(gL, -1)); - lua_rawgeti(gL, -1, hook_LinedefExecute); - lua_remove(gL, -2); - I_Assert(lua_istable(gL, -1)); - - // get function by line text - lua_getfield(gL, 1, line->text); - if (lua_isnil(gL, -1)) { - lua_pop(gL, 2); - return false; - } - lua_remove(gL, 1); // pop hook table off the stack - LUA_PushUserdata(gL, line, META_LINE); LUA_PushUserdata(gL, mo, META_MOBJ); LUA_PushUserdata(gL, sector, META_SECTOR); - LUA_Call(gL, 3); // pops hook function, line, mo, sector - lua_pop(gL, -1); + for (hookp = roothook; hookp; hookp = hookp->next) + if (hookp->type == hook_LinedefExecute + && !strcmp(hookp->s.funcname, line->text)) + { + lua_pushfstring(gL, FMT_HOOKID, hookp->id); + lua_gettable(gL, LUA_REGISTRYINDEX); + lua_pushvalue(gL, -4); + lua_pushvalue(gL, -4); + lua_pushvalue(gL, -4); + LUA_Call(gL, 3); + hooked = true; + } + + lua_pop(gL, 3); + lua_gc(gL, LUA_GCSTEP, 1); - return true; + return hooked; } -// Hook for PlayerMsg -Red +// Hook for player chat boolean LUAh_PlayerMsg(int source, int target, int flags, char *msg) { - boolean handled = false; - + hook_p hookp; + boolean hooked = false; if (!gL || !(hooksAvailable[hook_PlayerMsg/8] & (1<<(hook_PlayerMsg%8)))) return false; - lua_getfield(gL, LUA_REGISTRYINDEX, "hook"); - I_Assert(lua_istable(gL, -1)); - lua_rawgeti(gL, -1, hook_PlayerMsg); - lua_remove(gL, -2); - I_Assert(lua_istable(gL, -1)); - + lua_pop(gL, -1); LUA_PushUserdata(gL, &players[source], META_PLAYER); // Source player - if (flags & 2 /*HU_CSAY*/) { // csay TODO: make HU_CSAY accessible outside hu_stuff.c lua_pushinteger(gL, 3); // type lua_pushnil(gL); // target @@ -935,70 +700,73 @@ boolean LUAh_PlayerMsg(int source, int target, int flags, char *msg) lua_pushinteger(gL, 2); // type LUA_PushUserdata(gL, &players[target-1], META_PLAYER); // target } - lua_pushstring(gL, msg); // msg - lua_pushnil(gL); - - while (lua_next(gL, -6)) { - lua_pushvalue(gL, -6); // source - lua_pushvalue(gL, -6); // type - lua_pushvalue(gL, -6); // target - lua_pushvalue(gL, -6); // msg - if (lua_pcall(gL, 4, 1, 0)) { - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL,-1)); + for (hookp = roothook; hookp; hookp = hookp->next) + if (hookp->type == hook_PlayerMsg) + { + lua_pushfstring(gL, FMT_HOOKID, hookp->id); + lua_gettable(gL, LUA_REGISTRYINDEX); + lua_pushvalue(gL, -5); + lua_pushvalue(gL, -5); + lua_pushvalue(gL, -5); + lua_pushvalue(gL, -5); + if (lua_pcall(gL, 4, 1, 0)) { + if (!hookp->error || cv_debug & DBG_LUA) + CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); + lua_pop(gL, 1); + hookp->error = true; + continue; + } + if (lua_toboolean(gL, -1)) + hooked = true; lua_pop(gL, 1); - continue; } - if (lua_toboolean(gL, -1)) - handled = true; - lua_pop(gL, 1); // pop return value - } - lua_pop(gL, 4); // pop arguments and mobjtype table + + lua_pop(gL, 4); lua_gc(gL, LUA_GCSTEP, 1); - return handled; + return hooked; } -// Hook for hurt messages -Red -// The internal name is DeathMsg, but the API name is "HurtMsg". Keep that in mind. (Should this be fixed at some point?) -// @TODO This hook should be fixed to take mobj type at the addHook parameter to compare to inflictor. (I couldn't get this to work without crashing) -boolean LUAh_DeathMsg(player_t *player, mobj_t *inflictor, mobj_t *source) +// Hook for hurt messages +boolean LUAh_HurtMsg(player_t *player, mobj_t *inflictor, mobj_t *source) { - boolean handled = false; - - if (!gL || !(hooksAvailable[hook_DeathMsg/8] & (1<<(hook_DeathMsg%8)))) + hook_p hookp; + boolean hooked = false; + if (!gL || !(hooksAvailable[hook_HurtMsg/8] & (1<<(hook_HurtMsg%8)))) return false; - lua_getfield(gL, LUA_REGISTRYINDEX, "hook"); - I_Assert(lua_istable(gL, -1)); - lua_rawgeti(gL, -1, hook_DeathMsg); - lua_remove(gL, -2); - I_Assert(lua_istable(gL, -1)); + lua_pop(gL, -1); + LUA_PushUserdata(gL, player, META_PLAYER); + LUA_PushUserdata(gL, inflictor, META_MOBJ); + LUA_PushUserdata(gL, source, META_MOBJ); - LUA_PushUserdata(gL, player, META_PLAYER); // Player - LUA_PushUserdata(gL, inflictor, META_MOBJ); // Inflictor - LUA_PushUserdata(gL, source, META_MOBJ); // Source - - lua_pushnil(gL); - - while (lua_next(gL, -5)) { - lua_pushvalue(gL, -5); // player - lua_pushvalue(gL, -5); // inflictor - lua_pushvalue(gL, -5); // source - if (lua_pcall(gL, 3, 1, 0)) { - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL,-1)); + for (hookp = roothook; hookp; hookp = hookp->next) + if (hookp->type == hook_HurtMsg + && (hookp->s.mt == MT_NULL || (inflictor && hookp->s.mt == inflictor->type))) + { + lua_pushfstring(gL, FMT_HOOKID, hookp->id); + lua_gettable(gL, LUA_REGISTRYINDEX); + lua_pushvalue(gL, -4); + lua_pushvalue(gL, -4); + lua_pushvalue(gL, -4); + if (lua_pcall(gL, 3, 1, 0)) { + if (!hookp->error || cv_debug & DBG_LUA) + CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); + lua_pop(gL, 1); + hookp->error = true; + continue; + } + if (lua_toboolean(gL, -1)) + hooked = true; lua_pop(gL, 1); - continue; } - if (lua_toboolean(gL, -1)) - handled = true; - lua_pop(gL, 1); // pop return value - } - lua_pop(gL, 3); // pop arguments and mobjtype table + + lua_pop(gL, 3); lua_gc(gL, LUA_GCSTEP, 1); - return handled; + return hooked; } #endif diff --git a/src/p_inter.c b/src/p_inter.c index 8eaa4765a..478bd459c 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -1478,7 +1478,7 @@ static void P_HitDeathMessages(player_t *player, mobj_t *inflictor, mobj_t *sour return; // Presumably it's obvious what's happening in splitscreen. #ifdef HAVE_BLUA - if (LUAh_DeathMsg(player, inflictor, source)) + if (LUAh_HurtMsg(player, inflictor, source)) return; #endif