diff --git a/source/games/blood/src/actor.cpp b/source/games/blood/src/actor.cpp index 249bebcc1..600da89bd 100644 --- a/source/games/blood/src/actor.cpp +++ b/source/games/blood/src/actor.cpp @@ -1647,7 +1647,7 @@ static int actDamageDude(DBloodActor* source, DBloodActor* actor, int damage, DA { if (!actor->IsDudeActor()) { - Printf(PRINT_HIGH, "Bad Dude Failed: initial=%d type=%d %s\n", (int)actor->spr.inittype, (int)actor->GetType(), (int)(actor->spr.flags & kHitagRespawn) ? "RESPAWN" : "NORMAL"); + Printf(PRINT_HIGH, "Bad Dude Failed: initial=%s type=%d %s\n", actor->originalType->TypeName.GetChars(), (int)actor->GetType(), (int)(actor->spr.flags & kHitagRespawn) ? "RESPAWN" : "NORMAL"); return damage >> 4; } @@ -2970,13 +2970,13 @@ void MoveDude(DBloodActor* actor) break; case kDudeBurningCultist: { - const bool fixRandomCultist = !cl_bloodvanillaenemies && (actor->spr.inittype >= kDudeBase) && (actor->spr.inittype < kDudeMax) && (actor->spr.inittype != actor->GetType()) && !VanillaMode(); // fix burning cultists randomly switching types underwater + const bool fixRandomCultist = !cl_bloodvanillaenemies && actor->WasDudeActor() && actor->originalType != actor->GetClass() && !VanillaMode(); // fix burning cultists randomly switching types underwater if (Chance(chance)) actor->ChangeType(kDudeCultistTommy); else actor->ChangeType(kDudeCultistShotgun); if (fixRandomCultist) // fix burning cultists randomly switching types underwater - actor->ChangeType(actor->spr.inittype); // restore back to spawned cultist type + actor->ChangeType(actor->originalType); // restore back to spawned cultist type actor->xspr.burnTime = 0; evPostActor(actor, 0, AF(EnemyBubble)); sfxPlay3DSound(actor, 720, -1, 0); @@ -4136,8 +4136,7 @@ DBloodActor* actSpawnDude(DBloodActor* source, int nType, double dist) { pos.XY() += angle.ToVector() * dist; } - if (!VanillaMode()) - spawned->spr.inittype = nType; + spawned->originalType = cls; spawned->spr.Angles.Yaw = angle; SetActor(spawned, pos); diff --git a/source/games/blood/src/actor.h b/source/games/blood/src/actor.h index 49388c9cd..0378a1f00 100644 --- a/source/games/blood/src/actor.h +++ b/source/games/blood/src/actor.h @@ -132,7 +132,9 @@ DBloodActor* actSpawnThing(sectortype* pSector, const DVector3& pos, int nThingT DBloodActor* actFireThing(DBloodActor* actor, double xyoff, double zoff, double zvel, int thingType, double nSpeed); DBloodActor* actFireMissile(DBloodActor* actor, double xyoff, double zoff, DVector3 dc, int nType); +bool IsBurningDude(DBloodActor* pSprite); void actBurnSprite(DBloodActor* pSource, DBloodActor* pTarget, int nTime); + bool isGrown(DBloodActor* pSprite); bool isShrunk(DBloodActor* pSprite); bool ceilIsTooLow(DBloodActor* actor); diff --git a/source/games/blood/src/ai.cpp b/source/games/blood/src/ai.cpp index 6172e9d2a..1fe912c06 100644 --- a/source/games/blood/src/ai.cpp +++ b/source/games/blood/src/ai.cpp @@ -997,7 +997,7 @@ int aiDamageSprite(DBloodActor* source, DBloodActor* actor, DAMAGE_TYPE nDmgType DUDEEXTRA* pDudeExtra = &actor->dudeExtra; pDudeExtra->teslaHit = 0; } - const bool fixRandomCultist = !cl_bloodvanillaenemies && (actor->spr.inittype >= kDudeBase) && (actor->spr.inittype < kDudeMax) && (actor->spr.inittype != actor->GetType()) && !VanillaMode(); // fix burning cultists randomly switching types underwater + const bool fixRandomCultist = !cl_bloodvanillaenemies && actor->WasDudeActor() && actor->originalType != actor->GetClass() && !VanillaMode(); // fix burning cultists randomly switching types underwater switch (actor->GetType()) { case kDudeCultistTommy: @@ -1045,7 +1045,7 @@ int aiDamageSprite(DBloodActor* source, DBloodActor* actor, DAMAGE_TYPE nDmgType { actor->ChangeType(kDudeCultistTommy); if (fixRandomCultist) // fix burning cultists randomly switching types underwater - actor->ChangeType(actor->spr.inittype); // restore back to spawned cultist type + actor->ChangeType(actor->originalType); // restore back to spawned cultist type actor->xspr.burnTime = 0; aiNewState(actor, NAME_cultistSwimGoto); } @@ -1053,7 +1053,7 @@ int aiDamageSprite(DBloodActor* source, DBloodActor* actor, DAMAGE_TYPE nDmgType { actor->ChangeType(kDudeCultistShotgun); if (fixRandomCultist) // fix burning cultists randomly switching types underwater - actor->ChangeType(actor->spr.inittype); // restore back to spawned cultist type + actor->ChangeType(actor->originalType); // restore back to spawned cultist type actor->xspr.burnTime = 0; aiNewState(actor, NAME_cultistSwimGoto); } diff --git a/source/games/blood/src/aiunicult.cpp b/source/games/blood/src/aiunicult.cpp index 4fffcdd94..8e3026bfc 100644 --- a/source/games/blood/src/aiunicult.cpp +++ b/source/games/blood/src/aiunicult.cpp @@ -1947,8 +1947,8 @@ void genDudeTransform(DBloodActor* actor) // trigger dude death before transform trTriggerSprite(actor, kCmdOff, actor); - actor->spr.inittype = actIncarnation->GetType(); - actor->ChangeType(actor->spr.inittype); + actor->originalType = actIncarnation->GetClass(); + actor->ChangeType(actor->originalType); actor->spr.flags = actIncarnation->spr.flags; actor->spr.pal = actIncarnation->spr.pal; actor->spr.shade = actIncarnation->spr.shade; diff --git a/source/games/blood/src/bloodactor.h b/source/games/blood/src/bloodactor.h index 1d9197ec9..e32a3c0b2 100644 --- a/source/games/blood/src/bloodactor.h +++ b/source/games/blood/src/bloodactor.h @@ -46,6 +46,7 @@ public: XSPRITE xspr; SPRITEHIT hit; DUDEEXTRA dudeExtra; + PClass* originalType; // what this originally started as. TObjPtr ownerActor; // was previously stored in the sprite's owner field. // nnext stuff. For now not exported to scripting. @@ -130,6 +131,11 @@ public: return IsKindOf(BloodDudeBaseClass); } + bool WasDudeActor() + { + return originalType && originalType->IsDescendantOf(BloodDudeBaseClass); + } + bool IsThingActor() { return IsKindOf(BloodThingBaseClass); diff --git a/source/games/blood/src/callback.cpp b/source/games/blood/src/callback.cpp index 10a20ce23..3c7a31791 100644 --- a/source/games/blood/src/callback.cpp +++ b/source/games/blood/src/callback.cpp @@ -273,7 +273,7 @@ void Respawn(DBloodActor* actor) // 9 assert(actor->spr.intowner != kStatRespawn); assert(actor->spr.intowner >= 0 && actor->spr.intowner < kMaxStatus); ChangeActorStat(actor, actor->spr.intowner); - actor->ChangeType(actor->spr.inittype); + actor->ChangeType(actor->originalType); actor->SetOwner(nullptr); actor->spr.flags &= ~kHitagRespawn; actor->vel.Zero(); diff --git a/source/games/blood/src/loadsave.cpp b/source/games/blood/src/loadsave.cpp index 8207d98f4..4f22df8a4 100644 --- a/source/games/blood/src/loadsave.cpp +++ b/source/games/blood/src/loadsave.cpp @@ -71,6 +71,7 @@ void DBloodActor::Serialize(FSerializer& arc) Super::Serialize(arc); arc ("hasx", hasx) + ("spawntype", originalType) ("basepoint", basePoint); // The rest is only relevant if the actor has an xsprite. diff --git a/source/games/blood/src/nnexts.cpp b/source/games/blood/src/nnexts.cpp index c7f46e35b..e51225e81 100644 --- a/source/games/blood/src/nnexts.cpp +++ b/source/games/blood/src/nnexts.cpp @@ -5658,7 +5658,7 @@ bool modernTypeOperateSprite(DBloodActor* actor, EVENT& event) // dude to thing morphing causing a lot of problems since it continues receiving commands after dude is dead. // this leads to weird stuff like exploding with gargoyle gib or corpse disappearing immediately. // let's allow only specific commands here to avoid this. - if (actor->spr.inittype < kDudeBase || actor->spr.inittype >= kDudeMax) return false; + if (!actor->WasDudeActor()) return false; else if (event.cmd != kCmdToggle && event.cmd != kCmdOff && event.cmd != kCmdSpriteImpact) return true; DudeToGibCallback1(actor); // set proper gib type just in case DATAs was changed from the outside. return false; diff --git a/source/games/blood/src/nnexts.h b/source/games/blood/src/nnexts.h index 921de6f73..cf444fdb4 100644 --- a/source/games/blood/src/nnexts.h +++ b/source/games/blood/src/nnexts.h @@ -351,7 +351,6 @@ void callbackMakeMissileBlocking(DBloodActor* actor); void callbackGenDudeUpdate(DBloodActor* actor); // ------------------------------------------------------------------------- // DBloodPlayer* getPlayerById(int id); -bool IsBurningDude(DBloodActor* pSprite); bool IsKillableDude(DBloodActor* pSprite); bool isActive(DBloodActor* nSprite); int getDataFieldOfObject(EventObject& eob, int dataIndex); diff --git a/source/games/blood/src/seq.cpp b/source/games/blood/src/seq.cpp index 19030a6d0..cfc58c813 100644 --- a/source/games/blood/src/seq.cpp +++ b/source/games/blood/src/seq.cpp @@ -693,7 +693,7 @@ void seqProcess(int nTicks) if (actor) { evKillActor(actor); - if ((actor->spr.hitag & kAttrRespawn) != 0 && (actor->spr.inittype >= kDudeBase && actor->spr.inittype < kDudeMax)) + if ((actor->spr.hitag & kAttrRespawn) != 0 && actor->WasDudeActor()) evPostActor(actor, gGameOptions.nMonsterRespawnTime, AF(Respawn)); else DeleteSprite(actor); // safe to not use actPostSprite here } diff --git a/source/games/blood/src/triggers.cpp b/source/games/blood/src/triggers.cpp index 76bc3399d..28471557f 100644 --- a/source/games/blood/src/triggers.cpp +++ b/source/games/blood/src/triggers.cpp @@ -68,7 +68,7 @@ bool SetSpriteState(DBloodActor* actor, int nState, DBloodActor* initiator) actor->xspr.busy = IntToFixed(nState); actor->xspr.state = nState; evKillActor(actor, initiator); - if ((actor->spr.flags & kHitagRespawn) != 0 && actor->spr.inittype >= kDudeBase && actor->spr.inittype < kDudeMax) + if ((actor->spr.flags & kHitagRespawn) != 0 && actor->WasDudeActor()) { actor->xspr.respawnPending = 3; evPostActor(actor, gGameOptions.nMonsterRespawnTime, AF(Respawn)); @@ -480,26 +480,22 @@ void OperateSprite(DBloodActor* actor, EVENT event) break; case kMarkerDudeSpawn: - if (gGameOptions.nMonsterSettings && actor->xspr.data1 >= kDudeBase && actor->xspr.data1 < kDudeMax) + if (gGameOptions.nMonsterSettings) { - auto spawned = actSpawnDude(actor, actor->xspr.data1, -1); - if (spawned) { - if (AllowedKillType(spawned)) Level.addKillCount(); - switch (actor->xspr.data1) { - case kDudeBurningInnocent: - case kDudeBurningCultist: - case kDudeBurningZombieAxe: - case kDudeBurningZombieButcher: - case kDudeBurningTinyCaleb: - case kDudeBurningBeast: { - spawned->xspr.health = static_cast(GetDefaultByType(GetSpawnType(actor->xspr.data1)))->startHealth() << 4; - spawned->xspr.burnTime = 10; - spawned->SetTarget(nullptr); - aiActivateDude(spawned); - break; - default: - break; - } + auto type = GetSpawnType(actor->xspr.data1); + if (type->IsDescendantOf(BloodDudeBaseClass)) + { + auto spawned = actSpawnDude(actor, actor->xspr.data1, -1); + if (spawned) + { + if (AllowedKillType(spawned)) Level.addKillCount(); + if (IsBurningDude(spawned)) + { + spawned->xspr.health = static_cast(GetDefaultByType(GetSpawnType(actor->xspr.data1)))->startHealth() << 4; + spawned->xspr.burnTime = 10; + spawned->SetTarget(nullptr); + aiActivateDude(spawned); + } } } } @@ -2279,7 +2275,7 @@ void trInit(TArray& actors) for (auto actor : actors) { if (!actor->exists()) continue; - actor->spr.inittype = actor->GetType(); + actor->originalType = actor->GetClass(); actor->basePoint = actor->spr.pos; } for (auto& wal : wall)