fixed some issues with reviving monsters

- fixed: Thing_Raise didn't properly set the spawn health.
- fixed: Thing_Raise did not the CanRaise state flag.
- fixed: Reviving a monster must also reset the damage type.
- fixed: Thing_Raise reset the actor after calling the raise state, but it should be before, just as the Archvile code is doing.
- consolidated some common code of Thing_Raise and Archvile resurrection into AActor methods.
This commit is contained in:
Christoph Oelckers 2014-05-05 11:24:20 +02:00
parent a9f1b54d2d
commit 93aa1ea2c4
4 changed files with 152 additions and 151 deletions

View file

@ -1011,6 +1011,8 @@ public:
bool isSlow(); bool isSlow();
void SetIdle(); void SetIdle();
void ClearCounters(); void ClearCounters();
FState *GetRaiseState();
void Revive();
FState *FindState (FName label) const FState *FindState (FName label) const
{ {

View file

@ -2525,27 +2525,16 @@ static bool P_CheckForResurrection(AActor *self, bool usevilestates)
FBlockThingsIterator it(FBoundingBox(viletryx, viletryy, 32*FRACUNIT)); FBlockThingsIterator it(FBoundingBox(viletryx, viletryy, 32*FRACUNIT));
while ((corpsehit = it.Next())) while ((corpsehit = it.Next()))
{ {
if (!(corpsehit->flags & MF_CORPSE) ) FState *raisestate = corpsehit->GetRaiseState();
continue; // not a monster if (raisestate != NULL)
{
if (corpsehit->tics != -1 && // not lying still yet
!corpsehit->state->GetCanRaise()) // or not ready to be raised yet
continue;
raisestate = corpsehit->FindState(NAME_Raise);
if (raisestate == NULL)
continue; // monster doesn't have a raise state
if (corpsehit->IsKindOf(RUNTIME_CLASS(APlayerPawn)))
continue; // do not resurrect players
// use the current actor's radius instead of the Arch Vile's default. // use the current actor's radius instead of the Arch Vile's default.
fixed_t maxdist = corpsehit->GetDefault()->radius + self->radius; fixed_t maxdist = corpsehit->GetDefault()->radius + self->radius;
maxdist = corpsehit-> GetDefault()->radius + self->radius; maxdist = corpsehit->GetDefault()->radius + self->radius;
if ( abs(corpsehit-> x - viletryx) > maxdist || if (abs(corpsehit->x - viletryx) > maxdist ||
abs(corpsehit-> y - viletryy) > maxdist ) abs(corpsehit->y - viletryy) > maxdist)
continue; // not actually touching continue; // not actually touching
#ifdef _3DFLOORS #ifdef _3DFLOORS
// Let's check if there are floors in between the archvile and its target // Let's check if there are floors in between the archvile and its target
@ -2576,7 +2565,7 @@ static bool P_CheckForResurrection(AActor *self, bool usevilestates)
corpsehit->flags |= MF_SOLID; corpsehit->flags |= MF_SOLID;
corpsehit->height = corpsehit->GetDefault()->height; corpsehit->height = corpsehit->GetDefault()->height;
bool check = P_CheckPosition (corpsehit, corpsehit->x, corpsehit->y); bool check = P_CheckPosition(corpsehit, corpsehit->x, corpsehit->y);
corpsehit->flags = oldflags; corpsehit->flags = oldflags;
corpsehit->radius = oldradius; corpsehit->radius = oldradius;
corpsehit->height = oldheight; corpsehit->height = oldheight;
@ -2585,7 +2574,7 @@ static bool P_CheckForResurrection(AActor *self, bool usevilestates)
// got one! // got one!
temp = self->target; temp = self->target;
self->target = corpsehit; self->target = corpsehit;
A_FaceTarget (self); A_FaceTarget(self);
if (self->flags & MF_FRIENDLY) if (self->flags & MF_FRIENDLY)
{ {
// If this is a friendly Arch-Vile (which is turning the resurrected monster into its friend) // If this is a friendly Arch-Vile (which is turning the resurrected monster into its friend)
@ -2600,7 +2589,7 @@ static bool P_CheckForResurrection(AActor *self, bool usevilestates)
FState * state = self->FindState(NAME_Heal); FState * state = self->FindState(NAME_Heal);
if (state != NULL) if (state != NULL)
{ {
self->SetState (state); self->SetState(state);
} }
else if (usevilestates) else if (usevilestates)
{ {
@ -2609,11 +2598,11 @@ static bool P_CheckForResurrection(AActor *self, bool usevilestates)
const PClass *archvile = PClass::FindClass("Archvile"); const PClass *archvile = PClass::FindClass("Archvile");
if (archvile != NULL) if (archvile != NULL)
{ {
self->SetState (archvile->ActorInfo->FindState(NAME_Heal)); self->SetState(archvile->ActorInfo->FindState(NAME_Heal));
} }
} }
S_Sound (corpsehit, CHAN_BODY, "vile/raise", 1, ATTN_IDLE); S_Sound(corpsehit, CHAN_BODY, "vile/raise", 1, ATTN_IDLE);
info = corpsehit->GetDefault (); info = corpsehit->GetDefault();
if (corpsehit->state == corpsehit->FindState(NAME_GenericCrush)) if (corpsehit->state == corpsehit->FindState(NAME_GenericCrush))
{ {
@ -2643,30 +2632,17 @@ static bool P_CheckForResurrection(AActor *self, bool usevilestates)
corpsehit->height = info->height; // [RH] Use real mobj height corpsehit->height = info->height; // [RH] Use real mobj height
corpsehit->radius = info->radius; // [RH] Use real radius corpsehit->radius = info->radius; // [RH] Use real radius
} }
corpsehit->flags = info->flags;
corpsehit->flags2 = info->flags2;
corpsehit->flags3 = info->flags3;
corpsehit->flags4 = info->flags4;
corpsehit->flags5 = info->flags5;
corpsehit->flags6 = info->flags6;
corpsehit->flags7 = info->flags7;
corpsehit->health = corpsehit->SpawnHealth();
corpsehit->target = NULL;
corpsehit->lastenemy = NULL;
// [RH] If it's a monster, it gets to count as another kill corpsehit->Revive();
if (corpsehit->CountsAsKill())
{
level.total_monsters++;
}
// You are the Archvile's minion now, so hate what it hates // You are the Archvile's minion now, so hate what it hates
corpsehit->CopyFriendliness (self, false); corpsehit->CopyFriendliness(self, false);
corpsehit->SetState (raisestate); corpsehit->SetState(raisestate);
return true; return true;
} }
} }
}
return false; return false;
} }

