do not mofify global sequence data for the custom dudes.

Instead control the trigger from the outside so that the global data can be kept immutable. All Seq pointers are now const throughout.
This commit is contained in:
Christoph Oelckers 2023-10-17 18:09:33 +02:00
parent 1f5ff06b91
commit 2bae1077cf
6 changed files with 57 additions and 42 deletions

View file

@ -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;

View file

@ -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<TObjPtr<DBloodActor*>> pSlaves; // summoned dudes under control of this dude
TArray<int> 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

View file

@ -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;

View file

@ -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; }

View file

@ -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<int, Seq*> 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();
}

View file

@ -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