diff --git a/src/actor.h b/src/actor.h index 21057d86c3..4b7696752e 100644 --- a/src/actor.h +++ b/src/actor.h @@ -1011,6 +1011,8 @@ public: bool isSlow(); void SetIdle(); void ClearCounters(); + FState *GetRaiseState(); + void Revive(); FState *FindState (FName label) const { diff --git a/src/p_enemy.cpp b/src/p_enemy.cpp index 14c6b68aab..f84dd13aa5 100644 --- a/src/p_enemy.cpp +++ b/src/p_enemy.cpp @@ -2525,146 +2525,122 @@ static bool P_CheckForResurrection(AActor *self, bool usevilestates) FBlockThingsIterator it(FBoundingBox(viletryx, viletryy, 32*FRACUNIT)); while ((corpsehit = it.Next())) { - if (!(corpsehit->flags & MF_CORPSE) ) - continue; // not a monster - - 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. - fixed_t maxdist = corpsehit->GetDefault()->radius + self->radius; - - maxdist = corpsehit-> GetDefault()->radius + self->radius; - - if ( abs(corpsehit-> x - viletryx) > maxdist || - abs(corpsehit-> y - viletryy) > maxdist ) - continue; // not actually touching -#ifdef _3DFLOORS - // Let's check if there are floors in between the archvile and its target - sector_t *vilesec = self->Sector; - sector_t *corpsec = corpsehit->Sector; - // We only need to test if at least one of the sectors has a 3D floor. - sector_t *testsec = vilesec->e->XFloor.ffloors.Size() ? vilesec : - (vilesec != corpsec && corpsec->e->XFloor.ffloors.Size()) ? corpsec : NULL; - if (testsec) + FState *raisestate = corpsehit->GetRaiseState(); + if (raisestate != NULL) { - fixed_t zdist1, zdist2; - if (P_Find3DFloor(testsec, corpsehit->x, corpsehit->y, corpsehit->z, false, true, zdist1) - != P_Find3DFloor(testsec, self->x, self->y, self->z, false, true, zdist2)) + // use the current actor's radius instead of the Arch Vile's default. + fixed_t maxdist = corpsehit->GetDefault()->radius + self->radius; + + maxdist = corpsehit->GetDefault()->radius + self->radius; + + if (abs(corpsehit->x - viletryx) > maxdist || + abs(corpsehit->y - viletryy) > maxdist) + continue; // not actually touching +#ifdef _3DFLOORS + // Let's check if there are floors in between the archvile and its target + sector_t *vilesec = self->Sector; + sector_t *corpsec = corpsehit->Sector; + // We only need to test if at least one of the sectors has a 3D floor. + sector_t *testsec = vilesec->e->XFloor.ffloors.Size() ? vilesec : + (vilesec != corpsec && corpsec->e->XFloor.ffloors.Size()) ? corpsec : NULL; + if (testsec) { - // Not on same floor - if (vilesec == corpsec || abs(zdist1 - self->z) > self->height) + fixed_t zdist1, zdist2; + if (P_Find3DFloor(testsec, corpsehit->x, corpsehit->y, corpsehit->z, false, true, zdist1) + != P_Find3DFloor(testsec, self->x, self->y, self->z, false, true, zdist2)) + { + // Not on same floor + if (vilesec == corpsec || abs(zdist1 - self->z) > self->height) continue; + } } - } #endif - corpsehit->velx = corpsehit->vely = 0; - // [RH] Check against real height and radius + corpsehit->velx = corpsehit->vely = 0; + // [RH] Check against real height and radius - fixed_t oldheight = corpsehit->height; - fixed_t oldradius = corpsehit->radius; - int oldflags = corpsehit->flags; + fixed_t oldheight = corpsehit->height; + fixed_t oldradius = corpsehit->radius; + int oldflags = corpsehit->flags; - corpsehit->flags |= MF_SOLID; - corpsehit->height = corpsehit->GetDefault()->height; - bool check = P_CheckPosition (corpsehit, corpsehit->x, corpsehit->y); - corpsehit->flags = oldflags; - corpsehit->radius = oldradius; - corpsehit->height = oldheight; - if (!check) continue; + corpsehit->flags |= MF_SOLID; + corpsehit->height = corpsehit->GetDefault()->height; + bool check = P_CheckPosition(corpsehit, corpsehit->x, corpsehit->y); + corpsehit->flags = oldflags; + corpsehit->radius = oldradius; + corpsehit->height = oldheight; + if (!check) continue; - // got one! - temp = self->target; - self->target = corpsehit; - A_FaceTarget (self); - if (self->flags & MF_FRIENDLY) - { - // If this is a friendly Arch-Vile (which is turning the resurrected monster into its friend) - // and the Arch-Vile is currently targetting the resurrected monster the target must be cleared. - if (self->lastenemy == temp) self->lastenemy = NULL; - if (self->lastenemy == corpsehit) self->lastenemy = NULL; - if (temp == self->target) temp = NULL; - } - self->target = temp; - - // Make the state the monster enters customizable. - FState * state = self->FindState(NAME_Heal); - if (state != NULL) - { - self->SetState (state); - } - else if (usevilestates) - { - // For Dehacked compatibility this has to use the Arch Vile's - // heal state as a default if the actor doesn't define one itself. - const PClass *archvile = PClass::FindClass("Archvile"); - if (archvile != NULL) + // got one! + temp = self->target; + self->target = corpsehit; + A_FaceTarget(self); + if (self->flags & MF_FRIENDLY) { - self->SetState (archvile->ActorInfo->FindState(NAME_Heal)); + // If this is a friendly Arch-Vile (which is turning the resurrected monster into its friend) + // and the Arch-Vile is currently targetting the resurrected monster the target must be cleared. + if (self->lastenemy == temp) self->lastenemy = NULL; + if (self->lastenemy == corpsehit) self->lastenemy = NULL; + if (temp == self->target) temp = NULL; } - } - S_Sound (corpsehit, CHAN_BODY, "vile/raise", 1, ATTN_IDLE); - info = corpsehit->GetDefault (); - - if (corpsehit->state == corpsehit->FindState(NAME_GenericCrush)) - { - corpsehit->Translation = info->Translation; // Clean up bloodcolor translation from crushed corpses - } - if (ib_compatflags & BCOMPATF_VILEGHOSTS) - { - corpsehit->height <<= 2; - // [GZ] This was a commented-out feature, so let's make use of it, - // but only for ghost monsters so that they are visibly different. - if (corpsehit->height == 0) + self->target = temp; + + // Make the state the monster enters customizable. + FState * state = self->FindState(NAME_Heal); + if (state != NULL) { - // Make raised corpses look ghostly - if (corpsehit->alpha > TRANSLUC50) + self->SetState(state); + } + else if (usevilestates) + { + // For Dehacked compatibility this has to use the Arch Vile's + // heal state as a default if the actor doesn't define one itself. + const PClass *archvile = PClass::FindClass("Archvile"); + if (archvile != NULL) { - corpsehit->alpha /= 2; - } - // This will only work if the render style is changed as well. - if (corpsehit->RenderStyle == LegacyRenderStyles[STYLE_Normal]) - { - corpsehit->RenderStyle = STYLE_Translucent; + self->SetState(archvile->ActorInfo->FindState(NAME_Heal)); } } - } - else - { - corpsehit->height = info->height; // [RH] Use real mobj height - 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; + S_Sound(corpsehit, CHAN_BODY, "vile/raise", 1, ATTN_IDLE); + info = corpsehit->GetDefault(); - // [RH] If it's a monster, it gets to count as another kill - if (corpsehit->CountsAsKill()) - { - level.total_monsters++; + if (corpsehit->state == corpsehit->FindState(NAME_GenericCrush)) + { + corpsehit->Translation = info->Translation; // Clean up bloodcolor translation from crushed corpses + } + if (ib_compatflags & BCOMPATF_VILEGHOSTS) + { + corpsehit->height <<= 2; + // [GZ] This was a commented-out feature, so let's make use of it, + // but only for ghost monsters so that they are visibly different. + if (corpsehit->height == 0) + { + // Make raised corpses look ghostly + if (corpsehit->alpha > TRANSLUC50) + { + corpsehit->alpha /= 2; + } + // This will only work if the render style is changed as well. + if (corpsehit->RenderStyle == LegacyRenderStyles[STYLE_Normal]) + { + corpsehit->RenderStyle = STYLE_Translucent; + } + } + } + else + { + corpsehit->height = info->height; // [RH] Use real mobj height + corpsehit->radius = info->radius; // [RH] Use real radius + } + + corpsehit->Revive(); + + // You are the Archvile's minion now, so hate what it hates + corpsehit->CopyFriendliness(self, false); + corpsehit->SetState(raisestate); + + return true; } - - // You are the Archvile's minion now, so hate what it hates - corpsehit->CopyFriendliness (self, false); - corpsehit->SetState (raisestate); - - return true; } } return false; diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index f519ba763c..05eddf3abf 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -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() { unsigned int index = GetClass()->Meta.GetMetaInt (ACMETA_DropItems) - 1; diff --git a/src/p_things.cpp b/src/p_things.cpp index 4828e8cbc6..e62c65ae78 100644 --- a/src/p_things.cpp +++ b/src/p_things.cpp @@ -410,18 +410,11 @@ void P_RemoveThing(AActor * actor) bool P_Thing_Raise(AActor *thing) { - if (thing == NULL) - 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); + FState * RaiseState = thing->GetRaiseState(); if (RaiseState == NULL) + { return true; // monster doesn't have a raise state + } AActor *info = thing->GetDefault (); @@ -443,25 +436,12 @@ bool P_Thing_Raise(AActor *thing) return false; } - S_Sound (thing, CHAN_BODY, "vile/raise", 1, ATTN_IDLE); - - thing->SetState (RaiseState); - 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 - if (thing->CountsAsKill()) - { - level.total_monsters++; - } + S_Sound (thing, CHAN_BODY, "vile/raise", 1, ATTN_IDLE); + + thing->Revive(); + + thing->SetState (RaiseState); return true; }