From 6372cdaa4182d4f9c21f0f359d8e5f95ba20d979 Mon Sep 17 00:00:00 2001 From: Major Cooke Date: Wed, 12 Dec 2018 21:36:20 -0600 Subject: [PATCH] Split off pain chance triggering from ReactToDamage into its own function and gave ZScript access to it. - TriggerPainChance(Name mod, bool forcedPain) - One exception: PainThrehold is only checked in ReactToDamage, since this function does not require checking damage amount. --- src/p_interaction.cpp | 125 ++++++++++++++++++++------------ wadsrc/static/zscript/actor.txt | 1 + 2 files changed, 80 insertions(+), 46 deletions(-) diff --git a/src/p_interaction.cpp b/src/p_interaction.cpp index d35a6ad88..03f670b5e 100644 --- a/src/p_interaction.cpp +++ b/src/p_interaction.cpp @@ -788,6 +788,7 @@ void P_AutoUseStrifeHealth (player_t *player) // ReactToDamage // //========================================================================== +static bool TriggerPainChance(AActor *target, FName mod, bool forcedPain, bool zscript); static inline bool MustForcePain(AActor *target, AActor *inflictor) { @@ -809,7 +810,7 @@ static void ReactToDamage(AActor *target, AActor *inflictor, AActor *source, int bool forcedPain = false; bool noPain = false; - // Dead or non-existent entity, do not react. + // Dead or non-existent entity, do not react. Especially if the damage is cancelled. if (target == nullptr || target->health < 1 || damage < 0) return; @@ -848,53 +849,14 @@ static void ReactToDamage(AActor *target, AActor *inflictor, AActor *source, int } if (!noPain && - (target->player != nullptr || !G_SkillProperty(SKILLP_NoPain)) && !(target->flags & MF_SKULLFLY)) + ((target->player != nullptr || !G_SkillProperty(SKILLP_NoPain)) && !(target->flags & MF_SKULLFLY)) + && damage >= target->PainThreshold) { - painchance = target->PainChance; - for (auto & pc : target->GetInfo()->PainChances) - { - if (pc.first == mod) - { - painchance = pc.second; - break; - } - } + if (inflictor && inflictor->PainType != NAME_None) + mod = inflictor->PainType; - if (forcedPain || ((damage >= target->PainThreshold) && (pr_damagemobj() < painchance))) - { - if (mod == NAME_Electric) - { - if (pr_lightning() < 96) - { - justhit = true; - FState *painstate = target->FindState(NAME_Pain, mod); - if (painstate != NULL) - target->SetState(painstate); - } - else - { // "electrocute" the target - target->renderflags |= RF_FULLBRIGHT; - if ((target->flags3 & MF3_ISMONSTER) && pr_lightning() < 128) - { - target->Howl(); - } - } - } - else - { - justhit = true; - FState *painstate = target->FindState(NAME_Pain, ((inflictor && inflictor->PainType != NAME_None) ? inflictor->PainType : mod)); - if (painstate != NULL) - target->SetState(painstate); - if (mod == NAME_PoisonCloud) - { - if ((target->flags3 & MF3_ISMONSTER) && pr_poison() < 128) - { - target->Howl(); - } - } - } - } + // Not called from ZScript. + justhit = TriggerPainChance(target, mod, forcedPain, false); } if (target->player == nullptr) target->reactiontime = 0; // we're awake now... @@ -935,6 +897,77 @@ static void ReactToDamage(AActor *target, AActor *inflictor, AActor *source, int target->flags |= MF_JUSTHIT; // fight back! } +static bool TriggerPainChance(AActor *target, FName mod = NAME_None, bool forcedPain = false, bool zscript = false) +{ + if (target == nullptr || target->flags5 & MF5_NOPAIN || target->health < 1) + return false; + + bool justhit = false, flinched = false; + int painchance = target->PainChance; + for (auto & pc : target->GetInfo()->PainChances) + { + if (pc.first == mod) + { + painchance = pc.second; + break; + } + } + + if (forcedPain || (pr_damagemobj() < painchance)) + { + if (mod == NAME_Electric) + { + if (pr_lightning() < 96) + { + justhit = true; + FState *painstate = target->FindState(NAME_Pain, mod); + if (painstate != NULL) + { + flinched = true; + target->SetState(painstate); + } + } + else + { // "electrocute" the target + target->renderflags |= RF_FULLBRIGHT; + if ((target->flags3 & MF3_ISMONSTER) && pr_lightning() < 128) + { + target->Howl(); + } + } + } + else + { + justhit = true; + FState *painstate = target->FindState(NAME_Pain, mod); + if (painstate != NULL) + { + flinched = true; + target->SetState(painstate); + } + if (mod == NAME_PoisonCloud) + { + if ((target->flags3 & MF3_ISMONSTER) && pr_poison() < 128) + { + target->Howl(); + } + } + } + } + return (zscript) ? flinched : justhit; +} + +// TriggerPainChance directly from DECORATE/ZScript will return if the +// entity flinched or not. + +DEFINE_ACTION_FUNCTION(AActor, TriggerPainChance) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_NAME(mod); + PARAM_BOOL(forcedPain); + ACTION_RETURN_BOOL(TriggerPainChance(self, mod, forcedPain, true)); +} + /* ================= = diff --git a/wadsrc/static/zscript/actor.txt b/wadsrc/static/zscript/actor.txt index a63f51bcd..9fc91d7c3 100644 --- a/wadsrc/static/zscript/actor.txt +++ b/wadsrc/static/zscript/actor.txt @@ -666,6 +666,7 @@ class Actor : Thinker native native void SetIdle(bool nofunction = false); native bool CheckMeleeRange(); + 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 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);