From 32cc320195bfd0043027199665c74c37e1284ced Mon Sep 17 00:00:00 2001
From: Mitchell Richters <mjr4077au@gmail.com>
Date: Sun, 16 Apr 2023 08:03:23 +1000
Subject: [PATCH] - Exhumed: Refactor new sequence setup to not use naked
 TArray of frames.

* Also gives access to the previously discarded sequence flags that are currently not in any kind of use.
---
 source/games/exhumed/src/anims.cpp    |  4 +--
 source/games/exhumed/src/anubis.cpp   |  4 +--
 source/games/exhumed/src/bubbles.cpp  |  4 +--
 source/games/exhumed/src/bullet.cpp   |  8 +++---
 source/games/exhumed/src/fish.cpp     | 14 +++++------
 source/games/exhumed/src/grenade.cpp  |  6 ++---
 source/games/exhumed/src/gun.cpp      | 10 ++++----
 source/games/exhumed/src/lavadude.cpp |  6 ++---
 source/games/exhumed/src/lion.cpp     |  4 +--
 source/games/exhumed/src/mummy.cpp    |  4 +--
 source/games/exhumed/src/object.cpp   | 10 ++++----
 source/games/exhumed/src/player.cpp   | 12 ++++-----
 source/games/exhumed/src/queen.cpp    | 18 +++++++-------
 source/games/exhumed/src/ra.cpp       |  4 +--
 source/games/exhumed/src/rat.cpp      |  8 +++---
 source/games/exhumed/src/rex.cpp      |  4 +--
 source/games/exhumed/src/roach.cpp    |  4 +--
 source/games/exhumed/src/scorp.cpp    |  4 +--
 source/games/exhumed/src/sequence.cpp | 36 +++++++++++++++------------
 source/games/exhumed/src/sequence.h   | 18 ++++++++++----
 source/games/exhumed/src/set.cpp      | 12 ++++-----
 source/games/exhumed/src/snake.cpp    |  4 +--
 source/games/exhumed/src/sound.cpp    |  2 +-
 source/games/exhumed/src/spider.cpp   |  6 ++---
 source/games/exhumed/src/wasp.cpp     |  4 +--
 25 files changed, 111 insertions(+), 99 deletions(-)

diff --git a/source/games/exhumed/src/anims.cpp b/source/games/exhumed/src/anims.cpp
index 76d57a707..ac6340735 100644
--- a/source/games/exhumed/src/anims.cpp
+++ b/source/games/exhumed/src/anims.cpp
@@ -139,7 +139,7 @@ void AIAnim::Tick(RunListEvent* ev)
 
     if (!(pActor->spr.cstat & CSTAT_SPRITE_INVISIBLE))
     {
-        playFrameSound(pActor, animSeq[nFrame]);
+        playFrameSound(pActor, animSeq.frames[nFrame]);
     }
 
     if (pActor->spr.statnum == kStatIgnited)
@@ -202,7 +202,7 @@ void AIAnim::Tick(RunListEvent* ev)
     }
 
     pActor->nFrame++;
