diff --git a/src/g_shared/a_pickups.cpp b/src/g_shared/a_pickups.cpp index a9b7a64a5..b45e419a7 100644 --- a/src/g_shared/a_pickups.cpp +++ b/src/g_shared/a_pickups.cpp @@ -180,34 +180,43 @@ AInventory *AAmmo::CreateTossable() // //--------------------------------------------------------------------------- -bool P_GiveBody (AActor *actor, int num) +bool P_GiveBody (AActor *actor, int num, int max) { - int max; + if (actor->health <= 0 || (actor->player != NULL && actor->player->playerstate == PST_DEAD)) + { // Do not heal dead things. + return false; + } + player_t *player = actor->player; num = clamp(num, -65536, 65536); // prevent overflows for bad values if (player != NULL) { - max = static_cast(actor)->GetMaxHealth() + player->mo->stamina; - // [MH] First step in predictable generic morph effects - if (player->morphTics) - { - if (player->MorphStyle & MORPH_FULLHEALTH) - { - if (!(player->MorphStyle & MORPH_ADDSTAMINA)) + // Max is 0 by default, preserving default behavior for P_GiveBody() + // calls while supporting AHealth. + if (max <= 0) + { + max = static_cast(actor)->GetMaxHealth() + player->mo->stamina; + // [MH] First step in predictable generic morph effects + if (player->morphTics) + { + if (player->MorphStyle & MORPH_FULLHEALTH) { - max -= player->mo->stamina; + if (!(player->MorphStyle & MORPH_ADDSTAMINA)) + { + max -= player->mo->stamina; + } } - } - else // old health behaviour - { - max = MAXMORPHHEALTH; - if (player->MorphStyle & MORPH_ADDSTAMINA) + else // old health behaviour { - max += player->mo->stamina; + max = MAXMORPHHEALTH; + if (player->MorphStyle & MORPH_ADDSTAMINA) + { + max += player->mo->stamina; + } } - } - } + } + } // [RH] For Strife: A negative body sets you up with a percentage // of your full health. if (num < 0) @@ -236,6 +245,8 @@ bool P_GiveBody (AActor *actor, int num) } else { + // Parameter value for max is ignored on monsters, preserving original + // behaviour on AHealth as well as on existing calls to P_GiveBody(). max = actor->SpawnHealth(); if (num < 0) { @@ -1475,58 +1486,16 @@ const char *AHealth::PickupMessage () bool AHealth::TryPickup (AActor *&other) { - player_t *player = other->player; - int max = MaxAmount; - - if (player != NULL) + PrevHealth = other->player != NULL ? other->player->health : other->health; + + // P_GiveBody adds one new feature, applied only if it is possible to pick up negative health: + // Negative values are treated as positive percentages, ie Amount -100 means 100% health, ignoring max amount. + if (P_GiveBody(other, Amount, MaxAmount)) { - PrevHealth = other->player->health; - if (max == 0) - { - max = static_cast(other)->GetMaxHealth() + player->mo->stamina; - // [MH] First step in predictable generic morph effects - if (player->morphTics) - { - if (player->MorphStyle & MORPH_FULLHEALTH) - { - if (!(player->MorphStyle & MORPH_ADDSTAMINA)) - { - max -= player->mo->stamina; - } - } - else // old health behaviour - { - max = MAXMORPHHEALTH; - if (player->MorphStyle & MORPH_ADDSTAMINA) - { - max += player->mo->stamina; - } - } - } - } - if (player->health >= max) - { - return false; - } - player->health += Amount; - if (player->health > max) - { - player->health = max; - } - player->mo->health = player->health; + GoAwayAndDie(); + return true; } - else - { - PrevHealth = INT_MAX; - if (P_GiveBody(other, Amount)) - { - GoAwayAndDie (); - return true; - } - return false; - } - GoAwayAndDie (); - return true; + return false; } IMPLEMENT_CLASS (AHealthPickup) diff --git a/src/p_acs.cpp b/src/p_acs.cpp index e78dd99ea..782075956 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -2874,11 +2874,21 @@ void DLevelScript::DoSetActorProperty (AActor *actor, int property, int value) switch (property) { case APROP_Health: + // Don't alter the health of dead things. + if (actor->health <= 0 || (actor->player != NULL && actor->player->playerstate == PST_DEAD)) + { + break; + } actor->health = value; if (actor->player != NULL) { actor->player->health = value; } + // If the health is set to a non-positive value, properly kill the actor. + if (value <= 0) + { + actor->Die(activator, activator); + } break; case APROP_Speed: diff --git a/src/p_local.h b/src/p_local.h index 0b6474baa..d738f90b6 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -484,7 +484,7 @@ extern FBlockNode** blocklinks; // for thing chains void P_TouchSpecialThing (AActor *special, AActor *toucher); void P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage, FName mod, int flags=0); void P_PoisonMobj (AActor *target, AActor *inflictor, AActor *source, int damage, int duration, int period, FName type); -bool P_GiveBody (AActor *actor, int num); +bool P_GiveBody (AActor *actor, int num, int max=0); bool P_PoisonPlayer (player_t *player, AActor *poisoner, AActor *source, int poison); void P_PoisonDamage (player_t *player, AActor *source, int damage, bool playPainSound);