From a217178951210973aaf448ad9a47c7f726e874ea Mon Sep 17 00:00:00 2001 From: James R Date: Thu, 11 Jan 2024 21:25:29 -0800 Subject: [PATCH 01/20] Super Flicky: nerf while owner is in pain state - Not nerfed while orbiting the owner --- src/objects/super-flicky.cpp | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/objects/super-flicky.cpp b/src/objects/super-flicky.cpp index a27b8eded..15181e847 100644 --- a/src/objects/super-flicky.cpp +++ b/src/objects/super-flicky.cpp @@ -273,6 +273,8 @@ struct Flicky : mobj_t bool stunned() const { return mode() == Mode::kStunned || mode() == Mode::kWeak; } + bool owner_in_pain() const { return source()->player && P_PlayerInPain(source()->player); } + void light_up(bool n) { if (n) @@ -613,6 +615,25 @@ struct Flicky : mobj_t S_StartSound(this, sfx_s3k9f); } + void try_nerf() + { + if (owner_in_pain()) + { + mode(Mode::kWeak); + delay(2); + nerf(); + flags |= MF_NOGRAVITY; + } + } + + void preserve_nerf() + { + if (owner_in_pain()) + { + delay(1); + } + } + void whip() { reflect(); @@ -772,6 +793,7 @@ void Obj_SuperFlickyThink(mobj_t* mobj) break; case Flicky::Mode::kHunting: + x->try_nerf(); x->chase(); break; @@ -779,6 +801,7 @@ void Obj_SuperFlickyThink(mobj_t* mobj) break; case Flicky::Mode::kWeak: + x->preserve_nerf(); x->chase(); break; } From 3856fbf1c63259a847346df46e9de00606f922da Mon Sep 17 00:00:00 2001 From: James R Date: Thu, 11 Jan 2024 22:01:35 -0800 Subject: [PATCH 02/20] Add K_UpdateDamageFlashing, refactor Battle 0-flashing tics Instead of setting flashing tics to 0 in Battle, simply don't update the value in damage contexts (if Battle). --- src/k_kart.c | 19 ++++++++++++------- src/k_kart.h | 1 + src/p_inter.c | 2 +- 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/src/k_kart.c b/src/k_kart.c index 1c1bc19d7..94b59d1e0 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -3550,11 +3550,6 @@ UINT16 K_GetKartFlashing(const player_t *player) { UINT16 tics = flashingtics; - if (gametyperules & GTR_BUMPERS) - { - return 0; - } - if (player == NULL) { return tics; @@ -3564,6 +3559,16 @@ 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 ( @@ -8391,9 +8396,9 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) if (player->spinouttimer != 0) { if (( player->spinouttype & KSPIN_IFRAMES ) == 0) - player->flashing = 0; + K_UpdateDamageFlashing(player, 0); else - player->flashing = K_GetKartFlashing(player); + K_UpdateDamageFlashing(player, K_GetKartFlashing(player)); } if (player->spinouttimer) diff --git a/src/k_kart.h b/src/k_kart.h index 73a80694d..98d76b46c 100644 --- a/src/k_kart.h +++ b/src/k_kart.h @@ -192,6 +192,7 @@ 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 f8166381b..daa6eab8b 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -3333,7 +3333,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) - player->flashing = K_GetKartFlashing(player); + K_UpdateDamageFlashing(player, K_GetKartFlashing(player)); player->ringburst += ringburst; From 182df7bf44eb69e3a0b46df5557645d6223e173a Mon Sep 17 00:00:00 2001 From: James R Date: Thu, 11 Jan 2024 22:02:44 -0800 Subject: [PATCH 03/20] Give player 2 seconds of flashing tics when picking up power-ups --- src/p_inter.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/p_inter.c b/src/p_inter.c index daa6eab8b..4bc4cf9d8 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -402,6 +402,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) return; K_GivePowerUp(player, special->threshold, special->movecount); + player->flashing = 2*TICRATE; } else { From 49f0b31db7336a9844c8bd5eecaef0670adf57cf Mon Sep 17 00:00:00 2001 From: James R Date: Thu, 11 Jan 2024 22:03:10 -0800 Subject: [PATCH 04/20] Battle: do not decrease flashing tics in the air --- src/p_user.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/p_user.c b/src/p_user.c index 9fb1d06b4..f6d774cd2 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -4412,7 +4412,9 @@ void P_PlayerThink(player_t *player) // Strength counts up to diminish fade. if (player->flashing && player->flashing < UINT16_MAX && - (player->spectator || !P_PlayerInPain(player))) + (player->spectator || !P_PlayerInPain(player)) && + // Battle: flashing tics do not decrease in the air + (!(gametyperules & GTR_BUMPERS) || P_IsObjectOnGround(player->mo))) { player->flashing--; } From ecf9fd53f60ad670b295755d5c80853de1ddb4b7 Mon Sep 17 00:00:00 2001 From: James R Date: Thu, 11 Jan 2024 22:33:59 -0800 Subject: [PATCH 05/20] Players cannot be invincible to Insta-whip vs Guard counter Hacked into P_DamageMobj by way of inflictor == target --- src/k_collide.cpp | 5 +++-- src/p_inter.c | 6 ++++++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/k_collide.cpp b/src/k_collide.cpp index b9338e681..38e69c8e4 100644 --- a/src/k_collide.cpp +++ b/src/k_collide.cpp @@ -860,7 +860,8 @@ boolean K_InstaWhipCollide(mobj_t *shield, mobj_t *victim) attacker->momx = attacker->momy = 0; P_Thrust(attacker, thrangle, mapobjectscale*7); - P_DamageMobj(attacker, victim, victim, 1, DMG_TUMBLE); + // target is inflictor: hack to let invincible players lose to guard + P_DamageMobj(attacker, attacker, victim, 1, DMG_TUMBLE); // A little extra juice, so successful reads are usually positive or zero on spheres. victimPlayer->spheres = std::min(victimPlayer->spheres + 10, 40); @@ -883,7 +884,7 @@ boolean K_InstaWhipCollide(mobj_t *shield, mobj_t *victim) P_PlayVictorySound(victim); - P_DamageMobj(attacker, victim, victim, 1, DMG_TUMBLE); + P_DamageMobj(attacker, attacker, victim, 1, DMG_TUMBLE); S_StartSound(victim, sfx_mbv92); K_AddHitLag(attacker, victimHitlag, true); diff --git a/src/p_inter.c b/src/p_inter.c index 4bc4cf9d8..24edf3fdd 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -3076,6 +3076,12 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da invincible = false; } + // Hack for instawhip-guard counter, lets invincible players lose to guard + if (inflictor == target) + { + invincible = false; + } + // TODO: doing this from P_DamageMobj limits punting to objects that damage the player. // And it may be kind of yucky. // But this is easier than accounting for every condition in PIT_CheckThing! From b5d87a89f4076258d7249c28bc92fb0db45d9236 Mon Sep 17 00:00:00 2001 From: James R Date: Fri, 12 Jan 2024 00:57:56 -0800 Subject: [PATCH 06/20] Battle: use Prison Break spawnpoints in Duels --- src/g_game.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/g_game.c b/src/g_game.c index ef9b54f3c..5ebbf062b 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -2802,9 +2802,9 @@ mapthing_t *G_FindMapStart(INT32 playernum) if (K_PodiumSequence() == true) spawnpoint = G_FindPodiumStart(playernum); - // -- Time Attack -- + // -- Time Attack / Battle duels -- // Order: Race->DM->CTF - else if (K_TimeAttackRules() == true) + else if (K_TimeAttackRules() == true || ((gametyperules & GTR_BATTLESTARTS) && inDuel)) spawnpoint = G_FindRaceStartOrFallback(playernum); // -- CTF -- From e26a95af6e4ec31a07ca36ab2b4db4977520ac05 Mon Sep 17 00:00:00 2001 From: James R Date: Fri, 12 Jan 2024 01:10:37 -0800 Subject: [PATCH 07/20] Battle: show rank number on Tally screen --- src/k_hud.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/k_hud.cpp b/src/k_hud.cpp index f6bbcab2a..f7ea1837d 100644 --- a/src/k_hud.cpp +++ b/src/k_hud.cpp @@ -5550,7 +5550,7 @@ void K_drawKartHUD(void) } else if (freecam) ; - else if ((gametyperules & GTR_POWERSTONES)) + else if ((gametyperules & GTR_POWERSTONES) && !K_PlayerTallyActive(stplyr)) { if (!battleprisons) K_drawKartEmeralds(); From 69c3aaf4f2fc186586e8f3f1ebed246b10a72d6c Mon Sep 17 00:00:00 2001 From: James R Date: Fri, 12 Jan 2024 02:05:45 -0800 Subject: [PATCH 08/20] Gachabom Rebound: fix crash after owner object is removed --- src/info.c | 2 +- src/objects/orbinaut.c | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/info.c b/src/info.c index 4ed3520e2..9e57f5690 100644 --- a/src/info.c +++ b/src/info.c @@ -5601,7 +5601,7 @@ state_t states[NUMSTATES] = {SPR_UFOS, 0, -1, {NULL}, 0, 0, S_NULL}, // S_SPECIAL_UFO_STEM {SPR_GBOM, FF_ANIMATE, -1, {NULL}, 3, 1, S_NULL}, // S_GACHABOM - {SPR_GBOM, FF_INVERT, 2, {NULL}, 0, 0, S_NULL}, // S_GACHABOM_DEAD + {SPR_GBOM, FF_INVERT, 175, {NULL}, 0, 0, S_NULL}, // S_GACHABOM_DEAD {SPR_NULL, 0, 1, {NULL}, 0, 0, S_GACHABOM_EXPLOSION_2}, {SPR_GCHX, 0|FF_PAPERSPRITE|FF_ANIMATE, 14, {NULL}, 6, 2, S_GACHABOM_EXPLOSION_3A}, // S_GACHABOM_EXPLOSION_2 diff --git a/src/objects/orbinaut.c b/src/objects/orbinaut.c index 631b6f79e..a158b9a93 100644 --- a/src/objects/orbinaut.c +++ b/src/objects/orbinaut.c @@ -284,12 +284,13 @@ boolean Obj_OrbinautJawzCollide(mobj_t *t1, mobj_t *t2) S_StartSound(t1, t1->info->deathsound); P_KillMobj(t1, t2, t2, DMG_NORMAL); - if (t1->type == MT_GACHABOM) + if (t1->type == MT_GACHABOM && !P_MobjWasRemoved(orbinaut_owner(t1))) { // Instead of flying out at an angle when // destroyed, spawn an explosion and eventually // return to sender. The original Gachabom will be // removed next tic (see deathstate). + t1->tics = 2; Obj_SpawnGachaBomRebound(t1, orbinaut_owner(t1)); } else From 76b0639d7854c514e9e4b7b88ec500b2d77833ed Mon Sep 17 00:00:00 2001 From: James R Date: Fri, 12 Jan 2024 05:01:01 -0800 Subject: [PATCH 09/20] v_draw.hpp: fix r_draw.h being included inside srb2 namespace --- src/v_draw.hpp | 4 ++-- src/v_draw_setter.hpp | 5 +++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/v_draw.hpp b/src/v_draw.hpp index 8e04cc1c7..f283b25cd 100644 --- a/src/v_draw.hpp +++ b/src/v_draw.hpp @@ -256,8 +256,8 @@ private: static fixed_t font_width(Font font, INT32 flags, const char* string); }; -#include "v_draw_setter.hpp" - }; // namespace srb2 +#include "v_draw_setter.hpp" + #endif // __V_DRAW_HPP__ diff --git a/src/v_draw_setter.hpp b/src/v_draw_setter.hpp index 1085d3087..11b0b3e96 100644 --- a/src/v_draw_setter.hpp +++ b/src/v_draw_setter.hpp @@ -12,6 +12,9 @@ #include "r_draw.h" // R_GetTranslationColormap +namespace srb2 +{ + inline Draw::Chain& Draw::Chain::x(float x) { x_ += x; @@ -115,4 +118,6 @@ inline Draw::Chain& Draw::Chain::colorize(skincolornum_t color) return colormap(R_GetTranslationColormap(TC_RAINBOW, color, GTC_CACHE)); } +}; // namespace srb2 + #endif // __V_DRAW_SETTER_HPP__ From 45ef00fb63a17f34029576f75b5ad636a6ce8d68 Mon Sep 17 00:00:00 2001 From: James R Date: Fri, 12 Jan 2024 05:02:14 -0800 Subject: [PATCH 10/20] HUD: load Battle GOAL graphics --- src/k_hud.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/k_hud.cpp b/src/k_hud.cpp index f7ea1837d..1e8d0bc5c 100644 --- a/src/k_hud.cpp +++ b/src/k_hud.cpp @@ -111,6 +111,10 @@ static patch_t *kp_rankemerald; static patch_t *kp_rankemeraldflash; static patch_t *kp_rankemeraldback; +static patch_t *kp_goal[2][2]; // [skull][4p] +static patch_t *kp_goalrod[2]; // [4p] +static patch_t *kp_goaltext1p; + static patch_t *kp_battlewin; static patch_t *kp_battlecool; static patch_t *kp_battlelose; @@ -452,6 +456,15 @@ void K_LoadKartHUDGraphics(void) HU_UpdatePatch(&kp_rankemeraldflash, "K_EMERW"); HU_UpdatePatch(&kp_rankemeraldback, "K_EMERBK"); + // Battle goal + HU_UpdatePatch(&kp_goal[0][0], "K_ST1GLA"); + HU_UpdatePatch(&kp_goal[1][0], "K_ST1GLB"); + HU_UpdatePatch(&kp_goal[0][1], "K_ST4GLA"); + HU_UpdatePatch(&kp_goal[1][1], "K_ST4GLB"); + HU_UpdatePatch(&kp_goalrod[0], "K_ST1GLD"); + HU_UpdatePatch(&kp_goalrod[1], "K_ST4GLD"); + HU_UpdatePatch(&kp_goaltext1p, "K_ST1GLC"); + // Battle graphics HU_UpdatePatch(&kp_battlewin, "K_BWIN"); HU_UpdatePatch(&kp_battlecool, "K_BCOOL"); From a14adfa410c4e7bcaa3c1ad7e4f88bf6f39af5e2 Mon Sep 17 00:00:00 2001 From: James R Date: Fri, 12 Jan 2024 05:02:36 -0800 Subject: [PATCH 11/20] HUD: Battle rankings and GOAL (1P version only) Battle-specific HUD: - 3 players in rankings - Display player always appears on rankings (even if they are not in the top 3) - GOAL icon at the top of the rankings - Normally displays point limit - Becomes a skull when display player has reached point limit - "KO" flashes over the skull, at a rate of 6/12 tics --- src/k_hud.cpp | 47 +++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 45 insertions(+), 2 deletions(-) diff --git a/src/k_hud.cpp b/src/k_hud.cpp index 1e8d0bc5c..12e28e2d6 100644 --- a/src/k_hud.cpp +++ b/src/k_hud.cpp @@ -12,6 +12,8 @@ #include #include +#include "v_draw.hpp" + #include "k_hud.h" #include "k_kart.h" #include "k_battle.h" @@ -2272,7 +2274,9 @@ static boolean K_drawKartPositionFaces(void) ranklines++; } - if (ranklines < 5) + if (gametyperules & GTR_POINTLIMIT) // playing battle + Y += (9*5) - 5; // <-- arbitrary calculation + else if (ranklines < 5) Y += (9*ranklines); else Y += (9*5); @@ -2280,7 +2284,46 @@ static boolean K_drawKartPositionFaces(void) ranklines--; i = ranklines; - if ((gametyperules & GTR_POINTLIMIT) || strank <= 2) // too close to the top, or playing battle, or a spectator? would have had (strank == -1) called out, but already caught by (strank <= 2) + if (gametyperules & GTR_POINTLIMIT) // playing battle + { + // 3 lines max in Battle + if (i > 2) + i = 2; + ranklines = 0; + + // You must appear on the leaderboard, even if you don't rank top 3 + if (strank > i) + { + strank = i; + rankplayer[strank] = stplyr - players; + } + + // Draw GOAL + UINT8 skull = g_pointlimit <= stplyr->roundscore; + INT32 height = i*18; + INT32 GOAL_Y = Y-height; + V_DrawScaledPatch(FACE_X-5, GOAL_Y-32, V_HUDTRANS|V_SLIDEIN|V_SNAPTOLEFT, kp_goal[skull][0]); + + // Flashing KO + if (skull) + { + if (leveltime % 12 < 6) + V_DrawScaledPatch(FACE_X-5, GOAL_Y-32, V_HUDTRANS|V_SLIDEIN|V_SNAPTOLEFT, kp_goaltext1p); + } + else + { + using srb2::Draw; + Draw(FACE_X+8.5, GOAL_Y-15) + .font(Draw::Font::kZVote) + .align(Draw::Align::kCenter) + .flags(V_HUDTRANS|V_SLIDEIN|V_SNAPTOLEFT) + .text("{:02}", g_pointlimit); + } + + // Line cutting behind rank faces + V_DrawScaledPatch(FACE_X+6, GOAL_Y, V_HUDTRANS|V_SLIDEIN|V_SNAPTOLEFT, kp_goalrod[0]); + } + else if (strank <= 2) // too close to the top, or a spectator? would have had (strank == -1) called out, but already caught by (strank <= 2) { if (i > 4) // could be both... i = 4; From c3a6f6b77d9b86d9b2dcd0e4eb868449b7f90ae1 Mon Sep 17 00:00:00 2001 From: James R Date: Fri, 12 Jan 2024 05:25:27 -0800 Subject: [PATCH 12/20] K_drawKartPositionFaces: refactor into class so splitscreen drawing methods can be added --- src/k_hud.cpp | 58 +++++++++++++++++++++++++++++++++++---------------- 1 file changed, 40 insertions(+), 18 deletions(-) diff --git a/src/k_hud.cpp b/src/k_hud.cpp index 12e28e2d6..a344607e6 100644 --- a/src/k_hud.cpp +++ b/src/k_hud.cpp @@ -2211,24 +2211,20 @@ static void K_DrawKartPositionNum(UINT8 num) ); } -static boolean K_drawKartPositionFaces(void) +struct PositionFacesInfo { - // FACE_X = 15; // 15 - // FACE_Y = 72; // 72 + INT32 ranklines = 0; + INT32 strank = -1; + INT32 numplayersingame = 0; + INT32 rankplayer[MAXPLAYERS] = {}; - INT32 Y = FACE_Y-9; // -9 to offset where it's being drawn if there are more than one - INT32 i, j, ranklines, strank = -1; - boolean completed[MAXPLAYERS]; - INT32 rankplayer[MAXPLAYERS]; - INT32 bumperx, emeraldx, numplayersingame = 0; - INT32 xoff, yoff, flipflag = 0; - UINT8 workingskin; - UINT8 *colormap; - UINT32 skinflags; + PositionFacesInfo(); + void draw_1p(); +}; - ranklines = 0; - memset(completed, 0, sizeof (completed)); - memset(rankplayer, 0, sizeof (rankplayer)); +PositionFacesInfo::PositionFacesInfo() +{ + INT32 i, j; for (i = 0; i < MAXPLAYERS; i++) { @@ -2241,10 +2237,9 @@ static boolean K_drawKartPositionFaces(void) } if (numplayersingame <= 1) - return true; + return; - if (!LUA_HudEnabled(hud_minirankings)) - return false; // Don't proceed but still return true for free play above if HUD is disabled. + boolean completed[MAXPLAYERS] = {}; for (j = 0; j < numplayersingame; j++) { @@ -2273,6 +2268,20 @@ static boolean K_drawKartPositionFaces(void) ranklines++; } +} + +void PositionFacesInfo::draw_1p() +{ + // FACE_X = 15; // 15 + // FACE_Y = 72; // 72 + + INT32 Y = FACE_Y-9; // -9 to offset where it's being drawn if there are more than one + INT32 i, j; + INT32 bumperx, emeraldx; + INT32 xoff, yoff, flipflag = 0; + UINT8 workingskin; + UINT8 *colormap; + UINT32 skinflags; if (gametyperules & GTR_POINTLIMIT) // playing battle Y += (9*5) - 5; // <-- arbitrary calculation @@ -2456,6 +2465,19 @@ static boolean K_drawKartPositionFaces(void) Y -= 18; } +} + +static boolean K_drawKartPositionFaces(void) +{ + PositionFacesInfo state{}; + + if (state.numplayersingame <= 1) + return true; + + if (!LUA_HudEnabled(hud_minirankings)) + return false; // Don't proceed but still return true for free play above if HUD is disabled. + + state.draw_1p(); return false; } From f232647868555c29b9d41af9f2366e1807ccb001 Mon Sep 17 00:00:00 2001 From: James R Date: Fri, 12 Jan 2024 06:10:43 -0800 Subject: [PATCH 13/20] HUD: Battle rankings and GOAL (4P version) + 4P timer tweak - 4P version only displays top 2 players - Compared to 1P version, local player is not required to be on the list - Skull is displayed if any of the party members have reached the point limit - 4P timers reduced to just digits, in order to make space for rankings --- src/hud/timer.cpp | 7 +++-- src/k_hud.cpp | 66 ++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 68 insertions(+), 5 deletions(-) diff --git a/src/hud/timer.cpp b/src/hud/timer.cpp index 98456e8dd..39131e9d5 100644 --- a/src/hud/timer.cpp +++ b/src/hud/timer.cpp @@ -43,16 +43,15 @@ void K_drawKart2PTimestamp(void) void K_drawKart4PTimestamp(void) { - Draw row = Draw(154, 0).flags(kHudFlags).font(Draw::Font::kZVote).align(Draw::Align::kCenter); + Draw row = Draw(159, 0).flags(kHudFlags).font(Draw::Font::kZVote).align(Draw::Align::kCenter); auto draw = [](const Draw& row, tic_t time) { - row.patch("K_STTIMS"); - row.xy(5, 12).text("{:03}", time / TICRATE); + row.text("{:03}", time / TICRATE); }; auto time_of = [](int k) -> tic_t { return k <= r_splitscreen ? player_timer(&players[displayplayers[k]]) : 0u; }; draw(row.y(1).flags(V_SNAPTOTOP), std::max(time_of(0), time_of(1))); - draw(row.y(178).flags(V_SNAPTOBOTTOM), std::max(time_of(2), time_of(3))); + draw(row.y(191).flags(V_SNAPTOBOTTOM), std::max(time_of(2), time_of(3))); } diff --git a/src/k_hud.cpp b/src/k_hud.cpp index a344607e6..8c2c907f1 100644 --- a/src/k_hud.cpp +++ b/src/k_hud.cpp @@ -2220,6 +2220,7 @@ struct PositionFacesInfo PositionFacesInfo(); void draw_1p(); + void draw_4p_battle(int y, INT32 flags); }; PositionFacesInfo::PositionFacesInfo() @@ -2467,6 +2468,53 @@ void PositionFacesInfo::draw_1p() } } +void PositionFacesInfo::draw_4p_battle(int y, INT32 flags) +{ + using srb2::Draw; + Draw row = Draw(152, y).flags(V_HUDTRANS | V_SLIDEIN | flags).font(Draw::Font::kPing); + + UINT8 skull = [] + { + int party = G_PartySize(consoleplayer); + for (int i = 0; i < party; ++i) + { + // Is any party member about to win? + if (g_pointlimit <= players[G_PartyMember(consoleplayer, i)].roundscore) + { + return 1; + } + } + return 0; + }(); + + row.patch(kp_goal[skull][1]); + + if (!skull) + { + row.xy(8.5, 5).align(Draw::Align::kCenter).text("{:02}", g_pointlimit); + } + + row.xy(7, 18).patch(kp_goalrod[1]); + + auto head = [&](Draw col, int i) + { + const player_t& p = players[rankplayer[i]]; + col.colormap(p.skin, static_cast(p.skincolor)).patch(faceprefix[p.skin][FACE_MINIMAP]); + + bool dance = g_pointlimit <= p.roundscore; + bool flash = dance && leveltime % 8 < 4; + ( + flash ? + col.xy(8, 6).colorize(SKINCOLOR_TANGERINE).flags(V_STRINGDANCE) : + col.xy(8, 6).flags(dance ? V_STRINGDANCE : 0) + ).text("{:02}", p.roundscore); + }; + + // Draw top 2 players + head(row.xy(2, 31), 1); + head(row.xy(2, 18), 0); +} + static boolean K_drawKartPositionFaces(void) { PositionFacesInfo state{}; @@ -2477,7 +2525,18 @@ static boolean K_drawKartPositionFaces(void) if (!LUA_HudEnabled(hud_minirankings)) return false; // Don't proceed but still return true for free play above if HUD is disabled. - state.draw_1p(); + switch (r_splitscreen) + { + case 0: + state.draw_1p(); + break; + + case 2: + case 3: + state.draw_4p_battle(9, V_SNAPTOTOP); + state.draw_4p_battle(147, V_SNAPTOBOTTOM); + break; + } return false; } @@ -5592,6 +5651,11 @@ void K_drawKartHUD(void) { K_drawKart4PTimestamp(); } + + if (gametyperules & GTR_POINTLIMIT) + { + K_drawKartPositionFaces(); + } } } From 02719ef2bf69f934ceb5d3b7e22dd44071fba07c Mon Sep 17 00:00:00 2001 From: James R Date: Fri, 12 Jan 2024 06:46:46 -0800 Subject: [PATCH 14/20] HUD: Battle GOAL cycles colors when someone comes within 5 points of winning - Colors cycle at a speed of 4 tics - Adjusted "KO" flashing rate from 6/12 -> 8/16 --- src/k_hud.cpp | 37 ++++++++++++++++++++++++++++++++++--- 1 file changed, 34 insertions(+), 3 deletions(-) diff --git a/src/k_hud.cpp b/src/k_hud.cpp index 8c2c907f1..f3b99c876 100644 --- a/src/k_hud.cpp +++ b/src/k_hud.cpp @@ -10,6 +10,7 @@ /// \brief HUD drawing functions exclusive to Kart #include +#include #include #include "v_draw.hpp" @@ -2221,6 +2222,27 @@ struct PositionFacesInfo PositionFacesInfo(); void draw_1p(); void draw_4p_battle(int y, INT32 flags); + + UINT32 top_score() const { return players[rankplayer[0]].roundscore; } + bool near_goal() const { return g_pointlimit - 5 <= top_score(); } + skincolornum_t vomit_color() const + { + if (!near_goal()) + { + return SKINCOLOR_NONE; + } + + constexpr int kCycleSpeed = 4; + constexpr std::array kColors = { + SKINCOLOR_RED, + SKINCOLOR_VOMIT, + SKINCOLOR_YELLOW, + SKINCOLOR_GREEN, + SKINCOLOR_JET, + SKINCOLOR_MOONSET, + }; + return kColors[leveltime / kCycleSpeed % kColors.size()]; + } }; PositionFacesInfo::PositionFacesInfo() @@ -2312,12 +2334,20 @@ void PositionFacesInfo::draw_1p() UINT8 skull = g_pointlimit <= stplyr->roundscore; INT32 height = i*18; INT32 GOAL_Y = Y-height; - V_DrawScaledPatch(FACE_X-5, GOAL_Y-32, V_HUDTRANS|V_SLIDEIN|V_SNAPTOLEFT, kp_goal[skull][0]); + + colormap = nullptr; + + if (skincolornum_t vomit = vomit_color()) + { + colormap = R_GetTranslationColormap(TC_DEFAULT, vomit, GTC_CACHE); + } + + V_DrawMappedPatch(FACE_X-5, GOAL_Y-32, V_HUDTRANS|V_SLIDEIN|V_SNAPTOLEFT, kp_goal[skull][0], colormap); // Flashing KO if (skull) { - if (leveltime % 12 < 6) + if (leveltime % 16 < 8) V_DrawScaledPatch(FACE_X-5, GOAL_Y-32, V_HUDTRANS|V_SLIDEIN|V_SNAPTOLEFT, kp_goaltext1p); } else @@ -2487,7 +2517,8 @@ void PositionFacesInfo::draw_4p_battle(int y, INT32 flags) return 0; }(); - row.patch(kp_goal[skull][1]); + skincolornum_t vomit = vomit_color(); + (vomit ? row.colormap(vomit) : row).patch(kp_goal[skull][1]); if (!skull) { From 4694cb79ff0a053ffeee05e7e055c565307edd43 Mon Sep 17 00:00:00 2001 From: James R Date: Fri, 12 Jan 2024 07:30:32 -0800 Subject: [PATCH 15/20] HUD: Battle rankings and GOAL (2P version) + 2P minimap tweak - 2P version just reuses 4P version - Minimap shifted over slightly to make room --- src/k_hud.cpp | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/src/k_hud.cpp b/src/k_hud.cpp index f3b99c876..b71d5a8f6 100644 --- a/src/k_hud.cpp +++ b/src/k_hud.cpp @@ -1244,6 +1244,7 @@ static void K_initKartHUD(void) STCD_Y = BASEVIDHEIGHT/4; + MINI_X -= 16; MINI_Y = (BASEVIDHEIGHT/2); if (r_splitscreen > 1) // 3P/4P Small Splitscreen @@ -2221,7 +2222,7 @@ struct PositionFacesInfo PositionFacesInfo(); void draw_1p(); - void draw_4p_battle(int y, INT32 flags); + void draw_4p_battle(int x, int y, INT32 flags); UINT32 top_score() const { return players[rankplayer[0]].roundscore; } bool near_goal() const { return g_pointlimit - 5 <= top_score(); } @@ -2498,10 +2499,10 @@ void PositionFacesInfo::draw_1p() } } -void PositionFacesInfo::draw_4p_battle(int y, INT32 flags) +void PositionFacesInfo::draw_4p_battle(int x, int y, INT32 flags) { using srb2::Draw; - Draw row = Draw(152, y).flags(V_HUDTRANS | V_SLIDEIN | flags).font(Draw::Font::kPing); + Draw row = Draw(x, y).flags(V_HUDTRANS | V_SLIDEIN | flags).font(Draw::Font::kPing); UINT8 skull = [] { @@ -2562,10 +2563,14 @@ static boolean K_drawKartPositionFaces(void) state.draw_1p(); break; + case 1: + state.draw_4p_battle(292, 78, V_SNAPTORIGHT); + break; + case 2: case 3: - state.draw_4p_battle(9, V_SNAPTOTOP); - state.draw_4p_battle(147, V_SNAPTOBOTTOM); + state.draw_4p_battle(152, 9, V_SNAPTOTOP); + state.draw_4p_battle(152, 147, V_SNAPTOBOTTOM); break; } @@ -5675,6 +5680,11 @@ void K_drawKartHUD(void) { K_drawKart2PTimestamp(); } + + if (viewnum == r_splitscreen && gametyperules & GTR_POINTLIMIT) + { + K_drawKartPositionFaces(); + } } else if (viewnum == r_splitscreen) { From 711ffbef0a4177dea630dc271349a5b7cd351f45 Mon Sep 17 00:00:00 2001 From: James R Date: Fri, 12 Jan 2024 16:35:05 -0800 Subject: [PATCH 16/20] Guard Break: fix Guard not being broken --- 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 94b59d1e0..54724bc28 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -3831,7 +3831,7 @@ void K_DoGuardBreak(mobj_t *t1, mobj_t *t2) { if (P_PlayerInPain(t2->player)) return; - t1->player->instaWhipCharge = 0; + t1->player->defenseLockout = 1; S_StartSound(t1, sfx_gbrk); K_AddHitLag(t1, 24, true); From eb8741b481a4a238741ec2849f82b7c88e80120b Mon Sep 17 00:00:00 2001 From: James R Date: Fri, 12 Jan 2024 17:02:56 -0800 Subject: [PATCH 17/20] Barrier power-up: fix insta-whip - Fix being unable to insta-whip - Fix insta-whip interrupting Barrier --- src/k_kart.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/k_kart.c b/src/k_kart.c index 54724bc28..769b676c7 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -8574,7 +8574,9 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) S_StartSound(player->mo, sfx_s1af); player->oldGuard = true; - player->instaWhipCharge = 0; + + if (!K_PowerUpRemaining(player, POWERUP_BARRIER)) + player->instaWhipCharge = 0; } else if (player->oldGuard) { @@ -11679,10 +11681,9 @@ void K_MoveKartPlayer(player_t *player, boolean onground) else { player->instaWhipCharge = 0; - player->defenseLockout = PUNISHWINDOW; if (!K_PowerUpRemaining(player, POWERUP_BARRIER)) { - player->defenseLockout = INSTAWHIP_CHARGETIME; + player->defenseLockout = PUNISHWINDOW; } S_StartSound(player->mo, sfx_iwhp); From 92acc809759daa5f3821afa1aa83d331b5ba3734 Mon Sep 17 00:00:00 2001 From: James R Date: Fri, 12 Jan 2024 17:42:23 -0800 Subject: [PATCH 18/20] Battle: fix Overtime 1v1 sound playing when last player is eliminated - It should only play when a 3rd player dies, and leaves 2 remaining --- src/k_battle.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/k_battle.c b/src/k_battle.c index 8e9aba69f..97b134e0b 100644 --- a/src/k_battle.c +++ b/src/k_battle.c @@ -150,7 +150,7 @@ void K_CheckBumpers(void) } } - if (numingame - eliminated <= 2 && battleovertime.enabled && battleovertime.radius <= BARRIER_MIN_RADIUS) + if (numingame - eliminated == 2 && battleovertime.enabled && battleovertime.radius <= BARRIER_MIN_RADIUS) { Music_Stop("battle_overtime"); S_StartSound(NULL, sfx_kc4b); // Loud noise helps mask transition From b6a725ad7bc75ceb79936814c677ab303e14cc5b Mon Sep 17 00:00:00 2001 From: James R Date: Fri, 12 Jan 2024 17:54:30 -0800 Subject: [PATCH 19/20] HUD tracking: fix Super Flicky crash if owner died --- src/k_hud_track.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/k_hud_track.cpp b/src/k_hud_track.cpp index f0e01b1a0..bf1221edb 100644 --- a/src/k_hud_track.cpp +++ b/src/k_hud_track.cpp @@ -82,7 +82,7 @@ struct TargetTracking return player_emeralds_color(); case MT_SUPER_FLICKY: - return static_cast(Obj_SuperFlickyOwner(mobj)->color); + return Obj_SuperFlickyOwner(mobj) ? static_cast(Obj_SuperFlickyOwner(mobj)->color) : SKINCOLOR_NONE; default: return SKINCOLOR_NONE; From f2f2b41034b8da3a62725eda9f343da32c6043e9 Mon Sep 17 00:00:00 2001 From: James R Date: Fri, 12 Jan 2024 17:56:44 -0800 Subject: [PATCH 20/20] K_PlayerGuard: always disable if player is in damage state - Fixes Barrier power-up not being interrupted by damage state --- src/k_kart.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/k_kart.c b/src/k_kart.c index 769b676c7..71fe75aa6 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -10790,6 +10790,11 @@ boolean K_PlayerGuard(const player_t *player) return false; } + if (P_PlayerInPain(player) == true) + { + return false; + } + if (K_PowerUpRemaining(player, POWERUP_BARRIER)) { return true; @@ -10814,7 +10819,6 @@ boolean K_PlayerGuard(const player_t *player) if (K_PressingEBrake(player) == true && (player->drift == 0 || P_IsObjectOnGround(player->mo) == false) - && P_PlayerInPain(player) == false && player->spindashboost == 0 && player->nocontrol == 0) {