-    if (pActor->nFrame >= animSeq.Size())
+    if (pActor->nFrame >= animSeq.frames.Size())
     {
         if (pActor->nFlags & kAnimLoop)
         {
diff --git a/source/games/exhumed/src/anubis.cpp b/source/games/exhumed/src/anubis.cpp
index 07c1fb429..5486a371c 100644
--- a/source/games/exhumed/src/anubis.cpp
+++ b/source/games/exhumed/src/anubis.cpp
@@ -124,7 +124,7 @@ void AIAnubis::Tick(RunListEvent* ev)
     const int nAction = ap->nAction;
 
     const auto& anubisSeq = getSequence(ap->nSeqFile, AnubisSeq[nAction].nSeqId);
-    const auto& seqFrame = anubisSeq[ap->nFrame];
+    const auto& seqFrame = anubisSeq.frames[ap->nFrame];
     bool bVal = false;
 
     if (nAction < 11)
@@ -135,7 +135,7 @@ void AIAnubis::Tick(RunListEvent* ev)
     ap->spr.picnum = seqFrame.getFirstPicnum();
     ap->nFrame++;
 
-    if (ap->nFrame >= anubisSeq.Size())
+    if (ap->nFrame >= anubisSeq.frames.Size())
     {
         ap->nFrame = 0;
         bVal = true;
diff --git a/source/games/exhumed/src/bubbles.cpp b/source/games/exhumed/src/bubbles.cpp
index d88b561dc..65c136f51 100644
--- a/source/games/exhumed/src/bubbles.cpp
+++ b/source/games/exhumed/src/bubbles.cpp
@@ -98,11 +98,11 @@ void AIBubble::Tick(RunListEvent* ev)
 
     const auto& bubbSeq = getSequence(pActor->nSeqFile, pActor->nSeqIndex);
 
-    playFrameSound(pActor, bubbSeq[pActor->nFrame]);
+    playFrameSound(pActor, bubbSeq.frames[pActor->nFrame]);
 
     pActor->nFrame++;
 
-    if (pActor->nFrame >= bubbSeq.Size())
+    if (pActor->nFrame >= bubbSeq.frames.Size())
         pActor->nFrame = 0;
 
     pActor->spr.pos.Z = pActor->vel.Z;
diff --git a/source/games/exhumed/src/bullet.cpp b/source/games/exhumed/src/bullet.cpp
index e75be00ff..dbf0eaf2a 100644
--- a/source/games/exhumed/src/bullet.cpp
+++ b/source/games/exhumed/src/bullet.cpp
@@ -658,13 +658,13 @@ DExhumedActor* BuildBullet(DExhumedActor* pActor, int nType, double fZOffset, DA
     {
         pBullet->field_12 = 0;
         pBullet->seqFile = pBulletInfo->initSeq;
-        pBulletActor->spr.picnum = getSequence(pBullet->seqFile)[0].chunks[0].picnum;
+        pBulletActor->spr.picnum = getSequence(pBullet->seqFile).getFirstPicnum();
     }
     else if (pBulletInfo->seqFile != NAME_None)
     {
         pBullet->field_12 = 1;
         pBullet->seqFile = pBulletInfo->seqFile;
-        pBulletActor->spr.picnum = getSequence(pBullet->seqFile)[0].chunks[0].picnum;
+        pBulletActor->spr.picnum = getSequence(pBullet->seqFile).getFirstPicnum();
     }
     else
     {
@@ -803,7 +803,7 @@ void AIBullet::Tick(RunListEvent* ev)
         return;
 
     const auto& bulletSeq = getSequence(pBullet->seqFile);
-    const auto& seqFrame = bulletSeq[pBullet->nFrame];
+    const auto& seqFrame = bulletSeq.frames[pBullet->nFrame];
     DExhumedActor* pActor = BulletList[nBullet].pActor;
 
     playFrameSound(pActor, seqFrame);
@@ -814,7 +814,7 @@ void AIBullet::Tick(RunListEvent* ev)
     }
 
     pBullet->nFrame++;
-    if (pBullet->nFrame >= bulletSeq.Size())
+    if (pBullet->nFrame >= bulletSeq.frames.Size())
     {
         if (!pBullet->field_12)
         {
diff --git a/source/games/exhumed/src/fish.cpp b/source/games/exhumed/src/fish.cpp
index 5a6e6d8de..d0f555ba7 100644
--- a/source/games/exhumed/src/fish.cpp
+++ b/source/games/exhumed/src/fish.cpp
@@ -51,7 +51,7 @@ void BuildFishLimb(DExhumedActor* pActor, int anim)
 
     pChunkActor->nSeqFile = "fish";
     pChunkActor->nCount = anim + 40;
-    pChunkActor->nFrame = RandomSize(3) % getSequence(pChunkActor->nSeqFile, pChunkActor->nCount).Size();
+    pChunkActor->nFrame = RandomSize(3) % getSequence(pChunkActor->nSeqFile, pChunkActor->nCount).frames.Size();
 
 	pChunkActor->spr.pos = pActor->spr.pos;
     pChunkActor->spr.cstat = 0;
@@ -64,7 +64,7 @@ void BuildFishLimb(DExhumedActor* pActor, int anim)
     pChunkActor->spr.yoffset = 0;
     pChunkActor->vel.Z = ((-(RandomByte() + 512)) * 2) / 256.;
 
-    //getSequence(pChunkActor->nSeqFile, pChunkActor->nCount)[0].getFirstPicnum();
+    //getSequence(pChunkActor->nSeqFile, pChunkActor->nCount).getFirstPicnum();
 
     pChunkActor->spr.picnum = anim;
     pChunkActor->spr.lotag = runlist_HeadRun() + 1;
@@ -90,13 +90,13 @@ void AIFishLimb::Tick(RunListEvent* ev)
 
     const auto& fishSeq = getSequence(pActor->nSeqFile, pActor->nCount);
 
-    pActor->spr.picnum = fishSeq[pActor->nFrame].getFirstPicnum();
+    pActor->spr.picnum = fishSeq.frames[pActor->nFrame].getFirstPicnum();
 
     Gravity(pActor);
 
     pActor->nFrame++;
 
-    if (pActor->nFrame >= fishSeq.Size())
+    if (pActor->nFrame >= fishSeq.frames.Size())
     {
         pActor->nFrame = 0;
         if (RandomBit()) {
@@ -176,7 +176,7 @@ void BuildFish(DExhumedActor* pActor, const DVector3& pos, sectortype* pSector,
     pActor->spr.xoffset = 0;
     pActor->spr.yoffset = 0;
     pActor->nSeqFile = "fish";
-    pActor->spr.picnum = getSequence(pActor->nSeqFile, FishSeq[0].nSeqId)[0].getFirstPicnum();
+    pActor->spr.picnum = getSequence(pActor->nSeqFile, FishSeq[0].nSeqId).getFirstPicnum();
     pActor->vel.X = 0;
     pActor->vel.Y = 0;
     pActor->vel.Z = 0;
@@ -359,14 +359,14 @@ void AIFish::Tick(RunListEvent* ev)
     }
 
     const auto& fishSeq = getSequence(pActor->nSeqFile, FishSeq[nAction].nSeqId);
-    const auto& seqFrame = fishSeq[pActor->nFrame];
+    const auto& seqFrame = fishSeq.frames[pActor->nFrame];
 
     pActor->spr.picnum = seqFrame.getFirstPicnum();
 
     playFrameSound(pActor, seqFrame);
 
     pActor->nFrame++;
-    if (pActor->nFrame >= fishSeq.Size()) {
+    if (pActor->nFrame >= fishSeq.frames.Size()) {
         pActor->nFrame = 0;
     }
 
diff --git a/source/games/exhumed/src/grenade.cpp b/source/games/exhumed/src/grenade.cpp
index cfdf04240..1b6e71545 100644
--- a/source/games/exhumed/src/grenade.cpp
+++ b/source/games/exhumed/src/grenade.cpp
@@ -259,7 +259,7 @@ void AIGrenade::Tick(RunListEvent* ev)
     if (!pActor) return;
 
     const auto& grenadeSeq = pActor->nFrame ? getSequence("grenboom") : getSequence("grenroll", pActor->nIndex);
-    const auto& seqFrame = grenadeSeq[pActor->nHealth >> 8];
+    const auto& seqFrame = grenadeSeq.frames[pActor->nHealth >> 8];
 
     playFrameSound(pActor, seqFrame);
     pActor->spr.picnum = seqFrame.getFirstPicnum();
@@ -302,11 +302,11 @@ void AIGrenade::Tick(RunListEvent* ev)
 
         if (ebp < 0)
         {
-            pActor->nHealth += grenadeSeq.Size() << 8;
+            pActor->nHealth += grenadeSeq.frames.Size() << 8;
         }
         else
         {
-            if (ebp >= (signed)grenadeSeq.Size())
+            if (ebp >= (signed)grenadeSeq.frames.Size())
             {
                 if (pActor->nFrame)
                 {
diff --git a/source/games/exhumed/src/gun.cpp b/source/games/exhumed/src/gun.cpp
index 03ba7c6b5..aa7c09556 100644
--- a/source/games/exhumed/src/gun.cpp
+++ b/source/games/exhumed/src/gun.cpp
@@ -374,7 +374,7 @@ void MoveWeapons(int nPlayer)
 
     const auto nSeqFile = WeaponInfo[nWeapon].nSeqFile;
     auto weapSeq = std::ref(getSequence(nSeqFile, WeaponInfo[nWeapon].b[pPlayer->nState]));
-    auto seqFrame = std::ref(weapSeq.get()[pPlayer->nWeapFrame]);
+    auto seqFrame = std::ref(weapSeq.get().frames[pPlayer->nWeapFrame]);
 
     int var_1C = (pPlayer->nDouble > 0) + 1;
     int frames = var_1C - 1;
@@ -390,7 +390,7 @@ void MoveWeapons(int nPlayer)
             dword_96E22 = 0;
         }
 
-        if (pPlayer->nWeapFrame >= weapSeq.get().Size())
+        if (pPlayer->nWeapFrame >= weapSeq.get().frames.Size())
         {
             if (pPlayer->nNextWeapon == -1)
             {
@@ -468,7 +468,7 @@ void MoveWeapons(int nPlayer)
                             }
                             else
                             {
-                                pPlayer->nWeapFrame = weapSeq.get().Size() - 1;
+                                pPlayer->nWeapFrame = weapSeq.get().frames.Size() - 1;
                                 continue;
                             }
                         }
@@ -565,7 +565,7 @@ void MoveWeapons(int nPlayer)
                                 SelectNewWeapon(nPlayer);
                                 pPlayer->nState = 5;
 
-                                pPlayer->nWeapFrame = getSequence(nSeqFile, WeaponInfo[kWeaponGrenade].b[0]).Size() - 1; // CHECKME
+                                pPlayer->nWeapFrame = getSequence(nSeqFile, WeaponInfo[kWeaponGrenade].b[0]).frames.Size() - 1; // CHECKME
                                 goto loc_flag; // FIXME
                             }
                         }
@@ -639,7 +639,7 @@ void MoveWeapons(int nPlayer)
         }
 
 loc_flag:
-        seqFrame = std::ref(weapSeq.get()[pPlayer->nWeapFrame]);
+        seqFrame = std::ref(weapSeq.get().frames[pPlayer->nWeapFrame]);
 
         if (((!(nSectFlag & kSectUnderwater)) || nWeapon == kWeaponRing) && (seqFrame.get().flags & 4))
         {
diff --git a/source/games/exhumed/src/lavadude.cpp b/source/games/exhumed/src/lavadude.cpp
index 8190458bc..e12f58dc7 100644
--- a/source/games/exhumed/src/lavadude.cpp
+++ b/source/games/exhumed/src/lavadude.cpp
@@ -123,7 +123,7 @@ void BuildLava(DExhumedActor* pActor, const DVector3& pos, sectortype* pSector,
     pActor->spr.xoffset = 0;
     pActor->spr.yoffset = 0;
     pActor->nSeqFile = "lavag";
-    pActor->spr.picnum = getSequence(pActor->nSeqFile, LavadudeSeq[3].nSeqId)[0].getFirstPicnum();
+    pActor->spr.picnum = getSequence(pActor->nSeqFile, LavadudeSeq[3].nSeqId).getFirstPicnum();
     pActor->vel.X = 0;
     pActor->vel.Y = 0;
     pActor->vel.Z = 0;
@@ -216,7 +216,7 @@ void AILavaDude::Tick(RunListEvent* ev)
     int nAction = pActor->nAction;
 
     const auto& lavadudeSeq = getSequence(pActor->nSeqFile, LavadudeSeq[nAction].nSeqId);
-    const auto& seqFrame = lavadudeSeq[pActor->nFrame];
+    const auto& seqFrame = lavadudeSeq.frames[pActor->nFrame];
 
     pActor->spr.picnum = seqFrame.getFirstPicnum();
 
@@ -227,7 +227,7 @@ void AILavaDude::Tick(RunListEvent* ev)
         playFrameSound(pActor, seqFrame);
 
         pActor->nFrame++;
-        if (pActor->nFrame >= lavadudeSeq.Size())
+        if (pActor->nFrame >= lavadudeSeq.frames.Size())
         {
             var_1C = 1;
             pActor->nFrame = 0;
diff --git a/source/games/exhumed/src/lion.cpp b/source/games/exhumed/src/lion.cpp
index 4aef65857..85c04f7fd 100644
--- a/source/games/exhumed/src/lion.cpp
+++ b/source/games/exhumed/src/lion.cpp
@@ -201,14 +201,14 @@ void AILion::Tick(RunListEvent* ev)
     }
 
     const auto& lionSeq = getSequence(pActor->nSeqFile, LionSeq[nAction].nSeqId);
-    const auto& seqFrame = lionSeq[pActor->nFrame];
+    const auto& seqFrame = lionSeq.frames[pActor->nFrame];
 
     pActor->spr.picnum = seqFrame.getFirstPicnum();
 
     playFrameSound(pActor, seqFrame);
 
     pActor->nFrame++;
-    if (pActor->nFrame >= lionSeq.Size())
+    if (pActor->nFrame >= lionSeq.frames.Size())
     {
         pActor->nFrame = 0;
         bVal = true;
diff --git a/source/games/exhumed/src/mummy.cpp b/source/games/exhumed/src/mummy.cpp
index d30b6bf1a..43694bfa9 100644
--- a/source/games/exhumed/src/mummy.cpp
+++ b/source/games/exhumed/src/mummy.cpp
@@ -142,7 +142,7 @@ void AIMummy::Tick(RunListEvent* ev)
     Gravity(pActor);
 
     const auto& mummySeq = getSequence(pActor->nSeqFile, MummySeq[nAction].nSeqId);
-    const auto& seqFrame = mummySeq[pActor->nFrame];
+    const auto& seqFrame = mummySeq.frames[pActor->nFrame];
 
     pActor->spr.picnum = seqFrame.getFirstPicnum();
 
@@ -151,7 +151,7 @@ void AIMummy::Tick(RunListEvent* ev)
     bool bVal = false;
 
     pActor->nFrame++;
-    if (pActor->nFrame >= mummySeq.Size())
+    if (pActor->nFrame >= mummySeq.frames.Size())
     {
         pActor->nFrame = 0;
 
diff --git a/source/games/exhumed/src/object.cpp b/source/games/exhumed/src/object.cpp
index ee52ce076..7df648ece 100644
--- a/source/games/exhumed/src/object.cpp
+++ b/source/games/exhumed/src/object.cpp
@@ -1890,7 +1890,7 @@ DExhumedActor* BuildObject(DExhumedActor* pActor, int nOjectType, int nHitag)
     {
         if (!nOjectType) // if not Explosion Trigger (e.g. Exploding Fire Cauldron)
         {
-            pActor->nFrame = RandomSize(4) % (getSequence(pActor->nSeqFile).Size() - 1);
+            pActor->nFrame = RandomSize(4) % (getSequence(pActor->nSeqFile).frames.Size() - 1);
         }
 
         auto pActor2 = insertActor(pActor->sector(), 0);
@@ -1957,7 +1957,7 @@ void AIObject::Tick(RunListEvent* ev)
     // do animation
     if (pActor->nSeqFile != NAME_None)
     {
-        const auto& nSeqFrames = getSequence(pActor->nSeqFile);
+        const auto& nSeqFrames = getSequence(pActor->nSeqFile).frames;
 
         if (++pActor->nFrame >= nSeqFrames.Size())
             pActor->nFrame = 0;
@@ -2007,7 +2007,7 @@ void AIObject::Tick(RunListEvent* ev)
         if (nStat == kStatExplodeTrigger)
         {
             for (int i = 4; i < 8; i++) {
-                BuildCreatureChunk(pActor, getSequence("firepot", (i >> 2) + 1)[0].getFirstPicnum(), true);
+                BuildCreatureChunk(pActor, getSequence("firepot", (i >> 2) + 1).getFirstPicnum(), true);
             }
 
             runlist_RadialDamageEnemy(pActor, 200, 20);
@@ -2015,7 +2015,7 @@ void AIObject::Tick(RunListEvent* ev)
         else if (nStat == kStatExplodeTarget)
         {
             for (int i = 0; i < 8; i++) {
-                BuildCreatureChunk(pActor, getSequence("firepot", (i >> 1) + 3)[0].getFirstPicnum(), true);
+                BuildCreatureChunk(pActor, getSequence("firepot", (i >> 1) + 3).getFirstPicnum(), true);
             }
         }
 
@@ -2180,7 +2180,7 @@ void DoDrips()
             if (!pActor) continue;
 
             const auto& dripSeq = getSequence("drips", !(pActor->sector()->Flag & kSectLava));
-            playFrameSound(pActor, dripSeq[RandomSize(2) % dripSeq.Size()]);
+            playFrameSound(pActor, dripSeq.frames[RandomSize(2) % dripSeq.frames.Size()]);
 
             sDrip[i].nCount = RandomSize(8) + 90;
         }
diff --git a/source/games/exhumed/src/player.cpp b/source/games/exhumed/src/player.cpp
index 9abe927d8..93d7c7eab 100644
--- a/source/games/exhumed/src/player.cpp
+++ b/source/games/exhumed/src/player.cpp
@@ -220,7 +220,7 @@ void RestartPlayer(int nPlayer)
     pPlayerActor->nSeqFile = "joe";
     pPlayerActor->nAction = 0;
     pPlayerActor->nFrame = 0;
-    pPlayerActor->spr.picnum = getSequence(pPlayerActor->nSeqFile, 18)[0].getFirstPicnum();
+    pPlayerActor->spr.picnum = getSequence(pPlayerActor->nSeqFile, 18).getFirstPicnum();
     pPlayerActor->spr.hitag = 0;
     pPlayerActor->spr.extra = -1;
     pPlayerActor->spr.lotag = runlist_HeadRun() + 1;
@@ -642,7 +642,7 @@ void AIPlayer::Damage(RunListEvent* ev)
         {
             for (int i = 122; i <= 131; i++)
             {
-                BuildCreatureChunk(pPlayerActor, getSequence("joe", i)[0].getFirstPicnum());
+                BuildCreatureChunk(pPlayerActor, getSequence("joe", i).getFirstPicnum());
             }
 
             StartDeathSeq(nPlayer, 1);
@@ -1885,7 +1885,7 @@ static bool doPlayerDeathRestart(Player* const pPlayer)
         if (pPlayer->pActor->nAction != 20)
         {
             const auto pPlayerActor = pPlayer->pActor;
-            pPlayerActor->spr.picnum = getSequence("joe", 120)[0].getFirstPicnum();
+            pPlayerActor->spr.picnum = getSequence("joe", 120).getFirstPicnum();
             pPlayerActor->spr.cstat = 0;
             pPlayerActor->spr.pos.Z = pPlayerActor->sector()->floorz;
         }
@@ -1915,8 +1915,8 @@ static void doPlayerActionSequence(Player* const pPlayer)
     const auto pPlayerActor = pPlayer->pActor;
 
     const auto& playerSeq = getSequence(pPlayerActor->nSeqFile, PlayerSeq[pPlayerActor->nAction].nSeqId);
-    const auto& seqFrame = playerSeq[pPlayerActor->nFrame];
-    const auto seqSize = playerSeq.Size();
+    const auto& seqFrame = playerSeq.frames[pPlayerActor->nFrame];
+    const auto seqSize = playerSeq.frames.Size();
 
     playFrameSound(pPlayerActor, seqFrame);
     pPlayerActor->nFrame++;
@@ -2011,7 +2011,7 @@ void AIPlayer::Tick(RunListEvent* ev)
     const auto pPlayer = &PlayerList[nPlayer];
     const auto pPlayerActor = pPlayer->pActor;
 
-    pPlayerActor->spr.picnum = getSequence(pPlayerActor->nSeqFile, PlayerSeq[nHeightTemplate[pPlayerActor->nAction]].nSeqId)[0].getFirstPicnum();
+    pPlayerActor->spr.picnum = getSequence(pPlayerActor->nSeqFile, PlayerSeq[nHeightTemplate[pPlayerActor->nAction]].nSeqId).getFirstPicnum();
     pPlayer->pDoppleSprite->spr.picnum = pPlayerActor->spr.picnum;
 
     doPlayerCounters(pPlayer);
diff --git a/source/games/exhumed/src/queen.cpp b/source/games/exhumed/src/queen.cpp
index 6c4d67e3d..a05a0ea2c 100644
--- a/source/games/exhumed/src/queen.cpp
+++ b/source/games/exhumed/src/queen.cpp
@@ -252,7 +252,7 @@ void BlowChunks(DExhumedActor* pActor)
 {
     for (int i = 0; i < 4; i++)
     {
-        BuildCreatureChunk(pActor, getSequence("spider", i + 41)[0].getFirstPicnum());
+        BuildCreatureChunk(pActor, getSequence("spider", i + 41).getFirstPicnum());
     }
 }
 
@@ -275,7 +275,7 @@ void DestroyEgg(int nEgg)
     {
         for (int i = 0; i < 4; i++)
         {
-            BuildCreatureChunk(pActor, getSequence("queenegg", (i % 2) + 24)[0].getFirstPicnum());
+            BuildCreatureChunk(pActor, getSequence("queenegg", (i % 2) + 24).getFirstPicnum());
         }
     }
 
@@ -544,7 +544,7 @@ void AIQueenEgg::Tick(RunListEvent* ev)
     }
 
     const auto& eggSeq = getSequence(pActor->nSeqFile, EggSeq[nAction].nSeqId);
-    const auto& seqFrame = eggSeq[pEgg->nFrame];
+    const auto& seqFrame = eggSeq.frames[pEgg->nFrame];
 
     pActor->spr.picnum = seqFrame.getFirstPicnum();
 
@@ -553,7 +553,7 @@ void AIQueenEgg::Tick(RunListEvent* ev)
         playFrameSound(pActor, seqFrame);
 
         pEgg->nFrame++;
-        if (pEgg->nFrame >= eggSeq.Size())
+        if (pEgg->nFrame >= eggSeq.frames.Size())
         {
             pEgg->nFrame = 0;
             bVal = true;
@@ -803,14 +803,14 @@ void AIQueenHead::Tick(RunListEvent* ev)
     }
 
     const auto& queenSeq = getSequence(pActor->nSeqFile, HeadSeq[QueenHead.nAction].nSeqId);
-    const auto& seqFrame = queenSeq[QueenHead.nFrame];
+    const auto& seqFrame = queenSeq.frames[QueenHead.nFrame];
 
     playFrameSound(pActor, seqFrame);
 
     pActor->spr.picnum = seqFrame.getFirstPicnum();
 
     QueenHead.nFrame++;
-    if (QueenHead.nFrame >= queenSeq.Size())
+    if (QueenHead.nFrame >= queenSeq.frames.Size())
     {
         QueenHead.nFrame = 0;
         var_14 = 1;
@@ -1236,14 +1236,14 @@ void AIQueen::Tick(RunListEvent* ev)
     }
 
     const auto& queenSeq = getSequence(pActor->nSeqFile, QueenSeq[nAction].nSeqId);
-    const auto& seqFrame = queenSeq[QueenList[nQueen].nFrame];
+    const auto& seqFrame = queenSeq.frames[QueenList[nQueen].nFrame];
 
     pActor->spr.picnum = seqFrame.getFirstPicnum();
 
     playFrameSound(pActor, seqFrame);
 
     QueenList[nQueen].nFrame++;
-    if (QueenList[nQueen].nFrame >= queenSeq.Size())
+    if (QueenList[nQueen].nFrame >= queenSeq.frames.Size())
     {
         QueenList[nQueen].nFrame = 0;
         bVal = true;
@@ -1435,7 +1435,7 @@ void AIQueen::Tick(RunListEvent* ev)
                 if (QueenList[nQueen].nIndex <= 0)
                 {
                     pActor->spr.cstat = 0;
-                    const auto queenPicnum = getSequence("queen", 57)[0].getFirstPicnum();
+                    const auto queenPicnum = getSequence("queen", 57).getFirstPicnum();
 
                     for (int i = 0; i < 20; i++)
                     {
diff --git a/source/games/exhumed/src/ra.cpp b/source/games/exhumed/src/ra.cpp
index b033d2ca4..4d382fcad 100644
--- a/source/games/exhumed/src/ra.cpp
+++ b/source/games/exhumed/src/ra.cpp
@@ -214,7 +214,7 @@ void AIRa::Tick(RunListEvent* ev)
     if (!pActor) return;
 
     const auto& raSeq = getSequence(Ra[nPlayer].pActor->nSeqFile, RaSeq[Ra[nPlayer].nAction].nSeqId);
-    const auto& seqFrame = raSeq[Ra[nPlayer].nFrame];
+    const auto& seqFrame = raSeq.frames[Ra[nPlayer].nFrame];
 
     bool bVal = false;
 
@@ -226,7 +226,7 @@ void AIRa::Tick(RunListEvent* ev)
         playFrameSound(pActor, seqFrame);
 
         Ra[nPlayer].nFrame++;
-        if (Ra[nPlayer].nFrame >= raSeq.Size())
+        if (Ra[nPlayer].nFrame >= raSeq.frames.Size())
         {
             Ra[nPlayer].nFrame = 0;
             bVal = true;
diff --git a/source/games/exhumed/src/rat.cpp b/source/games/exhumed/src/rat.cpp
index 2bef8ce66..efa48e561 100644
--- a/source/games/exhumed/src/rat.cpp
+++ b/source/games/exhumed/src/rat.cpp
@@ -67,7 +67,7 @@ void InitRats()
 
     for (int i = 122; i <= 131; i++)
     {
-        int nPic = getSequence("joe", i)[0].getFirstPicnum();
+        int nPic = getSequence("joe", i).getFirstPicnum();
 
         if (nPic < nMinChunk)
             nMinChunk = nPic;
@@ -76,7 +76,7 @@ void InitRats()
             nMaxChunk = nPic;
     }
 
-    nPlayerPic = getSequence("joe", 120)[0].getFirstPicnum();
+    nPlayerPic = getSequence("joe", 120).getFirstPicnum();
 }
 
 void SetRatVel(DExhumedActor* pActor)
@@ -247,14 +247,14 @@ void AIRat::Tick(RunListEvent* ev)
     bool bVal = false;
 
     const auto& ratSeq = getSequence(pActor->nSeqFile, RatSeq[nAction].nSeqId);
-    const auto& seqFrame = ratSeq[pActor->nFrame];
+    const auto& seqFrame = ratSeq.frames[pActor->nFrame];
 
     pActor->spr.picnum = seqFrame.getFirstPicnum();
 
     playFrameSound(pActor, seqFrame);
 
     pActor->nFrame++;
-    if (pActor->nFrame >= ratSeq.Size())
+    if (pActor->nFrame >= ratSeq.frames.Size())
     {
         bVal = true;
         pActor->nFrame = 0;
diff --git a/source/games/exhumed/src/rex.cpp b/source/games/exhumed/src/rex.cpp
index 7b528e48e..7e3bfb799 100644
--- a/source/games/exhumed/src/rex.cpp
+++ b/source/games/exhumed/src/rex.cpp
@@ -193,7 +193,7 @@ void AIRex::Tick(RunListEvent* ev)
     Gravity(pActor);
 
     const auto& rexSeq = getSequence(pActor->nSeqFile, RexSeq[nAction].nSeqId);
-    const auto& seqFrame = rexSeq[pActor->nFrame];
+    const auto& seqFrame = rexSeq.frames[pActor->nFrame];
 
     pActor->spr.picnum = seqFrame.getFirstPicnum();
 
@@ -209,7 +209,7 @@ void AIRex::Tick(RunListEvent* ev)
         playFrameSound(pActor, seqFrame);
 
         pActor->nFrame++;
-        if (pActor->nFrame >= rexSeq.Size())
+        if (pActor->nFrame >= rexSeq.frames.Size())
         {
             pActor->nFrame = 0;
             bVal = true;
diff --git a/source/games/exhumed/src/roach.cpp b/source/games/exhumed/src/roach.cpp
index c66224fad..127ea7e38 100644
--- a/source/games/exhumed/src/roach.cpp
+++ b/source/games/exhumed/src/roach.cpp
@@ -213,13 +213,13 @@ void AIRoach::Tick(RunListEvent* ev)
     Gravity(pActor);
 
     const auto& roachSeq = getSequence(pActor->nSeqFile, RoachSeq[nAction].nSeqId);
-    const auto& seqFrame = roachSeq[pActor->nFrame];
+    const auto& seqFrame = roachSeq.frames[pActor->nFrame];
 
     pActor->spr.picnum = seqFrame.getFirstPicnum();
     playFrameSound(pActor, seqFrame);
 
     pActor->nFrame++;
-    if (pActor->nFrame >= roachSeq.Size())
+    if (pActor->nFrame >= roachSeq.frames.Size())
     {
         bVal = true;
         pActor->nFrame = 0;
diff --git a/source/games/exhumed/src/scorp.cpp b/source/games/exhumed/src/scorp.cpp
index 84a816614..d452f0b06 100644
--- a/source/games/exhumed/src/scorp.cpp
+++ b/source/games/exhumed/src/scorp.cpp
@@ -208,14 +208,14 @@ void AIScorp::Tick(RunListEvent* ev)
     }
 
     const auto& scorpSeq = getSequence(pActor->nSeqFile, ScorpSeq[nAction].nSeqId);
-    const auto& seqFrame = scorpSeq[pActor->nFrame];
+    const auto& seqFrame = scorpSeq.frames[pActor->nFrame];
 
     pActor->spr.picnum = seqFrame.getFirstPicnum();
     playFrameSound(pActor, seqFrame);
 
     pActor->nFrame++;
 
-    if (pActor->nFrame >= scorpSeq.Size())
+    if (pActor->nFrame >= scorpSeq.frames.Size())
     {
         pActor->nFrame = 0;
         bVal = true;
diff --git a/source/games/exhumed/src/sequence.cpp b/source/games/exhumed/src/sequence.cpp
index 953a304c7..251e00667 100644
--- a/source/games/exhumed/src/sequence.cpp
+++ b/source/games/exhumed/src/sequence.cpp
@@ -147,7 +147,7 @@ const char *SeqNames[kMaxSEQFiles] =
 };
 
 static int16_t SeqOffsets[kMaxSEQFiles];
-static TMap<FName, SeqArray> FileSeqMap;
+static TMap<FName, TArray<Seq>> FileSeqMap;
 
 
 //---------------------------------------------------------------------------
@@ -277,7 +277,7 @@ int getSeqFrameChunkFlags(const int nChunk)
 //
 //---------------------------------------------------------------------------
 
-SeqArray* getFileSeqs(const FName nSeqFile)
+TArray<Seq>* getFileSeqs(const FName nSeqFile)
 {
     return FileSeqMap.CheckKey(nSeqFile);
 }
@@ -399,17 +399,21 @@ int addSeq(const char *seqName)
     }
 
     // Add hastable entry for the amount of sequences this file contains.
-    auto& gSequences = FileSeqMap.Insert(FName(seqName), SeqArray(nSeqs, true));
+    auto& gSequences = FileSeqMap.Insert(FName(seqName), TArray<Seq>(nSeqs, true));
 
     // Read all this data into something sane.
     for (int nSeq = 0; nSeq < nSeqs; nSeq++)
     {
+        // Store unused sequence flags, they may be used with future expansion.
+        auto& gSeq = gSequences[nSeq];
+        gSeq.flags = nSeqFlags[nSeq];
+
         // Determine where we are in our frame array.
         const int firstFrame = nSeqFrames[nSeq];
         const int lastFrame = nSeqFrameCount[nSeq] + firstFrame;
 
         // Get sequence's frame array and resize.
-        auto& gSeqFrames = gSequences[nSeq];
+        auto& gSeqFrames = gSeq.frames;
         gSeqFrames.Resize(lastFrame - firstFrame);
 
         // Build out frame array.
@@ -625,20 +629,20 @@ void seq_LoadSequences()
     fclose(f);
 #endif
 
-    nShadowPic = getSequence("shadow")[0].getFirstPicnum();
+    nShadowPic = getSequence("shadow").getFirstPicnum();
     nShadowWidth = tileWidth(nShadowPic);
 
-    nFlameHeight = tileHeight(getSequence("firepoof")[0].getFirstPicnum());
+    nFlameHeight = tileHeight(getSequence("firepoof").getFirstPicnum());
 
-    nBackgroundPic = getSequence("backgrnd")[0].getFirstPicnum();
+    nBackgroundPic = getSequence("backgrnd").getFirstPicnum();
 
-    nPilotLightCount = getSequence("flamer", 3).Size();
+    nPilotLightCount = getSequence("flamer", 3).frames.Size();
     nPilotLightFrame = 0;
 
     const auto& fontSeq = getSequence("font2");
-    nFontFirstChar = fontSeq[0].getFirstPicnum();
+    nFontFirstChar = fontSeq.getFirstPicnum();
 
-    for (unsigned i = 0; i < fontSeq.Size(); i++)
+    for (unsigned i = 0; i < fontSeq.frames.Size(); i++)
     {
         auto tex = tileGetTexture(nFontFirstChar + i);
         tex->SetOffsets(0, 0);
@@ -658,7 +662,7 @@ void seq_DrawPilotLightSeq(double xOffset, double yOffset)
     if (!(pSect->Flag & kSectUnderwater))
     {
         const auto& pilotlightSeq = getSequence("flamer", 3);
-        const auto& seqFrame = pilotlightSeq[0];
+        const auto& seqFrame = pilotlightSeq.frames[0];
 
         for (unsigned i = 0; i < seqFrame.chunks.Size(); i++)
         {
@@ -677,9 +681,9 @@ void seq_DrawPilotLightSeq(double xOffset, double yOffset)
 //
 //---------------------------------------------------------------------------
 
-void seq_DrawGunSequence(const SeqFrameArray& weapSeq, int16_t frameIndex, double xOffs, double yOffs, int nShade, int nPal, DAngle angle, bool align)
+void seq_DrawGunSequence(const Seq& weapSeq, int16_t frameIndex, double xOffs, double yOffs, int nShade, int nPal, DAngle angle, bool align)
 {
-    const auto& seqFrame = weapSeq[frameIndex];
+    const auto& seqFrame = weapSeq.frames[frameIndex];
 
     if (seqFrame.flags & 4)
         nShade = -100;
@@ -768,7 +772,7 @@ void seq_PlotArrowSequence(const int nSprite, const FName seqFile, const int16_t
     const DAngle nAngle = (nCamerapos.XY() - pTSprite->pos.XY()).Angle();
     const int seqOffset = (((pTSprite->Angles.Yaw + DAngle90 + DAngle22_5 - nAngle).Buildang()) & kAngleMask) >> 8;
 
-    const auto& seqFrame = getSequence(seqFile, seqIndex + seqOffset)[frameIndex];
+    const auto& seqFrame = getSequence(seqFile, seqIndex + seqOffset).frames[frameIndex];
     const auto& frameChunk = seqFrame.chunks[0];
 
     auto nStat = pTSprite->cstat | CSTAT_SPRITE_YCENTER;
@@ -817,8 +821,8 @@ void seq_PlotSequence(const int nSprite, const FName seqFile, const int16_t seqI
     }
 
     const auto fileSeqs = getFileSeqs(seqFile);
-    const auto& baseFrame = fileSeqs->operator[](seqIndex)[frameIndex];
-    const auto& drawFrame = fileSeqs->operator[](seqIndex + seqOffset)[frameIndex];
+    const auto& baseFrame = fileSeqs->operator[](seqIndex).frames[frameIndex];
+    const auto& drawFrame = fileSeqs->operator[](seqIndex + seqOffset).frames[frameIndex];
     const auto chunkCount = drawFrame.chunks.Size();
 
     const auto nShade = (baseFrame.flags & 4) ? pTSprite->shade - 100 : pTSprite->shade;
diff --git a/source/games/exhumed/src/sequence.h b/source/games/exhumed/src/sequence.h
index e51aef924..ea6854b9b 100644
--- a/source/games/exhumed/src/sequence.h
+++ b/source/games/exhumed/src/sequence.h
@@ -128,8 +128,16 @@ struct SeqFrame
     }
 };
 
-using SeqFrameArray = TArray<SeqFrame>;
-using SeqArray = TArray<SeqFrameArray>;
+struct Seq
+{
+    int16_t flags;
+    TArray<SeqFrame> frames;
+
+    const int getFirstPicnum() const
+    {
+        return frames[0].getFirstPicnum();
+    }
+};
 
 extern int16_t nShadowWidth;
 extern int16_t nFlameHeight;
@@ -139,7 +147,7 @@ extern int16_t nPilotLightCount;
 
 void seq_LoadSequences();
 void seq_MoveSequence(DExhumedActor* actor, int16_t nSeq, int16_t nFrame);
-void seq_DrawGunSequence(const SeqFrameArray& weapSeq, int16_t frameIndex, double xOffs, double yOffs, int nShade, int nPal, DAngle angle, bool align = false);
+void seq_DrawGunSequence(const Seq& weapSeq, int16_t frameIndex, double xOffs, double yOffs, int nShade, int nPal, DAngle angle, bool align = false);
 void seq_PlotSequence(const int nSprite, const FName seqFile, const int16_t seqIndex, const int16_t frameIndex, const int16_t nFlags);
 void seq_PlotArrowSequence(const int nSprite, const FName seqFile, const int16_t seqIndex, const int frameIndex);
 void seq_DrawPilotLightSeq(double xOffset, double yOffset);
@@ -155,10 +163,10 @@ int getSeqFrameChunkPosY(const int nChunk);
 int getSeqFrameChunkPicnum(const int nChunk);
 int getSeqFrameChunkFlags(const int nChunk);
 
-SeqArray* getFileSeqs(const FName nSeqFile);
+TArray<Seq>* getFileSeqs(const FName nSeqFile);
 void playFrameSound(DExhumedActor* actor, const SeqFrame& seqFrame);
 
-inline const SeqFrameArray& getSequence(const FName nSeqFile, const unsigned nSeqIndex = 0)
+inline const Seq& getSequence(const FName nSeqFile, const unsigned nSeqIndex = 0)
 {
     return getFileSeqs(nSeqFile)->operator[](nSeqIndex);
 }
diff --git a/source/games/exhumed/src/set.cpp b/source/games/exhumed/src/set.cpp
index a88f7d206..73f93a07e 100644
--- a/source/games/exhumed/src/set.cpp
+++ b/source/games/exhumed/src/set.cpp
@@ -116,7 +116,7 @@ void BuildSoul(DExhumedActor* pSet)
     pActor->spr.xoffset = 0;
     pActor->spr.yoffset = 0;
     pActor->nSeqFile = "set";
-    pActor->spr.picnum = getSequence(pActor->nSeqFile, 75)[0].getFirstPicnum();
+    pActor->spr.picnum = getSequence(pActor->nSeqFile, 75).getFirstPicnum();
     pActor->spr.Angles.Yaw = RandomAngle();
     pActor->vel.X = 0;
     pActor->vel.Y = 0;
@@ -145,7 +145,7 @@ void AISoul::Tick(RunListEvent* ev)
 	auto pActor = ev->pObjActor;
 	if (!pActor) return;
 
-    playFrameSound(pActor, getSequence("set", 75)[0]);
+    playFrameSound(pActor, getSequence("set", 75).frames[0]);
 
     if (pActor->spr.scale.X < 0.5)
     {
@@ -272,7 +272,7 @@ void AISet::Tick(RunListEvent* ev)
     Gravity(pActor);
 
     const auto& setSeq = getSequence(pActor->nSeqFile, SetSeq[nAction].nSeqId);
-    const auto& seqFrame = setSeq[pActor->nFrame];
+    const auto& seqFrame = setSeq.frames[pActor->nFrame];
 
     pActor->spr.picnum = seqFrame.getFirstPicnum();
     playFrameSound(pActor, seqFrame);
@@ -285,7 +285,7 @@ void AISet::Tick(RunListEvent* ev)
     }
 
     pActor->nFrame++;
-    if (pActor->nFrame >= setSeq.Size())
+    if (pActor->nFrame >= setSeq.frames.Size())
     {
         pActor->nFrame = 0;
         bVal = true;
@@ -570,7 +570,7 @@ void AISet::Tick(RunListEvent* ev)
     {
         if (bVal)
         {
-            pActor->nFrame = setSeq.Size() - 1;
+            pActor->nFrame = setSeq.frames.Size() - 1;
         }
 
         if (nMov.exbits & kHitAux2)
@@ -609,7 +609,7 @@ void AISet::Tick(RunListEvent* ev)
         if (seqFrame.flags & 0x80)
         {
             pActor->spr.pos.Z -= GetActorHeight(pActor);
-            BuildCreatureChunk(pActor, getSequence("set", 76)[0].getFirstPicnum());
+            BuildCreatureChunk(pActor, getSequence("set", 76).getFirstPicnum());
 			pActor->spr.pos.Z += GetActorHeight(pActor);
         }
 
diff --git a/source/games/exhumed/src/snake.cpp b/source/games/exhumed/src/snake.cpp
index d2e766990..858280c62 100644
--- a/source/games/exhumed/src/snake.cpp
+++ b/source/games/exhumed/src/snake.cpp
@@ -164,7 +164,7 @@ void BuildSnake(int nPlayer, double zVal)
 
     auto pPlayerActor = PlayerList[nPlayer].pActor;
     auto pViewSect = PlayerList[nPlayer].pPlayerViewSect;
-    int nPic = getSequence("snakbody", 0)[0].getFirstPicnum();
+    int nPic = getSequence("snakbody", 0).getFirstPicnum();
 
 	auto pos = pPlayerActor->spr.pos.plusZ(zVal - 10);
 
@@ -339,7 +339,7 @@ void AISnake::Tick(RunListEvent* ev)
     DExhumedActor* pActor = SnakeList[nSnake].pSprites[0];
     if (!pActor) return;
 
-    playFrameSound(pActor, getSequence("snakehed")[0]);
+    playFrameSound(pActor, getSequence("snakehed").frames[0]);
 
     DExhumedActor* pEnemySprite = SnakeList[nSnake].pEnemy;
 
diff --git a/source/games/exhumed/src/sound.cpp b/source/games/exhumed/src/sound.cpp
index 2de1cf569..39c4ddb1b 100644
--- a/source/games/exhumed/src/sound.cpp
+++ b/source/games/exhumed/src/sound.cpp
@@ -719,7 +719,7 @@ void UpdateCreepySounds()
         if (nCreaturesKilled < nCreaturesTotal && !(PlayerList[nLocalPlayer].pPlayerViewSect->Flag & 0x2000))
         {
             const auto& creepySeq = getSequence("creepy");
-            const auto seqFrameSound = creepySeq[totalmoves % creepySeq.Size()].sound;
+            const auto seqFrameSound = creepySeq.frames[totalmoves % creepySeq.frames.Size()].sound;
             if (seqFrameSound >= 0 && (seqFrameSound & 0x1ff) < kMaxSounds)
             {
 				DVector2 adder;
diff --git a/source/games/exhumed/src/spider.cpp b/source/games/exhumed/src/spider.cpp
index 207f8b90a..3a9dcf26f 100644
--- a/source/games/exhumed/src/spider.cpp
+++ b/source/games/exhumed/src/spider.cpp
@@ -120,14 +120,14 @@ void AISpider::Tick(RunListEvent* ev)
     }
 
     const auto& spiderSeq = getSequence(spp->nSeqFile, SpiderSeq[nAction].nSeqId);
-    const auto& seqFrame = spiderSeq[spp->nFrame];
+    const auto& seqFrame = spiderSeq.frames[spp->nFrame];
 
     spp->spr.picnum = spp->nFrame < 9 ? seqFrame.getFirstPicnum() : -1;
 
     playFrameSound(spp, seqFrame);
 
     spp->nFrame++;
-    if (spp->nFrame >= spiderSeq.Size()) {
+    if (spp->nFrame >= spiderSeq.frames.Size()) {
         spp->nFrame = 0;
     }
 
@@ -421,7 +421,7 @@ void AISpider::Damage(RunListEvent* ev)
 
         for (int i = 0; i < 7; i++)
         {
-            BuildCreatureChunk(spp, getSequence("spider", i + 41)[0].getFirstPicnum());
+            BuildCreatureChunk(spp, getSequence("spider", i + 41).getFirstPicnum());
         }
     }
 }
diff --git a/source/games/exhumed/src/wasp.cpp b/source/games/exhumed/src/wasp.cpp
index bfc898c3a..a10ec90ac 100644
--- a/source/games/exhumed/src/wasp.cpp
+++ b/source/games/exhumed/src/wasp.cpp
@@ -216,14 +216,14 @@ void AIWasp::Tick(RunListEvent* ev)
     bool bVal = false;
 
     const auto& waspSeq = getSequence(pActor->nSeqFile, WaspSeq[nAction].nSeqId);
-    const auto& seqFrame = waspSeq[pActor->nFrame];
+    const auto& seqFrame = waspSeq.frames[pActor->nFrame];
 
     pActor->spr.picnum = seqFrame.getFirstPicnum();
 
     playFrameSound(pActor, seqFrame);
 
     pActor->nFrame++;
-    if (pActor->nFrame >= waspSeq.Size())
+    if (pActor->nFrame >= waspSeq.frames.Size())
     {
         pActor->nFrame = 0;
         bVal = true;