Merge remote-tracking branch 'upstream/master'

This commit is contained in:
Simon 2023-01-29 19:18:17 +00:00
commit 159c316ebb
36 changed files with 426 additions and 477 deletions

View file

@ -91,7 +91,7 @@ void initSkyInfo(HWDrawInfo *di, HWSkyInfo* sky, sectortype* sector, int plane)
pe.a = 230;
sky->fadecolor = pe;
sky->shade = clamp<int>(plane == plane_ceiling ? sector->ceilingshade : sector->floorshade, 0, numshades - 1);
sky->shade = 0;// clamp(plane == plane_ceiling ? sector->ceilingshade : sector->floorshade, 0, numshades - 1);
sky->texture = skytex;
}

View file

@ -822,6 +822,7 @@ DEFINE_FIELD_NAMED(DCoreActor, spr.Angles.Yaw, angle)
DEFINE_FIELD_NAMED(DCoreActor, spr.Angles.Pitch, pitch)
DEFINE_FIELD(DCoreActor, vel)
DEFINE_FIELD(DCoreActor, viewzoffset)
DEFINE_FIELD(DCoreActor, oviewzoffset)
DEFINE_FIELD(DCoreActor, opos)
void coreactor_setpos(DCoreActor* self, double x, double y, double z, int relink)

View file

@ -96,7 +96,7 @@ void cerberusBurnSeqCallback(int, DBloodActor* actor)
if (nDist == 0 || nDist > 0x280)
continue;
pos += actor2->vel * nDist * (65536. / 0x1aaaaa);
pos2 += actor->vel * nDist * (65536. / 0x1aaaaa);
DVector3 tvec = pos;
tvec.XY() += actor->spr.Angles.Yaw.ToVector() * nDist;
@ -161,7 +161,7 @@ void cerberusBurnSeqCallback2(int, DBloodActor* actor)
if (nDist == 0 || nDist > 0x280)
continue;
pos += actor2->vel * nDist * (65536. / 0x1aaaaa);
pos2 += actor->vel * nDist * (65536. / 0x1aaaaa);
DVector3 tvec = pos;
tvec.XY() += actor->spr.Angles.Yaw.ToVector() * nDist;

View file

@ -121,7 +121,7 @@ void BlastSSeqCallback(int, DBloodActor* actor)
if (nDist == 0 || nDist > 0x280)
continue;
pos += actor2->vel * nDist * (65536. / 0x1aaaaa);
pos2 += actor->vel * nDist * (65536. / 0x1aaaaa);
DVector3 tvec = pos;
tvec.XY() += actor->spr.Angles.Yaw.ToVector() * nDist;

View file

@ -108,7 +108,7 @@ void ghostBlastSeqCallback(int, DBloodActor* actor)
if (nDist == 0 || nDist > 0x280)
continue;
pos += actor2->vel * nDist * (65536. / 0x1aaaaa);
pos2 += actor->vel * nDist * (65536. / 0x1aaaaa);
DVector3 tvec = pos;
tvec.XY() += actor->spr.Angles.Yaw.ToVector() * nDist;

View file

@ -79,7 +79,7 @@ void tchernobogBurnSeqCallback(int, DBloodActor* actor)
if (nDist == 0 || nDist > 0x280)
continue;
pos += actor2->vel * nDist * (65536. / 0x1aaaaa);
pos2 += actor->vel * nDist * (65536. / 0x1aaaaa);
DVector3 tvec = pos;
tvec.XY() += actor->spr.Angles.Yaw.ToVector() * nDist;
@ -135,7 +135,7 @@ void tchernobogBurnSeqCallback2(int, DBloodActor* actor)
if (nDist == 0 || nDist > 0x280)
continue;
pos += actor2->vel * nDist * (65536. / 0x1aaaaa);
pos2 += actor->vel * nDist * (65536. / 0x1aaaaa);
DVector3 tvec = pos;
tvec.XY() += actor->spr.Angles.Yaw.ToVector() * nDist;

View file

@ -800,7 +800,6 @@ void nnExtInitModernStuff(TArray<DBloodActor*>& actors)
{
if (iactor->xspr.busyTime <= 0 || iactor->xspr.isTriggered) continue;
int count = 0;
TRCONDITION* pCond = &gConditions[gConditions.Reserve(1)];
for (auto iactor2 : actors)
@ -818,18 +817,18 @@ void nnExtInitModernStuff(TArray<DBloodActor*>& actors)
if (iactor2->spr.type == kModernCondition || iactor2->spr.type == kModernConditionFalse)
condError(iactor, "Tracking condition always must be first in condition sequence!");
pCond->objects.Reserve(2);
pCond->objects[count].obj = EventObject(iactor2);
pCond->objects[count++].cmd = (uint8_t)iactor2->xspr.command;
pCond->objects.Reserve(1);
pCond->objects.Last().obj = EventObject(iactor2);
pCond->objects.Last().cmd = (uint8_t)iactor2->xspr.command;
}
for (auto& sect : sector)
{
if (!sect.hasX() || sect.xs().txID != iactor->xspr.rxID) continue;
pCond->objects.Reserve(2);
pCond->objects[count].obj = EventObject(&sect);
pCond->objects[count++].cmd = sect.xs().command;
pCond->objects.Reserve(1);
pCond->objects.Last().obj = EventObject(&sect);
pCond->objects.Last().cmd = sect.xs().command;
}
for (auto& wal : wall)
@ -843,12 +842,12 @@ void nnExtInitModernStuff(TArray<DBloodActor*>& actors)
continue;
}
pCond->objects.Reserve(2);
pCond->objects[count].obj = EventObject(&wal);
pCond->objects[count++].cmd = wal.xw().command;
pCond->objects.Reserve(1);
pCond->objects.Last().obj = EventObject(&wal);
pCond->objects.Last().cmd = wal.xw().command;
}
if (iactor->xspr.data1 > kCondGameMax && count == 0)
if (iactor->xspr.data1 > kCondGameMax && pCond->objects.Size() == 0)
Printf(PRINT_HIGH, "No objects to track found for condition #%d, RXID: %d!", iactor->GetIndex(), iactor->xspr.rxID);
pCond->actor = iactor;

