From 441d526a15560a8dfd4e38c0d9d75e2597269df0 Mon Sep 17 00:00:00 2001 From: James R Date: Wed, 29 Nov 2023 00:47:48 -0800 Subject: [PATCH 1/3] Hardcode Angel Island scenery objects --- src/deh_tables.c | 22 ++++++ src/info.c | 180 +++++++++++++++++++++++++++++++++++++++++++++++ src/info.h | 31 ++++++++ src/p_mobj.c | 7 ++ 4 files changed, 240 insertions(+) diff --git a/src/deh_tables.c b/src/deh_tables.c index 4e3e668ed..9dfba1898 100644 --- a/src/deh_tables.c +++ b/src/deh_tables.c @@ -4864,6 +4864,21 @@ const char *const STATE_LIST[] = { // array length left dynamic for sanity testi "S_BETA_PARTICLE_WHEEL", "S_BETA_PARTICLE_ICON", "S_BETA_PARTICLE_EXPLOSION", + + // MT_AIZ_REDFERN + "S_AIZFL1", + "S_AIZFR1", + "S_AIZFR2", + "S_AIZTRE", + "S_AIZFR3", + "S_AIZDB1", + "S_AIZDB2", + "S_AIZDB3", + "S_AIZDB4", + "S_AIZDB5", + "S_AIZDB6", + "S_AIZDB7", + "S_AIZDB8", }; // RegEx to generate this from info.h: ^\tMT_([^,]+), --> \t"MT_\1", @@ -6108,6 +6123,13 @@ const char *const MOBJTYPE_LIST[] = { // array length left dynamic for sanity t "MT_BETA_PARTICLE_PHYSICAL", "MT_BETA_PARTICLE_VISUAL", "MT_BETA_PARTICLE_EXPLOSION", + + "MT_AIZ_REDFERN", + "MT_AIZ_FERN1", + "MT_AIZ_FERN2", + "MT_AIZ_TREE", + "MT_AIZ_FERN3", + "MT_AIZ_DDB", }; const char *const MOBJFLAG_LIST[] = { diff --git a/src/info.c b/src/info.c index 79fe99d2a..d503ec927 100644 --- a/src/info.c +++ b/src/info.c @@ -1001,6 +1001,15 @@ char sprnames[NUMSPRITES + 1][5] = "LCLA", + "AIZ1", + "AIZ2", + "AIZ3", + "AIZ4", + "AIZ5", + "AIZ6", + "AZR1", + "AZR2", + // First person view sprites; this is a sprite so that it can be replaced by a specialized MD2 draw later "VIEW", }; @@ -5725,6 +5734,21 @@ state_t states[NUMSTATES] = {SPR_LCLA, 0|FF_FULLBRIGHT|FF_PAPERSPRITE, -1, {NULL}, 0, 0, S_NULL}, // S_BETA_PARTICLE_WHEEL {SPR_LCLA, 1|FF_FULLBRIGHT|FF_PAPERSPRITE, -1, {NULL}, 0, 0, S_NULL}, // S_BETA_PARTICLE_ICON {SPR_LCLA, 2|FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL}, // S_BETA_PARTICLE_EXPLOSION + + // MT_AIZ_REDFERN + {SPR_AIZ1, 0, 1, {NULL}, 0, 0, S_AIZFL1}, // S_AIZFL1 + {SPR_AIZ2, 0, 1, {NULL}, 0, 0, S_AIZFR1}, // S_AIZFR1 + {SPR_AIZ3, 0, 1, {NULL}, 0, 0, S_AIZFR2}, // S_AIZFR2 + {SPR_AIZ4, 0, 1, {NULL}, 0, 0, S_AIZTRE}, // S_AIZTRE + {SPR_AIZ5, 0, 1, {NULL}, 0, 0, S_AIZFR3}, // S_AIZFR3 + {SPR_AIZ6, 0, 10, {NULL}, 0, 0, S_AIZDB2}, // S_AIZDB1 + {SPR_AIZ6, 1, 8, {NULL}, 0, 0, S_AIZDB3}, // S_AIZDB2 + {SPR_AIZ6, 2, 6, {NULL}, 0, 0, S_AIZDB4}, // S_AIZDB3 + {SPR_AIZ6, 3, 6, {NULL}, 0, 0, S_AIZDB5}, // S_AIZDB4 + {SPR_AIZ6, 4, 6, {NULL}, 0, 0, S_AIZDB6}, // S_AIZDB5 + {SPR_AIZ6, 5, 8, {NULL}, 0, 0, S_AIZDB7}, // S_AIZDB6 + {SPR_AIZ6, 6, 8, {NULL}, 0, 0, S_AIZDB8}, // S_AIZDB7 + {SPR_AIZ6, 7, 10, {NULL}, 0, 0, S_AIZDB1}, // S_AIZDB8 }; mobjinfo_t mobjinfo[NUMMOBJTYPES] = @@ -32639,6 +32663,162 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = MF_NOCLIPHEIGHT|MF_NOGRAVITY|MF_SCENERY|MF_DONTENCOREMAP|MF_NOHITLAGFORME|MF_SPECIAL|MF_DONTPUNT, // flags S_NULL // raisestate }, + { // MT_AIZ_REDFERN + 2910, // doomednum + S_AIZFL1, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 0, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 12*FRACUNIT, // radius + 64*FRACUNIT, // height + 0, // dispoffset + 0, // mass + 0, // damage + sfx_None, // activesound + MF_SCENERY, // flags + S_NULL // raisestate + }, + { // MT_AIZ_FERN1 + 2911, // doomednum + S_AIZFR1, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 0, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 72*FRACUNIT, // height + 0, // dispoffset + 0, // mass + 0, // damage + sfx_None, // activesound + MF_SCENERY, // flags + S_NULL // raisestate + }, + { // MT_AIZ_FERN2 + 2912, // doomednum + S_AIZFR2, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 0, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 64*FRACUNIT, // height + 0, // dispoffset + 0, // mass + 0, // damage + sfx_None, // activesound + MF_SCENERY, // flags + S_NULL // raisestate + }, + { // MT_AIZ_TREE + 2913, // doomednum + S_AIZTRE, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 0, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 9*FRACUNIT, // radius + 115*FRACUNIT, // height + 0, // dispoffset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SCENERY|MF_SOLID, // flags + S_NULL // raisestate + }, + { // MT_AIZ_FERN3 + 2914, // doomednum + S_AIZFR3, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 0, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 24*FRACUNIT, // height + 0, // dispoffset + 0, // mass + 0, // damage + sfx_None, // activesound + MF_SCENERY, // flags + S_NULL // raisestate + }, + { // MT_AIZ_DDB + 2915, // doomednum + S_AIZDB1, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 0, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 8*FRACUNIT, // radius + 20*FRACUNIT, // height + 0, // dispoffset + 0, // mass + 0, // damage + sfx_None, // activesound + MF_SCENERY, // flags + S_NULL // raisestate + }, }; diff --git a/src/info.h b/src/info.h index 339b261e0..700eadeea 100644 --- a/src/info.h +++ b/src/info.h @@ -1555,6 +1555,15 @@ typedef enum sprite SPR_LCLA, + SPR_AIZ1, + SPR_AIZ2, + SPR_AIZ3, + SPR_AIZ4, + SPR_AIZ5, + SPR_AIZ6, + SPR_AZR1, + SPR_AZR2, + // First person view sprites; this is a sprite so that it can be replaced by a specialized MD2 draw later SPR_VIEW, @@ -6150,6 +6159,21 @@ typedef enum state S_BETA_PARTICLE_ICON, S_BETA_PARTICLE_EXPLOSION, + // MT_AIZ_REDFERN + S_AIZFL1, + S_AIZFR1, + S_AIZFR2, + S_AIZTRE, + S_AIZFR3, + S_AIZDB1, + S_AIZDB2, + S_AIZDB3, + S_AIZDB4, + S_AIZDB5, + S_AIZDB6, + S_AIZDB7, + S_AIZDB8, + S_FIRSTFREESLOT, S_LASTFREESLOT = S_FIRSTFREESLOT + NUMSTATEFREESLOTS - 1, NUMSTATES @@ -7414,6 +7438,13 @@ typedef enum mobj_type MT_BETA_PARTICLE_VISUAL, MT_BETA_PARTICLE_EXPLOSION, + MT_AIZ_REDFERN, + MT_AIZ_FERN1, + MT_AIZ_FERN2, + MT_AIZ_TREE, + MT_AIZ_FERN3, + MT_AIZ_DDB, + MT_FIRSTFREESLOT, MT_LASTFREESLOT = MT_FIRSTFREESLOT + NUMMOBJFREESLOTS - 1, NUMMOBJTYPES diff --git a/src/p_mobj.c b/src/p_mobj.c index e971299e5..84f793513 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -11070,6 +11070,13 @@ fixed_t P_GetMobjDefaultScale(mobj_t *mobj) return 2*FRACUNIT; case MT_BETA_EMITTER: return 4*FRACUNIT; + case MT_AIZ_REDFERN: + case MT_AIZ_FERN1: + case MT_AIZ_FERN2: + case MT_AIZ_FERN3: + case MT_AIZ_TREE: + case MT_AIZ_DDB: + return 4*FRACUNIT; default: break; } From 69541b942274509543f41f37912399386c94535f Mon Sep 17 00:00:00 2001 From: James R Date: Thu, 7 Dec 2023 00:55:54 -0800 Subject: [PATCH 2/3] Hardcode bustable rocks -- Angel Island + Endless Mine --- src/deh_tables.c | 17 +++ src/info.c | 119 +++++++++++++++++++++ src/info.h | 21 ++++ src/k_objects.h | 7 ++ src/objects/CMakeLists.txt | 1 + src/objects/rocks.cpp | 210 +++++++++++++++++++++++++++++++++++++ src/p_inter.c | 7 ++ src/p_link.cpp | 3 +- src/p_mobj.c | 29 +++++ src/p_spec.c | 16 ++- 10 files changed, 427 insertions(+), 3 deletions(-) create mode 100644 src/objects/rocks.cpp diff --git a/src/deh_tables.c b/src/deh_tables.c index 9dfba1898..3a603086c 100644 --- a/src/deh_tables.c +++ b/src/deh_tables.c @@ -4879,6 +4879,17 @@ const char *const STATE_LIST[] = { // array length left dynamic for sanity testi "S_AIZDB6", "S_AIZDB7", "S_AIZDB8", + + // MT_AZROCKS + "S_AZROCKS", + "S_AZROCKS_RESPAWN", + "S_AZROCKS_PARTICLE1", + + // MT_EMROCKS + "S_EMROCKS", + "S_EMROCKS_RESPAWN", + "S_EMROCKS_PARTICLE1", + "S_EMROCKS_PARTICLE2", }; // RegEx to generate this from info.h: ^\tMT_([^,]+), --> \t"MT_\1", @@ -6130,6 +6141,12 @@ const char *const MOBJTYPE_LIST[] = { // array length left dynamic for sanity t "MT_AIZ_TREE", "MT_AIZ_FERN3", "MT_AIZ_DDB", + + "MT_AZROCKS", + "MT_AZROCKS_PARTICLE", + + "MT_EMROCKS", + "MT_EMROCKS_PARTICLE", }; const char *const MOBJFLAG_LIST[] = { diff --git a/src/info.c b/src/info.c index d503ec927..45c011312 100644 --- a/src/info.c +++ b/src/info.c @@ -1010,6 +1010,10 @@ char sprnames[NUMSPRITES + 1][5] = "AZR1", "AZR2", + "EMR1", + "EMR2", + "EMR3", + // First person view sprites; this is a sprite so that it can be replaced by a specialized MD2 draw later "VIEW", }; @@ -5749,6 +5753,17 @@ state_t states[NUMSTATES] = {SPR_AIZ6, 5, 8, {NULL}, 0, 0, S_AIZDB7}, // S_AIZDB6 {SPR_AIZ6, 6, 8, {NULL}, 0, 0, S_AIZDB8}, // S_AIZDB7 {SPR_AIZ6, 7, 10, {NULL}, 0, 0, S_AIZDB1}, // S_AIZDB8 + + // MT_AZROCKS + {SPR_AZR1, 0, -1, {NULL}, 0, 0, S_AZROCKS}, // S_AZROCKS + {SPR_NULL, 0, -1, {NULL}, 0, 0, S_AZROCKS}, // S_AZROCKS_RESPAWN + {SPR_AZR2, 0, 5*TICRATE, {NULL}, 0, 0, S_NULL}, // S_AZROCKS_PARTICLE1 + + // MT_EMROCKS + {SPR_EMR1, 0, -1, {NULL}, 0, 0, S_EMROCKS}, // S_EMROCKS + {SPR_NULL, 0, -1, {NULL}, 0, 0, S_EMROCKS}, // S_EMROCKS_RESPAWN + {SPR_EMR2, 0, 5*TICRATE, {NULL}, 0, 0, S_NULL}, // S_EMROCKS_PARTICLE1 + {SPR_EMR3, 0, 5*TICRATE, {NULL}, 0, 0, S_NULL}, // S_EMROCKS_PARTICLE2 }; mobjinfo_t mobjinfo[NUMMOBJTYPES] = @@ -32819,6 +32834,110 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = MF_SCENERY, // flags S_NULL // raisestate }, + { // MT_AZROCKS + 470, // doomednum + S_AZROCKS, // spawnstate + 1, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 0, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_s3k59, // deathsound + 0, // speed + 48*FRACUNIT, // radius + 96*FRACUNIT, // height + 0, // dispoffset + 0, // mass + 0, // damage + sfx_None, // activesound + MF_SPECIAL|MF_NOGRAVITY, // flags + S_NULL // raisestate + }, + { // MT_AZROCKS_PARTICLE + -1, // doomednum + S_AZROCKS_PARTICLE1, // spawnstate + 1, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 0, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 32*FRACUNIT, // height + 0, // dispoffset + 0, // mass + 0, // damage + sfx_None, // activesound + MF_NOCLIPHEIGHT|MF_SCENERY|MF_NOBLOCKMAP, // flags + S_NULL // raisestate + }, + { // MT_EMROCKS + 467, // doomednum + S_EMROCKS, // spawnstate + 1, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 0, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_s3k59, // deathsound + 0, // speed + 48*FRACUNIT, // radius + 96*FRACUNIT, // height + 0, // dispoffset + 0, // mass + 0, // damage + sfx_None, // activesound + MF_SPECIAL|MF_NOGRAVITY, // flags + S_NULL // raisestate + }, + { // MT_EMROCKS_PARTICLE + -1, // doomednum + S_EMROCKS_PARTICLE1, // spawnstate + 1, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 0, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 32*FRACUNIT, // height + 0, // dispoffset + 0, // mass + 0, // damage + sfx_None, // activesound + MF_NOCLIPHEIGHT|MF_SCENERY|MF_NOBLOCKMAP, // flags + S_NULL // raisestate + }, }; diff --git a/src/info.h b/src/info.h index 700eadeea..0fbee8940 100644 --- a/src/info.h +++ b/src/info.h @@ -1564,6 +1564,10 @@ typedef enum sprite SPR_AZR1, SPR_AZR2, + SPR_EMR1, + SPR_EMR2, + SPR_EMR3, + // First person view sprites; this is a sprite so that it can be replaced by a specialized MD2 draw later SPR_VIEW, @@ -6174,6 +6178,17 @@ typedef enum state S_AIZDB7, S_AIZDB8, + // MT_AZROCKS + S_AZROCKS, + S_AZROCKS_RESPAWN, + S_AZROCKS_PARTICLE1, + + // MT_EMROCKS + S_EMROCKS, + S_EMROCKS_RESPAWN, + S_EMROCKS_PARTICLE1, + S_EMROCKS_PARTICLE2, + S_FIRSTFREESLOT, S_LASTFREESLOT = S_FIRSTFREESLOT + NUMSTATEFREESLOTS - 1, NUMSTATES @@ -7445,6 +7460,12 @@ typedef enum mobj_type MT_AIZ_FERN3, MT_AIZ_DDB, + MT_AZROCKS, + MT_AZROCKS_PARTICLE, + + MT_EMROCKS, + MT_EMROCKS_PARTICLE, + MT_FIRSTFREESLOT, MT_LASTFREESLOT = MT_FIRSTFREESLOT + NUMMOBJFREESLOTS - 1, NUMMOBJTYPES diff --git a/src/k_objects.h b/src/k_objects.h index c564cc2a9..594d89702 100644 --- a/src/k_objects.h +++ b/src/k_objects.h @@ -339,6 +339,13 @@ void Obj_FuelCanisterTouch(mobj_t *special, mobj_t *toucher); void Obj_FuelCanisterExplosionTouch(mobj_t *special, mobj_t *toucher); boolean Obj_FuelCanisterExplosionThink(mobj_t *mo); +/* Bustable Rocks */ +void Obj_LinkRocks(mobj_t *mo); +void Obj_UnlinkRocks(mobj_t *mo); +void Obj_TouchRocks(mobj_t *special, mobj_t *toucher); +void Obj_UpdateRocks(void); +void Obj_AnimateEndlessMineRocks(mobj_t *mo); + #ifdef __cplusplus } // extern "C" #endif diff --git a/src/objects/CMakeLists.txt b/src/objects/CMakeLists.txt index 3048568ea..c8ed02f59 100644 --- a/src/objects/CMakeLists.txt +++ b/src/objects/CMakeLists.txt @@ -47,6 +47,7 @@ target_sources(SRB2SDL2 PRIVATE crate.cpp spear.cpp fuel.cpp + rocks.cpp ) add_subdirectory(versus) diff --git a/src/objects/rocks.cpp b/src/objects/rocks.cpp new file mode 100644 index 000000000..4a27206e4 --- /dev/null +++ b/src/objects/rocks.cpp @@ -0,0 +1,210 @@ +// DR. ROBOTNIK'S RING RACERS +//----------------------------------------------------------------------------- +// Copyright (C) 2023 by Kart Krew. +// +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. +//----------------------------------------------------------------------------- + +// Original Lua script by Sal +// Hardcoded by jartha + +#include +#include + +#include "../math/fixed.hpp" +#include "../math/vec.hpp" +#include "../mobj.hpp" +#include "../mobj_list.hpp" + +#include "../d_player.h" +#include "../doomstat.h" +#include "../info.h" +#include "../k_objects.h" +#include "../m_fixed.h" +#include "../p_pspr.h" +#include "../sounds.h" +#include "../tables.h" + +using srb2::Mobj; +using srb2::MobjList; +using srb2::math::Fixed; +using srb2::math::Vec2; + +extern mobj_t* svg_rocks; + +namespace +{ + +struct AngelIsland +{ + static constexpr statenum_t kRespawnState = S_AZROCKS_RESPAWN; + static constexpr mobjtype_t kParticleType = MT_AZROCKS_PARTICLE; + static constexpr std::array kParticleStates = {S_AZROCKS_PARTICLE1, S_AZROCKS_PARTICLE1}; +}; + +struct EndlessMine +{ + static constexpr statenum_t kRespawnState = S_EMROCKS_RESPAWN; + static constexpr mobjtype_t kParticleType = MT_EMROCKS_PARTICLE; + static constexpr std::array kParticleStates = {S_EMROCKS_PARTICLE1, S_EMROCKS_PARTICLE2}; +}; + +struct AnyRocks : Mobj +{ + void hnext() = delete; + AnyRocks* next() const { return Mobj::hnext(); } + void next(AnyRocks* n) { Mobj::hnext(n); } + + template + bool visit(F&& visitor); +}; + +template +struct Rocks : AnyRocks +{ + bool busted() const { return state()->num() == Config::kRespawnState; } + + void respawn() + { + if (busted()) + { + tics = 2; // respawn soon + } + } + + void touch(Mobj* toucher) + { + if (busted()) + { + if (tics > 0) + { + tics = 2; // postpone respawn + } + } + else + { + slow(toucher); + bust(toucher); + } + } + +private: + static void slow(Mobj* toucher) + { + const player_t* p = toucher->player; + + if (p->sneakertimer || p->invincibilitytimer || p->growshrinktimer > 0 || p->hyudorotimer) + { + return; + } + + toucher->momx /= 2; + toucher->momy /= 2; + toucher->momz = toucher->flip(std::abs(2 * toucher->momz / 3)); + } + + void bust(Mobj* toucher) + { + vfx(toucher, 1); + vfx(toucher, 2); + vfx(toucher, 3); + + voice(info->deathsound); + state(Config::kRespawnState); + } + + void vfx(Mobj* toucher, int i) + { + fixed_t zvar = flip((i + 1) * 4 * mapobjectscale); + angle_t avar = ANGLE_45 * (i - 2); + + auto part = [&](angle_t angle, statenum_t state) + { + Mobj* h = spawn_from({Vec2 {}, zvar}, Config::kParticleType); + h->state(state); + h->angle = angle; + h->instathrust(angle, 4 * mapobjectscale); + h->momz = zvar; + return h; + }; + + static_assert(Config::kParticleStates.size() == 2); + + part(toucher->angle + ANGLE_90 - avar, Config::kParticleStates[0]); + part(toucher->angle - ANGLE_90 + avar, Config::kParticleStates[1]); + } +}; + +struct AngelIslandRocks : Rocks +{ +}; + +struct EndlessMineRocks : Rocks +{ +}; + +template +bool AnyRocks::visit(F&& visitor) +{ + switch (type) + { + case MT_AZROCKS: + visitor(static_cast(this)); + break; + + case MT_EMROCKS: + visitor(static_cast(this)); + break; + + default: + return false; + } + + return true; +} + +MobjList rocks_list; + +}; // namespace + +void Obj_LinkRocks(mobj_t* mo) +{ + rocks_list.push_front(static_cast(mo)); +} + +void Obj_UnlinkRocks(mobj_t* mo) +{ + rocks_list.erase(static_cast(mo)); +} + +void Obj_TouchRocks(mobj_t* special, mobj_t* toucher) +{ + static_cast(special)->visit([&](auto rocks) { rocks->touch(static_cast(toucher)); }); +} + +void Obj_UpdateRocks(void) +{ + for (AnyRocks* h : rocks_list) + { + h->visit([](auto rocks) { rocks->respawn(); }); + } +} + +void Obj_AnimateEndlessMineRocks(mobj_t *mo) +{ + // sync colors with sky animation + constexpr int kFrames = 8; + constexpr int kDiff = kFrames - 2; + constexpr int kTotal = kFrames + kDiff; + + UINT8 f = ((leveltime / 6) % kTotal); + + if (f >= kFrames) + { + f = kTotal - f; + } + + mo->frame = (mo->frame & ~FF_FRAMEMASK) | f; +} diff --git a/src/p_inter.c b/src/p_inter.c index 4c600ef0b..4a8b3e31b 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -1007,6 +1007,13 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) return; } + case MT_AZROCKS: + case MT_EMROCKS: + { + Obj_TouchRocks(special, toucher); + return; + } + default: // SOC or script pickup P_SetTarget(&special->target, toucher); break; diff --git a/src/p_link.cpp b/src/p_link.cpp index 1bef20bc4..ca13df7fc 100644 --- a/src/p_link.cpp +++ b/src/p_link.cpp @@ -16,7 +16,8 @@ #define LINK_PACK \ svg_battleUfoSpawners,\ - svg_checkpoints + svg_checkpoints,\ + svg_rocks using link = mobj_t*; diff --git a/src/p_mobj.c b/src/p_mobj.c index 84f793513..5772c640e 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -3156,6 +3156,15 @@ boolean P_SceneryZMovement(mobj_t *mo) return false; } break; + case MT_EMROCKS_PARTICLE: + // Hits the ground + if (mo->momz <= 0 && mo->z + mo->momz <= mo->floorz - mo->height) + { + P_KillMobj(mo, NULL, NULL, DMG_NORMAL); + if (P_MobjWasRemoved(mo)) + return false; + } + break; default: break; } @@ -6880,6 +6889,11 @@ static void P_MobjSceneryThink(mobj_t *mobj) } break; } + case MT_EMROCKS_PARTICLE: + { + Obj_AnimateEndlessMineRocks(mobj); + break; + } case MT_VWREF: case MT_VWREB: { @@ -10285,6 +10299,11 @@ static boolean P_MobjRegularThink(mobj_t *mobj) } break; } + case MT_EMROCKS: + { + Obj_AnimateEndlessMineRocks(mobj); + break; + } case MT_BALLOON: { @@ -11793,6 +11812,10 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) case MT_GPZ_SEASAW_SPAWN: Obj_GPZSeasawSpawn(mobj); break; + case MT_AZROCKS: + case MT_EMROCKS: + Obj_LinkRocks(mobj); + break; default: break; } @@ -12067,6 +12090,12 @@ void P_RemoveMobj(mobj_t *mobj) Obj_UnlinkCheckpoint(mobj); break; } + case MT_AZROCKS: + case MT_EMROCKS: + { + Obj_UnlinkRocks(mobj); + break; + } default: { break; diff --git a/src/p_spec.c b/src/p_spec.c index 287a10e92..55d0bcf48 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -1933,12 +1933,14 @@ static void K_HandleLapIncrement(player_t *player) { size_t i = 0; UINT8 nump = 0; - UINT8 lowestLap; + UINT8 lowestLap = UINT8_MAX; for (i = 0; i < MAXPLAYERS; i++) { if (!playeringame[i] || players[i].spectator) continue; + if (players[i].laps < lowestLap) + lowestLap = players[i].laps; nump++; } @@ -2090,7 +2092,17 @@ static void K_HandleLapIncrement(player_t *player) } thwompsactive = true; // Lap 2 effects - lowestLap = P_FindLowestLap(); + + { + UINT8 prevLowest = lowestLap; + + lowestLap = P_FindLowestLap(); + + if (lowestLap > prevLowest) // last place finished the lap + { + Obj_UpdateRocks(); + } + } for (i = 0; i < numlines; i++) { From b68947e636e7728d229ad0f2633cb9f96be1fd71 Mon Sep 17 00:00:00 2001 From: James R Date: Thu, 7 Dec 2023 00:57:17 -0800 Subject: [PATCH 3/3] Hardcode Endless Mine faucet / rain - Note: rain does not use the weather system --- src/deh_tables.c | 14 +++++ src/info.c | 114 ++++++++++++++++++++++++++++++++++ src/info.h | 15 +++++ src/k_objects.h | 5 ++ src/objects/CMakeLists.txt | 1 + src/objects/emz-faucet.cpp | 123 +++++++++++++++++++++++++++++++++++++ src/p_inter.c | 3 + src/p_mobj.c | 12 ++++ 8 files changed, 287 insertions(+) create mode 100644 src/objects/emz-faucet.cpp diff --git a/src/deh_tables.c b/src/deh_tables.c index 3a603086c..135b79456 100644 --- a/src/deh_tables.c +++ b/src/deh_tables.c @@ -4890,6 +4890,15 @@ const char *const STATE_LIST[] = { // array length left dynamic for sanity testi "S_EMROCKS_RESPAWN", "S_EMROCKS_PARTICLE1", "S_EMROCKS_PARTICLE2", + + // MT_EMFAUCET + "S_EMFAUCET", + + // MT_EMFAUCET_DRIP + "S_EMROCKS_DRIP", + + // MT_EMFAUCET_PARTICLE + "S_EMFAUCET_PARTICLE", }; // RegEx to generate this from info.h: ^\tMT_([^,]+), --> \t"MT_\1", @@ -6147,6 +6156,11 @@ const char *const MOBJTYPE_LIST[] = { // array length left dynamic for sanity t "MT_EMROCKS", "MT_EMROCKS_PARTICLE", + + "MT_EMFAUCET", + "MT_EMFAUCET_DRIP", + "MT_EMFAUCET_PARTICLE", + "MT_EMRAINGEN", }; const char *const MOBJFLAG_LIST[] = { diff --git a/src/info.c b/src/info.c index 45c011312..9aecd9d5f 100644 --- a/src/info.c +++ b/src/info.c @@ -1013,6 +1013,7 @@ char sprnames[NUMSPRITES + 1][5] = "EMR1", "EMR2", "EMR3", + "EMFC", // First person view sprites; this is a sprite so that it can be replaced by a specialized MD2 draw later "VIEW", @@ -5764,6 +5765,15 @@ state_t states[NUMSTATES] = {SPR_NULL, 0, -1, {NULL}, 0, 0, S_EMROCKS}, // S_EMROCKS_RESPAWN {SPR_EMR2, 0, 5*TICRATE, {NULL}, 0, 0, S_NULL}, // S_EMROCKS_PARTICLE1 {SPR_EMR3, 0, 5*TICRATE, {NULL}, 0, 0, S_NULL}, // S_EMROCKS_PARTICLE2 + + // MT_EMFAUCET + {SPR_EMFC, 0, -1, {NULL}, 0, 0, S_EMFAUCET}, // S_EMFAUCET + + // MT_EMFAUCET_DRIP + {SPR_EMFC, 1, -1, {NULL}, 0, 0, S_EMROCKS_DRIP}, // S_EMROCKS_DRIP + + // MT_EMFAUCET_PARTICLE + {SPR_EMFC, 2, -1, {NULL}, 0, 0, S_EMFAUCET_PARTICLE}, // S_EMFAUCET_PARTICLE }; mobjinfo_t mobjinfo[NUMMOBJTYPES] = @@ -32938,6 +32948,110 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = MF_NOCLIPHEIGHT|MF_SCENERY|MF_NOBLOCKMAP, // flags S_NULL // raisestate }, + { // MT_EMFAUCET + 468, // doomednum + S_EMFAUCET, // spawnstate + 1, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 0, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 24*FRACUNIT, // radius + 24*FRACUNIT, // height + 1, // dispoffset + 0, // mass + 0, // damage + sfx_None, // activesound + MF_NOGRAVITY|MF_NOBLOCKMAP|MF_SCENERY, // flags + S_NULL // raisestate + }, + { // MT_EMFAUCET_DRIP + -1, // doomednum + S_EMROCKS_DRIP, // spawnstate + 1, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 0, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 4*FRACUNIT, // radius + 8*FRACUNIT, // height + 0, // dispoffset + 0, // mass + 0, // damage + sfx_None, // activesound + MF_NOCLIPHEIGHT|MF_SCENERY|MF_NOBLOCKMAP, // flags + S_NULL // raisestate + }, + { // MT_EMFAUCET_PARTICLE + -1, // doomednum + S_EMFAUCET_PARTICLE, // spawnstate + 1, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 0, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 4*FRACUNIT, // radius + 8*FRACUNIT, // height + 0, // dispoffset + 0, // mass + 0, // damage + sfx_None, // activesound + MF_NOCLIPHEIGHT|MF_SCENERY|MF_NOBLOCKMAP, // flags + S_NULL // raisestate + }, + { // MT_EMRAINGEN + 469, // doomednum + S_INVISIBLE, // spawnstate + 1, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 0, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 0, // radius + 0, // height + 0, // dispoffset + 0, // mass + 0, // damage + sfx_None, // activesound + MF_NOGRAVITY|MF_NOBLOCKMAP|MF_SCENERY, // flags + S_NULL // raisestate + }, }; diff --git a/src/info.h b/src/info.h index 0fbee8940..71c103b7b 100644 --- a/src/info.h +++ b/src/info.h @@ -1567,6 +1567,7 @@ typedef enum sprite SPR_EMR1, SPR_EMR2, SPR_EMR3, + SPR_EMFC, // First person view sprites; this is a sprite so that it can be replaced by a specialized MD2 draw later SPR_VIEW, @@ -6189,6 +6190,15 @@ typedef enum state S_EMROCKS_PARTICLE1, S_EMROCKS_PARTICLE2, + // MT_EMFAUCET + S_EMFAUCET, + + // MT_EMFAUCET_DRIP + S_EMROCKS_DRIP, + + // MT_EMFAUCET_PARTICLE + S_EMFAUCET_PARTICLE, + S_FIRSTFREESLOT, S_LASTFREESLOT = S_FIRSTFREESLOT + NUMSTATEFREESLOTS - 1, NUMSTATES @@ -7466,6 +7476,11 @@ typedef enum mobj_type MT_EMROCKS, MT_EMROCKS_PARTICLE, + MT_EMFAUCET, + MT_EMFAUCET_DRIP, + MT_EMFAUCET_PARTICLE, + MT_EMRAINGEN, + MT_FIRSTFREESLOT, MT_LASTFREESLOT = MT_FIRSTFREESLOT + NUMMOBJFREESLOTS - 1, NUMMOBJTYPES diff --git a/src/k_objects.h b/src/k_objects.h index 594d89702..9584f7ef9 100644 --- a/src/k_objects.h +++ b/src/k_objects.h @@ -346,6 +346,11 @@ void Obj_TouchRocks(mobj_t *special, mobj_t *toucher); void Obj_UpdateRocks(void); void Obj_AnimateEndlessMineRocks(mobj_t *mo); +/* Enldess Mine Faucet */ +void Obj_EMZFaucetThink(mobj_t *mo); +void Obj_EMZDripDeath(mobj_t *mo); +void Obj_EMZRainGenerator(mobj_t *mo); + #ifdef __cplusplus } // extern "C" #endif diff --git a/src/objects/CMakeLists.txt b/src/objects/CMakeLists.txt index c8ed02f59..f920b7d78 100644 --- a/src/objects/CMakeLists.txt +++ b/src/objects/CMakeLists.txt @@ -48,6 +48,7 @@ target_sources(SRB2SDL2 PRIVATE spear.cpp fuel.cpp rocks.cpp + emz-faucet.cpp ) add_subdirectory(versus) diff --git a/src/objects/emz-faucet.cpp b/src/objects/emz-faucet.cpp new file mode 100644 index 000000000..f31a19fa3 --- /dev/null +++ b/src/objects/emz-faucet.cpp @@ -0,0 +1,123 @@ +// DR. ROBOTNIK'S RING RACERS +//----------------------------------------------------------------------------- +// Copyright (C) 2023 by Kart Krew. +// +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. +//----------------------------------------------------------------------------- + +// Original Lua script by Sal +// Hardcoded by jartha + +// Faucet & rain effect +// I actually thought these were a hazard until I went back and looked at the original game... +// I just never got hit by 'em, so I assumed they were hazardous! +// In that same research session, I noticed the tiny droplet effect at the only "exposed" sky area... + +#include "../mobj.hpp" + +#include "../doomdef.h" +#include "../info.h" +#include "../k_objects.h" +#include "../m_fixed.h" +#include "../m_random.h" +#include "../tables.h" +#include "../p_slopes.h" +#include "../r_defs.h" +#include "../r_main.h" +#include "../r_sky.h" + +using srb2::Mobj; + +namespace +{ + +struct Drip : Mobj +{ + void splatter() + { + vfx(0); + vfx(90); + vfx(180); + vfx(270); + } + +private: + void vfx(int deg) + { + Mobj* h = spawn(pos(), MT_EMFAUCET_PARTICLE); + h->angle = (deg + P_RandomKey(PR_DECORATION, 90)) * ANG1; + h->instathrust(h->angle, 8 * h->scale()); + h->momz = h->flip(4 * h->scale()); + } +}; + +struct Faucet : Mobj +{ + void tick() + { + if (leveltime % (4*TICRATE) == 0) + { + spawn(pos(), MT_EMFAUCET_DRIP); + } + } +}; + +struct RainGenerator : Mobj +{ + void tick() + { + if (leveltime % 2) + { + return; + } + + for (int i = 0; i < 16; ++i) + { + if (rain()) + { + break; + } + } + } + +private: + bool rain() + { + auto rng = [](int x, int y) { return P_RandomRange(PR_DECORATION, x, y); }; + + const fixed_t x = this->x + (rng(-15, 15) * 256 * scale()); + const fixed_t y = this->y + (rng(-15, 15) * 256 * scale()); + + const sector_t* sector = R_PointInSubsector(x, y)->sector; + + if (sector->ceilingpic != skyflatnum) + { + return false; + } + + Mobj* h = spawn({x, y, P_GetSectorCeilingZAt(sector, x, y)}, MT_EMFAUCET_PARTICLE); + h->angle = rng(0, 359) * ANG1; + h->instathrust(h->angle, 4 * h->scale()); + + return true; + } +}; + +}; // namespace + +void Obj_EMZFaucetThink(mobj_t* mo) +{ + static_cast(mo)->tick(); +} + +void Obj_EMZDripDeath(mobj_t* mo) +{ + static_cast(mo)->splatter(); +} + +void Obj_EMZRainGenerator(mobj_t* mo) +{ + static_cast(mo)->tick(); +} diff --git a/src/p_inter.c b/src/p_inter.c index 4a8b3e31b..1b6441575 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -2353,6 +2353,9 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget case MT_BLENDEYE_PUYO: VS_PuyoDeath(target); break; + case MT_EMFAUCET_DRIP: + Obj_EMZDripDeath(target); + break; default: break; } diff --git a/src/p_mobj.c b/src/p_mobj.c index 5772c640e..3f2ec5672 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -3157,6 +3157,8 @@ boolean P_SceneryZMovement(mobj_t *mo) } break; case MT_EMROCKS_PARTICLE: + case MT_EMFAUCET_DRIP: + case MT_EMFAUCET_PARTICLE: // Hits the ground if (mo->momz <= 0 && mo->z + mo->momz <= mo->floorz - mo->height) { @@ -6894,6 +6896,16 @@ static void P_MobjSceneryThink(mobj_t *mobj) Obj_AnimateEndlessMineRocks(mobj); break; } + case MT_EMFAUCET: + { + Obj_EMZFaucetThink(mobj); + return; + } + case MT_EMRAINGEN: + { + Obj_EMZRainGenerator(mobj); + return; + } case MT_VWREF: case MT_VWREB: {