From c01a29c42a90ad3b257868eda3bf9c02ce4a8e3e Mon Sep 17 00:00:00 2001 From: James R Date: Thu, 29 Jun 2023 18:51:13 -0700 Subject: [PATCH] Add Power-Up Aura - Spawns on player when they use their first power-up - Lasts as long as player has any power-up - A hexagon of animated, additive, fullbright papersprites surround and move with the player, takes player's angle --- src/k_objects.h | 4 ++ src/k_powerup.cpp | 18 ++++++ src/k_powerup.h | 1 + src/objects/CMakeLists.txt | 1 + src/objects/powerup-aura.cpp | 121 +++++++++++++++++++++++++++++++++++ src/p_mobj.c | 8 +++ 6 files changed, 153 insertions(+) create mode 100644 src/objects/powerup-aura.cpp diff --git a/src/k_objects.h b/src/k_objects.h index cd645a1e7..b5cbb6e70 100644 --- a/src/k_objects.h +++ b/src/k_objects.h @@ -161,6 +161,10 @@ void Obj_SuperFlickyPlayerCollide(mobj_t *flicky, mobj_t *player); void Obj_SuperFlickyLanding(mobj_t *flicky); boolean Obj_IsSuperFlickyWhippable(const mobj_t *flicky); +/* Power-Up Aura */ +void Obj_SpawnPowerUpAura(player_t* player); +void Obj_PowerUpAuraThink(mobj_t* mobj); + #ifdef __cplusplus } // extern "C" #endif diff --git a/src/k_powerup.cpp b/src/k_powerup.cpp index a452d307e..84a1e27f3 100644 --- a/src/k_powerup.cpp +++ b/src/k_powerup.cpp @@ -25,8 +25,26 @@ tic_t K_PowerUpRemaining(const player_t* player, kartitems_t powerup) } } +boolean K_AnyPowerUpRemaining(const player_t* player) +{ + for (int k = FIRSTPOWERUP; k < ENDOFPOWERUPS; ++k) + { + if (K_PowerUpRemaining(player, static_cast(k))) + { + return true; + } + } + + return false; +} + void K_GivePowerUp(player_t* player, kartitems_t powerup, tic_t time) { + if (!K_AnyPowerUpRemaining(player)) + { + Obj_SpawnPowerUpAura(player); + } + switch (powerup) { case POWERUP_SMONITOR: diff --git a/src/k_powerup.h b/src/k_powerup.h index 736ce68fe..0598e45ce 100644 --- a/src/k_powerup.h +++ b/src/k_powerup.h @@ -9,6 +9,7 @@ extern "C" { #endif tic_t K_PowerUpRemaining(const player_t *player, kartitems_t powerup); +boolean K_AnyPowerUpRemaining(const player_t *player); void K_GivePowerUp(player_t *player, kartitems_t powerup, tic_t timer); void K_DropPowerUps(player_t *player); diff --git a/src/objects/CMakeLists.txt b/src/objects/CMakeLists.txt index 1bbf55729..2c1e68030 100644 --- a/src/objects/CMakeLists.txt +++ b/src/objects/CMakeLists.txt @@ -22,4 +22,5 @@ target_sources(SRB2SDL2 PRIVATE gachabom-rebound.cpp servant-hand.c super-flicky.cpp + powerup-aura.cpp ) diff --git a/src/objects/powerup-aura.cpp b/src/objects/powerup-aura.cpp new file mode 100644 index 000000000..80620010d --- /dev/null +++ b/src/objects/powerup-aura.cpp @@ -0,0 +1,121 @@ +#include "../info.h" +#include "../g_game.h" +#include "../m_fixed.h" +#include "../k_objects.h" +#include "../k_powerup.h" +#include "../p_local.h" +#include "../p_mobj.h" +#include "../tables.h" + +// copied from objects/monitor.c +#define FINE90 (FINEANGLES/4) +#define FINE180 (FINEANGLES/2) +#define TRUETAN(n) FINETANGENT(FINE90 + (n)) // bruh + +#define part_theta(o) ((o)->movedir) +#define part_seek(o) ((o)->extravalue1) + +namespace +{ + +constexpr int kSpriteWidth = 32; +constexpr int kNumSides = 6; + +struct Aura : mobj_t +{ + angle_t theta() const { return part_theta(this); } + void theta(angle_t n) { part_theta(this) = n; } + + unsigned seek() const { return part_seek(this); } + void seek(unsigned n) { part_seek(this) = n; } + + mobj_t* origin() const { return players[seek()].mo; } + + static void spawn(int player) + { + const fixed_t angle_factor = ANGLE_MAX / kNumSides; + + angle_t ang = 0u; + + for (int i = 0; i < kNumSides; ++i) + { + Aura* x = static_cast(P_SpawnMobj(0, 0, 0, MT_POWERUP_AURA)); + + x->theta(ang); + x->seek(player); + + ang += angle_factor; + } + } + + // copied from objects/monitor.c + static fixed_t get_inradius(fixed_t length) + { + return FixedDiv(length, 2 * TRUETAN(FINE180 / kNumSides)); + } + + bool valid() const + { + if (seek() >= MAXPLAYERS) + { + return false; + } + + if (!playeringame[seek()]) + { + return false; + } + + if (!K_AnyPowerUpRemaining(&players[seek()])) + { + return false; + } + + return true; + } + + void move() + { + if (P_MobjWasRemoved(origin())) + { + return; + } + + P_MoveOrigin(this, origin()->x, origin()->y, origin()->z); + P_InstaScale(this, 11 * origin()->scale / 10); + + translate(); + } + + void translate() + { + const fixed_t width = scale * kSpriteWidth; + const fixed_t rad = get_inradius(width); + const angle_t ang = theta() + origin()->angle; + + angle = (ang - ANGLE_90); + + sprxoff = FixedMul(FCOS(ang), rad); + spryoff = FixedMul(FSIN(ang), rad); + } +}; + +}; // namespace + +void Obj_SpawnPowerUpAura(player_t* player) +{ + Aura::spawn(player - players); +} + +void Obj_PowerUpAuraThink(mobj_t* mobj) +{ + Aura* x = static_cast(mobj); + + if (!x->valid()) + { + P_RemoveMobj(x); + return; + } + + x->move(); +} diff --git a/src/p_mobj.c b/src/p_mobj.c index a700dcac7..5e89fefbf 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -6698,6 +6698,14 @@ static void P_MobjSceneryThink(mobj_t *mobj) case MT_SUPER_FLICKY_CONTROLLER: Obj_SuperFlickyControllerThink(mobj); + if (P_MobjWasRemoved(mobj)) + { + return; + } + break; + case MT_POWERUP_AURA: + Obj_PowerUpAuraThink(mobj); + if (P_MobjWasRemoved(mobj)) { return;