- scriptified the Recon.

This commit is contained in:
Christoph Oelckers 2022-11-28 18:57:50 +01:00
parent 2ab5e63386
commit 9d1384449c
27 changed files with 515 additions and 373 deletions

View file

@ -76,6 +76,25 @@ DEFINE_ACTION_FUNCTION(_Raze, clipmove)
return min(numret, 2);
}
int Raze_cansee(double x, double y, double z, sectortype* sec, double xe, double ye, double ze, sectortype* sece)
{
return cansee(DVector3(x, y, z), sec, DVector3(xe, ye, ze), sece);
}
DEFINE_ACTION_FUNCTION_NATIVE(_Raze, cansee, Raze_cansee)
{
PARAM_PROLOGUE;
PARAM_FLOAT(x);
PARAM_FLOAT(y);
PARAM_FLOAT(z);
PARAM_POINTER(s, sectortype);
PARAM_FLOAT(xe);
PARAM_FLOAT(ye);
PARAM_FLOAT(ze);
PARAM_POINTER(se, sectortype);
ACTION_RETURN_BOOL(Raze_cansee(x, y, z, s, xe, ye, ze, se));
}
DEFINE_ACTION_FUNCTION_NATIVE(_Raze, SoundEnabled, SoundEnabled)

View file

@ -681,198 +681,6 @@ void rpgexplode(DDukeActor *actor, int hit, const DVector3 &pos, int EXPLOSION2,
//
//---------------------------------------------------------------------------
void recon(DDukeActor *actor, int explosion, int firelaser, int attacksnd, int painsnd, int roamsnd, int shift, int (*getspawn)(DDukeActor* i))
{
auto sectp = actor->sector();
DAngle a;
getglobalz(actor);
if (sectp->ceilingstat & CSTAT_SECTOR_SKY)
actor->spr.shade += (sectp->ceilingshade - actor->spr.shade) >> 1;
else actor->spr.shade += (sectp->floorshade - actor->spr.shade) >> 1;
if (actor->spr.pos.Z < sectp->ceilingz + 32)
actor->spr.pos.Z = sectp->ceilingz + 32;
if (ud.multimode < 2)
{
if (actor_tog == 1)
{
actor->spr.cstat = CSTAT_SPRITE_INVISIBLE;
return;
}
else if (actor_tog == 2) actor->spr.cstat = CSTAT_SPRITE_BLOCK_ALL;
}
if (fi.ifhitbyweapon(actor) >= 0)
{
if (actor->spr.extra < 0 && actor->temp_data[0] != -1)
{
actor->temp_data[0] = -1;
actor->spr.extra = 0;
}
if (painsnd >= 0) S_PlayActorSound(painsnd, actor);
RANDOMSCRAP(actor);
}
if (actor->temp_data[0] == -1)
{
actor->spr.pos.Z += 4;
actor->temp_data[2]++;
if ((actor->temp_data[2] & 3) == 0) spawn(actor, explosion);
getglobalz(actor);
actor->spr.Angles.Yaw += DAngle22_5 * 0.75;
actor->vel.X = 8;
int j = ssp(actor, CLIPMASK0);
if (j != 1 || actor->spr.pos.Z > actor->floorz)
{
for (int l = 0; l < 16; l++)
RANDOMSCRAP(actor);
S_PlayActorSound(LASERTRIP_EXPLODE, actor);
int sp = getspawn(actor);
if (sp >= 0) spawn(actor, sp);
ps[myconnectindex].actors_killed++;
actor->Destroy();
}
return;
}
else
{
if (actor->spr.pos.Z > actor->floorz - 48)
actor->spr.pos.Z = actor->floorz - 48;
}
double xx;
int p = findplayer(actor, &xx);
auto Owner = actor->GetOwner();
// 3 = findplayerz, 4 = shoot
if (actor->temp_data[0] >= 4)
{
actor->temp_data[2]++;
if ((actor->temp_data[2] & 15) == 0)
{
a = actor->spr.Angles.Yaw;
actor->spr.Angles.Yaw = actor->temp_angle;
if (attacksnd >= 0) S_PlayActorSound(attacksnd, actor);
fi.shoot(actor, firelaser);
actor->spr.Angles.Yaw = a;
}
if (actor->temp_data[2] > (26 * 3) || !cansee(actor->spr.pos.plusZ(-16), actor->sector(), ps[p].GetActor()->getPosWithOffsetZ(), ps[p].cursector))
{
actor->temp_data[0] = 0;
actor->temp_data[2] = 0;
}
else actor->temp_angle +=
deltaangle(actor->temp_angle, (ps[p].GetActor()->spr.pos.XY() - actor->spr.pos.XY()).Angle()) / 3;
}
else if (actor->temp_data[0] == 2 || actor->temp_data[0] == 3)
{
if(actor->vel.X > 0) actor->vel.X -= 1;
else actor->vel.X = 0;
if (actor->temp_data[0] == 2)
{
double l = ps[p].GetActor()->getOffsetZ() - actor->spr.pos.Z;
if (fabs(l) < 48) actor->temp_data[0] = 3;
else actor->spr.pos.Z += (Sgn(ps[p].GetActor()->getOffsetZ() - actor->spr.pos.Z) * shift); // The shift here differs between Duke and RR.
}
else
{
actor->temp_data[2]++;
if (actor->temp_data[2] > (26 * 3) || !cansee(actor->spr.pos.plusZ(-16), actor->sector(), ps[p].GetActor()->getPosWithOffsetZ(), ps[p].cursector))
{
actor->temp_data[0] = 1;
actor->temp_data[2] = 0;
}
else if ((actor->temp_data[2] & 15) == 0 && attacksnd >= 0)
{
S_PlayActorSound(attacksnd, actor);
fi.shoot(actor, firelaser);
}
}
actor->spr.Angles.Yaw += deltaangle(actor->spr.Angles.Yaw, (ps[p].GetActor()->spr.pos.XY() - actor->spr.pos.XY()).Angle()) * 0.25;
}
if (actor->temp_data[0] != 2 && actor->temp_data[0] != 3 && Owner)
{
double dist = (Owner->spr.pos.XY() - actor->spr.pos.XY()).Length();
if (dist <= 96)
{
a = actor->spr.Angles.Yaw;
actor->vel.X *= 0.5;
}
else a = (Owner->spr.pos.XY() - actor->spr.pos.XY()).Angle();
if (actor->temp_data[0] == 1 || actor->temp_data[0] == 4) // Found a locator and going with it
{
dist = (Owner->spr.pos - actor->spr.pos).Length();
if (dist <= 96) { if (actor->temp_data[0] == 1) actor->temp_data[0] = 0; else actor->temp_data[0] = 5; }
else
{
// Control speed here
if (dist > 96) { if (actor->vel.X < 16) actor->vel.X += 2.; }
else
{
if(actor->vel.X > 0) actor->vel.X -= 1;
else actor->vel.X = 0;
}
}
if (actor->temp_data[0] < 2) actor->temp_data[2]++;
if (xx < 384 && actor->temp_data[0] < 2 && actor->temp_data[2] > (26 * 4))
{
actor->temp_data[0] = 2 + (krand() & 2);
actor->temp_data[2] = 0;
actor->temp_angle = actor->spr.Angles.Yaw;
}
}
if (actor->temp_data[0] == 0 || actor->temp_data[0] == 5)
{
if (actor->temp_data[0] == 0)
actor->temp_data[0] = 1;
else actor->temp_data[0] = 4;
auto NewOwner = LocateTheLocator(actor->spr.hitag, nullptr);
if (!NewOwner)
{
actor->spr.hitag = actor->temp_data[5];
NewOwner = LocateTheLocator(actor->spr.hitag, nullptr);
if (!NewOwner)
{
actor->Destroy();
return;
}
}
else actor->spr.hitag++;
actor->SetOwner(NewOwner);
}
auto ang = deltaangle(actor->spr.Angles.Yaw, a);
actor->spr.Angles.Yaw += ang * 0.125;
if (actor->spr.pos.Z < Owner->spr.pos.Z - 2)
actor->spr.pos.Z += 2;
else if (actor->spr.pos.Z > Owner->spr.pos.Z + 2)
actor->spr.pos -= 2;
else actor->spr.pos.Z = Owner->spr.pos.Z;
}
if (roamsnd >= 0 && S_CheckActorSoundPlaying(actor, roamsnd) < 1)
S_PlayActorSound(roamsnd, actor);
ssp(actor, CLIPMASK0);
}
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
void ooz(DDukeActor *actor)
{
getglobalz(actor);

View file

@ -556,7 +556,7 @@ int ifhitbyweapon_d(DDukeActor *actor)
actor->spr.extra -= actor->hitextra;
auto Owner = actor->GetOwner();
if (actor->spr.picnum != RECON && Owner && Owner->spr.statnum < MAXSTATUS)
if (!actorflag(actor, SFLAG2_IGNOREHITOWNER) && Owner && Owner->spr.statnum < MAXSTATUS)
actor->SetOwner(hitowner);
}
@ -1373,6 +1373,7 @@ void movetransports_d(void)
case STAT_MISC:
case STAT_FALLER:
case STAT_DUMMYPLAYER:
if (actorflag(act, SFLAG2_DONTDIVE)) continue;
ll = abs(act2->vel.Z);
@ -1501,17 +1502,7 @@ static void greenslime(DDukeActor *actor)
auto sectp = actor->sector();
int j;
// #ifndef isShareware()
if (ud.multimode < 2)
{
if (actor_tog == 1)
{
actor->spr.cstat = CSTAT_SPRITE_INVISIBLE;
return;
}
else if (actor_tog == 2) actor->spr.cstat = CSTAT_SPRITE_BLOCK_ALL;
}
// #endif
if (monsterCheatCheck(actor)) return;
actor->temp_data[1] += 128;
@ -2310,10 +2301,6 @@ void moveactors_d(void)
ssp(act, CLIPMASK0);
break;
case RECON:
recon(act, EXPLOSION2, FIRELASER, RECO_ATTACK, RECO_PAIN, RECO_ROAM, 4, [](DDukeActor* i)->int { return PIGCOP; });
continue;
case OOZ:
case OOZ2:
ooz(act);
@ -2349,18 +2336,10 @@ void moveactors_d(void)
continue;
}
// #ifndef VOLOMEONE
if (ud.multimode < 2 && badguy(act))
if (monsterCheatCheck(act) && badguy(act))
{
if (actor_tog == 1)
{
act->spr.cstat = CSTAT_SPRITE_INVISIBLE;
continue;
}
else if (actor_tog == 2) act->spr.cstat = CSTAT_SPRITE_BLOCK_ALL;
continue;
}
// #endif
double xx;
p = findplayer(act, &xx);
@ -3050,7 +3029,7 @@ void move_d(DDukeActor *actor, int playernum, int xvel)
ps[playernum].vel.XY() *= gs.playerfriction - 0.125;
}
}
else if (actor->spr.picnum != DRONE && actor->spr.picnum != SHARK && actor->spr.picnum != COMMANDER)
else if (!actorflag(actor, SFLAG2_FLOATING))
{
if (!*(moveptr + 1))
{

View file

@ -451,7 +451,8 @@ int ifhitbyweapon_r(DDukeActor *actor)
return -1;
actor->spr.extra -= actor->hitextra;
if (actor->spr.picnum != RECON && actor->GetOwner() && actor->GetOwner()->spr.statnum < MAXSTATUS)
auto Owner = actor->GetOwner();
if (!actorflag(actor, SFLAG2_IGNOREHITOWNER) && Owner && Owner->spr.statnum < MAXSTATUS)
actor->SetOwner(hitowner);
}
@ -1248,13 +1249,10 @@ void movetransports_r(void)
break;
case STAT_ACTOR:
if (act->spr.picnum == SHARK ||
(isRRRA() && (act->spr.picnum == CHEERBOAT || act->spr.picnum == HULKBOAT || act->spr.picnum == MINIONBOAT || act->spr.picnum == UFO1_RRRA)) ||
(!isRRRA() && (act->spr.picnum == UFO1_RR || act->spr.picnum == UFO2 || act->spr.picnum == UFO3 || act->spr.picnum == UFO4 || act->spr.picnum == UFO5))) continue;
[[fallthrough]];
case STAT_PROJECTILE:
case STAT_MISC:
case STAT_DUMMYPLAYER:
if (actorflag(act, SFLAG2_DONTDIVE)) continue;
ll = abs(act2->vel.Z);
if (isRRRA())
@ -1271,8 +1269,7 @@ void movetransports_r(void)
warpspriteto = 1;
if (ll && sectlotag == ST_1_ABOVE_WATER && act2->spr.pos.Z > (sectp->floorz - ll))
if (!isRRRA() || (act2->spr.picnum != CHEERBOAT && act2->spr.picnum != HULKBOAT && act2->spr.picnum != MINIONBOAT))
warpspriteto = 1;
warpspriteto = 1;
if (isRRRA())
{
@ -2065,30 +2062,6 @@ void moveactors_r(void)
break;
}
case RECON:
case UFO1_RR:
case UFO2:
case UFO3:
case UFO4:
case UFO5:
recon(act, EXPLOSION2, FIRELASER, -1, -1, 457, 1, [](DDukeActor* act) ->int
{
if (isRRRA() && ufospawnsminion)
return MINION;
else if (act->spr.picnum == UFO1_RR)
return HEN;
else if (act->spr.picnum == UFO2)
return COOT;
else if (act->spr.picnum == UFO3)
return COW;
else if (act->spr.picnum == UFO4)
return PIG;
else if (act->spr.picnum == UFO5)
return BILLYRAY;
else return -1;
});
continue;
case OOZ:
ooz(act);
continue;
@ -2137,17 +2110,10 @@ void moveactors_r(void)
}
// #ifndef VOLOMEONE
if( ud.multimode < 2 && badguy(act) )
if (monsterCheatCheck(act) && badguy(act))
{
if( actor_tog == 1)
{
act->spr.cstat = CSTAT_SPRITE_INVISIBLE;
continue;
}
else if(actor_tog == 2) act->spr.cstat = CSTAT_SPRITE_BLOCK_ALL;
continue;
}
// #endif
p = findplayer(act, &xx);
@ -2381,30 +2347,30 @@ void handle_se06_r(DDukeActor *actor)
{
if (a2->spr.picnum == UFOBEAM && ufospawn && ++ufocnt == 64)
{
int pn;
ufocnt = 0;
ufospawn--;
const char* pn;
if (!isRRRA())
{
switch (krand() & 3)
{
default:
case 0:
pn = UFO1_RR;
pn = "RedneckUfo1";
break;
case 1:
pn = UFO2;
pn = "RedneckUfo2";
break;
case 2:
pn = UFO3;
pn = "RedneckUfo3";
break;
case 3:
pn = UFO4;
pn = "RedneckUfo4";
break;
}
}
else pn = UFO1_RRRA;
auto ns = spawn(actor, pn);
else pn = "RedneckUfoRRRA";
auto ns = spawn(actor, PClass::FindActor(pn));
if (ns) ns->spr.pos.Z = ns->sector()->ceilingz;
}
}
@ -2858,9 +2824,7 @@ void move_r(DDukeActor *actor, int pnum, int xvel)
ps[pnum].vel.XY() *= gs.playerfriction - 0.125;
}
}
else if ((isRRRA() && actor->spr.picnum != DRONE && actor->spr.picnum != SHARK && actor->spr.picnum != UFO1_RRRA) ||
(!isRRRA() && actor->spr.picnum != DRONE && actor->spr.picnum != SHARK && actor->spr.picnum != UFO1_RR
&& actor->spr.picnum != UFO2 && actor->spr.picnum != UFO3 && actor->spr.picnum != UFO4 && actor->spr.picnum != UFO5))
else if (!actorflag(actor, SFLAG2_FLOATING))
{
if (!*(moveptr + 1))
{

View file

@ -176,8 +176,11 @@ void animatesprites_d(tspriteArray& tsprites, const DVector2& viewVec, DAngle vi
if (h->GetClass() != RUNTIME_CLASS(DDukeActor))
{
bool res = CallAnimate(h, t);
if (actorflag(h, SFLAG2_ALWAYSROTATE1))
// some actors have 4, some 6 rotation frames - in true Build fashion there's no pointers what to do here without flagging it.
if (actorflag(h, SFLAG2_ALWAYSROTATE1) || (t->clipdist & TSPR_ROTATE8FRAMES))
applyRotation1(h, t, viewang);
else if (actorflag(h, SFLAG2_ALWAYSROTATE2) || (t->clipdist & TSPR_ROTATE12FRAMES))
applyRotation2(h, t, viewang);
if (sectp->floorpal && !actorflag(h, SFLAG2_NOFLOORPAL))
copyfloorpal(t, sectp);
@ -252,28 +255,6 @@ void animatesprites_d(tspriteArray& tsprites, const DVector2& viewVec, DAngle vi
t->picnum = RPG + k;
break;
case RECON:
if (hw_models && modelManager.CheckModel(h->spr.picnum, h->spr.pal))
{
t->cstat &= ~CSTAT_SPRITE_XFLIP;
break;
}
kang = (h->spr.pos - viewVec).Angle();
k = angletorotation2(h->spr.Angles.Yaw, kang);
if (k > 6)
{
k = 12 - k;
t->cstat |= CSTAT_SPRITE_XFLIP;
}
else t->cstat &= ~CSTAT_SPRITE_XFLIP;
if (abs(t3) > 64) k += 7;
t->picnum = RECON + k;
break;
case APLAYER:
p = h->PlayerIndex();

View file

@ -162,8 +162,11 @@ void animatesprites_r(tspriteArray& tsprites, const DVector2& viewVec, DAngle vi
if (h->GetClass() != RUNTIME_CLASS(DDukeActor))
{
bool res = CallAnimate(h, t);
if (actorflag(h, SFLAG2_ALWAYSROTATE1))
// some actors have 4, some 6 rotation frames - in true Build fashion there's no pointers what to do here without flagging it.
if (actorflag(h, SFLAG2_ALWAYSROTATE1) || (t->clipdist & TSPR_ROTATE8FRAMES))
applyRotation1(h, t, viewang);
else if (actorflag(h, SFLAG2_ALWAYSROTATE2) || (t->clipdist & TSPR_ROTATE12FRAMES))
applyRotation2(h, t, viewang);
if (sectp->floorpal && !actorflag(h, SFLAG2_NOFLOORPAL))
copyfloorpal(t, sectp);
@ -304,23 +307,6 @@ void animatesprites_r(tspriteArray& tsprites, const DVector2& viewVec, DAngle vi
t->picnum = RPG2 + k;
break;
case RECON:
kang = (h->spr.pos - viewVec).Angle();
k = angletorotation2(h->spr.Angles.Yaw, kang);
if (k > 6)
{
k = 12 - k;
t->cstat |= CSTAT_SPRITE_XFLIP;
}
else t->cstat &= ~CSTAT_SPRITE_XFLIP;
if (abs(t3) > 64) k += 7;
t->picnum = RECON + k;
break;
case APLAYER:
p = h->PlayerIndex();

View file

@ -180,9 +180,6 @@ void initactorflags_r()
setflag(SFLAG2_DIENOW, { RADIUSEXPLOSION });
setflag(SFLAG2_NORADIUSPUSH, { HULK });
setflag(SFLAG2_FREEZEDAMAGE | SFLAG2_REFLECTIVE, { FREEZEBLAST });
setflag(SFLAG2_ALWAYSROTATE2, { RECON });
setflag(SFLAG2_SPECIALAUTOAIM, { RECON });
setflag(SFLAG2_IGNOREHITOWNER, { RECON });
setflag(SFLAG2_FLOATING, { DRONE });

View file

@ -69,7 +69,7 @@ short fakebubba_spawn, mamaspawn_count, banjosound; // RRRA special effects
short BellTime;
int WindTime;
DAngle WindDir;
uint8_t enemysizecheat /*raat607*/, ufospawnsminion, pistonsound, chickenphase /* raat605*/, RRRA_ExitedLevel, fogactive;
uint8_t enemysizecheat /*raat607*/, pistonsound, chickenphase /* raat605*/, RRRA_ExitedLevel, fogactive;
//-------------------------------------------------------------------------
//

View file

@ -132,7 +132,7 @@ extern int WindTime;
extern DAngle WindDir;
extern short fakebubba_spawn, mamaspawn_count, banjosound;
extern short BellTime;
extern uint8_t enemysizecheat /*raat607*/, ufospawnsminion, pistonsound, chickenphase /* raat605*/, RRRA_ExitedLevel, fogactive;
extern uint8_t enemysizecheat /*raat607*/, pistonsound, chickenphase /* raat605*/, RRRA_ExitedLevel, fogactive;
extern uint32_t everyothertime;
extern player_orig po[MAXPLAYERS];
extern int32_t g_cdTrack;

View file

@ -319,4 +319,18 @@ inline void applyRotation2(DDukeActor* h, tspritetype* t, DAngle viewang)
t->picnum = h->spr.picnum + k;
}
inline int monsterCheatCheck(DDukeActor* self)
{
if (ud.multimode < 2)
{
if (actor_tog == 1)
{
self->spr.cstat = CSTAT_SPRITE_INVISIBLE;
return true;
}
else if (actor_tog == 2) self->spr.cstat = CSTAT_SPRITE_BLOCK_ALL;
}
return false;
}
END_DUKE_NS

View file

@ -453,6 +453,7 @@ x(EXPLOSION2, 1890)
x(COMMANDER, 1920)
x(COMMANDERSTAYPUT, 1921)
x(RECON, 1960)
x(RECON2, 1967)
x(TANK, 1975)
x(PIGCOP, 2000)
x(PIGCOPSTAYPUT, 2001)

View file

@ -648,7 +648,7 @@ void prelevel_common(int g)
{
auto p = &ps[screenpeek];
p->sea_sick_stat = 0;
ufospawnsminion = 0;
ud.ufospawnsminion = 0;
pistonsound = 0;
p->SlotWin = 0;
enemysizecheat = 0;

View file

@ -381,6 +381,7 @@ void GameInterface::SerializeGameState(FSerializer& arc)
("spriteqloc", spriteqloc)
("animates", animates)
("chickenplant", ud.chickenplant)
("ufospawnsminion", ud.ufospawnsminion)
("numclouds", numclouds)
("cloudx", cloudx)
@ -417,7 +418,6 @@ void GameInterface::SerializeGameState(FSerializer& arc)
("belltime", BellTime)
("bellsprite", BellSprite)
("enemysizecheat", enemysizecheat)
("ufospawnsminion", ufospawnsminion)
("pistonsound", pistonsound)
("chickenphase", chickenphase)
("RRRA_ExitedLevel", RRRA_ExitedLevel)

View file

@ -485,27 +485,7 @@ void initshell(DDukeActor* actj, DDukeActor* act, bool isshell)
int initreactor(DDukeActor* actj, DDukeActor* actor, bool isrecon)
{
if (isrecon)
{
if (actor->spr.lotag > ud.player_skill)
{
actor->spr.scale = DVector2(0, 0);
ChangeActorStat(actor, STAT_MISC);
return true;
}
if (!isRR() || actorflag(actor, SFLAG_KILLCOUNT)) // Duke is just like Doom - Bad guys always count as kill.
ps[myconnectindex].max_actors_killed++;
actor->temp_data[5] = 0;
if (ud.monsters_off == 1)
{
actor->spr.scale = DVector2(0, 0);
ChangeActorStat(actor, STAT_MISC);
return false;
}
actor->spr.extra = 130;
}
else
actor->spr.extra = gs.impact_damage;
actor->spr.extra = gs.impact_damage;
actor->spr.cstat |= CSTAT_SPRITE_BLOCK_ALL; // Make it hitable

View file

@ -713,8 +713,7 @@ DDukeActor* spawninit_d(DDukeActor* actj, DDukeActor* act, TArray<DDukeActor*>*
[[fallthrough]];
case REACTOR2:
case REACTOR:
case RECON:
if (initreactor(actj, act, act->spr.picnum == RECON)) return act;
if (initreactor(actj, act, false)) return act;
break;
case FLAMETHROWERSPRITE:

View file

@ -106,11 +106,6 @@ DDukeActor* spawninit_r(DDukeActor* actj, DDukeActor* act, TArray<DDukeActor*>*
act->spr.lotag = 1;
act->clipdist = 0;
break;
case RRTILE8192:
if (!isRRRA()) goto default_case;
act->spr.scale = DVector2(0, 0);
ufospawnsminion = 1;
break;
case RRTILE8193:
if (!isRRRA()) goto default_case;
act->spr.scale = DVector2(0, 0);
@ -457,14 +452,9 @@ DDukeActor* spawninit_r(DDukeActor* actj, DDukeActor* act, TArray<DDukeActor*>*
case ROCK2:
case MAMACLOUD:
case MAMA:
case UFO1_RRRA:
if (isRRRA()) goto rrra_badguy2;
else goto default_case;
case UFO1_RR:
if (!isRRRA()) goto rrra_badguy2;
else goto default_case;
case SBSWIPE:
case CHEERSTAYPUT:
if (isRRRA()) goto rrra_stayput;
@ -496,13 +486,8 @@ DDukeActor* spawninit_r(DDukeActor* actj, DDukeActor* act, TArray<DDukeActor*>*
case DRONE:
case PIG:
case MINION:
case UFO2:
case UFO3:
case UFO4:
case UFO5:
case COW:
case COOT:
case SHARK:
case VIXEN:
rrra_badguy2:
act->spr.scale = DVector2(0.625, 0.625);
@ -571,7 +556,7 @@ DDukeActor* spawninit_r(DDukeActor* actj, DDukeActor* act, TArray<DDukeActor*>*
case MINIONSTAYPUT:
act->spr.scale = DVector2(0.25, 0.25);
act->setClipDistFromTile();
if (isRRRA() && ufospawnsminion)
if (isRRRA() && ud.ufospawnsminion)
act->spr.pal = 8;
break;
case DOGRUN:
@ -670,16 +655,6 @@ DDukeActor* spawninit_r(DDukeActor* actj, DDukeActor* act, TArray<DDukeActor*>*
act->setClipDistFromTile();
break;
case UFO1_RRRA:
case UFO1_RR:
case UFO2:
case UFO3:
case UFO4:
case UFO5:
act->spr.scale = DVector2(0.5, 0.5);
act->setClipDistFromTile();
act->spr.extra = 50;
break;
case SBMOVE:
act->spr.scale = DVector2(0.75, 0.75);
act->setClipDistFromTile();
@ -745,8 +720,7 @@ DDukeActor* spawninit_r(DDukeActor* actj, DDukeActor* act, TArray<DDukeActor*>*
[[fallthrough]];
case REACTOR2:
case REACTOR:
case RECON:
if (initreactor(actj, act, act->spr.picnum == RECON)) return act;
if (initreactor(actj, act, false)) return act;
break;
case RPG2SPRITE:

View file

@ -145,6 +145,7 @@ struct user_defs
uint8_t god, cashman, eog;
uint8_t clipping;
uint8_t user_pals[MAXPLAYERS];
uint8_t ufospawnsminion;
short from_bonus;
short last_level, secretlevel;

View file

@ -29,7 +29,9 @@ int PicForName(int intname)
{"DukeShrinkerExplosion", "SHRINKEREXPLOSION" },
{"DukeWaterBubble", "WATERBUBBLE"},
{"DukeLavaPool", "LAVAPOOL"},
{"RedneckCircleStuck", "CIRCLESTUCK"}
{"RedneckCircleStuck", "CIRCLESTUCK"},
{"DukePigCop", "PIGCOP"},
{"DukeFireLaser", "FIRELASER"},
};
for (auto& p : classes)
@ -59,6 +61,17 @@ DEFINE_ACTION_FUNCTION_NATIVE(_Duke, getviewplayer, duke_getviewplayer)
ACTION_RETURN_POINTER(duke_getviewplayer());
}
player_struct* duke_getlocalplayer()
{
return &ps[myconnectindex];
}
DEFINE_ACTION_FUNCTION_NATIVE(_Duke, getlocalplayer, duke_getlocalplayer)
{
PARAM_PROLOGUE;
ACTION_RETURN_POINTER(duke_getlocalplayer());
}
DEFINE_ACTION_FUNCTION(_Duke, MaxAmmoAmount)
{
PARAM_PROLOGUE;
@ -592,6 +605,48 @@ DEFINE_ACTION_FUNCTION_NATIVE(DDukeActor, spritewidth, duke_spw)
ACTION_RETURN_INT(duke_spw(self));
}
DEFINE_ACTION_FUNCTION_NATIVE(DDukeActor, monsterCheatCheck, monsterCheatCheck)
{
PARAM_SELF_PROLOGUE(DDukeActor);
ACTION_RETURN_INT(monsterCheatCheck(self));
}
void DukeActor_shoot(DDukeActor* act, int intname)
{
int picnum = PicForName(intname);
if (picnum == -1)
{
auto cls = PClass::FindActor(FName(ENamedName(intname)));
assert(cls);
picnum = GetDefaultByType(cls)->spr.picnum;
fi.shoot(act, picnum); // for now this crutch must suffice.
}
else
{
fi.shoot(act, picnum);
}
}
DEFINE_ACTION_FUNCTION_NATIVE(DDukeActor, shoot, DukeActor_shoot)
{
PARAM_SELF_PROLOGUE(DDukeActor);
PARAM_INT(type);
DukeActor_shoot(self, type);
return 0;
}
void DukeActor_setclipDistFromTile(DDukeActor* a)
{
a->setClipDistFromTile();
}
DEFINE_ACTION_FUNCTION_NATIVE(DDukeActor, setclipDistFromTile, DukeActor_setclipDistFromTile)
{
PARAM_SELF_PROLOGUE(DDukeActor);
DukeActor_setclipDistFromTile(self);
return 0;
}
@ -1180,6 +1235,14 @@ DEFINE_ACTION_FUNCTION_NATIVE(_DukeLevel, resetswitch, resetswitch)
return 0;
}
DEFINE_ACTION_FUNCTION_NATIVE(_DukeLevel, LocateTheLocator, LocateTheLocator)
{
PARAM_PROLOGUE;
PARAM_INT(tag);
PARAM_POINTER(sect, sectortype);
ACTION_RETURN_POINTER(LocateTheLocator(tag, sect));
}
DEFINE_FIELD_X(DukeGameInfo, DukeGameInfo, playerfriction);
DEFINE_FIELD_X(DukeGameInfo, DukeGameInfo, gravity);
@ -1227,6 +1290,7 @@ DEFINE_FIELD_X(DukeUserDefs, user_defs, marker);
DEFINE_FIELD_X(DukeUserDefs, user_defs, bomb_tag);
DEFINE_FIELD_X(DukeUserDefs, user_defs, cameraactor);
DEFINE_FIELD_X(DukeUserDefs, user_defs, chickenplant);
DEFINE_FIELD_X(DukeUserDefs, user_defs, ufospawnsminion);
DEFINE_GLOBAL_UNSIZED(ud)

View file

@ -48,6 +48,7 @@ spawnclasses
901 = DukeStripeBall
903 = DukePoolPocket
2590 = DukeForceSphere
1960 = DukeRecon
1272 = DukeTrash

View file

@ -1,5 +1,10 @@
spawnclasses
{
5260 = "RedneckUfo1"
5274 = "RedneckUfo2"
5278 = "RedneckUfo3"
5282 = "RedneckUfo4"
5286 = "RedneckUfo5"
2654 = DukeGenericGlassSpawningDestructible, "*RRTILE2654", "", "GLASS_BREAKING"
2656 = DukeGenericGlassSpawningDestructible, "*RRTILE2656", "", "GLASS_BREAKING"
3172 = DukeGenericGlassSpawningDestructible, "*RRTILE3172", "", "GLASS_BREAKING"

View file

@ -35,6 +35,12 @@ spawnclasses
8165 = RedneckGamblingMachine
8593 = RedneckGamblingMachine2
2437 = RedneckBell
5270 = RedneckUfoRRRA
5274 = RedneckUfo2
5278 = RedneckUfo3
5282 = RedneckUfo4
5286 = RedneckUfo5
8192 = RedneckUfoSpawnerToggle
7636 = DukeGenericDestructible, "OLDPHOTO0", "OLDPHOTO0BROKE", "VENT_BUST"
7638 = DukeGenericDestructible, "OLDPHOTO1", "OLDPHOTO1BROKE", "VENT_BUST"

View file

@ -15,7 +15,7 @@ $conreserve DYNOCLMP 13
$conreserve DYNEW 14
$conreserve CRAPSTIR 15
$conreserve BRICDOOR 16
$conreserve BOMBEXPL 17
$conreserve LASERTRIP_EXPLODE 17
$conreserve VENT_BUST 18
$conreserve GLASS_BREAKING 19
$conreserve GLASS_HEAVYBREAK 20

View file

@ -78,6 +78,7 @@ version "4.10"
#include "zscript/games/duke/actors/tongue.zs"
#include "zscript/games/duke/actors/queball.zs"
#include "zscript/games/duke/actors/forcesphere.zs"
#include "zscript/games/duke/actors/recon.zs"
#include "zscript/games/duke/actors/genericdestructible.zs"
#include "zscript/games/duke/actors/redneckmisc.zs"

View file

@ -0,0 +1,355 @@
class DukeRecon : DukeActor
{
default
{
spriteset "RECON", "RECON2";
}
Sound AttackSnd;
Sound PainSnd;
Sound RoamSnd;
int shift;
String spawntype; // should be 'class<DukeActor>' but the spawned types have not been converted yet.
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";
shift = 4;
SpawnType = "DukePigCop";
}
override void Tick()
{
let sectp = self.sector;
double a;
self.getglobalz();
if (sectp.ceilingstat & CSTAT_SECTOR_SKY)
self.shade += (sectp.ceilingshade - self.shade) >> 1;
else self.shade += (sectp.floorshade - self.shade) >> 1;
if (self.pos.Z < sectp.ceilingz + 32)
self.pos.Z = sectp.ceilingz + 32;
if (self.monsterCheatCheck()) return;
if (self.ifhitbyweapon() >= 0)
{
if (self.extra < 0 && self.temp_data[0] != -1)
{
self.temp_data[0] = -1;
self.extra = 0;
}
if (painsnd >= 0) self.PlayActorSound(painsnd);
self.RANDOMSCRAP();
}
if (self.temp_data[0] == -1)
{
self.pos.Z += 4;
self.temp_data[2]++;
if ((self.temp_data[2] & 3) == 0) self.spawn("DukeExplosion2");
self.getglobalz();
self.angle += 22.5 * 0.75;
self.vel.X = 8;
int j = self.DoMove(CLIPMASK0);
if (j != 1 || self.pos.Z > self.floorz)
{
for (int l = 0; l < 16; l++)
self.RANDOMSCRAP();
self.PlayActorSound("LASERTRIP_EXPLODE");
let spawned = self.spawn(spawntype);
Duke.GetLocalPlayer().actors_killed++;
self.Destroy();
}
return;
}
else
{
if (self.pos.Z > self.floorz - 48)
self.pos.Z = self.floorz - 48;
}
double xx;
DukePlayer p;
[p, xx] = self.findplayer();
let pactor = p.actor;
let Owner = self.ownerActor;
// 3 = findplayerz, 4 = shoot
if (self.temp_data[0] >= 4)
{
self.temp_data[2]++;
if ((self.temp_data[2] & 15) == 0)
{
a = self.angle;
self.angle = self.temp_angle;
if (attacksnd >= 0) self.PlayActorSound(attacksnd);
self.shoot("DukeFirelaser");
self.angle = a;
}
if (self.temp_data[2] > (26 * 3) || !Raze.cansee(self.pos.plusZ(-16), self.sector, pactor.pos.plusZ(pactor.viewzoffset), p.cursector))
{
self.temp_data[0] = 0;
self.temp_data[2] = 0;
}
else self.temp_angle +=
deltaangle(self.temp_angle, (pactor.pos.XY - self.pos.XY).Angle()) / 3;
}
else if (self.temp_data[0] == 2 || self.temp_data[0] == 3)
{
if(self.vel.X > 0) self.vel.X -= 1;
else self.vel.X = 0;
if (self.temp_data[0] == 2)
{
double l = pactor.pos.Z + pactor.viewzoffset - self.pos.Z;
if (abs(l) < 48) self.temp_data[0] = 3;
else self.pos.Z += l < 0? -shift : shift; // The shift here differs between Duke and RR.
}
else
{
self.temp_data[2]++;
if (self.temp_data[2] > (26 * 3) || !Raze.cansee(self.pos.plusZ(-16), self.sector, pactor.pos.plusZ(pactor.viewzoffset), p.cursector))
{
self.temp_data[0] = 1;
self.temp_data[2] = 0;
}
else if ((self.temp_data[2] & 15) == 0 && attacksnd >= 0)
{
self.PlayActorSound(attacksnd);
self.shoot("DukeFirelaser");
}
}
self.angle += deltaangle(self.angle, (pactor.pos.XY - self.pos.XY).Angle()) * 0.25;
}
if (self.temp_data[0] != 2 && self.temp_data[0] != 3 && Owner)
{
double dist = (Owner.pos.XY - self.pos.XY).Length();
if (dist <= 96)
{
a = self.angle;
self.vel.X *= 0.5;
}
else a = (Owner.pos.XY - self.pos.XY).Angle();
if (self.temp_data[0] == 1 || self.temp_data[0] == 4) // Found a locator and going with it
{
dist = (Owner.pos - self.pos).Length();
if (dist <= 96) { if (self.temp_data[0] == 1) self.temp_data[0] = 0; else self.temp_data[0] = 5; }
else
{
// Control speed here
if (dist > 96) { if (self.vel.X < 16) self.vel.X += 2.; }
else
{
if(self.vel.X > 0) self.vel.X -= 1;
else self.vel.X = 0;
}
}
if (self.temp_data[0] < 2) self.temp_data[2]++;
if (xx < 384 && self.temp_data[0] < 2 && self.temp_data[2] > (26 * 4))
{
self.temp_data[0] = 2 + random(0, 1) * 2;
self.temp_data[2] = 0;
self.temp_angle = self.angle;
}
}
if (self.temp_data[0] == 0 || self.temp_data[0] == 5)
{
if (self.temp_data[0] == 0)
self.temp_data[0] = 1;
else self.temp_data[0] = 4;
let NewOwner = dlevel.LocateTheLocator(self.hitag, nullptr);
if (!NewOwner)
{
self.hitag = self.temp_data[5];
NewOwner = dlevel.LocateTheLocator(self.hitag, nullptr);
if (!NewOwner)
{
self.Destroy();
return;
}
}
else self.hitag++;
self.ownerActor = NewOwner;
}
let ang = deltaangle(self.angle, a);
self.angle += ang * 0.125;
if (self.pos.Z < Owner.pos.Z - 2)
self.pos.Z += 2;
else if (self.pos.Z > Owner.pos.Z + 2)
self.pos.Z -= 2;
else self.pos.Z = Owner.pos.Z;
}
if (roamsnd >= 0 && !self.CheckSoundPlaying(roamsnd))
self.PlayActorSound(roamsnd);
self.DoMove(CLIPMASK0);
}
override bool Animate(tspritetype t)
{
t.SetSpritePic(self, abs(self.temp_data[3]) > 64);
return true;
}
}
//---------------------------------------------------------------------------
//
// RR's UFOs use the same logic, but different setup.
//
//---------------------------------------------------------------------------
class RedneckUFO1 : DukeRecon
{
default
{
Pic "UFO1_RR";
ScaleX 0.5;
ScaleY 0.5;
Extra 50;
}
override void Initialize()
{
self.ChangeStat(STAT_ZOMBIEACTOR);
RoamSnd = "UFOLET";
shift = 1;
SpawnType = "RedneckHen";
self.setClipDistFromTile();
}
override bool Animate(tspritetype t)
{
return true;
}
}
class RedneckUFO2 : RedneckUFO1
{
default
{
Pic "UFO2";
}
override void Initialize()
{
Super.Initialize();
SpawnType = "RedneckCoot";
}
}
class RedneckUFO3 : RedneckUFO1
{
default
{
Pic "UFO3";
}
override void Initialize()
{
Super.Initialize();
SpawnType = "RedneckCow";
}
}
class RedneckUFO4 : RedneckUFO1
{
default
{
Pic "UFO4";
}
override void Initialize()
{
Super.Initialize();
SpawnType = "RedneckPig";
}
}
class RedneckUFO5 : RedneckUFO1
{
default
{
Pic "UFO5";
}
override void Initialize()
{
Super.Initialize();
SpawnType = "RedneckBillyRay";
}
}
class RedneckUFORRRA : RedneckUFO1
{
default
{
Pic "UFO1_RRRA";
}
override void Initialize()
{
Super.Initialize();
if (ud.ufospawnsminion) SpawnType = "RedneckMinion";
}
}
class RedneckUfoSpawnerToggle : DukeActor
{
default
{
statnum STAT_MISC;
}
override void Initialize()
{
//case RRTILE8192:
self.scale = (0, 0);
ud.ufospawnsminion = 1;
}
}

View file

@ -201,6 +201,9 @@ class DukeActor : CoreActor native
native double gutsoffset();
native int movesprite(Vector3 move, int clipmask);
native int movesprite_ex(Vector3 move, int clipmask, CollisionData coll);
native int monsterCheatCheck();
native void shoot(Name spawnclass);
native void setClipDistFromTile();
// temporary flag accessors - need to be eliminated once we can have true actor flags
@ -233,9 +236,10 @@ struct DukeLevel
native static void addlightning(sectortype sector, int shade);
native static int addambient(int hitag, int lotag);
native static void resetswitch(int tag); //
native bool isMirror(walltype wal);
native void checkhitwall(walltype wal, DukeActor hitter, Vector3 hitpos);
native void checkhitceiling(sectortype wal, DukeActor hitter);
native static bool isMirror(walltype wal);
native static void checkhitwall(walltype wal, DukeActor hitter, Vector3 hitpos);
native static void checkhitceiling(sectortype wal, DukeActor hitter);
native static DukeActor LocateTheLocator(int n, sectortype sect);
}
struct DukeStatIterator

View file

@ -139,6 +139,7 @@ struct Duke native
native static void StopSound(Sound num);
native static bool CheckSoundPlaying(Sound num);
native static DukePlayer GetViewPlayer();
native static DukePlayer GetLocalPlayer();
native static int MaxAmmoAmount(int weap);
native static DukePlayer checkcursectnums(sectortype sect);
native static int global_random();
@ -442,6 +443,7 @@ struct DukeUserDefs native
native readonly int ffire, multimode;
native readonly int player_skill, marker, chickenplant;
native uint8 ufospawnsminion;
native int16 bomb_tag;
native DukeActor cameraactor;
}

View file

@ -172,6 +172,7 @@ struct Raze
native static sectortype updatesector(Vector2 pos, sectortype lastsect, double maxdist = 96);
native static sectortype, Vector3 clipmove(Vector3 pos, sectortype sect, Vector2 move, double walldist, double ceildist, double flordist, uint cliptype, CollisionData coll, int clipmoveboxtracenum = 3);
native static bool cansee(Vector3 start, sectortype startsec, Vector3 end, sectortype endsec);
// game check shortcuts