From 8071fd13685553f08910058668d0581d4d3ed702 Mon Sep 17 00:00:00 2001 From: Boondorl Date: Tue, 17 Jun 2025 17:28:24 -0400 Subject: [PATCH] Scriptified ReactToDamage Allows pain handling to be overridden without needing to override the entirety of DamageMobj. --- src/playsim/p_interaction.cpp | 47 ++++++++++++++++++++++----- wadsrc/static/zscript/actors/actor.zs | 1 + 2 files changed, 40 insertions(+), 8 deletions(-) diff --git a/src/playsim/p_interaction.cpp b/src/playsim/p_interaction.cpp index 5202041f3..6cd3aa6c8 100644 --- a/src/playsim/p_interaction.cpp +++ b/src/playsim/p_interaction.cpp @@ -859,8 +859,9 @@ static inline bool isFakePain(AActor *target, AActor *inflictor, int damage) } // [MC] Completely ripped out of DamageMobj to make it less messy. -static void ReactToDamage(AActor *target, AActor *inflictor, AActor *source, int damage, FName mod, int flags, int originaldamage) +static int ReactToDamage(AActor *target, AActor *inflictor, AActor *source, int damage, int mod, int flags, int originaldamage) { + FName modName = ENamedName(mod); bool justhit = false; int painchance = 0; FState *woundstate = nullptr; @@ -871,17 +872,17 @@ static void ReactToDamage(AActor *target, AActor *inflictor, AActor *source, int // Dead or non-existent entity, do not react. Especially if the damage is cancelled. if (target == nullptr || target->health < 1 || damage < 0) - return; + return false; player_t *player = target->player; if (player && player->mo) { if ((player->cheats & CF_GODMODE2) || (player->mo->flags5 & MF5_NOPAIN) || ((player->cheats & CF_GODMODE) && damage < TELEFRAG_DAMAGE)) - return; + return false; } - woundstate = target->FindState(NAME_Wound, mod); + woundstate = target->FindState(NAME_Wound, modName); if (woundstate != nullptr) { int woundhealth = target->WoundHealth; @@ -889,7 +890,7 @@ static void ReactToDamage(AActor *target, AActor *inflictor, AActor *source, int if (target->health <= woundhealth) { target->SetState(woundstate); - return; + return true; } } // [MC] NOPAIN will not stop the actor from waking up if damaged. @@ -904,10 +905,10 @@ static void ReactToDamage(AActor *target, AActor *inflictor, AActor *source, int && (forcedPain || damage >= target->PainThreshold)) { if (inflictor && inflictor->PainType != NAME_None) - mod = inflictor->PainType; + modName = inflictor->PainType; // Not called from ZScript. - justhit = TriggerPainChance(target, mod, forcedPain, false); + justhit = TriggerPainChance(target, modName, forcedPain, false); } if (wakeup && target->player == nullptr) target->reactiontime = 0; // we're awake now... @@ -946,6 +947,36 @@ static void ReactToDamage(AActor *target, AActor *inflictor, AActor *source, int // killough 11/98: Don't attack a friend, unless hit by that friend. if (justhit && (target->target == source || !target->target || !target->IsFriend(target->target))) target->flags |= MF_JUSTHIT; // fight back! + + return justhit; +} + +static int CallReactToDamage(AActor* target, AActor* inflictor, AActor* source, int damage, FName mod, int flags, int originaldamage) +{ + int res = false; + IFVIRTUALPTR(target, AActor, ReactToDamage) + { + res = VMCallSingle(func, target, inflictor, source, damage, mod.GetIndex(), flags, originaldamage); + } + else + { + res = ReactToDamage(target, inflictor, source, damage, mod.GetIndex(), flags, originaldamage); + } + + return res; +} + +DEFINE_ACTION_FUNCTION_NATIVE(AActor, ReactToDamage, ReactToDamage) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_OBJECT(inflictor, AActor); + PARAM_OBJECT(source, AActor); + PARAM_INT(damage); + PARAM_NAME(mod); + PARAM_INT(flags); + PARAM_INT(originaldamage); + + ACTION_RETURN_BOOL(ReactToDamage(self, inflictor, source, damage, mod.GetIndex(), flags, originaldamage)); } static bool TriggerPainChance(AActor *target, FName mod = NAME_None, bool forcedPain = false, bool zscript = false) @@ -1537,7 +1568,7 @@ static int DoDamageMobj(AActor *target, AActor *inflictor, AActor *source, int d bool needevent = true; int realdamage = DamageMobj(target, inflictor, source, damage, mod, flags, angle, needevent); if (realdamage >= 0) //Keep this check separated. Mods relying upon negative numbers may break otherwise. - ReactToDamage(target, inflictor, source, realdamage, mod, flags, damage); + CallReactToDamage(target, inflictor, source, realdamage, mod, flags, damage); if (realdamage > 0 && needevent) { diff --git a/wadsrc/static/zscript/actors/actor.zs b/wadsrc/static/zscript/actors/actor.zs index 0bc9ee76f..15bd68236 100644 --- a/wadsrc/static/zscript/actors/actor.zs +++ b/wadsrc/static/zscript/actors/actor.zs @@ -826,6 +826,7 @@ class Actor : Thinker native native bool CheckMeleeRange(double range = -1); native bool TriggerPainChance(Name mod, bool forcedPain = false); native virtual int DamageMobj(Actor inflictor, Actor source, int damage, Name mod, int flags = 0, double angle = 0); + native virtual bool ReactToDamage(Actor inflictor, Actor source, int damage, Name mod, int flags, int originaldamage); native void PoisonMobj (Actor inflictor, Actor source, int damage, int duration, int period, Name type); native double AimLineAttack(double angle, double distance, out FTranslatedLineTarget pLineTarget = null, double vrange = 0., int flags = 0, Actor target = null, Actor friender = null); native Actor, int LineAttack(double angle, double distance, double pitch, int damage, Name damageType, class pufftype, int flags = 0, out FTranslatedLineTarget victim = null, double offsetz = 0., double offsetforward = 0., double offsetside = 0.);