From 30ccbe27106c578918ad41bc6ecc32837a3d7910 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 21 Dec 2022 13:20:14 +0100 Subject: [PATCH] - moved actions out of the ScriptCode array and gave them a dedicated struct with meaningful member names. --- source/games/duke/src/actors.cpp | 9 +++---- source/games/duke/src/animatesprites.cpp | 10 +++---- source/games/duke/src/game.cpp | 1 + source/games/duke/src/gamedef.cpp | 34 ++++++++++++++++-------- source/games/duke/src/gameexec.cpp | 8 +++--- source/games/duke/src/savegame.cpp | 21 ++++++++++++++- source/games/duke/src/spawn.cpp | 6 +++-- source/games/duke/src/types.h | 15 +++++++++++ 8 files changed, 76 insertions(+), 28 deletions(-) diff --git a/source/games/duke/src/actors.cpp b/source/games/duke/src/actors.cpp index cfcdc03db..6409f13e0 100644 --- a/source/games/duke/src/actors.cpp +++ b/source/games/duke/src/actors.cpp @@ -82,13 +82,12 @@ void TickActor(DDukeActor* self) } // Run sprite animations. - if (self->temp_data[4]) + if (self->curAction->name != NAME_None) { // This code was utterly cryptic in the original source. - auto ptr = &ScriptCode[self->temp_data[4]]; - int numframes = ptr[1]; - int increment = ptr[3]; - int delay = ptr[4]; + int numframes = self->curAction->numframes; + int increment = self->curAction->increment; + int delay = self->curAction->delay; self->spr.lotag += TICSPERFRAME; if (self->spr.lotag > delay) diff --git a/source/games/duke/src/animatesprites.cpp b/source/games/duke/src/animatesprites.cpp index cfe0b70d5..cbb7b598a 100644 --- a/source/games/duke/src/animatesprites.cpp +++ b/source/games/duke/src/animatesprites.cpp @@ -112,11 +112,11 @@ void applyanimations(tspritetype* t, DDukeActor* h, const DVector2& viewVec, DAn if (gs.actorinfo[h->spr.picnum].scriptaddress && !(h->flags2 & SFLAG2_DONTANIMATE))// && (t->cstat & CSTAT_SPRITE_ALIGNMENT_MASK) != CSTAT_SPRITE_ALIGNMENT_SLAB) { DAngle kang; - int t4 = h->temp_data[4]; + auto action = h->curAction; int k = 0, l = 0; - if (t4) + if (h->curAction->name != NAME_None) { - l = ScriptCode[t4 + 2]; + l = action->rotationtype; if (tilehasmodelorvoxel(h->spr.spritetexture(), h->spr.pal)) { @@ -168,7 +168,7 @@ void applyanimations(tspritetype* t, DDukeActor* h, const DVector2& viewVec, DAn if (isRR()) { bool bg = badguy(h); - if (bg && h->spr.statnum == 2 && h->spr.extra > 0) + if (bg && h->spr.statnum == STAT_ZOMBIEACTOR && h->spr.extra > 0) { kang = (t->pos.XY() - viewVec).Angle(); k = angletorotation1(t->Angles.Yaw, kang); @@ -186,7 +186,7 @@ void applyanimations(tspritetype* t, DDukeActor* h, const DVector2& viewVec, DAn } } - k += ScriptCode[t4] + l * h->temp_data[3]; + k += action->offset + l * h->temp_data[3]; t->picnum += k; if (isRRRA() && RRRAFullbrightHack(t, k)) t->shade = -127; diff --git a/source/games/duke/src/game.cpp b/source/games/duke/src/game.cpp index 1aa2e71c5..dbb47c7de 100644 --- a/source/games/duke/src/game.cpp +++ b/source/games/duke/src/game.cpp @@ -381,6 +381,7 @@ void GameInterface::app_init() ud.m_monsters_off = userConfig.nomonsters; ps[0].aim_mode = 1; ud.cameraactor = nullptr; + actions.Push({}); // make sure the first entry in 'actions' is a null action. if (fileSystem.FileExists("DUKESW.BIN")) g_gameType |= GAMEFLAG_SHAREWARE; diff --git a/source/games/duke/src/gamedef.cpp b/source/games/duke/src/gamedef.cpp index a452df32e..e7622a0e2 100644 --- a/source/games/duke/src/gamedef.cpp +++ b/source/games/duke/src/gamedef.cpp @@ -1155,19 +1155,31 @@ int ConCompiler::parsecommand() if (lnum >= 0) { warningcount++; - Printf(TEXTCOLOR_RED " * WARNING.(%s, line %d) Duplicate event '%s' ignored.\n", fn, line_number, parselabel.GetChars()); + Printf(TEXTCOLOR_RED " * WARNING.(%s, line %d) Duplicate action '%s' ignored.\n", fn, line_number, parselabel.GetChars()); } - else appendlabeladdress(LABEL_ACTION); + else appendlabelvalue(LABEL_ACTION, actions.Size()); - for (j = 0; j < 5; j++) - { - if (keyword() >= 0) break; - transnum(LABEL_DEFINE); - } - for (k = j; k < 5; k++) - { - appendscriptvalue(0); - } + ActorAction& action = actions[actions.Reserve(1)]; + + memset(&action, 0, sizeof(action)); + action.qualifiedName = FStringf("$con$.%s", parselabel.GetChars()); + action.name = parselabel.GetChars(); + action.base.SetNull(); // CON actions are relative to base pic. + if (keyword() >= 0) break; + transnum(LABEL_DEFINE); + action.offset = popscriptvalue(); + if (keyword() >= 0) break; + transnum(LABEL_DEFINE); + action.numframes = popscriptvalue(); + if (keyword() >= 0) break; + transnum(LABEL_DEFINE); + action.rotationtype = popscriptvalue(); + if (keyword() >= 0) break; + transnum(LABEL_DEFINE); + action.increment = popscriptvalue(); + if (keyword() >= 0) break; + transnum(LABEL_DEFINE); + action.delay = popscriptvalue(); } return 0; diff --git a/source/games/duke/src/gameexec.cpp b/source/games/duke/src/gameexec.cpp index 34609cbbe..9ab530d34 100644 --- a/source/games/duke/src/gameexec.cpp +++ b/source/games/duke/src/gameexec.cpp @@ -1508,7 +1508,7 @@ int ParseState::parse(void) insptr++; // HACK ALERT! The fire animation uses a broken ifrnd setup to delay its start because original CON has no variables // But the chosen random value of 16/255 is too low and can cause delays of a second or more. (identical in Duke and RR.) - if (g_ac->IsKindOf(NAME_RedneckFire) && g_t[4] == 0 && *insptr == 16) + if (g_ac->IsKindOf(NAME_RedneckFire) && g_ac->curAction->name == NAME_None && *insptr == 16) { parseifelse(rnd(64)); break; @@ -1554,7 +1554,7 @@ int ParseState::parse(void) case concmd_ai: insptr++; g_t[5] = *insptr; - g_t[4] = ScriptCode[g_t[5]]; // Action + g_ac->curAction = &actions[ScriptCode[g_t[5]]]; // Action g_t[1] = ScriptCode[g_t[5] + 1]; // move g_ac->spr.hitag = ScriptCode[g_t[5] + 2]; // Ai g_t[0] = g_t[2] = g_t[3] = 0; @@ -1566,7 +1566,7 @@ int ParseState::parse(void) insptr++; g_t[2] = 0; g_t[3] = 0; - g_t[4] = *insptr; + g_ac->curAction = &actions[*insptr]; insptr++; break; @@ -1912,7 +1912,7 @@ int ParseState::parse(void) break; case concmd_ifaction: insptr++; - parseifelse(g_t[4] == *insptr); + parseifelse((g_ac->curAction - actions.Data()) == *insptr); break; case concmd_ifactioncount: insptr++; diff --git a/source/games/duke/src/savegame.cpp b/source/games/duke/src/savegame.cpp index 6f43e9b4b..9fcb8652c 100644 --- a/source/games/duke/src/savegame.cpp +++ b/source/games/duke/src/savegame.cpp @@ -47,6 +47,24 @@ FSerializer& Serialize(FSerializer& arc, const char* keyname, GameVarValue& w, G void lava_serialize(FSerializer& arc); void SerializeGameVars(FSerializer &arc); +FSerializer& Serialize(FSerializer& arc, const char* keyname, ActorAction*& w, ActorAction** def) +{ + if (arc.isWriting()) + { + auto ww = w ? w : &actions[0]; + if (keyname == nullptr || ww->qualifiedName != NAME_None) Serialize(arc, keyname, ww->qualifiedName, nullptr); + } + else + { + FName n = NAME_None; + Serialize(arc, keyname, n, nullptr); + auto index = actions.FindEx([=](const ActorAction& el) { return el.qualifiedName == n; }); + if (index >= actions.Size()) index = 0; + w = &actions[index]; + } + return arc; +} + FSerializer& Serialize(FSerializer& arc, const char* keyname, animwalltype& w, animwalltype* def) { if (arc.BeginObject(keyname)) @@ -288,7 +306,8 @@ void DDukeActor::Serialize(FSerializer& arc) ("uservars", uservars) ("flags1", flags1) ("flags2", flags2) - ("flags3", flags3); + ("flags3", flags3) + ("curaction", curAction); } diff --git a/source/games/duke/src/spawn.cpp b/source/games/duke/src/spawn.cpp index dcd6545f9..ef47c2b0b 100644 --- a/source/games/duke/src/spawn.cpp +++ b/source/games/duke/src/spawn.cpp @@ -45,6 +45,7 @@ BEGIN_DUKE_NS void setFromSpawnRec(DDukeActor* act, SpawnRec* info) { + act->curAction = &actions[0]; if (info) { if (info->basetex > 0 && act->IsKindOf(NAME_DukeGenericDestructible)) @@ -59,6 +60,7 @@ void setFromSpawnRec(DDukeActor* act, SpawnRec* info) } else { + // same for simple sprite replacements with existing implementations. if (info->basetex >= 0 && info->basetex < MAXTILES) act->spr.picnum = info->basetex; if (info->fullbright & 1) act->spr.cstat2 |= CSTAT2_SPRITE_FULLBRIGHT; } @@ -123,7 +125,7 @@ DDukeActor* CreateActor(sectortype* whatsectp, const DVector3& pos, PClassActor* { auto sa = &ScriptCode[gs.actorinfo[s_pn].scriptaddress]; act->spr.extra = sa[0]; - act->temp_data[4] = sa[1]; + act->curAction = &actions[sa[1]]; act->temp_data[1] = sa[2]; act->spr.hitag = sa[3]; } @@ -246,7 +248,7 @@ bool initspriteforspawn(DDukeActor* act) if (gs.actorinfo[s].scriptaddress) { act->spr.extra = ScriptCode[gs.actorinfo[s].scriptaddress]; - act->temp_data[4] = ScriptCode[gs.actorinfo[s].scriptaddress+1]; + act->curAction = &actions[ScriptCode[gs.actorinfo[s].scriptaddress+1]]; act->temp_data[1] = ScriptCode[gs.actorinfo[s].scriptaddress+2]; int s3 = ScriptCode[gs.actorinfo[s].scriptaddress+3]; if (s3 && act->spr.hitag == 0) diff --git a/source/games/duke/src/types.h b/source/games/duke/src/types.h index 2f6576cf9..a9db46d18 100644 --- a/source/games/duke/src/types.h +++ b/source/games/duke/src/types.h @@ -22,6 +22,20 @@ struct STATUSBARTYPE bool gotweapon[MAX_WEAPONS]; }; +struct ActorAction +{ + FName qualifiedName; // this is only used for serialization. + FName name; + FTextureID base; + int offset; + int16_t numframes; + int16_t rotationtype; + int16_t increment; + int16_t delay; +}; + +inline TArray actions; + struct ActorInfo { uint32_t scriptaddress; @@ -68,6 +82,7 @@ public: sectortype* temp_sect, *actorstayput; DAngle temp_angle; DVector3 temp_pos, temp_pos2; + ActorAction* curAction; TObjPtr temp_actor, seek_actor;