From dc20fca17dc49d2c8360157c865244bfb3c76683 Mon Sep 17 00:00:00 2001 From: James R Date: Thu, 7 Dec 2023 14:35:47 -0800 Subject: [PATCH 1/8] Broly: convert to C++ --- src/objects/CMakeLists.txt | 2 +- src/objects/broly.c | 77 --------------------------- src/objects/broly.cpp | 106 +++++++++++++++++++++++++++++++++++++ 3 files changed, 107 insertions(+), 78 deletions(-) delete mode 100644 src/objects/broly.c create mode 100644 src/objects/broly.cpp diff --git a/src/objects/CMakeLists.txt b/src/objects/CMakeLists.txt index b7dda6caf..73a671802 100644 --- a/src/objects/CMakeLists.txt +++ b/src/objects/CMakeLists.txt @@ -8,7 +8,7 @@ target_sources(SRB2SDL2 PRIVATE orbinaut.c jawz.c duel-bomb.c - broly.c + broly.cpp ufo.c monitor.c item-spot.c diff --git a/src/objects/broly.c b/src/objects/broly.c deleted file mode 100644 index 2419fac10..000000000 --- a/src/objects/broly.c +++ /dev/null @@ -1,77 +0,0 @@ -#include "../doomdef.h" -#include "../info.h" -#include "../k_kart.h" -#include "../k_objects.h" -#include "../m_easing.h" -#include "../p_local.h" -#include "../s_sound.h" - -/* An object may not be visible on the same tic: - 1) that it spawned - 2) that it cycles to the next state */ -#define BUFFER_TICS (2) - -#define broly_duration(o) ((o)->extravalue1) -#define broly_maxscale(o) ((o)->extravalue2) - -static inline fixed_t -get_unit_linear (const mobj_t *x) -{ - const tic_t t = (x->tics - BUFFER_TICS); - - return t * FRACUNIT / broly_duration(x); -} - -mobj_t * -Obj_SpawnBrolyKi -( mobj_t * source, - tic_t duration) -{ - mobj_t *x; - - if (duration <= 0) - { - return NULL; - } - - x = P_SpawnMobjFromMobj( - source, 0, 0, 0, MT_BROLY); - - P_SetTarget(&x->target, source); - - // Shrink into center of source object. - x->z = (source->z + source->height / 2); - - x->colorized = true; - x->color = source->color; - x->hitlag = 0; // do not copy source hitlag - - broly_maxscale(x) = 64 * mapobjectscale; - broly_duration(x) = duration; - - x->tics = (duration + BUFFER_TICS); - - K_ReduceVFXForEveryone(x); - - S_StartSound(x, sfx_cdfm74); - - return x; -} - -boolean -Obj_BrolyKiThink (mobj_t *x) -{ - if (broly_duration(x) <= 0) - { - P_RemoveMobj(x); - return false; - } - - const fixed_t - t = get_unit_linear(x), - n = Easing_OutSine(t, 0, broly_maxscale(x)); - - P_InstaScale(x, n); - - return true; -} diff --git a/src/objects/broly.cpp b/src/objects/broly.cpp new file mode 100644 index 000000000..ebca879af --- /dev/null +++ b/src/objects/broly.cpp @@ -0,0 +1,106 @@ +// DR. ROBOTNIK'S RING RACERS +//----------------------------------------------------------------------------- +// Copyright (C) 2023 by James Robert Roman +// +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. +//----------------------------------------------------------------------------- + +#include "../math/fixed.hpp" +#include "../mobj.hpp" + +#include "../doomdef.h" +#include "../info.h" +#include "../k_kart.h" +#include "../k_objects.h" +#include "../m_easing.h" +#include "../p_local.h" +#include "../s_sound.h" + +using srb2::Mobj; +using srb2::math::Fixed; + +namespace +{ + +struct Broly : Mobj +{ + /* An object may not be visible on the same tic: + 1) that it spawned + 2) that it cycles to the next state */ + static constexpr int kBufferTics = 2; + + void extravalue1() = delete; + tic_t duration() const { return mobj_t::extravalue1; } + void duration(tic_t n) { mobj_t::extravalue1 = n; } + + void extravalue2() = delete; + Fixed max_scale() const { return mobj_t::extravalue2; } + void max_scale(Fixed n) { mobj_t::extravalue2 = n; } + + bool valid() const { return duration(); } + + tic_t remaining() const { return tics - kBufferTics; } + + Fixed linear() const { return (remaining() * FRACUNIT) / duration(); } + + static Broly* spawn(Mobj* source, tic_t duration) + { + if (duration == 0) + { + return nullptr; + } + + Broly* x = source->spawn_from({}, MT_BROLY); + + x->target(source); + + // Shrink into center of source object. + x->z = (source->z + source->height / 2); + + x->colorized = true; + x->color = source->color; + x->mobj_t::hitlag = 0; // do not copy source hitlag + + x->max_scale(64 * mapobjectscale); + x->duration(duration); + + x->tics = (duration + kBufferTics); + + K_ReduceVFXForEveryone(x); + + x->voice(sfx_cdfm74); + + return x; + } + + bool think() + { + if (!valid()) + { + remove(); + return false; + } + + scale(Easing_OutSine(linear(), 0, max_scale())); + + return true; + } +}; + +}; // namespace + +mobj_t * +Obj_SpawnBrolyKi +( mobj_t * source, + tic_t duration) +{ + return Broly::spawn(static_cast(source), duration); +} + +boolean +Obj_BrolyKiThink (mobj_t *x) +{ + return static_cast(x)->think(); +} From c5f421831f7075d54813a633e7b1ca7287a81fb2 Mon Sep 17 00:00:00 2001 From: James R Date: Thu, 7 Dec 2023 15:42:14 -0800 Subject: [PATCH 2/8] Broly: customize scale start/end --- src/objects/broly.cpp | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/src/objects/broly.cpp b/src/objects/broly.cpp index ebca879af..18d3df972 100644 --- a/src/objects/broly.cpp +++ b/src/objects/broly.cpp @@ -8,6 +8,7 @@ //----------------------------------------------------------------------------- #include "../math/fixed.hpp" +#include "../math/vec.hpp" #include "../mobj.hpp" #include "../doomdef.h" @@ -20,6 +21,7 @@ using srb2::Mobj; using srb2::math::Fixed; +using srb2::math::Vec2; namespace { @@ -35,9 +37,14 @@ struct Broly : Mobj tic_t duration() const { return mobj_t::extravalue1; } void duration(tic_t n) { mobj_t::extravalue1 = n; } + void threshold() = delete; void extravalue2() = delete; - Fixed max_scale() const { return mobj_t::extravalue2; } - void max_scale(Fixed n) { mobj_t::extravalue2 = n; } + Vec2 size() const { return {mobj_t::threshold, mobj_t::extravalue2}; } + void size(const Vec2& n) + { + mobj_t::threshold = n.x; + mobj_t::extravalue2 = n.y; + } bool valid() const { return duration(); } @@ -45,7 +52,7 @@ struct Broly : Mobj Fixed linear() const { return (remaining() * FRACUNIT) / duration(); } - static Broly* spawn(Mobj* source, tic_t duration) + static Broly* spawn(Mobj* source, tic_t duration, const Vec2& size) { if (duration == 0) { @@ -63,7 +70,7 @@ struct Broly : Mobj x->color = source->color; x->mobj_t::hitlag = 0; // do not copy source hitlag - x->max_scale(64 * mapobjectscale); + x->size(size); x->duration(duration); x->tics = (duration + kBufferTics); @@ -83,7 +90,9 @@ struct Broly : Mobj return false; } - scale(Easing_OutSine(linear(), 0, max_scale())); + const Vec2 v = size(); + + scale(Easing_OutSine(linear(), v.y, v.x)); return true; } @@ -96,7 +105,7 @@ Obj_SpawnBrolyKi ( mobj_t * source, tic_t duration) { - return Broly::spawn(static_cast(source), duration); + return Broly::spawn(static_cast(source), duration, {64 * mapobjectscale, 0}); } boolean From a96a64dff654fe66ae12bdb630e9bc43175ddc39 Mon Sep 17 00:00:00 2001 From: James R Date: Thu, 7 Dec 2023 15:42:58 -0800 Subject: [PATCH 3/8] Broly: scale hitbox --- src/info.c | 4 ++-- src/objects/broly.cpp | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/info.c b/src/info.c index 4e64a278a..b86c14411 100644 --- a/src/info.c +++ b/src/info.c @@ -30674,8 +30674,8 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed - 0, // radius - 0, // height + 40*FRACUNIT, // radius + 80*FRACUNIT, // height 0, // display offset 100, // mass 1, // damage diff --git a/src/objects/broly.cpp b/src/objects/broly.cpp index 18d3df972..76d8df3da 100644 --- a/src/objects/broly.cpp +++ b/src/objects/broly.cpp @@ -64,7 +64,7 @@ struct Broly : Mobj x->target(source); // Shrink into center of source object. - x->z = (source->z + source->height / 2); + x->z = source->center().z - (x->height / 2); x->colorized = true; x->color = source->color; @@ -90,9 +90,11 @@ struct Broly : Mobj return false; } + const Fixed center = z + (height / 2); const Vec2 v = size(); scale(Easing_OutSine(linear(), v.y, v.x)); + z = center - (height / 2); return true; } From 11555a2a3c2f5fe9107819dd167d930c78702c36 Mon Sep 17 00:00:00 2001 From: James R Date: Thu, 7 Dec 2023 16:06:22 -0800 Subject: [PATCH 4/8] Add objects/objects.hpp, common header for object classes --- src/objects/objects.hpp | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 src/objects/objects.hpp diff --git a/src/objects/objects.hpp b/src/objects/objects.hpp new file mode 100644 index 000000000..dd8869ccc --- /dev/null +++ b/src/objects/objects.hpp @@ -0,0 +1,19 @@ +#ifndef objects_objects_hpp +#define objects_objects_hpp + +#include "../math/fixed.hpp" +#include "../math/vec.hpp" +#include "../mobj.hpp" + +#include "../k_objects.h" + +namespace srb2::objects +{ + +using srb2::Mobj; +using srb2::math::Fixed; +using srb2::math::Vec2; + +}; // namespace srb2::objects + +#endif/*objects_objects_hpp*/ From b5062e862716fdeaf771cd635d3fb93379edc4fc Mon Sep 17 00:00:00 2001 From: James R Date: Thu, 7 Dec 2023 16:07:21 -0800 Subject: [PATCH 5/8] Broly: move Broly class into srb2::objects namespace --- src/objects/broly.cpp | 95 ++--------------------------------------- src/objects/broly.hpp | 98 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 101 insertions(+), 92 deletions(-) create mode 100644 src/objects/broly.hpp diff --git a/src/objects/broly.cpp b/src/objects/broly.cpp index 76d8df3da..7cd575d13 100644 --- a/src/objects/broly.cpp +++ b/src/objects/broly.cpp @@ -7,100 +7,11 @@ // See the 'LICENSE' file for more details. //----------------------------------------------------------------------------- -#include "../math/fixed.hpp" -#include "../math/vec.hpp" -#include "../mobj.hpp" +#include "broly.hpp" -#include "../doomdef.h" -#include "../info.h" -#include "../k_kart.h" -#include "../k_objects.h" -#include "../m_easing.h" -#include "../p_local.h" -#include "../s_sound.h" +#include "../doomstat.h" -using srb2::Mobj; -using srb2::math::Fixed; -using srb2::math::Vec2; - -namespace -{ - -struct Broly : Mobj -{ - /* An object may not be visible on the same tic: - 1) that it spawned - 2) that it cycles to the next state */ - static constexpr int kBufferTics = 2; - - void extravalue1() = delete; - tic_t duration() const { return mobj_t::extravalue1; } - void duration(tic_t n) { mobj_t::extravalue1 = n; } - - void threshold() = delete; - void extravalue2() = delete; - Vec2 size() const { return {mobj_t::threshold, mobj_t::extravalue2}; } - void size(const Vec2& n) - { - mobj_t::threshold = n.x; - mobj_t::extravalue2 = n.y; - } - - bool valid() const { return duration(); } - - tic_t remaining() const { return tics - kBufferTics; } - - Fixed linear() const { return (remaining() * FRACUNIT) / duration(); } - - static Broly* spawn(Mobj* source, tic_t duration, const Vec2& size) - { - if (duration == 0) - { - return nullptr; - } - - Broly* x = source->spawn_from({}, MT_BROLY); - - x->target(source); - - // Shrink into center of source object. - x->z = source->center().z - (x->height / 2); - - x->colorized = true; - x->color = source->color; - x->mobj_t::hitlag = 0; // do not copy source hitlag - - x->size(size); - x->duration(duration); - - x->tics = (duration + kBufferTics); - - K_ReduceVFXForEveryone(x); - - x->voice(sfx_cdfm74); - - return x; - } - - bool think() - { - if (!valid()) - { - remove(); - return false; - } - - const Fixed center = z + (height / 2); - const Vec2 v = size(); - - scale(Easing_OutSine(linear(), v.y, v.x)); - z = center - (height / 2); - - return true; - } -}; - -}; // namespace +using namespace srb2::objects; mobj_t * Obj_SpawnBrolyKi diff --git a/src/objects/broly.hpp b/src/objects/broly.hpp new file mode 100644 index 000000000..df8ce7587 --- /dev/null +++ b/src/objects/broly.hpp @@ -0,0 +1,98 @@ +// DR. ROBOTNIK'S RING RACERS +//----------------------------------------------------------------------------- +// Copyright (C) 2023 by James Robert Roman +// +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. +//----------------------------------------------------------------------------- + +#ifndef objects_broly_hpp +#define objects_broly_hpp + +#include "objects.hpp" + +#include "../info.h" +#include "../k_kart.h" +#include "../m_easing.h" + +namespace srb2::objects +{ + +struct Broly : Mobj +{ + /* An object may not be visible on the same tic: + 1) that it spawned + 2) that it cycles to the next state */ + static constexpr int kBufferTics = 2; + + void extravalue1() = delete; + tic_t duration() const { return mobj_t::extravalue1; } + void duration(tic_t n) { mobj_t::extravalue1 = n; } + + void threshold() = delete; + void extravalue2() = delete; + Vec2 size() const { return {mobj_t::threshold, mobj_t::extravalue2}; } + void size(const Vec2& n) + { + mobj_t::threshold = n.x; + mobj_t::extravalue2 = n.y; + } + + bool valid() const { return duration(); } + + tic_t remaining() const { return tics - kBufferTics; } + + Fixed linear() const { return (remaining() * FRACUNIT) / duration(); } + + static Broly* spawn(Mobj* source, tic_t duration, const Vec2& size) + { + if (duration == 0) + { + return nullptr; + } + + Broly* x = source->spawn_from({}, MT_BROLY); + + x->target(source); + + // Shrink into center of source object. + x->z = source->center().z - (x->height / 2); + + x->colorized = true; + x->color = source->color; + x->mobj_t::hitlag = 0; // do not copy source hitlag + + x->size(size); + x->duration(duration); + + x->tics = (duration + kBufferTics); + + K_ReduceVFXForEveryone(x); + + x->voice(sfx_cdfm74); + + return x; + } + + bool think() + { + if (!valid()) + { + remove(); + return false; + } + + const Fixed center = z + (height / 2); + const Vec2 v = size(); + + scale(Easing_OutSine(linear(), v.y, v.x)); + z = center - (height / 2); + + return true; + } +}; + +}; // namespace srb2::objects + +#endif/*objects_broly_hpp*/ From df023246a5087adcc871e07f5b6cdd8c01d770ab Mon Sep 17 00:00:00 2001 From: James R Date: Thu, 7 Dec 2023 16:17:59 -0800 Subject: [PATCH 6/8] Broly: separate explosion behavior from main class --- src/objects/broly.cpp | 12 +++++++++++- src/objects/broly.hpp | 22 ++++++++++------------ 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/src/objects/broly.cpp b/src/objects/broly.cpp index 7cd575d13..fe2f43726 100644 --- a/src/objects/broly.cpp +++ b/src/objects/broly.cpp @@ -10,6 +10,8 @@ #include "broly.hpp" #include "../doomstat.h" +#include "../k_kart.h" +#include "../sounds.h" using namespace srb2::objects; @@ -18,7 +20,15 @@ Obj_SpawnBrolyKi ( mobj_t * source, tic_t duration) { - return Broly::spawn(static_cast(source), duration, {64 * mapobjectscale, 0}); + Broly* x = Broly::spawn(static_cast(source), duration, {64 * mapobjectscale, 0}); + + x->colorized = true; + x->color = source->color; + + K_ReduceVFXForEveryone(x); + x->voice(sfx_cdfm74); + + return x; } boolean diff --git a/src/objects/broly.hpp b/src/objects/broly.hpp index df8ce7587..d75a7fc4b 100644 --- a/src/objects/broly.hpp +++ b/src/objects/broly.hpp @@ -10,10 +10,11 @@ #ifndef objects_broly_hpp #define objects_broly_hpp +#include + #include "objects.hpp" #include "../info.h" -#include "../k_kart.h" #include "../m_easing.h" namespace srb2::objects @@ -21,6 +22,8 @@ namespace srb2::objects struct Broly : Mobj { + static constexpr mobjtype_t kMobjType = MT_BROLY; + /* An object may not be visible on the same tic: 1) that it spawned 2) that it cycles to the next state */ @@ -45,33 +48,28 @@ struct Broly : Mobj Fixed linear() const { return (remaining() * FRACUNIT) / duration(); } - static Broly* spawn(Mobj* source, tic_t duration, const Vec2& size) + template + static T* spawn(Mobj* source, tic_t duration, const Vec2& size) { + static_assert(std::is_base_of_v); + if (duration == 0) { return nullptr; } - Broly* x = source->spawn_from({}, MT_BROLY); + T* x = Mobj::spawn(source->center(), T::kMobjType); x->target(source); // Shrink into center of source object. - x->z = source->center().z - (x->height / 2); - - x->colorized = true; - x->color = source->color; - x->mobj_t::hitlag = 0; // do not copy source hitlag + x->z -= x->height / 2; x->size(size); x->duration(duration); x->tics = (duration + kBufferTics); - K_ReduceVFXForEveryone(x); - - x->voice(sfx_cdfm74); - return x; } From f6ce183ceea738dc4ece94767075a17888fa7822 Mon Sep 17 00:00:00 2001 From: James R Date: Thu, 7 Dec 2023 19:18:33 -0800 Subject: [PATCH 7/8] Add Lost Colony Fuel Canister states --- src/deh_tables.c | 9 ++++ src/info.c | 110 +++++++++++++++++++++++++++++++++++++++++++++++ src/info.h | 11 +++++ src/p_mobj.c | 2 + src/sounds.c | 2 + src/sounds.h | 3 ++ 6 files changed, 137 insertions(+) diff --git a/src/deh_tables.c b/src/deh_tables.c index 78d6a6422..4e3e668ed 100644 --- a/src/deh_tables.c +++ b/src/deh_tables.c @@ -4860,6 +4860,10 @@ const char *const STATE_LIST[] = { // array length left dynamic for sanity testi // MT_BSZSLAMP "S_BSWL", "S_BSWC", + + "S_BETA_PARTICLE_WHEEL", + "S_BETA_PARTICLE_ICON", + "S_BETA_PARTICLE_EXPLOSION", }; // RegEx to generate this from info.h: ^\tMT_([^,]+), --> \t"MT_\1", @@ -6099,6 +6103,11 @@ const char *const MOBJTYPE_LIST[] = { // array length left dynamic for sanity t "MT_BSZLAMP_L", "MT_BSZSLAMP", "MT_BSZSLCHA", + + "MT_BETA_EMITTER", + "MT_BETA_PARTICLE_PHYSICAL", + "MT_BETA_PARTICLE_VISUAL", + "MT_BETA_PARTICLE_EXPLOSION", }; const char *const MOBJFLAG_LIST[] = { diff --git a/src/info.c b/src/info.c index b86c14411..58b6e1ad0 100644 --- a/src/info.c +++ b/src/info.c @@ -999,6 +999,8 @@ char sprnames[NUMSPRITES + 1][5] = "BSWL", "BSWC", + "LCLA", + // First person view sprites; this is a sprite so that it can be replaced by a specialized MD2 draw later "VIEW", }; @@ -5719,6 +5721,10 @@ state_t states[NUMSTATES] = // MT_BSZSLAMP {SPR_BSWL, 0|FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL}, // S_BSWL {SPR_BSWC, 0|FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL}, // S_BSWC + + {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 }; mobjinfo_t mobjinfo[NUMMOBJTYPES] = @@ -32529,6 +32535,110 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 0, // flags S_NULL // raisestate }, + { // MT_BETA_EMITTER + 2699, // 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_NOSECTOR|MF_SCENERY, // flags + S_NULL // raisestate + }, + { // MT_BETA_PARTICLE_PHYSICAL + -1, // 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 + 24*FRACUNIT, // radius + 128*FRACUNIT, // height + 0, // dispoffset + 0, // mass + 0, // damage + sfx_None, // activesound + MF_SPECIAL|MF_NOGRAVITY, // flags + S_NULL // raisestate + }, + { // MT_BETA_PARTICLE_VISUAL + -1, // doomednum + S_NULL, // 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_NOCLIPTHING|MF_NOCLIPHEIGHT|MF_NOCLIP|MF_SCENERY|MF_NOGRAVITY, // flags + S_NULL // raisestate + }, + { // MT_BETA_PARTICLE_EXPLOSION + -1, // doomednum + S_BETA_PARTICLE_EXPLOSION, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // 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 + 40*FRACUNIT, // radius + 80*FRACUNIT, // height + 0, // display offset + 100, // mass + 1, // damage + sfx_None, // activesound + MF_NOCLIPHEIGHT|MF_NOGRAVITY|MF_SCENERY|MF_DONTENCOREMAP|MF_NOHITLAGFORME|MF_SPECIAL|MF_DONTPUNT, // flags + S_NULL // raisestate + }, }; diff --git a/src/info.h b/src/info.h index 52c1b5942..339b261e0 100644 --- a/src/info.h +++ b/src/info.h @@ -1553,6 +1553,8 @@ typedef enum sprite SPR_BSWL, SPR_BSWC, + SPR_LCLA, + // First person view sprites; this is a sprite so that it can be replaced by a specialized MD2 draw later SPR_VIEW, @@ -6144,6 +6146,10 @@ typedef enum state S_BSWL, S_BSWC, + S_BETA_PARTICLE_WHEEL, + S_BETA_PARTICLE_ICON, + S_BETA_PARTICLE_EXPLOSION, + S_FIRSTFREESLOT, S_LASTFREESLOT = S_FIRSTFREESLOT + NUMSTATEFREESLOTS - 1, NUMSTATES @@ -7403,6 +7409,11 @@ typedef enum mobj_type MT_BSZSLAMP, MT_BSZSLCHA, + MT_BETA_EMITTER, + MT_BETA_PARTICLE_PHYSICAL, + MT_BETA_PARTICLE_VISUAL, + MT_BETA_PARTICLE_EXPLOSION, + MT_FIRSTFREESLOT, MT_LASTFREESLOT = MT_FIRSTFREESLOT + NUMMOBJFREESLOTS - 1, NUMMOBJTYPES diff --git a/src/p_mobj.c b/src/p_mobj.c index a21d676cb..555b2da35 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -11031,6 +11031,8 @@ fixed_t P_GetMobjDefaultScale(mobj_t *mobj) return 2*FRACUNIT; case MT_SPEAR: return 2*FRACUNIT; + case MT_BETA_EMITTER: + return 4*FRACUNIT; default: break; } diff --git a/src/sounds.c b/src/sounds.c index 1c9a5b841..9d0722e2a 100644 --- a/src/sounds.c +++ b/src/sounds.c @@ -1251,6 +1251,8 @@ sfxinfo_t S_sfx[NUMSFX] = {"ivobal", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, // Ivo Ball + {"lcfuel", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Fuel Capsule explodes"}, + // Damage sounds {"dmga1", false, 255, 8, -1, NULL, 0, -1, -1, LUMPERROR, "Damaged"}, {"dmga2", false, 255, 8, -1, NULL, 0, -1, -1, LUMPERROR, "Damaged"}, diff --git a/src/sounds.h b/src/sounds.h index 88ba458e4..9b31bb293 100644 --- a/src/sounds.h +++ b/src/sounds.h @@ -1323,6 +1323,9 @@ typedef enum // Ivo Ball sfx_ivobal, + // Fuel Capsule + sfx_lcfuel, + // Damage sounds sfx_dmga1, sfx_dmga2, From 5cba9d63b3f644113bcfd4852b117a3a7d88ce3f Mon Sep 17 00:00:00 2001 From: James R Date: Thu, 7 Dec 2023 19:19:02 -0800 Subject: [PATCH 8/8] Hardcode Lost Colony Fuel Canisters --- src/k_objects.h | 9 ++ src/objects/CMakeLists.txt | 1 + src/objects/fuel.cpp | 236 +++++++++++++++++++++++++++++++++++++ src/p_inter.c | 12 ++ src/p_mobj.c | 31 +++++ 5 files changed, 289 insertions(+) create mode 100644 src/objects/fuel.cpp diff --git a/src/k_objects.h b/src/k_objects.h index 215b4b84f..e3960513a 100644 --- a/src/k_objects.h +++ b/src/k_objects.h @@ -332,6 +332,15 @@ void Obj_TryCrateDamage(mobj_t *target, mobj_t *inflictor); void Obj_SpearInit(mobj_t *mo); void Obj_SpearThink(mobj_t *mo); +/* Lost Colony Fuel Canister */ +void Obj_FuelCanisterEmitterInit(mobj_t *mo); +boolean Obj_FuelCanisterVisualThink(mobj_t *mo); +boolean Obj_FuelCanisterEmitterThink(mobj_t *mo); +boolean Obj_FuelCanisterThink(mobj_t *mo); +void Obj_FuelCanisterTouch(mobj_t *special, mobj_t *toucher); +void Obj_FuelCanisterExplosionTouch(mobj_t *special, mobj_t *toucher); +boolean Obj_FuelCanisterExplosionThink(mobj_t *mo); + #ifdef __cplusplus } // extern "C" #endif diff --git a/src/objects/CMakeLists.txt b/src/objects/CMakeLists.txt index 73a671802..3048568ea 100644 --- a/src/objects/CMakeLists.txt +++ b/src/objects/CMakeLists.txt @@ -46,6 +46,7 @@ target_sources(SRB2SDL2 PRIVATE ivoball.cpp crate.cpp spear.cpp + fuel.cpp ) add_subdirectory(versus) diff --git a/src/objects/fuel.cpp b/src/objects/fuel.cpp new file mode 100644 index 000000000..53e4ccfcd --- /dev/null +++ b/src/objects/fuel.cpp @@ -0,0 +1,236 @@ +// DR. ROBOTNIK'S RING RACERS +//----------------------------------------------------------------------------- +// Copyright (C) 2023 by James Robert Roman +// +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. +//----------------------------------------------------------------------------- + +#include "broly.hpp" +#include "objects.hpp" + +#include "../doomdef.h" +#include "../doomstat.h" +#include "../info.h" +#include "../k_objects.h" +#include "../sounds.h" +#include "../tables.h" + +using namespace srb2::objects; + +namespace +{ + +struct FuelCanister : Mobj +{ + struct Emitter : Mobj + { + void thing_args() = delete; + tic_t frequency() const { return mobj_t::thing_args[0]; } + tic_t initial_timer() const { return mobj_t::thing_args[1]; } + + void extravalue1() = delete; + tic_t timer() const { return mobj_t::extravalue1; } + void timer(tic_t n) { mobj_t::extravalue1 = n; } + + void init() + { + timer(initial_timer()); + } + + bool think() + { + if (timer() > 0) + { + timer(timer() - 1); + return true; + } + + timer(frequency()); + + FuelCanister::spawn(this); + + return true; + } + }; + + struct Vis : Mobj + { + void extravalue1() = delete; + angle_t phys_angle_ofs() const { return mobj_t::extravalue1; } + void phys_angle_ofs(angle_t n) { mobj_t::extravalue1 = n; } + + void extravalue2() = delete; + angle_t vis_angle_ofs() const { return mobj_t::extravalue2; } + void vis_angle_ofs(angle_t n) { mobj_t::extravalue2 = n; } + + bool valid() const { return Mobj::valid() && Mobj::valid(target()); } + + bool think() + { + if (!valid()) + { + remove(); + return false; + } + + const angle_t angleOutward = target()->angle + phys_angle_ofs(); + + move_origin({target()->pos2d() + (vector(angleOutward) * Fixed {radius}), target()->z}); + angle = angleOutward + vis_angle_ofs(); + + return true; + } + }; + + struct Explosion : Broly + { + static constexpr mobjtype_t kMobjType = MT_BETA_PARTICLE_EXPLOSION; + + static Explosion* spawn(Mobj* source) + { + Explosion* x = Broly::spawn(source, 3*TICRATE, {1, 8 * mapobjectscale}); + x->voice(sfx_lcfuel); + return x; + } + + void touch(Mobj* toucher) + { + if (!P_DamageMobj(toucher, this, this, 1, DMG_NORMAL)) + { + auto& hitlag = toucher->mobj_t::hitlag; + + // Hitlag = remaining duration of explosion + if (hitlag >= 0 && hitlag + 0u < remaining()) + { + hitlag = remaining(); + } + } + } + + bool think() { return Broly::think(); } + }; + + bool valid() const { return Mobj::valid() && momz; } + + static FuelCanister* spawn(Mobj* source) + { + FuelCanister* caps = source->spawn_from({}, MT_BETA_PARTICLE_PHYSICAL); + caps->init(); + return caps; + } + + void init() + { + momz = 8 * scale(); + z -= momz; + + pieces(); + pieces(); + } + + bool think() + { + if (!valid()) + { + remove(); + return false; + } + + angle += 8 * ANG1; + + return true; + } + + void touch(Mobj* toucher) + { + Explosion::spawn(toucher); + } + +private: + struct Wheel + { + static constexpr int kSides = 6; + static constexpr statenum_t kState = S_BETA_PARTICLE_WHEEL; + static constexpr int kRadius = 8; + static constexpr Fixed kScale = FRACUNIT; + static constexpr angle_t kAngleOffset = 0; + static constexpr int kZOffset = 0; + }; + + struct Icon + { + static constexpr int kSides = 2; + static constexpr statenum_t kState = S_BETA_PARTICLE_ICON; + static constexpr int kRadius = 8; + static constexpr Fixed kScale = 3*FRACUNIT/4; + static constexpr angle_t kAngleOffset = ANGLE_90; + static constexpr int kZOffset = 64; + }; + + static Vec2 vector(angle_t angle) { return {FCOS(angle), FSIN(angle)}; } + + template + void pieces() + { + constexpr angle_t kAngleBetween = ANGLE_MAX / Config::kSides; + + const Fixed zOfs = Config::kZOffset * (Fixed {FRACUNIT} / Config::kScale); + const Fixed radius = Config::kRadius * scale(); + const Fixed scale = Config::kScale * this->scale(); + + for (int i = 1; i <= Config::kSides; ++i) + { + angle_t angleOutward = i * kAngleBetween; + + Vis* vis = spawn_from({vector(angle + angleOutward) * radius, 0}, MT_BETA_PARTICLE_VISUAL); + + vis->state(Config::kState); + vis->target(this); + vis->scale(scale); + vis->radius = radius; + vis->spriteyoffset(zOfs); + + vis->phys_angle_ofs(angleOutward); + vis->vis_angle_ofs(Config::kAngleOffset); + } + } +}; + +}; // namespace + +void Obj_FuelCanisterEmitterInit(mobj_t *mo) +{ + static_cast(mo)->init(); +} + +boolean Obj_FuelCanisterVisualThink(mobj_t *mo) +{ + return static_cast(mo)->think(); +} + +boolean Obj_FuelCanisterEmitterThink(mobj_t *mo) +{ + return static_cast(mo)->think(); +} + +boolean Obj_FuelCanisterThink(mobj_t *mo) +{ + return static_cast(mo)->think(); +} + +void Obj_FuelCanisterTouch(mobj_t *special, mobj_t *toucher) +{ + static_cast(special)->touch(static_cast(toucher)); +} + +void Obj_FuelCanisterExplosionTouch(mobj_t *special, mobj_t *toucher) +{ + static_cast(special)->touch(static_cast(toucher)); +} + +boolean Obj_FuelCanisterExplosionThink(mobj_t *mo) +{ + return static_cast(mo)->think(); +} diff --git a/src/p_inter.c b/src/p_inter.c index 05fb78b3d..4c600ef0b 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -995,6 +995,18 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) return; } + case MT_BETA_PARTICLE_PHYSICAL: + { + Obj_FuelCanisterTouch(special, toucher); + break; + } + + case MT_BETA_PARTICLE_EXPLOSION: + { + Obj_FuelCanisterExplosionTouch(special, toucher); + return; + } + default: // SOC or script pickup P_SetTarget(&special->target, toucher); break; diff --git a/src/p_mobj.c b/src/p_mobj.c index 555b2da35..a24f35956 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -6859,6 +6859,24 @@ static void P_MobjSceneryThink(mobj_t *mobj) { return; } + case MT_BETA_PARTICLE_VISUAL: + { + Obj_FuelCanisterVisualThink(mobj); + return; + } + case MT_BETA_EMITTER: + { + Obj_FuelCanisterEmitterThink(mobj); + return; + } + case MT_BETA_PARTICLE_EXPLOSION: + { + if (Obj_FuelCanisterExplosionThink(mobj) == false) + { + return; + } + break; + } case MT_VWREF: case MT_VWREB: { @@ -10256,6 +10274,14 @@ static boolean P_MobjRegularThink(mobj_t *mobj) Obj_SidewaysFreezeThrusterThink(mobj); break; } + case MT_BETA_PARTICLE_PHYSICAL: + { + if (!Obj_FuelCanisterThink(mobj)) + { + return false; + } + break; + } default: // check mobj against possible water content, before movement code @@ -14514,6 +14540,11 @@ static boolean P_SetupSpawnedMapThing(mapthing_t *mthing, mobj_t *mobj) Obj_SpearInit(mobj); break; } + case MT_BETA_EMITTER: + { + Obj_FuelCanisterEmitterInit(mobj); + break; + } default: break; }