- scriptified the green slimer.

This commit is contained in:
Christoph Oelckers 2022-11-30 19:39:06 +01:00
parent bc34746227
commit ff6a9b89ac
24 changed files with 524 additions and 477 deletions

View file

@ -715,6 +715,7 @@ DEFINE_FIELD_NAMED(DCoreActor, sprext.alpha, alpha)
DEFINE_FIELD_NAMED(DCoreActor, time, spawnindex)
DEFINE_FIELD(DCoreActor, spritesetindex)
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, opos)

View file

@ -909,8 +909,7 @@ void glasspieces(DDukeActor* actor)
if(actor->vel.X > 0)
{
actor->vel.X -= 1/8.;
static const ESpriteFlags flips[] = { 0, CSTAT_SPRITE_XFLIP, CSTAT_SPRITE_YFLIP, CSTAT_SPRITE_XFLIP | CSTAT_SPRITE_YFLIP };
actor->spr.cstat = flips[int(actor->vel.X * 16) & 3];
actor->spr.cstat = randomFlip();
}
else actor->vel.X = 0;
@ -3580,8 +3579,13 @@ void movefta(void)
auto check_fta_sounds = [](DDukeActor* act)
{
if (isRR()) check_fta_sounds_r(act);
else check_fta_sounds_d(act);
if (act->GetClass() == RUNTIME_CLASS(DDukeActor))
{
if (isRR()) check_fta_sounds_r(act);
else check_fta_sounds_d(act);
}
else
CallPlayFTASound(act);
};
DukeStatIterator it(STAT_ZOMBIEACTOR);

View file

