- cleaned up Duke's very broken kill count system.

This now uses a static flag to denote an actor as countable and an internal flag to track its killed state, because CON can toggle that at will.
This commit is contained in:
Christoph Oelckers 2023-04-07 09:46:51 +02:00
parent d7224245e3
commit 7a699e032f
14 changed files with 66 additions and 53 deletions

View file

@ -188,6 +188,7 @@ enum ESpriteBits2
CSTAT2_SPRITE_FULLBRIGHT = 16, // always draw fullbright with shade -127
CSTAT2_SPRITE_NOANIMATE = 32, // disable texture animation
CSTAT2_SPRITE_NOMODEL = 64, // disable models and voxels for this tsprite
CSTAT2_SPRITE_COUNTKILL = 128 // internal tracking of SFLAG_KILLCOUNT, thanks to non-existent automation in Duke.
};
// tsprite flags use the otherwise unused clipdist field.
@ -198,7 +199,7 @@ enum ETSprFlags
TSPR_MDLROTATE = 4, // rotate if this is a model or voxel.
TSPR_SLOPESPRITE = 8, // render as sloped sprite
TSPR_ROTATE8FRAMES = 16, // do an 8 frame rotation
TSPR_ROTATE12FRAMES = 32, // do an 12 frame rotation
TSPR_ROTATE12FRAMES = 32, // do a 12 frame rotation
TSPR_NOFLOORPAL = 64, // ignore the floorpal
};

View file

