From 3644f8afe732b02096fbf08544e4a7e3bb533ea3 Mon Sep 17 00:00:00 2001 From: James R Date: Mon, 19 May 2025 18:29:53 -0700 Subject: [PATCH] Add Lightning Shield visual object --- src/info.c | 2 +- src/k_kart.c | 2 + src/k_objects.h | 4 ++ src/objects/CMakeLists.txt | 1 + src/objects/lightning-shield.cpp | 74 ++++++++++++++++++++++++++++++++ src/p_mobj.c | 8 ++++ 6 files changed, 90 insertions(+), 1 deletion(-) create mode 100644 src/objects/lightning-shield.cpp diff --git a/src/info.c b/src/info.c index f51346127..f8c30e83a 100644 --- a/src/info.c +++ b/src/info.c @@ -15373,7 +15373,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = { // MT_LIGHTNINGSHIELD -1, // doomednum - S_LIGHTNINGSHIELD1, // spawnstate + S_INVISIBLE, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound diff --git a/src/k_kart.c b/src/k_kart.c index 4a00a1361..4879bd517 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -14059,6 +14059,8 @@ void K_MoveKartPlayer(player_t *player, boolean onground) P_SetTarget(&shield->target, player->mo); S_StartSound(player->mo, sfx_s3k41); player->curshield = KSHIELD_LIGHTNING; + + Obj_SpawnLightningShieldVisuals(shield); } if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO) diff --git a/src/k_objects.h b/src/k_objects.h index ed0d62022..a3468cb8e 100644 --- a/src/k_objects.h +++ b/src/k_objects.h @@ -453,6 +453,10 @@ void K_DoBallhogAttack(player_t *player, UINT8 num_hogs); void Obj_SpawnBubbleShieldVisuals(mobj_t *source); boolean Obj_TickBubbleShieldVisual(mobj_t *mobj); +/* Lightning Shield */ +void Obj_SpawnLightningShieldVisuals(mobj_t *source); +boolean Obj_TickLightningShieldVisual(mobj_t *mobj); + #ifdef __cplusplus } // extern "C" #endif diff --git a/src/objects/CMakeLists.txt b/src/objects/CMakeLists.txt index 01c773b7d..1b9b26f0f 100644 --- a/src/objects/CMakeLists.txt +++ b/src/objects/CMakeLists.txt @@ -62,6 +62,7 @@ target_sources(SRB2SDL2 PRIVATE ballhog.cpp bubble-shield.cpp flybot767.c + lightning-shield.cpp ) add_subdirectory(versus) diff --git a/src/objects/lightning-shield.cpp b/src/objects/lightning-shield.cpp new file mode 100644 index 000000000..e08e4529c --- /dev/null +++ b/src/objects/lightning-shield.cpp @@ -0,0 +1,74 @@ +// DR. ROBOTNIK'S RING RACERS +//----------------------------------------------------------------------------- +// Copyright (C) 2025 by James Robert Roman +// Copyright (C) 2025 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. +//----------------------------------------------------------------------------- + +#include "objects.hpp" + +#include "../tables.h" + +using namespace srb2::objects; + +namespace +{ + +struct Shield : Mobj +{ + void target() = delete; + Mobj* follow() const { return Mobj::target(); } + void follow(Mobj* n) { Mobj::target(n); } + + bool valid() const { return Mobj::valid(follow()); } +}; + +struct Visual : Mobj +{ + void target() = delete; + Shield* shield() const { return Mobj::target(); } + void shield(Shield* n) { Mobj::target(n); } + + bool valid() const { return Mobj::valid(shield()) && shield()->valid(); } + + static void spawn(Shield* shield) + { + if (!shield->valid()) + return; + + Visual* x = Mobj::spawn(shield->pos(), MT_LIGHTNINGSHIELD_VISUAL); + x->scale(5 * shield->follow()->scale() / 4); + x->shield(shield); + x->linkdraw(shield->follow()); + x->tick(); + } + + bool tick() + { + if (!valid()) + { + remove(); + return false; + } + + move_origin(shield()->pos()); + dispoffset = state()->num() == S_THNB1 ? -1 : 1; + + return true; + } +}; + +}; // namespace + +void Obj_SpawnLightningShieldVisuals(mobj_t *shield) +{ + Visual::spawn(static_cast(shield)); +} + +boolean Obj_TickLightningShieldVisual(mobj_t *mobj) +{ + return static_cast(mobj)->tick(); +} diff --git a/src/p_mobj.c b/src/p_mobj.c index c77e5b0ab..ea6bb86df 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -6666,6 +6666,14 @@ static void P_MobjSceneryThink(mobj_t *mobj) } break; } + case MT_LIGHTNINGSHIELD_VISUAL: + { + if (!Obj_TickLightningShieldVisual(mobj)) + { + return; + } + break; + } default: if (mobj->fuse) { // Scenery object fuse! Very basic!