Merge branch 'bubble-speed-cap' into 'master'

Bubble refinements

See merge request kart-krew-dev/ring-racers-internal!2639
This commit is contained in:
Oni VelocitOni 2025-06-21 05:19:17 +00:00
commit 53129a6b73
10 changed files with 98 additions and 18 deletions

View file

@ -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;

View file

@ -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",

View file

@ -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

View file

@ -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,

View file

@ -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)
@ -9951,7 +9967,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
@ -10029,7 +10045,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--;
}
@ -10060,6 +10076,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, BUBBLESCAM);
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--;
@ -13219,6 +13263,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;
@ -13237,14 +13282,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;
@ -14513,14 +14556,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;

View file

@ -91,6 +91,8 @@ Make sure this matches the actual number of states
#define MAXTOPACCEL (12*FRACUNIT)
#define TOPACCELREGEN (FRACUNIT/16)
#define BUBBLESCAM (4)
// Handling boosts and sliptide conditions got weird.
// You must be under a handling boost of at least SLIPTIDEHANDLING to sliptide.
// HANDLESCALING is used to adjust all handling boosts simultaneously (weight factors in the future?)
@ -124,7 +126,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);

View file

@ -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"))

View file

@ -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, BUBBLESCAM);
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,11 +138,12 @@ struct Visual : Mobj
void Obj_SpawnBubbleShieldVisuals(mobj_t *bubble)
{
Visual::spawn(static_cast<Bubble*>(bubble), S_BUBA1, 1, 2);
Visual::spawn(static_cast<Bubble*>(bubble), S_BUBB1, 0, 1);
Visual::spawn(static_cast<Bubble*>(bubble), S_BUBC1, 1, -1);
Visual::spawn(static_cast<Bubble*>(bubble), S_BUBD1, 0, -2);
Visual::spawn(static_cast<Bubble*>(bubble), S_BUBE1, 1, -3);
Visual::spawn(static_cast<Bubble*>(bubble), S_BUBA1, 1, 3); //Top shine/outline
Visual::spawn(static_cast<Bubble*>(bubble), S_BUBB1, 0, 2); //Top wave
Visual::spawn(static_cast<Bubble*>(bubble), S_BUBG1, 0, 1); //Fog mechanic
Visual::spawn(static_cast<Bubble*>(bubble), S_BUBC1, 1, -1); //Back Wave
Visual::spawn(static_cast<Bubble*>(bubble), S_BUBD1, 0, -2); //Bottom Reflection
Visual::spawn(static_cast<Bubble*>(bubble), S_BUBE1, 1, -3); //Backlit outline
}
boolean Obj_TickBubbleShieldVisual(mobj_t *mobj)

View file

@ -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);

View file

@ -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)