- Exhumed: Convert out anim system to new backend hashtable.

This commit is contained in:
Mitchell Richters 2023-04-16 08:11:01 +10:00
parent f404708f51
commit 6f242b901d
16 changed files with 103 additions and 127 deletions

View file

@ -33,9 +33,8 @@ enum
kAnimLoop = (1 << 4)
};
void InitAnims();
void DestroyAnim(DExhumedActor* nAnim);
DExhumedActor* BuildAnim(DExhumedActor* actor, int nSeq, int nOffset, const DVector3& pos, sectortype* pSector, double nScale, int nFlag);
DExhumedActor* BuildAnim(DExhumedActor* actor, const FName seqFile, int seqIndex, const DVector3& pos, sectortype* pSector, double nScale, int nFlag);
void UnlinkIgnitedAnim(DExhumedActor* pActor);
void FuncAnim(int, int, int, int);
void BuildExplosion(DExhumedActor* actor);
@ -64,7 +63,7 @@ struct bulletInfo
int field_4; // 4
int16_t field_8; // 8
int16_t nSeq; // 10
int16_t field_C; // 12
FName animFile; // 12
int16_t nFlags;
int16_t nRadius; // damage radius
int16_t xyRepeat;

View file

@ -25,10 +25,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
BEGIN_PS_NS
int nMagicSeq = -1;
int nPreMagicSeq = -1;
int nSavePointSeq = -1;
//---------------------------------------------------------------------------
//
@ -36,24 +32,6 @@ int nSavePointSeq = -1;
//
//---------------------------------------------------------------------------
void SerializeAnim(FSerializer& arc)
{
if (arc.BeginObject("anims"))
{
arc("magic", nMagicSeq)
("premagic", nPreMagicSeq)
("savepoint", nSavePointSeq)
.EndObject();
}
}
void InitAnims()
{
nMagicSeq = getSeqFromId(kSeqItems, 21);
nPreMagicSeq = getSeqFromId(kSeqMagic2);
nSavePointSeq = getSeqFromId(kSeqItems, 12);
}
/*
Use when deleting an ignited actor to check if any actors reference it.
Will remove the actor's anim loop flag and set the source (the ignited actor's) actor target to null.
@ -64,6 +42,7 @@ void InitAnims()
Specifically needed for IgniteSprite() anims which can become orphaned from the source actor (e.g a bullet)
when the bullet actor is deleted.
*/
void UnlinkIgnitedAnim(DExhumedActor* pActor)
{
ExhumedStatIterator it(kStatIgnited);
@ -95,7 +74,7 @@ void DestroyAnim(DExhumedActor* pActor)
//
//---------------------------------------------------------------------------
DExhumedActor* BuildAnim(DExhumedActor* pActor, int nSeq, int nOffset, const DVector3& pos, sectortype* pSector, double nScale, int nFlag)
DExhumedActor* BuildAnim(DExhumedActor* pActor, const FName seqFile, int seqIndex, const DVector3& pos, sectortype* pSector, double nScale, int nFlag)
{
if (pActor == nullptr)
pActor = insertActor(pSector, 500);
@ -135,7 +114,8 @@ DExhumedActor* BuildAnim(DExhumedActor* pActor, int nSeq, int nOffset, const DVe
pActor->nRun = runlist_AddRunRec(NewRun, pActor, 0x100000);
pActor->nFlags = nFlag;
pActor->nFrame = 0;
pActor->nSeq = getSeqFromId(nSeq, nOffset);
pActor->nSeqFile = seqFile;
pActor->nSeq = seqIndex;
pActor->pTarget = nullptr;
pActor->nPhase = ITEM_MAGIC;
pActor->backuppos();
@ -152,14 +132,14 @@ DExhumedActor* BuildAnim(DExhumedActor* pActor, int nSeq, int nOffset, const DVe
void AIAnim::Tick(RunListEvent* ev)
{
const auto pActor = ev->pObjActor;
if (!pActor) return;
if (!pActor || pActor->nSeqFile == NAME_None) return;
const int nSeq = pActor->nSeq;
const auto& animSeq = getSequence(pActor->nSeqFile, pActor->nSeq);
const int nFrame = pActor->nFrame;
if (!(pActor->spr.cstat & CSTAT_SPRITE_INVISIBLE))
{
seq_MoveSequence(pActor, nSeq, nFrame);
playFrameSound(pActor, animSeq[nFrame]);
}
if (pActor->spr.statnum == kStatIgnited)
@ -222,20 +202,21 @@ void AIAnim::Tick(RunListEvent* ev)
}
pActor->nFrame++;
if (pActor->nFrame >= getSeqFrameCount(nSeq))
if (pActor->nFrame >= animSeq.Size())
{
if (pActor->nFlags & kAnimLoop)
{
pActor->nFrame = 0;
}
else if (nSeq == nPreMagicSeq)
else if (pActor->nSeqFile == FName("magic2") && pActor->nSeq == 0)
{
pActor->nFrame = 0;
pActor->nSeq = nMagicSeq;
pActor->nSeqFile = "items";
pActor->nSeq = 21;
pActor->nFlags |= kAnimLoop;
pActor->spr.cstat |= CSTAT_SPRITE_TRANSLUCENT;
}
else if (nSeq == nSavePointSeq)
else if (pActor->nSeqFile == FName("items") && pActor->nSeq == 12)
{
pActor->nFrame = 0;
pActor->nSeq++;
@ -257,9 +238,9 @@ void AIAnim::Tick(RunListEvent* ev)
void AIAnim::Draw(RunListEvent* ev)
{
const auto pActor = ev->pObjActor;
if (!pActor) return;
if (!pActor || pActor->nSeqFile == NAME_None) return;
//seq_PlotSequence(ev->nParam, pActor->nSeq, pActor->nFrame, 0x101);
seq_PlotSequence(ev->nParam, pActor->nSeqFile, pActor->nSeq, pActor->nFrame, 0x101);
ev->pTSprite->ownerActor = nullptr;
}
@ -273,18 +254,18 @@ void BuildExplosion(DExhumedActor* pActor)
{
const auto pSector = pActor->sector();
int nSeq = 36;
FName seqFile = "grenpow";
if (pSector->Flag & kSectUnderwater)
{
nSeq = 75;
seqFile = "grenbubb";
}
else if (pActor->spr.pos.Z == pSector->floorz)
{
nSeq = 34;
seqFile = "grenboom";
}
BuildAnim(nullptr, nSeq, 0, pActor->spr.pos, pSector, pActor->spr.scale.X, 4);
BuildAnim(nullptr, seqFile, 0, pActor->spr.pos, pSector, pActor->spr.scale.X, 4);
}
//---------------------------------------------------------------------------
@ -312,20 +293,21 @@ void BuildSplash(DExhumedActor* pActor, sectortype* pSector)
const int bIsLava = pSector->Flag & kSectLava;
int nSeq, nFlag;
FName seqFile;
int nFlag;
if (bIsLava)
{
nSeq = 43;
seqFile = "lsplash";
nFlag = 4;
}
else
{
nSeq = 35;
seqFile = "splash";
nFlag = 0;
}
const auto pSpawned = BuildAnim(nullptr, nSeq, 0, DVector3(pActor->spr.pos.XY(), pSector->floorz), pSector, nScale, nFlag);
const auto pSpawned = BuildAnim(nullptr, seqFile, 0, DVector3(pActor->spr.pos.XY(), pSector->floorz), pSector, nScale, nFlag);
if (!bIsLava)
{

View file

@ -77,7 +77,8 @@ static DExhumedActor* BuildBubble(const DVector3& pos, sectortype* pSector, cons
// GrabTimeSlot(3);
pActor->nFrame = 0;
pActor->nSeq = getSeqFromId(kSeqBubble, nSize);
pActor->nSeqFile = "bubble";
pActor->nSeq = nSize;
pActor->spr.intowner = runlist_AddRunRec(pActor->spr.lotag - 1, pActor, 0x140000);
pActor->nRun = runlist_AddRunRec(NewRun, pActor, 0x140000);
@ -95,13 +96,13 @@ void AIBubble::Tick(RunListEvent* ev)
const auto pActor = ev->pObjActor;
if (!pActor) return;
const int nSeq = pActor->nSeq;
const auto& bubbSeq = getSequence(pActor->nSeqFile, pActor->nSeq);
seq_MoveSequence(pActor, nSeq, pActor->nFrame);
playFrameSound(pActor, bubbSeq[pActor->nFrame]);
pActor->nFrame++;
if (pActor->nFrame >= getSeqFrameCount(nSeq))
if (pActor->nFrame >= bubbSeq.Size())
pActor->nFrame = 0;
pActor->spr.pos.Z = pActor->vel.Z;
@ -113,7 +114,7 @@ void AIBubble::Tick(RunListEvent* ev)
auto pSectAbove = pSector->pAbove;
if (pActor->spr.hitag > -1 && pSectAbove != nullptr)
BuildAnim(nullptr, 70, 0, DVector3(pActor->spr.pos.XY(), pSectAbove->floorz), pSectAbove, 1., 0);
BuildAnim(nullptr, "seebubbl", 0, DVector3(pActor->spr.pos.XY(), pSectAbove->floorz), pSectAbove, 1., 0);
DestroyBubble(pActor);
}
@ -127,11 +128,11 @@ void AIBubble::Tick(RunListEvent* ev)
void AIBubble::Draw(RunListEvent* ev)
{
const auto pActor = ev->pObjActor;
if (!pActor) return;
//seq_PlotSequence(ev->nParam, pActor->nSeq, pActor->nFrame, 1);
ev->pTSprite->ownerActor = nullptr;
if (const auto pActor = ev->pObjActor)
{
seq_PlotSequence(ev->nParam, pActor->nSeqFile, pActor->nSeq, pActor->nFrame, 1);
ev->pTSprite->ownerActor = nullptr;
}
}

View file

@ -107,23 +107,23 @@ void SerializeBullet(FSerializer& arc)
}
bulletInfo BulletInfo[] = {
{ 25, 1, 20, -1, -1, 13, 0, 0, -1 },
{ 25, -1, 65000, -1, 31, 73, 0, 0, -1 },
{ 15, -1, 60000, -1, 31, 73, 0, 0, -1 },
{ 5, 15, 2000, -1, 14, 38, 4, 5, 3 },
{ 250, 100, 2000, -1, 33, 34, 4, 20, -1 },
{ 200, -1, 2000, -1, 20, 23, 4, 10, -1 },
{ 200, -1, 60000, 68, 68, -1, -1, 0, -1 },
{ 300, 1, 0, -1, -1, -1, 0, 50, -1 },
{ 18, -1, 2000, -1, 18, 29, 4, 0, -1 },
{ 20, -1, 2000, 37, 11, 30, 4, 0, -1 },
{ 25, -1, 3000, -1, 44, 36, 4, 15, 90 },
{ 30, -1, 1000, -1, 52, 53, 4, 20, 48 },
{ 20, -1, 3500, -1, 54, 55, 4, 30, -1 },
{ 10, -1, 5000, -1, 57, 76, 4, 0, -1 },
{ 40, -1, 1500, -1, 63, 38, 4, 10, 40 },
{ 20, -1, 2000, -1, 60, 12, 0, 0, -1 },
{ 5, -1, 60000, -1, 31, 76, 0, 0, -1 }
{ 25, 1, 20, -1, -1, "kapow", 0, 0, -1 },
{ 25, -1, 65000, -1, 31, "poof2", 0, 0, -1 },
{ 15, -1, 60000, -1, 31, "poof2", 0, 0, -1 },
{ 5, 15, 2000, -1, 14, "firepoof", 4, 5, 3 },
{ 250, 100, 2000, -1, 33, "grenboom", 4, 20, -1 },
{ 200, -1, 2000, -1, 20, "cobrapow", 4, 10, -1 },
{ 200, -1, 60000, 68, 68, NAME_None, -1, 0, -1 },
{ 300, 1, 0, -1, -1, NAME_None, 0, 50, -1 },
{ 18, -1, 2000, -1, 18, "anupoof", 4, 0, -1 },
{ 20, -1, 2000, 37, 11, "skulpoof", 4, 0, -1 },
{ 25, -1, 3000, -1, 44, "grenpow", 4, 15, 90 },
{ 30, -1, 1000, -1, 52, "setgblow", 4, 20, 48 },
{ 20, -1, 3500, -1, 54, "bizzpoof", 4, 30, -1 },
{ 10, -1, 5000, -1, 57, "rochfire", 4, 0, -1 },
{ 40, -1, 1500, -1, 63, "firepoof", 4, 10, 40 },
{ 20, -1, 2000, -1, 60, "poof", 0, 0, -1 },
{ 5, -1, 60000, -1, 31, "rochfire", 0, 0, -1 }
};
@ -177,9 +177,7 @@ void IgniteSprite(DExhumedActor* pActor)
{
pActor->spr.hitag += 2;
auto pAnimActor = BuildAnim(nullptr, 38, 0, pActor->spr.pos, pActor->sector(), 0.625, 20);
if (pAnimActor)
if (const auto pAnimActor = BuildAnim(nullptr, "firepoof", 0, pActor->spr.pos, pActor->sector(), 0.625, 20))
{
pAnimActor->pTarget = pActor;
ChangeActorStat(pAnimActor, kStatIgnited);
@ -217,7 +215,7 @@ void BulletHitsSprite(Bullet *pBullet, DExhumedActor* pBulletActor, DExhumedActo
}
if (!RandomSize(2)) {
BuildAnim(nullptr, pBulletInfo->field_C, 0, pos, pSector, 0.625, pBulletInfo->nFlags);
BuildAnim(nullptr, pBulletInfo->animFile, 0, pos, pSector, 0.625, pBulletInfo->nFlags);
}
return;
@ -280,7 +278,7 @@ void BulletHitsSprite(Bullet *pBullet, DExhumedActor* pBulletActor, DExhumedActo
if (nStat <= 90 || nStat >= 199)
{
BuildAnim(nullptr, pBulletInfo->field_C, 0, pos, pSector, 0.625, pBulletInfo->nFlags);
BuildAnim(nullptr, pBulletInfo->animFile, 0, pos, pSector, 0.625, pBulletInfo->nFlags);
return;
}
@ -292,13 +290,13 @@ void BulletHitsSprite(Bullet *pBullet, DExhumedActor* pBulletActor, DExhumedActo
case 102:
case kStatExplodeTrigger:
case kStatExplodeTarget:
BuildAnim(nullptr, 12, 0, pos, pSector, 0.625, 0);
BuildAnim(nullptr, "poof", 0, pos, pSector, 0.625, 0);
break;
default:
BuildAnim(nullptr, 39, 0, pos, pSector, 0.625, 0);
BuildAnim(nullptr, "bloodhit", 0, pos, pSector, 0.625, 0);
if (pBullet->nType > 2)
{
BuildAnim(nullptr, pBulletInfo->field_C, 0, pos, pSector, 0.625, pBulletInfo->nFlags);
BuildAnim(nullptr, pBulletInfo->animFile, 0, pos, pSector, 0.625, pBulletInfo->nFlags);
}
break;
}
@ -492,7 +490,7 @@ HITSPRITE:
}
else
{
BuildAnim(nullptr, pBulletInfo->field_C, 0, pos, pHitSect, 0.625, pBulletInfo->nFlags);
BuildAnim(nullptr, pBulletInfo->animFile, 0, pos, pHitSect, 0.625, pBulletInfo->nFlags);
}
}
else
@ -511,7 +509,7 @@ HITSPRITE:
}
// draws bullet puff on walls when they're shot
BuildAnim(nullptr, pBulletInfo->field_C, 0, pos.plusZ(zOffset - 16), pHitSect, 0.625, pBulletInfo->nFlags);
BuildAnim(nullptr, pBulletInfo->animFile, 0, pos.plusZ(zOffset - 16), pHitSect, 0.625, pBulletInfo->nFlags);
}
}
else
@ -808,7 +806,7 @@ void AIBullet::Tick(RunListEvent* ev)
if (nFlag & 0x80)
{
BuildAnim(nullptr, 45, 0, pActor->spr.pos, pActor->sector(), pActor->spr.scale.X, 0);
BuildAnim(nullptr, "smokebal", 0, pActor->spr.pos, pActor->sector(), pActor->spr.scale.X, 0);
}
BulletList[nBullet].nFrame++;

View file

@ -78,11 +78,6 @@ void BuildFishLimb(DExhumedActor* pActor, int anim)
pChunkActor->nSeqFile = "fish";
}
void BuildBlood(const DVector3& pos, sectortype* pSector)
{
BuildAnim(nullptr, kSeqFish, 36, pos, pSector, 1.171875, 128);
}
//---------------------------------------------------------------------------
//
//
@ -106,7 +101,7 @@ void AIFishLimb::Tick(RunListEvent* ev)
{
pActor->nFrame = 0;
if (RandomBit()) {
BuildBlood(pActor->spr.pos, pActor->sector());
BuildAnim(nullptr, pActor->nSeqFile, 36, pActor->spr.pos, pActor->sector(), 1.171875, 128);
}
}

View file

@ -166,7 +166,7 @@ void BuildGrenade(int nPlayer)
void ExplodeGrenade(DExhumedActor* pActor)
{
int var_28;
FName animFile;
double scale;
int nPlayer = pActor->spr.intowner;
@ -176,7 +176,7 @@ void ExplodeGrenade(DExhumedActor* pActor)
if (pGrenadeSect->Flag & kSectUnderwater)
{
var_28 = 75;
animFile = "grenbubb";
scale = 0.9375;
}
else
@ -184,13 +184,13 @@ void ExplodeGrenade(DExhumedActor* pActor)
if (pActor->spr.pos.Z < pGrenadeSect->floorz)
{
scale = 3.125;
var_28 = 36;
animFile = "grenpow";
// TODO MonoOut("GRENPOW\n");
}
else
{
var_28 = 34;
animFile = "grenboom";
scale = 2.3475;
// TODO MonoOut("GRENBOOM\n");
@ -220,7 +220,7 @@ void ExplodeGrenade(DExhumedActor* pActor)
runlist_RadialDamageEnemy(pActor, nDamage, BulletInfo[kWeaponGrenade].nRadius);
BuildAnim(nullptr, var_28, 0, pActor->spr.pos, pActor->sector(), scale, 4);
BuildAnim(nullptr, animFile, 0, pActor->spr.pos, pActor->sector(), scale, 4);
AddFlash(pActor->sector(), pActor->spr.pos, 128);
DestroyGrenade(pActor);

View file

@ -758,7 +758,7 @@ loc_flag:
else if (pActor2->spr.statnum == 102)
{
// loc_27370:
BuildAnim(nullptr, 12, 0, thePos, pSectorB, 0.46875, 0);
BuildAnim(nullptr, "poof", 0, thePos, pSectorB, 0.46875, 0);
}
else if (pActor2->spr.statnum == kStatExplodeTrigger) {
var_28 += 2;
@ -770,7 +770,7 @@ loc_flag:
else
{
// loc_27370:
BuildAnim(nullptr, 12, 0, thePos, pSectorB, 0.46875, 0);
BuildAnim(nullptr, "poof", 0, thePos, pSectorB, 0.46875, 0);
}
}
}

View file

@ -129,7 +129,6 @@ uint8_t LoadLevel(MapRecord* map)
InitRats();
InitBullets();
InitWeapons();
InitAnims();
InitSnakes();
InitLights();
ClearAutomap();

View file

@ -134,7 +134,7 @@ void BuildItemAnim(DExhumedActor* pActor)
if (nItemAnimInfo[nItem].a >= 0)
{
auto pAnimActor = BuildAnim(pActor, 41, nItemAnimInfo[nItem].a, pActor->spr.pos, pActor->sector(), nItemAnimInfo[nItem].repeat * REPEAT_SCALE, 20);
auto pAnimActor = BuildAnim(pActor, "items", nItemAnimInfo[nItem].a, pActor->spr.pos, pActor->sector(), nItemAnimInfo[nItem].repeat * REPEAT_SCALE, 20);
if (nItem == 44) {
pAnimActor->spr.cstat |= CSTAT_SPRITE_TRANSLUCENT;
@ -403,16 +403,7 @@ void DropMagic(DExhumedActor* pActor)
if (nMagicCount <= 0)
{
auto pAnimActor = BuildAnim(
nullptr,
64,
0,
pActor->spr.pos,
pActor->sector(),
0.75,
4);
if (pAnimActor)
if (const auto pAnimActor = BuildAnim(nullptr, "magic2", 0, pActor->spr.pos, pActor->sector(), 0.75,4))
{
AddFlash(pAnimActor->sector(), pAnimActor->spr.pos, 128);
ChangeActorStat(pAnimActor, 950);
@ -480,7 +471,7 @@ void DoRegenerates()
if (pActor->spr.extra <= 0)
{
BuildAnim(nullptr, 38, 0, pActor->spr.pos, pActor->sector(), 1, 4);
BuildAnim(nullptr, "firepoof", 0, pActor->spr.pos, pActor->sector(), 1, 4);
D3PlayFX(StaticSound[kSoundTorchOn], pActor);
}
else {

View file

@ -1998,20 +1998,9 @@ void AIObject::Tick(RunListEvent* ev)
}
else
{
int var_18;
// red branch
if ((nStat == kStatExplodeTarget) || (pActor->spr.pos.Z < pActor->sector()->floorz))
{
var_18 = 36;
}
else
{
var_18 = 34;
}
const FName animFile = (nStat == kStatExplodeTarget) || (pActor->spr.pos.Z < pActor->sector()->floorz) ? "grenpow" : "grenboom";
AddFlash(pActor->sector(), pActor->spr.pos, 128);
BuildAnim(nullptr, var_18, 0, DVector3(pActor->spr.pos.XY(), pActor->sector()->floorz), pActor->sector(), 3.75, 4);
BuildAnim(nullptr, animFile, 0, DVector3(pActor->spr.pos.XY(), pActor->sector()->floorz), pActor->sector(), 3.75, 4);
// int edi = nSprite | 0x4000;

View file

@ -1946,7 +1946,7 @@ static void doPlayerActionSequence(Player* const pPlayer)
{
sectortype* mouthSect;
const auto pos = WheresMyMouth(pPlayer->nPlayer, &mouthSect);
BuildAnim(nullptr, 71, 0, DVector3(pos.XY(), pPlayerActor->spr.pos.Z + 15), mouthSect, 1.171875, 128);
BuildAnim(nullptr, "blood", 0, DVector3(pos.XY(), pPlayerActor->spr.pos.Z + 15), mouthSect, 1.171875, 128);
}
break;
case 17:

View file

@ -269,7 +269,7 @@ void DestroyEgg(int nEgg)
if (QueenEgg[nEgg].nAction != 4)
{
BuildAnim(nullptr, 34, 0, pActor->spr.pos, pActor->sector(), pActor->spr.scale.X, 4);
BuildAnim(nullptr, "grenboom", 0, pActor->spr.pos, pActor->sector(), pActor->spr.scale.X, 4);
}
else
{
@ -1525,7 +1525,7 @@ void AIQueen::Damage(RunListEvent* ev)
QueenList[nQueen].nHealth = 4000;
QueenList[nQueen].nAction = 7;
BuildAnim(nullptr, 36, 0, pActor->spr.pos.plusZ(-30), pActor->sector(), pActor->spr.scale.X, 4);
BuildAnim(nullptr, "grenpow", 0, pActor->spr.pos.plusZ(-30), pActor->sector(), pActor->spr.scale.X, 4);
break;
case 2:
QueenList[nQueen].nHealth = 4000;

View file

@ -29,7 +29,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
BEGIN_PS_NS
void SerializeState(FSerializer& arc);
void SerializeAnim(FSerializer& arc);
void SerializeBullet(FSerializer& arc);
void SerializeGun(FSerializer& arc);
void SerializeInit(FSerializer& arc);
@ -60,7 +59,6 @@ void GameInterface::SerializeGameState(FSerializer& arc)
if (arc.BeginObject("exhumed"))
{
SerializeState(arc);
SerializeAnim(arc);
SerializeBullet(arc);
SerializeGun(arc);
SerializeInit(arc);

View file

@ -776,6 +776,29 @@ void seq_MoveSequence(DExhumedActor* actor, int16_t nSeq, int16_t nFrame)
//
//---------------------------------------------------------------------------
void playFrameSound(DExhumedActor* actor, const SeqFrame& seqFrame)
{
const int nSound = seqFrame.sound;
if (nSound == -1)
return;
if (actor)
{
D3PlayFX(nSound, actor);
}
else
{
PlayLocalSound(nSound, 0);
}
}
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
int seq_GetSeqPicnum2(int16_t nSeq, int16_t nFrame)
{
return getSeqFrameChunkPicnum(getSeqFrameChunk(getSeqFrame(nSeq, nFrame)));

View file

@ -159,6 +159,7 @@ int getSeqFrameChunkPicnum(const int nChunk);
int getSeqFrameChunkFlags(const int nChunk);
const SeqFrameArray& getSequence(const FName nSeqFile, const unsigned nSeqIndex = 0);
void playFrameSound(DExhumedActor* actor, const SeqFrame& seqFrame);
END_PS_NS

View file

@ -145,7 +145,7 @@ void ExplodeSnakeSprite(DExhumedActor* pActor, int nPlayer)
pActor->pTarget = nOwner;
BuildAnim(nullptr, 23, 0, pActor->spr.pos, pActor->sector(), 0.625, 4);
BuildAnim(nullptr, "cobrapow", 0, pActor->spr.pos, pActor->sector(), 0.625, 4);
AddFlash(pActor->sector(), pActor->spr.pos, 128);