- Applied a modified version of FDARI's patch to prevent giving health to dead things:

* P_GiveBody() now takes a max parameter so that it can also do the bulk of the work
    AHealth::TryPickup() previously did.
  * Setting an actor's health to 0 or below with SetActorProperty will now kill the actor
    properly.

SVN r3438 (trunk)
This commit is contained in:
Randy Heit 2012-03-15 21:21:00 +00:00
parent 6290ea4fcb
commit 977b2caa30
3 changed files with 48 additions and 69 deletions

View file

@ -180,13 +180,21 @@ 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; player_t *player = actor->player;
num = clamp(num, -65536, 65536); // prevent overflows for bad values num = clamp(num, -65536, 65536); // prevent overflows for bad values
if (player != NULL) if (player != NULL)
{
// Max is 0 by default, preserving default behavior for P_GiveBody()
// calls while supporting AHealth.
if (max <= 0)
{ {
max = static_cast<APlayerPawn*>(actor)->GetMaxHealth() + player->mo->stamina; max = static_cast<APlayerPawn*>(actor)->GetMaxHealth() + player->mo->stamina;
// [MH] First step in predictable generic morph effects // [MH] First step in predictable generic morph effects
@ -208,6 +216,7 @@ bool P_GiveBody (AActor *actor, int num)
} }
} }
} }
}
// [RH] For Strife: A negative body sets you up with a percentage // [RH] For Strife: A negative body sets you up with a percentage
// of your full health. // of your full health.
if (num < 0) if (num < 0)
@ -236,6 +245,8 @@ bool P_GiveBody (AActor *actor, int num)
} }
else 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(); max = actor->SpawnHealth();
if (num < 0) if (num < 0)
{ {
@ -1475,58 +1486,16 @@ const char *AHealth::PickupMessage ()
bool AHealth::TryPickup (AActor *&other) bool AHealth::TryPickup (AActor *&other)
{ {
player_t *player = other->player; PrevHealth = other->player != NULL ? other->player->health : other->health;
int max = MaxAmount;
if (player != NULL) // 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; GoAwayAndDie();
if (max == 0)
{
max = static_cast<APlayerPawn*>(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;
}
else
{
PrevHealth = INT_MAX;
if (P_GiveBody(other, Amount))
{
GoAwayAndDie ();
return true; return true;
} }
return false; return false;
}
GoAwayAndDie ();
return true;
} }
IMPLEMENT_CLASS (AHealthPickup) IMPLEMENT_CLASS (AHealthPickup)

View file

@ -2874,11 +2874,21 @@ void DLevelScript::DoSetActorProperty (AActor *actor, int property, int value)
switch (property) switch (property)
{ {
case APROP_Health: 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; actor->health = value;
if (actor->player != NULL) if (actor->player != NULL)
{ {
actor->player->health = value; 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; break;
case APROP_Speed: case APROP_Speed:

View file

@ -484,7 +484,7 @@ extern FBlockNode** blocklinks; // for thing chains
void P_TouchSpecialThing (AActor *special, AActor *toucher); 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_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); 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); bool P_PoisonPlayer (player_t *player, AActor *poisoner, AActor *source, int poison);
void P_PoisonDamage (player_t *player, AActor *source, int damage, bool playPainSound); void P_PoisonDamage (player_t *player, AActor *source, int damage, bool playPainSound);