From ed4477705d7e3610d4168a54ad60b834834ba1a4 Mon Sep 17 00:00:00 2001 From: Latapostrophe Date: Tue, 27 Nov 2018 18:27:43 +0100 Subject: [PATCH] Separated the damage hooks into multiple more precise hooks for players. --- src/k_kart.c | 42 +++++-- src/k_kart.h | 2 +- src/lua_baselib.c | 5 +- src/lua_hook.h | 13 +++ src/lua_hooklib.c | 286 +++++++++++++++++++++++++++++++++++++++++++++- src/p_inter.c | 2 +- src/p_map.c | 8 +- src/p_user.c | 2 +- 8 files changed, 340 insertions(+), 20 deletions(-) diff --git a/src/k_kart.c b/src/k_kart.c index dec6b0d2..8c2e8916 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -1845,11 +1845,11 @@ void K_SpawnBattlePoints(player_t *source, player_t *victim, UINT8 amount) void K_SpinPlayer(player_t *player, mobj_t *source, INT32 type, boolean trapitem, mobj_t *inflictor) { - + (void)inflictor; // in case some weirdo doesn't want Lua. // PS: Inflictor is unused for all purposes here and is actually only ever relevant to Lua. It may be nil too. #ifdef HAVE_BLUA - boolean force = false; // Used to check if Lua ShouldDamage should get us damaged reguardless of flashtics or heck knows what. - UINT8 shouldForce = LUAh_ShouldDamage(player->mo, inflictor, source, 1); + boolean force = false; // Used to check if Lua ShouldSpin should get us damaged reguardless of flashtics or heck knows what. + UINT8 shouldForce = LUAh_ShouldSpin(player, inflictor, source); if (P_MobjWasRemoved(player->mo)) return; // mobj was removed (in theory that shouldn't happen) if (shouldForce == 1) @@ -1884,7 +1884,7 @@ void K_SpinPlayer(player_t *player, mobj_t *source, INT32 type, boolean trapitem } } - if (LUAh_MobjDamage(player->mo, inflictor, source, 1)) + if (LUAh_PlayerSpin(player, inflictor, source)) // Let Lua do its thing or overwrite if it wants to. Make sure to let any possible instashield happen because we didn't get "damaged" in this case. return; if (source && source != player->mo && source->player) @@ -1963,8 +1963,24 @@ void K_SpinPlayer(player_t *player, mobj_t *source, INT32 type, boolean trapitem return; } -void K_SquishPlayer(player_t *player, mobj_t *source) +void K_SquishPlayer(player_t *player, mobj_t *source, mobj_t *inflictor) { + (void)inflictor; // Please stop forgetting to put inflictor in yer functions thank -Lat' + + // PS: Inflictor is unused for all purposes here and is actually only ever relevant to Lua. It may be nil too. +#ifdef HAVE_BLUA + boolean force = false; // Used to check if Lua ShouldSquish should get us damaged reguardless of flashtics or heck knows what. + UINT8 shouldForce = LUAh_ShouldSquish(player, inflictor, source); + if (P_MobjWasRemoved(player->mo)) + return; // mobj was removed (in theory that shouldn't happen) + if (shouldForce == 1) + force = true; + else if (shouldForce == 2) + return; +#else + static const boolean force = false; +#endif + UINT8 scoremultiply = 1; if (G_BattleGametype()) { @@ -1981,10 +1997,16 @@ void K_SquishPlayer(player_t *player, mobj_t *source) || player->kartstuff[k_growshrinktimer] > 0 || player->kartstuff[k_hyudorotimer] > 0 || (G_BattleGametype() && ((player->kartstuff[k_bumper] <= 0 && player->kartstuff[k_comebacktimer]) || player->kartstuff[k_comebackmode] == 1))) { - K_DoInstashield(player); - return; + if (!force) // You know the drill by now. + { + K_DoInstashield(player); + return; + } } + if (LUAh_PlayerSquish(player, inflictor, source)) // Let Lua do its thing or overwrite if it wants to. Make sure to let any possible instashield happen because we didn't get "damaged" in this case. + return; + player->kartstuff[k_sneakertimer] = 0; player->kartstuff[k_driftboost] = 0; @@ -2054,8 +2076,8 @@ void K_ExplodePlayer(player_t *player, mobj_t *source, mobj_t *inflictor) // A b { #ifdef HAVE_BLUA - boolean force = false; // Used to check if Lua ShouldDamage should get us damaged reguardless of flashtics or heck knows what. - UINT8 shouldForce = LUAh_ShouldDamage(player->mo, inflictor, source, 1); + boolean force = false; // Used to check if Lua ShouldExplode should get us damaged reguardless of flashtics or heck knows what. + UINT8 shouldForce = LUAh_ShouldExplode(player, inflictor, source); if (P_MobjWasRemoved(player->mo)) return; // mobj was removed (in theory that shouldn't happen) if (shouldForce == 1) @@ -2089,7 +2111,7 @@ void K_ExplodePlayer(player_t *player, mobj_t *source, mobj_t *inflictor) // A b } } - if (LUAh_MobjDamage(player->mo, inflictor, source, 1)) + if (LUAh_PlayerExplode(player, inflictor, source)) // Same thing. Also make sure to let Instashield happen blah blah return; if (source && source != player->mo && source->player) diff --git a/src/k_kart.h b/src/k_kart.h index 72a03e97..d191af97 100644 --- a/src/k_kart.h +++ b/src/k_kart.h @@ -29,7 +29,7 @@ void K_KartPlayerAfterThink(player_t *player); void K_DoInstashield(player_t *player); void K_SpawnBattlePoints(player_t *source, player_t *victim, UINT8 amount); void K_SpinPlayer(player_t *player, mobj_t *source, INT32 type, boolean trapitem, mobj_t *inflictor); -void K_SquishPlayer(player_t *player, mobj_t *source); +void K_SquishPlayer(player_t *player, mobj_t *source, mobj_t *inflictor); void K_ExplodePlayer(player_t *player, mobj_t *source, mobj_t *inflictor); void K_StealBumper(player_t *player, player_t *victim, boolean force); void K_SpawnKartExplosion(fixed_t x, fixed_t y, fixed_t z, fixed_t radius, INT32 number, mobjtype_t type, angle_t rotangle, boolean spawncenter, boolean ghostit, mobj_t *source); diff --git a/src/lua_baselib.c b/src/lua_baselib.c index c6d810c8..97eb5cf1 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -2207,12 +2207,15 @@ static int lib_kSquishPlayer(lua_State *L) { player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER)); mobj_t *source = NULL; + mobj_t *inflictor = NULL; NOHUD if (!player) return LUA_ErrInvalid(L, "player_t"); if (!lua_isnone(L, 2) && lua_isuserdata(L, 2)) source = *((mobj_t **)luaL_checkudata(L, 2, META_MOBJ)); - K_SquishPlayer(player, source); + if (!lua_isnone(L, 2) && lua_isuserdata(L, 2)) + inflictor = *((mobj_t **)luaL_checkudata(L, 2, META_MOBJ)); + K_SquishPlayer(player, source, inflictor); return 0; } diff --git a/src/lua_hook.h b/src/lua_hook.h index 26b70570..485db43f 100644 --- a/src/lua_hook.h +++ b/src/lua_hook.h @@ -44,6 +44,12 @@ enum hook { hook_HurtMsg, hook_PlayerSpawn, hook_PlayerQuit, + hook_ShouldSpin, //SRB2KART + hook_ShouldExplode, //SRB2KART + hook_ShouldSquish, //SRB2KART + hook_PlayerSpin, //SRB2KART + hook_PlayerExplode, //SRB2KART + hook_PlayerSquish, //SRB2KART hook_MAX // last hook }; @@ -80,4 +86,11 @@ boolean LUAh_HurtMsg(player_t *player, mobj_t *inflictor, mobj_t *source); // Ho #define LUAh_PlayerSpawn(player) LUAh_PlayerHook(player, hook_PlayerSpawn) // Hook for G_SpawnPlayer void LUAh_PlayerQuit(player_t *plr, int reason); // Hook for player quitting +UINT8 LUAh_ShouldSpin(player_t *player, mobj_t *inflictor, mobj_t *source); // SRB2KART: Should player be spun out? +UINT8 LUAh_ShouldExplode(player_t *player, mobj_t *inflictor, mobj_t *source); // SRB2KART: Should player be exploded? +UINT8 LUAh_ShouldSquish(player_t *player, mobj_t *inflictor, mobj_t *source); // SRB2KART: Should player be squished? + +boolean LUAh_PlayerSpin(player_t *player, mobj_t *inflictor, mobj_t *source); // SRB2KART: Hook for K_SpinPlayer. Allows Lua to execute code and/or overwrite its behavior. +boolean LUAh_PlayerExplode(player_t *player, mobj_t *inflictor, mobj_t *source); // SRB2KART: Hook for K_ExplodePlayer. Allows Lua to execute code and/or overwrite its behavior. +boolean LUAh_PlayerSquish(player_t *player, mobj_t *inflictor, mobj_t *source); // SRB2KART: Hook for K_SquishPlayer. Allows Lua to execute code and/or overwrite its behavior. #endif diff --git a/src/lua_hooklib.c b/src/lua_hooklib.c index f06e28cd..89a6db20 100644 --- a/src/lua_hooklib.c +++ b/src/lua_hooklib.c @@ -55,6 +55,12 @@ const char *const hookNames[hook_MAX+1] = { "HurtMsg", "PlayerSpawn", "PlayerQuit", + "ShouldSpin", + "ShouldExplode", + "ShouldSquish", + "PlayerSpin", + "PlayerExplode", + "PlayerSquish", NULL }; @@ -154,6 +160,12 @@ static int lib_addHook(lua_State *L) *p = 0; } break; + case hook_ShouldSpin: + case hook_ShouldExplode: + case hook_ShouldSquish: + case hook_PlayerSpin: + case hook_PlayerExplode: + case hook_PlayerSquish: default: break; } @@ -195,6 +207,12 @@ static int lib_addHook(lua_State *L) case hook_LinedefExecute: lastp = &linedefexecutorhooks; break; + case hook_ShouldSpin: + case hook_ShouldExplode: + case hook_ShouldSquish: + case hook_PlayerSpin: + case hook_PlayerExplode: + case hook_PlayerSquish: default: lastp = &roothook; break; @@ -953,7 +971,7 @@ boolean LUAh_LinedefExecute(line_t *line, mobj_t *mo, sector_t *sector) } // Hook for player chat -// Added the "mute" field. It's set to true if the message was supposed to be eaten by spam protection. +// Added the "mute" field. It's set to true if the message was supposed to be eaten by spam protection. // But for netgame consistency purposes, this hook is ran first reguardless, so this boolean allows for modders to adapt if they so desire. boolean LUAh_PlayerMsg(int source, int target, int flags, char *msg, int mute) { @@ -987,7 +1005,7 @@ boolean LUAh_PlayerMsg(int source, int target, int flags, char *msg, int mute) if (mute) lua_pushboolean(gL, true); // the message was supposed to be eaten by spamprotecc. else - lua_pushboolean(gL, false); + lua_pushboolean(gL, false); } lua_pushfstring(gL, FMT_HOOKID, hookp->id); lua_gettable(gL, LUA_REGISTRYINDEX); @@ -1108,4 +1126,268 @@ void LUAh_PlayerQuit(player_t *plr, int reason) lua_settop(gL, 0); } +// Hook for K_SpinPlayer. Determines if yes or no we should get damaged reguardless of circumstances. +UINT8 LUAh_ShouldSpin(player_t *player, mobj_t *inflictor, mobj_t *source) +{ + hook_p hookp; + UINT8 shouldDamage = 0; // 0 = default, 1 = force yes, 2 = force no. + if (!gL || !(hooksAvailable[hook_ShouldSpin/8] & (1<<(hook_ShouldSpin%8)))) + return 0; + + lua_settop(gL, 0); + + // We can afford not to check for mobj type because it will always be MT_PLAYER in this case. + + for (hookp = roothook; hookp; hookp = hookp->next) + if (hookp->type == hook_ShouldSpin) + { + if (lua_gettop(gL) == 0) + { + LUA_PushUserdata(gL, player, META_PLAYER); + LUA_PushUserdata(gL, inflictor, META_MOBJ); + LUA_PushUserdata(gL, source, META_MOBJ); + } + 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_isnil(gL, -1)) + { + if (lua_toboolean(gL, -1)) + shouldDamage = 1; // Force yes + else + shouldDamage = 2; // Force no + } + lua_pop(gL, 1); + } + + lua_settop(gL, 0); + return shouldDamage; +} + +// Hook for K_ExplodePlayer. Determines if yes or no we should get damaged reguardless of circumstances. +UINT8 LUAh_ShouldExplode(player_t *player, mobj_t *inflictor, mobj_t *source) +{ + hook_p hookp; + UINT8 shouldDamage = 0; // 0 = default, 1 = force yes, 2 = force no. + if (!gL || !(hooksAvailable[hook_ShouldExplode/8] & (1<<(hook_ShouldExplode%8)))) + return 0; + + lua_settop(gL, 0); + + // We can afford not to check for mobj type because it will always be MT_PLAYER in this case. + + for (hookp = roothook; hookp; hookp = hookp->next) + if (hookp->type == hook_ShouldExplode) + { + if (lua_gettop(gL) == 0) + { + LUA_PushUserdata(gL, player, META_PLAYER); + LUA_PushUserdata(gL, inflictor, META_MOBJ); + LUA_PushUserdata(gL, source, META_MOBJ); + } + 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_isnil(gL, -1)) + { + if (lua_toboolean(gL, -1)) + shouldDamage = 1; // Force yes + else + shouldDamage = 2; // Force no + } + lua_pop(gL, 1); + } + + lua_settop(gL, 0); + return shouldDamage; +} + +// Hook for K_SquishPlayer. Determines if yes or no we should get damaged reguardless of circumstances. +UINT8 LUAh_ShouldSquish(player_t *player, mobj_t *inflictor, mobj_t *source) +{ + hook_p hookp; + UINT8 shouldDamage = 0; // 0 = default, 1 = force yes, 2 = force no. + if (!gL || !(hooksAvailable[hook_ShouldSquish/8] & (1<<(hook_ShouldSquish%8)))) + return 0; + + lua_settop(gL, 0); + + // We can afford not to check for mobj type because it will always be MT_PLAYER in this case. + + for (hookp = roothook; hookp; hookp = hookp->next) + if (hookp->type == hook_ShouldSquish) + { + if (lua_gettop(gL) == 0) + { + LUA_PushUserdata(gL, player, META_PLAYER); + LUA_PushUserdata(gL, inflictor, META_MOBJ); + LUA_PushUserdata(gL, source, META_MOBJ); + } + 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_isnil(gL, -1)) + { + if (lua_toboolean(gL, -1)) + shouldDamage = 1; // Force yes + else + shouldDamage = 2; // Force no + } + lua_pop(gL, 1); + } + + lua_settop(gL, 0); + return shouldDamage; +} + +// Hook for K_SpinPlayer. This is used when the player has actually been spun out, but before anything has actually been done. This allows Lua to overwrite the behavior or to just perform actions. +boolean LUAh_PlayerSpin(player_t *player, mobj_t *inflictor, mobj_t *source) +{ + hook_p hookp; + boolean hooked = false; + if (!gL || !(hooksAvailable[hook_PlayerSpin/8] & (1<<(hook_PlayerSpin%8)))) + return 0; + + lua_settop(gL, 0); + + // We can afford not to look for target->type because it will always be MT_PLAYER. + + for (hookp = roothook; hookp; hookp = hookp->next) + if (hookp->type == hook_PlayerSpin) + { + if (lua_gettop(gL) == 0) + { + LUA_PushUserdata(gL, player, META_PLAYER); + LUA_PushUserdata(gL, inflictor, META_MOBJ); + LUA_PushUserdata(gL, source, META_MOBJ); + } + 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); + } + lua_settop(gL, 0); + return hooked; +} + +// Hook for K_SquishPlayer. This is used when the player has actually been spun out, but before anything has actually been done. This allows Lua to overwrite the behavior or to just perform actions. +boolean LUAh_PlayerSquish(player_t *player, mobj_t *inflictor, mobj_t *source) +{ + hook_p hookp; + boolean hooked = false; + if (!gL || !(hooksAvailable[hook_PlayerSquish/8] & (1<<(hook_PlayerSquish%8)))) + return 0; + + lua_settop(gL, 0); + + // We can afford not to look for target->type because it will always be MT_PLAYER. + + for (hookp = roothook; hookp; hookp = hookp->next) + if (hookp->type == hook_PlayerSquish) + { + if (lua_gettop(gL) == 0) + { + LUA_PushUserdata(gL, player, META_PLAYER); + LUA_PushUserdata(gL, inflictor, META_MOBJ); + LUA_PushUserdata(gL, source, META_MOBJ); + } + 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); + } + lua_settop(gL, 0); + return hooked; +} + +// Hook for K_ExplodePlayer. This is used when the player has actually been spun out, but before anything has actually been done. This allows Lua to overwrite the behavior or to just perform actions. +boolean LUAh_PlayerExplode(player_t *player, mobj_t *inflictor, mobj_t *source) +{ + hook_p hookp; + boolean hooked = false; + if (!gL || !(hooksAvailable[hook_PlayerExplode/8] & (1<<(hook_PlayerExplode%8)))) + return 0; + + lua_settop(gL, 0); + + // We can afford not to look for target->type because it will always be MT_PLAYER. + + for (hookp = roothook; hookp; hookp = hookp->next) + if (hookp->type == hook_PlayerExplode) + { + if (lua_gettop(gL) == 0) + { + LUA_PushUserdata(gL, player, META_PLAYER); + LUA_PushUserdata(gL, inflictor, META_MOBJ); + LUA_PushUserdata(gL, source, META_MOBJ); + } + 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); + } + lua_settop(gL, 0); + return hooked; +} + #endif diff --git a/src/p_inter.c b/src/p_inter.c index 7838db2c..717e8139 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -590,7 +590,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) P_RemoveMobj(special); } else - K_SpinPlayer(player, special, 0, false, NULL); + K_SpinPlayer(player, NULL, 0, false, special); return; /*case MT_EERIEFOG: special->frame &= ~FF_TRANS80; diff --git a/src/p_map.c b/src/p_map.c index c33a2dd5..6d8579df 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -1425,9 +1425,9 @@ static boolean PIT_CheckThing(mobj_t *thing) { if (tmthing->scale > thing->scale + (mapheaderinfo[gamemap-1]->mobj_scale/8)) // SRB2kart - Handle squishes first! - K_SquishPlayer(thing->player, tmthing); + K_SquishPlayer(thing->player, tmthing, tmthing); else if (thing->scale > tmthing->scale + (mapheaderinfo[gamemap-1]->mobj_scale/8)) - K_SquishPlayer(tmthing->player, thing); + K_SquishPlayer(tmthing->player, thing, tmthing); else if (tmthing->player->kartstuff[k_invincibilitytimer] && !thing->player->kartstuff[k_invincibilitytimer]) // SRB2kart - Then invincibility! P_DamageMobj(thing, tmthing, tmthing, 1); else if (thing->player->kartstuff[k_invincibilitytimer] && !tmthing->player->kartstuff[k_invincibilitytimer]) @@ -1664,7 +1664,7 @@ static boolean PIT_CheckThing(mobj_t *thing) // collide if (tmthing->z < thing->z && thing->momz < 0) - K_SquishPlayer(tmthing->player, thing); + K_SquishPlayer(tmthing->player, thing, thing); else { if (thing->flags2 & MF2_AMBUSH) @@ -4262,7 +4262,7 @@ static boolean PIT_ChangeSector(mobj_t *thing, boolean realcrush) if (!thing->player) P_DamageMobj(thing, killer, killer, 10000); else - K_SquishPlayer(thing->player, killer); // SRB2kart - Squish instead of kill + K_SquishPlayer(thing->player, killer, killer); // SRB2kart - Squish instead of kill } } } diff --git a/src/p_user.c b/src/p_user.c index b0caec59..296f3b0c 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -7242,7 +7242,7 @@ static void P_MovePlayer(player_t *player) P_DamageMobj(player->mo, NULL, NULL, 42000); // Respawn crushed spectators else { - K_SquishPlayer(player, NULL); // SRB2kart - we don't kill when squished, we squish when squished. + K_SquishPlayer(player, NULL, NULL); // SRB2kart - we don't kill when squished, we squish when squished. /* mobj_t *killer = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_NULL); killer->threshold = 44; // Special flag that it was crushing which killed you.