diff --git a/source/core/vmexports.cpp b/source/core/vmexports.cpp index 16fe1726a..f8966f359 100644 --- a/source/core/vmexports.cpp +++ b/source/core/vmexports.cpp @@ -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) diff --git a/source/games/duke/src/actors.cpp b/source/games/duke/src/actors.cpp index 549d14e02..65d4f153d 100644 --- a/source/games/duke/src/actors.cpp +++ b/source/games/duke/src/actors.cpp @@ -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); diff --git a/source/games/duke/src/actors_d.cpp b/source/games/duke/src/actors_d.cpp index 249048bfc..d1df49e55 100644 --- a/source/games/duke/src/actors_d.cpp +++ b/source/games/duke/src/actors_d.cpp @@ -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; } diff --git a/source/games/duke/src/actors_r.cpp b/source/games/duke/src/actors_r.cpp index 50224929f..57b5f7386 100644 --- a/source/games/duke/src/actors_r.cpp +++ b/source/games/duke/src/actors_r.cpp @@ -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; diff --git a/source/games/duke/src/animatesprites_d.cpp b/source/games/duke/src/animatesprites_d.cpp index 69dc7e8d7..49f635a8a 100644 --- a/source/games/duke/src/animatesprites_d.cpp +++ b/source/games/duke/src/animatesprites_d.cpp @@ -58,10 +58,11 @@ void animatesprites_d(tspriteArray& tsprites, const DVector2& viewVec, DAngle vi t = tsprites.get(j); h = static_cast(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; diff --git a/source/games/duke/src/constants.h b/source/games/duke/src/constants.h index e7d5b0466..3c80bb7e0 100644 --- a/source/games/duke/src/constants.h +++ b/source/games/duke/src/constants.h @@ -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; DEFINE_TFLAGS_OPERATORS(EDukeFlags2) +enum sflags3_t +{ + SFLAG3_DONTDIVEALIVE = 0x00000001, + +}; + +using EDukeFlags3 = TFlags; +DEFINE_TFLAGS_OPERATORS(EDukeFlags3) + // these get stored as user flags inside the texture manager. enum { diff --git a/source/games/duke/src/duke3d.h b/source/games/duke/src/duke3d.h index d01ccdba0..9c6bb85c2 100644 --- a/source/games/duke/src/duke3d.h +++ b/source/games/duke/src/duke3d.h @@ -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 diff --git a/source/games/duke/src/flags_d.cpp b/source/games/duke/src/flags_d.cpp index 4167e20c2..2ff54f3a2 100644 --- a/source/games/duke/src/flags_d.cpp +++ b/source/games/duke/src/flags_d.cpp @@ -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; diff --git a/source/games/duke/src/game.cpp b/source/games/duke/src/game.cpp index bab35a048..6b16cb1f5 100644 --- a/source/games/duke/src/game.cpp +++ b/source/games/duke/src/game.cpp @@ -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 diff --git a/source/games/duke/src/inlines.h b/source/games/duke/src/inlines.h index fed3dea99..54911b45c 100644 --- a/source/games/duke/src/inlines.h +++ b/source/games/duke/src/inlines.h @@ -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); diff --git a/source/games/duke/src/namelist_d.h b/source/games/duke/src/namelist_d.h index 5ef9a276d..34d0bd2db 100644 --- a/source/games/duke/src/namelist_d.h +++ b/source/games/duke/src/namelist_d.h @@ -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) diff --git a/source/games/duke/src/namelist_r.h b/source/games/duke/src/namelist_r.h index 98b42a71b..2feab8fa2 100644 --- a/source/games/duke/src/namelist_r.h +++ b/source/games/duke/src/namelist_r.h @@ -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) diff --git a/source/games/duke/src/player_d.cpp b/source/games/duke/src/player_d.cpp index 03f57aedc..5e8e49313 100644 --- a/source/games/duke/src/player_d.cpp +++ b/source/games/duke/src/player_d.cpp @@ -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; diff --git a/source/games/duke/src/savegame.cpp b/source/games/duke/src/savegame.cpp index 3b6caa0c9..b9fd55bc4 100644 --- a/source/games/duke/src/savegame.cpp +++ b/source/games/duke/src/savegame.cpp @@ -286,7 +286,8 @@ void DDukeActor::Serialize(FSerializer& arc) ("temp_sect", temp_sect) ("uservars", uservars) ("flags1", flags1) - ("flags2", flags2); + ("flags2", flags2) + ("flags3", flags3); } diff --git a/source/games/duke/src/sectors_d.cpp b/source/games/duke/src/sectors_d.cpp index 88d0eed36..cfaa1b1e0 100644 --- a/source/games/duke/src/sectors_d.cpp +++ b/source/games/duke/src/sectors_d.cpp @@ -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. { diff --git a/source/games/duke/src/spawn_d.cpp b/source/games/duke/src/spawn_d.cpp index 127cac809..7e7b5970e 100644 --- a/source/games/duke/src/spawn_d.cpp +++ b/source/games/duke/src/spawn_d.cpp @@ -525,10 +525,6 @@ DDukeActor* spawninit_d(DDukeActor* actj, DDukeActor* act, TArray* case BOSS3: case BOSS4: case ROTATEGUN: - case GREENSLIME: - if (act->spr.picnum == GREENSLIME) - act->spr.extra = 1; - [[fallthrough]]; case DRONE: case LIZTROOPONTOILET: case LIZTROOPJUSTSIT: diff --git a/source/games/duke/src/types.h b/source/games/duke/src/types.h index 87edf967d..6abfa80f4 100644 --- a/source/games/duke/src/types.h +++ b/source/games/duke/src/types.h @@ -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; diff --git a/source/games/duke/src/vmexports.cpp b/source/games/duke/src/vmexports.cpp index 290867ec8..3cff9fb14 100644 --- a/source/games/duke/src/vmexports.cpp +++ b/source/games/duke/src/vmexports.cpp @@ -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) diff --git a/wadsrc/static/filter/dukelike/engine/engine.def b/wadsrc/static/filter/dukelike/engine/engine.def index 9a8be40b2..9cf5735ba 100644 --- a/wadsrc/static/filter/dukelike/engine/engine.def +++ b/wadsrc/static/filter/dukelike/engine/engine.def @@ -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 diff --git a/wadsrc/static/zscript.txt b/wadsrc/static/zscript.txt index c40426222..65a2a21ff 100644 --- a/wadsrc/static/zscript.txt +++ b/wadsrc/static/zscript.txt @@ -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" diff --git a/wadsrc/static/zscript/coreactor.zs b/wadsrc/static/zscript/coreactor.zs index 2d5723a49..94ce53181 100644 --- a/wadsrc/static/zscript/coreactor.zs +++ b/wadsrc/static/zscript/coreactor.zs @@ -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; diff --git a/wadsrc/static/zscript/games/duke/actors/greenslime.zs b/wadsrc/static/zscript/games/duke/actors/greenslime.zs new file mode 100644 index 000000000..b6f480b1c --- /dev/null +++ b/wadsrc/static/zscript/games/duke/actors/greenslime.zs @@ -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; + } + } + } +} diff --git a/wadsrc/static/zscript/games/duke/dukeactor.zs b/wadsrc/static/zscript/games/duke/dukeactor.zs index ebbc94c4b..aeb64e5b9 100644 --- a/wadsrc/static/zscript/games/duke/dukeactor.zs +++ b/wadsrc/static/zscript/games/duke/dukeactor.zs @@ -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 _ diff --git a/wadsrc/static/zscript/games/duke/dukegame.zs b/wadsrc/static/zscript/games/duke/dukegame.zs index b41ce4ef5..88dd74818 100644 --- a/wadsrc/static/zscript/games/duke/dukegame.zs +++ b/wadsrc/static/zscript/games/duke/dukegame.zs @@ -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);