Merge pull request '[FEAT] Recovery Dash / Recovery Spin' (#213) from ssmt into next

Reviewed-on: https://codeberg.org/NepDisk/blankart/pulls/213
This commit is contained in:
minenice55 2026-01-29 23:46:23 +01:00
commit 7d82c72092
16 changed files with 343 additions and 13 deletions

View file

@ -93,7 +93,7 @@
#define ASSET_HASH_TEXTURES_KART 0xb4211b2f32b6a291
#define ASSET_HASH_CHARS_KART 0x1e68a3e01aa5c68b
#define ASSET_HASH_MAPS_KART 0x38558ed00da41ce9
#define ASSET_HASH_MAIN_PK3 0xbfb32f5c97ecf875
#define ASSET_HASH_MAIN_PK3 0x6a399991c4467fe6
#define ASSET_HASH_MAPPATCH_PK3 0xbbc2c6a7a685da3a
#define ASSET_HASH_BONUSCHARS_KART 0x60e6f13d822a7461
#ifdef USE_PATCH_FILE

View file

@ -170,6 +170,7 @@ static void KartSlopeBoost_OnChange(void);
static void KartDrafting_OnChange(void);
static void KartAirDrop_OnChange(void);
static void KartAirThrust_OnChange(void);
static void KartRecoveryDash_OnChange(void);
static void KartWaterSkipLock_OnChange(void);
static void KartItemLitter_OnChange(void);
static void KartItemPush_OnChange(void);
@ -549,6 +550,18 @@ consvar_t cv_kartstacking_ring_accelboost = CVAR_INIT ("vanillaboost_ring_accelb
consvar_t cv_kartstacking_ring_handleboost = CVAR_INIT ("vanillaboost_ring_handleboost", "0", CV_NETVAR|CV_CHEAT|CV_FLOAT|CV_GUARD, CV_Unsigned, NULL);
consvar_t cv_kartstacking_ring_stackable = CVAR_INIT ("vanillaboost_ring_stackable", "On", CV_NETVAR|CV_CHEAT|CV_GUARD, CV_OnOff, NULL);
consvar_t cv_kartstacking_ssmt_speedboost = CVAR_INIT ("vanillaboost_ssmt_speedboost", "0.1", CV_NETVAR|CV_CHEAT|CV_FLOAT|CV_GUARD, CV_Unsigned, NULL);
consvar_t cv_kartstacking_ssmt_accelboost = CVAR_INIT ("vanillaboost_ssmt_accelboost", "8.0", CV_NETVAR|CV_CHEAT|CV_FLOAT|CV_GUARD, CV_Unsigned, NULL);
consvar_t cv_kartstacking_ssmt_handleboost = CVAR_INIT ("vanillaboost_ssmt_handleboost", "0.1", CV_NETVAR|CV_CHEAT|CV_FLOAT|CV_GUARD, CV_Unsigned, NULL);
consvar_t cv_kartstacking_recspin_speedboost_lo = CVAR_INIT ("vanillaboost_recspin_speedboost_lo", "0.0001", CV_NETVAR|CV_CHEAT|CV_FLOAT|CV_GUARD, CV_Unsigned, NULL);
consvar_t cv_kartstacking_recspin_accelboost_lo = CVAR_INIT ("vanillaboost_recspin_accelboost_lo", "2.0", CV_NETVAR|CV_CHEAT|CV_FLOAT|CV_GUARD, CV_Unsigned, NULL);
consvar_t cv_kartstacking_recspin_handleboost_lo = CVAR_INIT ("vanillaboost_recspin_handleboost_lo", "0.25", CV_NETVAR|CV_CHEAT|CV_FLOAT|CV_GUARD, CV_Unsigned, NULL);
consvar_t cv_kartstacking_recspin_speedboost_hi = CVAR_INIT ("vanillaboost_recspin_speedboost_hi", "0.0001", CV_NETVAR|CV_CHEAT|CV_FLOAT|CV_GUARD, CV_Unsigned, NULL);
consvar_t cv_kartstacking_recspin_accelboost_hi = CVAR_INIT ("vanillaboost_recspin_accelboost_hi", "8.0", CV_NETVAR|CV_CHEAT|CV_FLOAT|CV_GUARD, CV_Unsigned, NULL);
consvar_t cv_kartstacking_recspin_handleboost_hi = CVAR_INIT ("vanillaboost_recspin_handleboost_hi", "0.5", CV_NETVAR|CV_CHEAT|CV_FLOAT|CV_GUARD, CV_Unsigned, NULL);
consvar_t cv_kartstacking_slope_decay = CVAR_INIT ("vanillaboost_slope_decay", "0.004", CV_NETVAR|CV_CHEAT|CV_FLOAT|CV_GUARD, CV_Unsigned, NULL);
consvar_t cv_kartstacking_slope_brakemod = CVAR_INIT ("vanillaboost_slope_brakemod", "0.01", CV_NETVAR|CV_CHEAT|CV_FLOAT|CV_GUARD, CV_Unsigned, NULL);
consvar_t cv_kartstacking_slope_speedboost_max = CVAR_INIT ("vanillaboost_slope_speedboost_max", "3.0", CV_NETVAR|CV_CHEAT|CV_FLOAT|CV_GUARD, CV_Unsigned, NULL);
@ -617,6 +630,9 @@ consvar_t cv_kartforcelegacyodds = CVAR_INIT ("kartforcelegacyodds", "Off", CV_N
consvar_t cv_handleboostslip = CVAR_INIT ("karthandleboostsliptide", "Off", CV_NETVAR, CV_OnOff, NULL);
consvar_t cv_kartrecoverydash = CVAR_INIT ("kartrecoverydash", "No", CV_NETVAR|CV_CALL|CV_NOINIT|CV_GUARD, CV_YesNo, KartRecoveryDash_OnChange);
consvar_t cv_kartrecoverydash_spinspeed = CVAR_INIT ("kartrecoverydash_spinspeed", "24.0", CV_NETVAR|CV_FLOAT|CV_CHEAT|CV_GUARD, CV_Unsigned, NULL);
#define ANTIBUMP_MAX (UINT32_MAX / TICRATE)
static CV_PossibleValue_t antibump_cons_t[] = {{0, "MIN"}, {ANTIBUMP_MAX, "MAX"}, {0, NULL}};
consvar_t cv_kartantibump = CVAR_INIT ("kartantibump", "0", CV_NETVAR|CV_CALL|CV_NOINIT, antibump_cons_t, KartAntiBump_OnChange);
@ -8500,6 +8516,39 @@ static void KartAirThrust_OnChange(void)
}
}
static void KartRecoveryDash_OnChange(void)
{
if (K_CanChangeRules(false) == false)
{
return;
}
if (!K_RecoveryDashActive() && cv_kartrecoverydash.value)
{
if (leveltime < starttime)
{
recoverydashactive = true;
CONS_Printf(M_GetText("Recovery Dash has been turned \"On\".\n"));
}
else
{
CONS_Printf(M_GetText("Recovery Dash will be turned \"On\" Next Round.\n"));
}
}
else if (K_RecoveryDashActive() && !cv_kartrecoverydash.value)
{
if (leveltime < starttime)
{
recoverydashactive = false;
CONS_Printf(M_GetText("Recovery Dash has been turned \"Off\".\n"));
}
else
{
CONS_Printf(M_GetText("Recovery Dash will be turned \"Off\" next round.\n"));
}
}
}
static void KartWaterSkipLock_OnChange(void)
{
if (K_CanChangeRules(false) == false)

View file

@ -167,6 +167,18 @@ extern consvar_t cv_kartstacking_ring_accelboost;
extern consvar_t cv_kartstacking_ring_handleboost;
extern consvar_t cv_kartstacking_ring_stackable;
extern consvar_t cv_kartstacking_ssmt_speedboost;
extern consvar_t cv_kartstacking_ssmt_accelboost;
extern consvar_t cv_kartstacking_ssmt_handleboost;
extern consvar_t cv_kartstacking_recspin_speedboost_lo;
extern consvar_t cv_kartstacking_recspin_accelboost_lo;
extern consvar_t cv_kartstacking_recspin_handleboost_lo;
extern consvar_t cv_kartstacking_recspin_speedboost_hi;
extern consvar_t cv_kartstacking_recspin_accelboost_hi;
extern consvar_t cv_kartstacking_recspin_handleboost_hi;
extern consvar_t cv_kartstacking_slope_decay;
extern consvar_t cv_kartstacking_slope_brakemod;
extern consvar_t cv_kartstacking_slope_speedboost_max;
@ -230,6 +242,9 @@ extern consvar_t cv_kartforcelegacyodds;
extern consvar_t cv_handleboostslip;
extern consvar_t cv_kartrecoverydash;
extern consvar_t cv_kartrecoverydash_spinspeed;
extern consvar_t cv_kartoddsdist;
extern consvar_t cv_kartlegacyoddsdist;

View file

@ -103,8 +103,9 @@ typedef enum
PF_SHRINKACTIVE = 1<<26, // "Shrink me" cheat is in effect. (Can't be disabled mid-race)
PF_JUSTFLIPPED = 1<<27, // Just got flipped over, handle the bump interaction.
PF_RECOVERYSPIN = 1<<28, // Player was charging SSMT last tick
// up to 1<<28 is free
PF_USEDOWN = 1<<29, // For lua compat, don't use!
PF_ATTACKDOWN = 1<<30, // For lua compat, don't use!
PF_SLIDING = 1<<31, // For lua compat, don't use!
@ -598,6 +599,9 @@ struct player_t
// Potentially influenced by player lag.
tic_t driftdelay;
tic_t recoverydashcharge; // Time spent charging SSMT
UINT16 recoverydash; // SSMT boost timer (weak boost that ignores offroad)
fixed_t spinoutrot; // When a player spins out, this value increments modulus 360.
SINT8 aizdriftstrat; // (-1 to 1) - Let go of your drift while boosting? Helper for the SICK STRATZ (sliptiding!) you have just unlocked
@ -619,6 +623,7 @@ struct player_t
fixed_t prevspeedboost; // Max speed boost value from the last frame
fixed_t accelboost; // Boost value smoothing for acceleration
fixed_t handleboost; // Boost value smoothing for handling
fixed_t forcedtopspeed; // Force this top speed while charging SSMT
angle_t boostangle; // angle set when not spun out OR boosted to determine what direction you should keep going at if you're spun out and boosted.
boostinfo_t boostinfo; // Stores values used for setting speed and accel boosts.
UINT8 numsneakers; // Number of stacked sneakers

View file

@ -1540,14 +1540,17 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer)
forward += (value * MAXPLMOVE) / JOYAXISRANGE;
}
if (player->sneakertimer)
if (player->sneakertimer || player->recoverydash)
forward = MAXPLMOVE; // 50
value = G_PlayerInputAnalog(forplayer, gc_brake, false, DEADZONE_BUTTON);
if (value != 0)
{
cmd->buttons |= BT_BRAKE;
forward -= (value * 25) / JOYAXISRANGE;
if (!(player->pflags & PF_RECOVERYSPIN))
{
forward -= (value * 25) / JOYAXISRANGE;
}
}
// But forward/backward IS used for aiming.

