diff --git a/src/d_main.cpp b/src/d_main.cpp index c98a9b2cd..d00bdf210 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -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 diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 1c00dac5e..f13b53579 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -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) diff --git a/src/d_netcmd.h b/src/d_netcmd.h index 92aa7df48..8b5b1cc66 100644 --- a/src/d_netcmd.h +++ b/src/d_netcmd.h @@ -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; diff --git a/src/d_player.h b/src/d_player.h index b6b7bb4e6..bd615c632 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -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 diff --git a/src/g_game.c b/src/g_game.c index 4e5bc2cc1..71adedadb 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -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. diff --git a/src/info/sprites.h b/src/info/sprites.h index 0f8c11cbb..74b3bfa27 100644 --- a/src/info/sprites.h +++ b/src/info/sprites.h @@ -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) diff --git a/src/info/states.h b/src/info/states.h index c58c239e9..7440fdeff 100644 --- a/src/info/states.h +++ b/src/info/states.h @@ -3621,3 +3621,6 @@ _(GHORIZ4) // Arrow Bullet _(ALTSHRINK_ARROWBULLET) +// Recovery Spin Skid +_(RECSPIN_SKID) + diff --git a/src/k_kart.c b/src/k_kart.c index 22e880273..500e6ee11 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -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<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) diff --git a/src/k_kart.h b/src/k_kart.h index 8eb01ef09..5b4d9830c 100644 --- a/src/k_kart.h +++ b/src/k_kart.h @@ -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); diff --git a/src/lua_playerlib.c b/src/lua_playerlib.c index 7a1622492..8570a8589 100644 --- a/src/lua_playerlib.c +++ b/src/lua_playerlib.c @@ -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: diff --git a/src/p_inter.c b/src/p_inter.c index 7d9613a14..97b0add7a 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -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; diff --git a/src/p_mobj.c b/src/p_mobj.c index 2a35f9c72..2a72acfff 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -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) { diff --git a/src/p_mobj.h b/src/p_mobj.h index 4f828cf25..80f0447ba 100644 --- a/src/p_mobj.h +++ b/src/p_mobj.h @@ -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; diff --git a/src/p_saveg.c b/src/p_saveg.c index b2343b002..0b8fb89dc 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -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); diff --git a/src/p_setup.c b/src/p_setup.c index 112378981..35dc4b2f6 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -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; diff --git a/src/p_user.c b/src/p_user.c index fa1006847..a58cb63be 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -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);