- 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: {
SEQINST *pInst = GetInstance(3, pSprite->extra);
if (pInst && pInst->at13) {
DICTNODE *hSeq = gSysRes.Lookup(pInst->at8, "SEQ");
if (!hSeq) break;
auto seq = getSequence(pInst->at8);
if (!seq) break;
seqSpawn(pInst->at8, 3, pSprite->extra);
}
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();
}
@ -2966,7 +2966,7 @@ void actKillDude(int nKillerSprite, spritetype *pSprite, DAMAGE_TYPE damageType,
playGenDudeSound(pSprite, kGenDudeSndTransforming);
int seqId = pXSprite->data2 + kGenDudeSeqTransform;
if (gSysRes.Lookup(seqId, "SEQ")) seqSpawn(seqId, 3, nXSprite, -1);
if (getSequence(seqId)) seqSpawn(seqId, 3, nXSprite, -1);
else {
seqKill(3, nXSprite);
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;
}
if (!gSysRes.Lookup(getDudeInfo(nType+kDudeBase)->seqStartID + nSeq, "SEQ"))
if (!getSequence(getDudeInfo(nType+kDudeBase)->seqStartID + nSeq))
{
seqKill(3, nXSprite);
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);
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 (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 {
@ -5344,7 +5344,7 @@ void actExplodeSprite(spritetype *pSprite)
}
#endif
if (gSysRes.Lookup(nSeq, "SEQ"))
if (getSequence(nSeq))
seqSpawn(nSeq, 3, nXSprite, -1);
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;
pXSprite2->health = getDudeInfo(nDude+kDudeBase)->startHealth<<4;
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);
#ifdef NOONE_EXTENSIONS

View File

@ -94,7 +94,7 @@ void aiNewState(spritetype *pSprite, XSPRITE *pXSprite, AISTATE *pAIState)
if (pAIState->seqId >= 0) {
seqStartId += pAIState->seqId;
if (gSysRes.Lookup(seqStartId, "SEQ"))
if (getSequence(seqStartId))
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;
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);
}
@ -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]);
}
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
Seq* pSeq = NULL; DICTNODE* hSeq = gSysRes.Lookup(xsprite[pSprite->extra].data2 + 6, "SEQ"); int disp = 1;
if (hSeq != NULL && (pSeq = (Seq*)gSysRes.Load(hSeq)) != NULL) {
Seq* pSeq = getSequence(xsprite[pSprite->extra].data2 + 6);
int disp = 1;
if (pSeq != nullptr)
{
int nFrames = pSeq->nFrames; int ticks = pSeq->at8; int shots = 0;
for (int i = 0; i <= pSeq->nFrames; i++) {
if (pSeq->frames[i].at5_5) shots++;
@ -1487,9 +1490,8 @@ int getRangeAttackDist(spritetype* pSprite, int minDist, int maxDist) {
if (yrepeat > 0) {
if (seqId >= 0) {
Seq* pSeq = NULL; DICTNODE* hSeq = gSysRes.Lookup(seqId, "SEQ");
if (hSeq) {
pSeq = (Seq*)gSysRes.Load(hSeq);
Seq* pSeq = getSequence(seqId);
if (pSeq) {
picnum = seqGetTile(&pSeq->frames[0]);
}
}
@ -1974,7 +1976,7 @@ bool genDudePrepare(spritetype* pSprite, int propId) {
}
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->weaponType = kGenDudeWeaponNone;
@ -2033,45 +2035,54 @@ bool genDudePrepare(spritetype* pSprite, int propId) {
case kGenDudeSeqAttackNormalL:
case kGenDudeSeqAttackThrow:
case kGenDudeSeqAttackPunch:
if (!gSysRes.Lookup(i, "SEQ")) {
{
Seq* pSeq = getSequence(i);
if (!pSeq)
{
pXSprite->data2 = getDudeInfo(pSprite->type)->seqStartID;
viewSetSystemMessage("No SEQ animation id %d found for custom dude #%d!", i, pSprite->index);
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
Seq* pSeq = NULL; DICTNODE* hSeq = gSysRes.Lookup(i, "SEQ");
pSeq = (Seq*)gSysRes.Load(hSeq);
for (int i = 0; i < pSeq->nFrames; i++) {
if (!pSeq->frames[i].at5_5) continue;
pExtra->forcePunch = false;
break;
}
}
}
break;
}
case kGenDudeSeqDeathExplode:
pExtra->availDeaths[kDmgExplode] = (bool)gSysRes.Lookup(i, "SEQ");
pExtra->availDeaths[kDmgExplode] = !!getSequence(i);
break;
case kGenDudeSeqBurning:
pExtra->canBurn = gSysRes.Lookup(i, "SEQ");
pExtra->canBurn = !!getSequence(i);
break;
case kGenDudeSeqElectocuted:
pExtra->canElectrocute = gSysRes.Lookup(i, "SEQ");
pExtra->canElectrocute = !!getSequence(i);
break;
case kGenDudeSeqRecoil:
pExtra->canRecoil = gSysRes.Lookup(i, "SEQ");
pExtra->canRecoil = !!getSequence(i);
break;
case kGenDudeSeqMoveL: {
bool oldStatus = pExtra->canWalk;
pExtra->canWalk = gSysRes.Lookup(i, "SEQ");
pExtra->canWalk = !!getSequence(i);
if (oldStatus != pExtra->canWalk) {
if (!spriRangeIsFine(pXSprite->target)) {
if (!spriRangeIsFine(pXSprite->target))
{
if (spriteIsUnderwater(pSprite, false)) aiGenDudeNewState(pSprite, &genDudeIdleW);
else aiGenDudeNewState(pSprite, &genDudeIdleL);
} else if (pExtra->canWalk) {
}
else if (pExtra->canWalk)
{
if (spriteIsUnderwater(pSprite, false)) aiGenDudeNewState(pSprite, &genDudeChaseW);
else if (inDuck(pXSprite->aiState)) aiGenDudeNewState(pSprite, &genDudeChaseD);
else aiGenDudeNewState(pSprite, &genDudeChaseL);
} else {
}
else
{
if (spriteIsUnderwater(pSprite, false)) aiGenDudeNewState(pSprite, &genDudeChaseNoWalkW);
else if (inDuck(pXSprite->aiState)) aiGenDudeNewState(pSprite, &genDudeChaseNoWalkD);
else aiGenDudeNewState(pSprite, &genDudeChaseNoWalkL);
@ -2080,12 +2091,13 @@ bool genDudePrepare(spritetype* pSprite, int propId) {
break;
}
case kGenDudeSeqAttackNormalDW:
pExtra->canDuck = (gSysRes.Lookup(i, "SEQ") && gSysRes.Lookup(seqStartId + 14, "SEQ"));
pExtra->canSwim = (gSysRes.Lookup(i, "SEQ") && gSysRes.Lookup(seqStartId + 13, "SEQ")
&& gSysRes.Lookup(seqStartId + 17, "SEQ"));
pExtra->canDuck = (getSequence(i) && getSequence(seqStartId + 14));
pExtra->canSwim = (getSequence(i) && getSequence(seqStartId + 13)
&& getSequence(seqStartId + 17));
break;
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;
else if (seq16) pExtra->availDeaths[kDmgBurn] = 2;
else if (seq15) pExtra->availDeaths[kDmgBurn] = 1;
@ -2103,7 +2115,7 @@ bool genDudePrepare(spritetype* pSprite, int propId) {
case kGenDudeSeqReserved6:
case kGenDudeSeqReserved7:
case kGenDudeSeqReserved8:
/*if (gSysRes.Lookup(i, "SEQ")) {
/*if (getSequence(i)) {
viewSetSystemMessage("Found reserved SEQ animation (%d) for custom dude #%d!", i, pSprite->index);
viewSetSystemMessage("Using reserved animation is not recommended.");
viewSetSystemMessage("SEQ base id: %d", seqStartId);

View File

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

View File

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

View File

@ -275,7 +275,7 @@ void Respawn(int nSprite) // 9
switch (pSprite->type) {
default:
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);
break;
case kDudeModernCustom:
@ -285,7 +285,7 @@ void Respawn(int nSprite) // 9
#else
pSprite->clipdist = getDudeInfo(nType + kDudeBase)->clipdist;
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);
#endif
aiInitSprite(pSprite);

View File

@ -948,10 +948,9 @@ int getSpriteMassBySize(spritetype* pSprite) {
short massDiv = 30; short addMul = 2; short subMul = 2;
if (seqId >= 0) {
DICTNODE* hSeq = gSysRes.Lookup(seqId, "SEQ");
if (hSeq)
auto pSeq = getSequence(seqId);
if (pSeq)
{
pSeq = (Seq*)gSysRes.Load(hSeq);
picnum = seqGetTile(&pSeq->frames[0]);
} else
picnum = pSprite->picnum;
@ -2326,7 +2325,7 @@ void useSpriteDamager(XSPRITE* pXSource, spritetype* pSprite) {
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);
return;
}

View File

@ -2121,7 +2121,7 @@ int playerDamageSprite(int nSource, PLAYER *pPlayer, DAMAGE_TYPE nDamageType, in
FragPlayer(pPlayer, nSource);
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);
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)
{
SFX *pSFX = (SFX*)p;

View File

@ -79,11 +79,8 @@ void Seq::Precache(void)
void seqPrecacheId(int id)
{
DICTNODE *hSeq = gSysRes.Lookup(id, "SEQ");
if (!hSeq)
return;
Seq *pSeq = (Seq*)gSysRes.Load(hSeq);
pSeq->Precache();
auto pSeq = getSequence(id);
if (pSeq) pSeq->Precache();
}
SEQINST siWall[kMaxXWalls];
@ -371,9 +368,7 @@ SEQINST * GetInstance(int a1, int a2)
void UnlockInstance(SEQINST *pInst)
{
dassert(pInst != NULL);
dassert(pInst->hSeq != NULL);
dassert(pInst->pSequence != NULL);
pInst->hSeq = NULL;
pInst->pSequence = NULL;
pInst->at13 = 0;
}
@ -383,14 +378,14 @@ void seqSpawn(int a1, int a2, int a3, int a4)
SEQINST *pInst = GetInstance(a2, a3);
if (!pInst) return;
DICTNODE *hSeq = gSysRes.Lookup(a1, "SEQ");
if (!hSeq)
auto pSeq = getSequence(a1);
if (!pSeq)
ThrowError("Missing sequence #%d", a1);
int i = activeCount;
if (pInst->at13)
{
if (hSeq == pInst->hSeq)
if (pSeq == pInst->pSequence)
return;
UnlockInstance(pInst);
for (i = 0; i < activeCount; i++)
@ -400,7 +395,6 @@ void seqSpawn(int a1, int a2, int a3, int a4)
}
dassert(i < activeCount);
}
Seq *pSeq = (Seq*)gSysRes.Load(hSeq);
if (memcmp(pSeq->signature, "SEQ\x1a", 4) != 0)
ThrowError("Invalid sequence %d", a1);
if ((pSeq->version & 0xff00) != 0x300)
@ -411,7 +405,6 @@ void seqSpawn(int a1, int a2, int a3, int a4)
pSeq->frames[i].tile2 = 0;
}
pInst->at13 = 1;
pInst->hSeq = hSeq;
pInst->pSequence = pSeq;
pInst->at8 = a1;
pInst->atc = a4;
@ -557,21 +550,16 @@ void SeqLoadSave::Load(void)
Read(&activeCount, sizeof(activeCount));
for (int i = 0; i < kMaxXWalls; i++)
{
siWall[i].hSeq = NULL;
siMasked[i].hSeq = NULL;
siWall[i].pSequence = NULL;
siMasked[i].pSequence = NULL;
}
for (int i = 0; i < kMaxXSectors; i++)
{
siCeiling[i].hSeq = NULL;
siFloor[i].hSeq = NULL;
siCeiling[i].pSequence = NULL;
siFloor[i].pSequence = NULL;
}
for (int i = 0; i < kMaxXSprites; i++)
{
siSprite[i].hSeq = NULL;
siSprite[i].pSequence = NULL;
}
for (int i = 0; i < activeCount; i++)
@ -580,17 +568,15 @@ void SeqLoadSave::Load(void)
if (pInst->at13)
{
int nSeq = pInst->at8;
DICTNODE *hSeq = gSysRes.Lookup(nSeq, "SEQ");
if (!hSeq) {
auto pSeq = getSequence(nSeq);
if (!pSeq) {
ThrowError("Missing sequence #%d", nSeq);
continue;
}
Seq *pSeq = (Seq*)gSysRes.Load(hSeq);
if (memcmp(pSeq->signature, "SEQ\x1a", 4) != 0)
ThrowError("Invalid sequence %d", nSeq);
if ((pSeq->version & 0xff00) != 0x300)
ThrowError("Sequence %d is obsolete version", nSeq);
pInst->hSeq = hSeq;
pInst->pSequence = pSeq;
}
}
@ -614,4 +600,66 @@ void SeqLoadSaveConstruct(void)
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

View File

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