diff --git a/src/mobj.hpp b/src/mobj.hpp new file mode 100644 index 000000000..2a330727e --- /dev/null +++ b/src/mobj.hpp @@ -0,0 +1,195 @@ +// 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 mobj_hpp +#define mobj_hpp + +#include + +#include "math/fixed.hpp" +#include "math/vec.hpp" + +#include "info.h" +#include "p_local.h" +#include "p_mobj.h" +#include "s_sound.h" +#include "sounds.h" +#include "typedef.h" + +namespace srb2 +{ + +struct Mobj : mobj_t +{ + // TODO: Vec3 would be nice + struct PosArg + { + math::Fixed x, y, z; + + PosArg() : PosArg(0, 0, 0) {} + PosArg(fixed_t x_, fixed_t y_, fixed_t z_) : x(x_), y(y_), z(z_) {} + + template + PosArg(math::Vec2 p, fixed_t z) : PosArg(p.x, p.y, z) {} + + PosArg(const mobj_t* mobj) : PosArg(mobj->x, mobj->y, mobj->z) {} + }; + + // ManagedPtr(mobj_t::target); wrapper around a reference + // counted mobj pointer. Assigning the wrapper updates + // the original pointer and performs reference counting. + struct ManagedPtr + { + ManagedPtr(mobj_t*& ref) : ref_(ref) {} + ManagedPtr& operator=(mobj_t* ptr) + { + P_SetTarget(&ref_, ptr); + return *this; + } + operator mobj_t*() const { return ref_; } + + private: + mobj_t*& ref_; + }; + + + // + // Validity checks + // + + static bool valid(const Mobj* mobj) { return !P_MobjWasRemoved(mobj); } // safe for nullptr + bool valid() const { return Mobj::valid(this); } + + void remove() { P_RemoveMobj(this); } + + + // + // Spawning + // + + // Mobj_t::spawn; spawn Mobj at position. Mobj inherits map defaults (scale, gravity). + template + static T* spawn(const PosArg& p, mobjtype_t type) { return static_cast(P_SpawnMobj(p.x, p.y, p.z, type)); } + + // this->spawn_from; spawn Mobj relative to parent (this->pos + p). Mobj inherits parent scale, gravity. + template + T* spawn_from(const PosArg& p, mobjtype_t type) + { + return static_cast(P_SpawnMobjFromMobjUnscaled(this, p.x, p.y, p.z, type)); + } + + template + T* spawn_from(mobjtype_t type) { return spawn_from({}, type); } + + // TODO: ghosts have unique properties, add Ghost class + Mobj* spawn_ghost() { return static_cast(P_SpawnGhostMobj(this)); } + + + // + // Position + // + + PosArg center() const { return {x, y, z + (height / 2)}; } + PosArg pos() const { return {x, y, z}; } + math::Vec2 pos2d() const { return {x, y}; } + math::Fixed top() const { return z + height; } + + bool is_flipped() const { return eflags & MFE_VERTICALFLIP; } + math::Fixed flip(fixed_t x) const { return x * P_MobjFlip(this); } + + // Collision helper + bool z_overlaps(const Mobj* b) const { return z < b->top() && b->z < top(); } + + void move_origin(const PosArg& p) { P_MoveOrigin(this, p.x, p.y, p.z); } + void set_origin(const PosArg& p) { P_SetOrigin(this, p.x, p.y, p.z); } + void instathrust(angle_t angle, fixed_t speed) { P_InstaThrust(this, angle, speed); } + void thrust(angle_t angle, fixed_t speed) { P_Thrust(this, angle, speed); } + + + // + // Mobj pointers + // + +#define MOBJ_PTR_METHOD(member) \ + template \ + T* member() const { return static_cast(mobj_t::member); }\ + template \ + void member(T* n) { ManagedPtr(this->mobj_t::member) = n; } + + MOBJ_PTR_METHOD(hnext) + MOBJ_PTR_METHOD(hprev) + MOBJ_PTR_METHOD(itnext) + MOBJ_PTR_METHOD(target) + MOBJ_PTR_METHOD(tracer) + MOBJ_PTR_METHOD(punt_ref) + MOBJ_PTR_METHOD(owner) + +#undef MOBJ_PTR_METHOD + + + // + // State + // + + struct State : state_t + { + statenum_t num() const { return static_cast(static_cast(this) - states); } + }; + + void state(statenum_t state) { P_SetMobjState(this, state); } + const State* state() const { return static_cast(mobj_t::state); } + + + // + // Scale + // + + math::Fixed scale() const { return mobj_t::scale; } + + void scale(fixed_t n) + { + mobj_t::scale = n; + mobj_t::destscale = n; + } + + void scale_to(fixed_t stop, std::optional speed = {}) + { + mobj_t::destscale = stop; + + if (speed) + { + mobj_t::scalespeed = *speed; + } + } + + void scale_between(fixed_t start, fixed_t stop, std::optional speed = {}) + { + mobj_t::scale = start; + scale_to(stop, speed); + } + + + // + // Sound + // + + void voice(sfxenum_t sfx, int volume = 255) const { S_StartSoundAtVolume(this, sfx, volume); } + bool voice_playing(sfxenum_t sfx) const { return S_SoundPlaying(this, sfx); } + void voice_loop(sfxenum_t sfx, int volume = 255) const + { + if (!voice_playing(sfx)) + { + voice(sfx, volume); + } + } +}; + +}; // namespace srb2 + +#endif/*mobj_hpp*/ diff --git a/src/objects/mega-barrier.cpp b/src/objects/mega-barrier.cpp index cfdd4f077..258b6717a 100644 --- a/src/objects/mega-barrier.cpp +++ b/src/objects/mega-barrier.cpp @@ -9,6 +9,8 @@ #include +#include "../mobj.hpp" + #include "../doomdef.h" #include "../d_player.h" #include "../g_game.h" @@ -23,45 +25,13 @@ #define barrier_player(o) ((o)->extravalue1) +using srb2::Mobj; + 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) {} - }; - - static bool valid(const Mobj* mobj) { return !P_MobjWasRemoved(mobj); } - - PosArg center() const { return {x, y, z + (height / 2)}; } - - template - T* spawn_offset(mobjtype_t type) { return static_cast(P_SpawnMobjFromMobj(this, 0, 0, 0, type)); } - - void state(statenum_t state) { P_SetMobjState(this, state); } - statenum_t statenum() const { return static_cast(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 @@ -87,7 +57,7 @@ struct Barrier : Mobj static Barrier* spawn(Player* player, statenum_t state, int idx) { - Barrier* child = player->mobj()->spawn_offset(MT_MEGABARRIER); + Barrier* child = player->mobj()->spawn_from(MT_MEGABARRIER); child->angle = player->mobj()->angle + (idx * kSpinGap); child->player(player); diff --git a/src/s_sound.c b/src/s_sound.c index 33cf4c3be..90cc11fb8 100644 --- a/src/s_sound.c +++ b/src/s_sound.c @@ -1090,7 +1090,7 @@ INT32 S_IdPlaying(sfxenum_t id) // Searches through the channels and checks for // origin x playing sound id y. -INT32 S_SoundPlaying(void *origin, sfxenum_t id) +INT32 S_SoundPlaying(const void *origin, sfxenum_t id) { INT32 cnum; if (!origin) diff --git a/src/s_sound.h b/src/s_sound.h index bb20f8994..3ad5b65cc 100644 --- a/src/s_sound.h +++ b/src/s_sound.h @@ -248,7 +248,7 @@ void S_SetMusicVolume(void); INT32 S_OriginPlaying(void *origin); INT32 S_IdPlaying(sfxenum_t id); -INT32 S_SoundPlaying(void *origin, sfxenum_t id); +INT32 S_SoundPlaying(const void *origin, sfxenum_t id); void S_StartSoundName(void *mo, const char *soundname);