@ -108,9 +108,6 @@ void check_fta_sounds_d(DDukeActor* actor)
S_PlaySound(BOS4_RECOG);
S_PlaySound(BOSS4_FIRSTSEE);
break;
case GREENSLIME:
S_PlayActorSound(SLIM_RECOG, actor);
break;
}
}
@ -945,22 +942,7 @@ void movetransports_d(void)
break;
case STAT_ACTOR:
switch (act2->spr.picnum)
{
case SHARK:
case COMMANDER:
case OCTABRAIN:
case GREENSLIME:
case GREENSLIME + 1:
case GREENSLIME + 2:
case GREENSLIME + 3:
case GREENSLIME + 4:
case GREENSLIME + 5:
case GREENSLIME + 6:
case GREENSLIME + 7:
if (act2->spr.extra > 0)
continue;
}
if (actorflag(act, SFLAG3_DONTDIVEALIVE) && act2->spr.extra > 0) continue;
[[fallthrough]];
case STAT_PROJECTILE:
case STAT_MISC:
@ -1090,399 +1072,6 @@ void movetransports_d(void)
//
//---------------------------------------------------------------------------
static void greenslime(DDukeActor *actor)
{
auto sectp = actor->sector();
int j;
if (monsterCheatCheck(actor)) return;
actor->temp_data[1] += 128;
if (sectp->floorstat & CSTAT_SECTOR_SKY)
{
actor->Destroy();
return;
}
double xx;
int p = findplayer(actor, &xx);
if (xx > 1280)
{
actor->timetosleep++;
if (actor->timetosleep > SLEEPTIME)
{
actor->timetosleep = 0;
ChangeActorStat(actor, STAT_ZOMBIEACTOR);
return;
}
}
if (actor->temp_data[0] == -5) // FROZEN
{
actor->temp_data[3]++;
if (actor->temp_data[3] > 280)
{
actor->spr.pal = 0;
actor->temp_data[0] = 0;
return;
}
makeitfall(actor);
actor->spr.cstat = CSTAT_SPRITE_BLOCK_ALL;
actor->spr.picnum = GREENSLIME + 2;
actor->spr.extra = 1;
actor->spr.pal = 1;
j = fi.ifhitbyweapon(actor);
if (j >= 0)
{
if (j == FREEZEBLAST)
return;
for (j = 16; j >= 0; j--)
{
auto a = randomAngle();
auto vel = krandf(2) + 2;
auto zvel = 4 - krandf(4);
auto k = CreateActor(actor->sector(), actor->spr.pos, GLASSPIECES + (j % 3), -32, DVector2(0.5625, 0.5625), a, vel, zvel, actor, 5);
k->spr.pal = 1;
}
ps[p].actors_killed++;
S_PlayActorSound(GLASS_BREAKING, actor);
actor->Destroy();
}
else if (xx < 64 && ps[p].quick_kick == 0)
{
auto ang = absangle(ps[p].GetActor()->spr.Angles.Yaw, (actor->spr.pos.XY() - ps[p].GetActor()->spr.pos.XY()).Angle());
if (ang < DAngle22_5)
ps[p].quick_kick = 14;
}
return;
}
if (xx < 99.75)
actor->spr.cstat = 0;
else actor->spr.cstat = CSTAT_SPRITE_BLOCK_ALL;
if (actor->temp_data[0] == -4) //On the player
{
if (ps[p].GetActor()->spr.extra < 1)
{
actor->temp_data[0] = 0;
return;
}
SetActor(actor, actor->spr.pos);
actor->spr.Angles.Yaw = ps[p].GetActor()->spr.Angles.Yaw;
if ((PlayerInput(p, SB_FIRE) || (ps[p].quick_kick > 0)) && ps[p].GetActor()->spr.extra > 0)
if (ps[p].quick_kick > 0 || (ps[p].curr_weapon != HANDREMOTE_WEAPON && ps[p].curr_weapon != HANDBOMB_WEAPON && ps[p].curr_weapon != TRIPBOMB_WEAPON && ps[p].ammo_amount[ps[p].curr_weapon] >= 0))
{
for (int x = 0; x < 8; x++)
{
auto a = randomAngle();
auto vel = krandf(4) + 4;
auto zvel = -krandf(16) - actor->vel.Z * 0.25;
auto spawned = CreateActor(actor->sector(), actor->spr.pos.plusZ(-8), PClass::FindActor("DukeScrap"), -8, DVector2(0.75, 0.75), a, vel, zvel, actor, STAT_MISC);
if (spawned)
{
if (spawned) spawned->spriteextra = Scrap3 + (krand() & 3);
spawned->spr.pal = 6;
}
}
S_PlayActorSound(SLIM_DYING, actor);
S_PlayActorSound(SQUISHED, actor);
if ((krand() & 255) < 32)
{
auto spawned = spawn(actor, BLOODPOOL);
if (spawned) spawned->spr.pal = 0;
}
ps[p].actors_killed++;
actor->temp_data[0] = -3;
if (ps[p].somethingonplayer == actor)
ps[p].somethingonplayer = nullptr;
actor->Destroy();
return;
}
actor->spr.pos.Z = ps[p].GetActor()->getOffsetZ() + 8 + ps[p].pyoff - (actor->temp_data[2] + (ps[p].GetActor()->spr.Angles.Pitch.Tan() * 2048.)) * zinttoworld;
if (actor->temp_data[2] > 512)
actor->temp_data[2] -= 128;
if (actor->temp_data[2] < 348)
actor->temp_data[2] += 128;
if (ps[p].newOwner != nullptr)
{
ps[p].newOwner = nullptr;
ps[p].GetActor()->restoreloc();
updatesector(ps[p].GetActor()->getPosWithOffsetZ(), &ps[p].cursector);
DukeStatIterator it(STAT_ACTOR);
while (auto ac = it.Next())
{
if (actorflag(ac, SFLAG2_CAMERA)) ac->spr.yint = 0;
}
}
if (actor->temp_data[3] > 0)
{
static const uint8_t frames[] = { 5,5,6,6,7,7,6,5 };
actor->spr.picnum = GREENSLIME + frames[actor->temp_data[3]];
if (actor->temp_data[3] == 5)
{
auto psp = ps[p].GetActor();
psp->spr.extra += -(5 + (krand() & 3));
S_PlayActorSound(SLIM_ATTACK, actor);
}
if (actor->temp_data[3] < 7) actor->temp_data[3]++;
else actor->temp_data[3] = 0;
}
else
{
actor->spr.picnum = GREENSLIME + 5;
if (rnd(32))
actor->temp_data[3] = 1;
}
double add = (BobVal(actor->temp_data[1]) * 2) * REPEAT_SCALE;
actor->spr.scale = DVector2(0.3125 + add, 0.234375 + add);
actor->spr.pos.XY() = ps[p].GetActor()->spr.pos.XY() + ps[p].GetActor()->spr.Angles.Yaw.ToVector() * 8;
return;
}
else if (actor->vel.X < 4 && xx < 48)
{
if (ps[p].somethingonplayer == nullptr)
{
ps[p].somethingonplayer = actor;
if (actor->temp_data[0] == 3 || actor->temp_data[0] == 2) //Falling downward
actor->temp_data[2] = (12 << 8);
else actor->temp_data[2] = -(13 << 8); //Climbing up duke
actor->temp_data[0] = -4;
}
}
j = fi.ifhitbyweapon(actor);
if (j >= 0)
{
S_PlayActorSound(SLIM_DYING, actor);
if (ps[p].somethingonplayer == actor)
ps[p].somethingonplayer = nullptr;
if (j == FREEZEBLAST)
{
S_PlayActorSound(SOMETHINGFROZE, actor);
actor->temp_data[0] = -5; actor->temp_data[3] = 0;
return;
}
ps[p].actors_killed++;
if ((krand() & 255) < 32)
{
auto spawned = spawn(actor, BLOODPOOL);
if (spawned) spawned->spr.pal = 0;
}
for (int x = 0; x < 8; x++)
{
auto a = randomAngle();
auto vel = krandf(4) + 4;
auto zvel = -krandf(16) - actor->vel.Z * 0.25;
auto spawned = CreateActor(actor->sector(), actor->spr.pos.plusZ(-8), PClass::FindActor("DukeScrap"), -8, DVector2(0.75, 0.75), a, vel, zvel, actor, STAT_MISC);
if (spawned)
{
if (spawned) spawned->spriteextra = Scrap3 + (krand() & 3);
spawned->spr.pal = 6;
}
}
actor->temp_data[0] = -3;
actor->Destroy();
return;
}
// All weap
if (actor->temp_data[0] == -1) //Shrinking down
{
makeitfall(actor);
actor->spr.cstat &= ~CSTAT_SPRITE_YFLIP;
actor->spr.picnum = GREENSLIME + 4;
if (actor->spr.scale.X > 0.5 ) actor->spr.scale.X += (-(krand() & 7) * REPEAT_SCALE);
if (actor->spr.scale.Y > 0.25 ) actor->spr.scale.Y += (-(krand() & 7) * REPEAT_SCALE);
else
{
actor->spr.scale = DVector2(0.625, 0.25);
actor->temp_actor = nullptr;
actor->temp_data[0] = 0;
}
return;
}
else if (actor->temp_data[0] != -2) getglobalz(actor);
if (actor->temp_data[0] == -2) //On top of somebody (an enemy)
{
DDukeActor* s5 = actor->temp_actor;
makeitfall(actor);
if (s5)
{
s5->vel.X = 0;
actor->spr.pos = s5->spr.pos + s5->spr.Angles.Yaw.ToVector() * 0.5;
actor->spr.picnum = GREENSLIME + 2 + (global_random & 1);
if (actor->spr.scale.Y < 1) actor->spr.scale.Y += (0.03125);
else
{
if (actor->spr.scale.X < 0.5) actor->spr.scale.X += (0.0625);
else
{
actor->temp_data[0] = -1;
double dist = (actor->spr.pos.XY() - s5->spr.pos.XY()).LengthSquared();
if (dist < 48*48) {
s5->spr.scale.X = 0;
}
}
}
}
return;
}
//Check randomly to see of there is an actor near
if (rnd(32))
{
DukeSectIterator it(actor->sector());
while (auto a2 = it.Next())
{
if (actorflag(a2, SFLAG_GREENSLIMEFOOD))
{
double dist = (actor->spr.pos.XY() - a2->spr.pos.XY()).LengthSquared();
if (dist < 48*48 && (abs(actor->spr.pos.Z - a2->spr.pos.Z) < 16)) //Gulp them
{
actor->temp_actor = a2;
actor->temp_data[0] = -2;
actor->temp_data[1] = 0;
return;
}
}
}
}
//Moving on the ground or ceiling
if (actor->temp_data[0] == 0 || actor->temp_data[0] == 2)
{
actor->spr.picnum = GREENSLIME;
if ((krand() & 511) == 0)
S_PlayActorSound(SLIM_ROAM, actor);
if (actor->temp_data[0] == 2)
{
actor->vel.Z = 0;
actor->spr.cstat &= ~CSTAT_SPRITE_YFLIP;
if ((sectp->ceilingstat & CSTAT_SECTOR_SKY) || (actor->ceilingz + 24) < actor->spr.pos.Z)
{
actor->spr.pos.Z += 8;
actor->temp_data[0] = 3;
return;
}
}
else
{
actor->spr.cstat |= CSTAT_SPRITE_YFLIP;
makeitfall(actor);
}
if (everyothertime & 1) ssp(actor, CLIPMASK0);
if (actor->vel.X > 6)
{
actor->vel.X -= 1/8.;
return;
}
else
{
if (actor->vel.X < 2) actor->vel.X += 0.25;
actor->vel.X = 4 - BobVal(512 + actor->temp_data[1]) * 2;
actor->spr.Angles.Yaw += deltaangle(actor->spr.Angles.Yaw, (ps[p].GetActor()->spr.pos.XY() - actor->spr.pos.XY()).Angle()) * 0.125;
// TJR
}
actor->spr.scale.X = (0.5625 + BobVal(512 + actor->temp_data[1]) * 0.125);
actor->spr.scale.Y = (0.25 + BobVal(actor->temp_data[1]) * 0.03125);
if (rnd(4) && (sectp->ceilingstat & CSTAT_SECTOR_SKY) == 0 &&
abs(actor->floorz - actor->ceilingz) < 192)
{
actor->vel.Z = 0;
actor->temp_data[0]++;
}
}
if (actor->temp_data[0] == 1)
{
actor->spr.picnum = GREENSLIME;
if (actor->spr.scale.Y < 0.625) actor->spr.scale.Y += (0.125);
if (actor->spr.scale.X > 0.125 ) actor->spr.scale.X += (-0.0625);
if (actor->vel.Z > -12)
actor->vel.Z -= 348 / 256.;
actor->spr.pos.Z += actor->vel.Z;
if (actor->spr.pos.Z < actor->ceilingz + 16)
{
actor->spr.pos.Z = actor->ceilingz + 16;
actor->vel.X = 0;
actor->temp_data[0] = 2;
}
}
if (actor->temp_data[0] == 3)
{
actor->spr.picnum = GREENSLIME + 1;
makeitfall(actor);
if (actor->spr.pos.Z > actor->floorz - 8)
{
actor->spr.scale.Y += (-0.0625);
actor->spr.scale.X += (0.03125);
}
else
{
if (actor->spr.scale.Y < 0.5625) actor->spr.scale.Y += (0.125);
if (actor->spr.scale.X > 0.125 ) actor->spr.scale.X += (-0.0625);
}
if (actor->spr.pos.Z > actor->floorz - 8)
{
actor->spr.pos.Z = actor->floorz - 8;
actor->temp_data[0] = 0;
actor->vel.X = 0;
}
}
}
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
static void flamethrowerflame(DDukeActor *actor)
{
auto sectp = actor->sector();
@ -1825,17 +1414,6 @@ void moveactors_d(void)
if (isWorldTour()) flamethrowerflame(act);
continue;
case GREENSLIME:
case GREENSLIME + 1:
case GREENSLIME + 2:
case GREENSLIME + 3:
case GREENSLIME + 4:
case GREENSLIME + 5:
case GREENSLIME + 6:
case GREENSLIME + 7:
greenslime(act);
continue;
case BOUNCEMINE:
case MORTER:
spawn(act, FRAMEEFFECT1)->temp_data[0] = 3;
@ -2018,8 +1596,8 @@ void moveexplosions_d(void) // STATNUM 5
continue;
case GLASSPIECES:
case GLASSPIECES + 1:
case GLASSPIECES + 2:
case GLASSPIECES1:
case GLASSPIECES2:
glasspieces(act);
continue;
}

