diff --git a/src/p_interaction.cpp b/src/p_interaction.cpp index c46cb40f74..cc4c9aece6 100644 --- a/src/p_interaction.cpp +++ b/src/p_interaction.cpp @@ -657,10 +657,37 @@ void AActor::Die (AActor *source, AActor *inflictor, int dmgflags) FState *diestate = NULL; + int gibhealth = GibHealth(); + bool extremelydead = ((health < gibhealth || flags4 & MF4_EXTREMEDEATH) && !(flags4 & MF4_NOEXTREMEDEATH)); + + // Special check for 'extreme' damage type to ensure that it gets recorded properly as an extreme death for subsequent checks. + if (DamageType == NAME_Extreme) + { + extremelydead = true; + DamageType = NAME_None; + } + + // find the appropriate death state. The order is: + // + // 1. If damagetype is not 'none' and death is extreme, try a damage type specific extreme death state + // 2. If no such state is found or death is not extreme try a damage type specific normal death state + // 3. If damagetype is 'ice' and actor is a monster or player, try the generic freeze death (unless prohibited) + // 4. If no state has been found and death is extreme, try the extreme death state + // 5. If no such state is found or death is not extreme try the regular death state. + // 6. If still no state has been found, destroy the actor immediately. if (DamageType != NAME_None) { - diestate = FindState (NAME_Death, DamageType, true); + if (extremelydead) + { + FName labels[] = { NAME_Death, NAME_Extreme, DamageType }; + diestate = FindState(3, labels, true); + } + if (diestate == NULL) + { + diestate = FindState (NAME_Death, DamageType, true); + if (diestate != NULL) extremelydead = false; + } if (diestate == NULL) { if (DamageType == NAME_Ice) @@ -669,6 +696,7 @@ void AActor::Die (AActor *source, AActor *inflictor, int dmgflags) if (!deh.NoAutofreeze && !(flags4 & MF4_NOICEDEATH) && (player || (flags3 & MF3_ISMONSTER))) { diestate = FindState(NAME_GenericFreezeDeath); + extremelydead = false; } } } @@ -676,8 +704,6 @@ void AActor::Die (AActor *source, AActor *inflictor, int dmgflags) if (diestate == NULL) { int flags4 = inflictor == NULL ? 0 : inflictor->flags4; - - int gibhealth = GibHealth(); // Don't pass on a damage type this actor cannot handle. // (most importantly, prevent barrels from passing on ice damage.) @@ -687,26 +713,33 @@ void AActor::Die (AActor *source, AActor *inflictor, int dmgflags) DamageType = NAME_None; } - if ((health < gibhealth || flags4 & MF4_EXTREMEDEATH) && !(flags4 & MF4_NOEXTREMEDEATH)) + if (extremelydead) { // Extreme death diestate = FindState (NAME_Death, NAME_Extreme, true); - // If a non-player, mark as extremely dead for the crash state. - if (diestate != NULL && player == NULL && health >= gibhealth) - { - health = gibhealth - 1; - } - // For players, mark the appropriate flag. - else if (player != NULL) - { - player->cheats |= CF_EXTREMELYDEAD; - } } if (diestate == NULL) { // Normal death + extremelydead = false; diestate = FindState (NAME_Death); } } + if (extremelydead) + { + // We'll only get here if an actual extreme death state was used. + + // For players, mark the appropriate flag. + if (player != NULL) + { + player->cheats |= CF_EXTREMELYDEAD; + } + // If a non-player, mark as extremely dead for the crash state. + else if (health >= gibhealth) + { + health = gibhealth - 1; + } + } + if (diestate != NULL) { SetState (diestate); diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 41b41aec67..3b11ec415d 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -5922,7 +5922,15 @@ void AActor::Crash() if (DamageType != NAME_None) { - crashstate = FindState(NAME_Crash, DamageType, true); + if (health < GibHealth()) + { // Extreme death + FName labels[] = { NAME_Crash, NAME_Extreme, DamageType }; + crashstate = FindState (3, labels, true); + } + if (crashstate == NULL) + { // Normal death + crashstate = FindState(NAME_Crash, DamageType, true); + } } if (crashstate == NULL) { diff --git a/src/p_spec.h b/src/p_spec.h index 4f67f87ffb..57d2169729 100644 --- a/src/p_spec.h +++ b/src/p_spec.h @@ -763,7 +763,7 @@ protected: fixed_t stairsize, fixed_t speed, int delay, int reset, int igntxt, int usespecials); friend bool EV_DoFloor (DFloor::EFloor floortype, line_t *line, int tag, - fixed_t speed, fixed_t height, int crush, int change, bool hexencrush, bool hereticlower=false); + fixed_t speed, fixed_t height, int crush, int change, bool hexencrush, bool hereticlower); friend bool EV_FloorCrushStop (int tag); friend bool EV_DoDonut (int tag, line_t *line, fixed_t pillarspeed, fixed_t slimespeed); private: @@ -774,7 +774,7 @@ bool EV_BuildStairs (int tag, DFloor::EStair type, line_t *line, fixed_t stairsize, fixed_t speed, int delay, int reset, int igntxt, int usespecials); bool EV_DoFloor (DFloor::EFloor floortype, line_t *line, int tag, - fixed_t speed, fixed_t height, int crush, int change, bool hexencrush, bool hereticlower); + fixed_t speed, fixed_t height, int crush, int change, bool hexencrush, bool hereticlower=false); bool EV_FloorCrushStop (int tag); bool EV_DoDonut (int tag, line_t *line, fixed_t pillarspeed, fixed_t slimespeed);