View file

@ -239,12 +239,12 @@ struct TRPLAYERCTRL { // this one for controlling the player using triggers (mov
};
struct OBJECTS_TO_TRACK {
uint8_t cmd;
EventObject obj;
uint8_t cmd = 0;
EventObject obj = EventObject(nullptr);
};
struct TRCONDITION {
DBloodActor* actor;
DBloodActor* actor = nullptr;
TArray<OBJECTS_TO_TRACK> objects;
};

View file

@ -1452,7 +1452,7 @@ int ActionScan(PLAYER* pPlayer, HitInfo* out)
int nMass = getDudeInfo(hitactor->spr.type)->mass;
if (nMass)
{
hitactor->spr.pos += pos * (FixedToFloat<8>(0xccccc) / nMass);
hitactor->vel += pos * (FixedToFloat<10>(0xccccc) / nMass);
}
if (hitactor->xspr.Push && !hitactor->xspr.state && !hitactor->xspr.isTriggered)
trTriggerSprite(hitactor, kCmdSpritePush);

View file

@ -577,9 +577,11 @@ void tickstat(int stat, bool deleteinvalid)
if (actorflag(act, SFLAG2_DIENOW) || act->sector() == nullptr || (deleteinvalid && act->spr.scale.X == 0))
{
act->Destroy();
continue;
}
CallTick(act);
else if (stat != STAT_ACTOR || !badguy(act) || !monsterCheatCheck(act))
{
CallTick(act);
}
}
}
@ -2964,6 +2966,8 @@ void getglobalz(DDukeActor* actor)
void makeitfall(DDukeActor* actor)
{
if (actorflag(actor, SFLAG3_NOGRAVITY)) return;
double grav;
if( floorspace(actor->sector()) )
@ -2993,7 +2997,7 @@ void makeitfall(DDukeActor* actor)
if( actor->spr.pos.Z < actor->floorz - FOURSLEIGHT_F)
{
if( actor->sector()->lotag == 2 && actor->vel.Z > 3122/256.)
if( actor->sector()->lotag == ST_2_UNDERWATER && actor->vel.Z > 3122/256.)
actor->vel.Z = 3144 / 256.;
if (actor->vel.Z < 24)
actor->vel.Z += grav;

View file

@ -991,201 +991,6 @@ void movetransports_d(void)
//
//---------------------------------------------------------------------------
static void flamethrowerflame(DDukeActor *actor)
{
auto sectp = actor->sector();
double xx;
int p = findplayer(actor, &xx);
execute(actor, p, xx);
if (actor->ObjectFlags & OF_EuthanizeMe) return; // killed by script.
actor->temp_data[0]++;
if (sectp->lotag == 2)
{
spawn(actor, DTILE_EXPLOSION2)->spr.shade = 127;
actor->Destroy();
return;
}
auto dapos = actor->spr.pos;
getglobalz(actor);
int ds = actor->temp_data[0] / 6;
if (actor->spr.scale.X < 0.1250)
{
actor->spr.scale.X += (ds * REPEAT_SCALE);
actor->spr.scale.Y = (actor->spr.scale.X);
}
actor->clipdist += ds * 0.25;
if (actor->temp_data[0] <= 2)
actor->temp_data[3] = krand() % 10;
if (actor->temp_data[0] > 30)
{
spawn(actor, DTILE_EXPLOSION2)->spr.shade = 127;
actor->Destroy();
return;
}
Collision coll;
movesprite_ex(actor, DVector3(actor->spr.Angles.Yaw.ToVector() * actor->vel.X, actor->vel.Z), CLIPMASK1, coll);
if (!actor->insector())
{
actor->Destroy();
return;
}
if (coll.type != kHitSprite)
{
if (actor->spr.pos.Z < actor->ceilingz)
{
coll.setSector(actor->sector());
actor->vel.Z -= 1/256.;
}
else if ((actor->spr.pos.Z > actor->floorz && actor->sector()->lotag != 1)
|| (actor->spr.pos.Z > actor->floorz + 16 && actor->sector()->lotag == 1))
{
coll.setSector(actor->sector());
if (actor->sector()->lotag != 1)
actor->vel.Z += 1/256.;
}
}
if (coll.type != 0) {
actor->vel.XY().Zero();
actor->vel.Z = 0;
if (coll.type == kHitSprite)
{
fi.checkhitsprite(coll.actor(), actor);
if (coll.actor()->isPlayer())
S_PlayActorSound(PISTOL_BODYHIT, coll.actor());
}
else if (coll.type == kHitWall)
{
SetActor(actor, dapos);
checkhitwall(actor, coll.hitWall, actor->spr.pos);
}
else if (coll.type == kHitSector)
{
SetActor(actor, dapos);
if (actor->vel.Z < 0)
checkhitceiling(actor->sector());
}
if (actor->spr.scale.X >= 0.15625)
{
int x = actor->spr.extra;
fi.hitradius(actor, gs.rpgblastradius, x >> 2, x >> 1, x - (x >> 2), x);
}
else
{
int x = actor->spr.extra + (global_random & 3);
fi.hitradius(actor, (gs.rpgblastradius >> 1), x >> 2, x >> 1, x - (x >> 2), x);
}
}
}
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
void moveactors_d(void)
{
DukeStatIterator it(STAT_ACTOR);
while (auto act = it.Next())
{
if (act->spr.scale.X == 0 || act->spr.sectp == nullptr || actorflag(act, SFLAG2_DIENOW))
{
act->Destroy();
}
else if (monsterCheatCheck(act) && badguy(act))
{
continue;
}
else if (isWorldTour() && act->spr.picnum == DTILE_FLAMETHROWERFLAME)
{
flamethrowerflame(act);
}
else
{
CallTick(act);
}
}
}
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
static void fireflyflyingeffect(DDukeActor *actor)
{
double xx;
int p = findplayer(actor, &xx);
execute(actor, p, xx);
if (actor->ObjectFlags & OF_EuthanizeMe) return; // killed by script.
auto Owner = actor->GetOwner();
if (!Owner || Owner->spr.picnum != DTILE_FIREFLY)
{
actor->Destroy();
return;
}
if (Owner->spr.scale.X >= 0.375 || Owner->spr.pal == 1)
actor->spr.cstat |= CSTAT_SPRITE_INVISIBLE;
else
actor->spr.cstat &= ~CSTAT_SPRITE_INVISIBLE;
auto dvec = Owner->spr.pos.XY() - ps[p].GetActor()->spr.pos.XY();
double dist = dvec.Length();
if (dist != 0.0) dvec /= dist;
actor->spr.pos = Owner->spr.pos + DVector3(dvec.X * -0.625, dvec.Y * -0.625, 8);
if (Owner->spr.extra <= 0)
{
actor->Destroy();
}
}
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
void moveexplosions_d(void) // STATNUM 5
{
DukeStatIterator it(STAT_MISC);
while (auto act = it.Next())
{
if (act->spr.scale.X == 0 || act->spr.sectp == nullptr || actorflag(act, SFLAG2_DIENOW))
{
act->Destroy();
}
else if (isWorldTour() && act->spr.picnum == DTILE_FIREFLYFLYINGEFFECT)
{
fireflyflyingeffect(act);
}
else
{
CallTick(act);
}
}
}
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
void handle_se06_d(DDukeActor* actor)
{
auto sc = actor->sector();
@ -1741,11 +1546,11 @@ void think_d(void)
tickstat(STAT_PROJECTILE); //ST 4
moveplayers(); //ST 10
movefallers_d(); //ST 12
moveexplosions_d(); //ST 5
tickstat(STAT_MISC, true); //ST 5
actortime.Reset();
actortime.Clock();
moveactors_d(); //ST 1
tickstat(STAT_ACTOR); //ST 1
actortime.Unclock();
moveeffectors_d(); //ST 3

View file

@ -1018,10 +1018,6 @@ static void rrra_specialstats()
void moveactors_r(void)
{
double xx;
int p;
Collision coll;
dojaildoor();
moveminecart();
@ -1033,46 +1029,7 @@ void moveactors_r(void)
if (ud.chickenplant) tickstat(STAT_CHICKENPLANT);
tickstat(STAT_BOWLING);
tickstat(STAT_TELEPORT);
DukeStatIterator it(STAT_ACTOR);
while (auto act = it.Next())
{
if( act->spr.scale.X == 0 || !act->insector() || actorflag(act, SFLAG2_DIENOW))
{
act->Destroy();
continue;
}
if (monsterCheatCheck(act) && badguy(act))
{
continue;
}
auto sectp = act->sector();
if (act->GetClass() != RUNTIME_CLASS(DDukeActor))
{
CallTick(act);
continue;
}
else switch(act->spr.picnum)
{
case RTILE_POWDERKEG:
if (!isRRRA() || (sectp->lotag != ST_1_ABOVE_WATER && sectp->lotag != ST_160_FLOOR_TELEPORT))
if (act->vel.X != 0)
{
movesprite_ex(act, DVector3(act->spr.Angles.Yaw.ToVector()* act->vel.X, act->vel.Z), CLIPMASK0, coll);
act->vel.X -= 1. / 16.;
}
break;
}
p = findplayer(act, &xx);
execute(act,p,xx);
}
tickstat(STAT_ACTOR);
}
//---------------------------------------------------------------------------

View file

@ -126,8 +126,6 @@ void animatesprites_r(tspriteArray& tsprites, const DVector2& viewVec, DAngle vi
if (h->spr.extra > 0)
t->pos.Z += 6;
break;
case RTILE_POWDERKEG:
continue;
case RTILE_BURNING:
if (OwnerAc && OwnerAc->spr.statnum == STAT_PLAYER)
{

View file

@ -404,6 +404,7 @@ enum sflags3_t
SFLAG3_BROWNBLOOD = 0x00000004,
SFLAG3_LIGHTDAMAGE = 0x00000008,
SFLAG3_FORCERUNCON = 0x00000010, // by default only STAT_ACTOR runs CON - this enables it for other statnums as well, provided they run Tick()
SFLAG3_NOGRAVITY = 0x00000020, // disables makeitfall.
};

View file

@ -40,6 +40,7 @@ BEGIN_DUKE_NS
void initactorflags_d()
{
setflag(SFLAG3_NOGRAVITY, { DTILE_RECON }); // not ported!!!
gs.actorinfo[DTILE_COMMANDER].gutsoffset = -24;

View file

@ -232,6 +232,7 @@ void initactorflags_r()
RTILE_SHITBALL,
RTILE_RPG,
RTILE_RECON,
RTILE_POWDERKEG
});
// Animals were not supposed to have this, but due to a coding bug the logic was unconditional for everything in the game.
for (auto& ainf : gs.actorinfo)

View file

@ -175,7 +175,7 @@ DDukeActor* spawninit_r(DDukeActor* actj, DDukeActor* act, TArray<DDukeActor*>*
void addspritetodelete(int spnum=0);
void checkavailinven(player_struct* p);
bool initspriteforspawn(DDukeActor* spn);
bool spawninitdefault(DDukeActor* actj, DDukeActor* act);
bool commonEnemySetup(DDukeActor* self, DDukeActor* owner);
void spawntransporter(DDukeActor* actj, DDukeActor* acti, bool beam);
int spawnbloodpoolpart1(DDukeActor* acti);
void initshell(DDukeActor* actj, DDukeActor* acti, bool isshell);

View file

@ -142,91 +142,6 @@ static void shootfireball(DDukeActor *actor, int p, DVector3 pos, DAngle ang)
//
//---------------------------------------------------------------------------
static void shootflamethrowerflame(DDukeActor* actor, int p, DVector3 spos, DAngle sang)
{
double vel, zvel = 0;
if (actor->spr.extra >= 0)
actor->spr.shade = -96;
vel = 25;
DDukeActor* spawned = nullptr;
if (p < 0)
{
double x;
int j = findplayer(actor, &x);
sang = (ps[j].GetActor()->opos.XY() - spos.XY()).Angle();
if (actor->spr.picnum == DTILE_BOSS5)
{
vel = 33;
spos.Z += 24;
}
else if (actor->spr.picnum == DTILE_BOSS3)
spos.Z -= 32;
double dist = (ps[j].GetActor()->spr.pos.XY() - actor->spr.pos.XY()).Length();
if (dist != 0)
zvel = (((ps[j].GetActor()->getPrevOffsetZ() - spos.Z) * vel) / dist);
if (badguy(actor) && (actor->spr.hitag & face_player_smart) != 0)
sang = actor->spr.Angles.Yaw + mapangle((krand() & 31) - 16);
if (actor->sector()->lotag == 2 && (krand() % 5) == 0)
spawned = spawn(actor, DTILE_WATERBUBBLE);
}
else
{
setFreeAimVelocity(vel, zvel, ps[p].Angles.getPitchWithView(), 40.5);
// WTF???
DAngle myang = DAngle90 - (DAngle180 - abs(abs((spos.XY() - ps[p].GetActor()->spr.pos.XY()).Angle() - sang) - DAngle180));
if (ps[p].GetActor()->vel.X != 0)
vel = ((myang / DAngle90) * ps[p].GetActor()->vel.X) + 25;
if (actor->sector()->lotag == 2 && (krand() % 5) == 0)
spawned = spawn(actor, DTILE_WATERBUBBLE);
}
if (spawned == nullptr)
{
spawned = spawn(actor, DTILE_FLAMETHROWERFLAME);
if (!spawned) return;
spawned->vel.X = vel;
spawned->vel.Z = zvel;
}
DVector3 offset;
offset.X = (sang + DAngle::fromBuild(118)).Cos() * (1024 / 448.); // Yes, these angles are really different!
offset.Y = (sang + DAngle::fromBuild(112)).Sin() * (1024 / 448.);
offset.Z = -1;
spawned->spr.pos = spos + offset;
spawned->spr.pos.Z--;
spawned->setsector(actor->sector());
spawned->spr.cstat = CSTAT_SPRITE_YCENTER;
spawned->spr.Angles.Yaw = sang;
spawned->spr.scale = DVector2(0.03125, 0.03125);
spawned->clipdist = 10;
spawned->spr.yint = p;
spawned->SetOwner(actor);
if (p == -1)
{
if (actor->spr.picnum == DTILE_BOSS5)
{
spawned->spr.pos += sang.ToVector() * (128. / 7);
spawned->spr.scale = DVector2(0.15625, 0.15625);
}
}
}
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
static void shootknee(DDukeActor* actor, int p, DVector3 pos, DAngle ang)
{
auto sectp = actor->sector();
@ -1105,10 +1020,6 @@ void shoot_d(DDukeActor* actor, int atwith, PClass *cls)
shootfireball(actor, p, spos, sang);
return;
case DTILE_FLAMETHROWERFLAME:
shootflamethrowerflame(actor, p, spos, sang);
return;
case DTILE_FIREFLY: // DTILE_BOSS5 shot
{
auto k = spawn(actor, atwith);

View file

@ -845,17 +845,6 @@ void shoot_r(DDukeActor* actor, int atwith, PClass* cls)
shootweapon(actor, p, spos, sang, atwith);
return;
case RTILE_POWDERKEG:
{
auto j = spawn(actor, atwith);
if (j)
{
j->vel.X = 2;
j->spr.Angles.Yaw = actor->spr.Angles.Yaw;
j->spr.pos.Z -= 5;
}
break;
}
case RTILE_OWHIP:
case RTILE_UWHIP:
shootwhip(actor, p, spos, sang, atwith);

View file

@ -298,63 +298,48 @@ DDukeActor* spawn(DDukeActor* actj, PClassActor * cls)
//
//---------------------------------------------------------------------------
bool spawninitdefault(DDukeActor* actj, DDukeActor *act)
bool commonEnemySetup(DDukeActor* self, DDukeActor* owner)
{
if (gs.actorinfo[act->spr.picnum].scriptaddress)
if (!self->mapSpawned) self->spr.lotag = 0;
// Init the size. This is different for internal and user enemies.
if (actorflag(self, SFLAG_INTERNAL_BADGUY))
{
if (actj == nullptr && act->spr.lotag > ud.player_skill)
{
// make it go away...
act->spr.scale = DVector2(0, 0);
ChangeActorStat(act, STAT_MISC);
return false;
}
// Init the size
if (act->spr.scale.X == 0 || act->spr.scale.Y == 0)
act->spr.scale = DVector2(REPEAT_SCALE, REPEAT_SCALE);
if (actorflag(act, SFLAG_BADGUY))
{
if (ud.monsters_off == 1)
{
act->spr.scale = DVector2(0, 0);
ChangeActorStat(act, STAT_MISC);
return false;
}
makeitfall(act);
if (actorflag(act, SFLAG_BADGUYSTAYPUT))
act->actorstayput = act->sector();
if (!isRR() || actorflag(act, SFLAG_KILLCOUNT)) // Duke is just like Doom - Bad guys always count as kill.
ps[myconnectindex].max_actors_killed++;
act->clipdist = 20;
if (actj)
{
if (isrespawncontroller(actj))
act->tempval = act->spr.pal = actj->spr.pal;
ChangeActorStat(act, STAT_ACTOR);
}
else ChangeActorStat(act, STAT_ZOMBIEACTOR);
}
else
{
act->clipdist = 10;
act->SetOwner(act);
ChangeActorStat(act, STAT_ACTOR);
}
act->timetosleep = 0;
if (actj)
act->spr.Angles.Yaw = actj->spr.Angles.Yaw;
self->spr.scale = DVector2(0.625, 0.625);
}
else if (self->spr.scale.X == 0 || self->spr.scale.Y == 0)
{
self->spr.scale = DVector2(REPEAT_SCALE, REPEAT_SCALE);
}
if ((self->spr.lotag > ud.player_skill) || ud.monsters_off == 1)
{
self->spr.scale.Zero();
ChangeActorStat(self, STAT_MISC);
return false;
}
else
{
makeitfall(self);
self->spr.cstat |= CSTAT_SPRITE_BLOCK_ALL;
if (!isRR() && actorflag(self, SFLAG_KILLCOUNT))
ps[myconnectindex].max_actors_killed++;
self->timetosleep = 0;
if (!self->mapSpawned)
{
CallPlayFTASound(self);
ChangeActorStat(self, STAT_ACTOR);
if (owner && !actorflag(self, SFLAG_INTERNAL_BADGUY)) self->spr.Angles.Yaw = owner->spr.Angles.Yaw;
}
else ChangeActorStat(self, STAT_ZOMBIEACTOR);
return true;
}
return true;
}
//---------------------------------------------------------------------------
//
//

View file

@ -59,7 +59,7 @@ DDukeActor* spawninit_d(DDukeActor* actj, DDukeActor* act, TArray<DDukeActor*>*
if (act->GetClass() != RUNTIME_CLASS(DDukeActor))
{
if (spawninitdefault(actj, act))
if (!badguy(act) || commonEnemySetup(act, actj))
CallInitialize(act);
return act;
}
@ -123,11 +123,6 @@ DDukeActor* spawninit_d(DDukeActor* actj, DDukeActor* act, TArray<DDukeActor*>*
ChangeActorStat(act, STAT_ZOMBIEACTOR);
}
return act;
case DTILE_FIREFLYFLYINGEFFECT:
act->SetOwner(actj);
ChangeActorStat(act, STAT_MISC);
act->spr.scale = DVector2(0.25, 0.25);
return act;
case DTILE_LAVAPOOLBUBBLE:
if (actj->spr.scale.X < 0.46875)
return act;
@ -154,7 +149,7 @@ DDukeActor* spawninit_d(DDukeActor* actj, DDukeActor* act, TArray<DDukeActor*>*
switch (act->spr.picnum)
{
default:
spawninitdefault(actj, act);
CallInitialize(act);
break;
case FOF:
act->spr.scale = DVector2(0, 0);

View file

@ -51,7 +51,7 @@ DDukeActor* spawninit_r(DDukeActor* actj, DDukeActor* act, TArray<DDukeActor*>*
if (act->GetClass() != RUNTIME_CLASS(DDukeActor))
{
if (spawninitdefault(actj, act))
if (!badguy(act) || commonEnemySetup(act, actj))
CallInitialize(act);
return act;
}
@ -61,7 +61,7 @@ DDukeActor* spawninit_r(DDukeActor* actj, DDukeActor* act, TArray<DDukeActor*>*
{
default:
default_case:
spawninitdefault(actj, act);
CallInitialize(act);
break;
case RTILE_RRTILE7936:
if (!isRRRA()) goto default_case;

View file

@ -212,6 +212,20 @@ DEFINE_ACTION_FUNCTION_NATIVE(_Duke, StopCommentary, StopCommentary)
return 0;
}
int getPlayerIndex(player_struct* p)
{
if (!p) return -1;
return int(p - ps);
}
DEFINE_ACTION_FUNCTION_NATIVE(_Duke, getPlayerIndex, getPlayerIndex)
{
PARAM_PROLOGUE;
PARAM_POINTER(p, player_struct);
ACTION_RETURN_INT(getPlayerIndex(p));
return 0;
}
DEFINE_GLOBAL_UNSIZED(dlevel)
DEFINE_GLOBAL(camsprite)
@ -609,6 +623,17 @@ DEFINE_ACTION_FUNCTION_NATIVE(DDukeActor, badguy, badguy)
ACTION_RETURN_INT(badguy(self));
}
int duke_scripted(DDukeActor* act)
{
return gs.actorinfo[act->spr.picnum].scriptaddress > 0;
}
DEFINE_ACTION_FUNCTION_NATIVE(DDukeActor, scripted, duke_scripted)
{
PARAM_SELF_PROLOGUE(DDukeActor);
ACTION_RETURN_INT(duke_scripted(self));
}
int duke_isplayer(DDukeActor* act)
{
return act->isPlayer();

View file

@ -110,7 +110,7 @@ static void analyzesprites(tspriteArray& tsprites, const DVector3& view, double
pTSprite->pos.Z -= nTileY;
}
if (pTSprite->pal == 4 && pTSprite->shade >= numshades) pTSprite->shade = numshades - 1;
if (pTSprite->pal == 4 && pTSprite->shade >= numshades && !hw_int_useindexedcolortextures) pTSprite->shade = numshades - 1;
if (pActor->spr.statnum > 0)
{

View file

@ -5,4 +5,6 @@ spawnclasses
5736 = DukeGenericDestructible, "WTGLASS1", "", "GLASS_BREAKING", spawnglass
5737 = DukeGenericDestructible, "WTGLASS2", "", "GLASS_BREAKING", spawnglass
5294 = DeveloperCommentary
1891 = DukeFlamethrowerFlame
5296 = DukeFireflyFlyingEffect
}

View file

@ -125,6 +125,7 @@ spawnclasses
1083 = DukeCameraPole
26 = RedneckDynamite
27 = RedneckPowderKeg
1416 = RedneckMortar
285 = RedneckChickenSpawner1
286 = RedneckChickenSpawner2

View file

@ -102,7 +102,10 @@ version "4.10"
#include "zscript/games/duke/actors/bloodpool.zs"
#include "zscript/games/duke/actors/toilet.zs"
#include "zscript/games/duke/actors/flamethrowerflame.zs"
#include "zscript/games/duke/actors/firefly.zs"
#include "zscript/games/duke/actors/powderkeg.zs"
#include "zscript/games/duke/actors/redneckmisc.zs"
#include "zscript/games/duke/actors/emptybike.zs"
#include "zscript/games/duke/actors/rrteleport.zs"

View file

@ -57,6 +57,7 @@ class CoreActor native
native double pitch;
native Vector3 vel;
native double viewzoffset;
native double oviewzoffset;
native readonly int16 spritesetindex;
native readonly int spawnindex;

View file

@ -0,0 +1,47 @@
// for now only the effect is scriptified.
class DukeFireflyFlyingEffect : DukeActor
{
default
{
pic "FIREFLYFLYINGEFFECT";
}
override void Initialize()
{
self.scale = (0.25, 0.25);
self.ChangeStat(STAT_MISC);
}
override void Tick()
{
Super.Tick();
if (bDestroyed) return; // killed by script.
let Owner = self.ownerActor;
if (!Owner || !Owner.checkType("FIREFLY"))
{
self.Destroy();
return;
}
if (Owner.scale.X >= 0.375 || Owner.pal == 1)
self.cstat |= CSTAT_SPRITE_INVISIBLE;
else
self.cstat &= ~CSTAT_SPRITE_INVISIBLE;
let p = self.findplayer();
let dvec = Owner.pos.XY - p.actor.pos.XY;
double dist = dvec.Length();
if (dist != 0.0) dvec /= dist;
self.pos = Owner.pos + (dvec.X * -0.625, dvec.Y * -0.625, 8);
if (Owner.extra <= 0)
{
self.Destroy();
}
}
}

View file

@ -0,0 +1,192 @@
class DukeFlamethrowerFlame : DukeActor
{
default
{
pic "FLAMETHROWERFLAME";
}
override void Tick()
{
Console.Printf("ticky");
let sectp = self.sector;
double xx;
Super.Tick(); // Run CON or its replacement.
if (self.bDestroyed) return; // killed by script.
self.temp_data[0]++;
if (sectp.lotag == ST_2_UNDERWATER)
{
let spawned = self.spawn("DukeExplosion2");
if (spawned) spawned.shade = 127;
self.Destroy();
return;
}
let dapos = self.pos;
self.getglobalz();
int ds = self.temp_data[0] / 6;
if (self.scale.X < 0.1250)
{
self.scale.X += (ds * REPEAT_SCALE);
self.scale.Y = (self.scale.X);
}
self.clipdist += ds * 0.25;
if (self.temp_data[0] <= 2)
self.temp_data[3] = random(0, 9);
if (self.temp_data[0] > 30)
{
let spawned = self.spawn("DukeExplosion2");
if (spawned) spawned.shade = 127;
self.Destroy();
return;
}
CollisionData coll;
self.movesprite_ex((self.angle.ToVector() * self.vel.X, self.vel.Z), CLIPMASK1, coll);
if (self.sector == null)
{
self.Destroy();
return;
}
if (coll.type != kHitSprite)
{
if (self.pos.Z < self.ceilingz)
{
coll.setSector(self.sector);
self.vel.Z -= 1/256.;
}
else if ((self.pos.Z > self.floorz && self.sector.lotag != ST_1_ABOVE_WATER)
|| (self.pos.Z > self.floorz + 16 && self.sector.lotag == ST_1_ABOVE_WATER))
{
coll.setSector(self.sector);
if (self.sector.lotag != 1)
self.vel.Z += 1/256.;
}
}
if (coll.type != 0)
{
self.vel.XY = (0, 0);
self.vel.Z = 0;
if (coll.type == kHitSprite)
{
let hitact = DukeActor(coll.hitActor());
hitact.checkhitsprite(self);
if (hitact.isPlayer())
hitact.PlayActorSound("PISTOL_BODYHIT");
}
else if (coll.type == kHitWall)
{
self.SetPosition(dapos);
dlevel.checkhitwall(coll.hitWall(), self, self.pos);
}
else if (coll.type == kHitSector)
{
self.SetPosition(dapos);
if (self.vel.Z < 0)
dlevel.checkhitceiling(self.sector, self);
}
if (self.scale.X >= 0.15625)
{
int x = self.extra;
self.hitradius(gs.rpgblastradius, x >> 2, x >> 1, x - (x >> 2), x);
}
else
{
int x = self.extra + (Duke.global_random() & 3);
self.hitradius((gs.rpgblastradius >> 1), x >> 2, x >> 1, x - (x >> 2), x);
}
}
}
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
override bool shootthis(DukeActor actor, DukePlayer p, Vector3 spos, double sang) const
{
Console.Printf("launching");
double vel, zvel = 0;
if (actor.extra >= 0)
actor.shade = -96;
vel = 25;
DukeActor spawned = nullptr;
if (p == null)
{
double x;
DukePlayer j;
[j, x] = actor.findplayer();
sang = (j.Actor.opos.XY - spos.XY).Angle();
if (actor.checktype("BOSS5"))
{
vel = 33;
spos.Z += 24;
}
else if (actor.checktype("BOSS3"))
spos.Z -= 32;
double dist = (j.actor.pos.XY - actor.pos.XY).Length();
if (dist != 0)
zvel = (((j.actor.opos.Z + j.actor.oviewzoffset - spos.Z) * vel) / dist);
if (actor.badguy() && (actor.hitag & face_player_smart) != 0)
sang = actor.Angle + Raze.BAngToDegree * random(-16, 15);
}
else
{
[vel, zvel] = Raze.setFreeAimVelocity(vel, zvel, p.getPitchWithView(), 40.5);
// WTF???
double myang = 90. - (180. - abs(abs((spos.XY - p.actor.pos.XY).Angle() - sang) - 180.));
if (p.actor.vel.X != 0)
vel = ((myang / 90.) * p.actor.vel.X) + 25;
}
if (actor.sector.lotag == ST_2_UNDERWATER && (random(0, 4)) == 0)
spawned = actor.spawn("DukeWaterBubble");
if (spawned == nullptr)
{
spawned = actor.spawn("DukeFlamethrowerFlame");
if (!spawned) return true;
spawned.vel.X = vel;
spawned.vel.Z = zvel;
}
Vector3 offset;
offset.X = cos(sang + Raze.BAngToDegree * 118) * (1024 / 448.); // Yes, these angles are really different!
offset.Y = sin(sang + Raze.BAngToDegree * 112) * (1024 / 448.);
offset.Z = -1;
spawned.pos = spos + offset;
spawned.pos.Z--;
spawned.sector = actor.sector;
spawned.cstat = CSTAT_SPRITE_YCENTER;
spawned.Angle = sang;
spawned.scale = (0.03125, 0.03125);
spawned.clipdist = 10;
spawned.yint = Duke.GetPlayerIndex(p);
spawned.ownerActor = actor;
if (p == null)
{
if (actor.checktype("BOSS5"))
{
spawned.pos += sang.ToVector() * (128. / 7);
spawned.scale = (0.15625, 0.15625);
}
}
return true;
}
}

View file

@ -7,7 +7,6 @@ class DukeGreenSlime : DukeActor
override void Initialize()
{
commonEnemySetup();
self.scale = (0.625, 0.625);
self.clipdist = 20;
self.extra = 1;

View file

@ -0,0 +1,34 @@
class RedneckPowderKeg : DukeActor
{
default
{
pic "POWDERKEG";
}
override void Tick()
{
let sectp = self.sector;
if (sectp.lotag != ST_1_ABOVE_WATER && sectp.lotag != ST_160_FLOOR_TELEPORT)
if (self.vel.X != 0)
{
movesprite((self.Angle.ToVector()* self.vel.X, self.vel.Z), CLIPMASK0);
self.vel.X -= 1. / 16.;
}
Super.Tick();
}
override bool shootthis(DukeActor actor, DukePlayer p, Vector3 spos, double sang)
{
let j = actor.spawn("RedneckPowderKeg");
if (j)
{
j.vel.X = 2;
j.Angle = actor.Angle;
j.pos.Z -= 5;
}
return true;
}
}

View file

@ -13,36 +13,12 @@ class DukeRecon : DukeActor
override void initialize()
{
if (self.lotag > ud.player_skill)
{
self.scale = (0, 0);
self.ChangeStat(STAT_MISC);
return;
}
if (!Raze.isRR() || self.actorflag1(SFLAG_KILLCOUNT)) // in Duke bad guys always count as kill. RR uses a flag. Needs to be cleaned up.
Duke.GetLocalPlayer().max_actors_killed++;
self.temp_data[5] = 0;
if (ud.monsters_off == 1)
{
self.scale = (0, 0);
self.ChangeStat(STAT_MISC);
return;
}
self.extra = 130;
self.cstat |= CSTAT_SPRITE_BLOCK_ALL; // Make it hitable
if (ud.multimode < 2 && self.pal != 0)
{
self.scale = (0, 0);
self.ChangeStat(STAT_MISC);
return;
}
self.pal = 0;
self.shade = -17;
self.ChangeStat(STAT_ZOMBIEACTOR);
AttackSnd = "RECO_ATTACK";
PainSnd = "RECO_PAIN";
RoamSnd = "RECO_ROAM";

View file

@ -115,6 +115,28 @@ class DukeActor : CoreActor native
STAT_REMOVED = MAXSTATUS-2,
};
enum amoveflags_t
{
face_player = 1,
geth = 2,
getv = 4,
random_angle = 8,
face_player_slow = 16,
spin = 32,
face_player_smart = 64,
fleeenemy = 128,
jumptoplayer_only = 256,
justjump1 = 256,
jumptoplayer = 257,
seekplayer = 512,
furthestdir = 1024,
dodgebullet = 4096,
justjump2 = 8192,
windang = 16384,
antifaceplayerslow = 32768
};
native void SetSpritesetImage(int index);
native int GetSpritesetSize();
@ -187,7 +209,6 @@ class DukeActor : CoreActor native
virtual void BeginPlay() {}
virtual void StaticSetup() {}
virtual void Initialize() {}
virtual void onHit(DukeActor hitter) { checkhitdefault(hitter); }
virtual void onHurt(DukePlayer p) {}
virtual bool onUse(DukePlayer user) { return false; }
@ -208,6 +229,7 @@ class DukeActor : CoreActor native
native void hitradius(int r, int hp1, int hp2, int hp3, int hp4);
native double, DukeActor hitasprite();
native int badguy();
native int scripted();
native int isplayer();
native void lotsofstuff(Name type, int count);
native double gutsoffset();
@ -229,33 +251,26 @@ class DukeActor : CoreActor native
deprecated("4.9") native bool checktype(String name); // this must not stay in the code, so mark it deprecated to keep the annoying warning at startup.
void commonEnemySetup(bool countkill = true)
virtual void Initialize()
{
if (!self.mapSpawned) self.lotag = 0;
if ((self.lotag > ud.player_skill) || ud.monsters_off == 1)
if (!self.badguy() && self.scripted())
{
self.scale = (0, 0);
self.ChangeStat(STAT_MISC);
}
else
{
self.makeitfall();
if (!self.mapSpawned) self.lotag = 0;
self.cstat |= CSTAT_SPRITE_BLOCK_ALL;
if (countkill)
Duke.GetLocalPlayer().max_actors_killed++;
if (!self.mapSpawned)
if (self.lotag > ud.player_skill)
{
self.timetosleep = 0;
self.PlayFTASound();
self.ChangeStat(STAT_ACTOR);
self.scale = (0, 0);
self.ChangeStat(STAT_MISC);
}
else self.ChangeStat(STAT_ZOMBIEACTOR);
self.clipdist = 10;
self.ownerActor = self;
self.ChangeStat(STAT_ACTOR);
}
}
int checkLocationForFloorSprite(double radius)
{
bool away = self.isAwayFromWall(radius);

View file

@ -170,6 +170,7 @@ struct Duke native
native static void updatepindisplay(int tag, int pinmask);
native static bool StartCommentary(int tag, DukeActor act);
native static void StopCommentary();
static native int getPlayerIndex(DukePlayer p);
static int rnd(int val)
{
return (random(0, 255) >= (255 - (val)));
@ -216,6 +217,7 @@ struct Duke native
if (align != -1) x -= myfont.StringWidth(t) * (align == 0 ? 0.5 : 1);
Screen.DrawText(myfont, Font.CR_NATIVEPAL, x, y + 2, t, DTA_FullscreenScale, fsmode, DTA_TranslationIndex, Translation.MakeID(Translation_Remap, trans), DTA_Color, Raze.shadeToLight(shade));
}
}
struct DukePlayer native

View file

@ -264,6 +264,11 @@ struct Raze
// Right now, with no MP support there is no need, though.
}
static double, double setFreeAimVelocity(double vel, double zvel, double pitch, double zvspeed)
{
return vel * cos(pitch), sin(pitch) * zvspeed;
}
}
/*