View file

@ -1810,8 +1810,8 @@ void moveexplosions_r(void) // STATNUM 5
continue;
case GLASSPIECES:
case GLASSPIECES + 1:
case GLASSPIECES + 2:
case GLASSPIECES1:
case GLASSPIECES2:
case POPCORN:
glasspieces(act);
continue;

View file

@ -58,10 +58,11 @@ void animatesprites_d(tspriteArray& tsprites, const DVector2& viewVec, DAngle vi
t = tsprites.get(j);
h = static_cast<DDukeActor*>(t->ownerActor);
if (!actorflag(h, SFLAG2_FORCESECTORSHADE))
switch (t->picnum)
{
case DEVELOPERCOMMENTARY:
case DEVELOPERCOMMENTARY + 1:
case DEVELOPERCOMMENTARYON:
if (isWorldTour() && !wt_commentary)
t->scale = DVector2(0, 0);
break;
@ -99,15 +100,6 @@ void animatesprites_d(tspriteArray& tsprites, const DVector2& viewVec, DAngle vi
case NEON5:
case NEON6:
continue;
case GREENSLIME:
case GREENSLIME + 1:
case GREENSLIME + 2:
case GREENSLIME + 3:
case GREENSLIME + 4:
case GREENSLIME + 5:
case GREENSLIME + 6:
case GREENSLIME + 7:
break;
default:
if (((t->cstat & CSTAT_SPRITE_ALIGNMENT_WALL)) || (badguypic(t->picnum) && t->extra > 0) || t->statnum == STAT_PLAYER)
continue;

View file

@ -382,12 +382,22 @@ enum sflags2_t
SFLAG2_ALTPROJECTILESPRITE = 0x10000000, // yet another shooter flag. :(
SFLAG2_UNDERWATERSLOWDOWN = 0x20000000,
SFLAG2_TRIGGERRESPAWN = 0x40000000,
SFLAG2_FORCESECTORSHADE = 0x80000000,
};
using EDukeFlags2 = TFlags<sflags2_t, uint32_t>;
DEFINE_TFLAGS_OPERATORS(EDukeFlags2)
enum sflags3_t
{
SFLAG3_DONTDIVEALIVE = 0x00000001,
};
using EDukeFlags3 = TFlags<sflags3_t, uint32_t>;
DEFINE_TFLAGS_OPERATORS(EDukeFlags3)
// these get stored as user flags inside the texture manager.
enum
{

View file

@ -126,6 +126,7 @@ void CallOnRespawn(DDukeActor* actor, int low);
bool CallAnimate(DDukeActor* actor, tspritetype* hitter);
bool CallShootThis(DDukeActor* clsdef, DDukeActor* actor, int pn, const DVector3& spos, DAngle sang);
void CallStaticSetup(DDukeActor* actor);
void CallPlayFTASound(DDukeActor* actor);
END_DUKE_NS

View file

@ -78,13 +78,6 @@ void initactorflags_d()
BOSS3,
BOSS4,
GREENSLIME,
GREENSLIME+1,
GREENSLIME+2,
GREENSLIME+3,
GREENSLIME+4,
GREENSLIME+5,
GREENSLIME+6,
GREENSLIME+7,
RAT,
ROTATEGUN });
@ -150,13 +143,6 @@ void initactorflags_d()
setflag(SFLAG_SHRINKAUTOAIM, {
GREENSLIME,
GREENSLIME + 1,
GREENSLIME + 2,
GREENSLIME + 3,
GREENSLIME + 4,
GREENSLIME + 5,
GREENSLIME + 6,
GREENSLIME + 7,
});
setflag(SFLAG_HITRADIUSCHECK, {
@ -214,6 +200,7 @@ void initactorflags_d()
TOUGHGAL
});
setflag(SFLAG2_FORCESECTORSHADE, { GREENSLIME });
// The feature guarded by this flag does not exist in Duke, it always acts as if the flag was set.
for (auto& ainf : gs.actorinfo) ainf.flags |= SFLAG_MOVEFTA_CHECKSEE;

View file

@ -519,4 +519,14 @@ bool CallShootThis(DDukeActor* clsdef, DDukeActor* actor, int pn, const DVector3
return rv;
}
void CallPlayFTASound(DDukeActor* actor)
{
IFVIRTUALPTR(actor, DDukeActor, PlayFTASound)
{
VMValue val = actor;
VMCall(func, &val, 1, nullptr, 0);
}
}
END_DUKE_NS

View file

@ -64,6 +64,11 @@ inline int actorflag(DDukeActor* actor, EDukeFlags2 mask)
return (((gs.actorinfo[actor->spr.picnum].flags2) & mask) != 0);
}
inline int actorflag(DDukeActor* actor, EDukeFlags3 mask)
{
return (((gs.actorinfo[actor->spr.picnum].flags3) & mask) != 0);
}
inline int attackerflag(DDukeActor* actor, EDukeFlags1 mask)
{
return (((gs.actorinfo[actor->attackertype].flags) & mask) != 0);

View file

@ -307,6 +307,8 @@ x(MASKWALL15, 1024)
x(BOTTLE7, 1025)
x(HORSEONSIDE, 1026)
x(GLASSPIECES, 1031)
x(GLASSPIECES1, 1032)
x(GLASSPIECES2, 1033)
x(HORSELITE, 1034)
x(DONUTS, 1045)
x(NEON6, 1046)
@ -532,6 +534,14 @@ x(SMALLSMOKEMAKER, 2330)
x(FLOORFLAME, 2333)
x(ROTATEGUN, 2360)
x(GREENSLIME, 2370)
x(GREENSLIME1, 2371)
x(GREENSLIME2, 2372)
x(GREENSLIME3, 2373)
x(GREENSLIME4, 2374)
x(GREENSLIME5, 2375)
x(GREENSLIME6, 2376)
x(GREENSLIME7, 2377)
x(WATERDRIPSPLASH, 2380)
@ -899,6 +909,7 @@ x(FIREFLYSHRINKEFFECT, 5360)
x(FIREFLYGROWEFFECT, 5367)
x(FIREFLYFLYINGEFFECT, 5296)
x(DEVELOPERCOMMENTARY, 5294)
x(DEVELOPERCOMMENTARYON, 5295)
x(BOSS5, 5310)
x(BOSS5STAYPUT, 5311)
x(SERIOUSSAM, 5846)

View file

@ -401,6 +401,8 @@ x(SPOTLITE, 1247)
x(HANGOOZ, 1249)
x(HORSEONSIDE, 1251)
x(GLASSPIECES, 1256)
x(GLASSPIECES1, 1257)
x(GLASSPIECES2, 1258)
x(HORSELITE, 1259)
x(DONUTS, 1263)
x(NEON6, 1264)

View file

@ -335,13 +335,6 @@ static void shootweapon(DDukeActor *actor, int p, DVector3 pos, DAngle ang, int
switch (aimed->spr.picnum)
{
case GREENSLIME:
case GREENSLIME + 1:
case GREENSLIME + 2:
case GREENSLIME + 3:
case GREENSLIME + 4:
case GREENSLIME + 5:
case GREENSLIME + 6:
case GREENSLIME + 7:
case ROTATEGUN:
dal -= 8;
break;
@ -907,13 +900,6 @@ static void shootgrowspark(DDukeActor* actor, int p, DVector3 pos, DAngle ang)
switch (aimed->spr.picnum)
{
case GREENSLIME:
case GREENSLIME + 1:
case GREENSLIME + 2:
case GREENSLIME + 3:
case GREENSLIME + 4:
case GREENSLIME + 5:
case GREENSLIME + 6:
case GREENSLIME + 7:
case ROTATEGUN:
dal -= 8;
break;

View file

@ -286,7 +286,8 @@ void DDukeActor::Serialize(FSerializer& arc)
("temp_sect", temp_sect)
("uservars", uservars)
("flags1", flags1)
("flags2", flags2);
("flags2", flags2)
("flags3", flags3);
}

View file

@ -948,7 +948,7 @@ void checkhitdefault_d(DDukeActor* targ, DDukeActor* proj)
if (proj->spr.picnum == RPG) proj->spr.extra <<= 1;
if ((targ->spr.picnum != DRONE) && (targ->spr.picnum != ROTATEGUN) && (targ->spr.picnum != COMMANDER) && (targ->spr.picnum < GREENSLIME || targ->spr.picnum > GREENSLIME + 7))
if ((targ->spr.picnum != DRONE) && (targ->spr.picnum != ROTATEGUN) && (targ->spr.picnum != COMMANDER) && targ->spr.picnum != GREENSLIME)
if (proj->spr.picnum != FREEZEBLAST)
//if (actortype[targ->spr.picnum] == 0) //TRANSITIONAL.
{

View file

@ -525,10 +525,6 @@ DDukeActor* spawninit_d(DDukeActor* actj, DDukeActor* act, TArray<DDukeActor*>*
case BOSS3:
case BOSS4:
case ROTATEGUN:
case GREENSLIME:
if (act->spr.picnum == GREENSLIME)
act->spr.extra = 1;
[[fallthrough]];
case DRONE:
case LIZTROOPONTOILET:
case LIZTROOPJUSTSIT:

View file

@ -27,6 +27,7 @@ struct ActorInfo
uint32_t scriptaddress;
EDukeFlags1 flags;
EDukeFlags2 flags2;
EDukeFlags3 flags3;
int aimoffset;
int falladjustz;
int gutsoffset;
@ -68,6 +69,7 @@ public:
EDukeFlags1 flags1;
EDukeFlags2 flags2;
EDukeFlags3 flags3;
DDukeActor() = default;
size_t PropagateMark() override;

View file

@ -207,6 +207,7 @@ DEFINE_FIELD(DDukeActor, temp_actor)
DEFINE_FIELD(DDukeActor, seek_actor)
DEFINE_FIELD(DDukeActor, flags1)
DEFINE_FIELD(DDukeActor, flags2)
DEFINE_FIELD(DDukeActor, flags3)
DEFINE_FIELD(DDukeActor, spritesetindex)
DEFINE_FIELD(DDukeActor, temp_walls)
DEFINE_FIELD(DDukeActor, temp_sect)
@ -681,6 +682,18 @@ DEFINE_ACTION_FUNCTION_NATIVE(DDukeActor, operateforcefields, DukeActor_operatef
return 0;
}
void DukeActor_restoreloc(DDukeActor* self)
{
self->restoreloc();
}
DEFINE_ACTION_FUNCTION_NATIVE(DDukeActor, restoreloc, DukeActor_restoreloc)
{
PARAM_SELF_PROLOGUE(DDukeActor);
PARAM_INT(tag);
DukeActor_restoreloc(self);
return 0;
}
// temporary helpers to hide the fact that these flags are not part of the actor yet.
DEFINE_ACTION_FUNCTION(DDukeActor, actorflag1)

View file

@ -110,6 +110,8 @@ spawnclasses
1520 = DukePlayerTorso
1528 = DukePlayerGun
1536 = DukePlayerLeg
2370 = DukeGreenSlime
595 = DukeGenericDestructible, "GRATE1", "BGRATE1", "VENT_BUST", solid, unblocking
1113 = DukeGenericDestructible, "CIRCLEPANNEL", "CIRCLEPANNELBROKE", "VENT_BUST", unblocking

View file

@ -87,6 +87,7 @@ version "4.10"
#include "zscript/games/duke/actors/destructibles.zs"
#include "zscript/games/duke/actors/ducktarget.zs"
#include "zscript/games/duke/actors/helicopt.zs"
#include "zscript/games/duke/actors/greenslime.zs"
#include "zscript/games/duke/actors/redneckmisc.zs"
#include "zscript/games/duke/actors/rabbitspawner.zs"

View file

@ -54,6 +54,7 @@ class CoreActor native
native float alpha;
native double clipdist;
native double angle;
native double pitch;
native Vector3 vel;
native double viewzoffset;

View file

@ -0,0 +1,411 @@
class DukeGreenSlime : DukeActor
{
default
{
spriteset "GREENSLIME", "GREENSLIME1", "GREENSLIME2", "GREENSLIME3", "GREENSLIME4", "GREENSLIME5", "GREENSLIME6", "GREENSLIME7";
scaleX 0.625;
scaleY 0.625;
clipdist 20;
extra 1;
}
override void Initialize()
{
commonEnemySetup();
}
override void PlayFTASound()
{
self.PlayActorSound("SLIM_RECOG");
}
override void Tick()
{
let sectp = self.sector;
int j;
if (self.monsterCheatCheck()) return;
self.temp_data[1] += 128;
if (sectp.floorstat & CSTAT_SECTOR_SKY)
{
self.Destroy();
return;
}
double xx;
DukePlayer p;
[p, xx] = self.findplayer();
let pactor = p.actor;
if (xx > 1280)
{
self.timetosleep++;
if (self.timetosleep > Duke.SLEEPTIME)
{
self.timetosleep = 0;
self.ChangeStat(STAT_ZOMBIEACTOR);
return;
}
}
if (self.temp_data[0] == -5) // FROZEN
{
self.temp_data[3]++;
if (self.temp_data[3] > 280)
{
self.pal = 0;
self.temp_data[0] = 0;
return;
}
self.makeitfall();
self.cstat = CSTAT_SPRITE_BLOCK_ALL;
self.setSpriteSetImage(2);
self.extra = 1;
self.pal = 1;
j = self.ifhitbyweapon();
if (j >= 0)
{
if (self.attackerflag2(SFLAG2_FREEZEDAMAGE))
return;
for (j = 16; j >= 0; j--)
{
let a = frandom(0, 360);
let vel = frandom(0, 2) + 2;
let zvel = 4 - frandom(0, 4);
static const name pieces[] = {'DukeGlassPieces', 'DukeGlassPieces', 'DukeGlassPieces'};
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.PlayActorSound("GLASS_BREAKING");
self.Destroy();
}
else if (xx < 64 && p.quick_kick == 0)
{
let ang = absangle(pactor.angle, (self.pos.XY - pactor.pos.XY).Angle());
if (ang < 22.5)
p.quick_kick = 14;
}
return;
}
if (xx < 99.75)
self.cstat = 0;
else self.cstat = CSTAT_SPRITE_BLOCK_ALL;
if (self.temp_data[0] == -4) //On the player
{
if (pactor.extra < 1)
{
self.temp_data[0] = 0;
return;
}
self.SetPosition(self.pos);
self.angle = pactor.angle;
if ((p.PlayerInput(Duke.SB_FIRE) || (p.quick_kick > 0)) && pactor.extra > 0)
if (p.quick_kick > 0 || (p.curr_weapon != DukeWpn.HANDREMOTE_WEAPON && p.curr_weapon != DukeWpn.HANDBOMB_WEAPON && p.curr_weapon != DukeWpn.TRIPBOMB_WEAPON && p.ammo_amount[p.curr_weapon] >= 0))
{
for (int x = 0; x < 8; x++)
{
let a = frandom(0, 360);
let vel = frandom(0, 4) + 4;
let zvel = -frandom(0, 16) - self.vel.Z * 0.25;
let spawned = dlevel.SpawnActor(self.sector, self.pos.plusZ(-8), "DukeScrap", -8, (0.75, 0.75), a, vel, zvel, self, STAT_MISC);
if (spawned)
{
if (spawned) spawned.spriteextra = DukeScrap.Scrap3 + random(0, 3);
spawned.pal = 6;
}
}
self.PlayActorSound("SLIM_DYING");
self.PlayActorSound("SQUISHED");
if (random(0, 255) < 32)
{
let spawned = self.spawn("DukeBloodPool");
if (spawned) spawned.pal = 0;
}
p.actors_killed++;
self.temp_data[0] = -3;
if (p.somethingonplayer == self)
p.somethingonplayer = nullptr;
self.Destroy();
return;
}
self.pos.Z = pactor.pos.Z + pactor.viewzoffset + 8 + p.pyoff - (self.temp_data[2] + tan(pactor.pitch) * 2048.) * zmaptoworld;
if (self.temp_data[2] > 512)
self.temp_data[2] -= 128;
if (self.temp_data[2] < 348)
self.temp_data[2] += 128;
if (p.newOwner != nullptr)
{
p.newOwner = nullptr;
pactor.restoreloc();
p.cursector = Raze.updatesector(pactor.pos.XY, p.cursector);
DukeStatIterator it;
for (let ac = it.First(STAT_ACTOR); ac; ac = it.Next())
{
if (ac.actorflag2(SFLAG2_CAMERA)) ac.yint = 0;
}
}
if (self.temp_data[3] > 0)
{
static const int frames[] = { 5,5,6,6,7,7,6,5 };
self.setSpriteSetImage(frames[self.temp_data[3]]);
if (self.temp_data[3] == 5)
{
let psp = pactor;
psp.extra -= random(5, 8);
self.PlayActorSound("SLIM_ATTACK");
}
if (self.temp_data[3] < 7) self.temp_data[3]++;
else self.temp_data[3] = 0;
}
else
{
self.setSpriteSetImage(5);
if (Duke.rnd(32))
self.temp_data[3] = 1;
}
double add = (Raze.BobVal(self.temp_data[1]) * 2) * REPEAT_SCALE;
self.scale = (0.3125 + add, 0.234375 + add);
self.pos.XY = pactor.pos.XY + pactor.angle.ToVector() * 8;
return;
}
else if (self.vel.X < 4 && xx < 48)
{
if (p.somethingonplayer == nullptr)
{
p.somethingonplayer = self;
if (self.temp_data[0] == 3 || self.temp_data[0] == 2) //Falling downward
self.temp_data[2] = (12 << 8);
else self.temp_data[2] = -(13 << 8); //Climbing up duke
self.temp_data[0] = -4;
}
}
j = self.ifhitbyweapon();
if (j >= 0)
{
self.PlayActorSound("SLIM_DYING");
if (p.somethingonplayer == self)
p.somethingonplayer = nullptr;
if (self.attackerflag2(SFLAG2_FREEZEDAMAGE))
{
self.PlayActorSound("SOMETHINGFROZE");
self.temp_data[0] = -5; self.temp_data[3] = 0;
return;
}
p.actors_killed++;
if (random(0, 255) < 32)
{
let spawned = self.spawn("DukeBloodPool");
if (spawned) spawned.pal = 0;
}
for (int x = 0; x < 8; x++)
{
let a = frandom(0, 360);
let vel = frandom(0, 4) + 4;
let zvel = -frandom(0, 16) - self.vel.Z * 0.25;
let spawned = dlevel.SpawnActor(self.sector, self.pos.plusZ(-8), "DukeScrap", -8, (0.75, 0.75), a, vel, zvel, self, STAT_MISC);
if (spawned)
{
spawned.spriteextra = DukeScrap.Scrap3 + random(0, 3);
spawned.pal = 6;
}
}
self.temp_data[0] = -3;
self.Destroy();
return;
}
// All weap
if (self.temp_data[0] == -1) //Shrinking down
{
self.makeitfall();
self.cstat &= ~CSTAT_SPRITE_YFLIP;
self.setSpriteSetImage(4);
if (self.scale.X > 0.5 ) self.scale.X += (-random(0, 7)) * REPEAT_SCALE;
if (self.scale.Y > 0.25 ) self.scale.Y += (-random(0, 7)) * REPEAT_SCALE;
else
{
self.scale = (0.625, 0.25);
self.temp_actor = nullptr;
self.temp_data[0] = 0;
}
return;
}
else if (self.temp_data[0] != -2) self.getglobalz();
if (self.temp_data[0] == -2) //On top of somebody (an enemy)
{
DukeActor s5 = self.temp_actor;
self.makeitfall();
if (s5)
{
s5.vel.X = 0;
self.pos = s5.pos + s5.angle.ToVector() * 0.5;
self.setspriteSetImage(Duke.global_random() & 1);
if (self.scale.Y < 1) self.scale.Y += (0.03125);
else
{
if (self.scale.X < 0.5) self.scale.X += (0.0625);
else
{
self.temp_data[0] = -1;
double dist = (self.pos.XY - s5.pos.XY).LengthSquared();
if (dist < 48*48) {
s5.scale.X = 0;
}
}
}
}
return;
}
//Check randomly to see of there is an actor near
if (Duke.rnd(32))
{
DukeSectIterator it;
for (let a2 = it.First(self.sector); a2; a2 = it.Next())
{
if (a2.actorflag1(SFLAG_GREENSLIMEFOOD))
{
double dist = (self.pos.XY - a2.pos.XY).LengthSquared();
if (dist < 48*48 && (abs(self.pos.Z - a2.pos.Z) < 16)) //Gulp them
{
self.temp_actor = a2;
self.temp_data[0] = -2;
self.temp_data[1] = 0;
return;
}
}
}
}
//Moving on the ground or ceiling
if (self.temp_data[0] == 0 || self.temp_data[0] == 2)
{
self.setspriteSetImage(0);
if (random(0, 511) == 0)
self.PlayActorSound("SLIM_ROAM");
if (self.temp_data[0] == 2)
{
self.vel.Z = 0;
self.cstat &= ~CSTAT_SPRITE_YFLIP;
if ((sectp.ceilingstat & CSTAT_SECTOR_SKY) || (self.ceilingz + 24) < self.pos.Z)
{
self.pos.Z += 8;
self.temp_data[0] = 3;
return;
}
}
else
{
self.cstat |= CSTAT_SPRITE_YFLIP;
self.makeitfall();
}
if (PlayClock & 4) self.DoMove(CLIPMASK0);
if (self.vel.X > 6)
{
self.vel.X -= 1/8.;
return;
}
else
{
if (self.vel.X < 2) self.vel.X += 0.25;
self.vel.X = 4 - Raze.BobVal(512 + self.temp_data[1]) * 2;
self.angle += deltaangle(self.angle, (pactor.pos.XY - self.pos.XY).Angle()) * 0.125;
// TJR
}
self.scale.X = (0.5625 + Raze.BobVal(512 + self.temp_data[1]) * 0.125);
self.scale.Y = (0.25 + Raze.BobVal(self.temp_data[1]) * 0.03125);
if (Duke.rnd(4) && (sectp.ceilingstat & CSTAT_SECTOR_SKY) == 0 &&
abs(self.floorz - self.ceilingz) < 192)
{
self.vel.Z = 0;
self.temp_data[0]++;
}
}
if (self.temp_data[0] == 1)
{
self.setspriteSetImage(0);
if (self.scale.Y < 0.625) self.scale.Y += (0.125);
if (self.scale.X > 0.125 ) self.scale.X += (-0.0625);
if (self.vel.Z > -12)
self.vel.Z -= 348 / 256.;
self.pos.Z += self.vel.Z;
if (self.pos.Z < self.ceilingz + 16)
{
self.pos.Z = self.ceilingz + 16;
self.vel.X = 0;
self.temp_data[0] = 2;
}
}
if (self.temp_data[0] == 3)
{
self.setspriteSetImage(1);
self.makeitfall();
if (self.pos.Z > self.floorz - 8)
{
self.scale.Y += (-0.0625);
self.scale.X += (0.03125);
}
else
{
if (self.scale.Y < 0.5625) self.scale.Y += (0.125);
if (self.scale.X > 0.125 ) self.scale.X += (-0.0625);
}
if (self.pos.Z > self.floorz - 8)
{
self.pos.Z = self.floorz - 8;
self.temp_data[0] = 0;
self.vel.X = 0;
}
}
}
}

View file

@ -124,7 +124,7 @@ class DukeActor : CoreActor native
native int saved_ammo;
native int palvals;
native int temp_data[6];
native private int flags1, flags2;
native private int flags1, flags2, flags3;
native walltype temp_walls[2];
native sectortype temp_sect, actorstayput;
@ -132,7 +132,7 @@ class DukeActor : CoreActor native
native Vector3 temp_pos, temp_pos2;
native double temp_angle;
// this is not really usable unless all actors are properly scriptified.
flagdef Inventory: flags1, 0;
flagdef ShrinkAutoaim: flags1, 1;
flagdef Badguy: flags1, 2;
@ -190,6 +190,7 @@ class DukeActor : CoreActor native
virtual void onRespawn(int tag) { }
virtual bool animate(tspritetype tspr) { return false; }
virtual void RunState() {} // this is the CON function.
virtual void PlayFTASound() {}
virtual bool shootthis(DukeActor actor, DukePlayer p, Vector3 pos, double ang) const // this gets called on the defaults.
{
return false;
@ -211,6 +212,7 @@ class DukeActor : CoreActor native
native void setClipDistFromTile();
native void insertspriteq();
native void operateforcefields(int tag);
native void restoreloc();
// temporary flag accessors - need to be eliminated once we can have true actor flags
@ -218,6 +220,34 @@ class DukeActor : CoreActor native
native int actorflag2(int mask);
native int attackerflag1(int mask);
native int attackerflag2(int mask);
void commonEnemySetup(bool countkill = true)
{
if (self.ownerActor != self) self.lotag = 0;
if ((self.lotag > ud.player_skill) || ud.monsters_off == 1)
{
self.scale = (0, 0);
self.ChangeStat(STAT_MISC);
}
else
{
self.makeitfall();
self.cstat |= CSTAT_SPRITE_BLOCK_ALL;
if (countkill)
Duke.GetLocalPlayer().max_actors_killed++;
if (self.ownerActor != self)
{
self.timetosleep = 0;
self.PlayFTASound();
self.ChangeStat(STAT_ACTOR);
}
else self.ChangeStat(STAT_ZOMBIEACTOR);
}
}
}
extend struct _

View file

@ -137,6 +137,9 @@ struct Duke native
SB_INTERFACE_BITS = (SB_WEAPONMASK_BITS | SB_ITEMUSE_BITS | SB_INTERFACE_MASK),
SB_ALL = ~0u
};
const SLEEPTIME = 1536;
native static void PlaySpecialMusic(int which);
native static int PlaySound(Sound num, int channel = CHAN_AUTO, int flags = 0, float vol =0.8f);