@ -51,7 +51,9 @@ void initactorflags_d()
gs.actorinfo[DTILE_OCTABRAIN].falladjustz = gs.actorinfo[DTILE_COMMANDER].falladjustz = gs.actorinfo[DTILE_DRONE].falladjustz = 0;
setflag(SFLAG_INTERNAL_BADGUY, {
DTILE_SHARK,
DTILE_SHARK });
setflag(SFLAG_INTERNAL_BADGUY | SFLAG_KILLCOUNT, {
DTILE_RECON,
DTILE_DRONE,
DTILE_LIZTROOPONTOILET,
@ -178,8 +180,8 @@ void initactorflags_d()
if (isWorldTour())
{
setflag(SFLAG_INTERNAL_BADGUY, { DTILE_FIREFLY });
setflag(SFLAG_INTERNAL_BADGUY|SFLAG_NODAMAGEPUSH|SFLAG_BOSS, { DTILE_BOSS5 });
setflag(SFLAG_INTERNAL_BADGUY | SFLAG_KILLCOUNT, { DTILE_FIREFLY });
setflag(SFLAG_INTERNAL_BADGUY | SFLAG_KILLCOUNT |SFLAG_NODAMAGEPUSH|SFLAG_BOSS, { DTILE_BOSS5 });
setflag(SFLAG3_FORCERUNCON, { DTILE_LAVAPOOL, DTILE_ONFIRE, DTILE_ONFIRESMOKE, DTILE_BURNEDCORPSE, DTILE_LAVAPOOLBUBBLE, DTILE_WHISPYSMOKE, DTILE_FIREFLYFLYINGEFFECT });
}

View file

@ -1204,10 +1204,10 @@ int ConCompiler::parsecommand()
if (tw == concmd_useractor)
{
if (j & 1)
gs.actorinfo[lnum].flags |= SFLAG_BADGUY;
gs.actorinfo[lnum].flags |= SFLAG_BADGUY | SFLAG_KILLCOUNT;
if (j & 2)
gs.actorinfo[lnum].flags |= (SFLAG_BADGUY | SFLAG_BADGUYSTAYPUT);
gs.actorinfo[lnum].flags |= (SFLAG_BADGUY | SFLAG_KILLCOUNT | SFLAG_BADGUYSTAYPUT);
}
for (j = 0; j < 4; j++)

View file

@ -913,16 +913,6 @@ void DoPlayer(bool bSet, int lVar1, int lLabelID, int lVar2, DDukeActor* sActor,
else SetGameVarID(lVar2, ps[iPlayer].secret_rooms, sActor, sPlayer);
break;
case PLAYER_MAX_ACTORS_KILLED:
if (bSet) ps[iPlayer].max_actors_killed = lValue;
else SetGameVarID(lVar2, ps[iPlayer].max_actors_killed, sActor, sPlayer);
break;
case PLAYER_ACTORS_KILLED:
if (bSet) ps[iPlayer].actors_killed = lValue;
else SetGameVarID(lVar2, ps[iPlayer].actors_killed, sActor, sPlayer);
break;
case PLAYER_RETURN_TO_CENTER:
if (bSet) ps[iPlayer].sync.actions |= SB_CENTERVIEW;
else SetGameVarID(lVar2, ps[iPlayer].sync.actions & SB_CENTERVIEW ? int(abs((ps[iPlayer].GetActor()->spr.Angles.Pitch * (DAngle::fromDeg(9.) / GetMaxPitch())).Degrees())) : 0, sActor, sPlayer);
@ -1700,12 +1690,6 @@ int ParseState::parse(void)
g_ac->spr.pal = ps[g_ac->PlayerIndex()].palookup;
else
{
// Copied from DukeGDX.
if (g_ac->spr.picnum == TILE_EGG && g_ac->temp_data[5] == TILE_EGG + 2 && g_ac->spr.pal == 1)
{
ps[connecthead].max_actors_killed++; //revive the egg
g_ac->temp_data[5] = 0;
}
g_ac->spr.pal = (uint8_t)g_ac->tempval;
}
g_ac->tempval = 0;
@ -1902,15 +1886,11 @@ int ParseState::parse(void)
break;
case concmd_addkills:
insptr++;
if (isRR())
if (g_ac->spriteextra < 1 || g_ac->spriteextra == 128 || !isRR())
{
if (g_ac->spriteextra < 1 || g_ac->spriteextra == 128)
{
if (actorfella(g_ac))
ps[g_p].actors_killed += *insptr;
}
if (*insptr) addkill(g_ac);
else if (*insptr < 0) subkill(g_ac);
}
else ps[g_p].actors_killed += *insptr;
g_ac->actorstayput = nullptr;
insptr++;
break;
@ -3744,8 +3724,7 @@ bool execute(DDukeActor *actor,int p,double xx)
// this must go away.
if(!actor->insector())
{
if(badguy(actor))
ps[p].actors_killed++;
addkill(actor);
actor->Destroy();
return true;
}

View file

@ -86,11 +86,6 @@ inline int attackerflag(DDukeActor* actor, EDukeFlags2 mask)
return (((gs.actorinfo[actor->attackertype].flags2) & mask) != 0);
}
inline int actorfella(DDukeActor* actor)
{
return actorflag(actor, SFLAG_KILLCOUNT);
}
inline void setflag(EDukeFlags1 flag, const std::initializer_list<short>& types)
{
for (auto val : types)
@ -363,4 +358,33 @@ inline void setPlayerActorViewZOffset(DDukeActor* const pact)
}
}
// flag mess to avoid double counting of kills.
// this is still not foolproof because CON requires manually recording the kills.
inline void addtokills(DDukeActor* actor)
{
if (actorflag(actor, SFLAG_KILLCOUNT))
{
ps[myconnectindex].max_actors_killed++;
actor->spr.cstat2 |= CSTAT2_SPRITE_COUNTKILL;
}
}
inline void addkill(DDukeActor* actor)
{
if (actorflag(actor, SFLAG_KILLCOUNT) && (actor->spr.cstat2 & CSTAT2_SPRITE_COUNTKILL))
{
ps[myconnectindex].actors_killed++;
actor->spr.cstat2 &= ~CSTAT2_SPRITE_COUNTKILL;
}
}
inline void subkill(DDukeActor* actor)
{
if (actorflag(actor, SFLAG_KILLCOUNT) && !(actor->spr.cstat2 & CSTAT2_SPRITE_COUNTKILL))
{
ps[myconnectindex].actors_killed--;
actor->spr.cstat2 |= CSTAT2_SPRITE_COUNTKILL;
}
}
END_DUKE_NS

View file

@ -408,7 +408,7 @@ void dokneeattack(int snum)
else if (badguy(p->actorsqu))
{
p->actorsqu->Destroy();
p->actors_killed++;
addkill(p->actorsqu);
}
else p->actorsqu->Destroy();
}

View file

@ -325,8 +325,7 @@ bool commonEnemySetup(DDukeActor* self, DDukeActor* owner)
self->spr.cstat |= CSTAT_SPRITE_BLOCK_ALL;
if (!isRR() && actorflag(self, SFLAG_KILLCOUNT))
ps[myconnectindex].max_actors_killed++;
addtokills(self);
self->timetosleep = 0;
if (!self->mapSpawned)

View file

