diff --git a/source/games/blood/src/nnextcdud.cpp b/source/games/blood/src/nnextcdud.cpp index e7f536b0d..7691429fa 100644 --- a/source/games/blood/src/nnextcdud.cpp +++ b/source/games/blood/src/nnextcdud.cpp @@ -703,7 +703,7 @@ bool DCustomDude::NewState(AISTATE* pState) if (pState->seqId > 0) { - seqSpawn(pState->seqId, pSpr, *pState->funcId); + /*!!!*/seqSpawn(pState->seqId, pSpr, *pState->funcId); } else if (pState->seqId == 0) { @@ -2025,7 +2025,8 @@ void CUSTOMDUDE_SETUP::SoundFill(void) void CUSTOMDUDE_SETUP::FindLargestPic(void) { int i, j, nHeigh = 0; - AISTATE* pState; Seq* pSeq; + AISTATE* pState; + const Seq* pSeq; for (i = 0; i < kCdudeStateMax; i++) { @@ -3183,9 +3184,7 @@ void CUSTOMDUDEV2_SETUP::SetupWeapons(void) { if (!helperSeqTriggerExists(pState->seqId)) { - Seq* pSeq = getSequence(pState->seqId); - if (pSeq) - pSeq->frames[pSeq->nFrames - 1].trigger = 1; + pDude->triggerSeqs.Push(pState->seqId); } pState++; @@ -3779,7 +3778,7 @@ void CUSTOMDUDEV2_SETUP::Setup(void) case kParGroupDodge: SetupDodge(); break; case kParGroupKnockout: SetupKnockout(); break; case kParGroupWeapon: SetupWeapons(); break; - case kParGroupFXEffect: SetupEffect(); break; + case kParGroupFXEffect: SetupEffect(); break; case kParGroupMovePat: SetupMovePattern(); break; case kParGroupDropItem: SetupDropItem(); break; } @@ -3935,9 +3934,7 @@ void CUSTOMDUDEV1_SETUP::WeaponMeleeSet(CUSTOMDUDE_WEAPON* pWeapon) { if (!helperSeqTriggerExists(pState->seqId)) { - Seq* pSeq = getSequence(pState->seqId); - if (pSeq) - pSeq->frames[pSeq->nFrames - 1].trigger = 1; + pDude->triggerSeqs.Push(pState->seqId); } pState++; @@ -4209,10 +4206,10 @@ static FTextureID helperGetFirstPic(DCustomDude* pDude) int nSeq = pDude->GetStateSeq(kCdudeStateIdle, kCdudePostureL); if (getSequence(nSeq)) { - Seq* pSeq = getSequence(nSeq); + const Seq* pSeq = getSequence(nSeq); if (pSeq) { - SEQFRAME* pFrame = &pSeq->frames[0]; + const SEQFRAME* pFrame = &pSeq->frames[0]; nPic = tileGetTextureID(pFrame->tile + (pFrame->tile2 << 12)); } } @@ -4223,7 +4220,7 @@ static FTextureID helperGetFirstPic(DCustomDude* pDude) static bool helperSeqTriggerExists(int nSeq) { int i; - Seq* pSeq = getSequence(nSeq); + const Seq* pSeq = getSequence(nSeq); if (pSeq) { i = pSeq->nFrames; diff --git a/source/games/blood/src/nnextcdud.h b/source/games/blood/src/nnextcdud.h index 45163e81c..b608104c9 100644 --- a/source/games/blood/src/nnextcdud.h +++ b/source/games/blood/src/nnextcdud.h @@ -1216,6 +1216,7 @@ class DCustomDude : public DObject CUSTOMDUDE_EFFECT effects[kCdudeMaxEffectGroups]; // fx, gib effect stuff AISTATE states[kCdudeStateMax][kCdudePostureMax]; // includes states for weapons TArray> pSlaves; // summoned dudes under control of this dude + TArray triggerSeqs; // this originally hacked the global ser uint8_t medium ; // medium in which it can live uint8_t posture ; // current posture unsigned int mass ; // mass in KG diff --git a/source/games/blood/src/nnexts.cpp b/source/games/blood/src/nnexts.cpp index dc32fa01a..9fa2dc275 100644 --- a/source/games/blood/src/nnexts.cpp +++ b/source/games/blood/src/nnexts.cpp @@ -5656,7 +5656,7 @@ void useUniMissileGen(DBloodActor* sourceactor, DBloodActor* actor) canInherit &= ~0x8; SEQINST* pInst = GetInstance(missileactor); - Seq* pSeq = pInst->pSequence; + const Seq* pSeq = pInst->pSequence; for (int i = 0; i < pSeq->nFrames; i++) { if ((canInherit & 0x4) && pSeq->frames[i].palette != 0) canInherit &= ~0x4; @@ -6423,7 +6423,7 @@ bool seqForceOverride(DBloodActor* pSpr, SEQINST* pInst, bool ovrPic, bool ovrPa { bool xrp, yrp, plu; bool killSeq = (ovrPic || ovrShd); - Seq* pSeq; + const Seq* pSeq; if (pInst && ((pSeq = pInst->pSequence) != NULL)) { @@ -6476,7 +6476,7 @@ void gibPropagateAppearance(DBloodActor* pSrc, DBloodActor* pFrom, DBloodActor* if (pDest->hasX() && (t = seqGetID(pDest)) >= 0) { - Seq* pSeq = getSequence(t); + const Seq* pSeq = getSequence(t); if (pSeq) { if (!killSeq) @@ -8815,9 +8815,9 @@ bool isOnRespawn(DBloodActor* pSpr) // //--------------------------------------------------------------------------- -bool seqCanOverride(Seq* pSeq, int nFrame, bool* xrp, bool* yrp, bool* plu) +bool seqCanOverride(const Seq* pSeq, int nFrame, bool* xrp, bool* yrp, bool* plu) { - SEQFRAME* pFrame; + const SEQFRAME* pFrame; *xrp = *yrp = *plu = true; if (!pSeq) return true; diff --git a/source/games/blood/src/nnexts.h b/source/games/blood/src/nnexts.h index d50b2c2f6..06b28e661 100644 --- a/source/games/blood/src/nnexts.h +++ b/source/games/blood/src/nnexts.h @@ -383,7 +383,7 @@ void actPropagateSpriteOwner(DBloodActor* pShot, DBloodActor* pSpr); int nnExtDudeStartHealth(DBloodActor* pSpr, int nHealth); void nnExtSprScaleSet(DBloodActor* actor, int nScale); struct Seq; -bool seqCanOverride(Seq* pSeq, int nFrame, bool* xrp, bool* yrp, bool* plu); +bool seqCanOverride(const Seq* pSeq, int nFrame, bool* xrp, bool* yrp, bool* plu); inline unsigned int perc2val(unsigned int reqPerc, unsigned int val) { return (val * reqPerc) / 100; } inline int perc2val(int reqPerc, int val) { return (val * reqPerc) / 100; } inline double perc2val(int reqPerc, double val) { return (val * reqPerc) / 100; } diff --git a/source/games/blood/src/seq.cpp b/source/games/blood/src/seq.cpp index 2063d005b..e27f55216 100644 --- a/source/games/blood/src/seq.cpp +++ b/source/games/blood/src/seq.cpp @@ -42,7 +42,7 @@ BEGIN_BLD_NS // //--------------------------------------------------------------------------- -void Seq::Precache(int palette) +void Seq::Precache(int palette) const { if (memcmp(signature, "SEQ\x1a", 4) != 0) I_Error("Invalid sequence"); @@ -64,7 +64,7 @@ void seqPrecacheId(int id, int palette) // //--------------------------------------------------------------------------- -void UpdateCeiling(sectortype* pSector, SEQFRAME* pFrame) +void UpdateCeiling(sectortype* pSector, const SEQFRAME* pFrame) { pSector->setceilingtexture(seqGetTexture(pFrame)); pSector->ceilingshade = pFrame->shade; @@ -78,7 +78,7 @@ void UpdateCeiling(sectortype* pSector, SEQFRAME* pFrame) // //--------------------------------------------------------------------------- -void UpdateFloor(sectortype* pSector, SEQFRAME* pFrame) +void UpdateFloor(sectortype* pSector, const SEQFRAME* pFrame) { pSector->setfloortexture(seqGetTexture(pFrame)); pSector->floorshade = pFrame->shade; @@ -92,7 +92,7 @@ void UpdateFloor(sectortype* pSector, SEQFRAME* pFrame) // //--------------------------------------------------------------------------- -void UpdateWall(walltype* pWall, SEQFRAME* pFrame) +void UpdateWall(walltype* pWall, const SEQFRAME* pFrame) { assert(pWall->hasX()); pWall->setwalltexture(seqGetTexture(pFrame)); @@ -122,7 +122,7 @@ void UpdateWall(walltype* pWall, SEQFRAME* pFrame) // //--------------------------------------------------------------------------- -void UpdateMasked(walltype* pWall, SEQFRAME* pFrame) +void UpdateMasked(walltype* pWall, const SEQFRAME* pFrame) { assert(pWall->hasX()); walltype* pWallNext = pWall->nextWall(); @@ -179,7 +179,7 @@ void UpdateMasked(walltype* pWall, SEQFRAME* pFrame) // //--------------------------------------------------------------------------- -void UpdateSprite(DBloodActor* actor, SEQFRAME* pFrame) +void UpdateSprite(DBloodActor* actor, const SEQFRAME* pFrame) { assert(actor->hasX()); if (actor->spr.flags & 2) @@ -336,11 +336,13 @@ void SEQINST::Update() break; } - // all seq callbacks are for sprites, but there's no sanity checks here that what gets passed is meant to be for a sprite... - if (pSequence->frames[frameIndex].trigger && callback != nullptr) + // all seq callbacks are for sprites + if (callback != nullptr && type == SS_SPRITE) { - assert(type == SS_SPRITE); - if (target.isActor()) callActorFunction(callback, target.actor()); + if (pSequence->frames[frameIndex].trigger || (autotrigger && frameIndex == pSequence->nFrames - 1)) + { + if (target.isActor()) callActorFunction(callback, target.actor()); + } } } @@ -507,7 +509,7 @@ static void ByteSwapSEQ(Seq* pSeq) FMemArena seqcache; static TMap sequences; -Seq* getSequence(int res_id) +const Seq* getSequence(int res_id) { auto p = sequences.CheckKey(res_id); if (p != nullptr) return *p; @@ -531,9 +533,9 @@ Seq* getSequence(int res_id) // //--------------------------------------------------------------------------- -void seqSpawn_(int nSeqID, int type, const EventObject& eob, VMFunction* callback) +void seqSpawn_(int nSeqID, int type, const EventObject& eob, VMFunction* callback, bool autotrigger = false) { - Seq* pSequence = getSequence(nSeqID); + const Seq* pSequence = getSequence(nSeqID); if (pSequence == nullptr) return; @@ -556,12 +558,26 @@ void seqSpawn_(int nSeqID, int type, const EventObject& eob, VMFunction* callbac pInst->frameIndex = 0; pInst->type = type; pInst->target = eob; + pInst->autotrigger = autotrigger; pInst->Update(); } void seqSpawn(int nSeqID, DBloodActor* actor, VMFunction* callback) { - seqSpawn_(nSeqID, SS_SPRITE, EventObject(actor), callback); + bool autotrigger = false; +#ifdef NOONE_EXTENSIONS + // the custom dude code originally hacked the actual sequence data to insert a trigger. + // This is not acceptable because the sequences are supposed to be global immutable data. + // So instead, flag them in the dude's data so we can insert the synthesized trigger into + // the instance data here without altering the sequence itself. This is also far more + // serialization friendly. + if (IsCustomDude(actor) && callback) + { + auto dude = cdudeGet(actor); + autotrigger = (dude && dude->triggerSeqs.Contains(nSeqID)); + } +#endif + seqSpawn_(nSeqID, SS_SPRITE, EventObject(actor), callback, autotrigger); } void seqSpawn(int nSeqID, int type, sectortype* sect, VMFunction* callback) @@ -636,7 +652,7 @@ void seqProcess(int nTicks) for (int i = 0; i < activeList.getSize(); i++) { SEQINST* pInst = activeList.getInst(i); - Seq* pSeq = pInst->pSequence; + const Seq* pSeq = pInst->pSequence; auto target = pInst->target; assert(pInst->frameIndex < pSeq->nFrames); @@ -703,7 +719,8 @@ FSerializer& Serialize(FSerializer& arc, const char* keyname, SEQINST& w, SEQINS ("seqid", w.nSeqID) ("timecounter", w.timeCounter) ("frameindex", w.frameIndex) - ("target", w.target); + ("target", w.target) + ("autotrigger", w.autotrigger); arc.EndObject(); } diff --git a/source/games/blood/src/seq.h b/source/games/blood/src/seq.h index f07d48429..09dca4f57 100644 --- a/source/games/blood/src/seq.h +++ b/source/games/blood/src/seq.h @@ -59,14 +59,14 @@ struct Seq { int16_t soundId; int flags; SEQFRAME frames[1]; - void Precache(int palette); + void Precache(int palette) const; - bool isLooping() + bool isLooping() const { return (flags & 1) != 0; } - bool isRemovable() + bool isRemovable() const { return (flags & 2) != 0; } @@ -75,7 +75,7 @@ struct Seq { class DBloodActor; struct SEQINST { - Seq* pSequence; + const Seq* pSequence; EventObject target; int type; @@ -83,15 +83,16 @@ struct SEQINST VMFunction* callback; int16_t timeCounter; uint8_t frameIndex; + bool autotrigger; void Update(); }; -inline int seqGetTile(SEQFRAME* pFrame) +inline int seqGetTile(const SEQFRAME* pFrame) { return pFrame->tile + (pFrame->tile2 << 12); } -inline FTextureID seqGetTexture(SEQFRAME* pFrame) +inline FTextureID seqGetTexture(const SEQFRAME* pFrame) { return tileGetTextureID(pFrame->tile + (pFrame->tile2 << 12)); } @@ -100,7 +101,6 @@ int seqRegisterClient(void(*pClient)(int, int)); void seqPrecacheId(int id, int palette); SEQINST* GetInstance(int a1, EventObject& a2); SEQINST* GetInstance(DBloodActor* actor); -void UnlockInstance(SEQINST* pInst); void seqSpawn(int a1, int ty, walltype* a2, VMFunction* a4 = nullptr); void seqSpawn(int a1, int ty, sectortype* a2, VMFunction* a4 = nullptr); void seqSpawn(int a1, DBloodActor* actor, VMFunction* a4 = nullptr); @@ -117,7 +117,7 @@ int seqGetID(int a1, sectortype* a2); int seqGetID(DBloodActor*); void seqProcess(int a1); -Seq* getSequence(int res_id); +const Seq* getSequence(int res_id); END_BLD_NS