Merge branch 'master' of https://git.do.srb2.org/KartKrew/Kart into separate-spb-attack-records

This commit is contained in:
toaster 2024-02-17 23:13:06 +00:00
commit d87fba3f57
20 changed files with 330 additions and 26 deletions

View file

@ -72,6 +72,7 @@ add_executable(SRB2SDL2 MACOSX_BUNDLE WIN32
r_data.c
r_debug.cpp
r_debug_parser.cpp
r_debug_printer.cpp
r_draw.cpp
r_fps.c
r_main.cpp

View file

@ -90,6 +90,7 @@
#include "k_dialogue.h"
#include "k_bans.h"
#include "k_credits.h"
#include "r_debug.hpp"
#ifdef HWRENDER
#include "hardware/hw_main.h" // 3D View Rendering
@ -663,6 +664,7 @@ static bool D_Display(void)
{
AM_Drawer();
ST_Drawer();
srb2::r_debug::draw_frame_list();
F_TextPromptDrawer();
break;
}
@ -858,6 +860,7 @@ void D_SRB2Loop(void)
g_dc = {};
Z_Frame_Reset();
srb2::r_debug::clear_frame_list();
{
// Casting the return value of a function is bad practice (apparently)

View file

@ -965,6 +965,8 @@ struct player_t
mobj_t *hand;
mobj_t *flickyAttacker;
SINT8 pitblame; // Index of last player that hit you, resets after being in control for a bit. If you deathpit, credit the old attacker!
UINT8 instaWhipCharge;
UINT8 defenseLockout; // Committed to universal attack/defense, make 'em vulnerable! No whip/guard.
UINT8 instaWhipChargeLockout; // Input safety
@ -978,9 +980,11 @@ struct player_t
angle_t besthanddirection;
INT16 incontrol; // -1 to -175 when spinning out or tumbling, 1 to 175 when not. Use to check for combo hits or emergency inputs.
UINT16 progressivethrust; // When getting beat up in GTR_BUMPERS, speed up the longer you've been out of control.
boolean markedfordeath;
boolean dotrickfx;
UINT8 bumperinflate;
UINT8 ringboxdelay; // Delay until Ring Box auto-activates
UINT8 ringboxaward; // Where did we stop?

View file

@ -56,6 +56,7 @@
#include "k_follower.h"
#include "k_vote.h"
#include "k_credits.h"
#include "k_grandprix.h"
boolean nodrawers; // for comparative timing purposes
boolean noblit; // for comparative timing purposes
@ -64,7 +65,7 @@ tic_t demostarttime; // for comparative timing purposes
static char demoname[MAX_WADPATH];
static savebuffer_t demobuf = {0};
static UINT8 *demotime_p, *demoinfo_p;
static UINT8 demoflags;
static UINT16 demoflags;
boolean demosynced = true; // console warning message
struct demovars_s demo;
@ -103,7 +104,7 @@ demoghost *ghosts = NULL;
// DEMO RECORDING
//
#define DEMOVERSION 0x0007
#define DEMOVERSION 0x0008
#define DEMOHEADER "\xF0" "KartReplay" "\x0F"
#define DF_ATTACKMASK (ATTACKING_TIME|ATTACKING_LAP|ATTACKING_SPB) // This demo contains time/lap data
@ -117,6 +118,8 @@ demoghost *ghosts = NULL;
#define DF_ENCORE 0x40
#define DF_MULTIPLAYER 0x80 // This demo was recorded in multiplayer mode!
#define DF_GRANDPRIX 0x0100
#define DEMO_SPECTATOR 0x01
#define DEMO_KICKSTART 0x02
#define DEMO_SHRINKME 0x04
@ -2126,6 +2129,9 @@ void G_BeginRecording(void)
if (multiplayer)
demoflags |= DF_LUAVARS;
if (grandprixinfo.gp)
demoflags |= DF_GRANDPRIX;
// Setup header.
M_Memcpy(demobuf.p, DEMOHEADER, 12); demobuf.p += 12;
WRITEUINT8(demobuf.p,VERSION);
@ -2148,7 +2154,7 @@ void G_BeginRecording(void)
WRITESTRINGN(demobuf.p, mapheaderinfo[gamemap-1]->lumpname, MAXMAPLUMPNAME);
M_Memcpy(demobuf.p, mapmd5, 16); demobuf.p += 16;
WRITEUINT8(demobuf.p, demoflags);
WRITEUINT16(demobuf.p, demoflags);
WRITESTRINGN(demobuf.p, gametypes[gametype]->name, MAXGAMETYPELENGTH);
@ -2186,6 +2192,13 @@ void G_BeginRecording(void)
// Save netvar data
CV_SaveDemoVars(&demobuf.p);
if ((demoflags & DF_GRANDPRIX))
{
WRITEUINT8(demobuf.p, grandprixinfo.gamespeed);
WRITEUINT8(demobuf.p, grandprixinfo.masterbots == true);
WRITEUINT8(demobuf.p, grandprixinfo.eventmode);
}
// Now store some info for each in-game player
// Lat' 12/05/19: Do note that for the first game you load, everything that gets saved here is total garbage;
@ -2274,6 +2287,10 @@ void G_BeginRecording(void)
// And mobjtype_t is best with UINT32 too...
WRITEUINT32(demobuf.p, player->followitem);
// GP
WRITESINT8(demobuf.p, player->lives);
WRITEINT16(demobuf.p, player->totalring);
}
}
@ -2364,7 +2381,7 @@ void G_SetDemoTime(UINT32 ptime, UINT32 plap)
UINT8 G_CmpDemoTime(char *oldname, char *newname)
{
UINT8 *buffer,*p;
UINT8 flags;
UINT16 flags;
UINT32 oldtime = UINT32_MAX, newtime = UINT32_MAX;
UINT32 oldlap = UINT32_MAX, newlap = UINT32_MAX;
UINT16 oldversion;
@ -2395,7 +2412,7 @@ UINT8 G_CmpDemoTime(char *oldname, char *newname)
p += 4; // PLAY
SKIPSTRING(p); // gamemap
p += 16; // map md5
flags = READUINT8(p); // demoflags
flags = READUINT16(p); // demoflags
SKIPSTRING(p); // gametype
p++; // numlaps
G_SkipDemoExtraFiles(&p);
@ -2454,7 +2471,7 @@ UINT8 G_CmpDemoTime(char *oldname, char *newname)
} p += 4; // "PLAY"
SKIPSTRING(p); // gamemap
p += 16; // mapmd5
flags = READUINT8(p);
flags = READUINT16(p);
SKIPSTRING(p); // gametype
p++; // numlaps
G_SkipDemoExtraFiles(&p);
@ -2498,7 +2515,8 @@ void G_LoadDemoInfo(menudemo_t *pdemo)
{
savebuffer_t info = {0};
UINT8 *extrainfo_p;
UINT8 version, subversion, pdemoflags, worknumskins, skinid;
UINT8 version, subversion, worknumskins, skinid;
UINT16 pdemoflags;
democharlist_t *skinlist = NULL;
UINT16 pdemoversion, count;
char mapname[MAXMAPLUMPNAME],gtname[MAXGAMETYPELENGTH];
@ -2578,7 +2596,7 @@ void G_LoadDemoInfo(menudemo_t *pdemo)
goto corrupt;
}
pdemoflags = READUINT8(info.p);
pdemoflags = READUINT16(info.p);
// temp?
if (!(pdemoflags & DF_MULTIPLAYER))
@ -2649,6 +2667,9 @@ void G_LoadDemoInfo(menudemo_t *pdemo)
if (pdemoflags & DF_ENCORE)
pdemo->kartspeed |= DF_ENCORE;
if (pdemoflags & DF_GRANDPRIX)
pdemo->gp = true;
// Read standings!
count = 0;
@ -2914,7 +2935,7 @@ void G_DoPlayDemo(const char *defdemoname)
READSTRINGN(demobuf.p, mapname, sizeof(mapname)); // gamemap
demobuf.p += 16; // mapmd5
demoflags = READUINT8(demobuf.p);
demoflags = READUINT16(demobuf.p);
READSTRINGN(demobuf.p, gtname, sizeof(gtname)); // gametype
@ -3041,6 +3062,15 @@ void G_DoPlayDemo(const char *defdemoname)
// net var data
CV_LoadDemoVars(&demobuf.p);
memset(&grandprixinfo, 0, sizeof grandprixinfo);
if ((demoflags & DF_GRANDPRIX))
{
grandprixinfo.gp = true;
grandprixinfo.gamespeed = READUINT8(demobuf.p);
grandprixinfo.masterbots = READUINT8(demobuf.p) != 0;
grandprixinfo.eventmode = READUINT8(demobuf.p);
}
// Sigh ... it's an empty demo.
if (*demobuf.p == DEMOMARKER)
{
@ -3216,6 +3246,10 @@ void G_DoPlayDemo(const char *defdemoname)
// Followitem
players[p].followitem = READUINT32(demobuf.p);
// GP
players[p].lives = READSINT8(demobuf.p);
players[p].totalring = READINT16(demobuf.p);
// Look for the next player
p = READUINT8(demobuf.p);
}
@ -3249,7 +3283,7 @@ void G_DoPlayDemo(const char *defdemoname)
P_SetRandSeed(i, randseed[i]);
}
G_InitNew(demoflags & DF_ENCORE, gamemap, true, true); // Doesn't matter whether you reset or not here, given changes to resetplayer.
G_InitNew((demoflags & DF_ENCORE) != 0, gamemap, true, true); // Doesn't matter whether you reset or not here, given changes to resetplayer.
for (i = 0; i < numslots; i++)
{
@ -3288,7 +3322,7 @@ void G_AddGhost(savebuffer_t *buffer, const char *defdemoname)
INT32 i;
char name[17], color[MAXCOLORNAME+1], md5[16];
demoghost *gh;
UINT8 flags;
UINT16 flags;
UINT8 *p;
mapthing_t *mthing;
UINT16 count, ghostversion;
@ -3346,7 +3380,7 @@ void G_AddGhost(savebuffer_t *buffer, const char *defdemoname)
SKIPSTRING(p); // gamemap
p += 16; // mapmd5 (possibly check for consistency?)
flags = READUINT8(p);
flags = READUINT16(p);
if (!(flags & DF_GHOST))
{
CONS_Alert(CONS_NOTICE, M_GetText("Ghost %s: No ghost data in this demo.\n"), defdemoname);
@ -3399,6 +3433,9 @@ void G_AddGhost(savebuffer_t *buffer, const char *defdemoname)
p++;
}
if ((flags & DF_GRANDPRIX))
p += 3;
if (*p == DEMOMARKER)
{
CONS_Alert(CONS_NOTICE, M_GetText("Failed to add ghost %s: Replay is empty.\n"), defdemoname);
@ -3443,6 +3480,9 @@ void G_AddGhost(savebuffer_t *buffer, const char *defdemoname)
p += 4; // followitem (maybe change later)
p += 1; // lives
p += 2; // rings
if (READUINT8(p) != 0xFF)
{
CONS_Alert(CONS_NOTICE, M_GetText("Failed to add ghost %s: Invalid player slot (bad terminator)\n"), defdemoname);
@ -3534,7 +3574,7 @@ staffbrief_t *G_GetStaffGhostBrief(UINT8 *buffer)
{
UINT8 *p = buffer;
UINT16 ghostversion;
UINT8 flags;
UINT16 flags;
INT32 i;
staffbrief_t temp = {0};
staffbrief_t *ret = NULL;
@ -3575,7 +3615,7 @@ staffbrief_t *G_GetStaffGhostBrief(UINT8 *buffer)
SKIPSTRING(p); // gamemap
p += 16; // mapmd5 (possibly check for consistency?)
flags = READUINT8(p);
flags = READUINT16(p);
if (!(flags & DF_GHOST))
{
goto fail; // we don't NEED to do it here, but whatever
@ -3608,6 +3648,9 @@ staffbrief_t *G_GetStaffGhostBrief(UINT8 *buffer)
p++; // stealth
}
if ((flags & DF_GRANDPRIX))
p += 3;
// Assert first player is in and then read name
if (READUINT8(p) != 0)
goto fail;

View file

@ -89,6 +89,7 @@ struct menudemo_t {
INT16 gametype;
SINT8 kartspeed; // Add OR DF_ENCORE for encore mode, idk
UINT8 numlaps;
UINT8 gp;
struct {
UINT8 ranking;

View file

@ -2398,6 +2398,8 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
p->ringvolume = 255;
p->ringtransparency = 255;
p->pitblame = -1;
p->topAccel = MAXTOPACCEL;
p->botvars.rubberband = FRACUNIT;

View file

@ -4562,6 +4562,22 @@ static boolean K_LastTumbleBounceCondition(player_t *player)
return (player->tumbleBounces > TUMBLEBOUNCES && player->tumbleHeight < 60);
}
// Bumpers give you bonus launch height and speed, strengthening your DI to help evade combos.
// bumperinflate visuals are handled by MT_BATTLEBUMPER, but the effects are in K_KartPlayerThink.
void K_BumperInflate(player_t *player)
{
if (!player || P_MobjWasRemoved(player->mo))
return;
if (!(gametyperules & GTR_BUMPERS))
return;
player->bumperinflate = 3;
if (player->mo->health > 1)
S_StartSound(player->mo, sfx_cdpcm9);
}
static void K_HandleTumbleBounce(player_t *player)
{
player->tumbleBounces++;
@ -4609,6 +4625,8 @@ static void K_HandleTumbleBounce(player_t *player)
}
}
K_BumperInflate(player);
// A bit of damage hitlag.
// This gives a window for DI!!
K_AddHitLag(player->mo, 3, true);
@ -8794,6 +8812,33 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd)
if (player->hyudorotimer)
player->hyudorotimer--;
if (player->bumperinflate && player->mo->hitlag == 0)
{
fixed_t thrustdelta = MAXCOMBOTHRUST - MINCOMBOTHRUST;
fixed_t floatdelta = MAXCOMBOFLOAT - MINCOMBOFLOAT;
fixed_t thrustpertic = thrustdelta / MAXCOMBOTIME;
fixed_t floatpertic = floatdelta / MAXCOMBOTIME;
fixed_t totalthrust = thrustpertic * player->progressivethrust + MINCOMBOTHRUST;
fixed_t totalfloat = floatpertic * player->progressivethrust + MINCOMBOFLOAT;
if (player->speed > K_GetKartSpeed(player, false, false))
totalthrust = 0;
if (player->tumbleBounces && player->tumbleBounces <= TUMBLEBOUNCES)
{
player->mo->momz += totalfloat;
P_Thrust(player->mo, K_MomentumAngle(player->mo), totalthrust/2);
}
else
{
P_Thrust(player->mo, K_MomentumAngle(player->mo), totalthrust);
}
player->bumperinflate--;
}
if (player->ringvolume < MINRINGVOLUME)
player->ringvolume = MINRINGVOLUME;
else if (MAXRINGVOLUME - player->ringvolume < RINGVOLUMEREGEN)
@ -8900,12 +8945,16 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd)
if (player->spinouttimer || player->tumbleBounces)
{
if (player->progressivethrust < MAXCOMBOTIME)
player->progressivethrust++;
if (player->incontrol > 0)
player->incontrol = 0;
player->incontrol--;
}
else
{
if (player->progressivethrust)
player->progressivethrust--;
if (player->incontrol < 0)
player->incontrol = 0;
player->incontrol++;
@ -8914,6 +8963,9 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd)
player->incontrol = min(player->incontrol, 5*TICRATE);
player->incontrol = max(player->incontrol, -5*TICRATE);
if (player->incontrol == 3*TICRATE)
player->pitblame = -1;
if (P_PlayerInPain(player) || player->respawn.state != RESPAWNST_NONE)
{
player->lastpickuptype = -1; // got your ass beat, go grab anything

View file

@ -37,6 +37,12 @@ Make sure this matches the actual number of states
#define INSTAWHIP_TETHERBLOCK (TICRATE*4)
#define PUNISHWINDOW (7*TICRATE/10)
#define MAXCOMBOTHRUST (mapobjectscale*20)
#define MAXCOMBOFLOAT (mapobjectscale*10)
#define MINCOMBOTHRUST (mapobjectscale*2)
#define MINCOMBOFLOAT (mapobjectscale*1)
#define MAXCOMBOTIME (TICRATE*4)
#define FLAMESHIELD_MAX (120)
#define RR_PROJECTILE_FUSE (8*TICRATE)
@ -257,6 +263,8 @@ boolean K_IsPlayingDisplayPlayer(player_t *player);
boolean K_PlayerCanPunt(player_t *player);
void K_MakeObjectReappear(mobj_t *mo);
void K_BumperInflate(player_t *player);
#ifdef __cplusplus
} // extern "C"
#endif

View file

@ -257,8 +257,14 @@ static int player_get(lua_State *L)
lua_pushboolean(L, plr->flipDI);
else if (fastcmp(field,"markedfordeath"))
lua_pushboolean(L, plr->markedfordeath);
else if (fastcmp(field,"incontrol"))
lua_pushboolean(L, plr->incontrol);
else if (fastcmp(field,"progressivethrust"))
lua_pushboolean(L, plr->progressivethrust);
else if (fastcmp(field,"dotrickfx"))
lua_pushboolean(L, plr->dotrickfx);
else if (fastcmp(field,"bumperinflate"))
lua_pushboolean(L, plr->bumperinflate);
else if (fastcmp(field,"ringboxdelay"))
lua_pushinteger(L, plr->ringboxdelay);
else if (fastcmp(field,"ringboxaward"))
@ -351,6 +357,8 @@ static int player_get(lua_State *L)
lua_pushinteger(L, plr->topAccel);
else if (fastcmp(field,"instaWhipCharge"))
lua_pushinteger(L, plr->instaWhipCharge);
else if (fastcmp(field,"pitblame"))
lua_pushinteger(L, plr->pitblame);
else if (fastcmp(field,"defenseLockout"))
lua_pushinteger(L, plr->defenseLockout);
else if (fastcmp(field,"oldGuard"))
@ -781,10 +789,16 @@ static int player_set(lua_State *L)
plr->justDI = luaL_checkinteger(L, 3);
else if (fastcmp(field,"flipDI"))
plr->flipDI = luaL_checkboolean(L, 3);
else if (fastcmp(field,"incontrol"))
plr->incontrol = luaL_checkinteger(L, 3);
else if (fastcmp(field,"progressivethrust"))
plr->progressivethrust = luaL_checkboolean(L, 3);
else if (fastcmp(field,"markedfordeath"))
plr->markedfordeath = luaL_checkboolean(L, 3);
else if (fastcmp(field,"dotrickfx"))
plr->dotrickfx = luaL_checkboolean(L, 3);
else if (fastcmp(field,"bumperinflate"))
plr->bumperinflate = luaL_checkboolean(L, 3);
else if (fastcmp(field,"ringboxdelay"))
plr->ringboxdelay = luaL_checkinteger(L, 3);
else if (fastcmp(field,"ringboxaward"))
@ -877,6 +891,8 @@ static int player_set(lua_State *L)
plr->topAccel = luaL_checkinteger(L, 3);
else if (fastcmp(field,"instaWhipCharge"))
plr->instaWhipCharge = luaL_checkinteger(L, 3);
else if (fastcmp(field,"pitblame"))
plr->pitblame = luaL_checkinteger(L, 3);
else if (fastcmp(field,"defenseLockout"))
plr->defenseLockout = luaL_checkinteger(L, 3);
else if (fastcmp(field,"oldGuard"))

View file

@ -237,7 +237,7 @@ EggTVData::Replay::Replay(Folder::Cache::ReplayRef& ref) : ref_(&ref)
if (info.gametype == GT_RACE)
{
gametype_ = Gametype(GT_RACE, Gametype::Race {
gametype_ = Gametype(GT_RACE, info.gp, Gametype::Race {
info.numlaps,
kartspeed_cons_t[(info.kartspeed & ~(DF_ENCORE)) + 1].strvalue,
(info.kartspeed & DF_ENCORE) != 0,
@ -245,7 +245,7 @@ EggTVData::Replay::Replay(Folder::Cache::ReplayRef& ref) : ref_(&ref)
}
else
{
gametype_ = Gametype(info.gametype);
gametype_ = Gametype(info.gametype, info.gp);
}
for (const auto& data : info.standings)

View file

@ -193,12 +193,12 @@ public:
};
explicit Gametype() {}
explicit Gametype(INT16 gt, Race race) : gametype_(get(gt)), var_(race) {}
explicit Gametype(INT16 gt) : gametype_(get(gt)) {}
explicit Gametype(INT16 gt, bool gp) : gametype_(get(gt)), name_(get_name(gt, gp)) {}
explicit Gametype(INT16 gt, bool gp, Race race) : Gametype(gt, gp) { var_ = race; }
bool valid() const { return gametype_; }
std::string_view name() const { return valid() ? gametype_->name : "<Unknown gametype>"; }
std::string_view name() const { return name_; }
UINT32 rules() const { return valid() ? gametype_->rules : 0u; }
bool ranks_time() const { return !ranks_points(); }
@ -208,8 +208,29 @@ public:
private:
const gametype_t* gametype_ = nullptr;
std::string_view name_;
std::variant<std::monostate, Race> var_;
std::string_view get_name(INT16 gt, bool gp) const
{
if (!valid())
{
return "<Unknown gametype>";
}
if (gt == GT_SPECIAL)
{
return "Sealed Star";
}
if ((rules() & GTR_PRISONS) && gp)
{
return "Prison Break";
}
return gametype_->name;
}
static gametype_t* get(INT16 gt) { return gt >= 0 && gt < numgametypes ? gametypes[gt] : nullptr; }
};

View file

@ -92,10 +92,9 @@ public:
std::unordered_map<std::string_view, patch> gametype = {
{"Race", "RHGT1"},
{"Battle", "RHGT2"},
// TODO: requires support in the demo format
//{"Prisons", "RHGT3"},
//{"Special", "RHGT4"},
{"Prison Break", "RHGT3"},
{"Sealed Star", "RHGT4"},
{"Versus", "RHGT5"},
};
patch fav = "RHFAV";

View file

@ -2501,9 +2501,19 @@ static boolean P_KillPlayer(player_t *player, mobj_t *inflictor, mobj_t *source,
}
if (gametyperules & (GTR_BUMPERS|GTR_CHECKPOINTS))
{
if ((player->pitblame > -1) && (player->pitblame < MAXPLAYERS)
&& (playeringame[player->pitblame]) && (!players[player->pitblame].spectator)
&& (players[player->pitblame].mo) && (!P_MobjWasRemoved(players[player->pitblame].mo)))
{
P_DamageMobj(player->mo, players[player->pitblame].mo, players[player->pitblame].mo, 1, DMG_KARMA);
player->pitblame = -1;
}
else if (player->mo->health > 1 || battleprisons)
{
player->mo->health--;
}
}
if (player->mo->health <= 0)
{
@ -3134,6 +3144,14 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
}
}
if (source && source != player->mo && source->player)
{
if (damagetype != DMG_DEATHPIT)
{
player->pitblame = source->player - players;
}
}
player->sneakertimer = player->numsneakers = 0;
player->driftboost = player->strongdriftboost = 0;
player->gateBoost = 0;
@ -3143,6 +3161,7 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
player->preventfailsafe = TICRATE*3;
player->pflags &= ~PF_GAINAX;
Obj_EndBungee(player);
K_BumperInflate(target->player);
if (player->spectator == false && !(player->charflags & SF_IRONMAN))
{
@ -3167,6 +3186,14 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
//P_KillPlayer(player, inflictor, source, damagetype);
}
// Death save! On your last hit, no matter what, demote to weakest damage type for one last escape chance.
if (player->mo->health == 2 && damage && gametyperules & GTR_BUMPERS)
{
S_StartSound(target, sfx_gshc7);
player->flashing = TICRATE;
type = DMG_STUMBLE;
}
switch (type)
{
case DMG_STING:

View file

@ -4064,6 +4064,15 @@ static void P_BouncePlayerMove(mobj_t *mo, TryMoveResult_t *result)
P_PlayerHitBounceLine(bestslideline, &result->normal);
mo->eflags |= MFE_JUSTBOUNCEDWALL;
// Combo avoidance!
if (mo->player && P_PlayerInPain(mo->player) && gametyperules & GTR_BUMPERS && mo->health == 1)
{
K_StumblePlayer(mo->player);
K_BumperInflate(mo->player);
mo->player->tumbleBounces = TUMBLEBOUNCES;
mo->hitlag = max(mo->hitlag, 6);
}
mo->momx = tmxmove;
mo->momy = tmymove;
mo->player->cmomx = tmxmove;

View file

@ -6235,6 +6235,18 @@ static void P_MobjSceneryThink(mobj_t *mobj)
// Shrink your items if the player shrunk too.
P_SetScale(mobj, mobj->target->scale);
if (mobj->target->player->bumperinflate && bumpers > mobj->threshold)
{
mobj->frame |= FF_INVERT;
// This line sucks. Scale to player, plus up to 1.5x their size based on how long the combo you're in is.
P_SetScale(mobj, mobj->target->scale + (mobj->target->player->progressivethrust * 3 * mobj->target->scale / 2 / MAXCOMBOTIME));
}
else
{
mobj->frame &= ~FF_INVERT;
}
P_UnsetThingPosition(mobj);
{
const angle_t fa = ang >> ANGLETOFINESHIFT;

View file

@ -578,6 +578,8 @@ static void P_NetArchivePlayers(savebuffer_t *save)
WRITEMEM(save->p, players[i].public_key, PUBKEYLENGTH);
WRITESINT8(save->p, players[i].pitblame);
WRITEUINT8(save->p, players[i].instaWhipCharge);
WRITEUINT8(save->p, players[i].defenseLockout);
WRITEUINT8(save->p, players[i].oldGuard);
@ -590,9 +592,11 @@ static void P_NetArchivePlayers(savebuffer_t *save)
WRITEANGLE(save->p, players[i].besthanddirection);
WRITEINT16(save->p, players[i].incontrol);
WRITEUINT16(save->p, players[i].progressivethrust);
WRITEUINT8(save->p, players[i].markedfordeath);
WRITEUINT8(save->p, players[i].dotrickfx);
WRITEUINT8(save->p, players[i].bumperinflate);
WRITEUINT8(save->p, players[i].ringboxdelay);
WRITEUINT8(save->p, players[i].ringboxaward);
@ -1153,6 +1157,8 @@ static void P_NetUnArchivePlayers(savebuffer_t *save)
READMEM(save->p, players[i].public_key, PUBKEYLENGTH);
players[i].pitblame = READSINT8(save->p);
players[i].instaWhipCharge = READUINT8(save->p);
players[i].defenseLockout = READUINT8(save->p);
players[i].oldGuard = READUINT8(save->p);
@ -1165,9 +1171,11 @@ static void P_NetUnArchivePlayers(savebuffer_t *save)
players[i].besthanddirection = READANGLE(save->p);
players[i].incontrol = READINT16(save->p);
players[i].progressivethrust = READUINT16(save->p);
players[i].markedfordeath = READUINT8(save->p);
players[i].dotrickfx = READUINT8(save->p);
players[i].bumperinflate = READUINT8(save->p);
players[i].ringboxdelay = READUINT8(save->p);
players[i].ringboxaward = READUINT8(save->p);

24
src/r_debug.hpp Normal file
View file

@ -0,0 +1,24 @@
// DR. ROBOTNIK'S RING RACERS
//-----------------------------------------------------------------------------
// Copyright (C) 2024 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 r_debug_hpp
#define r_debug_hpp
#include "doomtype.h"
namespace srb2::r_debug
{
void add_texture_to_frame_list(INT32 texnum);
void clear_frame_list();
void draw_frame_list();
}; // namespace srb2::r_debug
#endif/*r_debug_hpp*/

67
src/r_debug_printer.cpp Normal file
View file

@ -0,0 +1,67 @@
// DR. ROBOTNIK'S RING RACERS
//-----------------------------------------------------------------------------
// Copyright (C) 2024 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 <string_view>
#include <unordered_set>
#include "r_debug.hpp"
#include "v_draw.hpp"
#include "doomdef.h"
#include "doomtype.h"
#include "r_textures.h"
#include "screen.h"
using srb2::Draw;
namespace
{
std::unordered_set<INT32> frame_list;
}; // namespace
namespace srb2::r_debug
{
void add_texture_to_frame_list(INT32 texnum)
{
if (cht_debug & DBG_RENDER)
{
frame_list.insert(texnum);
}
}
void clear_frame_list()
{
frame_list.clear();
}
void draw_frame_list()
{
if (!(cht_debug & DBG_RENDER))
{
return;
}
Draw line = Draw(4, BASEVIDHEIGHT - 20)
.font(Draw::Font::kConsole)
.scale(0.5)
.flags(V_ORANGEMAP | V_SNAPTOLEFT | V_SNAPTOBOTTOM);
line.y(-4 * static_cast<int>(frame_list.size() - 1)).size(32, 4 * frame_list.size()).fill(31);
for (INT32 texnum : frame_list)
{
line.text("{}", std::string_view {textures[texnum]->name, 8});
line = line.y(-4);
}
}
}; // namespace srb2::r_debug

View file

@ -35,6 +35,7 @@
#include "core/memory.h"
#include "core/thread_pool.h"
#include "k_terrain.h"
#include "r_debug.hpp"
extern "C" consvar_t cv_debugfinishline;
@ -2064,7 +2065,13 @@ void R_StoreWallRange(INT32 start, INT32 stop)
auto get_flat_tex = [](INT32 texnum)
{
texnum = R_GetTextureNum(texnum);
return textures[texnum]->holes ? 0 : texnum; // R_DrawWallColumn cannot render holey textures
if (textures[texnum]->holes)
{
srb2::r_debug::add_texture_to_frame_list(texnum);
// R_DrawWallColumn cannot render holey textures
return R_GetTextureNum(R_CheckTextureNumForName("TRANSER1"));
}
return texnum;
};
if (!backsector)

View file

@ -1448,7 +1448,7 @@ sfxinfo_t S_sfx[NUMSFX] =
{"gshc4", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""},
{"gshc5", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""},
{"gshc6", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""},
{"gshc7", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""},
{"gshc7", false, 64, 16, -1, NULL, 0, -1, -1, LUMPERROR, ""}, //x8away
{"gshc8", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""},
{"gshc9", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""},
{"gshca", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""},