From 4bcdd22e2c587d15f1613052b266d12eaf85f9f7 Mon Sep 17 00:00:00 2001 From: James R Date: Sat, 13 Jan 2024 12:34:28 -0800 Subject: [PATCH 01/21] HUD: Battle GOAL uses leading player's color by default --- src/k_hud.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/k_hud.cpp b/src/k_hud.cpp index b71d5a8f6..d1ab57c6f 100644 --- a/src/k_hud.cpp +++ b/src/k_hud.cpp @@ -2224,13 +2224,14 @@ struct PositionFacesInfo void draw_1p(); void draw_4p_battle(int x, int y, INT32 flags); - UINT32 top_score() const { return players[rankplayer[0]].roundscore; } + player_t* top() const { return &players[rankplayer[0]]; } + UINT32 top_score() const { return top()->roundscore; } bool near_goal() const { return g_pointlimit - 5 <= top_score(); } skincolornum_t vomit_color() const { if (!near_goal()) { - return SKINCOLOR_NONE; + return static_cast(top()->skincolor); } constexpr int kCycleSpeed = 4; From da2e6f1bfefa329b298c6c0de5bc29416c741d8c Mon Sep 17 00:00:00 2001 From: James R Date: Sat, 13 Jan 2024 12:41:57 -0800 Subject: [PATCH 02/21] battlebumpers: let minimum be 0 Useful for testing. --- src/cvars.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cvars.cpp b/src/cvars.cpp index 3c61539a0..f13457d4d 100644 --- a/src/cvars.cpp +++ b/src/cvars.cpp @@ -712,7 +712,7 @@ consvar_t cv_kartbot = UnsavedNetVar("bots", "Off").values({ {13,"Lv.MAX"}, }); -consvar_t cv_kartbumpers = UnsavedNetVar("battlebumpers", "3").min_max(1, 12); +consvar_t cv_kartbumpers = UnsavedNetVar("battlebumpers", "3").min_max(0, 12); void KartEliminateLast_OnChange(void); consvar_t cv_karteliminatelast = UnsavedNetVar("eliminatelast", "Yes").yes_no().onchange(KartEliminateLast_OnChange); From a349b1acf03083eae26883e91e41eb2685b00f37 Mon Sep 17 00:00:00 2001 From: James R Date: Sat, 13 Jan 2024 12:52:09 -0800 Subject: [PATCH 03/21] Revert "Add K_UpdateDamageFlashing, refactor Battle 0-flashing tics" This reverts commit 3856fbf1c63259a847346df46e9de00606f922da. --- src/k_kart.c | 19 +++++++------------ src/k_kart.h | 1 - src/p_inter.c | 2 +- 3 files changed, 8 insertions(+), 14 deletions(-) diff --git a/src/k_kart.c b/src/k_kart.c index b17241488..8a2299b59 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -3550,6 +3550,11 @@ UINT16 K_GetKartFlashing(const player_t *player) { UINT16 tics = flashingtics; + if (gametyperules & GTR_BUMPERS) + { + return 0; + } + if (player == NULL) { return tics; @@ -3559,16 +3564,6 @@ UINT16 K_GetKartFlashing(const player_t *player) return tics; } -void K_UpdateDamageFlashing(player_t *player, UINT16 tics) -{ - if (gametyperules & GTR_BUMPERS) - { - return; - } - - player->flashing = tics; -} - boolean K_PlayerShrinkCheat(const player_t *player) { return ( @@ -8396,9 +8391,9 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) if (player->spinouttimer != 0) { if (( player->spinouttype & KSPIN_IFRAMES ) == 0) - K_UpdateDamageFlashing(player, 0); + player->flashing = 0; else - K_UpdateDamageFlashing(player, K_GetKartFlashing(player)); + player->flashing = K_GetKartFlashing(player); } if (player->spinouttimer) diff --git a/src/k_kart.h b/src/k_kart.h index 698cec3c5..6b54f9a37 100644 --- a/src/k_kart.h +++ b/src/k_kart.h @@ -192,7 +192,6 @@ fixed_t K_GetKartSpeedFromStat(UINT8 kartspeed); fixed_t K_GetKartSpeed(const player_t *player, boolean doboostpower, boolean dorubberbanding); fixed_t K_GetKartAccel(const player_t *player); UINT16 K_GetKartFlashing(const player_t *player); -void K_UpdateDamageFlashing(player_t *player, UINT16 tics); boolean K_PlayerShrinkCheat(const player_t *player); void K_UpdateShrinkCheat(player_t *player); boolean K_KartKickstart(const player_t *player); diff --git a/src/p_inter.c b/src/p_inter.c index 53561406c..c0001e4c8 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -3341,7 +3341,7 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da if (type != DMG_STUMBLE && type != DMG_WHUMBLE) { if (type != DMG_STING) - K_UpdateDamageFlashing(player, K_GetKartFlashing(player)); + player->flashing = K_GetKartFlashing(player); player->ringburst += ringburst; From 57c501f6ee2e67cbdbc576ec24e6fa5cad297db4 Mon Sep 17 00:00:00 2001 From: James R Date: Sat, 13 Jan 2024 12:54:43 -0800 Subject: [PATCH 04/21] Revert "0 flashtics in Battle" This reverts commit 79eb400f494cd9736e36e35b664fef11ab49f61e. --- 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 8a2299b59..095d5cfdd 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -3552,7 +3552,7 @@ UINT16 K_GetKartFlashing(const player_t *player) if (gametyperules & GTR_BUMPERS) { - return 0; + return 1; } if (player == NULL) From 92cd95311c113305f0e410b729ff8f914ebc6b42 Mon Sep 17 00:00:00 2001 From: James R Date: Sat, 13 Jan 2024 13:07:02 -0800 Subject: [PATCH 05/21] Add P_IsKartItem: true for anything the player can hold or throw (except shield overlays) --- src/p_mobj.c | 33 +++++++++++++++++++++++++++++++++ src/p_mobj.h | 1 + 2 files changed, 34 insertions(+) diff --git a/src/p_mobj.c b/src/p_mobj.c index f1d393afc..517434f17 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -5317,6 +5317,39 @@ cont: // Kartitem stuff. +// These are held/thrown by players. +boolean P_IsKartItem(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: + case MT_SINK: + case MT_GACHABOM: + return true; + + default: + return false; + } +} + // This item is never attached to a player -- it can DIE // unconditionally in death sectors. boolean P_IsKartFieldItem(INT32 type) diff --git a/src/p_mobj.h b/src/p_mobj.h index dabdafe51..1e429aa26 100644 --- a/src/p_mobj.h +++ b/src/p_mobj.h @@ -540,6 +540,7 @@ void P_InitCachedActions(void); void P_RunCachedActions(void); void P_AddCachedAction(mobj_t *mobj, INT32 statenum); +boolean P_IsKartItem(INT32 type); boolean P_IsKartFieldItem(INT32 type); boolean K_IsMissileOrKartItem(mobj_t *mo); boolean P_CanDeleteKartItem(INT32 type); From 9fa7cb096b19087819318c565b7a1ec4bc3ddf82 Mon Sep 17 00:00:00 2001 From: James R Date: Sat, 13 Jan 2024 13:16:58 -0800 Subject: [PATCH 06/21] P_DamageMobj: items and PvP damage bypass flashing tics if the victim is in a damage state --- src/p_inter.c | 35 ++++++++++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/src/p_inter.c b/src/p_inter.c index c0001e4c8..a36f74262 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -2812,6 +2812,34 @@ static void AddNullHitlag(player_t *player, tic_t oldHitlag) } } +static boolean P_FlashingException(const player_t *player, const mobj_t *inflictor) +{ + if (!inflictor) + { + // Sector damage always behaves the same. + return false; + } + + if (!P_IsKartItem(inflictor->type) && inflictor->type != MT_PLAYER) + { + // Exception only applies to player items. + // Also applies to players because of PvP collision. + // Lightning Shield also uses the player object as inflictor. + return false; + } + + if (!P_PlayerInPain(player)) + { + // Flashing tics is sometimes used in a way unrelated to damage. + // E.g. picking up a power-up gives you flashing tics. + // Respect this usage of flashing tics. + return false; + } + + // Flashing tics are ignored. + return true; +} + /** Damages an object, which may or may not be a player. * For melee attacks, source and inflictor are the same. * @@ -3176,7 +3204,12 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da } // DMG_EXPLODE excluded from flashtic checks to prevent dodging eggbox/SPB with weak spinout - if ((target->hitlag == 0 || allowcombo == false) && player->flashing > 0 && type != DMG_EXPLODE && type != DMG_STUMBLE && type != DMG_WHUMBLE) + if ((target->hitlag == 0 || allowcombo == false) && + player->flashing > 0 && + type != DMG_EXPLODE && + type != DMG_STUMBLE && + type != DMG_WHUMBLE && + P_FlashingException(player, inflictor) == false) { // Post-hit invincibility K_DoInstashield(player); From fd7eb42e9d6358a257ce2fbc2e75f4b7ba23c10b Mon Sep 17 00:00:00 2001 From: James R Date: Sat, 13 Jan 2024 14:31:15 -0800 Subject: [PATCH 07/21] Vote: fix Encore appearing on Battle, if gametype was changed --- src/d_netcmd.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index b950aec95..165d8ca84 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -2194,6 +2194,8 @@ void D_MapChange(UINT16 mapnum, INT32 newgametype, boolean pencoremode, boolean void D_SetupVote(INT16 newgametype) { + const UINT32 rules = gametypes[newgametype]->rules; + UINT8 buf[(VOTE_NUM_LEVELS * 2) + 4]; UINT8 *p = buf; @@ -2203,7 +2205,7 @@ void D_SetupVote(INT16 newgametype) memset(votebuffer, UINT16_MAX, sizeof(votebuffer)); WRITEINT16(p, newgametype); - WRITEUINT8(p, ((cv_kartencore.value == 1) && (gametyperules & GTR_ENCORE))); + WRITEUINT8(p, ((cv_kartencore.value == 1) && (rules & GTR_ENCORE))); WRITEUINT8(p, G_SometimesGetDifferentEncore()); for (i = 0; i < VOTE_NUM_LEVELS; i++) From db4e2e692b18ff06e060a3b21bc60c2193cd0415 Mon Sep 17 00:00:00 2001 From: James R Date: Sat, 13 Jan 2024 14:32:07 -0800 Subject: [PATCH 08/21] Add LobbySize option to level headers, controls whether the map appears in vote, based on player count - Prevents a map from appearing on the vote screen if there are too many players - LobbySize - Duel - 2 players max - Small - 5 players max - Medium - 10 players max - Large - 16 players max (default if not set) - Future proofing - Doesn't count bot players in gametypes that don't support bots --- src/d_netcmd.c | 25 +++++++++++++++++++++++-- src/deh_soc.c | 23 +++++++++++++++++++++++ src/doomstat.h | 1 + src/g_game.c | 13 ++++++++++++- src/g_game.h | 1 + src/p_setup.cpp | 1 + 6 files changed, 61 insertions(+), 3 deletions(-) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 165d8ca84..a4f52e383 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -2208,13 +2208,34 @@ void D_SetupVote(INT16 newgametype) WRITEUINT8(p, ((cv_kartencore.value == 1) && (rules & GTR_ENCORE))); WRITEUINT8(p, G_SometimesGetDifferentEncore()); + UINT8 numPlayers = 0; + + for (i = 0; i < MAXPLAYERS; ++i) + { + if (!playeringame[i] || players[i].spectator) + { + continue; + } + + extern consvar_t cv_forcebots; // debug + + if (!(rules & GTR_BOTS) && players[i].bot && !cv_forcebots.value) + { + // Gametype doesn't support bots + continue; + } + + numPlayers++; + } + for (i = 0; i < VOTE_NUM_LEVELS; i++) { - UINT16 m = G_RandMap( + UINT16 m = G_RandMapPerPlayerCount( G_TOLFlag(newgametype), prevmap, false, (i < VOTE_NUM_LEVELS-1), - votebuffer + votebuffer, + numPlayers ); votebuffer[i] = m; WRITEUINT16(p, m); diff --git a/src/deh_soc.c b/src/deh_soc.c index 9ceb61f95..9d9ff8bf3 100644 --- a/src/deh_soc.c +++ b/src/deh_soc.c @@ -1417,6 +1417,29 @@ void readlevelheader(MYFILE *f, char * name) mapheaderinfo[num]->destroyforchallenge_size = j; } } + else if (fastcmp(word, "LOBBYSIZE")) + { + if (fastcmp(word2, "DUEL")) + { + mapheaderinfo[num]->playerLimit = 2; + } + else if (fastcmp(word2, "SMALL")) + { + mapheaderinfo[num]->playerLimit = 5; + } + else if (fastcmp(word2, "MEDIUM")) + { + mapheaderinfo[num]->playerLimit = 10; + } + else if (fastcmp(word2, "LARGE")) + { + mapheaderinfo[num]->playerLimit = 16; + } + else + { + deh_warning("Level header %d: invalid lobby size '%s'", num, word2); + } + } else deh_warning("Level header %d: unknown word '%s'", num, word); } diff --git a/src/doomstat.h b/src/doomstat.h index 5247ea082..333bfd6f0 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -501,6 +501,7 @@ struct mapheader_t UINT8 levelselect; ///< Is this map available in the level select? If so, which map list is it available in? UINT16 menuflags; ///< LF2_flags: options that affect record attack menus + UINT8 playerLimit; ///< This map does not appear in multiplayer vote if there are too many players // Operational metadata UINT16 levelflags; ///< LF_flags: merged booleans into one UINT16 for space, see below diff --git a/src/g_game.c b/src/g_game.c index 35161cb79..457062058 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -3499,7 +3499,7 @@ static UINT16 *g_allowedMaps = NULL; static size_t g_randMapStack = 0; #endif -UINT16 G_RandMap(UINT32 tolflags, UINT16 pprevmap, boolean ignoreBuffers, boolean callAgainSoon, UINT16 *extBuffer) +UINT16 G_RandMapPerPlayerCount(UINT32 tolflags, UINT16 pprevmap, boolean ignoreBuffers, boolean callAgainSoon, UINT16 *extBuffer, UINT8 numPlayers) { INT32 allowedMapsCount = 0; INT32 extBufferCount = 0; @@ -3558,6 +3558,12 @@ tryAgain: continue; } + if (numPlayers > mapheaderinfo[i]->playerLimit) + { + // Too many players for this map. + continue; + } + // Only care about restrictions if the host is a listen server. if (!dedicated) { @@ -3665,6 +3671,11 @@ tryAgain: return ret; } +UINT16 G_RandMap(UINT32 tolflags, UINT16 pprevmap, boolean ignoreBuffers, boolean callAgainSoon, UINT16 *extBuffer) +{ + return G_RandMapPerPlayerCount(tolflags, pprevmap, ignoreBuffers, callAgainSoon, extBuffer, 0); +} + void G_AddMapToBuffer(UINT16 map) { if (mapheaderinfo[map]->justPlayed == 0) // Started playing a new map. diff --git a/src/g_game.h b/src/g_game.h index d1378ce30..4f08804c6 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -277,6 +277,7 @@ FUNCMATH INT32 G_TicsToMilliseconds(tic_t tics); UINT32 G_TOLFlag(INT32 pgametype); UINT16 G_GetFirstMapOfGametype(UINT16 pgametype); +UINT16 G_RandMapPerPlayerCount(UINT32 tolflags, UINT16 pprevmap, boolean ignoreBuffers, boolean callAgainSoon, UINT16 *extBuffer, UINT8 numPlayers); UINT16 G_RandMap(UINT32 tolflags, UINT16 pprevmap, boolean ignoreBuffers, boolean callAgainSoon, UINT16 *extBuffer); void G_AddMapToBuffer(UINT16 map); diff --git a/src/p_setup.cpp b/src/p_setup.cpp index a1af94db5..604f29b06 100644 --- a/src/p_setup.cpp +++ b/src/p_setup.cpp @@ -457,6 +457,7 @@ static void P_ClearSingleMapHeaderInfo(INT16 num) mapheaderinfo[num]->levelselect = 0; mapheaderinfo[num]->levelflags = 0; mapheaderinfo[num]->menuflags = 0; + mapheaderinfo[num]->playerLimit = MAXPLAYERS; mapheaderinfo[num]->mobj_scale = FRACUNIT; mapheaderinfo[num]->default_waypoint_radius = 0; P_ClearMapHeaderLighting(&mapheaderinfo[num]->lighting); From 5ec2e156ab13b63aaa78061349cd53e267f74078 Mon Sep 17 00:00:00 2001 From: James R Date: Sat, 13 Jan 2024 15:15:28 -0800 Subject: [PATCH 09/21] Battle: fix viewpoint switching to eliminated player --- src/g_game.c | 3 ++- src/k_director.cpp | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/g_game.c b/src/g_game.c index 457062058..cf3bc74e2 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -1526,7 +1526,8 @@ boolean G_CouldView(INT32 playernum) // boolean G_CanView(INT32 playernum, UINT8 viewnum, boolean onlyactive) { - if (!playeringame[playernum] || players[playernum].spectator) + // PF_ELIMINATED: Battle Overtime Barrier killed this player + if (!playeringame[playernum] || players[playernum].spectator || (players[playernum].pflags & PF_ELIMINATED)) { return false; } diff --git a/src/k_director.cpp b/src/k_director.cpp index 118786d63..93f3ea47d 100644 --- a/src/k_director.cpp +++ b/src/k_director.cpp @@ -112,7 +112,9 @@ struct DirectorInfo } // pair finished? try the next one - if (players[playerstat[targetposition].sorted].exiting) + if (players[playerstat[targetposition].sorted].exiting || + // Battle: player was killed by Overtime Barrier + (players[playerstat[targetposition].sorted].pflags & PF_ELIMINATED)) { continue; } From 3c85a9a4365bed4b33da59756e5748798f2bfcd2 Mon Sep 17 00:00:00 2001 From: James R Date: Sat, 13 Jan 2024 15:44:29 -0800 Subject: [PATCH 10/21] Director: let it switch to splitscreen players --- src/k_director.cpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/k_director.cpp b/src/k_director.cpp index 93f3ea47d..308b30bca 100644 --- a/src/k_director.cpp +++ b/src/k_director.cpp @@ -139,12 +139,6 @@ struct DirectorInfo break; } - // if this is a splitscreen player, try next pair - if (P_IsDisplayPlayer(&players[target])) - { - continue; - } - // if we're certain the back half of the pair is actually in this position, try to switch if (!players[target].positiondelay) { From dd1db7cd4ad63c2945323b24afc56e6b8c696115 Mon Sep 17 00:00:00 2001 From: James R Date: Sat, 13 Jan 2024 15:46:06 -0800 Subject: [PATCH 11/21] Reset viewpoint to self when you spawn --- src/p_mobj.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/p_mobj.c b/src/p_mobj.c index 517434f17..b4634563c 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -12972,19 +12972,20 @@ void P_SpawnPlayer(INT32 playernum) if (G_IsPartyLocal(playernum)) { - // Spectating always enables director cam. If there - // is no one to view, this will do nothing. If - // someone enters the game later, it will - // automatically switch to that player. - K_ToggleDirector(G_PartyPosition(playernum), p->spectator); - // Spectators can switch to freecam. This should be // disabled when they enter the race, or when the level // changes. if (!demo.playback) { camera[G_PartyPosition(playernum)].freecam = false; + displayplayers[G_PartyPosition(playernum)] = playernum; } + + // Spectating always enables director cam. If there + // is no one to view, this will do nothing. If + // someone enters the game later, it will + // automatically switch to that player. + K_ToggleDirector(G_PartyPosition(playernum), p->spectator); } else if (pcount == 1 && !p->spectator) { From 99a2a3fb74b4067a6b68d82fc474e8f42fcb00e7 Mon Sep 17 00:00:00 2001 From: James R Date: Sat, 13 Jan 2024 16:31:54 -0800 Subject: [PATCH 12/21] Let Bubble blow-up destroy any MF_SHOOTABLE object --- src/k_collide.cpp | 11 ---------- src/p_map.c | 55 +++++++++++++++++++++++++++++++---------------- 2 files changed, 37 insertions(+), 29 deletions(-) diff --git a/src/k_collide.cpp b/src/k_collide.cpp index 38e69c8e4..d10dd845f 100644 --- a/src/k_collide.cpp +++ b/src/k_collide.cpp @@ -745,17 +745,6 @@ void K_LightningShieldAttack(mobj_t *actor, fixed_t size) boolean K_BubbleShieldCollide(mobj_t *t1, mobj_t *t2) { - if (t1->type == MT_PLAYER) - { - // Bubble Shield already has a hitbox, and it gets - // teleported every tic so the Bubble itself will - // always make contact with other objects. - // - // Therefore, we don't need a second, smaller hitbox - // on the player. It'll just cause unwanted hitlag. - return true; - } - if (t2->type == MT_PLAYER) { // Counter desyncs diff --git a/src/p_map.c b/src/p_map.c index 1f64946a3..782028790 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -522,6 +522,17 @@ static void P_DoFanAndGasJet(mobj_t *spring, mobj_t *object) } } +static boolean P_BubbleCanReflect(mobj_t *t1, mobj_t *t2) +{ + return (t2->type == MT_ORBINAUT || t2->type == MT_JAWZ || t2->type == MT_GACHABOM + || t2->type == MT_BANANA || t2->type == MT_EGGMANITEM || t2->type == MT_BALLHOG + || t2->type == MT_SSMINE || t2->type == MT_LANDMINE || t2->type == MT_SINK + || t2->type == MT_GARDENTOP + || t2->type == MT_DROPTARGET + || t2->type == MT_KART_LEFTOVER + || (t2->type == MT_PLAYER && t1->target != t2)); +} + // // PIT_CheckThing // @@ -994,15 +1005,8 @@ static BlockItReturn_t PIT_CheckThing(mobj_t *thing) return BMIT_CONTINUE; // Bubble Shield reflect - if (((thing->type == MT_BUBBLESHIELD && thing->target->player && thing->target->player->bubbleblowup) + if ((thing->type == MT_BUBBLESHIELD && thing->target->player && thing->target->player->bubbleblowup) || (thing->player && thing->player->bubbleblowup)) - && (tm.thing->type == MT_ORBINAUT || tm.thing->type == MT_JAWZ || tm.thing->type == MT_GACHABOM - || tm.thing->type == MT_BANANA || tm.thing->type == MT_EGGMANITEM || tm.thing->type == MT_BALLHOG - || tm.thing->type == MT_SSMINE || tm.thing->type == MT_LANDMINE || tm.thing->type == MT_SINK - || tm.thing->type == MT_GARDENTOP - || tm.thing->type == MT_DROPTARGET - || tm.thing->type == MT_KART_LEFTOVER - || (tm.thing->type == MT_PLAYER && thing->target != tm.thing))) { // see if it went over / under if (tm.thing->z > thing->z + thing->height) @@ -1010,17 +1014,21 @@ static BlockItReturn_t PIT_CheckThing(mobj_t *thing) if (tm.thing->z + tm.thing->height < thing->z) return BMIT_CONTINUE; // underneath - return K_BubbleShieldCollide(thing, tm.thing) ? BMIT_CONTINUE : BMIT_ABORT; + if (P_BubbleCanReflect(thing, tm.thing)) + { + // don't let player hitbox touch it too + if (thing->player) + return BMIT_CONTINUE; + return K_BubbleShieldCollide(thing, tm.thing) ? BMIT_CONTINUE : BMIT_ABORT; + } + else if ((tm.thing->flags & MF_SHOOTABLE) && !thing->player) + { + P_DamageMobj(tm.thing, thing, thing->target, 1, DMG_NORMAL); + return BMIT_CONTINUE; + } } - else if (((tm.thing->type == MT_BUBBLESHIELD && tm.thing->target->player && tm.thing->target->player->bubbleblowup) + else if ((tm.thing->type == MT_BUBBLESHIELD && tm.thing->target->player && tm.thing->target->player->bubbleblowup) || (tm.thing->player && tm.thing->player->bubbleblowup)) - && (thing->type == MT_ORBINAUT || thing->type == MT_JAWZ || thing->type == MT_GACHABOM - || thing->type == MT_BANANA || thing->type == MT_EGGMANITEM || thing->type == MT_BALLHOG - || thing->type == MT_SSMINE || thing->type == MT_LANDMINE || thing->type == MT_SINK - || thing->type == MT_GARDENTOP - || thing->type == MT_DROPTARGET - || thing->type == MT_KART_LEFTOVER - || (thing->type == MT_PLAYER && tm.thing->target != thing))) { // see if it went over / under if (tm.thing->z > thing->z + thing->height) @@ -1028,7 +1036,18 @@ static BlockItReturn_t PIT_CheckThing(mobj_t *thing) if (tm.thing->z + tm.thing->height < thing->z) return BMIT_CONTINUE; // underneath - return K_BubbleShieldCollide(tm.thing, thing) ? BMIT_CONTINUE : BMIT_ABORT; + if (P_BubbleCanReflect(tm.thing, thing)) + { + // don't let player hitbox touch it too + if (tm.thing->player) + return BMIT_CONTINUE; + return K_BubbleShieldCollide(tm.thing, thing) ? BMIT_CONTINUE : BMIT_ABORT; + } + else if ((thing->flags & MF_SHOOTABLE) && !tm.thing->player) + { + P_DamageMobj(thing, tm.thing, tm.thing->target, 1, DMG_NORMAL); + return BMIT_CONTINUE; + } } // double make sure bubbles won't collide with anything else From 26b03a810c237a334015fba49c9e227e806e464c Mon Sep 17 00:00:00 2001 From: James R Date: Sat, 13 Jan 2024 16:54:20 -0800 Subject: [PATCH 13/21] HUD: fix GOAL not turning rainbow if point limit is less than 5 --- src/k_hud.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/k_hud.cpp b/src/k_hud.cpp index d1ab57c6f..17b396872 100644 --- a/src/k_hud.cpp +++ b/src/k_hud.cpp @@ -2226,7 +2226,13 @@ struct PositionFacesInfo player_t* top() const { return &players[rankplayer[0]]; } UINT32 top_score() const { return top()->roundscore; } - bool near_goal() const { return g_pointlimit - 5 <= top_score(); } + + bool near_goal() const + { + constexpr tic_t kThreshold = 5; + return std::max(kThreshold, g_pointlimit) - kThreshold <= top_score(); + } + skincolornum_t vomit_color() const { if (!near_goal()) From 92f6e61243b7da1885930900bf6b047daa76404c Mon Sep 17 00:00:00 2001 From: James R Date: Sat, 13 Jan 2024 16:59:12 -0800 Subject: [PATCH 14/21] Battle: downscale hitlag VFX and Gahabom explosion (not in Prisons) - Hitlag VFX: 3/4x - Gachabom explosion: 1/2x --- src/k_hitlag.c | 6 ++++++ src/objects/gachabom-rebound.cpp | 6 +++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/k_hitlag.c b/src/k_hitlag.c index 3f1a3afad..e211e90c0 100644 --- a/src/k_hitlag.c +++ b/src/k_hitlag.c @@ -14,6 +14,7 @@ #include "doomdef.h" #include "doomstat.h" +#include "k_battle.h" #include "k_kart.h" #include "m_random.h" #include "p_local.h" @@ -195,6 +196,11 @@ static void K_SpawnHitLagEFX(mobj_t *victim, mobj_t *inflictor, mobj_t *source, newScale = 3 * victim->destscale; } + if ((gametyperules & GTR_BUMPERS) && battleprisons == false) + { + newScale = 3 * newScale / 4; + } + if (P_MobjWasRemoved(source) == false) { color = (source->player != NULL) ? source->player->skincolor : source->color; diff --git a/src/objects/gachabom-rebound.cpp b/src/objects/gachabom-rebound.cpp index 9c12ba0ad..91e1f23c5 100644 --- a/src/objects/gachabom-rebound.cpp +++ b/src/objects/gachabom-rebound.cpp @@ -1,6 +1,7 @@ #include #include "../d_player.h" +#include "../k_battle.h" #include "../k_objects.h" #include "../m_fixed.h" #include "../info.h" @@ -230,7 +231,10 @@ void Obj_SpawnGachaBomRebound(mobj_t* source, mobj_t* target) x->color = target->color; x->angle = angle; - P_InstaScale(x, 2 * x->scale); + if (!(gametyperules & GTR_BUMPERS) || battleprisons) + { + P_InstaScale(x, 2 * x->scale); + } rebound_mode(x) = static_cast(mode); rebound_timer(x) = kReboundAcceptPause; From 9e650fa6c022483e727dc3ce0e1915c67a8fc60e Mon Sep 17 00:00:00 2001 From: James R Date: Sat, 13 Jan 2024 17:30:16 -0800 Subject: [PATCH 15/21] Guard: reflect items like Bubble - Clash + player knockback --- src/k_collide.cpp | 5 +++++ src/p_map.c | 21 +++++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/src/k_collide.cpp b/src/k_collide.cpp index d10dd845f..c9dd7085b 100644 --- a/src/k_collide.cpp +++ b/src/k_collide.cpp @@ -771,6 +771,11 @@ boolean K_BubbleShieldCollide(mobj_t *t1, mobj_t *t2) { if (!t2->threshold || t2->type == MT_DROPTARGET) { + if (t1->player && K_PlayerGuard(t1->player)) + { + K_KartSolidBounce(t1, t2); + K_DoPowerClash(t1, t2); + } if (!t2->momx && !t2->momy) { t2->momz += (24*t2->scale) * P_MobjFlip(t2); diff --git a/src/p_map.c b/src/p_map.c index 782028790..95e509cca 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -1004,6 +1004,27 @@ static BlockItReturn_t PIT_CheckThing(mobj_t *thing) if (tm.thing->type == MT_RANDOMITEM) return BMIT_CONTINUE; + if (tm.thing->type != MT_PLAYER && thing->player && K_PlayerGuard(thing->player) && P_BubbleCanReflect(thing, tm.thing)) + { + // see if it went over / under + if (tm.thing->z > thing->z + thing->height) + return BMIT_CONTINUE; // overhead + if (tm.thing->z + tm.thing->height < thing->z) + return BMIT_CONTINUE; // underneath + + return K_BubbleShieldCollide(thing, tm.thing) ? BMIT_CONTINUE : BMIT_ABORT; + } + else if (thing->type != MT_PLAYER && tm.thing->player && K_PlayerGuard(tm.thing->player) && P_BubbleCanReflect(tm.thing, thing)) + { + // see if it went over / under + if (tm.thing->z > thing->z + thing->height) + return BMIT_CONTINUE; // overhead + if (tm.thing->z + tm.thing->height < thing->z) + return BMIT_CONTINUE; // underneath + + return K_BubbleShieldCollide(tm.thing, thing) ? BMIT_CONTINUE : BMIT_ABORT; + } + // Bubble Shield reflect if ((thing->type == MT_BUBBLESHIELD && thing->target->player && thing->target->player->bubbleblowup) || (thing->player && thing->player->bubbleblowup)) From f8f2c51a8d810e2618dd7e9a852f3b9c2d4130d6 Mon Sep 17 00:00:00 2001 From: James R Date: Sat, 13 Jan 2024 17:43:48 -0800 Subject: [PATCH 16/21] Bubble/Guard: reflect strength 4x -> 6x --- src/k_collide.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/k_collide.cpp b/src/k_collide.cpp index c9dd7085b..30cdf5745 100644 --- a/src/k_collide.cpp +++ b/src/k_collide.cpp @@ -782,9 +782,9 @@ boolean K_BubbleShieldCollide(mobj_t *t1, mobj_t *t2) } else { - t2->momx = -4*t2->momx; - t2->momy = -4*t2->momy; - t2->momz = -4*t2->momz; + t2->momx = -6*t2->momx; + t2->momy = -6*t2->momy; + t2->momz = -6*t2->momz; t2->angle += ANGLE_180; } if (t2->type == MT_JAWZ) From 9af09ec5076a67d35df1141331be71ced47b41dd Mon Sep 17 00:00:00 2001 From: James R Date: Sat, 13 Jan 2024 18:38:33 -0800 Subject: [PATCH 17/21] Bubble/Guard: fix reflected item intangibility, transfer ownership of reflected items - Ignores item just-thrown intangibility only if the item owner is the same (standard behavior) - Player who reflected the item takes ownership of it - Required to make intangibility work correctly - Improvement to game design --- src/k_collide.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/k_collide.cpp b/src/k_collide.cpp index 30cdf5745..afc72e998 100644 --- a/src/k_collide.cpp +++ b/src/k_collide.cpp @@ -769,7 +769,9 @@ boolean K_BubbleShieldCollide(mobj_t *t1, mobj_t *t2) } else { - if (!t2->threshold || t2->type == MT_DROPTARGET) + mobj_t *owner = t1->player ? t1 : t1->target; + + if (t2->target != owner || !t2->threshold || t2->type == MT_DROPTARGET) { if (t1->player && K_PlayerGuard(t1->player)) { @@ -789,6 +791,7 @@ boolean K_BubbleShieldCollide(mobj_t *t1, mobj_t *t2) } if (t2->type == MT_JAWZ) P_SetTarget(&t2->tracer, t2->target); // Back to the source! + P_SetTarget(&t2->target, owner); // Let the source reflect it back again! t2->threshold = 10; S_StartSound(t1, sfx_s3k44); } From ce1fe0028a05e69f8f8f41a1a4b6a94dec7723d7 Mon Sep 17 00:00:00 2001 From: James R Date: Sat, 13 Jan 2024 19:17:57 -0800 Subject: [PATCH 18/21] Insta-Whip: respect flashing tics unless player is in damage state - Matches new flashing tics behavior --- src/k_collide.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/k_collide.cpp b/src/k_collide.cpp index afc72e998..b9fc3c391 100644 --- a/src/k_collide.cpp +++ b/src/k_collide.cpp @@ -822,8 +822,7 @@ boolean K_InstaWhipCollide(mobj_t *shield, mobj_t *victim) { player_t *victimPlayer = victim->player; - //if (victim != attacker && !P_PlayerInPain(victimPlayer) && victimPlayer->flashing == 0) - if (victim != attacker && victim->hitlag == 0) + if (victim != attacker && (P_PlayerInPain(victimPlayer) ? victim->hitlag == 0 : victimPlayer->flashing == 0)) { // If both players have a whip, hits are order-of-execution dependent and that sucks. // Player expectation is a clash here. From 9c7e8b8be33aec982207fac4d54734908bfddf16 Mon Sep 17 00:00:00 2001 From: James R Date: Sat, 13 Jan 2024 20:00:14 -0800 Subject: [PATCH 19/21] Battle: cap point limit at 20 --- src/k_kart.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/k_kart.c b/src/k_kart.c index 095d5cfdd..6e5434a85 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -13328,6 +13328,11 @@ UINT32 K_PointLimitForGametype(void) ptsCap += 4; } } + + if (ptsCap > 20) + { + ptsCap = 20; + } } return ptsCap; From bb2affc484f72a100dfcb9da687fa5fd01988b36 Mon Sep 17 00:00:00 2001 From: James R Date: Sat, 13 Jan 2024 20:23:35 -0800 Subject: [PATCH 20/21] Battle: base PWR level on correct score value --- src/k_pwrlv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/k_pwrlv.c b/src/k_pwrlv.c index 0a15b6c9b..4d7bc80e4 100644 --- a/src/k_pwrlv.c +++ b/src/k_pwrlv.c @@ -131,7 +131,7 @@ INT16 K_PowerLevelPlacementScore(player_t *player) } else { - return player->score; + return player->roundscore; } } From 2213386498aff7bb79ecd4bf546a48b022dd31be Mon Sep 17 00:00:00 2001 From: James R Date: Sat, 13 Jan 2024 20:44:24 -0800 Subject: [PATCH 21/21] HUD: fix 1P Battle GOAL offset in Duel --- src/k_hud.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/k_hud.cpp b/src/k_hud.cpp index 17b396872..7afd5a493 100644 --- a/src/k_hud.cpp +++ b/src/k_hud.cpp @@ -2315,7 +2315,11 @@ void PositionFacesInfo::draw_1p() UINT32 skinflags; if (gametyperules & GTR_POINTLIMIT) // playing battle - Y += (9*5) - 5; // <-- arbitrary calculation + { + Y += 40; + if (ranklines < 3) + Y -= 18; + } else if (ranklines < 5) Y += (9*ranklines); else