From 2e054dd827226d005d28a5af360a22e180680cd3 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 12 Oct 2023 17:38:35 +0200 Subject: [PATCH] WIP for actKillDude scriptification --- source/games/blood/src/actor.cpp | 276 +----------------- source/games/blood/src/actor.h | 6 +- source/games/blood/src/aiunicult.cpp | 17 ++ source/games/blood/src/vmexports.cpp | 10 + .../zscript/games/blood/actors/dudes.zs | 256 ++++++++++++++++ 5 files changed, 293 insertions(+), 272 deletions(-) diff --git a/source/games/blood/src/actor.cpp b/source/games/blood/src/actor.cpp index 5ae2a9786..7ca515d48 100644 --- a/source/games/blood/src/actor.cpp +++ b/source/games/blood/src/actor.cpp @@ -1197,84 +1197,6 @@ static void checkAddFrag(DBloodActor* killerActor, DBloodActor* actor) // //--------------------------------------------------------------------------- -static void checkDropObjects(DBloodActor* actor) -{ - if (actor->xspr.key > 0) actDropObject(actor, kItemKeyBase + actor->xspr.key - 1); - if (actor->xspr.dropMsg > 0) actDropObject(actor, actor->xspr.dropMsg); - - switch (actor->GetType()) - { - case kDudeCultistTommy: - { - int nRand = Random(100); - if (nRand < 10) actDropObject(actor, kItemWeaponTommygun); - else if (nRand < 50) actDropObject(actor, kItemAmmoTommygunFew); - break; - } - case kDudeCultistShotgun: - { - int nRand = Random(100); - if (nRand <= 10) actDropObject(actor, kItemWeaponSawedoff); - else if (nRand <= 50) actDropObject(actor, kItemAmmoSawedoffFew); - break; - } - } -} - -//--------------------------------------------------------------------------- -// -// -// -//--------------------------------------------------------------------------- - -static int checkDamageType(DBloodActor* actor, DAMAGE_TYPE damageType) -{ - int nSeq; - - switch (damageType) - { - case kDamageExplode: - { - nSeq = 2; - - auto snd = actor->SoundVar(NAME_explodeSound); - sfxPlay3DSound(actor, snd, -1, 0); - break; - } - case kDamageBurn: - nSeq = 3; - sfxPlay3DSound(actor, 351, -1, 0); - break; - case kDamageSpirit: - switch (actor->GetType()) { - case kDudeZombieAxeNormal: - case kDudeZombieAxeBuried: - nSeq = 14; - break; - case kDudeZombieButcher: - nSeq = 11; - break; - default: - nSeq = 1; - break; - } - break; - case kDamageFall: - nSeq = 1; - break; - default: - nSeq = 1; - break; - } - return nSeq; -} - -//--------------------------------------------------------------------------- -// -// -// -//--------------------------------------------------------------------------- - static void spawnGibs(DBloodActor* actor, int type, fixed_t velz) { double top, bottom; @@ -1400,9 +1322,9 @@ void actKillDude(DBloodActor* killerActor, DBloodActor* actor, DAMAGE_TYPE damag { assert(actor->IsDudeActor()&& actor->hasX()); - // if (onKill(killerActor, actor, damageType, damage)) return; // call an optional script handler. + // if (preKill(killerActor, actor, damageType, damage)) return; // call an optional script handler. (only needed by custom dudes so far. - if (actKillDudeStage1(actor, damageType)) return; + if (actKillDudeStage1(actor, damageType)) return; // check if the killed actor should transition to something else. for (int p = connecthead; p >= 0; p = connectpoint2[p]) { @@ -1412,199 +1334,15 @@ void actKillDude(DBloodActor* killerActor, DBloodActor* actor, DAMAGE_TYPE damag if (actor->GetType() != kDudeCultistBeast) trTriggerSprite(actor, kCmdOff, killerActor); - actor->spr.flags |= 7; + actor->spr.flags |= kPhysMove | kPhysGravity | kPhysFalling; checkAddFrag(killerActor, actor); - checkDropObjects(actor); - int nSeq = checkDamageType(actor, damageType); + // from here it will be delegated to the scripts + actOnKillDude(killerActor, actor, damageType, damage); - if (!getSequence(actor->seqStartName(), actor->seqStartID() + nSeq)) - { - seqKill(actor); - AddKill(killerActor, actor); - actPostSprite(actor, kStatFree); - return; - } - - auto Owner = actor->GetOwner(); - switch (actor->GetType()) - { - case kDudeZombieAxeNormal: - zombieAxeNormalDeath(actor, nSeq); - break; - - case kDudeCultistTommy: - case kDudeCultistShotgun: - case kDudeCultistTesla: - case kDudeCultistTNT: - sfxPlay3DSound(actor, 1018 + Random(2), -1, 0); - seqSpawn(actor->seqStartName(), actor->seqStartID() + nSeq, actor, nSeq == 3 ? AF(DudeToGibCallback2) : AF(DudeToGibCallback1)); - break; - - case kDudeBurningCultist: - burningCultistDeath(actor, nSeq); - damageType = kDamageExplode; - break; - -#ifdef NOONE_EXTENSIONS - case kDudeModernCustom: - modernCustomDudeDeath(actor, nSeq, damageType); - genDudePostDeath(actor, damageType, damage); - return; - - case kDudeModernCustomBurning: - modernCustomDudeBurningDeath(actor, nSeq); - genDudePostDeath(actor, kDamageExplode, damage); - return; -#endif - - case kDudeBurningZombieAxe: - zombieAxeBurningDeath(actor, nSeq); - damageType = kDamageExplode; - break; - - case kDudeBurningZombieButcher: - genericDeath(actor, nSeq, 1204, 4608 + 10); // this was hardcoded to the non-burning butcher's base seq. - break; - - case kDudeBurningInnocent: - damageType = kDamageExplode; - seqSpawn(actor->seqStartName(), actor->seqStartID() + 7, actor, AF(DudeToGibCallback1)); - break; - - case kDudeZombieButcher: - zombieButcherDeath(actor, nSeq); - break; - - case kDudeGargoyleFlesh: - genericDeath(actor, nSeq, 1403, actor->seqStartID() + nSeq); - break; - - case kDudeGargoyleStone: - genericDeath(actor, nSeq, 1453, actor->seqStartID() + nSeq); - break; - - case kDudePhantasm: - genericDeath(actor, nSeq, 1603, actor->seqStartID() + nSeq); - break; - - case kDudeHellHound: - genericDeath(actor, nSeq, 1303, actor->seqStartID() + nSeq); - break; - - case kDudeHand: - genericDeath(actor, nSeq, 1903, actor->seqStartID() + nSeq); - break; - - case kDudeSpiderBrown: - if (Owner) Owner->dudeExtra.birthCounter--; - genericDeath(actor, nSeq, 1803, actor->seqStartID() + nSeq); - break; - - case kDudeSpiderRed: - if (Owner) Owner->dudeExtra.birthCounter--; - genericDeath(actor, nSeq, 1803, actor->seqStartID() + nSeq); - break; - - case kDudeSpiderBlack: - if (Owner) Owner->dudeExtra.birthCounter--; - genericDeath(actor, nSeq, 1803, actor->seqStartID() + nSeq); - break; - - case kDudeSpiderMother: - sfxPlay3DSound(actor, 1850, -1, 0); - seqSpawn(actor->seqStartName(), actor->seqStartID() + nSeq, actor); - break; - - case kDudeGillBeast: - genericDeath(actor, nSeq, 1703, actor->seqStartID() + nSeq); - break; - - case kDudeBoneEel: - genericDeath(actor, nSeq, 1503, actor->seqStartID() + nSeq); - break; - - case kDudeBat: - genericDeath(actor, nSeq, 2003, actor->seqStartID() + nSeq); - break; - - case kDudeRat: - genericDeath(actor, nSeq, 2103, actor->seqStartID() + nSeq); - break; - - case kDudePodGreen: - case kDudeTentacleGreen: - case kDudePodFire: - case kDudeTentacleFire: - if ((actor->spr.cstat & CSTAT_SPRITE_YFLIP)) actor->spr.cstat &= ~CSTAT_SPRITE_YFLIP; - switch (actor->GetType()) - { - case kDudePodGreen: - genericDeath(actor, nSeq, 2203, actor->seqStartID() + nSeq); - break; - case kDudeTentacleGreen: - sfxPlay3DSound(actor, damage == 5 ? 2471 : 2472, -1, 0); - seqSpawn(actor->seqStartName(), actor->seqStartID() + nSeq, actor); - break; - case kDudePodFire: - sfxPlay3DSound(actor, damage == 5 ? 2451 : 2452, -1, 0); - seqSpawn(actor->seqStartName(), actor->seqStartID() + nSeq, actor); - break; - case kDudeTentacleFire: - sfxPlay3DSound(actor, 2501, -1, 0); - seqSpawn(actor->seqStartName(), actor->seqStartID() + nSeq, actor); - break; - } - break; - - case kDudePodMother: - case kDudeTentacleMother: - genericDeath(actor, nSeq, 2203, actor->seqStartID() + nSeq); - break; - - case kDudeCerberusTwoHead: - case kDudeCerberusOneHead: - genericDeath(actor, nSeq, 2303, actor->seqStartID() + nSeq); - break; - - case kDudeTchernobog: - sfxPlay3DSound(actor, 2380, -1, 0); - seqSpawn(actor->seqStartName(), actor->seqStartID() + nSeq, actor); - break; - - case kDudeBurningTinyCaleb: - damageType = kDamageExplode; - seqSpawn(actor->seqStartName(), actor->seqStartID() + 11, actor, AF(DudeToGibCallback1)); - break; - - case kDudeBeast: - sfxPlay3DSound(actor, 9000 + Random(2), -1, 0); - seqSpawn(actor->seqStartName(), actor->seqStartID() + nSeq, actor, nSeq == 3 ? AF(DudeToGibCallback2) : AF(DudeToGibCallback1)); - break; - - case kDudeBurningBeast: - damageType = kDamageExplode; - seqSpawn(actor->seqStartName(), actor->seqStartID() + 12, actor, AF(DudeToGibCallback1)); - break; - - default: - seqSpawn(actor->seqStartName(), actor->seqStartID() + nSeq, actor); - break; - } - - if (damageType == kDamageExplode) - { - auto gibType = actor->IntArray("gibtype"); - for (int i = 0; i < 3; i++) - if (gibType[i] > -1) - GibSprite(actor, (GIBTYPE)gibType[i], nullptr, nullptr); - for (int i = 0; i < 4; i++) - fxSpawnBlood(actor, damage); - } + // keep the kill credit on the native side to avoid problems with the statistics. AddKill(killerActor, actor); - actCheckRespawn(actor); - actor->ChangeType(kThingBloodChunks); - actPostSprite(actor, kStatThing); + } //--------------------------------------------------------------------------- diff --git a/source/games/blood/src/actor.h b/source/games/blood/src/actor.h index 4ce58c9a8..8dc354b15 100644 --- a/source/games/blood/src/actor.h +++ b/source/games/blood/src/actor.h @@ -145,8 +145,6 @@ bool actCheckRespawn(DBloodActor *pSprite); void actFireVector(DBloodActor* shooter, double offset, double zoffset, DVector3 dv, VECTOR_TYPE vectorType, double nRange = -1); void actPostSprite(DBloodActor* actor, int status); void actPostProcess(void); -void actOnHit(DBloodActor *actor, Collision& hit); -void callActorFunction(VMFunction* funcID, DBloodActor* actor); extern const int16_t DudeDifficulty[]; @@ -166,7 +164,9 @@ bool IsUnderwaterSector(sectortype* pSector); } #define AF(func) DBloodActor_##func##_VMPtr -void callActorFunction(VMFunction* callback, DBloodActor* actor); +void actOnHit(DBloodActor* actor, Collision& hit); +void callActorFunction(VMFunction* funcID, DBloodActor* actor); +void actOnKillDude(DBloodActor* killerActor, DBloodActor* actor, DAMAGE_TYPE damageType, int damage); #define xx(n) inline PClassActor* n##Class; #include "classnames.h" diff --git a/source/games/blood/src/aiunicult.cpp b/source/games/blood/src/aiunicult.cpp index 6cbd5854e..4bfc91878 100644 --- a/source/games/blood/src/aiunicult.cpp +++ b/source/games/blood/src/aiunicult.cpp @@ -2692,6 +2692,23 @@ case kDudePodMother: // FakeDude type (no seq, custom flags, clipdist and cstat break; } +*/ + +/* onDeath + +#ifdef NOONE_EXTENSIONS + case kDudeModernCustom: + modernCustomDudeDeath(actor, nSeq, damageType); + genDudePostDeath(actor, damageType, damage); + return; + + case kDudeModernCustomBurning: + modernCustomDudeBurningDeath(actor, nSeq); + genDudePostDeath(actor, kDamageExplode, damage); + return; +#endif + + */ END_BLD_NS #endif diff --git a/source/games/blood/src/vmexports.cpp b/source/games/blood/src/vmexports.cpp index e3f1641f9..600c09560 100644 --- a/source/games/blood/src/vmexports.cpp +++ b/source/games/blood/src/vmexports.cpp @@ -528,5 +528,15 @@ void callActorFunction(VMFunction* funcID, DBloodActor* actor) } +void actOnKillDude(DBloodActor* killerActor, DBloodActor* actor, DAMAGE_TYPE damageType, int damage) +{ + IFVIRTUALPTR(actor, DBloodActor, onKillDude) + { + int postaction = -1; + VMValue param[] = { actor, killerActor, (int)damageType, damage }; + VMCall(func, param, 4, nullptr, 0); + } +} + END_BLD_NS diff --git a/wadsrc/static/zscript/games/blood/actors/dudes.zs b/wadsrc/static/zscript/games/blood/actors/dudes.zs index d40848dc7..7d5410bbc 100644 --- a/wadsrc/static/zscript/games/blood/actors/dudes.zs +++ b/wadsrc/static/zscript/games/blood/actors/dudes.zs @@ -335,6 +335,225 @@ class BloodDudeBase : Bloodactor return gGameOptions.nMonsterRespawnTime; return -1; } + + virtual int checkDamageType(int damageType) + { + int nSeq; + + switch (damageType) + { + case kDamageExplode: + { + nSeq = 2; + self.play3DSound(actor.explodeSound, -1, 0); + break; + } + case kDamageBurn: + nSeq = 3; + sfxPlay3DSoundID(actor, 351, -1, 0); + break; + + default: + nSeq = 1; + break; + } + return nSeq; + } + + virtual void checkDropObjects() + { + if (self.xspr.key > 0) self.dropObject(actor, GetSpawnType(kItemKeyBase + self.xspr.key - 1)); + if (self.xspr.dropMsg > 0) actDropObject(actor, GetSpawnType(self.xspr.dropMsg)); + } + + virtual int killAction(int damageType, int damage) + { + // todo: split this up + /* + auto Owner = actor->GetOwner(); + switch (actor->GetType()) + { + case kDudeZombieAxeNormal: + zombieAxeNormalDeath(actor, nSeq); + break; + + case kDudeCultistTommy: + case kDudeCultistShotgun: + case kDudeCultistTesla: + case kDudeCultistTNT: + sfxPlay3DSound(actor, 1018 + Random(2), -1, 0); + seqSpawn(actor->seqStartName(), actor->seqStartID() + nSeq, actor, nSeq == 3 ? AF(DudeToGibCallback2) : AF(DudeToGibCallback1)); + break; + + case kDudeBurningCultist: + burningCultistDeath(actor, nSeq); + damageType = kDamageExplode; + break; + + case kDudeBurningZombieAxe: + zombieAxeBurningDeath(actor, nSeq); + damageType = kDamageExplode; + break; + + case kDudeBurningZombieButcher: + genericDeath(actor, nSeq, 1204, 4608 + 10); // this was hardcoded to the non-burning butcher's base seq. + break; + + case kDudeBurningInnocent: + damageType = kDamageExplode; + seqSpawn(actor->seqStartName(), actor->seqStartID() + 7, actor, AF(DudeToGibCallback1)); + break; + + case kDudeZombieButcher: + zombieButcherDeath(actor, nSeq); + break; + + case kDudeGargoyleFlesh: + genericDeath(actor, nSeq, 1403, actor->seqStartID() + nSeq); + break; + + case kDudeGargoyleStone: + genericDeath(actor, nSeq, 1453, actor->seqStartID() + nSeq); + break; + + case kDudePhantasm: + genericDeath(actor, nSeq, 1603, actor->seqStartID() + nSeq); + break; + + case kDudeHellHound: + genericDeath(actor, nSeq, 1303, actor->seqStartID() + nSeq); + break; + + case kDudeHand: + genericDeath(actor, nSeq, 1903, actor->seqStartID() + nSeq); + break; + + case kDudeSpiderBrown: + if (Owner) Owner->dudeExtra.birthCounter--; + genericDeath(actor, nSeq, 1803, actor->seqStartID() + nSeq); + break; + + case kDudeSpiderRed: + if (Owner) Owner->dudeExtra.birthCounter--; + genericDeath(actor, nSeq, 1803, actor->seqStartID() + nSeq); + break; + + case kDudeSpiderBlack: + if (Owner) Owner->dudeExtra.birthCounter--; + genericDeath(actor, nSeq, 1803, actor->seqStartID() + nSeq); + break; + + case kDudeSpiderMother: + sfxPlay3DSound(actor, 1850, -1, 0); + seqSpawn(actor->seqStartName(), actor->seqStartID() + nSeq, actor); + break; + + case kDudeGillBeast: + genericDeath(actor, nSeq, 1703, actor->seqStartID() + nSeq); + break; + + case kDudeBoneEel: + genericDeath(actor, nSeq, 1503, actor->seqStartID() + nSeq); + break; + + case kDudeBat: + genericDeath(actor, nSeq, 2003, actor->seqStartID() + nSeq); + break; + + case kDudeRat: + genericDeath(actor, nSeq, 2103, actor->seqStartID() + nSeq); + break; + + case kDudePodGreen: + case kDudeTentacleGreen: + case kDudePodFire: + case kDudeTentacleFire: + if ((actor->spr.cstat & CSTAT_SPRITE_YFLIP)) actor->spr.cstat &= ~CSTAT_SPRITE_YFLIP; + switch (actor->GetType()) + { + case kDudePodGreen: + genericDeath(actor, nSeq, 2203, actor->seqStartID() + nSeq); + break; + case kDudeTentacleGreen: + sfxPlay3DSound(actor, damage == 5 ? 2471 : 2472, -1, 0); + seqSpawn(actor->seqStartName(), actor->seqStartID() + nSeq, actor); + break; + case kDudePodFire: + sfxPlay3DSound(actor, damage == 5 ? 2451 : 2452, -1, 0); + seqSpawn(actor->seqStartName(), actor->seqStartID() + nSeq, actor); + break; + case kDudeTentacleFire: + sfxPlay3DSound(actor, 2501, -1, 0); + seqSpawn(actor->seqStartName(), actor->seqStartID() + nSeq, actor); + break; + } + break; + + case kDudePodMother: + case kDudeTentacleMother: + genericDeath(actor, nSeq, 2203, actor->seqStartID() + nSeq); + break; + + case kDudeCerberusTwoHead: + case kDudeCerberusOneHead: + genericDeath(actor, nSeq, 2303, actor->seqStartID() + nSeq); + break; + + case kDudeTchernobog: + sfxPlay3DSound(actor, 2380, -1, 0); + seqSpawn(actor->seqStartName(), actor->seqStartID() + nSeq, actor); + break; + + case kDudeBurningTinyCaleb: + damageType = kDamageExplode; + seqSpawn(actor->seqStartName(), actor->seqStartID() + 11, actor, AF(DudeToGibCallback1)); + break; + + case kDudeBeast: + sfxPlay3DSound(actor, 9000 + Random(2), -1, 0); + seqSpawn(actor->seqStartName(), actor->seqStartID() + nSeq, actor, nSeq == 3 ? AF(DudeToGibCallback2) : AF(DudeToGibCallback1)); + break; + + case kDudeBurningBeast: + damageType = kDamageExplode; + seqSpawn(actor->seqStartName(), actor->seqStartID() + 12, actor, AF(DudeToGibCallback1)); + break; + + default: + seqSpawn(actor->seqStartName(), actor->seqStartID() + nSeq, actor); + break; + } + + */ + } + + // this should only be overridden in special cases, normally killAction should suffice + virtual void onKillDude(BloodActor killerActor, int damageType, int damage) + { + self.checkDropObjects(); + int nSeq = self.checkDamageType(damageType); + + if (!getSequence(actor->seqStartName, actor->seqStartID + nSeq)) + { + self.seqKill(actor); + self.postSprite(kStatFree); + return; + } + + int postAction = self.killAction(damageType, damage); + + if (postaction == 1) + { + for (int i = 0; i < 3; i++) + if (self.gibType[i] > -1) + self.GibSprite(gibType[i], nullptr, nullptr); + for (int i = 0; i < 4; i++) + self.fxSpawnBlood(damage); + } + self.checkRespawn(); + self.changeType("BloodThingBloodChunks"); + self.postSprite(kStatThing); + } } class BloodPlayerBase : BloodDudeBase @@ -404,6 +623,14 @@ class BloodDudeCultistTommy : BloodDudeBase preloadseq 6, 7, 8, 9, 13, 14, 15; BurnType "BloodDudeBurningCultist"; } + + override void checkDropObjects() + { + super.checkDropObjects(); + int nRand = Blood.Random(100); + if (nRand < 10) self.dropObject("BloodItemWeaponTommygun"); + else if (nRand < 50) self.DropObject("BloodItemAmmoTommygunFew"); + } } class BloodDudeCultistShotgun : BloodDudeBase @@ -439,6 +666,14 @@ class BloodDudeCultistShotgun : BloodDudeBase preloadseq 6, 7, 8, 9, 13, 14, 15; BurnType "BloodDudeBurningCultist"; } + + override void checkDropObjects() + { + super.checkDropObjects(); + int nRand = Blood.Random(100); + if (nRand < 10) self.dropObject("BloodItemWeaponSawedoff"); + else if (nRand < 50) self.DropObject("BloodItemAmmoSawedoffFew"); + } } class BloodDudeZombieAxeNormal : BloodDudeBase @@ -471,6 +706,13 @@ class BloodDudeZombieAxeNormal : BloodDudeBase preloadseq 6, 7, 8, 11, 13, 14; BurnType "BloodDudeBurningZombieAxe"; } + + override int checkDamageType(int damageType) + { + if (damageType == kDamageSpirit) return 14; + return super.checkDamageType(damageType); + } + } class BloodDudeZombieButcher : BloodDudeBase @@ -503,6 +745,13 @@ class BloodDudeZombieButcher : BloodDudeBase preloadseq 6, 7, 8, 9, 10, 11; BurnType "BloodDudeBurningZombieButcher"; } + + override int checkDamageType(int damageType) + { + if (damageType == kDamageSpirit) return 11; + return super.checkDamageType(damageType); + } + } class BloodDudeZombieAxeBuried : BloodDudeBase @@ -535,6 +784,13 @@ class BloodDudeZombieAxeBuried : BloodDudeBase preloadseq 12, 9, 10; BurnType "BloodDudeBurningZombieAxe"; } + + override int checkDamageType(int damageType) + { + if (damageType == kDamageSpirit) return 14; + return super.checkDamageType(damageType); + } + } class BloodDudeGargoyleFlesh : BloodDudeBase