View file

@ -6074,6 +6074,49 @@ int AActor::SpawnHealth()
} }
} }
FState *AActor::GetRaiseState()
{
if (!(flags & MF_CORPSE))
{
return NULL; // not a monster
}
if (tics != -1 && // not lying still yet
state->GetCanRaise()) // or not ready to be raised yet
{
return NULL;
}
if (IsKindOf(RUNTIME_CLASS(APlayerPawn)))
{
return NULL; // do not resurrect players
}
return FindState(NAME_Raise);
}
void AActor::Revive()
{
AActor *info = GetDefault();
flags = info->flags;
flags2 = info->flags2;
flags3 = info->flags3;
flags4 = info->flags4;
flags5 = info->flags5;
flags6 = info->flags6;
flags7 = info->flags7;
DamageType = info->DamageType;
health = SpawnHealth();
target = NULL;
lastenemy = NULL;
// [RH] If it's a monster, it gets to count as another kill
if (CountsAsKill())
{
level.total_monsters++;
}
}
FDropItem *AActor::GetDropItems() FDropItem *AActor::GetDropItems()
{ {
unsigned int index = GetClass()->Meta.GetMetaInt (ACMETA_DropItems) - 1; unsigned int index = GetClass()->Meta.GetMetaInt (ACMETA_DropItems) - 1;

View file

@ -410,18 +410,11 @@ void P_RemoveThing(AActor * actor)
bool P_Thing_Raise(AActor *thing) bool P_Thing_Raise(AActor *thing)
{ {
if (thing == NULL) FState * RaiseState = thing->GetRaiseState();
return false; // not valid
if (!(thing->flags & MF_CORPSE) )
return true; // not a corpse
if (thing->tics != -1)
return true; // not lying still yet
FState * RaiseState = thing->FindState(NAME_Raise);
if (RaiseState == NULL) if (RaiseState == NULL)
{
return true; // monster doesn't have a raise state return true; // monster doesn't have a raise state
}
AActor *info = thing->GetDefault (); AActor *info = thing->GetDefault ();
@ -443,25 +436,12 @@ bool P_Thing_Raise(AActor *thing)
return false; return false;
} }
S_Sound (thing, CHAN_BODY, "vile/raise", 1, ATTN_IDLE); S_Sound (thing, CHAN_BODY, "vile/raise", 1, ATTN_IDLE);
thing->SetState (RaiseState); thing->Revive();
thing->flags = info->flags;
thing->flags2 = info->flags2;
thing->flags3 = info->flags3;
thing->flags4 = info->flags4;
thing->flags5 = info->flags5;
thing->flags6 = info->flags6;
thing->flags7 = info->flags7;
thing->health = info->health;
thing->target = NULL;
thing->lastenemy = NULL;
// [RH] If it's a monster, it gets to count as another kill thing->SetState (RaiseState);
if (thing->CountsAsKill())
{
level.total_monsters++;
}
return true; return true;
} }