mirror of
https://github.com/ZDoom/qzdoom.git
synced 2024-11-28 15:02:01 +00:00
DamageMobj Refactor
- Split off all reactive functionality (pain, infighting, etc) into its own function, ReactToDamage. - Refactored all DamageMobj's damage <= 0 values. - Any unconditional cancellations now return -1. ReactToDamage will not be called if values < 0. - All pain/wound/target changing allowances return 0.
This commit is contained in:
parent
d2d684a35a
commit
2f7fae2fb0
1 changed files with 184 additions and 221 deletions
|
@ -783,6 +783,158 @@ void P_AutoUseStrifeHealth (player_t *player)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// ReactToDamage
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
static inline bool MustForcePain(AActor *target, AActor *inflictor)
|
||||||
|
{
|
||||||
|
return (inflictor && (inflictor->flags6 & MF6_FORCEPAIN));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool isFakePain(AActor *target, AActor *inflictor, int damage)
|
||||||
|
{
|
||||||
|
return ((target->flags7 & MF7_ALLOWPAIN && damage > 0) || (inflictor && (inflictor->flags7 & MF7_CAUSEPAIN)));
|
||||||
|
}
|
||||||
|
|
||||||
|
// [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)
|
||||||
|
{
|
||||||
|
bool justhit = false;
|
||||||
|
int painchance = 0;
|
||||||
|
FState *woundstate = nullptr;
|
||||||
|
bool fakedPain = false;
|
||||||
|
bool forcedPain = false;
|
||||||
|
bool noPain = false;
|
||||||
|
|
||||||
|
// Dead or non-existent entity, do not react.
|
||||||
|
if (target == nullptr || target->health < 1 || damage < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
player_t *player = target->player;
|
||||||
|
if (player)
|
||||||
|
{
|
||||||
|
if ((player->cheats & CF_GODMODE2) || (player->mo->flags5 & MF5_NOPAIN) ||
|
||||||
|
((player->cheats & CF_GODMODE) && damage < TELEFRAG_DAMAGE))
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
noPain = (flags & DMG_NO_PAIN) || (target->flags5 & MF5_NOPAIN) || (inflictor && (inflictor->flags5 & MF5_PAINLESS));
|
||||||
|
|
||||||
|
// Are we attempting to cause pain?
|
||||||
|
if (!noPain)
|
||||||
|
{
|
||||||
|
fakedPain = (isFakePain(target, inflictor, damage));
|
||||||
|
forcedPain = (MustForcePain(target, inflictor));
|
||||||
|
}
|
||||||
|
|
||||||
|
// [MC] No forced or faked pain so skip it.
|
||||||
|
// However the rest of the function must carry on.
|
||||||
|
if (!noPain && damage < 1 && !fakedPain && !forcedPain)
|
||||||
|
noPain = true;
|
||||||
|
|
||||||
|
woundstate = target->FindState(NAME_Wound, mod);
|
||||||
|
if (woundstate != NULL)
|
||||||
|
{
|
||||||
|
int woundhealth = target->WoundHealth;
|
||||||
|
|
||||||
|
if (target->health <= woundhealth)
|
||||||
|
{
|
||||||
|
target->SetState(woundstate);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!noPain &&
|
||||||
|
(target->player != nullptr || !G_SkillProperty(SKILLP_NoPain)) && !(target->flags & MF_SKULLFLY))
|
||||||
|
{
|
||||||
|
painchance = target->PainChance;
|
||||||
|
for (auto & pc : target->GetInfo()->PainChances)
|
||||||
|
{
|
||||||
|
if (pc.first == mod)
|
||||||
|
{
|
||||||
|
painchance = pc.second;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (target->player == nullptr) target->reactiontime = 0; // we're awake now...
|
||||||
|
if (source)
|
||||||
|
{
|
||||||
|
if (source == target->target)
|
||||||
|
{
|
||||||
|
target->threshold = target->DefThreshold;
|
||||||
|
if (target->state == target->SpawnState && target->SeeState != NULL)
|
||||||
|
{
|
||||||
|
target->SetState(target->SeeState);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (source != target->target && target->CallOkayToSwitchTarget(source))
|
||||||
|
{
|
||||||
|
// Target actor is not intent on another actor,
|
||||||
|
// so make him chase after source
|
||||||
|
|
||||||
|
// killough 2/15/98: remember last enemy, to prevent
|
||||||
|
// sleeping early; 2/21/98: Place priority on players
|
||||||
|
|
||||||
|
if (target->lastenemy == NULL ||
|
||||||
|
(target->lastenemy->player == NULL && target->TIDtoHate == 0) ||
|
||||||
|
target->lastenemy->health <= 0)
|
||||||
|
{
|
||||||
|
target->lastenemy = target->target; // remember last enemy - killough
|
||||||
|
}
|
||||||
|
target->target = source;
|
||||||
|
target->threshold = target->DefThreshold;
|
||||||
|
if (target->state == target->SpawnState && target->SeeState != NULL)
|
||||||
|
{
|
||||||
|
target->SetState(target->SeeState);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 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!
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
=================
|
=================
|
||||||
=
|
=
|
||||||
|
@ -798,16 +950,6 @@ void P_AutoUseStrifeHealth (player_t *player)
|
||||||
==================
|
==================
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static inline bool MustForcePain(AActor *target, AActor *inflictor)
|
|
||||||
{
|
|
||||||
return (inflictor && (inflictor->flags6 & MF6_FORCEPAIN));
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline bool isFakePain(AActor *target, AActor *inflictor, int damage)
|
|
||||||
{
|
|
||||||
return ((target->flags7 & MF7_ALLOWPAIN && damage > 0) || ((inflictor != NULL) && (inflictor->flags7 & MF7_CAUSEPAIN)));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Returns the amount of damage actually inflicted upon the target, or -1 if
|
// Returns the amount of damage actually inflicted upon the target, or -1 if
|
||||||
// the damage was cancelled.
|
// the damage was cancelled.
|
||||||
|
@ -815,16 +957,8 @@ static int DamageMobj (AActor *target, AActor *inflictor, AActor *source, int da
|
||||||
{
|
{
|
||||||
player_t *player = NULL;
|
player_t *player = NULL;
|
||||||
int temp;
|
int temp;
|
||||||
int painchance = 0;
|
|
||||||
FState * woundstate = NULL;
|
|
||||||
bool justhit = false;
|
bool justhit = false;
|
||||||
bool plrDontThrust = false;
|
bool plrDontThrust = false;
|
||||||
bool invulpain = false;
|
|
||||||
bool fakedPain = false;
|
|
||||||
bool forcedPain = false;
|
|
||||||
bool noPain = false;
|
|
||||||
int fakeDamage = 0;
|
|
||||||
int holdDamage = 0;
|
|
||||||
const int rawdamage = damage;
|
const int rawdamage = damage;
|
||||||
const bool telefragDamage = (rawdamage >= TELEFRAG_DAMAGE);
|
const bool telefragDamage = (rawdamage >= TELEFRAG_DAMAGE);
|
||||||
|
|
||||||
|
@ -832,32 +966,23 @@ static int DamageMobj (AActor *target, AActor *inflictor, AActor *source, int da
|
||||||
|
|
||||||
if (target == NULL || !((target->flags & MF_SHOOTABLE) || (target->flags6 & MF6_VULNERABLE)))
|
if (target == NULL || !((target->flags & MF_SHOOTABLE) || (target->flags6 & MF6_VULNERABLE)))
|
||||||
{ // Shouldn't happen
|
{ // Shouldn't happen
|
||||||
return 0;
|
return -1;
|
||||||
}
|
}
|
||||||
FName MeansOfDeath = mod;
|
FName MeansOfDeath = mod;
|
||||||
|
|
||||||
// Rather than unnecessarily call the function over and over again, let's be a little more efficient.
|
|
||||||
// But first, check and see if it's even needed, which it won't be if pain must not be triggered.
|
|
||||||
noPain = ((flags & DMG_NO_PAIN) || (target->flags5 & MF5_NOPAIN) || (inflictor && (inflictor->flags5 & MF5_PAINLESS)));
|
|
||||||
if (!noPain)
|
|
||||||
{
|
|
||||||
fakedPain = (isFakePain(target, inflictor, damage));
|
|
||||||
forcedPain = (MustForcePain(target, inflictor));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Spectral targets only take damage from spectral projectiles.
|
// Spectral targets only take damage from spectral projectiles.
|
||||||
if (target->flags4 & MF4_SPECTRAL && !telefragDamage)
|
if (target->flags4 & MF4_SPECTRAL && !telefragDamage)
|
||||||
{
|
{
|
||||||
if (inflictor == NULL || !(inflictor->flags4 & MF4_SPECTRAL))
|
if (inflictor == NULL || !(inflictor->flags4 & MF4_SPECTRAL))
|
||||||
{
|
{
|
||||||
return 0;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (target->health <= 0)
|
if (target->health <= 0)
|
||||||
{
|
{
|
||||||
if (inflictor && mod == NAME_Ice && !(inflictor->flags7 & MF7_ICESHATTER))
|
if (inflictor && mod == NAME_Ice && !(inflictor->flags7 & MF7_ICESHATTER))
|
||||||
{
|
{
|
||||||
return 0;
|
return -1;
|
||||||
}
|
}
|
||||||
else if (target->flags & MF_ICECORPSE) // frozen
|
else if (target->flags & MF_ICECORPSE) // frozen
|
||||||
{
|
{
|
||||||
|
@ -865,7 +990,7 @@ static int DamageMobj (AActor *target, AActor *inflictor, AActor *source, int da
|
||||||
target->flags6 |= MF6_SHATTERING;
|
target->flags6 |= MF6_SHATTERING;
|
||||||
target->Vel.Zero();
|
target->Vel.Zero();
|
||||||
}
|
}
|
||||||
return 0;
|
return -1;
|
||||||
}
|
}
|
||||||
if (target == source && (!telefragDamage || target->flags7 & MF7_LAXTELEFRAGDMG))
|
if (target == source && (!telefragDamage || target->flags7 & MF7_LAXTELEFRAGDMG))
|
||||||
{
|
{
|
||||||
|
@ -882,15 +1007,6 @@ static int DamageMobj (AActor *target, AActor *inflictor, AActor *source, int da
|
||||||
{
|
{
|
||||||
if (inflictor == NULL || (!(inflictor->flags3 & MF3_FOILINVUL) && !(flags & DMG_FOILINVUL)))
|
if (inflictor == NULL || (!(inflictor->flags3 & MF3_FOILINVUL) && !(flags & DMG_FOILINVUL)))
|
||||||
{
|
{
|
||||||
if (fakedPain)
|
|
||||||
{
|
|
||||||
// big mess here: What do we use for the pain threshold?
|
|
||||||
// We cannot run the various damage filters below so for consistency it needs to be 0.
|
|
||||||
damage = 0;
|
|
||||||
invulpain = true;
|
|
||||||
goto fakepain;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -899,9 +1015,6 @@ static int DamageMobj (AActor *target, AActor *inflictor, AActor *source, int da
|
||||||
// Players are optionally excluded from getting thrust by damage.
|
// Players are optionally excluded from getting thrust by damage.
|
||||||
if (static_cast<APlayerPawn *>(target)->PlayerFlags & PPF_NOTHRUSTWHENINVUL)
|
if (static_cast<APlayerPawn *>(target)->PlayerFlags & PPF_NOTHRUSTWHENINVUL)
|
||||||
{
|
{
|
||||||
if (fakedPain)
|
|
||||||
plrDontThrust = 1;
|
|
||||||
else
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -931,7 +1044,7 @@ static int DamageMobj (AActor *target, AActor *inflictor, AActor *source, int da
|
||||||
if (target->flags2 & MF2_DORMANT)
|
if (target->flags2 & MF2_DORMANT)
|
||||||
{
|
{
|
||||||
// Invulnerable, and won't wake up
|
// Invulnerable, and won't wake up
|
||||||
return 0;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!telefragDamage || (target->flags7 & MF7_LAXTELEFRAGDMG)) // TELEFRAG_DAMAGE may only be reduced with LAXTELEFRAGDMG or it may not guarantee its effect.
|
if (!telefragDamage || (target->flags7 & MF7_LAXTELEFRAGDMG)) // TELEFRAG_DAMAGE may only be reduced with LAXTELEFRAGDMG or it may not guarantee its effect.
|
||||||
|
@ -959,19 +1072,19 @@ static int DamageMobj (AActor *target, AActor *inflictor, AActor *source, int da
|
||||||
if (player != NULL)
|
if (player != NULL)
|
||||||
{
|
{
|
||||||
if (!deathmatch && inflictor->FriendPlayer > 0)
|
if (!deathmatch && inflictor->FriendPlayer > 0)
|
||||||
return 0;
|
return -1;
|
||||||
}
|
}
|
||||||
else if (target->flags4 & MF4_SPECTRAL)
|
else if (target->flags4 & MF4_SPECTRAL)
|
||||||
{
|
{
|
||||||
if (inflictor->FriendPlayer == 0 && !target->IsHostile(inflictor))
|
if (inflictor->FriendPlayer == 0 && !target->IsHostile(inflictor))
|
||||||
return 0;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
damage = inflictor->CallDoSpecialDamage(target, damage, mod);
|
damage = inflictor->CallDoSpecialDamage(target, damage, mod);
|
||||||
if (damage < 0)
|
if (damage < 0)
|
||||||
{
|
{
|
||||||
return 0;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1005,19 +1118,9 @@ static int DamageMobj (AActor *target, AActor *inflictor, AActor *source, int da
|
||||||
// '<0' is handled below. This only handles the case where damage gets reduced to 0.
|
// '<0' is handled below. This only handles the case where damage gets reduced to 0.
|
||||||
if (damage == 0 && olddam > 0)
|
if (damage == 0 && olddam > 0)
|
||||||
{
|
{
|
||||||
{ // Still allow FORCEPAIN
|
|
||||||
if (forcedPain)
|
|
||||||
{
|
|
||||||
goto dopain;
|
|
||||||
}
|
|
||||||
else if (fakedPain)
|
|
||||||
{
|
|
||||||
goto fakepain;
|
|
||||||
}
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if (target->flags5 & MF5_NODAMAGE)
|
if (target->flags5 & MF5_NODAMAGE)
|
||||||
{
|
{
|
||||||
damage = 0;
|
damage = 0;
|
||||||
|
@ -1026,7 +1129,7 @@ static int DamageMobj (AActor *target, AActor *inflictor, AActor *source, int da
|
||||||
if (damage < 0)
|
if (damage < 0)
|
||||||
{
|
{
|
||||||
// any negative value means that something in the above chain has cancelled out all damage and all damage effects, including pain.
|
// any negative value means that something in the above chain has cancelled out all damage and all damage effects, including pain.
|
||||||
return 0;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1092,21 +1195,9 @@ static int DamageMobj (AActor *target, AActor *inflictor, AActor *source, int da
|
||||||
if (!telefragDamage || (target->flags7 & MF7_LAXTELEFRAGDMG))
|
if (!telefragDamage || (target->flags7 & MF7_LAXTELEFRAGDMG))
|
||||||
{ // Still allow telefragging :-(
|
{ // Still allow telefragging :-(
|
||||||
damage = (int)(damage * level.teamdamage);
|
damage = (int)(damage * level.teamdamage);
|
||||||
if (damage < 0)
|
if (damage <= 0)
|
||||||
{
|
{
|
||||||
return 0;
|
return (damage < 0) ? -1 : 0;
|
||||||
}
|
|
||||||
else if (damage == 0)
|
|
||||||
{
|
|
||||||
if (forcedPain)
|
|
||||||
{
|
|
||||||
goto dopain;
|
|
||||||
}
|
|
||||||
else if (fakedPain)
|
|
||||||
{
|
|
||||||
goto fakepain;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1141,16 +1232,6 @@ static int DamageMobj (AActor *target, AActor *inflictor, AActor *source, int da
|
||||||
(player->cheats & CF_GODMODE2) || (player->mo->flags5 & MF5_NODAMAGE))
|
(player->cheats & CF_GODMODE2) || (player->mo->flags5 & MF5_NODAMAGE))
|
||||||
//Absolutely no hurting if NODAMAGE is involved. Same for GODMODE2.
|
//Absolutely no hurting if NODAMAGE is involved. Same for GODMODE2.
|
||||||
{ // player is invulnerable, so don't hurt him
|
{ // player is invulnerable, so don't hurt him
|
||||||
//Make sure no godmodes and NOPAIN flags are found first.
|
|
||||||
//Then, check to see if the player has NODAMAGE or ALLOWPAIN, or inflictor has CAUSEPAIN.
|
|
||||||
if ((flags & DMG_NO_PAIN) || (player->cheats & CF_GODMODE) || (player->cheats & CF_GODMODE2) || (player->mo->flags5 & MF5_NOPAIN))
|
|
||||||
return 0;
|
|
||||||
else if ((((player->mo->flags7 & MF7_ALLOWPAIN) || (player->mo->flags5 & MF5_NODAMAGE)) || ((inflictor != NULL) && (inflictor->flags7 & MF7_CAUSEPAIN))))
|
|
||||||
{
|
|
||||||
invulpain = true;
|
|
||||||
goto fakepain;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
// Armor for players.
|
// Armor for players.
|
||||||
|
@ -1169,20 +1250,7 @@ static int DamageMobj (AActor *target, AActor *inflictor, AActor *source, int da
|
||||||
|
|
||||||
if (damage <= 0)
|
if (damage <= 0)
|
||||||
{
|
{
|
||||||
// [MC] Godmode doesn't need checking here, it's already being handled above.
|
return (damage < 0) ? -1 : 0;
|
||||||
if (noPain)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
// If MF6_FORCEPAIN is set, make the player enter the pain state.
|
|
||||||
if ((inflictor && (inflictor->flags6 & MF6_FORCEPAIN)))
|
|
||||||
goto dopain;
|
|
||||||
else if (((player->mo->flags7 & MF7_ALLOWPAIN) && (rawdamage > 0)) ||
|
|
||||||
(inflictor && (inflictor->flags7 & MF7_CAUSEPAIN)))
|
|
||||||
{
|
|
||||||
invulpain = true;
|
|
||||||
goto fakepain;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1246,10 +1314,7 @@ static int DamageMobj (AActor *target, AActor *inflictor, AActor *source, int da
|
||||||
damage = newdam;
|
damage = newdam;
|
||||||
if (damage <= 0)
|
if (damage <= 0)
|
||||||
{
|
{
|
||||||
if (fakedPain)
|
return (damage < 0) ? -1 : 0;
|
||||||
goto fakepain;
|
|
||||||
else
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1295,7 +1360,6 @@ static int DamageMobj (AActor *target, AActor *inflictor, AActor *source, int da
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (target->health <= 0)
|
if (target->health <= 0)
|
||||||
{
|
{
|
||||||
//[MC]Buddha flag for monsters.
|
//[MC]Buddha flag for monsters.
|
||||||
|
@ -1350,115 +1414,6 @@ static int DamageMobj (AActor *target, AActor *inflictor, AActor *source, int da
|
||||||
return realdamage;
|
return realdamage;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
woundstate = target->FindState(NAME_Wound, mod);
|
|
||||||
if (woundstate != NULL)
|
|
||||||
{
|
|
||||||
int woundhealth = target->WoundHealth;
|
|
||||||
|
|
||||||
if (target->health <= woundhealth)
|
|
||||||
{
|
|
||||||
target->SetState (woundstate);
|
|
||||||
return MAX(0, damage);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fakepain: //Needed so we can skip the rest of the above, but still obey the original rules.
|
|
||||||
|
|
||||||
if (!noPain &&
|
|
||||||
(target->player != NULL || !G_SkillProperty(SKILLP_NoPain)) && !(target->flags & MF_SKULLFLY))
|
|
||||||
{
|
|
||||||
painchance = target->PainChance;
|
|
||||||
for (auto & pc : target->GetInfo()->PainChances)
|
|
||||||
{
|
|
||||||
if (pc.first == mod)
|
|
||||||
{
|
|
||||||
painchance = pc.second;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (((damage >= target->PainThreshold) && (pr_damagemobj() < painchance))
|
|
||||||
|| (inflictor != NULL && (inflictor->flags6 & MF6_FORCEPAIN)))
|
|
||||||
{
|
|
||||||
dopain:
|
|
||||||
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 ();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//ALLOWPAIN and CAUSEPAIN can still trigger infighting, even if no pain state is worked out.
|
|
||||||
if (target->player == nullptr) target->reactiontime = 0; // we're awake now...
|
|
||||||
if (source)
|
|
||||||
{
|
|
||||||
if (source == target->target)
|
|
||||||
{
|
|
||||||
target->threshold = target->DefThreshold;
|
|
||||||
if (target->state == target->SpawnState && target->SeeState != NULL)
|
|
||||||
{
|
|
||||||
target->SetState (target->SeeState);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (source != target->target && target->CallOkayToSwitchTarget (source))
|
|
||||||
{
|
|
||||||
// Target actor is not intent on another actor,
|
|
||||||
// so make him chase after source
|
|
||||||
|
|
||||||
// killough 2/15/98: remember last enemy, to prevent
|
|
||||||
// sleeping early; 2/21/98: Place priority on players
|
|
||||||
|
|
||||||
if (target->lastenemy == NULL ||
|
|
||||||
(target->lastenemy->player == NULL && target->TIDtoHate == 0) ||
|
|
||||||
target->lastenemy->health <= 0)
|
|
||||||
{
|
|
||||||
target->lastenemy = target->target; // remember last enemy - killough
|
|
||||||
}
|
|
||||||
target->target = source;
|
|
||||||
target->threshold = target->DefThreshold;
|
|
||||||
if (target->state == target->SpawnState && target->SeeState != NULL)
|
|
||||||
{
|
|
||||||
target->SetState (target->SeeState);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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!
|
|
||||||
|
|
||||||
if (invulpain) //Note that this takes into account all the cheats a player has, in terms of invulnerability.
|
|
||||||
{
|
|
||||||
return 0; //NOW we return -1!
|
|
||||||
}
|
|
||||||
return MAX(0, damage);
|
return MAX(0, damage);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1475,11 +1430,15 @@ DEFINE_ACTION_FUNCTION(AActor, DamageMobj)
|
||||||
// [ZZ] event handlers need the result.
|
// [ZZ] event handlers need the result.
|
||||||
bool needevent = true;
|
bool needevent = true;
|
||||||
int realdamage = DamageMobj(self, inflictor, source, damage, mod, flags, angle, needevent);
|
int realdamage = DamageMobj(self, inflictor, source, damage, mod, flags, angle, needevent);
|
||||||
if (realdamage && needevent)
|
if (realdamage >= 0)
|
||||||
|
ReactToDamage(self, inflictor, source, realdamage, mod, flags);
|
||||||
|
|
||||||
|
if (realdamage > 0 && needevent)
|
||||||
{
|
{
|
||||||
E_WorldThingDamaged(self, inflictor, source, realdamage, mod, flags, angle);
|
E_WorldThingDamaged(self, inflictor, source, realdamage, mod, flags, angle);
|
||||||
}
|
}
|
||||||
ACTION_RETURN_INT(realdamage);
|
|
||||||
|
ACTION_RETURN_INT(MAX(0,realdamage));
|
||||||
}
|
}
|
||||||
|
|
||||||
int P_DamageMobj(AActor *target, AActor *inflictor, AActor *source, int damage, FName mod, int flags, DAngle angle)
|
int P_DamageMobj(AActor *target, AActor *inflictor, AActor *source, int damage, FName mod, int flags, DAngle angle)
|
||||||
|
@ -1497,12 +1456,16 @@ int P_DamageMobj(AActor *target, AActor *inflictor, AActor *source, int damage,
|
||||||
{
|
{
|
||||||
bool needevent = true;
|
bool needevent = true;
|
||||||
int realdamage = DamageMobj(target, inflictor, source, damage, mod, flags, angle, needevent);
|
int realdamage = DamageMobj(target, inflictor, source, damage, mod, flags, angle, needevent);
|
||||||
if (realdamage && needevent)
|
if (realdamage >= 0) //Keep this check separated. Mods relying upon negative numbers may break otherwise.
|
||||||
|
ReactToDamage(target, inflictor, source, realdamage, mod, flags);
|
||||||
|
|
||||||
|
if (realdamage > 0 && needevent)
|
||||||
{
|
{
|
||||||
// [ZZ] event handlers only need the resultant damage (they can't do anything about it anyway)
|
// [ZZ] event handlers only need the resultant damage (they can't do anything about it anyway)
|
||||||
E_WorldThingDamaged(target, inflictor, source, realdamage, mod, flags, angle);
|
E_WorldThingDamaged(target, inflictor, source, realdamage, mod, flags, angle);
|
||||||
}
|
}
|
||||||
return realdamage;
|
|
||||||
|
return MAX(0,realdamage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue