From 26677c612ef21c742f90fa260d2465e4bc380874 Mon Sep 17 00:00:00 2001 From: AJ Martinez Date: Tue, 23 Jan 2024 22:06:17 -0700 Subject: [PATCH 01/21] WIP: Improved bumper defenses --- src/d_player.h | 1 + src/k_kart.c | 23 +++++++++++++++++++++++ src/k_kart.h | 5 +++++ src/lua_playerlib.c | 4 ++++ src/p_inter.c | 8 ++++++++ src/p_map.c | 6 ++++++ src/p_mobj.c | 5 +++++ src/p_saveg.c | 2 ++ 8 files changed, 54 insertions(+) diff --git a/src/d_player.h b/src/d_player.h index 75002da11..24b5ac1c7 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -979,6 +979,7 @@ struct player_t boolean markedfordeath; boolean dotrickfx; + UINT8 bumperinflate; UINT8 ringboxdelay; // Delay until Ring Box auto-activates UINT8 ringboxaward; // Where did we stop? diff --git a/src/k_kart.c b/src/k_kart.c index 7334567a9..eba4701bd 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -4543,6 +4543,19 @@ 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 (!(player->mo->health > 1 && gametyperules & GTR_BUMPERS)) + return; + + player->bumperinflate = 3; +} + static void K_HandleTumbleBounce(player_t *player) { player->tumbleBounces++; @@ -4590,6 +4603,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); @@ -8766,6 +8781,14 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) if (player->hyudorotimer) player->hyudorotimer--; + if (player->bumperinflate && player->mo->health > 1 && player->mo->hitlag == 0) + { + P_Thrust(player->mo, K_MomentumAngle(player->mo), BUMPER_THRUST); + if (player->tumbleBounces) + player->mo->momz += BUMPER_FLOAT; + player->bumperinflate--; + } + if (player->ringvolume < MINRINGVOLUME) player->ringvolume = MINRINGVOLUME; else if (MAXRINGVOLUME - player->ringvolume < RINGVOLUMEREGEN) diff --git a/src/k_kart.h b/src/k_kart.h index ad1132f61..c2b02ef01 100644 --- a/src/k_kart.h +++ b/src/k_kart.h @@ -37,6 +37,9 @@ Make sure this matches the actual number of states #define INSTAWHIP_TETHERBLOCK (TICRATE*4) #define PUNISHWINDOW (7*TICRATE/10) +#define BUMPER_FLOAT (4*mapobjectscale) +#define BUMPER_THRUST (10*mapobjectscale) + #define FLAMESHIELD_MAX (120) #define RR_PROJECTILE_FUSE (8*TICRATE) @@ -256,6 +259,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 diff --git a/src/lua_playerlib.c b/src/lua_playerlib.c index fe2291cab..875167cb6 100644 --- a/src/lua_playerlib.c +++ b/src/lua_playerlib.c @@ -259,6 +259,8 @@ static int player_get(lua_State *L) lua_pushboolean(L, plr->markedfordeath); 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")) @@ -783,6 +785,8 @@ static int player_set(lua_State *L) 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")) diff --git a/src/p_inter.c b/src/p_inter.c index 6a7164745..5561932b5 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -3352,6 +3352,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)) { @@ -3376,6 +3377,13 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da //P_KillPlayer(player, inflictor, source, damagetype); } + // Have bumpers? Demote wipeout combos to stumble, force the attacker to make a DI read. + if (player->mo->health > 1 && gametyperules & GTR_BUMPERS) + { + if (type == DMG_WIPEOUT && P_PlayerInPain(player)) + type = DMG_STUMBLE; + } + switch (type) { case DMG_STING: diff --git a/src/p_map.c b/src/p_map.c index 7c7593cad..076687fb0 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -4177,6 +4177,12 @@ static void P_BouncePlayerMove(mobj_t *mo, TryMoveResult_t *result) P_PlayerHitBounceLine(bestslideline, &result->normal); mo->eflags |= MFE_JUSTBOUNCEDWALL; + if (mo->player && P_PlayerInPain(mo->player) && gametyperules & GTR_BUMPERS && mo->health > 1) + { + CONS_Printf("get me outta here\n"); + P_DamageMobj(mo, NULL, NULL, 1, DMG_STUMBLE); + } + mo->momx = tmxmove; mo->momy = tmymove; mo->player->cmomx = tmxmove; diff --git a/src/p_mobj.c b/src/p_mobj.c index 1e7f4a65c..6e687971a 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -6364,6 +6364,11 @@ 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) + { + P_SetScale(mobj, mobj->target->scale + (mobj->target->scale * mobj->target->player->bumperinflate / 2)); + } + P_UnsetThingPosition(mobj); { const angle_t fa = ang >> ANGLETOFINESHIFT; diff --git a/src/p_saveg.c b/src/p_saveg.c index 2cf06d1e2..6fafe80bb 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -592,6 +592,7 @@ static void P_NetArchivePlayers(savebuffer_t *save) 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); @@ -1166,6 +1167,7 @@ static void P_NetUnArchivePlayers(savebuffer_t *save) 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); From b97a94a2a9605793334c6b6992f898d92b183e48 Mon Sep 17 00:00:00 2001 From: AJ Martinez Date: Wed, 24 Jan 2024 05:37:37 -0700 Subject: [PATCH 02/21] Bumper inflate: remove debug print --- src/p_map.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/p_map.c b/src/p_map.c index 076687fb0..4d0aea282 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -4177,9 +4177,9 @@ 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) { - CONS_Printf("get me outta here\n"); P_DamageMobj(mo, NULL, NULL, 1, DMG_STUMBLE); } From a514a36128c3c828784e9863769af667eb5d04cd Mon Sep 17 00:00:00 2001 From: AJ Martinez Date: Wed, 24 Jan 2024 22:45:30 -0700 Subject: [PATCH 03/21] Less volatile bumper inflate --- src/k_kart.c | 5 +++-- src/p_map.c | 1 + 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/k_kart.c b/src/k_kart.c index eba4701bd..e84ff8aec 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -8783,8 +8783,9 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) if (player->bumperinflate && player->mo->health > 1 && player->mo->hitlag == 0) { - P_Thrust(player->mo, K_MomentumAngle(player->mo), BUMPER_THRUST); - if (player->tumbleBounces) + if (player->speed < K_GetKartSpeed(player, false, false)/2) + P_Thrust(player->mo, K_MomentumAngle(player->mo), BUMPER_THRUST); + if (player->tumbleBounces && player->tumbleBounces <= TUMBLEBOUNCES) player->mo->momz += BUMPER_FLOAT; player->bumperinflate--; } diff --git a/src/p_map.c b/src/p_map.c index 4d0aea282..957d376df 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -4181,6 +4181,7 @@ static void P_BouncePlayerMove(mobj_t *mo, TryMoveResult_t *result) if (mo->player && P_PlayerInPain(mo->player) && gametyperules & GTR_BUMPERS && mo->health > 1) { P_DamageMobj(mo, NULL, NULL, 1, DMG_STUMBLE); + mo->player->tumbleBounces = TUMBLEBOUNCES; } mo->momx = tmxmove; From c197d41bdc32af5c813c75431cd8bb6409e7f419 Mon Sep 17 00:00:00 2001 From: AJ Martinez Date: Thu, 25 Jan 2024 15:14:32 -0700 Subject: [PATCH 04/21] Bumper inflate refinements part 69 --- src/k_kart.c | 9 +++++++-- src/k_kart.h | 2 +- src/p_map.c | 4 +++- src/p_mobj.c | 7 ++++++- 4 files changed, 17 insertions(+), 5 deletions(-) diff --git a/src/k_kart.c b/src/k_kart.c index e84ff8aec..597762186 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -4554,6 +4554,7 @@ void K_BumperInflate(player_t *player) return; player->bumperinflate = 3; + S_StartSound(player->mo, sfx_cdpcm9); } static void K_HandleTumbleBounce(player_t *player) @@ -8783,10 +8784,14 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) if (player->bumperinflate && player->mo->health > 1 && player->mo->hitlag == 0) { - if (player->speed < K_GetKartSpeed(player, false, false)/2) - P_Thrust(player->mo, K_MomentumAngle(player->mo), BUMPER_THRUST); if (player->tumbleBounces && player->tumbleBounces <= TUMBLEBOUNCES) + { player->mo->momz += BUMPER_FLOAT; + } + else if (player->speed < K_GetKartSpeed(player, false, false)/2) + { + P_Thrust(player->mo, K_MomentumAngle(player->mo), BUMPER_THRUST); + } player->bumperinflate--; } diff --git a/src/k_kart.h b/src/k_kart.h index c2b02ef01..7b9793c77 100644 --- a/src/k_kart.h +++ b/src/k_kart.h @@ -37,7 +37,7 @@ Make sure this matches the actual number of states #define INSTAWHIP_TETHERBLOCK (TICRATE*4) #define PUNISHWINDOW (7*TICRATE/10) -#define BUMPER_FLOAT (4*mapobjectscale) +#define BUMPER_FLOAT (8*mapobjectscale) #define BUMPER_THRUST (10*mapobjectscale) #define FLAMESHIELD_MAX (120) diff --git a/src/p_map.c b/src/p_map.c index 957d376df..edd9cd993 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -4180,8 +4180,10 @@ static void P_BouncePlayerMove(mobj_t *mo, TryMoveResult_t *result) // Combo avoidance! if (mo->player && P_PlayerInPain(mo->player) && gametyperules & GTR_BUMPERS && mo->health > 1) { - P_DamageMobj(mo, NULL, NULL, 1, DMG_STUMBLE); + K_StumblePlayer(mo->player); + K_BumperInflate(mo->player); mo->player->tumbleBounces = TUMBLEBOUNCES; + mo->hitlag = max(mo->hitlag, 6); } mo->momx = tmxmove; diff --git a/src/p_mobj.c b/src/p_mobj.c index 6e687971a..3f5cdcb80 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -6366,7 +6366,12 @@ static void P_MobjSceneryThink(mobj_t *mobj) if (mobj->target->player->bumperinflate) { - P_SetScale(mobj, mobj->target->scale + (mobj->target->scale * mobj->target->player->bumperinflate / 2)); + mobj->frame |= FF_INVERT; + P_SetScale(mobj, mobj->target->scale + (mobj->target->scale * 3 * mobj->target->player->bumperinflate / 4)); + } + else + { + mobj->frame &= ~FF_INVERT; } P_UnsetThingPosition(mobj); From 9231e9510127c76a8d22c9298c71352f57c34150 Mon Sep 17 00:00:00 2001 From: AJ Martinez Date: Mon, 29 Jan 2024 17:02:25 -0700 Subject: [PATCH 05/21] WIP: Battle combo mitigation rework --- src/d_player.h | 1 + src/k_kart.c | 20 ++++++++++++++------ src/k_kart.h | 5 +++-- src/lua_playerlib.c | 8 ++++++++ src/p_inter.c | 9 +++++---- src/p_map.c | 2 +- src/p_saveg.c | 2 ++ src/sounds.c | 2 +- 8 files changed, 35 insertions(+), 14 deletions(-) diff --git a/src/d_player.h b/src/d_player.h index ba491154e..2dfb00652 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -977,6 +977,7 @@ 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; diff --git a/src/k_kart.c b/src/k_kart.c index 33f622d71..9d117d0ec 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -4560,11 +4560,13 @@ void K_BumperInflate(player_t *player) if (!player || P_MobjWasRemoved(player->mo)) return; - if (!(player->mo->health > 1 && gametyperules & GTR_BUMPERS)) + if (!(gametyperules & GTR_BUMPERS)) return; player->bumperinflate = 3; - S_StartSound(player->mo, sfx_cdpcm9); + + if (player->mo->health > 1) + S_StartSound(player->mo, sfx_cdpcm9); } static void K_HandleTumbleBounce(player_t *player) @@ -8801,15 +8803,18 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) if (player->hyudorotimer) player->hyudorotimer--; - if (player->bumperinflate && player->mo->health > 1 && player->mo->hitlag == 0) + if (player->bumperinflate && player->mo->hitlag == 0) { + UINT16 cappedthrust = min(player->progressivethrust, THRUSTCAP); + if (player->tumbleBounces && player->tumbleBounces <= TUMBLEBOUNCES) { - player->mo->momz += BUMPER_FLOAT; + player->mo->momz += DAMAGEFLOAT * cappedthrust; + P_Thrust(player->mo, K_MomentumAngle(player->mo), DAMAGETHRUST * cappedthrust / 2); } - else if (player->speed < K_GetKartSpeed(player, false, false)/2) + else { - P_Thrust(player->mo, K_MomentumAngle(player->mo), BUMPER_THRUST); + P_Thrust(player->mo, K_MomentumAngle(player->mo), DAMAGETHRUST * cappedthrust); } player->bumperinflate--; } @@ -8920,12 +8925,15 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) if (player->spinouttimer || player->tumbleBounces) { + player->progressivethrust++; if (player->incontrol > 0) player->incontrol = 0; player->incontrol--; } else { + if (player->progressivethrust && leveltime % 3 == 0) + player->progressivethrust--; if (player->incontrol < 0) player->incontrol = 0; player->incontrol++; diff --git a/src/k_kart.h b/src/k_kart.h index 8309bfc08..b60614477 100644 --- a/src/k_kart.h +++ b/src/k_kart.h @@ -37,8 +37,9 @@ Make sure this matches the actual number of states #define INSTAWHIP_TETHERBLOCK (TICRATE*4) #define PUNISHWINDOW (7*TICRATE/10) -#define BUMPER_FLOAT (8*mapobjectscale) -#define BUMPER_THRUST (10*mapobjectscale) +#define DAMAGEFLOAT (FRACUNIT/50) +#define DAMAGETHRUST (FRACUNIT/70) +#define THRUSTCAP (TICRATE*10) #define FLAMESHIELD_MAX (120) diff --git a/src/lua_playerlib.c b/src/lua_playerlib.c index 875167cb6..616121b21 100644 --- a/src/lua_playerlib.c +++ b/src/lua_playerlib.c @@ -257,6 +257,10 @@ 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")) @@ -781,6 +785,10 @@ 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")) diff --git a/src/p_inter.c b/src/p_inter.c index 62e2d3cef..a074b23fa 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -3374,11 +3374,12 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da //P_KillPlayer(player, inflictor, source, damagetype); } - // Have bumpers? Demote wipeout combos to stumble, force the attacker to make a DI read. - if (player->mo->health > 1 && gametyperules & GTR_BUMPERS) + // 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) { - if (type == DMG_WIPEOUT && P_PlayerInPain(player)) - type = DMG_STUMBLE; + S_StartSound(target, sfx_gshc7); + player->flashing = TICRATE; + type = DMG_STUMBLE; } switch (type) diff --git a/src/p_map.c b/src/p_map.c index edd9cd993..182db056c 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -4178,7 +4178,7 @@ static void P_BouncePlayerMove(mobj_t *mo, TryMoveResult_t *result) mo->eflags |= MFE_JUSTBOUNCEDWALL; // Combo avoidance! - if (mo->player && P_PlayerInPain(mo->player) && gametyperules & GTR_BUMPERS && mo->health > 1) + if (mo->player && P_PlayerInPain(mo->player) && gametyperules & GTR_BUMPERS && mo->health == 1) { K_StumblePlayer(mo->player); K_BumperInflate(mo->player); diff --git a/src/p_saveg.c b/src/p_saveg.c index 6fafe80bb..180c6ed0b 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -589,6 +589,7 @@ 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); @@ -1164,6 +1165,7 @@ 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); diff --git a/src/sounds.c b/src/sounds.c index 828f67242..1339fd384 100644 --- a/src/sounds.c +++ b/src/sounds.c @@ -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, ""}, From 10ba1fa25fa3d6f4220183ca57267e7de64dd8b7 Mon Sep 17 00:00:00 2001 From: AJ Martinez Date: Mon, 29 Jan 2024 18:27:26 -0700 Subject: [PATCH 06/21] WIP: Adjust combo escape tuning defines --- src/k_kart.c | 22 +++++++++++++++++----- src/k_kart.h | 8 +++++--- 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/src/k_kart.c b/src/k_kart.c index 9d117d0ec..63241ed56 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -8805,17 +8805,28 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) if (player->bumperinflate && player->mo->hitlag == 0) { - UINT16 cappedthrust = min(player->progressivethrust, THRUSTCAP); + 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 += DAMAGEFLOAT * cappedthrust; - P_Thrust(player->mo, K_MomentumAngle(player->mo), DAMAGETHRUST * cappedthrust / 2); + player->mo->momz += totalfloat; + P_Thrust(player->mo, K_MomentumAngle(player->mo), totalthrust/2); } else { - P_Thrust(player->mo, K_MomentumAngle(player->mo), DAMAGETHRUST * cappedthrust); + P_Thrust(player->mo, K_MomentumAngle(player->mo), totalthrust); } + player->bumperinflate--; } @@ -8925,7 +8936,8 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) if (player->spinouttimer || player->tumbleBounces) { - player->progressivethrust++; + if (player->progressivethrust < MAXCOMBOTIME) + player->progressivethrust++; if (player->incontrol > 0) player->incontrol = 0; player->incontrol--; diff --git a/src/k_kart.h b/src/k_kart.h index b60614477..c7da3eca8 100644 --- a/src/k_kart.h +++ b/src/k_kart.h @@ -37,9 +37,11 @@ Make sure this matches the actual number of states #define INSTAWHIP_TETHERBLOCK (TICRATE*4) #define PUNISHWINDOW (7*TICRATE/10) -#define DAMAGEFLOAT (FRACUNIT/50) -#define DAMAGETHRUST (FRACUNIT/70) -#define THRUSTCAP (TICRATE*10) +#define MAXCOMBOTHRUST (mapobjectscale*20) +#define MAXCOMBOFLOAT (mapobjectscale*10) +#define MINCOMBOTHRUST (mapobjectscale*2) +#define MINCOMBOFLOAT (mapobjectscale*1) +#define MAXCOMBOTIME (TICRATE*10) #define FLAMESHIELD_MAX (120) From 18ee3ad73d932b6d0cd6be8edff684eb61247229 Mon Sep 17 00:00:00 2001 From: AJ Martinez Date: Sat, 10 Feb 2024 14:38:04 -0700 Subject: [PATCH 07/21] Battle bumpers: 3x progressivethrust decay --- src/k_kart.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/k_kart.c b/src/k_kart.c index 75bf2bbc0..ba8a9b216 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -8953,7 +8953,7 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) } else { - if (player->progressivethrust && leveltime % 3 == 0) + if (player->progressivethrust) player->progressivethrust--; if (player->incontrol < 0) player->incontrol = 0; From b55d2367339f12c62512408930dab9458a06edd0 Mon Sep 17 00:00:00 2001 From: AJ Martinez Date: Sat, 10 Feb 2024 15:16:48 -0700 Subject: [PATCH 08/21] Scale bumper size to combo length when hit --- src/k_kart.h | 2 +- src/p_mobj.c | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/k_kart.h b/src/k_kart.h index c7da3eca8..a4be3bdc4 100644 --- a/src/k_kart.h +++ b/src/k_kart.h @@ -41,7 +41,7 @@ Make sure this matches the actual number of states #define MAXCOMBOFLOAT (mapobjectscale*10) #define MINCOMBOTHRUST (mapobjectscale*2) #define MINCOMBOFLOAT (mapobjectscale*1) -#define MAXCOMBOTIME (TICRATE*10) +#define MAXCOMBOTIME (TICRATE*6) #define FLAMESHIELD_MAX (120) diff --git a/src/p_mobj.c b/src/p_mobj.c index 2ef4eecfb..329378f70 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -6238,7 +6238,9 @@ static void P_MobjSceneryThink(mobj_t *mobj) if (mobj->target->player->bumperinflate) { mobj->frame |= FF_INVERT; - P_SetScale(mobj, mobj->target->scale + (mobj->target->scale * 3 * mobj->target->player->bumperinflate / 4)); + // 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 { From 8f2989a8a9fbf1700d74bb47862f085046717957 Mon Sep 17 00:00:00 2001 From: AJ Martinez Date: Sat, 10 Feb 2024 15:28:26 -0700 Subject: [PATCH 09/21] Don't inflate bumpers you're going to lose --- src/p_mobj.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/p_mobj.c b/src/p_mobj.c index 329378f70..6bd3924fc 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -6235,7 +6235,7 @@ 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) + 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. From 09b5cb50208e530e9dfbdc58eacd929b4e3d1f0f Mon Sep 17 00:00:00 2001 From: AJ Martinez Date: Sat, 10 Feb 2024 15:50:15 -0700 Subject: [PATCH 10/21] MAXCOMBOTIME 6s -> 4s --- src/k_kart.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/k_kart.h b/src/k_kart.h index a4be3bdc4..dd4828c20 100644 --- a/src/k_kart.h +++ b/src/k_kart.h @@ -41,7 +41,7 @@ Make sure this matches the actual number of states #define MAXCOMBOFLOAT (mapobjectscale*10) #define MINCOMBOTHRUST (mapobjectscale*2) #define MINCOMBOFLOAT (mapobjectscale*1) -#define MAXCOMBOTIME (TICRATE*6) +#define MAXCOMBOTIME (TICRATE*4) #define FLAMESHIELD_MAX (120) From 38c9c5f9a7256e2456da00b866d3cd96255a1434 Mon Sep 17 00:00:00 2001 From: James R Date: Sun, 11 Feb 2024 16:28:01 -0800 Subject: [PATCH 11/21] devmode render: show a list of errored holey textures on the HUD Holey textures (textures with transparent pixels) cannot be used on upper/lower textures or on 1-sided linedefs. If the game tries to render this, the texture name will appear on the HUD if devmode render is turned on. --- src/CMakeLists.txt | 1 + src/d_main.cpp | 3 ++ src/r_debug.hpp | 24 +++++++++++++++ src/r_debug_printer.cpp | 67 +++++++++++++++++++++++++++++++++++++++++ src/r_segs.cpp | 8 ++++- 5 files changed, 102 insertions(+), 1 deletion(-) create mode 100644 src/r_debug.hpp create mode 100644 src/r_debug_printer.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 7e453e45e..d48f2b506 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -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 diff --git a/src/d_main.cpp b/src/d_main.cpp index 7dee5488f..ad5276ca1 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -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) diff --git a/src/r_debug.hpp b/src/r_debug.hpp new file mode 100644 index 000000000..1910912c0 --- /dev/null +++ b/src/r_debug.hpp @@ -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*/ diff --git a/src/r_debug_printer.cpp b/src/r_debug_printer.cpp new file mode 100644 index 000000000..728bf29ee --- /dev/null +++ b/src/r_debug_printer.cpp @@ -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 +#include + +#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 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(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 diff --git a/src/r_segs.cpp b/src/r_segs.cpp index 6f0ca5224..e25b1415f 100644 --- a/src/r_segs.cpp +++ b/src/r_segs.cpp @@ -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,12 @@ 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); + return 0; // R_DrawWallColumn cannot render holey textures + } + return texnum; }; if (!backsector) From 3e225f97a276023d1675c3117ff28276eff35c5e Mon Sep 17 00:00:00 2001 From: James R Date: Sun, 11 Feb 2024 17:04:51 -0800 Subject: [PATCH 12/21] Render errored holey textures as TRANSERx --- src/r_segs.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/r_segs.cpp b/src/r_segs.cpp index e25b1415f..60012fe80 100644 --- a/src/r_segs.cpp +++ b/src/r_segs.cpp @@ -2068,7 +2068,8 @@ void R_StoreWallRange(INT32 start, INT32 stop) if (textures[texnum]->holes) { srb2::r_debug::add_texture_to_frame_list(texnum); - return 0; // R_DrawWallColumn cannot render holey textures + // R_DrawWallColumn cannot render holey textures + return R_GetTextureNum(R_CheckTextureNumForName("TRANSER1")); } return texnum; }; From c0598610e90006f576f1de5f2fb520daa15c60e0 Mon Sep 17 00:00:00 2001 From: AJ Martinez Date: Sun, 11 Feb 2024 21:40:53 -0700 Subject: [PATCH 13/21] Credit players for deathpits that result from their hits --- src/d_player.h | 2 ++ src/g_game.c | 2 ++ src/k_kart.c | 3 +++ src/lua_playerlib.c | 4 ++++ src/p_inter.c | 18 +++++++++++++++++- src/p_saveg.c | 4 ++++ 6 files changed, 32 insertions(+), 1 deletion(-) diff --git a/src/d_player.h b/src/d_player.h index a29de3368..623cb1b6b 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -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 diff --git a/src/g_game.c b/src/g_game.c index f52eaf0f4..3e69e344a 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -2389,6 +2389,8 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps) p->ringvolume = 255; p->ringtransparency = 255; + p->pitblame = -1; + p->topAccel = MAXTOPACCEL; p->botvars.rubberband = FRACUNIT; diff --git a/src/k_kart.c b/src/k_kart.c index dbe81babf..5e13b5b98 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -8914,6 +8914,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 diff --git a/src/lua_playerlib.c b/src/lua_playerlib.c index bda0f8b58..e8376d83e 100644 --- a/src/lua_playerlib.c +++ b/src/lua_playerlib.c @@ -351,6 +351,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")) @@ -877,6 +879,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")) diff --git a/src/p_inter.c b/src/p_inter.c index bba888358..87c8dbdd0 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -2502,7 +2502,15 @@ static boolean P_KillPlayer(player_t *player, mobj_t *inflictor, mobj_t *source, if (gametyperules & (GTR_BUMPERS|GTR_CHECKPOINTS)) { - player->mo->health--; + if ((player->pitblame != -1) && (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); + } + else if (player->mo->health > 1 || battleprisons) + { + player->mo->health--; + } } if (player->mo->health <= 0) @@ -3134,6 +3142,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; diff --git a/src/p_saveg.c b/src/p_saveg.c index 1ed3801b0..f363a34ab 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -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); @@ -1153,6 +1155,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); From 11f7eb4b2640465579c1415ec1fb8a099851ab3b Mon Sep 17 00:00:00 2001 From: AJ Martinez Date: Sun, 11 Feb 2024 23:43:42 -0700 Subject: [PATCH 14/21] Guard against out-of-range pitblame, reset pitblame when triggered --- src/p_inter.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/p_inter.c b/src/p_inter.c index 87c8dbdd0..447d05c58 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -2502,10 +2502,12 @@ static boolean P_KillPlayer(player_t *player, mobj_t *inflictor, mobj_t *source, if (gametyperules & (GTR_BUMPERS|GTR_CHECKPOINTS)) { - if ((player->pitblame != -1) && (playeringame[player->pitblame]) && (!players[player->pitblame].spectator) + 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) { From 5650dde2ac402031c691f08621873072e16b6cc1 Mon Sep 17 00:00:00 2001 From: James R Date: Sun, 11 Feb 2024 18:18:55 -0800 Subject: [PATCH 15/21] G_DoPlayDemo: fix encoremode boolean on demo playback Fixes the Title Card using the wrong sound effect --- src/g_demo.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/g_demo.c b/src/g_demo.c index 95ebc454a..b3fc6efbe 100644 --- a/src/g_demo.c +++ b/src/g_demo.c @@ -3249,7 +3249,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++) { From 6dc8f45df622752bd7fff47938f85c01282552ca Mon Sep 17 00:00:00 2001 From: James R Date: Mon, 12 Feb 2024 18:04:41 -0800 Subject: [PATCH 16/21] Replays: flags UINT8 -> UINT16 --- src/g_demo.c | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/src/g_demo.c b/src/g_demo.c index b3fc6efbe..b67098534 100644 --- a/src/g_demo.c +++ b/src/g_demo.c @@ -64,7 +64,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; @@ -2148,7 +2148,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); @@ -2364,7 +2364,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 +2395,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 +2454,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 +2498,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 +2579,7 @@ void G_LoadDemoInfo(menudemo_t *pdemo) goto corrupt; } - pdemoflags = READUINT8(info.p); + pdemoflags = READUINT16(info.p); // temp? if (!(pdemoflags & DF_MULTIPLAYER)) @@ -2914,7 +2915,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 @@ -3288,7 +3289,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 +3347,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); @@ -3534,7 +3535,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 +3576,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 From b2ce6aebe7b576b52fa78134370fcdeed890b367 Mon Sep 17 00:00:00 2001 From: James R Date: Mon, 12 Feb 2024 18:08:11 -0800 Subject: [PATCH 17/21] Replays: save Grand Prix info - grandprixinfo - gp - gamespeed - masterbots - eventmode - player_t - lives - totalring --- src/g_demo.c | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/src/g_demo.c b/src/g_demo.c index b67098534..e804db401 100644 --- a/src/g_demo.c +++ b/src/g_demo.c @@ -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 @@ -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); @@ -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); } } @@ -3042,6 +3059,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) { @@ -3217,6 +3243,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); } @@ -3400,6 +3430,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); @@ -3444,6 +3477,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); @@ -3609,6 +3645,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; From aa4ff315b7d158ff3aadc9b83483013f4e1b1b71 Mon Sep 17 00:00:00 2001 From: James R Date: Mon, 12 Feb 2024 18:08:44 -0800 Subject: [PATCH 18/21] Replays: bump demo version 7 -> 8 --- src/g_demo.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/g_demo.c b/src/g_demo.c index e804db401..587054845 100644 --- a/src/g_demo.c +++ b/src/g_demo.c @@ -104,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 From b275a14ec2b91f4443dfe1c14feb34aa27e613a4 Mon Sep 17 00:00:00 2001 From: James R Date: Mon, 12 Feb 2024 18:10:26 -0800 Subject: [PATCH 19/21] Egg TV: detect Prisons mode --- src/g_demo.c | 3 +++ src/g_demo.h | 1 + src/menus/class-egg-tv/EggTVData.cpp | 4 ++-- src/menus/class-egg-tv/EggTVData.hpp | 22 +++++++++++++++++++--- 4 files changed, 25 insertions(+), 5 deletions(-) diff --git a/src/g_demo.c b/src/g_demo.c index 587054845..87e43d750 100644 --- a/src/g_demo.c +++ b/src/g_demo.c @@ -2667,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; diff --git a/src/g_demo.h b/src/g_demo.h index 501f8da72..808f3ff25 100644 --- a/src/g_demo.h +++ b/src/g_demo.h @@ -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; diff --git a/src/menus/class-egg-tv/EggTVData.cpp b/src/menus/class-egg-tv/EggTVData.cpp index 78078e9c5..f8fdd66c2 100644 --- a/src/menus/class-egg-tv/EggTVData.cpp +++ b/src/menus/class-egg-tv/EggTVData.cpp @@ -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) diff --git a/src/menus/class-egg-tv/EggTVData.hpp b/src/menus/class-egg-tv/EggTVData.hpp index b898ee45a..d7de9517d 100644 --- a/src/menus/class-egg-tv/EggTVData.hpp +++ b/src/menus/class-egg-tv/EggTVData.hpp @@ -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 : ""; } + 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,24 @@ public: private: const gametype_t* gametype_ = nullptr; + std::string_view name_; std::variant var_; + std::string_view get_name(INT16 gt, bool gp) const + { + if (!valid()) + { + return ""; + } + + 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; } }; From 822d67e42259090d3072461049b6c96816538234 Mon Sep 17 00:00:00 2001 From: James R Date: Mon, 12 Feb 2024 18:11:07 -0800 Subject: [PATCH 20/21] Egg TV: rename "Special" mode to "Sealed Star" --- src/menus/class-egg-tv/EggTVData.hpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/menus/class-egg-tv/EggTVData.hpp b/src/menus/class-egg-tv/EggTVData.hpp index d7de9517d..fa7491ded 100644 --- a/src/menus/class-egg-tv/EggTVData.hpp +++ b/src/menus/class-egg-tv/EggTVData.hpp @@ -218,6 +218,11 @@ public: return ""; } + if (gt == GT_SPECIAL) + { + return "Sealed Star"; + } + if ((rules() & GTR_PRISONS) && gp) { return "Prison Break"; From 8bf2343a5d8a325724c8c75ca2e2e6d566590715 Mon Sep 17 00:00:00 2001 From: James R Date: Mon, 12 Feb 2024 18:13:09 -0800 Subject: [PATCH 21/21] Egg TV: Prisons, Sealed Star and Versus icons --- src/menus/class-egg-tv/EggTVGraphics.hpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/menus/class-egg-tv/EggTVGraphics.hpp b/src/menus/class-egg-tv/EggTVGraphics.hpp index 643da3b45..cdfc404a2 100644 --- a/src/menus/class-egg-tv/EggTVGraphics.hpp +++ b/src/menus/class-egg-tv/EggTVGraphics.hpp @@ -92,10 +92,9 @@ public: std::unordered_map 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";