From ce77568087a5cf30835dc301cdeb7aebb7e65822 Mon Sep 17 00:00:00 2001 From: Antonio Martinez Date: Fri, 20 Jun 2025 20:29:03 -0400 Subject: [PATCH] Bubble refinements --- src/d_player.h | 1 + src/deh_tables.c | 1 + src/info.c | 2 + src/info.h | 2 + src/k_kart.c | 73 +++++++++++++++++++++++++++++------ src/k_kart.h | 2 +- src/lua_playerlib.c | 4 ++ src/objects/bubble-shield.cpp | 18 ++++++++- src/p_saveg.cpp | 2 + src/p_user.c | 1 + 10 files changed, 92 insertions(+), 14 deletions(-) diff --git a/src/d_player.h b/src/d_player.h index 23369d110..5cb2f7afc 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -1046,6 +1046,7 @@ struct player_t UINT8 lastsafecheatcheck; UINT8 ignoreAirtimeLeniency; // We bubblebounced or otherwise did an airtime thing with control, powerup timers should still count down + boolean bubbledrag; // Just bubblebounced, slow down! fixed_t topAccel; // Reduced on straight wall collisions to give players extra recovery time fixed_t vortexBoost; diff --git a/src/deh_tables.c b/src/deh_tables.c index c6d40380a..cd479a80c 100644 --- a/src/deh_tables.c +++ b/src/deh_tables.c @@ -2047,6 +2047,7 @@ const char *const STATE_LIST[] = { // array length left dynamic for sanity testi "S_BUBC2", "S_BUBD1", "S_BUBE1", + "S_BUBG1", // F used by Nova Shore // Flame Shield "S_FLAMESHIELD1", diff --git a/src/info.c b/src/info.c index 8ac7b4eba..690b5e5c7 100644 --- a/src/info.c +++ b/src/info.c @@ -390,6 +390,7 @@ char sprnames[NUMSPRITES + 1][5] = "BUBC", // Bubble Shield Bottom Wave "BUBD", // Bubble Shield Reflection "BUBE", // Bubble Shield Underline + "BUBG", // Bubble Shield drag "BWVE", // Bubble Shield waves "FLMS", // Flame Shield "FLMA", // Flame Shield Top Layer @@ -2604,6 +2605,7 @@ state_t states[NUMSTATES] = {SPR_NULL, 0, 5, {NULL}, 0, 0, S_BUBC1}, // S_BUBC2 {SPR_BUBD, FF_FULLBRIGHT, 1, {NULL}, 0, 0, S_BUBD1}, // S_BUBD1 {SPR_BUBE, FF_FULLBRIGHT, 1, {NULL}, 0, 0, S_BUBE1}, // S_BUBE1 + {SPR_BUBG, FF_FULLBRIGHT, 1, {NULL}, 0, 0, S_BUBG1}, // S_BUBG1 {SPR_FLMS, FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_FLAMESHIELD2}, // S_FLAMESHIELD1 {SPR_FLMS, FF_FULLBRIGHT|9, 2, {NULL}, 0, 0, S_FLAMESHIELD3}, // S_FLAMESHIELD2 diff --git a/src/info.h b/src/info.h index e6df879b5..f704e4426 100644 --- a/src/info.h +++ b/src/info.h @@ -931,6 +931,7 @@ typedef enum sprite SPR_BUBC, // Bubble Shield Bottom Wave SPR_BUBD, // Bubble Shield Reflection SPR_BUBE, // Bubble Shield Underline + SPR_BUBG, // Bubble Shield drag SPR_BWVE, // Bubble Shield waves SPR_FLMS, // Flame Shield SPR_FLMA, // Flame Shield Top Layer @@ -3101,6 +3102,7 @@ typedef enum state S_BUBC2, S_BUBD1, S_BUBE1, + S_BUBG1, // Flame Shield S_FLAMESHIELD1, diff --git a/src/k_kart.c b/src/k_kart.c index 5870ba4c2..f442b9d38 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -72,6 +72,15 @@ // comeback is Battle Mode's karma comeback, also bool // mapreset is set when enough players fill an empty server +static void K_PopBubbleShield(player_t *player) +{ + S_StartSound(player->mo, sfx_kc31); + K_StripItems(player); + K_AddHitLag(player->mo, 4, false); + vector3_t offset = { 0, 0, 0 }; + K_SpawnSingleHitLagSpark(player->mo, &offset, player->mo->scale*2, 4, 0, player->skincolor); +} + boolean K_ThunderDome(void) { if (K_CanChangeRules(true)) @@ -479,17 +488,24 @@ boolean K_IsPlayerLosing(player_t *player) } // Some behavior should change if the player approaches the frontrunner unusually fast. -boolean K_IsPlayerScamming(player_t *player) +fixed_t K_PlayerScamPercentage(player_t *player, UINT8 mult) { if (!M_NotFreePlay()) - return false; + return 0; if (!(gametyperules & GTR_CIRCUIT)) - return false; + return 0; // "Why 8?" Consistency // "Why 2000?" Vibes - return (K_GetItemRouletteDistance(player, 8) < SCAMDIST); + + UINT32 distance = K_GetItemRouletteDistance(player, 8); + UINT32 scamdistance = mult * SCAMDIST; + + if (distance >= scamdistance) + return 0; + + return Easing_Linear((scamdistance - distance) * FRACUNIT / scamdistance, 0, FRACUNIT); } fixed_t K_GetKartGameSpeedScalar(SINT8 value) @@ -9950,7 +9966,7 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) if (player->invincibilitytimer && (player->ignoreAirtimeLeniency > 0 || onground == true || K_PowerUpRemaining(player, POWERUP_SMONITOR))) { player->invincibilitytimer--; - if (player->invincibilitytimer && K_IsPlayerScamming(player)) + if (player->invincibilitytimer && K_PlayerScamPercentage(player, 1)) player->invincibilitytimer--; // Extra tripwire leniency for the end of invincibility @@ -10028,7 +10044,7 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) if (player->growshrinktimer > 0 && (onground == true || player->ignoreAirtimeLeniency > 0)) { player->growshrinktimer--; - if (player->growshrinktimer && K_IsPlayerScamming(player)) + if (player->growshrinktimer && K_PlayerScamPercentage(player, 1)) player->growshrinktimer--; } @@ -10059,6 +10075,34 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) if (player->ignoreAirtimeLeniency) player->ignoreAirtimeLeniency--; + if (player->bubbledrag) + { + if (onground) + { + player->bubbledrag = false; + } + else + { + fixed_t scam = K_PlayerScamPercentage(player, 2); + fixed_t speed = R_PointToDist2(0, 0, player->mo->momx, player->mo->momy); + fixed_t basespeed = K_GetKartSpeed(player, false, false); + + fixed_t targetspeed = 4 * basespeed; + targetspeed -= FixedMul(scam, targetspeed); + + // CONS_Printf("spd %d tspd %d psp %d\n", speed, targetspeed, scam); + + fixed_t div = 12*FRACUNIT; // bigger number slower drag + + if (speed > targetspeed) + { + fixed_t newspeed = speed - FixedDiv((speed - targetspeed), div); + player->mo->momx = FixedMul(FixedDiv(player->mo->momx, speed), newspeed); + player->mo->momy = FixedMul(FixedDiv(player->mo->momy, speed), newspeed); + } + } + } + if (player->freeRingShooterCooldown && !player->mo->hitlag) player->freeRingShooterCooldown--; @@ -13218,6 +13262,7 @@ boolean K_FastFallBounce(player_t *player) P_InstaThrust(player->mo, player->mo->angle, 11*max(minspeed, fallspeed)/10); player->ignoreAirtimeLeniency = max(player->ignoreAirtimeLeniency, TICRATE); + player->bubbledrag = true; bounce += 3 * mapobjectscale; @@ -13236,14 +13281,12 @@ boolean K_FastFallBounce(player_t *player) numplayers = 1; // solo behavior } + /* if (player->position == 1 && player->positiondelay <= 0 && numplayers != 1) { - S_StartSound(player->mo, sfx_kc31); - K_StripItems(player); - K_AddHitLag(player->mo, 4, false); - vector3_t offset = { 0, 0, 0 }; - K_SpawnSingleHitLagSpark(player->mo, &offset, player->mo->scale*2, 4, 0, player->skincolor); + K_PopBubbleShield(player); } + */ if (player->tripwireReboundDelay) bounce /= 2; @@ -14512,14 +14555,20 @@ void K_MoveKartPlayer(player_t *player, boolean onground) if (player->bubbleblowup > bubbletime*2) { player->itemamount--; - K_ThrowKartItem(player, (player->throwdir > 0), MT_BUBBLESHIELDTRAP, -1, 0, 0); + if (player->throwdir == -1) { P_InstaThrust(player->mo, player->mo->angle, player->speed + (80 * mapobjectscale)); player->wavedashboost += TICRATE; player->wavedashpower = FRACUNIT; player->fakeBoost += TICRATE/2; + K_PopBubbleShield(player); } + else + { + K_ThrowKartItem(player, (player->throwdir > 0), MT_BUBBLESHIELDTRAP, -1, 0, 0); + } + K_PlayAttackTaunt(player->mo); player->bubbleblowup = 0; player->bubblecool = 0; diff --git a/src/k_kart.h b/src/k_kart.h index 9cf9bdaea..0ad2ca587 100644 --- a/src/k_kart.h +++ b/src/k_kart.h @@ -124,7 +124,7 @@ UINT32 K_GetPlayerDontDrawFlag(player_t *player); void K_ReduceVFXForEveryone(mobj_t *mo); boolean K_IsPlayerLosing(player_t *player); -boolean K_IsPlayerScamming(player_t *player); +fixed_t K_PlayerScamPercentage(player_t *player, UINT8 mult); fixed_t K_GetKartGameSpeedScalar(SINT8 value); INT32 K_GetShieldFromItem(INT32 item); diff --git a/src/lua_playerlib.c b/src/lua_playerlib.c index 2f580553a..1a7d199c0 100644 --- a/src/lua_playerlib.c +++ b/src/lua_playerlib.c @@ -412,6 +412,8 @@ static int player_get(lua_State *L) lua_pushinteger(L, plr->lastsafecheatcheck); else if (fastcmp(field,"ignoreairtimeleniency")) lua_pushinteger(L, plr->ignoreAirtimeLeniency); + else if (fastcmp(field,"bubbledrag")) + lua_pushinteger(L, plr->bubbledrag); else if (fastcmp(field,"topaccel")) lua_pushinteger(L, plr->topAccel); else if (fastcmp(field,"vortexboost")) @@ -1042,6 +1044,8 @@ static int player_set(lua_State *L) plr->lastsafecheatcheck = luaL_checkinteger(L, 3); else if (fastcmp(field,"ignoreairtimeleniency")) plr->ignoreAirtimeLeniency = luaL_checkinteger(L, 3); + else if (fastcmp(field,"bubbledrag")) + plr->bubbledrag = luaL_checkinteger(L, 3); else if (fastcmp(field,"topaccel")) plr->topAccel = luaL_checkinteger(L, 3); else if (fastcmp(field,"vortexboost")) diff --git a/src/objects/bubble-shield.cpp b/src/objects/bubble-shield.cpp index 89d60e129..5b69d28e8 100644 --- a/src/objects/bubble-shield.cpp +++ b/src/objects/bubble-shield.cpp @@ -15,6 +15,7 @@ #include "../m_easing.h" #include "../m_fixed.h" #include "../tables.h" +#include "../k_hud.h" // transflag using namespace srb2::objects; @@ -89,6 +90,7 @@ struct Visual : Mobj if (sprite != SPR_BUBB && sprite != SPR_BUBC && + sprite != SPR_BUBG && bubble()->player()->bubblecool && f == 0) // base size renderflags |= RF_DONTDRAW; @@ -113,6 +115,19 @@ struct Visual : Mobj spritescale({ FRACUNIT, FRACUNIT }); } + if (sprite == SPR_BUBG) + { + renderflags &= ~(RF_TRANSMASK|RF_DONTDRAW); + renderflags |= RF_ADD; + + fixed_t transpercent = K_PlayerScamPercentage(bubble()->follow()->player, 2); + UINT8 transfactor = (transpercent * NUMTRANSMAPS) / FRACUNIT; + + if (transfactor < 10) + renderflags |= ((10-transfactor) << RF_TRANSSHIFT); + // CONS_Printf("tp %d rf %d\n", transpercent, renderflags); + } + prev_scale(scale()); return true; @@ -123,7 +138,8 @@ struct Visual : Mobj void Obj_SpawnBubbleShieldVisuals(mobj_t *bubble) { - Visual::spawn(static_cast(bubble), S_BUBA1, 1, 2); + Visual::spawn(static_cast(bubble), S_BUBA1, 1, 3); + Visual::spawn(static_cast(bubble), S_BUBG1, 0, 2); Visual::spawn(static_cast(bubble), S_BUBB1, 0, 1); Visual::spawn(static_cast(bubble), S_BUBC1, 1, -1); Visual::spawn(static_cast(bubble), S_BUBD1, 0, -2); diff --git a/src/p_saveg.cpp b/src/p_saveg.cpp index 8ec1685f1..8e6bcc6e8 100644 --- a/src/p_saveg.cpp +++ b/src/p_saveg.cpp @@ -641,6 +641,7 @@ static void P_NetArchivePlayers(savebuffer_t *save) WRITEUINT8(save->p, players[i].lastsafecheatcheck); WRITEUINT8(save->p, players[i].ignoreAirtimeLeniency); + WRITEUINT8(save->p, players[i].bubbledrag); WRITEFIXED(save->p, players[i].topAccel); WRITEFIXED(save->p, players[i].vortexBoost); @@ -1292,6 +1293,7 @@ static void P_NetUnArchivePlayers(savebuffer_t *save) players[i].lastsafecheatcheck = READUINT8(save->p); players[i].ignoreAirtimeLeniency = READUINT8(save->p); + players[i].bubbledrag = READUINT8(save->p); players[i].topAccel = READFIXED(save->p); players[i].vortexBoost = READFIXED(save->p); diff --git a/src/p_user.c b/src/p_user.c index a7753235e..74a4be388 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -428,6 +428,7 @@ void P_ResetPlayer(player_t *player) player->glanceDir = 0; player->fastfall = 0; player->turbine = 0; + player->bubbledrag = false; Obj_EndBungee(player); if (player->mo != NULL && P_MobjWasRemoved(player->mo) == false)