Mega Barrier for Barrier power-up -- just a visual object

This commit is contained in:
James R 2023-11-16 01:32:12 -08:00
parent 9f088f40bb
commit 1df4094c65
6 changed files with 178 additions and 9 deletions

View file

@ -293,6 +293,9 @@ void Obj_BallSwitchThink(mobj_t *mobj);
void Obj_BallSwitchTouched(mobj_t *mobj, mobj_t *toucher);
void Obj_BallSwitchDamaged(mobj_t *mobj, mobj_t *inflictor, mobj_t *source);
/* Barrier Power-Up */
void Obj_SpawnMegaBarrier(player_t *player);
boolean Obj_MegaBarrierThink(mobj_t *mobj);
#ifdef __cplusplus
} // extern "C"

View file

@ -56,6 +56,7 @@ void K_GivePowerUp(player_t* player, kartitems_t powerup, tic_t time)
case POWERUP_BARRIER:
player->powerup.barrierTimer += time;
Obj_SpawnMegaBarrier(player);
break;
case POWERUP_BUMPER:

View file

@ -40,6 +40,7 @@ target_sources(SRB2SDL2 PRIVATE
shadow.cpp
ball-switch.cpp
charge.c
mega-barrier.cpp
)
add_subdirectory(versus)

View file

@ -5,11 +5,6 @@
#include "../k_kart.h"
#include "../k_powerup.h"
static INT16 guard_upscale (player_t *player)
{
return K_PowerUpRemaining(player, POWERUP_BARRIER) ? 40 : player->spheres;
}
void Obj_BlockRingThink (mobj_t *ring)
{
if (P_MobjWasRemoved(ring->target) || !ring->target->player)
@ -28,7 +23,7 @@ void Obj_BlockRingThink (mobj_t *ring)
ring->color = mo->color;
fixed_t baseScale = mo->scale / 2;
baseScale += (mo->scale / 30) * guard_upscale(player);
baseScale += (mo->scale / 30) * player->spheres;
P_SetScale(ring, baseScale);
// Twirl
@ -41,7 +36,7 @@ void Obj_BlockRingThink (mobj_t *ring)
else
ring->renderflags |= RF_DONTDRAW;
if (!K_PlayerGuard(player))
if (K_PowerUpRemaining(player, POWERUP_BARRIER) || !K_PlayerGuard(player))
ring->renderflags |= RF_DONTDRAW;
}
}
@ -61,7 +56,7 @@ void Obj_BlockBodyThink (mobj_t *body)
body->flags &= ~(MF_NOCLIPTHING);
fixed_t baseScale = mo->scale / 2;
baseScale += (mo->scale / 30) * guard_upscale(player);
baseScale += (mo->scale / 30) * player->spheres;
P_SetScale(body, baseScale);
P_MoveOrigin(body, mo->x, mo->y, mo->z + mo->height/2);
@ -76,7 +71,7 @@ void Obj_BlockBodyThink (mobj_t *body)
else
body->renderflags |= RF_DONTDRAW;
if (!K_PlayerGuard(player))
if (K_PowerUpRemaining(player, POWERUP_BARRIER) || !K_PlayerGuard(player))
body->renderflags |= RF_DONTDRAW;
}
}

View file

@ -0,0 +1,161 @@
// 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 <cstddef>
#include "../doomdef.h"
#include "../d_player.h"
#include "../g_game.h"
#include "../info.h"
#include "../k_kart.h"
#include "../k_objects.h"
#include "../k_powerup.h"
#include "../m_fixed.h"
#include "../p_local.h"
#include "../p_mobj.h"
#include "../r_defs.h"
#define barrier_player(o) ((o)->extravalue1)
namespace
{
struct Barrier;
// TODO: header
struct Mobj : mobj_t
{
struct PosArg
{
fixed_t x, y, z;
PosArg(fixed_t x_, fixed_t y_, fixed_t z_) : x(x_), y(y_), z(z_) {}
PosArg(const mobj_t* mobj) : x(mobj->x), y(mobj->y), z(mobj->z) {}
};
bool valid() const { return !P_MobjWasRemoved(this); }
PosArg center() const { return {x, y, z + (height / 2)}; }
template <typename T>
T* spawn_offset(mobjtype_t type) { return static_cast<T*>(P_SpawnMobjFromMobj(this, 0, 0, 0, type)); }
void state(statenum_t state) { P_SetMobjState(this, state); }
statenum_t statenum() const { return static_cast<statenum_t>(mobj_t::state - states); }
fixed_t scale() const { return mobj_t::scale; }
void scale(fixed_t n)
{
mobj_t::scale = n;
mobj_t::destscale = n;
}
void move_origin(const PosArg& p) { P_MoveOrigin(this, p.x, p.y, p.z); }
void remove() { P_RemoveMobj(this); }
};
struct Player : player_t
{
struct Powerups : powerupvars_t
{
Barrier* barrier() const { return reinterpret_cast<Barrier*>(powerupvars_t::barrier); }
void barrier(Barrier* n) { P_SetTarget(&this->powerupvars_t::barrier, reinterpret_cast<mobj_t*>(n)); }
};
static Player* at(std::size_t i) { return static_cast<Player*>(&players[i]); }
bool valid() const { return this >= players && this < &players[MAXPLAYERS] && playeringame[num()]; }
std::size_t num() const { return this - Player::at(0); }
Mobj* mobj() const { return static_cast<Mobj*>(mo); }
Powerups& powerups() { return static_cast<Powerups&>(player_t::powerup); }
const Powerups& powerups() const { return static_cast<const Powerups&>(player_t::powerup); }
};
struct Barrier : Mobj
{
static constexpr angle_t kSpinSpeed = ANGLE_22h;
static constexpr angle_t kSpinGap = 20*ANG1;
static Barrier* spawn(Player* player, statenum_t state, int idx)
{
Barrier* child = player->mobj()->spawn_offset<Barrier>(MT_MEGABARRIER);
child->angle = player->mobj()->angle + (idx * kSpinGap);
child->player(player);
child->renderflags |= RF_DONTDRAW;
child->state(state);
return child;
}
static void spawn_chain(Player* player)
{
player->powerups().barrier(spawn(player, S_MEGABARRIER1, 0));
spawn(player, S_MEGABARRIER2, 1);
spawn(player, S_MEGABARRIER2, 2);
spawn(player, S_MEGABARRIER2, 3);
spawn(player, S_MEGABARRIER2, 4);
spawn(player, S_MEGABARRIER3, 5);
}
int playernum() const { return barrier_player(this); }
Player* player() const { return Player::at(playernum()); }
void player(player_t* n) { barrier_player(this) = n - players; }
bool valid() const { return Mobj::valid() && player()->valid() && player()->mobj()->valid(); }
bool think()
{
if (!valid() || !K_PowerUpRemaining(player(), POWERUP_BARRIER))
{
remove();
return false;
}
Mobj* source = player()->mobj();
color = source->color;
scale(8 * source->scale() / 9);
move_origin(source->center());
angle += kSpinSpeed;
eflags = (eflags & ~MFE_VERTICALFLIP) | (source->eflags & MFE_VERTICALFLIP);
if (K_PlayerGuard(player()))
{
renderflags &= ~RF_DONTDRAW;
renderflags ^= RF_ADD | RF_TRANS90;
}
else
{
renderflags |= RF_DONTDRAW;
}
return true;
}
};
}; // namespace
void Obj_SpawnMegaBarrier(player_t* p)
{
Player* player = static_cast<Player*>(p);
if (!static_cast<Mobj*>(player->powerups().barrier())->valid())
{
Barrier::spawn_chain(player);
}
}
boolean Obj_MegaBarrierThink(mobj_t* mobj)
{
return static_cast<Barrier*>(mobj)->think();
}

View file

@ -6807,6 +6807,14 @@ static void P_MobjSceneryThink(mobj_t *mobj)
mobj->angle += ANG2;
break;
}
case MT_MEGABARRIER:
{
if (!Obj_MegaBarrierThink(mobj))
{
return;
}
break;
}
case MT_VWREF:
case MT_VWREB:
{