View file

@ -653,5 +653,8 @@ _(SSWG)
// Arrow Bullet
_(AWBT)
// Recovery Spin Skid
_(RCSP)
// First person view sprites; this is a sprite so that it can be replaced by a specialized MD2 draw later
_(VIEW)

View file

@ -3621,3 +3621,6 @@ _(GHORIZ4)
// Arrow Bullet
_(ALTSHRINK_ARROWBULLET)
// Recovery Spin Skid
_(RECSPIN_SKID)

View file

@ -357,6 +357,17 @@ void K_RegisterKartStuff(void)
CV_RegisterVar(&cv_kartstacking_ring_handleboost);
CV_RegisterVar(&cv_kartstacking_ring_stackable);
CV_RegisterVar(&cv_kartstacking_ssmt_speedboost);
CV_RegisterVar(&cv_kartstacking_ssmt_accelboost);
CV_RegisterVar(&cv_kartstacking_ssmt_handleboost);
CV_RegisterVar(&cv_kartstacking_recspin_speedboost_lo);
CV_RegisterVar(&cv_kartstacking_recspin_accelboost_lo);
CV_RegisterVar(&cv_kartstacking_recspin_handleboost_lo);
CV_RegisterVar(&cv_kartstacking_recspin_speedboost_hi);
CV_RegisterVar(&cv_kartstacking_recspin_accelboost_hi);
CV_RegisterVar(&cv_kartstacking_recspin_handleboost_hi);
CV_RegisterVar(&cv_kartstacking_slope_decay);
CV_RegisterVar(&cv_kartstacking_slope_brakemod);
CV_RegisterVar(&cv_kartstacking_slope_speedboost_max);
@ -407,6 +418,9 @@ void K_RegisterKartStuff(void)
CV_RegisterVar(&cv_kartslopeboost);
CV_RegisterVar(&cv_kartrecoverydash);
CV_RegisterVar(&cv_kartrecoverydash_spinspeed);
CV_RegisterVar(&cv_kartaltshrinktime);
CV_RegisterVar(&cv_kartinvintheme);
@ -2167,7 +2181,9 @@ boolean K_ApplyOffroad(const player_t *player)
if (modeattacking != ATTACKING_NONE)
sneakertimer = player->sneakertimer > 0;
if (player->hyudorotimer || sneakertimer || (cv_kartbubble_boost_offroadignore.value && player->bubbleboost))
if (player->hyudorotimer || sneakertimer ||
(cv_kartbubble_boost_offroadignore.value && player->bubbleboost) ||
player->recoverydash || (player->pflags & PF_RECOVERYSPIN))
return false;
return true;
}
@ -2832,6 +2848,23 @@ static void K_GetKartBoostPower(player_t *player)
K_DoBoost(player, RINGSPEEDBOOST, RINGACCELBOOST, RINGHANDLEBOOST, RINGSTACKABLE, RINGSTACKABLE); // + 20% top speed, + 400% acceleration
}
if (player->recoverydash) // SSMT Boost
{
K_DoBoost(player, SSMTSPEEDBOOST, SSMTACCELBOOST, SSMTHANDLEBOOST, false, true); // + 10% top speed, + ?% acceleration
}
if ((player->pflags & PF_RECOVERYSPIN))
{
if (player->flashing || player->recoverydashcharge >= TICRATE)
{
K_DoBoost(player, RECSPINSPEEDBOOSTHI, RECSPINACCELBOOSTHI, RECSPINHANDLEBOOSTHI, false, false); // + 500% acceleration, + 25% handling
}
else
{
K_DoBoost(player, RECSPINSPEEDBOOSTLO, RECSPINACCELBOOSTLO, RECSPINHANDLEBOOSTLO, false, false);// + 200% acceleration, + 25% handling
}
}
if (player->slopeboost || player->slopeaccel)
{
K_DoBoost(player, player->slopeboost, player->slopeaccel, 0, SLOPESTACKABLE, false); // + ???% top speed, + 300% acceleration
@ -2964,6 +2997,9 @@ fixed_t K_GetKartSpeed(const player_t *player, boolean doboostpower, boolean dor
boolean karmabomb = ((gametyperules & GTR_BUMPERS) && player->bumper <= 0);
fixed_t finalspeed;
if (player->forcedtopspeed > 0)
return FixedMul(player->forcedtopspeed, player->mo->scale);
if (doboostpower && !player->pogospring && !P_IsObjectOnGround(player->mo) && (player->airdriftspeed == 0))
return (75*mapobjectscale); // air speed cap
@ -7041,6 +7077,7 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd)
// Speed lines
if (player->sneakertimer || player->ringboost
|| player->driftboost || player->startboost
|| player->recoverydash
|| player->walltransferboost
|| player->bubbleboost)
{
@ -7239,6 +7276,9 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd)
if (player->realsneakertimer)
player->realsneakertimer--;
if (player->recoverydash)
player->recoverydash--;
if (player->sneakertimer && player->wipeoutslow > 0 && player->wipeoutslow < wipeoutslowtime+1)
player->wipeoutslow = wipeoutslowtime+1;
@ -9132,7 +9172,7 @@ UINT8 K_GetKartDriftSparkStageForValue(const player_t *player, INT32 value)
}
}
static void K_SpawnDriftEFX(player_t *player,SINT8 level)
static void K_SpawnDriftEFX(player_t *player, SINT8 level)
{
mobj_t *overlay = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_BOOSTFLAME);
P_SetMobjState(overlay, S_DRIFTBOOSTFLAME);
@ -9267,6 +9307,10 @@ static void K_KartDrift(player_t *player, boolean onground)
// This fixes this problem.
if (player->pogospring == 2 && player->mo->scale > mapobjectscale)
minspeed = FixedMul(10<<FRACBITS, mapobjectscale);
// horrible
if (player->pflags & PF_RECOVERYSPIN)
minspeed = (player->speed+1);
// air thrust drag
if (K_AirThrustActive())
@ -9464,7 +9508,7 @@ static void K_KartDrift(player_t *player, boolean onground)
// Stop drifting
// experiment: wall transfers should allow zero speed
// reasoning: when driving right into a half pipe face-on, there is no h-speed for the entire launch
if (player->walltransfered || player->dashRingPullTics || player->dashRingPushTics)
if ((player->walltransfered || player->dashRingPullTics || player->dashRingPushTics) && !(player->pflags & PF_RECOVERYSPIN))
{
minspeed = 0;
}
@ -9611,6 +9655,150 @@ static void K_KartSlipdash(player_t *player, boolean onground)
}
}
static boolean K_PlayerCanStartRecoverySpin(player_t *player)
{
return (K_RecoveryDashActive() && P_IsObjectOnGround(player->mo) && (!(player->pflags & PF_STASIS)) && (player->carry == CR_NONE) &&
player->speed < 10*player->mo->scale && (!(player->pflags & PF_RECOVERYSPIN)) &&
(player->cmd.buttons & BT_ACCELERATE) && (player->cmd.buttons & BT_BRAKE) && !(player->cmd.buttons & BT_DRIFT));
}
static boolean K_PlayerCanRecoverySpin(player_t *player)
{
return (K_RecoveryDashActive() && leveltime > starttime && (player->carry == CR_NONE) &&
!(player->sneakertimer || K_IsPlayerDamaged(player) || player->squishedtimer ||
player->exiting || (player->pflags & PF_STASIS) || player->dashpadcooldown ||
player->walltransferboost || player->loop.radius
));
}
static void K_RecoveryDash(player_t *player)
{
if (K_PlayerCanRecoverySpin(player))
{
if (K_PlayerCanStartRecoverySpin(player))
{
player->pflags |= PF_RECOVERYSPIN;
S_StartSound(player->mo, sfx_cdfm20);
}
if (player->pflags & PF_RECOVERYSPIN)
{
if ((player->cmd.buttons & BT_ACCELERATE) && (player->cmd.buttons & BT_BRAKE))
{
player->forcedtopspeed = cv_kartrecoverydash_spinspeed.value + 8;
if (P_IsObjectOnGround(player->mo))
{
player->recoverydashcharge += 1;
K_SpawnWipeoutTrail(player->mo, (player->recoverydashcharge < 3*TICRATE/2));
if (leveltime % 6 == 0)
{
if (player->recoverydashcharge < 2*TICRATE)
{
S_StartSound(player->mo, sfx_s225);
}
}
if (leveltime % 4 == 0)
{
fixed_t newx;
fixed_t newy;
mobj_t *skid;
angle_t travelangle;
travelangle = player->mo->angle;
for (INT32 i = 0; i < 2; i++)
{
newx = P_ReturnThrustX(player->mo, travelangle + ((i&1) ? -1 : 1)*ANGLE_135, FixedMul(28*FRACUNIT, player->mo->scale));
newy = P_ReturnThrustY(player->mo, travelangle + ((i&1) ? -1 : 1)*ANGLE_135, FixedMul(28*FRACUNIT, player->mo->scale));
skid = P_SpawnMobjFromMobj(player->mo, newx, newy, (10*player->mo->scale), MT_OVERLAY);
P_SetTarget(&skid->target, player->mo);
skid->sprxoff = newx;
skid->spryoff = newy;
skid->sprzoff = (10*player->mo->scale);
P_SetScale(skid, player->mo->scale);
skid->destscale = player->mo->destscale;
skid->scalespeed = player->mo->scalespeed;
skid->movefactor = FRACUNIT;
skid->angle = travelangle;
P_SetMobjState(skid, S_RECSPIN_SKID);
K_MatchGenericExtraFlags(skid, player->mo);
if (player->recoverydashcharge >= 2*TICRATE)
{
skid->renderflags |= RF_TRANS20;
}
else
{
skid->renderflags |= RF_TRANS40;
}
if (i) skid->renderflags |= RF_HORIZONTALFLIP;
}
}
}
if (player->recoverydashcharge >= 2*TICRATE)
{
if (player->recoverydashcharge == 2*TICRATE)
{
S_StartSound(player->mo, sfx_s3ka2);
}
if (leveltime & 1)
{
fixed_t newx;
fixed_t newy;
mobj_t *spark;
angle_t travelangle, sparkangle;
travelangle = player->mo->angle;
sparkangle = R_PointToAngle2(0, 0, player->mo->momx, player->mo->momy);
for (INT32 i = 0; i < 2; i++)
{
newx = player->mo->x + P_ReturnThrustX(player->mo, travelangle + ((i&1) ? -1 : 1)*ANGLE_135, FixedMul(32*FRACUNIT, player->mo->scale));
newy = player->mo->y + P_ReturnThrustY(player->mo, travelangle + ((i&1) ? -1 : 1)*ANGLE_135, FixedMul(32*FRACUNIT, player->mo->scale));
spark = P_SpawnMobj(newx, newy, player->mo->z, MT_DRIFTSPARK);
spark->momx = player->mo->momx/2;
spark->momy = player->mo->momy/2;
P_SetTarget(&spark->target, player->mo);
spark->angle = sparkangle;
spark->color = SKINCOLOR_WHITE;
if (player->recoverydashcharge >= 2*TICRATE + TICRATE/4)
{
P_SetMobjState(spark, S_DRIFTSPARK_B1);
}
else
{
P_SetMobjState(spark, S_DRIFTSPARK_A1);
}
K_MatchGenericExtraFlags(spark, player->mo);
}
}
}
}
else
{
player->pflags &= ~PF_RECOVERYSPIN;
player->forcedtopspeed = 0;
player->tiregrease = 2*TICRATE;
if (player->recoverydashcharge >= 2*TICRATE && (player->cmd.buttons & BT_ACCELERATE))
{
player->outrun = TICRATE/4;
player->recoverydash = TICRATE;
player->flashing = 0;
S_StartSound(player->mo, sfx_s23c);
K_SpawnDashDustRelease(player, true);
}
player->recoverydashcharge = 0;
}
}
}
else
{
player->pflags &= ~PF_RECOVERYSPIN;
player->forcedtopspeed = 0;
player->recoverydashcharge = 0;
}
}
INT32 K_GetDriftAngleOffset(player_t *player)
{
INT32 a = 0;
@ -10617,6 +10805,15 @@ static void K_AdjustPlayerFriction(player_t *player)
player->mo->friction = prevfriction;
if ((player->pflags & PF_RECOVERYSPIN) && player->speed < K_GetKartSpeedFromStat(player->kartspeed, false))
{
if (player->cmd.turning)
player->mo->friction += 1880;
else
player->mo->friction += 1280;
K_RecalculateMovefactor(player->mo);
}
// Reduce friction after exiting a loop.
if (player->tiregrease)
{
@ -11058,6 +11255,8 @@ void K_MoveKartPlayer(player_t *player, boolean onground)
K_KartSlipdash(player, onground);
K_RecoveryDash(player);
// Quick Turning
// You can't turn your kart when you're not moving.
// So now it's time to burn some rubber!
@ -11421,6 +11620,17 @@ boolean K_AirThrustActive(void)
return false;
}
boolean K_RecoveryDashActive(void)
{
if (recoverydashactive)
{
// Recovery Dash is enabled!
return true;
}
return false;
}
boolean K_WaterskipBricksActive(void)
{
if (waterskipbricks)

View file

@ -163,6 +163,18 @@ extern vector3_t clusterpoint, clusterdtf;
#define RINGHANDLEBOOST CV_Get(&cv_kartstacking_ring_handleboost)
#define RINGSTACKABLE CV_Get(&cv_kartstacking_ring_stackable)
#define SSMTSPEEDBOOST CV_Get(&cv_kartstacking_ssmt_speedboost)
#define SSMTACCELBOOST CV_Get(&cv_kartstacking_ssmt_accelboost)
#define SSMTHANDLEBOOST CV_Get(&cv_kartstacking_ssmt_handleboost)
#define RECSPINSPEEDBOOSTLO CV_Get(&cv_kartstacking_recspin_speedboost_lo)
#define RECSPINACCELBOOSTLO CV_Get(&cv_kartstacking_recspin_accelboost_lo)
#define RECSPINHANDLEBOOSTLO CV_Get(&cv_kartstacking_recspin_handleboost_lo)
#define RECSPINSPEEDBOOSTHI CV_Get(&cv_kartstacking_recspin_speedboost_hi)
#define RECSPINACCELBOOSTHI CV_Get(&cv_kartstacking_recspin_accelboost_hi)
#define RECSPINHANDLEBOOSTHI CV_Get(&cv_kartstacking_recspin_handleboost_hi)
#define SLOPEDECAY CV_Get(&cv_kartstacking_slope_decay)
#define SLOPEBRAKEMOD CV_Get(&cv_kartstacking_slope_brakemod)
#define SLOPESPEEDBOOSTMAX CV_Get(&cv_kartstacking_slope_speedboost_max)
@ -371,6 +383,7 @@ boolean K_SlopeBoostActive(void);
boolean K_DraftingActive(void);
boolean K_AirDropActive(void);
boolean K_AirThrustActive(void);
boolean K_RecoveryDashActive(void);
boolean K_WaterskipBricksActive(void);
boolean K_ItemLitterActive(void);
boolean K_ItemListActive(void);

View file

@ -455,7 +455,9 @@ static int lib_lenLocalplayers(lua_State *L)
X(loop) \
X(prevonground) \
X(walltransfered) \
X(walltransferboost)
X(walltransferboost) \
X(recoverydashcharge) \
X(recoverydash)
enum player_e
{
@ -1185,6 +1187,12 @@ static int player_get(lua_State *L)
case player_walltransferboost:
lua_pushinteger(L, plr->walltransferboost);
break;
case player_recoverydashcharge:
lua_pushinteger(L, plr->recoverydashcharge);
break;
case player_recoverydash:
lua_pushinteger(L, plr->recoverydash);
break;
#ifdef HWRENDER
case player_fovadd:
lua_pushfixed(L, plr->fovadd);
@ -1936,7 +1944,13 @@ static int player_set(lua_State *L)
plr->walltransfered = lua_toboolean(L, 3);
break;
case player_walltransferboost:
plr->walltransferboost= lua_tointeger(L, 3);
plr->walltransferboost = lua_tointeger(L, 3);
break;
case player_recoverydashcharge:
plr->recoverydashcharge = lua_tointeger(L, 3);
break;
case player_recoverydash:
plr->recoverydash = lua_tointeger(L, 3);
break;
#ifdef HWRENDER
case player_fovadd:

View file

@ -2337,6 +2337,8 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
}
player->driftboost = 0;
player->recoverydash = 0;
player->recoverydashcharge = 0;
player->airdriftspeed = 0;
player->ringboost = 0;
player->glanceDir = 0;

View file

@ -6764,6 +6764,8 @@ void P_RunOverlays(void)
if (!(mo->threshold & OV_DONTROLL))
{
mo->slopepitch = mo->target->slopepitch;
mo->sloperoll = mo->target->sloperoll;
mo->rollangle = mo->target->rollangle;
mo->pitch = mo->target->pitch;
mo->roll = mo->target->roll;
@ -8923,7 +8925,7 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
if (p)
{
if (mobj->extravalue1)
if (mobj->extravalue1 > 0)
{
if (p->driftboost > mobj->movecount)
{

View file

@ -619,6 +619,7 @@ extern boolean slopeboostactive;
extern boolean draftingactive;
extern boolean airdropactive;
extern boolean airthrustactive;
extern boolean recoverydashactive;
extern boolean waterskipbricks;
extern boolean itemlittering;
extern boolean itempushing;

View file

@ -614,6 +614,9 @@ static void P_NetSyncPlayers(savebuffer_t *save)
SYNC(players[i].driftboost);
SYNC(players[i].airdriftspeed);
SYNC(players[i].recoverydashcharge);
SYNC(players[i].recoverydash);
SYNC(players[i].aizdriftstrat);
SYNC(players[i].aizdrifttilt);
SYNC(players[i].aizdriftturn);
@ -633,6 +636,7 @@ static void P_NetSyncPlayers(savebuffer_t *save)
SYNC(players[i].prevspeedboost);
SYNC(players[i].accelboost);
SYNC(players[i].handleboost);
SYNC(players[i].forcedtopspeed);
SYNC(players[i].boostangle);
SYNC(players[i].numsneakers);
SYNC(players[i].numpanels);
@ -4237,6 +4241,7 @@ static boolean P_NetSyncMisc(savebuffer_t *save, boolean resending)
SYNCBOOLEAN(draftingactive);
SYNCBOOLEAN(airdropactive);
SYNCBOOLEAN(airthrustactive);
SYNCBOOLEAN(recoverydashactive);
SYNCBOOLEAN(waterskipbricks);
SYNCBOOLEAN(itemlittering);
SYNCBOOLEAN(itempushing);

View file

@ -162,6 +162,7 @@ boolean slopeboostactive;
boolean draftingactive;
boolean airdropactive;
boolean airthrustactive;
boolean recoverydashactive;
boolean waterskipbricks;
boolean itemlittering;
boolean itempushing;
@ -8184,6 +8185,7 @@ static void P_InitLevelSettings(boolean reloadinggamestate)
draftingactive = false;
airdropactive = false;
airthrustactive = false;
recoverydashactive = false;
waterskipbricks = false;
itemlittering = false;
itempushing = false;
@ -8218,6 +8220,9 @@ static void P_InitLevelSettings(boolean reloadinggamestate)
if (cv_kartairthrust.value)
airthrustactive = true;
if (cv_kartrecoverydash.value)
recoverydashactive = true;
if (cv_kartwaterskiplock.value)
waterskipbricks = true;

View file

@ -2296,13 +2296,13 @@ void P_MovePlayer(player_t *player)
// Drifting sound
// Start looping the sound now.
if (leveltime % 50 == 0 && onground && player->drift != 0)
if (leveltime % 50 == 0 && onground && (player->drift != 0 || (player->pflags & PF_RECOVERYSPIN)))
S_StartSound(player->mo, sfx_drift);
// Leveltime being 50 might take a while at times. We'll start it up once, isntantly.
else if (!S_SoundPlaying(player->mo, sfx_drift) && onground && player->drift != 0)
else if (!S_SoundPlaying(player->mo, sfx_drift) && onground && (player->drift != 0 || (player->pflags & PF_RECOVERYSPIN)))
S_StartSound(player->mo, sfx_drift);
// Ok, we'll stop now.
else if (player->drift == 0 || !onground)
else if ((player->drift == 0 && !(player->pflags & PF_RECOVERYSPIN)) || (!onground))
S_StopSoundByID(player->mo, sfx_drift);
K_MoveKartPlayer(player, onground);