@ -106,7 +106,6 @@ DDukeActor* spawninit_d(DDukeActor* actj, DDukeActor* act, TArray<DDukeActor*>*
makeitfall(act);
act->spr.cstat |= CSTAT_SPRITE_BLOCK_ALL;
ps[connecthead].max_actors_killed++;
if (actj) {
act->timetosleep = 0;
@ -271,8 +270,6 @@ DDukeActor* spawninit_d(DDukeActor* actj, DDukeActor* act, TArray<DDukeActor*>*
makeitfall(act);
act->spr.cstat |= CSTAT_SPRITE_BLOCK_ALL;
if (act->spr.picnum != DTILE_SHARK)
ps[myconnectindex].max_actors_killed++;
if (act->spr.picnum == DTILE_ORGANTIC) act->spr.cstat |= CSTAT_SPRITE_YCENTER;
@ -413,7 +410,6 @@ DDukeActor* spawninit_d(DDukeActor* actj, DDukeActor* act, TArray<DDukeActor*>*
if (act->spr.picnum == DTILE_EGG)
{
act->clipdist = 6;
ps[connecthead].max_actors_killed++;
}
act->spr.cstat = CSTAT_SPRITE_BLOCK_ALL | randomXFlip();
ChangeActorStat(act, STAT_ZOMBIEACTOR);

View file

@ -357,9 +357,6 @@ DDukeActor* spawninit_r(DDukeActor* actj, DDukeActor* act, TArray<DDukeActor*>*
act->spr.cstat |= CSTAT_SPRITE_BLOCK_ALL;
if (actorfella(act))
ps[myconnectindex].max_actors_killed++;
if (actj)
{
act->timetosleep = 0;

View file

@ -681,6 +681,21 @@ DEFINE_ACTION_FUNCTION_NATIVE(DDukeActor, restoreloc, DukeActor_restoreloc)
return 0;
}
DEFINE_ACTION_FUNCTION_NATIVE(DDukeActor, addkill, addkill)
{
PARAM_SELF_PROLOGUE(DDukeActor);
addkill(self);
return 0;
}
DEFINE_ACTION_FUNCTION_NATIVE(DDukeActor, subkill, subkill)
{
PARAM_SELF_PROLOGUE(DDukeActor);
subkill(self);
return 0;
}
// temporary helpers to hide the fact that these flags are not part of the actor yet.
DEFINE_ACTION_FUNCTION(DDukeActor, actorflag1)
{
@ -837,8 +852,6 @@ DEFINE_FIELD_X(DukePlayer, player_struct, palookup)
DEFINE_FIELD_X(DukePlayer, player_struct, quick_kick_msg)
DEFINE_FIELD_X(DukePlayer, player_struct, max_secret_rooms)
DEFINE_FIELD_X(DukePlayer, player_struct, secret_rooms)
DEFINE_FIELD_X(DukePlayer, player_struct, max_actors_killed)
DEFINE_FIELD_X(DukePlayer, player_struct, actors_killed)
DEFINE_FIELD_X(DukePlayer, player_struct, stairs)
DEFINE_FIELD_X(DukePlayer, player_struct, detonate_count)
//DEFINE_FIELD_X(DukePlayer, player_struct, noise.X)

View file

@ -77,7 +77,7 @@ class DukeGreenSlime : DukeActor
let k = dlevel.SpawnActor(self.sector, self.pos, pieces[j % 3], -32, (0.5625, 0.5625), a, vel, zvel, self, STAT_MISC);
if (k) k.pal = 1;
}
p.actors_killed++;
self.addkill();
self.PlayActorSound("GLASS_BREAKING");
self.Destroy();
}
@ -131,7 +131,7 @@ class DukeGreenSlime : DukeActor
let spawned = self.spawn("DukeBloodPool");
if (spawned) spawned.pal = 0;
}
p.actors_killed++;
self.addkill();
self.temp_data[0] = -3;
if (p.somethingonplayer == self)
p.somethingonplayer = nullptr;
@ -217,7 +217,7 @@ class DukeGreenSlime : DukeActor
self.temp_data[0] = -5; self.temp_data[3] = 0;
return;
}
p.actors_killed++;
self.addkill();
if (random(0, 255) < 32)
{

View file

@ -66,7 +66,7 @@ class DukeRecon : DukeActor
self.RANDOMSCRAP();
self.PlayActorSound("LASERTRIP_EXPLODE");
let spawned = self.spawn(spawntype);
Duke.GetLocalPlayer().actors_killed++;
self.addkill();
self.Destroy();
}
return;

View file

@ -240,6 +240,8 @@ class DukeActor : CoreActor native
native void insertspriteq();
native void operateforcefields(int tag);
native void restoreloc();
native void addkill();
native void subkill();
// temporary flag accessors - need to be eliminated once we can have true actor flags

View file

@ -302,7 +302,7 @@ struct DukePlayer native
native uint8 walking_snd_toggle, palookup;
native bool quick_kick_msg;
native int max_secret_rooms, secret_rooms, max_actors_killed, actors_killed;
native int max_secret_rooms, secret_rooms;
// Redneck Rampage additions. Those which did not have names in the reconstructed source got one from either RedneckGDX or RedNukem.
// Items were reordered by size.