From b79f79db5115dd74281ccef323da9a9c725adebc Mon Sep 17 00:00:00 2001 From: Antonio Martinez Date: Thu, 22 May 2025 11:06:37 -0400 Subject: [PATCH 01/27] Postrace director cam --- src/k_tally.cpp | 19 +++++++++++++++++++ src/k_tally.h | 3 +++ 2 files changed, 22 insertions(+) diff --git a/src/k_tally.cpp b/src/k_tally.cpp index 877e39dd1..4f3886d1c 100644 --- a/src/k_tally.cpp +++ b/src/k_tally.cpp @@ -37,6 +37,7 @@ #include "g_party.h" #include "g_input.h" #include "k_objects.h" +#include "k_director.h" boolean level_tally_t::UseBonuses(void) { @@ -781,6 +782,24 @@ void level_tally_t::Tick(void) return; } + if (done == true) + { + if (directorWait < TALLY_DIRECTOR_TIME) + { + directorWait++; + + if (directorWait == TALLY_DIRECTOR_TIME && G_IsPartyLocal(owner - players) == true) + { + // Finished tally, go to director while we wait for others to finish. + K_ToggleDirector(G_PartyPosition(owner - players), true); + } + } + } + else + { + directorWait = 0; + } + if (transition < FRACUNIT) { if (transitionTime <= 0) diff --git a/src/k_tally.h b/src/k_tally.h index 335a74979..1fcac8919 100644 --- a/src/k_tally.h +++ b/src/k_tally.h @@ -57,6 +57,8 @@ typedef enum TALLY_ST_GAMEOVER_DONE, } tally_state_e; +#define TALLY_DIRECTOR_TIME (2 * TICRATE) + struct level_tally_t { boolean active; @@ -97,6 +99,7 @@ struct level_tally_t boolean showGrade; boolean done; boolean releasedFastForward; + INT32 directorWait; #ifdef __cplusplus boolean UseBonuses(void); From 2f73cddf50f4edd0935107e6a37cc85dcebe6268 Mon Sep 17 00:00:00 2001 From: Antonio Martinez Date: Sat, 24 May 2025 15:31:50 -0400 Subject: [PATCH 02/27] Show difficulty on GP results screen --- src/k_podium.cpp | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/k_podium.cpp b/src/k_podium.cpp index f2a6b5d89..9797f58ba 100644 --- a/src/k_podium.cpp +++ b/src/k_podium.cpp @@ -87,6 +87,7 @@ static struct podiumData_s boolean fastForward; char header[64]; + char difficulty[64]; void Init(void); void NextLevel(void); @@ -258,6 +259,27 @@ void podiumData_s::Init(void) ); } + switch(grandprixinfo.gamespeed) + { + case KARTSPEED_EASY: + snprintf(difficulty, sizeof difficulty, "Relaxed"); + break; + case KARTSPEED_NORMAL: + snprintf(difficulty, sizeof difficulty, "Intense"); + break; + case KARTSPEED_HARD: + snprintf(difficulty, sizeof difficulty, "Vicious"); + break; + default: + snprintf(difficulty, sizeof difficulty, "?"); + } + + if (grandprixinfo.masterbots) + snprintf(difficulty, sizeof difficulty, "Master"); + + if (cv_4thgear.value || cv_levelskull.value) + snprintf(difficulty, sizeof difficulty, "Extra"); + header[sizeof header - 1] = '\0'; displayLevels = 0; @@ -504,6 +526,12 @@ void podiumData_s::Draw(void) .colormap(bestHuman->skin, static_cast(bestHuman->skincolor)) .patch(faceprefix[bestHuman->skin][FACE_WANTED]); + drawer_winner + .xy(16, 28) + .align(srb2::Draw::Align::kCenter) + .font(srb2::Draw::Font::kMenu) + .text(difficulty); + drawer_winner .xy(44, 31) .align(srb2::Draw::Align::kCenter) From e1cab3a62e5bcf98e03e471f2daa23f557b85787 Mon Sep 17 00:00:00 2001 From: toaster Date: Mon, 26 May 2025 21:21:29 +0100 Subject: [PATCH 03/27] Undo over-optimisation and don't drop the visited status of unloaded custom courses Fixes everyone having to NoVisitNeeded their SP-intended stuff --- src/g_gamedata.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/g_gamedata.cpp b/src/g_gamedata.cpp index 556def12a..1fd9e3ab3 100644 --- a/src/g_gamedata.cpp +++ b/src/g_gamedata.cpp @@ -655,7 +655,7 @@ void srb2::load_ng_gamedata() mapheaderinfo[mapnum]->records = dummyrecord; } - else if (dummyrecord.mapvisited & MV_BEATEN + else if (dummyrecord.mapvisited & (MV_VISITED|MV_BEATEN) || dummyrecord.timeattack.time != 0 || dummyrecord.timeattack.lap != 0 || dummyrecord.spbattack.time != 0 || dummyrecord.spbattack.lap != 0 || dummyrecord.spraycan != MCAN_INVALID) From b4bb4db12bf9a6bdc12246e82c8fc54337f98e6a Mon Sep 17 00:00:00 2001 From: toaster Date: Mon, 26 May 2025 21:25:06 +0100 Subject: [PATCH 04/27] skinref_t: Don't dereference out-of-range - Misjudged the boundary conditions as `numskins == MAXSKINS` is valid - Internal version of public MR !113, credit Alu Folie for bringing attention to the area of error --- src/g_gamedata.cpp | 2 +- src/k_menudraw.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/g_gamedata.cpp b/src/g_gamedata.cpp index 1fd9e3ab3..be218c5ca 100644 --- a/src/g_gamedata.cpp +++ b/src/g_gamedata.cpp @@ -214,7 +214,7 @@ void srb2::save_ng_gamedata() { newrecords.bestskin = String(skinref.unloaded->name); } - else + else if (skinref.id < numskins) { newrecords.bestskin = String(skins[skinref.id].name); } diff --git a/src/k_menudraw.c b/src/k_menudraw.c index 61853ece5..45465504a 100644 --- a/src/k_menudraw.c +++ b/src/k_menudraw.c @@ -3029,7 +3029,7 @@ fixed_t M_DrawCupWinData(INT32 rankx, INT32 ranky, cupheader_t *cup, UINT8 diffi patch_t *charPat = NULL; if ((windata->best_skin.unloaded != NULL) - || (windata->best_skin.id > numskins)) + || (windata->best_skin.id >= numskins)) { colormap = NULL; From afab1eebd0ef0ca321dc7ee4d79bd6b01c0f3c74 Mon Sep 17 00:00:00 2001 From: toaster Date: Mon, 26 May 2025 21:33:01 +0100 Subject: [PATCH 05/27] Drop time attack 1.0 records entirely on gamedata conversion - We keep medals, but times are invalid due to the massive overhaul! - To avoid double increment of minorversion, this will not fire on current internal, only 2.3 gamedatas --- src/g_gamedata.cpp | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/src/g_gamedata.cpp b/src/g_gamedata.cpp index be218c5ca..077eb0b81 100644 --- a/src/g_gamedata.cpp +++ b/src/g_gamedata.cpp @@ -32,6 +32,7 @@ namespace fs = std::filesystem; #define GD_VERSION_MINOR (2) #define GD_MINIMUM_SPRAYCANSV2 (2) +#define GD_MINIMUM_TIMEATTACKV2 (2) void srb2::save_ng_gamedata() { @@ -614,10 +615,22 @@ void srb2::load_ng_gamedata() dummyrecord.mapvisited |= mappair.second.visited.encore ? MV_ENCORE : 0; dummyrecord.mapvisited |= mappair.second.visited.spbattack ? MV_SPBATTACK : 0; dummyrecord.mapvisited |= mappair.second.visited.mysticmelody ? MV_MYSTICMELODY : 0; - dummyrecord.timeattack.time = mappair.second.stats.timeattack.besttime; - dummyrecord.timeattack.lap = mappair.second.stats.timeattack.bestlap; - dummyrecord.spbattack.time = mappair.second.stats.spbattack.besttime; - dummyrecord.spbattack.lap = mappair.second.stats.spbattack.bestlap; + + if (minorversion >= GD_MINIMUM_TIMEATTACKV2) + { + dummyrecord.timeattack.time = mappair.second.stats.timeattack.besttime; + dummyrecord.timeattack.lap = mappair.second.stats.timeattack.bestlap; + dummyrecord.spbattack.time = mappair.second.stats.spbattack.besttime; + dummyrecord.spbattack.lap = mappair.second.stats.spbattack.bestlap; + } + else + { + converted = true; + + dummyrecord.timeattack.time = dummyrecord.timeattack.lap = \ + dummyrecord.spbattack.time = dummyrecord.spbattack.lap = 0; + } + dummyrecord.timeplayed = mappair.second.stats.time.total; dummyrecord.netgametimeplayed = mappair.second.stats.time.netgame; dummyrecord.modetimeplayed[GDGT_RACE] = mappair.second.stats.time.race; From adff23f106e3a1665a711fb6cd96b39793166022 Mon Sep 17 00:00:00 2001 From: Antonio Martinez Date: Sun, 1 Jun 2025 05:52:28 -0400 Subject: [PATCH 06/27] Teams juice --- src/k_collide.cpp | 13 ++++++++++++- src/k_hud.cpp | 36 +++++++++++++++++++++++++----------- src/k_hud.h | 2 ++ src/k_hud_track.cpp | 23 +++++------------------ src/k_kart.c | 12 ++++++++++++ src/p_mobj.c | 15 ++------------- src/y_inter.cpp | 2 ++ 7 files changed, 60 insertions(+), 43 deletions(-) diff --git a/src/k_collide.cpp b/src/k_collide.cpp index 77cf778c8..cf22d5c33 100644 --- a/src/k_collide.cpp +++ b/src/k_collide.cpp @@ -269,7 +269,10 @@ static inline BlockItReturn_t PIT_SSMineSearch(mobj_t *thing) return BMIT_CONTINUE; } - if (thing == grenade->target && grenade->threshold != 0) // Don't blow up at your owner instantly. + if (thing == grenade->target) // Don't blow up at your owner instantly. + return BMIT_CONTINUE; + + if (grenade->target->player && thing->player && G_SameTeam(grenade->target->player, thing->player)) return BMIT_CONTINUE; if (PIT_SSMineChecks(thing) == true) @@ -388,6 +391,9 @@ boolean K_MineCollide(mobj_t *t1, mobj_t *t2) if (t2->player->flashing > 0 && t2->hitlag == 0) return true; + if (K_TryPickMeUp(t1, t2, false)) + return true; + // Bomb punting if ((t1->state >= &states[S_SSMINE1] && t1->state <= &states[S_SSMINE4]) || (t1->state >= &states[S_SSMINE_DEPLOY8] && t1->state <= &states[S_SSMINE_EXPLODE2])) @@ -1138,6 +1144,11 @@ boolean K_PvPTouchDamage(mobj_t *t1, mobj_t *t2) if (P_MobjWasRemoved(t1) || P_MobjWasRemoved(t2) || !t1->player || !t2->player) return false; + if (G_SameTeam(t1->player, t2->player)) + { + return false; + } + // Clash instead of damage if both parties have any of these conditions auto canClash = [](mobj_t *t1, mobj_t *t2) { diff --git a/src/k_hud.cpp b/src/k_hud.cpp index 91bd054f1..2620655a5 100644 --- a/src/k_hud.cpp +++ b/src/k_hud.cpp @@ -3540,7 +3540,7 @@ static tic_t scorechangecooldown = 0; // but HUD hooks run at variable timing based on your actual framerate. static tic_t teams_lastleveltime = 0; -static void K_drawKartTeamScores(void) +void K_drawKartTeamScores(boolean fromintermission) { if (G_GametypeHasTeams() == false) { @@ -3559,8 +3559,16 @@ static void K_drawKartTeamScores(void) INT32 basey = 0; INT32 flags = V_HUDTRANS|V_SLIDEIN; INT32 snapflags = V_SNAPTOTOP|V_SNAPTORIGHT; + if (use4p) snapflags = V_SNAPTOTOP; + + if (fromintermission) + { + use4p = true; + snapflags = 0; + } + flags |= snapflags; // bar stuff, relative to base @@ -3737,10 +3745,22 @@ static void K_drawKartTeamScores(void) } // Draw at the top and bottom of the screen in 4P. - boolean goagain = use4p; + // Draw only at the bottom in intermission. + boolean shouldsecondpass = use4p; + boolean onsecondpass = fromintermission; draw: + if (onsecondpass) + { + if (!fromintermission) + { + flags |= V_SNAPTOBOTTOM; + } + flags &= ~V_SNAPTOTOP; + basey = 170; + } + V_DrawScaledPatch(basex, basey, flags, kp_team_sticker[use4p]); V_DrawMappedPatch(basex, basey, flags, kp_team_underlay[use4p][0], enemycolor); V_DrawMappedPatch(basex, basey, flags, kp_team_underlay[use4p][1], allycolor); @@ -3807,12 +3827,9 @@ static void K_drawKartTeamScores(void) you.text("{:02}", youscore); } - if (goagain) + if (shouldsecondpass && !onsecondpass) { - goagain = false; - flags |= V_SNAPTOBOTTOM; - flags &= ~V_SNAPTOTOP; - basey = 170; + onsecondpass = true; goto draw; } @@ -7572,10 +7589,7 @@ void K_drawKartHUD(void) } } - if (G_GametypeHasTeams() == true) - { - K_drawKartTeamScores(); - } + K_drawKartTeamScores(false); if (K_InRaceDuel()) { diff --git a/src/k_hud.h b/src/k_hud.h index 038be77f2..24eb20458 100644 --- a/src/k_hud.h +++ b/src/k_hud.h @@ -164,6 +164,8 @@ position_t K_GetKartObjectPosToMinimapPos(fixed_t objx, fixed_t objy); INT32 K_DrawGameControl(UINT16 x, UINT16 y, UINT8 player, const char *str, UINT8 alignment, UINT8 font, UINT32 flags); +void K_drawKartTeamScores(boolean fromintermission); + #ifdef __cplusplus } // extern "C" #endif diff --git a/src/k_hud_track.cpp b/src/k_hud_track.cpp index 0ac07e641..b2a2d19c9 100644 --- a/src/k_hud_track.cpp +++ b/src/k_hud_track.cpp @@ -389,25 +389,12 @@ bool is_object_tracking_target(const mobj_t* mobj) return !(mobj->renderflags & (RF_TRANSMASK | RF_DONTDRAW)) && // the spraycan wasn't collected yet P_CheckSight(stplyr->mo, const_cast(mobj)); - case MT_JAWZ: - case MT_JAWZ_SHIELD: - case MT_ORBINAUT: - case MT_ORBINAUT_SHIELD: - case MT_DROPTARGET: - case MT_DROPTARGET_SHIELD: - case MT_LANDMINE: - case MT_BANANA: - case MT_BANANA_SHIELD: - case MT_GACHABOM: - case MT_BUBBLESHIELDTRAP: - case MT_EGGMANITEM: - case MT_EGGMANITEM_SHIELD: - return (mobj->target && !P_MobjWasRemoved(mobj->target) && ( - (mobj->target->player && stplyr == mobj->target->player) - || (mobj->target->player && G_SameTeam(stplyr, mobj->target->player)) - ) && P_CheckSight(stplyr->mo, const_cast(mobj))); - default: + if (K_IsPickMeUpItem(mobj->type)) + return (mobj->target && !P_MobjWasRemoved(mobj->target) && ( + (mobj->target->player && stplyr == mobj->target->player) + || (mobj->target->player && G_SameTeam(stplyr, mobj->target->player)) + ) && P_CheckSight(stplyr->mo, const_cast(mobj))); return false; } } diff --git a/src/k_kart.c b/src/k_kart.c index 856ea65d4..3f8ec901d 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -1102,6 +1102,12 @@ boolean K_KartBouncing(mobj_t *mobj1, mobj_t *mobj2) disty = FixedMul(minBump, normalisedy); } + if (mobj1->player && mobj2->player && G_SameTeam(mobj1->player, mobj2->player)) + { + distx /= 3; + disty /= 3; + } + if (mass2 > 0) { mobj1->momx = mobj1->momx - FixedMul(FixedDiv(2*mass2, mass1 + mass2), distx); @@ -15812,6 +15818,8 @@ boolean K_IsPickMeUpItem(mobjtype_t type) case MT_EGGMANITEM: case MT_EGGMANITEM_SHIELD: case MT_BUBBLESHIELDTRAP: + case MT_SSMINE: + case MT_SSMINE_SHIELD: return true; default: return false; @@ -15861,6 +15869,10 @@ static boolean K_PickUp(player_t *player, mobj_t *picked) case MT_SINK: type = KITEM_KITCHENSINK; break; + case MT_SSMINE: + case MT_SSMINE_SHIELD: + type = KITEM_MINE; + break; default: type = KITEM_SAD; break; diff --git a/src/p_mobj.c b/src/p_mobj.c index 98d377637..fd0f3c098 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -5402,20 +5402,9 @@ static boolean P_IsTrackerType(INT32 type) case MT_GARDENTOP: // Frey return true; - case MT_JAWZ_SHIELD: // Pick-me-up - case MT_ORBINAUT: - case MT_ORBINAUT_SHIELD: - case MT_DROPTARGET: - case MT_DROPTARGET_SHIELD: - case MT_LANDMINE: - case MT_BANANA: - case MT_BANANA_SHIELD: - case MT_GACHABOM: - case MT_EGGMANITEM: - case MT_EGGMANITEM_SHIELD: - return true; - default: + if (K_IsPickMeUpItem(type)) + return true; return false; } } diff --git a/src/y_inter.cpp b/src/y_inter.cpp index b2159285a..508fa1b95 100644 --- a/src/y_inter.cpp +++ b/src/y_inter.cpp @@ -1949,6 +1949,8 @@ finalcounter: if ((modeattacking == ATTACKING_NONE) && demo.recording) ST_DrawSaveReplayHint(0); + K_drawKartTeamScores(true); + if (Y_CanSkipIntermission()) { const tic_t end = roundqueue.size != 0 ? 3*TICRATE : TICRATE; From 3a39399346ab5efc4d42dcd500165618b110760c Mon Sep 17 00:00:00 2001 From: Antonio Martinez Date: Sun, 1 Jun 2025 16:04:14 -0400 Subject: [PATCH 07/27] Control prompt localplayers cleanup --- src/d_netcmd.c | 10 ++++++++++ src/k_hud.cpp | 14 ++++++++------ src/v_draw.cpp | 18 ++++++++++++------ 3 files changed, 30 insertions(+), 12 deletions(-) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 56c1eeef9..d872064c6 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -73,6 +73,7 @@ #include "k_bans.h" #include "k_director.h" #include "k_credits.h" +#include "k_hud.h" // K_AddMessage #ifdef SRB2_CONFIG_ENABLE_WEBM_MOVIES #include "m_avrecorder.h" @@ -180,6 +181,8 @@ static void Command_Archivetest_f(void); static void Command_KartGiveItem_f(void); +static void Command_DebugMessageFeed(void); + static void Command_Schedule_Add(void); static void Command_Schedule_Clear(void); static void Command_Schedule_List(void); @@ -434,6 +437,8 @@ void D_RegisterServerCommands(void) COM_AddDebugCommand("give3", Command_KartGiveItem_f); COM_AddDebugCommand("give4", Command_KartGiveItem_f); + COM_AddDebugCommand("debugmessagefeed", Command_DebugMessageFeed); + COM_AddCommand("schedule_add", Command_Schedule_Add); COM_AddCommand("schedule_clear", Command_Schedule_Clear); COM_AddCommand("schedule_list", Command_Schedule_List); @@ -6358,6 +6363,11 @@ static void Command_Archivetest_f(void) } #endif +static void Command_DebugMessageFeed(void) +{ + K_AddMessage("Hello world! A = , Right = ", true, false); +} + /** Give yourself an, optional quantity or one of, an item. */ static void Command_KartGiveItem_f(void) diff --git a/src/k_hud.cpp b/src/k_hud.cpp index 91bd054f1..62c9a9910 100644 --- a/src/k_hud.cpp +++ b/src/k_hud.cpp @@ -7164,17 +7164,19 @@ static std::vector messagestates{MAXSPLITSCREENPLAYERS}; void K_AddMessage(const char *msg, boolean interrupt, boolean persist) { - for (auto &state : messagestates) + for (UINT8 i = 0; i <= r_splitscreen; i++) { - if (interrupt) - state.clear(); + messagestate_t *state = &messagestates[i]; - std::string parsedmsg = srb2::Draw::TextElement().parse(msg).string(); + if (interrupt) + state->clear(); + + std::string parsedmsg = srb2::Draw::TextElement().as(g_localplayers[i]).parse(msg).string(); if (persist) - state.objective = parsedmsg; + state->objective = parsedmsg; else - state.add(parsedmsg); + state->add(parsedmsg); } } diff --git a/src/v_draw.cpp b/src/v_draw.cpp index f8fe7df9c..b21e89448 100644 --- a/src/v_draw.cpp +++ b/src/v_draw.cpp @@ -22,6 +22,7 @@ #include "z_zone.h" #include "k_profiles.h" // controls #include "p_local.h" // stplyr +#include "r_fps.h" // R_GetViewNumber() using srb2::Draw; using Chain = Draw::Chain; @@ -176,17 +177,22 @@ Draw::TextElement& Draw::TextElement::parse(std::string_view raw) else if (auto it = translation.find(code); it != translation.end()) // This represents a gamecontrol, turn into Saturn button or generic button. { - UINT8 localplayer = 0; - UINT8 indexedplayer = as_.value_or(stplyr - players); - for (UINT8 i = 0; i < MAXSPLITSCREENPLAYERS; i++) + UINT8 localplayer = R_GetViewNumber(); + + if (as_.has_value()) { - if (g_localplayers[i] == indexedplayer) + UINT8 indexedplayer = as_.value(); + for (UINT8 i = 0; i < MAXSPLITSCREENPLAYERS; i++) { - localplayer = i; - break; + if (g_localplayers[i] == indexedplayer) + { + localplayer = i; + break; + } } } + // This isn't how v_video.cpp checks for buttons and I don't know why. if (cv_descriptiveinput[localplayer].value && ((it->second & 0xF0) != 0x80)) // Should we do game control translation? { From b8a4d21ba597a06f2bfc667b7c0e5589799f3d76 Mon Sep 17 00:00:00 2001 From: Antonio Martinez Date: Sun, 1 Jun 2025 18:28:32 -0400 Subject: [PATCH 08/27] Intermission teamscore fixup --- src/k_hud.cpp | 33 ++++++++++++++++++++------------- src/k_hud.h | 2 +- src/y_inter.cpp | 5 +++-- 3 files changed, 24 insertions(+), 16 deletions(-) diff --git a/src/k_hud.cpp b/src/k_hud.cpp index 2620655a5..f3d0cfe31 100644 --- a/src/k_hud.cpp +++ b/src/k_hud.cpp @@ -3540,7 +3540,7 @@ static tic_t scorechangecooldown = 0; // but HUD hooks run at variable timing based on your actual framerate. static tic_t teams_lastleveltime = 0; -void K_drawKartTeamScores(boolean fromintermission) +void K_drawKartTeamScores(boolean fromintermission, INT32 interoffset) { if (G_GametypeHasTeams() == false) { @@ -3563,12 +3563,6 @@ void K_drawKartTeamScores(boolean fromintermission) if (use4p) snapflags = V_SNAPTOTOP; - if (fromintermission) - { - use4p = true; - snapflags = 0; - } - flags |= snapflags; // bar stuff, relative to base @@ -3612,6 +3606,14 @@ void K_drawKartTeamScores(boolean fromintermission) faceoff = 4; } + if (fromintermission) + { + use4p = true; + snapflags = 0; + flags = 0; + basex += interoffset; + } + UINT8 allies = stplyr->team; UINT8 enemies = (allies == TEAM_ORANGE) ? TEAM_BLUE : TEAM_ORANGE; @@ -3698,9 +3700,12 @@ void K_drawKartTeamScores(boolean fromintermission) } } - // replace scores with eased scores - allyscore = easedallyscore; - enemyscore = totalscore - allyscore; + if (!fromintermission) + { + // replace scores with eased scores + allyscore = easedallyscore; + enemyscore = totalscore - allyscore; + } } teams_lastleveltime = leveltime; @@ -3756,8 +3761,8 @@ void K_drawKartTeamScores(boolean fromintermission) if (!fromintermission) { flags |= V_SNAPTOBOTTOM; + flags &= ~V_SNAPTOTOP; } - flags &= ~V_SNAPTOTOP; basey = 170; } @@ -3768,8 +3773,10 @@ void K_drawKartTeamScores(boolean fromintermission) if (!use4p) V_DrawScaledPatch(basex, basey, flags, kp_team_you); - if (V_GetHUDTranslucency(0) != 10) + /* + if (V_GetHUDTranslucency(0) != 10 || fromintermission) return; + */ V_DrawFill(basex+barx, basey+bary, enemywidth, barheight, enemyfill|flags); V_DrawFill(basex+barx+enemywidth, basey+bary, allywidth, barheight, allyfill|flags); @@ -7589,7 +7596,7 @@ void K_drawKartHUD(void) } } - K_drawKartTeamScores(false); + K_drawKartTeamScores(false, 0); if (K_InRaceDuel()) { diff --git a/src/k_hud.h b/src/k_hud.h index 24eb20458..15b1501db 100644 --- a/src/k_hud.h +++ b/src/k_hud.h @@ -164,7 +164,7 @@ position_t K_GetKartObjectPosToMinimapPos(fixed_t objx, fixed_t objy); INT32 K_DrawGameControl(UINT16 x, UINT16 y, UINT8 player, const char *str, UINT8 alignment, UINT8 font, UINT32 flags); -void K_drawKartTeamScores(boolean fromintermission); +void K_drawKartTeamScores(boolean fromintermission, INT32 interoffset); #ifdef __cplusplus } // extern "C" diff --git a/src/y_inter.cpp b/src/y_inter.cpp index 508fa1b95..1f2f4c1c8 100644 --- a/src/y_inter.cpp +++ b/src/y_inter.cpp @@ -1928,6 +1928,9 @@ void Y_IntermissionDrawer(void) // Returns early if there's no players to draw Y_PlayerStandingsDrawer(&data, x); + if ((intertic - sorttic) < 8) + K_drawKartTeamScores(true, x); + // Draw bottom (and top) pieces skiptallydrawer: if (!LUA_HudEnabled(hud_intermissionmessages)) @@ -1949,8 +1952,6 @@ finalcounter: if ((modeattacking == ATTACKING_NONE) && demo.recording) ST_DrawSaveReplayHint(0); - K_drawKartTeamScores(true); - if (Y_CanSkipIntermission()) { const tic_t end = roundqueue.size != 0 ? 3*TICRATE : TICRATE; From 2190b5ebfeb8116fc0fc05467889f085e52cb74c Mon Sep 17 00:00:00 2001 From: Antonio Martinez Date: Sun, 1 Jun 2025 19:21:48 -0400 Subject: [PATCH 09/27] Teamplay intermission fixup TWO --- src/k_hud.cpp | 4 +++- src/y_inter.cpp | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/k_hud.cpp b/src/k_hud.cpp index f3d0cfe31..922cf8c1b 100644 --- a/src/k_hud.cpp +++ b/src/k_hud.cpp @@ -3563,6 +3563,9 @@ void K_drawKartTeamScores(boolean fromintermission, INT32 interoffset) if (use4p) snapflags = V_SNAPTOTOP; + if (fromintermission) + use4p = true; + flags |= snapflags; // bar stuff, relative to base @@ -3608,7 +3611,6 @@ void K_drawKartTeamScores(boolean fromintermission, INT32 interoffset) if (fromintermission) { - use4p = true; snapflags = 0; flags = 0; basex += interoffset; diff --git a/src/y_inter.cpp b/src/y_inter.cpp index 1f2f4c1c8..6063d155d 100644 --- a/src/y_inter.cpp +++ b/src/y_inter.cpp @@ -1928,7 +1928,7 @@ void Y_IntermissionDrawer(void) // Returns early if there's no players to draw Y_PlayerStandingsDrawer(&data, x); - if ((intertic - sorttic) < 8) + if (sorttic == -1 || ((intertic - sorttic) < 8)) K_drawKartTeamScores(true, x); // Draw bottom (and top) pieces From 32f40ca013316ea8be0cdc80e384904806e695e4 Mon Sep 17 00:00:00 2001 From: Antonio Martinez Date: Mon, 2 Jun 2025 12:47:38 -0400 Subject: [PATCH 10/27] More damage cheats --- src/d_netcmd.c | 15 +++++++++-- src/k_kart.c | 2 +- src/m_cheat.c | 71 +++++++++++++++++++++++++++++++++++++++++++++++++- src/m_cheat.h | 10 +++++++ 4 files changed, 94 insertions(+), 4 deletions(-) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 56c1eeef9..858d608f9 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -559,6 +559,14 @@ void D_RegisterClientCommands(void) COM_AddDebugCommand("scale", Command_Scale_f); COM_AddDebugCommand("gravflip", Command_Gravflip_f); COM_AddDebugCommand("hurtme", Command_Hurtme_f); + COM_AddDebugCommand("stumble", Command_Stumble_f); + COM_AddDebugCommand("tumble", Command_Tumble_f); + COM_AddDebugCommand("whumble", Command_Whumble_f); + COM_AddDebugCommand("explode", Command_Explode_f); + COM_AddDebugCommand("spinout", Command_Spinout_f); + COM_AddDebugCommand("wipeout", Command_Wipeout_f); + COM_AddDebugCommand("sting", Command_Sting_f); + COM_AddDebugCommand("kill", Command_Kill_f); COM_AddDebugCommand("teleport", Command_Teleport_f); COM_AddDebugCommand("rteleport", Command_RTeleport_f); COM_AddDebugCommand("skynum", Command_Skynum_f); @@ -5924,10 +5932,13 @@ static void Got_Cheat(const UINT8 **cp, INT32 playernum) if (!P_MobjWasRemoved(player->mo)) { - P_DamageMobj(player->mo, NULL, NULL, damage, DMG_NORMAL); + if (damage >= DMG_INSTAKILL) + P_KillMobj(player->mo, NULL, NULL, (UINT8)damage); + else + P_DamageMobj(player->mo, NULL, NULL, 1, (UINT8)damage); } - CV_CheaterWarning(targetPlayer, va("%d damage to me", damage)); + CV_CheaterWarning(targetPlayer, va("damage (flags=%d) to me", damage)); break; } diff --git a/src/k_kart.c b/src/k_kart.c index 8ce6ba3f8..26b9ffdee 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -5449,7 +5449,7 @@ void K_DebtStingPlayer(player_t *player, mobj_t *source) { INT32 length = TICRATE; - if (source->player) + if (source && !P_MobjWasRemoved(source) && source->player) { length += (4 * (source->player->kartweight - player->kartweight)); } diff --git a/src/m_cheat.c b/src/m_cheat.c index 48b51f412..3c48ec521 100644 --- a/src/m_cheat.c +++ b/src/m_cheat.c @@ -115,13 +115,82 @@ void Command_Hurtme_f(void) if (COM_Argc() < 2) { - CONS_Printf(M_GetText("hurtme : Damage yourself by a specific amount\n")); + CONS_Printf(M_GetText("hurtme : Damage yourself with specific flags\n")); + CONS_Printf(M_GetText("Norm 0 Wipe 1 Expl 2 Tumb 3 Stng 4\n")); + CONS_Printf(M_GetText("Krma 5 Volt 6 Stmb 7 Whmb 8\n")); + CONS_Printf(M_GetText("Ikll 128 Dpit 129 Crsh 130 Spec 131 Time 132\n")); + CONS_Printf(M_GetText("Wmbo 16 Stel 32 Hslf 64\n")); return; } D_Cheat(consoleplayer, CHEAT_HURT, atoi(COM_Argv(1))); } +void Command_Spinout_f(void) +{ + REQUIRE_CHEATS; + REQUIRE_INLEVEL; + + D_Cheat(consoleplayer, CHEAT_HURT, DMG_NORMAL); +} + +void Command_Wipeout_f(void) +{ + REQUIRE_CHEATS; + REQUIRE_INLEVEL; + + D_Cheat(consoleplayer, CHEAT_HURT, DMG_WIPEOUT); +} + +void Command_Explode_f(void) +{ + REQUIRE_CHEATS; + REQUIRE_INLEVEL; + + D_Cheat(consoleplayer, CHEAT_HURT, DMG_EXPLODE); +} + +void Command_Sting_f(void) +{ + REQUIRE_CHEATS; + REQUIRE_INLEVEL; + + D_Cheat(consoleplayer, CHEAT_HURT, DMG_STING); +} + + +void Command_Tumble_f(void) +{ + REQUIRE_CHEATS; + REQUIRE_INLEVEL; + + D_Cheat(consoleplayer, CHEAT_HURT, DMG_TUMBLE); +} + +void Command_Stumble_f(void) +{ + REQUIRE_CHEATS; + REQUIRE_INLEVEL; + + D_Cheat(consoleplayer, CHEAT_HURT, DMG_STUMBLE); +} + +void Command_Whumble_f(void) +{ + REQUIRE_CHEATS; + REQUIRE_INLEVEL; + + D_Cheat(consoleplayer, CHEAT_HURT, DMG_WHUMBLE); +} + +void Command_Kill_f(void) +{ + REQUIRE_CHEATS; + REQUIRE_INLEVEL; + + D_Cheat(consoleplayer, CHEAT_HURT, DMG_INSTAKILL); +} + void Command_RTeleport_f(void) { float x = atof(COM_Argv(1)); diff --git a/src/m_cheat.h b/src/m_cheat.h index 8618fc1b1..1ee2707fe 100644 --- a/src/m_cheat.h +++ b/src/m_cheat.h @@ -80,6 +80,16 @@ void Command_Devmode_f(void); void Command_Scale_f(void); void Command_Gravflip_f(void); void Command_Hurtme_f(void); + +void Command_Stumble_f(void); +void Command_Whumble_f(void); +void Command_Tumble_f(void); +void Command_Explode_f(void); +void Command_Spinout_f(void); +void Command_Wipeout_f(void); +void Command_Sting_f(void); +void Command_Kill_f(void); + void Command_Teleport_f(void); void Command_RTeleport_f(void); void Command_Skynum_f(void); From a5790f0ce133800cb7413301a124f09dd4c8efe9 Mon Sep 17 00:00:00 2001 From: Antonio Martinez Date: Mon, 2 Jun 2025 18:50:40 -0400 Subject: [PATCH 11/27] Restore duel score after true death --- src/g_game.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/g_game.c b/src/g_game.c index 1dedf3833..46c880cde 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -2269,6 +2269,8 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps) UINT8 lastsafecheatcheck; UINT16 bigwaypointgap; + INT16 duelscore; + roundconditions_t roundconditions; boolean saveroundconditions; @@ -2433,6 +2435,7 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps) lastsafelap = 0; lastsafecheatcheck = 0; bigwaypointgap = 0; + duelscore = 0; tallyactive = false; @@ -2494,6 +2497,8 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps) } cangrabitems = players[player].cangrabitems; + + duelscore = players[player].duelscore; } spectatorReentry = (betweenmaps ? 0 : players[player].spectatorReentry); @@ -2598,6 +2603,8 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps) p->gradingpointnum = gradingpointnum; p->totalring = totalring; + p->duelscore = duelscore; + for (i = 0; i < LAP__MAX; i++) { p->laptime[i] = laptime[i]; From 7157d80d00569fbd3641cec409da594a55557ef0 Mon Sep 17 00:00:00 2001 From: eebrozgi Date: Tue, 3 Jun 2025 01:58:12 +0300 Subject: [PATCH 12/27] More tripwire leniency after invinc + fixed regression in rocketsneaker boost type separation What it says on the tin. Shoutouts to Ashnal for figuring out the regression before anyone got hit by it! --- src/k_kart.c | 5 +++++ src/p_saveg.cpp | 1 + 2 files changed, 6 insertions(+) diff --git a/src/k_kart.c b/src/k_kart.c index 64cea1ec2..60f743c81 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -9816,6 +9816,11 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) player->invincibilitytimer--; if (player->invincibilitytimer && K_IsPlayerScamming(player)) player->invincibilitytimer--; + + // Extra tripwire leniency for the end of invincibility + if (player->invincibilitytimer <= 0) { + player->tripwireLeniency = max( player->tripwireLeniency, TICRATE ); + } } // The precise ordering of start-of-level made me want to cut my head off, diff --git a/src/p_saveg.cpp b/src/p_saveg.cpp index b3029e0fa..2c7b05fc9 100644 --- a/src/p_saveg.cpp +++ b/src/p_saveg.cpp @@ -1198,6 +1198,7 @@ static void P_NetUnArchivePlayers(savebuffer_t *save) players[i].numsneakers = READUINT8(save->p); players[i].panelsneakertimer = READUINT16(save->p); players[i].numpanelsneakers = READUINT8(save->p); + players[i].weaksneakertimer = READUINT16(save->p); players[i].numweaksneakers = READUINT8(save->p); players[i].floorboost = READUINT8(save->p); From 78652200f68356c5881b56a7759b208e2a45356d Mon Sep 17 00:00:00 2001 From: eebrozgi Date: Tue, 3 Jun 2025 04:34:06 +0300 Subject: [PATCH 13/27] Sneaker panel overshield stacking code to actually run Using a stronger sneaker boost promoted the boost type variable so that the sneaker panel specific code virtually never ran. Oops! Fixed. --- src/k_kart.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/k_kart.c b/src/k_kart.c index 64cea1ec2..3f0a707ce 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -7213,6 +7213,7 @@ static void K_FlameDashLeftoverSmoke(mobj_t *src) void K_DoSneaker(player_t *player, INT32 type) { + INT32 originaltype = type; fixed_t intendedboost = FRACUNIT/2; // If you've already got an rocket sneaker type boost, panel sneakers will instead turn into rocket sneaker boosts @@ -7317,16 +7318,27 @@ void K_DoSneaker(player_t *player, INT32 type) { case 0: // Panel sneaker player->panelsneakertimer = sneakertime; + break; + case 1: // Single item sneaker + player->sneakertimer = sneakertime; + break; + case 2: // Rocket sneaker (aka. weaksneaker) + player->weaksneakertimer = 3*sneakertime/4; + break; + } + + // Give invincibility based on the ACTUAL boost type used, not the "promoted" boost type + switch (originaltype) + { + case 0: // Panel sneaker if (player->overshield > 0) { player->overshield = min( player->overshield + TICRATE/3, max( TICRATE, player->overshield )); } break; case 1: // Single item sneaker - player->sneakertimer = sneakertime; player->overshield = max( player->overshield, 25 ); break; case 2: // Rocket sneaker (aka. weaksneaker) - player->weaksneakertimer = 3*sneakertime/4; player->overshield = max( player->overshield, TICRATE/2 ); break; } From 2e57dd6212bd3998e76f357631c6ec88607e5db5 Mon Sep 17 00:00:00 2001 From: Antonio Martinez Date: Mon, 2 Jun 2025 23:01:41 -0400 Subject: [PATCH 14/27] Fix edge cases in turn solver sliptide preservation --- src/p_user.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/p_user.c b/src/p_user.c index 5895b6cbc..a88981115 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -2371,15 +2371,15 @@ static void P_UpdatePlayerAngle(player_t *player) // Don't force another turning tic, just give them the desired angle! #endif - if (!(player->cmd.buttons & BT_DRIFT) && (abs(player->drift) == 1) && ((player->cmd.turning > 0) == (player->drift > 0)) && player->handleboost > SLIPTIDEHANDLING) + if (!(player->cmd.buttons & BT_DRIFT) && (abs(player->drift) == 1) && ((player->cmd.turning > 0) == (player->drift > 0)) && player->handleboost >= SLIPTIDEHANDLING) { // This drift release is eligible to start a sliptide. Don't do lag-compensation countersteer behavior that could destroy it! - if (player->cmd.turning >= 0) + if (player->cmd.turning > 0) { steeringLeft = max(steeringLeft, 1); steeringRight = max(steeringRight, steeringLeft); } - else if (player->cmd.turning <= 0) + else if (player->cmd.turning < 0) { steeringRight = min(steeringRight, -1); steeringLeft = min(steeringLeft, steeringRight); From 333734fdf362880bcfd368df7b6803bb49126c39 Mon Sep 17 00:00:00 2001 From: eebrozgi Date: Tue, 3 Jun 2025 06:43:44 +0300 Subject: [PATCH 15/27] Fixing and cleaning rocket sneaker boost state separation shit - Fixed rocket sneaker tripwire state not activating - Exposed sneaker boost variables to lua - Made bots at least aware of the new sneaker boost type...? Probably. --- src/k_botitem.cpp | 6 +++--- src/k_kart.c | 3 ++- src/lua_playerlib.c | 8 ++++++++ 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/k_botitem.cpp b/src/k_botitem.cpp index e3bb56c33..7bf222a62 100644 --- a/src/k_botitem.cpp +++ b/src/k_botitem.cpp @@ -531,7 +531,7 @@ static void K_BotItemSneaker(const player_t *player, ticcmd_t *cmd) || player->speedboost > (FRACUNIT/8) // Have another type of boost (tethering) || player->botvars.itemconfirm > 4*TICRATE) // Held onto it for too long { - if (player->sneakertimer == 0 && K_ItemButtonWasDown(player) == false) + if (player->sneakertimer == 0 && player->weaksneakertimer == 0 && K_ItemButtonWasDown(player) == false) { cmd->buttons |= BT_ATTACK; //player->botvars.itemconfirm = 2*TICRATE; @@ -567,7 +567,7 @@ static void K_BotItemRocketSneaker(const player_t *player, ticcmd_t *cmd) if (player->botvars.itemconfirm > TICRATE) { - if (player->sneakertimer == 0 && K_ItemButtonWasDown(player) == false) + if (player->sneakertimer == 0 && player->weaksneakertimer == 0 && K_ItemButtonWasDown(player) == false) { cmd->buttons |= BT_ATTACK; //player->botvars.itemconfirm = 0; @@ -1605,7 +1605,7 @@ static void K_BotItemIceCube(const player_t *player, ticcmd_t *cmd) return; } - if (player->sneakertimer) + if (player->sneakertimer || player->weaksneakertimer) { return; } diff --git a/src/k_kart.c b/src/k_kart.c index 3f0a707ce..ef8aa95b3 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -3071,7 +3071,8 @@ tripwirepass_t K_TripwirePassConditions(const player_t *player) { if ( player->invincibilitytimer || - player->sneakertimer + player->sneakertimer || + player->weaksneakertimer ) return TRIPWIRE_BLASTER; diff --git a/src/lua_playerlib.c b/src/lua_playerlib.c index a71b3214d..498a1bddf 100644 --- a/src/lua_playerlib.c +++ b/src/lua_playerlib.c @@ -1124,6 +1124,14 @@ static int player_set(lua_State *L) plr->sneakertimer = luaL_checkinteger(L, 3); else if (fastcmp(field,"numsneakers")) plr->numsneakers = luaL_checkinteger(L, 3); + else if (fastcmp(field,"panelsneakertimer")) + plr->panelsneakertimer = luaL_checkinteger(L, 3); + else if (fastcmp(field,"numpanelsneakers")) + plr->numpanelsneakers = luaL_checkinteger(L, 3); + else if (fastcmp(field,"weaksneakertimer")) + plr->weaksneakertimer = luaL_checkinteger(L, 3); + else if (fastcmp(field,"numpweaksneakers")) + plr->numweaksneakers = luaL_checkinteger(L, 3); else if (fastcmp(field,"floorboost")) plr->floorboost = luaL_checkinteger(L, 3); else if (fastcmp(field,"growshrinktimer")) From 906c9ea62dce96b18f5e7e9d0fc5f28325032092 Mon Sep 17 00:00:00 2001 From: eebrozgi Date: Tue, 3 Jun 2025 06:58:22 +0300 Subject: [PATCH 16/27] numweaksneakers LUA EXPOSE TYPO AAAAAAEIUGHYHHG --- src/lua_playerlib.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lua_playerlib.c b/src/lua_playerlib.c index 498a1bddf..2f580553a 100644 --- a/src/lua_playerlib.c +++ b/src/lua_playerlib.c @@ -1130,7 +1130,7 @@ static int player_set(lua_State *L) plr->numpanelsneakers = luaL_checkinteger(L, 3); else if (fastcmp(field,"weaksneakertimer")) plr->weaksneakertimer = luaL_checkinteger(L, 3); - else if (fastcmp(field,"numpweaksneakers")) + else if (fastcmp(field,"numweaksneakers")) plr->numweaksneakers = luaL_checkinteger(L, 3); else if (fastcmp(field,"floorboost")) plr->floorboost = luaL_checkinteger(L, 3); From 2a05b761c6f690c3791c0ce4642acdaae1e86886 Mon Sep 17 00:00:00 2001 From: Antonio Martinez Date: Tue, 3 Jun 2025 00:18:30 -0400 Subject: [PATCH 17/27] directorwait 2sec -> 4sec --- src/k_tally.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/k_tally.h b/src/k_tally.h index 1fcac8919..6ae04ca14 100644 --- a/src/k_tally.h +++ b/src/k_tally.h @@ -57,7 +57,7 @@ typedef enum TALLY_ST_GAMEOVER_DONE, } tally_state_e; -#define TALLY_DIRECTOR_TIME (2 * TICRATE) +#define TALLY_DIRECTOR_TIME (4 * TICRATE) struct level_tally_t { From 778ac464371c469681c537f37aeddbdf1ccba73b Mon Sep 17 00:00:00 2001 From: eebrozgi Date: Tue, 3 Jun 2025 23:57:51 +0300 Subject: [PATCH 18/27] UFO's determination - Nerf Sealed Star UFO damage carryover 2.4 has player-buffing mechanics, especially item snatching. 2.4 also has damage frames for UFO, so UFO damage carryover probably *feels* more significant even if it's numerically worse. Thus, UFO damage carryover: - 1/6 of damage retained -> 1/12 of damage retained - 40% cap -> 20% cap Seems like an uncontroversial change. --- src/objects/ufo.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/objects/ufo.c b/src/objects/ufo.c index 8bdce7962..7f77e18ce 100644 --- a/src/objects/ufo.c +++ b/src/objects/ufo.c @@ -1286,7 +1286,9 @@ static mobj_t *InitSpecialUFO(waypoint_t *start) // Set specialDamage as early as possible, for glass ball's sake if (grandprixinfo.gp && grandprixinfo.specialDamage) { - ufo->health -= min(4*(UINT32)mobjinfo[MT_SPECIAL_UFO].spawnhealth/10, grandprixinfo.specialDamage/6); + ufo->health -= min(2*(UINT32)mobjinfo[MT_SPECIAL_UFO].spawnhealth/10, grandprixinfo.specialDamage/12); + // Use this if you want to spy on what the health ends up being: + //CONS_Printf("the UFO weeps: %d hp\n", ufo->health ); } ufo_speed(ufo) = FixedMul(UFO_START_SPEED, K_GetKartGameSpeedScalar(gamespeed)); From 885a8c2557c4e3fbd2940f39eb2884128af63805 Mon Sep 17 00:00:00 2001 From: James R Date: Tue, 3 Jun 2025 15:53:09 -0700 Subject: [PATCH 19/27] Add P_IsRelinkItem, fix Hyudoro not being relinked correctly - MT_HYUDORO itself was being relinked, causing the Hyudoro to not disappear after delivery - MT_HYUDORO_CENTER is relinked instead; this is the object that actually holds a player reference --- src/p_mobj.c | 37 +++++++++++++++++++++++++++++++++++-- src/p_mobj.h | 1 + 2 files changed, 36 insertions(+), 2 deletions(-) diff --git a/src/p_mobj.c b/src/p_mobj.c index b0ce8a6d6..60a3a6409 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -5337,6 +5337,39 @@ boolean P_IsKartFieldItem(INT32 type) } } +// This item keeps track of its owner by the mobj target +boolean P_IsRelinkItem(INT32 type) +{ + switch (type) + { + case MT_POGOSPRING: + case MT_EGGMANITEM: + case MT_EGGMANITEM_SHIELD: + case MT_BANANA: + case MT_BANANA_SHIELD: + case MT_ORBINAUT: + case MT_ORBINAUT_SHIELD: + case MT_JAWZ: + case MT_JAWZ_SHIELD: + case MT_SSMINE: + case MT_SSMINE_SHIELD: + case MT_LANDMINE: + case MT_DROPTARGET: + case MT_DROPTARGET_SHIELD: + case MT_BALLHOG: + case MT_SPB: + case MT_BUBBLESHIELDTRAP: + case MT_GARDENTOP: + case MT_HYUDORO_CENTER: + case MT_SINK: + case MT_GACHABOM: + return true; + + default: + return false; + } +} + boolean K_IsMissileOrKartItem(mobj_t *mo) { if (mo->flags & MF_MISSILE) @@ -10355,7 +10388,7 @@ void P_MobjThinker(mobj_t *mobj) I_Assert(mobj != NULL); I_Assert(!P_MobjWasRemoved(mobj)); - if (P_IsKartItem(mobj->type) && mobj->target && !P_MobjWasRemoved(mobj->target)) + if (P_IsRelinkItem(mobj->type) && mobj->target && !P_MobjWasRemoved(mobj->target)) { player_t *link = mobj->target->player; if (link && playeringame[link-players] && !link->spectator) @@ -10366,7 +10399,7 @@ void P_MobjThinker(mobj_t *mobj) if (mobj->target && P_MobjWasRemoved(mobj->target)) { P_SetTarget(&mobj->target, NULL); - if (P_IsKartItem(mobj->type) && mobj->relinkplayer && mobj->relinkplayer <= MAXPLAYERS) + if (P_IsRelinkItem(mobj->type) && mobj->relinkplayer && mobj->relinkplayer <= MAXPLAYERS) { player_t *relink = &players[mobj->relinkplayer-1]; if (playeringame[relink-players] && !relink->spectator && relink->mo && !P_MobjWasRemoved(relink->mo)) diff --git a/src/p_mobj.h b/src/p_mobj.h index 353011ddf..eec956024 100644 --- a/src/p_mobj.h +++ b/src/p_mobj.h @@ -547,6 +547,7 @@ void P_AddCachedAction(mobj_t *mobj, INT32 statenum); boolean P_IsKartItem(INT32 type); boolean P_IsKartFieldItem(INT32 type); +boolean P_IsRelinkItem(INT32 type); boolean K_IsMissileOrKartItem(mobj_t *mo); boolean P_CanDeleteKartItem(INT32 type); From c7aa32d27213257a509b95dc5484340b664073d2 Mon Sep 17 00:00:00 2001 From: James R Date: Tue, 3 Jun 2025 16:02:52 -0700 Subject: [PATCH 20/27] objects/checkpoint.cpp: fix -Wformat warning --- src/objects/checkpoint.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/objects/checkpoint.cpp b/src/objects/checkpoint.cpp index 97bba1cd5..81b546400 100644 --- a/src/objects/checkpoint.cpp +++ b/src/objects/checkpoint.cpp @@ -499,7 +499,7 @@ struct CheckpointManager auto lines = tagged_lines(chk->linetag()); if (lines.empty() && gametype != GT_TUTORIAL) { - CONS_Alert(CONS_WARNING, "Checkpoint thing %d, has linetag %d, but no lines found. Please ensure all checkpoints have associated lines.\n", chk->spawnpoint - mapthings, chk->linetag()); + CONS_Alert(CONS_WARNING, "Checkpoint thing %s, has linetag %d, but no lines found. Please ensure all checkpoints have associated lines.\n", sizeu1(chk->spawnpoint - mapthings), chk->linetag()); } else { @@ -510,7 +510,7 @@ struct CheckpointManager { if (gametype != GT_TUTORIAL) { - CONS_Alert(CONS_WARNING, "Checkpoint thing %d, has no linetag. Please ensure all checkpoint things have a linetag.\n", chk->spawnpoint - mapthings); + CONS_Alert(CONS_WARNING, "Checkpoint thing %s, has no linetag. Please ensure all checkpoint things have a linetag.\n", sizeu1(chk->spawnpoint - mapthings)); } } list_.push_front(chk); From 5ed7b13ddb76e05cef10af19de719730d42248f0 Mon Sep 17 00:00:00 2001 From: James R Date: Tue, 3 Jun 2025 16:03:41 -0700 Subject: [PATCH 21/27] K_SpawnAmps: fix -Wtype-limits <0 comparison warning --- src/k_kart.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/k_kart.c b/src/k_kart.c index 12973fddb..25eb7a8a6 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -4176,8 +4176,8 @@ void K_SpawnAmps(player_t *player, UINT8 amps, mobj_t *impact) if (amps == 0) return; - UINT32 itemdistance = max(0, min( FRACUNIT-1, K_GetItemRouletteDistance(player, D_NumPlayersInRace()))); // cap this to FRACUNIT-1, so it doesn't wrap when turning it into fixed_t - fixed_t itemdistmult = FRACUNIT + max( 0, min( FRACUNIT, (itemdistance<kartspeed) - (9-player->kartweight)) / 10); // Debug print for scaledamps calculation // CONS_Printf("K_SpawnAmps: player=%s, amps=%d, kartspeed=%d, kartweight=%d, itemdistance=%d, itemdistmult=%0.2f, statscaledamps=%d, distscaledamps=%d\n", From d457a0b5811e64c1c1d94cd4d2aed22dee020bc3 Mon Sep 17 00:00:00 2001 From: James R Date: Tue, 3 Jun 2025 16:15:34 -0700 Subject: [PATCH 22/27] Replays: replace slashes in branch name with hyphen --- src/p_setup.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/p_setup.cpp b/src/p_setup.cpp index 27e808c7c..6eced0c66 100644 --- a/src/p_setup.cpp +++ b/src/p_setup.cpp @@ -8159,6 +8159,15 @@ static void P_InitGametype(void) #else strcpy(ver, VERSIONSTRING); #endif + // Replace path separators with hyphens + { + char *p = ver; + while ((p = strpbrk(p, "/\\"))) + { + *p = '-'; + p++; + } + } sprintf(buf, "%s" PATHSEP "media" PATHSEP "replay" PATHSEP "online" PATHSEP "%s" PATHSEP "%d-%s", srb2home, ver, (int) (time(NULL)), G_BuildMapName(gamemap)); From cac7903bdfeb582ed32ac4d860630f8eca4dd01b Mon Sep 17 00:00:00 2001 From: James R Date: Mon, 26 May 2025 20:14:51 -0700 Subject: [PATCH 23/27] Fix Turbines taking away ring boost, rotate player sprite without setting spinouttimer --- src/objects/wpzturbine.c | 2 -- src/p_user.c | 14 ++++++++++++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/objects/wpzturbine.c b/src/objects/wpzturbine.c index f86f11da6..be7f075de 100644 --- a/src/objects/wpzturbine.c +++ b/src/objects/wpzturbine.c @@ -237,7 +237,6 @@ void Obj_playerWPZTurbine(player_t *p) if (mode && !distreached) p->turbineangle = (INT32)R_PointToAngle2(t->x, t->y, pmo->x, pmo->y); - p->spinouttimer = TICRATE; pmo->pitch = 0; // determine target x/y/z @@ -344,7 +343,6 @@ void Obj_playerWPZTurbine(player_t *p) pmo->momy = (pmo->momy*17)/10; } - p->spinouttimer = 0; pmo->flags &= ~MF_NOCLIP; } } diff --git a/src/p_user.c b/src/p_user.c index 5895b6cbc..7754d785c 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -2539,9 +2539,19 @@ void P_MovePlayer(player_t *player) player->glanceDir = 0; player->pflags &= ~PF_GAINAX; } - else if ((player->pflags & PF_FAULT) || (player->spinouttimer > 0)) + else if ((player->pflags & PF_FAULT) || (player->spinouttimer > 0) || (player->turbine && (player->mo->flags & MF_NOCLIP))) { - UINT16 speed = ((player->pflags & PF_FAULT) ? player->nocontrol : player->spinouttimer)/8; + tic_t timer = 0; + + if ((player->pflags & PF_FAULT)) + timer = player->nocontrol; + else if (player->spinouttimer > 0) + timer = player->spinouttimer; + else if (player->turbine && (player->mo->flags & MF_NOCLIP)) + timer = TICRATE; + + UINT16 speed = timer / 8; + if (speed > 8) speed = 8; else if (speed < 1) From f5a4f079ecedaf1e5c1399c4e8e25f746d9bf36c Mon Sep 17 00:00:00 2001 From: James R Date: Mon, 26 May 2025 20:15:23 -0700 Subject: [PATCH 24/27] Fix ice cubes taking away ring boost, do not consider ice cube a pain state I found no reason these should be a pain state --- src/p_user.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/p_user.c b/src/p_user.c index 7754d785c..033c7eb18 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -405,7 +405,7 @@ UINT8 P_FindHighestLap(void) // boolean P_PlayerInPain(const player_t *player) { - if (player->spinouttimer || (player->tumbleBounces > 0) || (player->pflags & PF_FAULT) || player->icecube.frozen) + if (player->spinouttimer || (player->tumbleBounces > 0) || (player->pflags & PF_FAULT)) return true; return false; From 29d6169bf579992cd36f93e3f4e6cc88487c2b9f Mon Sep 17 00:00:00 2001 From: James R Date: Mon, 26 May 2025 23:00:17 -0700 Subject: [PATCH 25/27] Fix Aerial Highlands clouds taking away drift --- src/objects/cloud.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/objects/cloud.c b/src/objects/cloud.c index 045d360fc..b0e0c71f0 100644 --- a/src/objects/cloud.c +++ b/src/objects/cloud.c @@ -17,6 +17,7 @@ #include "../s_sound.h" #include "../r_main.h" #include "../m_random.h" +#include "../k_hitlag.h" #define BULB_ZTHRUST 96*FRACUNIT @@ -143,7 +144,6 @@ void Obj_PlayerCloudThink(player_t *player) if (player->cloud) { player->cloud--; - P_InstaThrust(mo, 0, 0); mo->momz = 0; player->fastfall = 0; @@ -157,6 +157,7 @@ void Obj_PlayerCloudThink(player_t *player) player->cloudlaunch = TICRATE; P_InstaThrust(mo, mo->cusval, mo->cvmem); + K_AddHitLag(mo, 6, false); } } } From 377ec280f8c474971d00593c0685c665dd25fbd9 Mon Sep 17 00:00:00 2001 From: James R Date: Tue, 3 Jun 2025 17:19:10 -0700 Subject: [PATCH 26/27] Do not let player use items while in turbines or ice cubes --- src/k_kart.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/k_kart.c b/src/k_kart.c index 25eb7a8a6..c8e03ddf1 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -15710,6 +15710,12 @@ void K_MakeObjectReappear(mobj_t *mo) boolean K_PlayerCanUseItem(player_t *player) { + if (player->icecube.frozen) + return false; + + if (player->turbine && (player->mo->flags & MF_NOCLIP)) + return false; + return (player->mo->health > 0 && !player->spectator && !P_PlayerInPain(player) && !mapreset && leveltime > introtime); } From 8ed97a013f5f57a638bad3c34dd2e03cdb05251c Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Wed, 4 Jun 2025 02:23:41 -0400 Subject: [PATCH 27/27] Fix stage striking copypaste error for Battle (Blatantly incorrect, so I'm pushing to master.) --- src/k_vote.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/k_vote.c b/src/k_vote.c index e5eeb5c63..21b1494f5 100644 --- a/src/k_vote.c +++ b/src/k_vote.c @@ -2238,7 +2238,7 @@ static boolean Y_DetermineStageStrike(void) case int_score: { score_a = a->score; - score_b = b->realtime; + score_b = b->score; break; } default: