diff --git a/src/d_netcmd.c b/src/d_netcmd.c index d08112fe6..d3fb124e0 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -150,6 +150,7 @@ static void KartEncore_OnChange(void); static void KartComeback_OnChange(void); static void KartEliminateLast_OnChange(void); static void KartRings_OnChange(void); +static void KartStacking_OnChange(void); static void Schedule_OnChange(void); @@ -430,20 +431,21 @@ static CV_PossibleValue_t kartbot_cons_t[] = { }; consvar_t cv_kartbot = CVAR_INIT ("kartbot", "0", CV_NETVAR, kartbot_cons_t, NULL); -consvar_t cv_karteliminatelast = CVAR_INIT ("karteliminatelast", "Yes", CV_NETVAR|CV_CHEAT|CV_CALL, CV_YesNo, KartEliminateLast_OnChange); +consvar_t cv_karteliminatelast = CVAR_INIT ("karteliminatelast", "Yes", CV_NETVAR|CV_CALL, CV_YesNo, KartEliminateLast_OnChange); // Toggles for new features -consvar_t cv_kartrings = CVAR_INIT ("kartrings", "No", CV_NETVAR|CV_CHEAT|CV_CALL|CV_NOINIT, CV_YesNo, KartRings_OnChange); +consvar_t cv_kartrings = CVAR_INIT ("kartrings", "No", CV_NETVAR|CV_CALL|CV_NOINIT, CV_YesNo, KartRings_OnChange); +consvar_t cv_kartstacking = CVAR_INIT ("kartstacking", "No", CV_NETVAR|CV_CALL|CV_NOINIT, CV_YesNo, KartStacking_OnChange); consvar_t cv_kartwalltransfer = CVAR_INIT ("BG_forcewalltransfer", "Off", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL); -consvar_t cv_kartusepwrlv = CVAR_INIT ("kartusepwrlv", "Yes", CV_NETVAR|CV_CHEAT, CV_YesNo, NULL); +consvar_t cv_kartusepwrlv = CVAR_INIT ("kartusepwrlv", "Yes", CV_NETVAR, CV_YesNo, NULL); -consvar_t cv_kartpurpledrift = CVAR_INIT ("kartpurpledrift", "No", CV_NETVAR|CV_CHEAT, CV_YesNo, NULL); +consvar_t cv_kartpurpledrift = CVAR_INIT ("kartpurpledrift", "No", CV_NETVAR, CV_YesNo, NULL); -consvar_t cv_kartbumpspark = CVAR_INIT ("kartbumpspark", "No", CV_NETVAR|CV_CHEAT, CV_YesNo, NULL); +consvar_t cv_kartbumpspark = CVAR_INIT ("kartbumpspark", "No", CV_NETVAR, CV_YesNo, NULL); -consvar_t cv_kartbumpspring = CVAR_INIT ("kartbumpspring", "No", CV_NETVAR|CV_CHEAT, CV_YesNo, NULL); +consvar_t cv_kartbumpspring = CVAR_INIT ("kartbumpspring", "No", CV_NETVAR, CV_YesNo, NULL); static CV_PossibleValue_t kartdebugitem_cons_t[] = { @@ -6903,6 +6905,23 @@ static void KartRings_OnChange(void) } } +static void KartStacking_OnChange(void) +{ + if (K_CanChangeRules() == false) + { + return; + } + + if (cv_kartstacking.value) + { + CONS_Printf(M_GetText("Boost Stacking will be turned \"On\" Next Round.\n")); + } + else + { + CONS_Printf(M_GetText("Boost Stacking will be turned \"Off\" Next Round.\n")); + } +} + static void Schedule_OnChange(void) { size_t i; diff --git a/src/d_netcmd.h b/src/d_netcmd.h index 285d4b19c..7f1b80249 100644 --- a/src/d_netcmd.h +++ b/src/d_netcmd.h @@ -96,6 +96,7 @@ extern consvar_t cv_kartbot; extern consvar_t cv_karteliminatelast; extern consvar_t cv_kartusepwrlv; extern consvar_t cv_kartrings; +extern consvar_t cv_kartstacking; extern consvar_t cv_kartwalltransfer; extern consvar_t cv_kartpurpledrift; extern consvar_t cv_kartbumpspark; diff --git a/src/d_player.h b/src/d_player.h index d57f9e1f2..d5d4292ed 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -581,6 +581,8 @@ struct player_t fixed_t boostpower; // Base boost value, for offroad fixed_t speedboost; // Boost value smoothing for max speed + INT32 numsneakers; // Number of stacked sneakers + INT32 numboosts; // Number of Boosts stacking this frame fixed_t accelboost; // Boost value smoothing for acceleration 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. diff --git a/src/k_kart.c b/src/k_kart.c index 6cc84af15..9842cd613 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -251,6 +251,7 @@ void K_RegisterKartStuff(void) CV_RegisterVar(&cv_lessflicker); CV_RegisterVar(&cv_kartrings); + CV_RegisterVar(&cv_kartstacking); CV_RegisterVar(&cv_newspeedometer); CV_RegisterVar(&cv_showinput); @@ -3297,11 +3298,26 @@ static inline fixed_t K_GetSneakerBoostSpeed(void) } } +// Precalculated constants for stacked boost diminishing +// *Somewhat* matches old calc but doesn't use arrays, which makes it faster and more memory efficent +#define CALC_ARG_OFFSET 32*FRACUNIT/100 +#define CALC_RET_OFFSET FixedSqrt(CALC_ARG_OFFSET) +#define MAXVANILLABOOST 3*FRACUNIT/8 +#define SPEEDBOOSTDROPOFF FloatToFixed(0.01) +#define SPEEDBOOSTDROPOFF_BRAKE FloatToFixed(0.05) + +static fixed_t diminish(fixed_t speedboost) +{ + return FixedSqrt(speedboost + CALC_ARG_OFFSET) - CALC_RET_OFFSET; +} + // sets boostpower, speedboost and accelboost to whatever we need it to be static void K_GetKartBoostPower(player_t *player) { fixed_t boostpower = FRACUNIT; - fixed_t speedboost = 0, accelboost = 0; + fixed_t nonstack_speedboost = 0, speedboost = 0, accelboost = 0; + INT32 numboosts = 0; + fixed_t prevspeedboost = player->speedboost ? player->speedboost : 0; if (player->spinouttimer && player->wipeoutslow == 1) // Slow down after you've been bumped { @@ -3327,26 +3343,40 @@ static void K_GetKartBoostPower(player_t *player) S_StartSound(player->mo, sfx_cdfm70); } -#define ADDBOOST(s,a) { \ - speedboost = max(speedboost,s); \ - accelboost = max(accelboost,a); \ +#define ADDBOOST(s,a,st) { \ + if (stackingactive) \ + { \ + if (st) \ + { \ + numboosts++; \ + speedboost += s; \ + } \ + else \ + nonstack_speedboost = max(speedboost,s); \ + accelboost = max(accelboost,a); \ + } \ + else \ + { \ + speedboost = max(speedboost,s); \ + accelboost = max(accelboost,a); \ + } \ } if (player->sneakertimer) // Sneaker { fixed_t sneakerspeedboost = K_GetSneakerBoostSpeed(); - ADDBOOST(sneakerspeedboost, 8*FRACUNIT); // + ???% top speed, + 800% acceleration + ADDBOOST(sneakerspeedboost, 8*FRACUNIT, true); // + ???% top speed, + 800% acceleration } if (player->invincibilitytimer) // Invincibility { - ADDBOOST(3*FRACUNIT/8, 3*FRACUNIT); // + 37.5% top speed, + 300% acceleration + ADDBOOST(3*FRACUNIT/8, 3*FRACUNIT, false); // + 37.5% top speed, + 300% acceleration } if (player->growshrinktimer > 0) // Grow { - ADDBOOST(FRACUNIT/5, 0); // + 20% top speed, + 0% acceleration + ADDBOOST(FRACUNIT/5, 0, false); // + 20% top speed, + 0% acceleration } if (player->flamestore) // Flame Shield dash @@ -3360,43 +3390,77 @@ static void K_GetKartBoostPower(player_t *player) intermediate = FixedDiv(FixedMul(val, FRACUNIT*-1/2) - FRACUNIT/4,-val+FRACUNIT/2); boost = FixedMul(val,(FRACUNIT-FixedDiv(FRACUNIT,(dash+intermediate)))); - ADDBOOST(boost, accel); + ADDBOOST(boost, accel, false); } if (player->startboost) // Startup Boost { - ADDBOOST(FRACUNIT/4, 6*FRACUNIT); // + 25% top speed, + 300% acceleration + ADDBOOST(FRACUNIT/4, 6*FRACUNIT, true); // + 25% top speed, + 300% acceleration } if (player->driftboost) // Drift Boost { - ADDBOOST(FRACUNIT/4, 4*FRACUNIT); // + 25% top speed, + 400% acceleration + ADDBOOST(FRACUNIT/4, 4*FRACUNIT, true); // + 25% top speed, + 400% acceleration } if (player->ringboost) // Ring Boost { - ADDBOOST(FRACUNIT/5, 4*FRACUNIT); // + 20% top speed, + 400% acceleration + ADDBOOST(FRACUNIT/5, 4*FRACUNIT, true); // + 20% top speed, + 400% acceleration } - // This should always remain the last boost stack before tethering + // This should always remain the last boost if (player->botvars.rubberband > FRACUNIT && K_PlayerUsesBotMovement(player) == true) { - ADDBOOST(player->botvars.rubberband - FRACUNIT, 0); + ADDBOOST(player->botvars.rubberband - FRACUNIT, 0, false); } player->boostpower = boostpower; - // value smoothing - if (speedboost > player->speedboost) + if (stackingactive) { - player->speedboost = speedboost; + // Combine nonstack and stacking boosts here. + speedboost = max(nonstack_speedboost ? nonstack_speedboost : 0, diminish(speedboost)); + } + + // value smoothing + if (stackingactive) + { + // value smoothing + if (player->offroad && K_ApplyOffroad(player)) + { + player->speedboost = max(speedboost, player->speedboost)/2; + player->accelboost = max(accelboost, player->accelboost)/2; + } + else if (speedboost >= prevspeedboost) + { + player->speedboost = max(player->speedboost, speedboost); + player->accelboost = max(accelboost, player->accelboost); + } + else if ((player->aizdriftstrat && abs((player->drift) < 5)) || (K_GetKartButtons(player) & BT_BRAKE)) + { + player->speedboost = max(prevspeedboost - SPEEDBOOSTDROPOFF_BRAKE, min(player->speedboost, MAXVANILLABOOST)); + player->accelboost = max(accelboost, player->accelboost); + } + else + { + player->speedboost = max(prevspeedboost - SPEEDBOOSTDROPOFF, player->speedboost); + player->accelboost = max(accelboost, player->accelboost); + } } else { - player->speedboost += (speedboost - player->speedboost) / (TICRATE/2); + if (speedboost > player->speedboost) + { + player->speedboost = speedboost; + } + else + { + player->speedboost += (speedboost - player->speedboost) / (TICRATE/2); + } } player->accelboost = accelboost; + player->numboosts = numboosts; } // Returns value based on being Grown or Shrunk otherwise returns FRACUNIT @@ -5177,6 +5241,7 @@ void K_DoSneaker(player_t *player, INT32 type) } player->sneakertimer = sneakertime; + player->numsneakers++; // set angle for spun out players: player->boostangle = player->mo->angle; @@ -5207,6 +5272,7 @@ void K_DoWaterRunPanel(player_t *player) } player->sneakertimer = TICRATE*2; + player->numsneakers++; player->mo->flags2 |= MF2_WATERRUN; // set angle for spun out players: diff --git a/src/p_mobj.h b/src/p_mobj.h index 7244ce061..587308d39 100644 --- a/src/p_mobj.h +++ b/src/p_mobj.h @@ -578,6 +578,7 @@ extern UINT16 emeraldspawndelay; extern INT32 numstarposts; extern INT32 numbosswaypoints; extern boolean ringsactive; +extern boolean stackingactive; extern UINT16 bossdisabled; extern boolean stoppedclock; diff --git a/src/p_saveg.c b/src/p_saveg.c index 86f2b8125..af8bd7fae 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -5022,6 +5022,7 @@ static void P_NetArchiveMisc(savebuffer_t *save, boolean resending) WRITEINT16(save->p, lastmap); WRITEUINT16(save->p, bossdisabled); WRITEUINT8(save->p, ringsactive); + WRITEUINT8(save->p, stackingactive); for (i = 0; i < 4; i++) { @@ -5191,6 +5192,7 @@ FUNCINLINE static ATTRINLINE boolean P_NetUnArchiveMisc(savebuffer_t *save, bool lastmap = READINT16(save->p); bossdisabled = READUINT16(save->p); ringsactive = READUINT8(save->p); + stackingactive = READUINT8(save->p); for (i = 0; i < 4; i++) { diff --git a/src/p_setup.c b/src/p_setup.c index 8aeb9fd97..2d80ad9ad 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -143,6 +143,7 @@ side_t *spawnsides; INT32 numstarposts; INT32 numbosswaypoints; boolean ringsactive; +boolean stackingactive; UINT16 bossdisabled; boolean stoppedclock; boolean levelloading; @@ -7883,6 +7884,11 @@ static void P_InitLevelSettings(boolean reloadinggamestate) else ringsactive = false; + if (cv_kartstacking.value) + stackingactive = true; + else + stackingactive = false; + // emerald hunt hunt1 = hunt2 = hunt3 = NULL;