- 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.
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)

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)
{
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;

View file

@ -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;

View file

@ -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++)
{
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);
}
for (k = j; k < 5; k++)
{
appendscriptvalue(0);
}
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;

View file

@ -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++;

View file

@ -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);
}

View file

@ -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)

View file

@ -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<ActorAction> 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<DDukeActor*> temp_actor, seek_actor;