- implemented a proper cache for Blood's SEQs.

Messing around in the file system cache should be a no-go, so now it's no longer done.
This also allows reenabling the byte swapping needed for Big Endian.
This commit is contained in:
Christoph Oelckers 2020-07-25 22:47:46 +02:00
parent bbbd7fadbb
commit b804589f81
11 changed files with 126 additions and 107 deletions

View file

@ -2498,8 +2498,8 @@ void actInit(bool bSaveLoad) {
case kThingBloodChunks: { case kThingBloodChunks: {
SEQINST *pInst = GetInstance(3, pSprite->extra); SEQINST *pInst = GetInstance(3, pSprite->extra);
if (pInst && pInst->at13) { if (pInst && pInst->at13) {
DICTNODE *hSeq = gSysRes.Lookup(pInst->at8, "SEQ"); auto seq = getSequence(pInst->at8);
if (!hSeq) break; if (!seq) break;
seqSpawn(pInst->at8, 3, pSprite->extra); seqSpawn(pInst->at8, 3, pSprite->extra);
} }
break; break;
@ -2577,7 +2577,7 @@ void actInit(bool bSaveLoad) {
} }
if (gSysRes.Lookup(seqStartId, "SEQ")) seqSpawn(seqStartId, 3, pSprite->extra); if (getSequence(seqStartId)) seqSpawn(seqStartId, 3, pSprite->extra);
} }
aiInit(); aiInit();
} }
@ -2966,7 +2966,7 @@ void actKillDude(int nKillerSprite, spritetype *pSprite, DAMAGE_TYPE damageType,
playGenDudeSound(pSprite, kGenDudeSndTransforming); playGenDudeSound(pSprite, kGenDudeSndTransforming);
int seqId = pXSprite->data2 + kGenDudeSeqTransform; int seqId = pXSprite->data2 + kGenDudeSeqTransform;
if (gSysRes.Lookup(seqId, "SEQ")) seqSpawn(seqId, 3, nXSprite, -1); if (getSequence(seqId)) seqSpawn(seqId, 3, nXSprite, -1);
else { else {
seqKill(3, nXSprite); seqKill(3, nXSprite);
spritetype* pEffect = gFX.fxSpawn((FX_ID)52, pSprite->sectnum, pSprite->x, pSprite->y, pSprite->z, pSprite->ang); spritetype* pEffect = gFX.fxSpawn((FX_ID)52, pSprite->sectnum, pSprite->x, pSprite->y, pSprite->z, pSprite->ang);
@ -3152,7 +3152,7 @@ void actKillDude(int nKillerSprite, spritetype *pSprite, DAMAGE_TYPE damageType,
break; break;
} }
if (!gSysRes.Lookup(getDudeInfo(nType+kDudeBase)->seqStartID + nSeq, "SEQ")) if (!getSequence(getDudeInfo(nType+kDudeBase)->seqStartID + nSeq))
{ {
seqKill(3, nXSprite); seqKill(3, nXSprite);
gKillMgr.AddKill(pSprite); gKillMgr.AddKill(pSprite);
@ -3227,7 +3227,7 @@ void actKillDude(int nKillerSprite, spritetype *pSprite, DAMAGE_TYPE damageType,
if (pExtra->availDeaths[kDmgBurn] == 3) seqSpawn((15 + Random(2)) + pXSprite->data2, 3, nXSprite, dudeToGib); if (pExtra->availDeaths[kDmgBurn] == 3) seqSpawn((15 + Random(2)) + pXSprite->data2, 3, nXSprite, dudeToGib);
else if (pExtra->availDeaths[kDmgBurn] == 2) seqSpawn(16 + pXSprite->data2, 3, nXSprite, dudeToGib); else if (pExtra->availDeaths[kDmgBurn] == 2) seqSpawn(16 + pXSprite->data2, 3, nXSprite, dudeToGib);
else if (pExtra->availDeaths[kDmgBurn] == 1) seqSpawn(15 + pXSprite->data2, 3, nXSprite, dudeToGib); else if (pExtra->availDeaths[kDmgBurn] == 1) seqSpawn(15 + pXSprite->data2, 3, nXSprite, dudeToGib);
else if (gSysRes.Lookup(pXSprite->data2 + nSeq, "SEQ"))seqSpawn(nSeq + pXSprite->data2, 3, nXSprite, dudeToGib); else if (getSequence(pXSprite->data2 + nSeq))seqSpawn(nSeq + pXSprite->data2, 3, nXSprite, dudeToGib);
else seqSpawn(1 + pXSprite->data2, 3, nXSprite, dudeToGib); else seqSpawn(1 + pXSprite->data2, 3, nXSprite, dudeToGib);
} else { } else {
@ -5344,7 +5344,7 @@ void actExplodeSprite(spritetype *pSprite)
} }
#endif #endif
if (gSysRes.Lookup(nSeq, "SEQ")) if (getSequence(nSeq))
seqSpawn(nSeq, 3, nXSprite, -1); seqSpawn(nSeq, 3, nXSprite, -1);
sfxPlay3DSound(pSprite, nSnd, -1, 0); sfxPlay3DSound(pSprite, nSnd, -1, 0);
@ -6110,7 +6110,7 @@ spritetype *actSpawnDude(spritetype *pSource, short nType, int a3, int a4)
pSprite2->clipdist = getDudeInfo(nDude+kDudeBase)->clipdist; pSprite2->clipdist = getDudeInfo(nDude+kDudeBase)->clipdist;
pXSprite2->health = getDudeInfo(nDude+kDudeBase)->startHealth<<4; pXSprite2->health = getDudeInfo(nDude+kDudeBase)->startHealth<<4;
pXSprite2->respawn = 1; pXSprite2->respawn = 1;
if (gSysRes.Lookup(getDudeInfo(nDude+kDudeBase)->seqStartID, "SEQ")) if (getSequence(getDudeInfo(nDude+kDudeBase)->seqStartID))
seqSpawn(getDudeInfo(nDude+kDudeBase)->seqStartID, 3, pSprite2->extra, -1); seqSpawn(getDudeInfo(nDude+kDudeBase)->seqStartID, 3, pSprite2->extra, -1);
#ifdef NOONE_EXTENSIONS #ifdef NOONE_EXTENSIONS

View file

@ -94,7 +94,7 @@ void aiNewState(spritetype *pSprite, XSPRITE *pXSprite, AISTATE *pAIState)
if (pAIState->seqId >= 0) { if (pAIState->seqId >= 0) {
seqStartId += pAIState->seqId; seqStartId += pAIState->seqId;
if (gSysRes.Lookup(seqStartId, "SEQ")) if (getSequence(seqStartId))
seqSpawn(seqStartId, 3, pSprite->extra, pAIState->funcId); seqSpawn(seqStartId, 3, pSprite->extra, pAIState->funcId);
} }

View file

@ -1110,7 +1110,7 @@ void aiGenDudeNewState(spritetype* pSprite, AISTATE* pAIState) {
pXSprite->stateTimer = pAIState->stateTicks; pXSprite->aiState = pAIState; pXSprite->stateTimer = pAIState->stateTicks; pXSprite->aiState = pAIState;
int stateSeq = pXSprite->data2 + pAIState->seqId; int stateSeq = pXSprite->data2 + pAIState->seqId;
if (pAIState->seqId >= 0 && gSysRes.Lookup(stateSeq, "SEQ")) { if (pAIState->seqId >= 0 && getSequence(stateSeq)) {
seqSpawn(stateSeq, 3, pSprite->extra, pAIState->funcId); seqSpawn(stateSeq, 3, pSprite->extra, pAIState->funcId);
} }
@ -1460,10 +1460,13 @@ void scaleDamage(XSPRITE* pXSprite) {
//viewSetSystemMessage("0: %d, 1: %d, 2: %d, 3: %d, 4: %d, 5: %d, 6: %d", dc[0], dc[1], dc[2], dc[3], dc[4], dc[5], dc[6]); //viewSetSystemMessage("0: %d, 1: %d, 2: %d, 3: %d, 4: %d, 5: %d, 6: %d", dc[0], dc[1], dc[2], dc[3], dc[4], dc[5], dc[6]);
} }
int getDispersionModifier(spritetype* pSprite, int minDisp, int maxDisp) { int getDispersionModifier(spritetype* pSprite, int minDisp, int maxDisp)
{
// the faster fire rate, the less frames = more dispersion // the faster fire rate, the less frames = more dispersion
Seq* pSeq = NULL; DICTNODE* hSeq = gSysRes.Lookup(xsprite[pSprite->extra].data2 + 6, "SEQ"); int disp = 1; Seq* pSeq = getSequence(xsprite[pSprite->extra].data2 + 6);
if (hSeq != NULL && (pSeq = (Seq*)gSysRes.Load(hSeq)) != NULL) { int disp = 1;
if (pSeq != nullptr)
{
int nFrames = pSeq->nFrames; int ticks = pSeq->at8; int shots = 0; int nFrames = pSeq->nFrames; int ticks = pSeq->at8; int shots = 0;
for (int i = 0; i <= pSeq->nFrames; i++) { for (int i = 0; i <= pSeq->nFrames; i++) {
if (pSeq->frames[i].at5_5) shots++; if (pSeq->frames[i].at5_5) shots++;
@ -1487,9 +1490,8 @@ int getRangeAttackDist(spritetype* pSprite, int minDist, int maxDist) {
if (yrepeat > 0) { if (yrepeat > 0) {
if (seqId >= 0) { if (seqId >= 0) {
Seq* pSeq = NULL; DICTNODE* hSeq = gSysRes.Lookup(seqId, "SEQ"); Seq* pSeq = getSequence(seqId);
if (hSeq) { if (pSeq) {
pSeq = (Seq*)gSysRes.Load(hSeq);
picnum = seqGetTile(&pSeq->frames[0]); picnum = seqGetTile(&pSeq->frames[0]);
} }
} }
@ -1974,7 +1976,7 @@ bool genDudePrepare(spritetype* pSprite, int propId) {
} }
pExtra->canAttack = false; pExtra->canAttack = false;
if (pExtra->curWeapon > 0 && gSysRes.Lookup(pXSprite->data2 + kGenDudeSeqAttackNormalL, "SEQ")) if (pExtra->curWeapon > 0 && getSequence(pXSprite->data2 + kGenDudeSeqAttackNormalL))
pExtra->canAttack = true; pExtra->canAttack = true;
pExtra->weaponType = kGenDudeWeaponNone; pExtra->weaponType = kGenDudeWeaponNone;
@ -2033,45 +2035,54 @@ bool genDudePrepare(spritetype* pSprite, int propId) {
case kGenDudeSeqAttackNormalL: case kGenDudeSeqAttackNormalL:
case kGenDudeSeqAttackThrow: case kGenDudeSeqAttackThrow:
case kGenDudeSeqAttackPunch: case kGenDudeSeqAttackPunch:
if (!gSysRes.Lookup(i, "SEQ")) { {
Seq* pSeq = getSequence(i);
if (!pSeq)
{
pXSprite->data2 = getDudeInfo(pSprite->type)->seqStartID; pXSprite->data2 = getDudeInfo(pSprite->type)->seqStartID;
viewSetSystemMessage("No SEQ animation id %d found for custom dude #%d!", i, pSprite->index); viewSetSystemMessage("No SEQ animation id %d found for custom dude #%d!", i, pSprite->index);
viewSetSystemMessage("SEQ base id: %d", seqStartId); viewSetSystemMessage("SEQ base id: %d", seqStartId);
} else if ((i - seqStartId) == kGenDudeSeqAttackPunch) { }
else if ((i - seqStartId) == kGenDudeSeqAttackPunch)
{
pExtra->forcePunch = true; // required for those who don't have fire trigger in punch seq and for default animation pExtra->forcePunch = true; // required for those who don't have fire trigger in punch seq and for default animation
Seq* pSeq = NULL; DICTNODE* hSeq = gSysRes.Lookup(i, "SEQ");
pSeq = (Seq*)gSysRes.Load(hSeq);
for (int i = 0; i < pSeq->nFrames; i++) { for (int i = 0; i < pSeq->nFrames; i++) {
if (!pSeq->frames[i].at5_5) continue; if (!pSeq->frames[i].at5_5) continue;
pExtra->forcePunch = false; pExtra->forcePunch = false;
break; break;
} }
} }
break; break;
}
case kGenDudeSeqDeathExplode: case kGenDudeSeqDeathExplode:
pExtra->availDeaths[kDmgExplode] = (bool)gSysRes.Lookup(i, "SEQ"); pExtra->availDeaths[kDmgExplode] = !!getSequence(i);
break; break;
case kGenDudeSeqBurning: case kGenDudeSeqBurning:
pExtra->canBurn = gSysRes.Lookup(i, "SEQ"); pExtra->canBurn = !!getSequence(i);
break; break;
case kGenDudeSeqElectocuted: case kGenDudeSeqElectocuted:
pExtra->canElectrocute = gSysRes.Lookup(i, "SEQ"); pExtra->canElectrocute = !!getSequence(i);
break; break;
case kGenDudeSeqRecoil: case kGenDudeSeqRecoil:
pExtra->canRecoil = gSysRes.Lookup(i, "SEQ"); pExtra->canRecoil = !!getSequence(i);
break; break;
case kGenDudeSeqMoveL: { case kGenDudeSeqMoveL: {
bool oldStatus = pExtra->canWalk; bool oldStatus = pExtra->canWalk;
pExtra->canWalk = gSysRes.Lookup(i, "SEQ"); pExtra->canWalk = !!getSequence(i);
if (oldStatus != pExtra->canWalk) { if (oldStatus != pExtra->canWalk) {
if (!spriRangeIsFine(pXSprite->target)) { if (!spriRangeIsFine(pXSprite->target))
{
if (spriteIsUnderwater(pSprite, false)) aiGenDudeNewState(pSprite, &genDudeIdleW); if (spriteIsUnderwater(pSprite, false)) aiGenDudeNewState(pSprite, &genDudeIdleW);
else aiGenDudeNewState(pSprite, &genDudeIdleL); else aiGenDudeNewState(pSprite, &genDudeIdleL);
} else if (pExtra->canWalk) { }
else if (pExtra->canWalk)
{
if (spriteIsUnderwater(pSprite, false)) aiGenDudeNewState(pSprite, &genDudeChaseW); if (spriteIsUnderwater(pSprite, false)) aiGenDudeNewState(pSprite, &genDudeChaseW);
else if (inDuck(pXSprite->aiState)) aiGenDudeNewState(pSprite, &genDudeChaseD); else if (inDuck(pXSprite->aiState)) aiGenDudeNewState(pSprite, &genDudeChaseD);
else aiGenDudeNewState(pSprite, &genDudeChaseL); else aiGenDudeNewState(pSprite, &genDudeChaseL);
} else { }
else
{
if (spriteIsUnderwater(pSprite, false)) aiGenDudeNewState(pSprite, &genDudeChaseNoWalkW); if (spriteIsUnderwater(pSprite, false)) aiGenDudeNewState(pSprite, &genDudeChaseNoWalkW);
else if (inDuck(pXSprite->aiState)) aiGenDudeNewState(pSprite, &genDudeChaseNoWalkD); else if (inDuck(pXSprite->aiState)) aiGenDudeNewState(pSprite, &genDudeChaseNoWalkD);
else aiGenDudeNewState(pSprite, &genDudeChaseNoWalkL); else aiGenDudeNewState(pSprite, &genDudeChaseNoWalkL);
@ -2080,12 +2091,13 @@ bool genDudePrepare(spritetype* pSprite, int propId) {
break; break;
} }
case kGenDudeSeqAttackNormalDW: case kGenDudeSeqAttackNormalDW:
pExtra->canDuck = (gSysRes.Lookup(i, "SEQ") && gSysRes.Lookup(seqStartId + 14, "SEQ")); pExtra->canDuck = (getSequence(i) && getSequence(seqStartId + 14));
pExtra->canSwim = (gSysRes.Lookup(i, "SEQ") && gSysRes.Lookup(seqStartId + 13, "SEQ") pExtra->canSwim = (getSequence(i) && getSequence(seqStartId + 13)
&& gSysRes.Lookup(seqStartId + 17, "SEQ")); && getSequence(seqStartId + 17));
break; break;
case kGenDudeSeqDeathBurn1: { case kGenDudeSeqDeathBurn1: {
bool seq15 = gSysRes.Lookup(i, "SEQ"); bool seq16 = gSysRes.Lookup(seqStartId + 16, "SEQ"); bool seq15 = getSequence(i);
bool seq16 = getSequence(seqStartId + 16);
if (seq15 && seq16) pExtra->availDeaths[kDmgBurn] = 3; if (seq15 && seq16) pExtra->availDeaths[kDmgBurn] = 3;
else if (seq16) pExtra->availDeaths[kDmgBurn] = 2; else if (seq16) pExtra->availDeaths[kDmgBurn] = 2;
else if (seq15) pExtra->availDeaths[kDmgBurn] = 1; else if (seq15) pExtra->availDeaths[kDmgBurn] = 1;
@ -2103,7 +2115,7 @@ bool genDudePrepare(spritetype* pSprite, int propId) {
case kGenDudeSeqReserved6: case kGenDudeSeqReserved6:
case kGenDudeSeqReserved7: case kGenDudeSeqReserved7:
case kGenDudeSeqReserved8: case kGenDudeSeqReserved8:
/*if (gSysRes.Lookup(i, "SEQ")) { /*if (getSequence(i)) {
viewSetSystemMessage("Found reserved SEQ animation (%d) for custom dude #%d!", i, pSprite->index); viewSetSystemMessage("Found reserved SEQ animation (%d) for custom dude #%d!", i, pSprite->index);
viewSetSystemMessage("Using reserved animation is not recommended."); viewSetSystemMessage("Using reserved animation is not recommended.");
viewSetSystemMessage("SEQ base id: %d", seqStartId); viewSetSystemMessage("SEQ base id: %d", seqStartId);

View file

@ -1782,10 +1782,6 @@ bool VanillaMode() {
return gDemo.m_bLegacy && gDemo.at1; return gDemo.m_bLegacy && gDemo.at1;
} }
bool fileExistsRFF(int id, const char *ext) {
return gSysRes.Lookup(id, ext);
}
int sndTryPlaySpecialMusic(int nMusic) int sndTryPlaySpecialMusic(int nMusic)
{ {
if (Mus_Play(nullptr, quoteMgr.GetQuote(nMusic), true)) if (Mus_Play(nullptr, quoteMgr.GetQuote(nMusic), true))

View file

@ -132,7 +132,6 @@ void ProcessFrame(void);
void ScanINIFiles(void); void ScanINIFiles(void);
bool DemoRecordStatus(void); bool DemoRecordStatus(void);
bool VanillaMode(void); bool VanillaMode(void);
bool fileExistsRFF(int id, const char* ext);
int sndTryPlaySpecialMusic(int nMusic); int sndTryPlaySpecialMusic(int nMusic);
void sndPlaySpecialMusicOrNothing(int nMusic); void sndPlaySpecialMusicOrNothing(int nMusic);

View file

@ -275,7 +275,7 @@ void Respawn(int nSprite) // 9
switch (pSprite->type) { switch (pSprite->type) {
default: default:
pSprite->clipdist = getDudeInfo(nType + kDudeBase)->clipdist; pSprite->clipdist = getDudeInfo(nType + kDudeBase)->clipdist;
if (gSysRes.Lookup(getDudeInfo(nType + kDudeBase)->seqStartID, "SEQ")) if (getSequence(getDudeInfo(nType + kDudeBase)->seqStartID))
seqSpawn(getDudeInfo(nType + kDudeBase)->seqStartID, 3, pSprite->extra, -1); seqSpawn(getDudeInfo(nType + kDudeBase)->seqStartID, 3, pSprite->extra, -1);
break; break;
case kDudeModernCustom: case kDudeModernCustom:
@ -285,7 +285,7 @@ void Respawn(int nSprite) // 9
#else #else
pSprite->clipdist = getDudeInfo(nType + kDudeBase)->clipdist; pSprite->clipdist = getDudeInfo(nType + kDudeBase)->clipdist;
pXSprite->health = getDudeInfo(nType + kDudeBase)->startHealth << 4; pXSprite->health = getDudeInfo(nType + kDudeBase)->startHealth << 4;
if (gSysRes.Lookup(getDudeInfo(nType + kDudeBase)->seqStartID, "SEQ")) if (getSequence(getDudeInfo(nType + kDudeBase)->seqStartID))
seqSpawn(getDudeInfo(nType + kDudeBase)->seqStartID, 3, pSprite->extra, -1); seqSpawn(getDudeInfo(nType + kDudeBase)->seqStartID, 3, pSprite->extra, -1);
#endif #endif
aiInitSprite(pSprite); aiInitSprite(pSprite);

View file

@ -948,10 +948,9 @@ int getSpriteMassBySize(spritetype* pSprite) {
short massDiv = 30; short addMul = 2; short subMul = 2; short massDiv = 30; short addMul = 2; short subMul = 2;
if (seqId >= 0) { if (seqId >= 0) {
DICTNODE* hSeq = gSysRes.Lookup(seqId, "SEQ"); auto pSeq = getSequence(seqId);
if (hSeq) if (pSeq)
{ {
pSeq = (Seq*)gSysRes.Load(hSeq);
picnum = seqGetTile(&pSeq->frames[0]); picnum = seqGetTile(&pSeq->frames[0]);
} else } else
picnum = pSprite->picnum; picnum = pSprite->picnum;
@ -2326,7 +2325,7 @@ void useSpriteDamager(XSPRITE* pXSource, spritetype* pSprite) {
void useSeqSpawnerGen(XSPRITE* pXSource, int objType, int index) { void useSeqSpawnerGen(XSPRITE* pXSource, int objType, int index) {
if (pXSource->data2 > 0 && !gSysRes.Lookup(pXSource->data2, "SEQ")) { if (pXSource->data2 > 0 && !getSequence(pXSource->data2)) {
consoleSysMsg("Missing sequence #%d", pXSource->data2); consoleSysMsg("Missing sequence #%d", pXSource->data2);
return; return;
} }

View file

@ -2121,7 +2121,7 @@ int playerDamageSprite(int nSource, PLAYER *pPlayer, DAMAGE_TYPE nDamageType, in
FragPlayer(pPlayer, nSource); FragPlayer(pPlayer, nSource);
trTriggerSprite(nSprite, pXSprite, kCmdOff); trTriggerSprite(nSprite, pXSprite, kCmdOff);
} }
dassert(gSysRes.Lookup(pDudeInfo->seqStartID + nDeathSeqID, "SEQ") != NULL); dassert(getSequence(pDudeInfo->seqStartID + nDeathSeqID) != NULL);
seqSpawn(pDudeInfo->seqStartID+nDeathSeqID, 3, nXSprite, nKneelingPlayer); seqSpawn(pDudeInfo->seqStartID+nDeathSeqID, 3, nXSprite, nKneelingPlayer);
return nDamage; return nDamage;
} }

View file

@ -73,44 +73,6 @@ void ByteSwapQAV(void *p)
} }
} }
void ByteSwapSEQ(void *p)
{
Seq *pSeq = (Seq*)p;
pSeq->version = B_LITTLE16(pSeq->version);
pSeq->nFrames = B_LITTLE16(pSeq->nFrames);
pSeq->at8 = B_LITTLE16(pSeq->at8);
pSeq->ata = B_LITTLE16(pSeq->ata);
pSeq->atc = B_LITTLE32(pSeq->atc);
for (int i = 0; i < pSeq->nFrames; i++)
{
SEQFRAME *pFrame = &pSeq->frames[i];
BitReader bitReader((char *)pFrame, sizeof(SEQFRAME));
SEQFRAME swapFrame;
swapFrame.tile = bitReader.readUnsigned(12);
swapFrame.at1_4 = bitReader.readBit();
swapFrame.at1_5 = bitReader.readBit();
swapFrame.at1_6 = bitReader.readBit();
swapFrame.at1_7 = bitReader.readBit();
swapFrame.at2_0 = bitReader.readUnsigned(8);
swapFrame.at3_0 = bitReader.readUnsigned(8);
swapFrame.at4_0 = bitReader.readSigned(8);
swapFrame.at5_0 = bitReader.readUnsigned(5);
swapFrame.at5_5 = bitReader.readBit();
swapFrame.at5_6 = bitReader.readBit();
swapFrame.at5_7 = bitReader.readBit();
swapFrame.at6_0 = bitReader.readBit();
swapFrame.at6_1 = bitReader.readBit();
swapFrame.at6_2 = bitReader.readBit();
swapFrame.at6_3 = bitReader.readBit();
swapFrame.at6_4 = bitReader.readBit();
swapFrame.tile2 = bitReader.readUnsigned(4);
swapFrame.soundRange = bitReader.readUnsigned(4);
swapFrame.surfaceSound = bitReader.readBit();
swapFrame.reserved = bitReader.readUnsigned(2);
*pFrame = swapFrame;
}
}
void ByteSwapSFX(void *p) void ByteSwapSFX(void *p)
{ {
SFX *pSFX = (SFX*)p; SFX *pSFX = (SFX*)p;

View file

@ -79,11 +79,8 @@ void Seq::Precache(void)
void seqPrecacheId(int id) void seqPrecacheId(int id)
{ {
DICTNODE *hSeq = gSysRes.Lookup(id, "SEQ"); auto pSeq = getSequence(id);
if (!hSeq) if (pSeq) pSeq->Precache();
return;
Seq *pSeq = (Seq*)gSysRes.Load(hSeq);
pSeq->Precache();
} }
SEQINST siWall[kMaxXWalls]; SEQINST siWall[kMaxXWalls];
@ -371,9 +368,7 @@ SEQINST * GetInstance(int a1, int a2)
void UnlockInstance(SEQINST *pInst) void UnlockInstance(SEQINST *pInst)
{ {
dassert(pInst != NULL); dassert(pInst != NULL);
dassert(pInst->hSeq != NULL);
dassert(pInst->pSequence != NULL); dassert(pInst->pSequence != NULL);
pInst->hSeq = NULL;
pInst->pSequence = NULL; pInst->pSequence = NULL;
pInst->at13 = 0; pInst->at13 = 0;
} }
@ -383,14 +378,14 @@ void seqSpawn(int a1, int a2, int a3, int a4)
SEQINST *pInst = GetInstance(a2, a3); SEQINST *pInst = GetInstance(a2, a3);
if (!pInst) return; if (!pInst) return;
DICTNODE *hSeq = gSysRes.Lookup(a1, "SEQ"); auto pSeq = getSequence(a1);
if (!hSeq) if (!pSeq)
ThrowError("Missing sequence #%d", a1); ThrowError("Missing sequence #%d", a1);
int i = activeCount; int i = activeCount;
if (pInst->at13) if (pInst->at13)
{ {
if (hSeq == pInst->hSeq) if (pSeq == pInst->pSequence)
return; return;
UnlockInstance(pInst); UnlockInstance(pInst);
for (i = 0; i < activeCount; i++) for (i = 0; i < activeCount; i++)
@ -400,7 +395,6 @@ void seqSpawn(int a1, int a2, int a3, int a4)
} }
dassert(i < activeCount); dassert(i < activeCount);
} }
Seq *pSeq = (Seq*)gSysRes.Load(hSeq);
if (memcmp(pSeq->signature, "SEQ\x1a", 4) != 0) if (memcmp(pSeq->signature, "SEQ\x1a", 4) != 0)
ThrowError("Invalid sequence %d", a1); ThrowError("Invalid sequence %d", a1);
if ((pSeq->version & 0xff00) != 0x300) if ((pSeq->version & 0xff00) != 0x300)
@ -411,7 +405,6 @@ void seqSpawn(int a1, int a2, int a3, int a4)
pSeq->frames[i].tile2 = 0; pSeq->frames[i].tile2 = 0;
} }
pInst->at13 = 1; pInst->at13 = 1;
pInst->hSeq = hSeq;
pInst->pSequence = pSeq; pInst->pSequence = pSeq;
pInst->at8 = a1; pInst->at8 = a1;
pInst->atc = a4; pInst->atc = a4;
@ -557,21 +550,16 @@ void SeqLoadSave::Load(void)
Read(&activeCount, sizeof(activeCount)); Read(&activeCount, sizeof(activeCount));
for (int i = 0; i < kMaxXWalls; i++) for (int i = 0; i < kMaxXWalls; i++)
{ {
siWall[i].hSeq = NULL;
siMasked[i].hSeq = NULL;
siWall[i].pSequence = NULL; siWall[i].pSequence = NULL;
siMasked[i].pSequence = NULL; siMasked[i].pSequence = NULL;
} }
for (int i = 0; i < kMaxXSectors; i++) for (int i = 0; i < kMaxXSectors; i++)
{ {
siCeiling[i].hSeq = NULL;
siFloor[i].hSeq = NULL;
siCeiling[i].pSequence = NULL; siCeiling[i].pSequence = NULL;
siFloor[i].pSequence = NULL; siFloor[i].pSequence = NULL;
} }
for (int i = 0; i < kMaxXSprites; i++) for (int i = 0; i < kMaxXSprites; i++)
{ {
siSprite[i].hSeq = NULL;
siSprite[i].pSequence = NULL; siSprite[i].pSequence = NULL;
} }
for (int i = 0; i < activeCount; i++) for (int i = 0; i < activeCount; i++)
@ -580,17 +568,15 @@ void SeqLoadSave::Load(void)
if (pInst->at13) if (pInst->at13)
{ {
int nSeq = pInst->at8; int nSeq = pInst->at8;
DICTNODE *hSeq = gSysRes.Lookup(nSeq, "SEQ"); auto pSeq = getSequence(nSeq);
if (!hSeq) { if (!pSeq) {
ThrowError("Missing sequence #%d", nSeq); ThrowError("Missing sequence #%d", nSeq);
continue; continue;
} }
Seq *pSeq = (Seq*)gSysRes.Load(hSeq);
if (memcmp(pSeq->signature, "SEQ\x1a", 4) != 0) if (memcmp(pSeq->signature, "SEQ\x1a", 4) != 0)
ThrowError("Invalid sequence %d", nSeq); ThrowError("Invalid sequence %d", nSeq);
if ((pSeq->version & 0xff00) != 0x300) if ((pSeq->version & 0xff00) != 0x300)
ThrowError("Sequence %d is obsolete version", nSeq); ThrowError("Sequence %d is obsolete version", nSeq);
pInst->hSeq = hSeq;
pInst->pSequence = pSeq; pInst->pSequence = pSeq;
} }
} }
@ -614,4 +600,66 @@ void SeqLoadSaveConstruct(void)
myLoadSave = new SeqLoadSave(); myLoadSave = new SeqLoadSave();
} }
static void ByteSwapSEQ(Seq* pSeq)
{
pSeq->version = B_LITTLE16(pSeq->version);
pSeq->nFrames = B_LITTLE16(pSeq->nFrames);
pSeq->at8 = B_LITTLE16(pSeq->at8);
pSeq->ata = B_LITTLE16(pSeq->ata);
pSeq->atc = B_LITTLE32(pSeq->atc);
for (int i = 0; i < pSeq->nFrames; i++)
{
SEQFRAME* pFrame = &pSeq->frames[i];
BitReader bitReader((char*)pFrame, sizeof(SEQFRAME));
SEQFRAME swapFrame;
swapFrame.tile = bitReader.readUnsigned(12);
swapFrame.at1_4 = bitReader.readBit();
swapFrame.at1_5 = bitReader.readBit();
swapFrame.at1_6 = bitReader.readBit();
swapFrame.at1_7 = bitReader.readBit();
swapFrame.at2_0 = bitReader.readUnsigned(8);
swapFrame.at3_0 = bitReader.readUnsigned(8);
swapFrame.at4_0 = bitReader.readSigned(8);
swapFrame.at5_0 = bitReader.readUnsigned(5);
swapFrame.at5_5 = bitReader.readBit();
swapFrame.at5_6 = bitReader.readBit();
swapFrame.at5_7 = bitReader.readBit();
swapFrame.at6_0 = bitReader.readBit();
swapFrame.at6_1 = bitReader.readBit();
swapFrame.at6_2 = bitReader.readBit();
swapFrame.at6_3 = bitReader.readBit();
swapFrame.at6_4 = bitReader.readBit();
swapFrame.tile2 = bitReader.readUnsigned(4);
swapFrame.soundRange = bitReader.readUnsigned(4);
swapFrame.surfaceSound = bitReader.readBit();
swapFrame.reserved = bitReader.readUnsigned(2);
*pFrame = swapFrame;
}
}
// This is to eliminate a huge design issue in NBlood that was apparently copied verbatim from the DOS-Version.
// Sequences were cached in the resource and directly returned from there in writable form, with byte swapping directly performed in the cache on Big Endian systems.
// To avoid such unsafe operations this caches the read data separately in static memory that's guaranteed not to be touched by the file system.
FMemArena seqcache;
static TMap<int, Seq*> sequences;
Seq* getSequence(int res_id)
{
auto p = sequences.CheckKey(res_id);
if (p != nullptr) return *p;
int index = fileSystem.FindResource(res_id, "SEQ");
if (index < 0)
{
return nullptr;
}
auto fr = fileSystem.OpenFileReader(index);
auto seqdata = (Seq*)seqcache.Alloc(fr.GetLength());
fr.Read(seqdata, fr.GetLength());
sequences.Insert(res_id, seqdata);
ByteSwapSEQ(seqdata);
return seqdata;
}
END_BLD_NS END_BLD_NS

View file

@ -24,6 +24,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
BEGIN_BLD_NS BEGIN_BLD_NS
struct SEQFRAME { struct SEQFRAME {
unsigned int tile : 12; unsigned int tile : 12;
unsigned int at1_4 : 1; // transparent unsigned int at1_4 : 1; // transparent
@ -68,7 +69,6 @@ struct ACTIVE
struct SEQINST struct SEQINST
{ {
DICTNODE *hSeq;
Seq *pSequence; Seq *pSequence;
int at8; int at8;
int atc; int atc;
@ -94,4 +94,7 @@ int seqGetStatus(int a1, int a2);
int seqGetID(int a1, int a2); int seqGetID(int a1, int a2);
void seqProcess(int a1); void seqProcess(int a1);
Seq* getSequence(int res_id);
END_BLD_NS END_BLD_NS