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.
This commit is contained in:
Major Cooke 2018-12-12 21:36:20 -06:00 committed by Christoph Oelckers
parent 2f7fae2fb0
commit 6372cdaa41
2 changed files with 80 additions and 46 deletions

View file

@ -788,6 +788,7 @@ void P_AutoUseStrifeHealth (player_t *player)
// ReactToDamage // ReactToDamage
// //
//========================================================================== //==========================================================================
static bool TriggerPainChance(AActor *target, FName mod, bool forcedPain, bool zscript);
static inline bool MustForcePain(AActor *target, AActor *inflictor) 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 forcedPain = false;
bool noPain = 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) if (target == nullptr || target->health < 1 || damage < 0)
return; return;
@ -848,53 +849,14 @@ static void ReactToDamage(AActor *target, AActor *inflictor, AActor *source, int
} }
if (!noPain && 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; if (inflictor && inflictor->PainType != NAME_None)
for (auto & pc : target->GetInfo()->PainChances) mod = inflictor->PainType;
{
if (pc.first == mod)
{
painchance = pc.second;
break;
}
}
if (forcedPain || ((damage >= target->PainThreshold) && (pr_damagemobj() < painchance))) // Not called from ZScript.
{ justhit = TriggerPainChance(target, mod, forcedPain, false);
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();
}
}
}
}
} }
if (target->player == nullptr) target->reactiontime = 0; // we're awake now... 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! 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));
}
/* /*
================= =================
= =

View file

@ -666,6 +666,7 @@ class Actor : Thinker native
native void SetIdle(bool nofunction = false); native void SetIdle(bool nofunction = false);
native bool CheckMeleeRange(); 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 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 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 double AimLineAttack(double angle, double distance, out FTranslatedLineTarget pLineTarget = null, double vrange = 0., int flags = 0, Actor target = null, Actor friender = null);