- moved actions out of the ScriptCode array and gave them a dedicated struct with meaningful member names.

This commit is contained in:
Christoph Oelckers 2022-12-21 13:20:14 +01:00
parent 94b676bd7c
commit 30ccbe2710
8 changed files with 76 additions and 28 deletions

View file

@ -82,13 +82,12 @@ void TickActor(DDukeActor* self)
} }
// Run sprite animations. // Run sprite animations.
if (self->temp_data[4]) if (self->curAction->name != NAME_None)
{ {
// This code was utterly cryptic in the original source. // This code was utterly cryptic in the original source.
auto ptr = &ScriptCode[self->temp_data[4]]; int numframes = self->curAction->numframes;
int numframes = ptr[1]; int increment = self->curAction->increment;
int increment = ptr[3]; int delay = self->curAction->delay;
int delay = ptr[4];
self->spr.lotag += TICSPERFRAME; self->spr.lotag += TICSPERFRAME;
if (self->spr.lotag > delay) if (self->spr.lotag > delay)

View file

@ -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) if (gs.actorinfo[h->spr.picnum].scriptaddress && !(h->flags2 & SFLAG2_DONTANIMATE))// && (t->cstat & CSTAT_SPRITE_ALIGNMENT_MASK) != CSTAT_SPRITE_ALIGNMENT_SLAB)
{ {
DAngle kang; DAngle kang;
int t4 = h->temp_data[4]; auto action = h->curAction;
int k = 0, l = 0; 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)) if (tilehasmodelorvoxel(h->spr.spritetexture(), h->spr.pal))
{ {
@ -168,7 +168,7 @@ void applyanimations(tspritetype* t, DDukeActor* h, const DVector2& viewVec, DAn
if (isRR()) if (isRR())
{ {
bool bg = badguy(h); 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(); kang = (t->pos.XY() - viewVec).Angle();
k = angletorotation1(t->Angles.Yaw, kang); 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; t->picnum += k;
if (isRRRA() && RRRAFullbrightHack(t, k)) t->shade = -127; if (isRRRA() && RRRAFullbrightHack(t, k)) t->shade = -127;

View file

@ -381,6 +381,7 @@ void GameInterface::app_init()
ud.m_monsters_off = userConfig.nomonsters; ud.m_monsters_off = userConfig.nomonsters;
ps[0].aim_mode = 1; ps[0].aim_mode = 1;
ud.cameraactor = nullptr; ud.cameraactor = nullptr;
actions.Push({}); // make sure the first entry in 'actions' is a null action.
if (fileSystem.FileExists("DUKESW.BIN")) if (fileSystem.FileExists("DUKESW.BIN"))
g_gameType |= GAMEFLAG_SHAREWARE; g_gameType |= GAMEFLAG_SHAREWARE;

View file

@ -1155,19 +1155,31 @@ int ConCompiler::parsecommand()
if (lnum >= 0) if (lnum >= 0)
{ {
warningcount++; 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++) ActorAction& action = actions[actions.Reserve(1)];
{
if (keyword() >= 0) break; memset(&action, 0, sizeof(action));
transnum(LABEL_DEFINE); action.qualifiedName = FStringf("$con$.%s", parselabel.GetChars());
} action.name = parselabel.GetChars();
for (k = j; k < 5; k++) action.base.SetNull(); // CON actions are relative to base pic.
{ if (keyword() >= 0) break;
appendscriptvalue(0); 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; return 0;

View file

@ -1508,7 +1508,7 @@ int ParseState::parse(void)
insptr++; insptr++;
// HACK ALERT! The fire animation uses a broken ifrnd setup to delay its start because original CON has no variables // 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.) // 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)); parseifelse(rnd(64));
break; break;
@ -1554,7 +1554,7 @@ int ParseState::parse(void)
case concmd_ai: case concmd_ai:
insptr++; insptr++;
g_t[5] = *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_t[1] = ScriptCode[g_t[5] + 1]; // move
g_ac->spr.hitag = ScriptCode[g_t[5] + 2]; // Ai g_ac->spr.hitag = ScriptCode[g_t[5] + 2]; // Ai
g_t[0] = g_t[2] = g_t[3] = 0; g_t[0] = g_t[2] = g_t[3] = 0;
@ -1566,7 +1566,7 @@ int ParseState::parse(void)
insptr++; insptr++;
g_t[2] = 0; g_t[2] = 0;
g_t[3] = 0; g_t[3] = 0;
g_t[4] = *insptr; g_ac->curAction = &actions[*insptr];
insptr++; insptr++;
break; break;
@ -1912,7 +1912,7 @@ int ParseState::parse(void)
break; break;
case concmd_ifaction: case concmd_ifaction:
insptr++; insptr++;
parseifelse(g_t[4] == *insptr); parseifelse((g_ac->curAction - actions.Data()) == *insptr);
break; break;
case concmd_ifactioncount: case concmd_ifactioncount:
insptr++; insptr++;

View file

@ -47,6 +47,24 @@ FSerializer& Serialize(FSerializer& arc, const char* keyname, GameVarValue& w, G
void lava_serialize(FSerializer& arc); void lava_serialize(FSerializer& arc);
void SerializeGameVars(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) FSerializer& Serialize(FSerializer& arc, const char* keyname, animwalltype& w, animwalltype* def)
{ {
if (arc.BeginObject(keyname)) if (arc.BeginObject(keyname))
@ -288,7 +306,8 @@ void DDukeActor::Serialize(FSerializer& arc)
("uservars", uservars) ("uservars", uservars)
("flags1", flags1) ("flags1", flags1)
("flags2", flags2) ("flags2", flags2)
("flags3", flags3); ("flags3", flags3)
("curaction", curAction);
} }

View file

@ -45,6 +45,7 @@ BEGIN_DUKE_NS
void setFromSpawnRec(DDukeActor* act, SpawnRec* info) void setFromSpawnRec(DDukeActor* act, SpawnRec* info)
{ {
act->curAction = &actions[0];
if (info) if (info)
{ {
if (info->basetex > 0 && act->IsKindOf(NAME_DukeGenericDestructible)) if (info->basetex > 0 && act->IsKindOf(NAME_DukeGenericDestructible))
@ -59,6 +60,7 @@ void setFromSpawnRec(DDukeActor* act, SpawnRec* info)
} }
else else
{ {
// same for simple sprite replacements with existing implementations.
if (info->basetex >= 0 && info->basetex < MAXTILES) act->spr.picnum = info->basetex; if (info->basetex >= 0 && info->basetex < MAXTILES) act->spr.picnum = info->basetex;
if (info->fullbright & 1) act->spr.cstat2 |= CSTAT2_SPRITE_FULLBRIGHT; 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]; auto sa = &ScriptCode[gs.actorinfo[s_pn].scriptaddress];
act->spr.extra = sa[0]; act->spr.extra = sa[0];
act->temp_data[4] = sa[1]; act->curAction = &actions[sa[1]];
act->temp_data[1] = sa[2]; act->temp_data[1] = sa[2];
act->spr.hitag = sa[3]; act->spr.hitag = sa[3];
} }
@ -246,7 +248,7 @@ bool initspriteforspawn(DDukeActor* act)
if (gs.actorinfo[s].scriptaddress) if (gs.actorinfo[s].scriptaddress)
{ {
act->spr.extra = ScriptCode[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]; act->temp_data[1] = ScriptCode[gs.actorinfo[s].scriptaddress+2];
int s3 = ScriptCode[gs.actorinfo[s].scriptaddress+3]; int s3 = ScriptCode[gs.actorinfo[s].scriptaddress+3];
if (s3 && act->spr.hitag == 0) if (s3 && act->spr.hitag == 0)

View file

@ -22,6 +22,20 @@ struct STATUSBARTYPE
bool gotweapon[MAX_WEAPONS]; 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<ActorAction> actions;
struct ActorInfo struct ActorInfo
{ {
uint32_t scriptaddress; uint32_t scriptaddress;
@ -68,6 +82,7 @@ public:
sectortype* temp_sect, *actorstayput; sectortype* temp_sect, *actorstayput;
DAngle temp_angle; DAngle temp_angle;
DVector3 temp_pos, temp_pos2; DVector3 temp_pos, temp_pos2;
ActorAction* curAction;
TObjPtr<DDukeActor*> temp_actor, seek_actor; TObjPtr<DDukeActor*> temp_actor, seek_actor;