diff --git a/src/command.c b/src/command.c index a6f14c9a8..d70fbc198 100644 --- a/src/command.c +++ b/src/command.c @@ -74,6 +74,7 @@ static char * COM_Purge (char *text, int *lenp); CV_PossibleValue_t CV_OnOff[] = {{0, "Off"}, {1, "On"}, {0, NULL}}; CV_PossibleValue_t CV_YesNo[] = {{0, "No"}, {1, "Yes"}, {0, NULL}}; +CV_PossibleValue_t CV_Signed[] = {{-999999999, "MIN"}, {999999999, "MAX"}, {0, NULL}}; CV_PossibleValue_t CV_Unsigned[] = {{0, "MIN"}, {999999999, "MAX"}, {0, NULL}}; CV_PossibleValue_t CV_Natural[] = {{1, "MIN"}, {999999999, "MAX"}, {0, NULL}}; diff --git a/src/command.h b/src/command.h index 9aba7d707..1e5a1a19c 100644 --- a/src/command.h +++ b/src/command.h @@ -170,6 +170,7 @@ struct consvar_t //NULL, NULL, 0, NULL, NULL |, 0, NULL, NULL, 0, 0, NULL extern CV_PossibleValue_t CV_OnOff[]; extern CV_PossibleValue_t CV_YesNo[]; +extern CV_PossibleValue_t CV_Signed[]; extern CV_PossibleValue_t CV_Unsigned[]; extern CV_PossibleValue_t CV_Natural[]; diff --git a/src/d_netcmd.c b/src/d_netcmd.c index c01df78d7..0107e256f 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -151,6 +151,8 @@ 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 KartChaining_OnChange(void); static void KartItemBreaker_OnChange(void); static void Schedule_OnChange(void); @@ -436,22 +438,57 @@ 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); + +// Stacking related +consvar_t cv_kartstacking = CVAR_INIT ("kartstacking", "No", CV_NETVAR|CV_CALL|CV_NOINIT, CV_YesNo, KartStacking_OnChange); +consvar_t cv_kartstacking_calc_arg_offset = CVAR_INIT ("kartstacking_calcargoffset", "0.32", CV_NETVAR|CV_CHEAT|CV_FLOAT, CV_Unsigned, NULL); +consvar_t cv_kartstacking_maxvanillaboost = CVAR_INIT ("kartstacking_maxvanillaboost", "0.375", CV_NETVAR|CV_CHEAT|CV_FLOAT, CV_Unsigned, NULL); +consvar_t cv_kartstacking_speedboostdropoff = CVAR_INIT ("kartstacking_speedboostdropoff", "0.01", CV_NETVAR|CV_CHEAT|CV_FLOAT, CV_Unsigned, NULL); +consvar_t cv_kartstacking_speedboostdropoff_brake = CVAR_INIT ("kartstacking_speedboostdropoff_brake", "0.05", CV_NETVAR|CV_CHEAT|CV_FLOAT, CV_Unsigned, NULL); + +// Vanilla Stacking boosts. +consvar_t cv_kartstacking_sneaker_easyspeedboost = CVAR_INIT ("vanillaboost_sneaker_easyspeedboost", "0.8317", CV_NETVAR|CV_CHEAT|CV_FLOAT, CV_Unsigned, NULL); +consvar_t cv_kartstacking_sneaker_normalspeedboost = CVAR_INIT ("vanillaboost_sneaker_normalspeedboost", "0.5", CV_NETVAR|CV_CHEAT|CV_FLOAT, CV_Unsigned, NULL); +consvar_t cv_kartstacking_sneaker_hardspeedboost = CVAR_INIT ("vanillaboost_sneaker_hardspeedboost", "0.2756", CV_NETVAR|CV_CHEAT|CV_FLOAT, CV_Unsigned, NULL); +consvar_t cv_kartstacking_sneaker_accelboost = CVAR_INIT ("vanillaboost_sneaker_accelboost", "8.0", CV_NETVAR|CV_CHEAT|CV_FLOAT, CV_Unsigned, NULL); +consvar_t cv_kartstacking_sneaker_maxgrade = CVAR_INIT ("vanillaboost_sneaker_maxgrade", "3", CV_NETVAR|CV_CHEAT, CV_Natural, NULL); + +consvar_t cv_kartstacking_invincibility_speedboost = CVAR_INIT ("vanillaboost_invincibility_speedboost", "0.375", CV_NETVAR|CV_CHEAT|CV_FLOAT, CV_Unsigned, NULL); +consvar_t cv_kartstacking_invincibility_accelboost = CVAR_INIT ("vanillaboost_invincibility_accelboost", "3.0", CV_NETVAR|CV_CHEAT|CV_FLOAT, CV_Unsigned, NULL); + +consvar_t cv_kartstacking_grow_speedboost = CVAR_INIT ("vanillaboost_grow_speedboost", "0.2", CV_NETVAR|CV_CHEAT|CV_FLOAT, CV_Unsigned, NULL); +consvar_t cv_kartstacking_grow_accelboost = CVAR_INIT ("vanillaboost_grow_accelboost", "0", CV_NETVAR|CV_CHEAT|CV_FLOAT, CV_Unsigned, NULL); + +consvar_t cv_kartstacking_flame_speedval = CVAR_INIT ("vanillaboost_flame_speedval", "0.80", CV_NETVAR|CV_CHEAT|CV_FLOAT, CV_Unsigned, NULL); +consvar_t cv_kartstacking_flame_accelboost = CVAR_INIT ("vanillaboost_flame_accelboost", "3.0", CV_NETVAR|CV_CHEAT|CV_FLOAT, CV_Unsigned, NULL); + +consvar_t cv_kartstacking_start_speedboost = CVAR_INIT ("vanillaboost_start_speedboost", "0.25", CV_NETVAR|CV_CHEAT|CV_FLOAT, CV_Unsigned, NULL); +consvar_t cv_kartstacking_start_accelboost = CVAR_INIT ("vanillaboost_start_accelboost", "6.0", CV_NETVAR|CV_CHEAT|CV_FLOAT, CV_Unsigned, NULL); + +consvar_t cv_kartstacking_drift_speedboost = CVAR_INIT ("vanillaboost_drift_speedboost", "0.25", CV_NETVAR|CV_CHEAT|CV_FLOAT, CV_Unsigned, NULL); +consvar_t cv_kartstacking_drift_accelboost = CVAR_INIT ("vanillaboost_drift_accelboost", "4.0", CV_NETVAR|CV_CHEAT|CV_FLOAT, CV_Unsigned, NULL); + +consvar_t cv_kartstacking_ring_speedboost = CVAR_INIT ("vanillaboost_ring_speedboost", "0.2", CV_NETVAR|CV_CHEAT|CV_FLOAT, CV_Unsigned, NULL); +consvar_t cv_kartstacking_ring_accelboost = CVAR_INIT ("vanillaboost_ring_accelboost", "4.0", CV_NETVAR|CV_CHEAT|CV_FLOAT, CV_Unsigned, NULL); + +consvar_t cv_kartchaining = CVAR_INIT ("kartchaining", "No", CV_NETVAR|CV_CALL|CV_NOINIT, CV_YesNo, KartChaining_OnChange); +consvar_t cv_kartchainingoffroad = CVAR_INIT ("kartchaining_chainoffroad", "No", CV_NETVAR, CV_YesNo, NULL); consvar_t cv_kartitembreaker = CVAR_INIT ("kartitembreaker", "No", CV_NETVAR|CV_CHEAT|CV_CALL|CV_NOINIT, CV_YesNo, KartItemBreaker_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[] = { @@ -6941,16 +6978,82 @@ static void KartRings_OnChange(void) return; } - if (cv_kartrings.value) + if (!K_RingsActive() && cv_kartrings.value) { CONS_Printf(M_GetText("Rings will be turned \"On\" Next Round.\n")); } - else + else if (K_RingsActive() && !cv_kartrings.value) { CONS_Printf(M_GetText("Rings will be turned \"Off\" Next Round.\n")); } } +static void KartStacking_OnChange(void) +{ + if (K_CanChangeRules() == false) + { + return; + } + + if (!stackingactive && cv_kartstacking.value) + { + if (leveltime < starttime) + { + stackingactive = true; + CONS_Printf(M_GetText("Boost Stacking has been turned \"On\".\n")); + } + else + { + CONS_Printf(M_GetText("Boost Stacking will be turned \"On\" next round.\n")); + } + } + else if (stackingactive && !cv_kartstacking.value) + { + if (leveltime < starttime) + { + stackingactive = false; + CONS_Printf(M_GetText("Boost Stacking has been turned \"Off\".\n")); + } + else + { + CONS_Printf(M_GetText("Boost Stacking will be turned \"Off\" next round.\n")); + } + } +} + +static void KartChaining_OnChange(void) +{ + if (K_CanChangeRules() == false) + { + return; + } + + if (!chainingactive && cv_kartchaining.value) + { + if (leveltime < starttime) + { + chainingactive = true; + CONS_Printf(M_GetText("Boost Chaining has been turned \"On\".\n")); + } + else + { + CONS_Printf(M_GetText("Boost Chaining will be turned \"On\" Next Round.\n")); + } + } + else if (chainingactive && !cv_kartstacking.value) + { + if (leveltime < starttime) + { + chainingactive = false; + CONS_Printf(M_GetText("Boost Chaining has been turned \"Off\".\n")); + } + else + { + CONS_Printf(M_GetText("Boost Chaining will be turned \"Off\" next round.\n")); + } + } +} + static void KartItemBreaker_OnChange(void) { if (K_CanChangeRules() == false) @@ -6958,11 +7061,16 @@ static void KartItemBreaker_OnChange(void) return; } - if (cv_kartitembreaker.value) + if (!multiplayer) + { + return; + } + + if (!itembreaker && cv_kartitembreaker.value) { CONS_Printf(M_GetText("Singleplayer Item Breaker will be turned \"On\" Next Round.\n")); } - else + else if (itembreaker && !cv_kartitembreaker.value) { CONS_Printf(M_GetText("Singleplayer Item Breaker will be turned \"Off\" Next Round.\n")); } diff --git a/src/d_netcmd.h b/src/d_netcmd.h index b9ca59fd7..0fc16f637 100644 --- a/src/d_netcmd.h +++ b/src/d_netcmd.h @@ -96,6 +96,40 @@ 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_kartstacking_calc_arg_offset; +extern consvar_t cv_kartstacking_maxvanillaboost; +extern consvar_t cv_kartstacking_speedboostdropoff; +extern consvar_t cv_kartstacking_speedboostdropoff_brake; + +extern consvar_t cv_kartstacking_sneaker_easyspeedboost; +extern consvar_t cv_kartstacking_sneaker_normalspeedboost; +extern consvar_t cv_kartstacking_sneaker_hardspeedboost; +extern consvar_t cv_kartstacking_sneaker_accelboost; +extern consvar_t cv_kartstacking_sneaker_maxgrade; + +extern consvar_t cv_kartstacking_invincibility_speedboost; +extern consvar_t cv_kartstacking_invincibility_accelboost; + +extern consvar_t cv_kartstacking_flame_speedval; +extern consvar_t cv_kartstacking_flame_accelboost; + +extern consvar_t cv_kartstacking_grow_speedboost; +extern consvar_t cv_kartstacking_grow_accelboost; + +extern consvar_t cv_kartstacking_start_speedboost; +extern consvar_t cv_kartstacking_start_accelboost; + +extern consvar_t cv_kartstacking_drift_speedboost; +extern consvar_t cv_kartstacking_drift_accelboost; + +extern consvar_t cv_kartstacking_ring_speedboost; +extern consvar_t cv_kartstacking_ring_accelboost; + +extern consvar_t cv_kartchaining; +extern consvar_t cv_kartchainingoffroad; + extern consvar_t cv_kartitembreaker; extern consvar_t cv_kartwalltransfer; extern consvar_t cv_kartpurpledrift; diff --git a/src/d_player.h b/src/d_player.h index 9b7f6b4d1..9c337042b 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -452,6 +452,13 @@ struct sonicloopvars_t sonicloopcamvars_t camera; }; +struct boostinfo_t { + fixed_t stackspeedboost; + fixed_t nonstackspeedboost; + fixed_t accelboost; + UINT8 grade; +}; + // ======================================================================== // PLAYER STRUCTURE // ======================================================================== @@ -581,6 +588,9 @@ struct player_t fixed_t speedboost; // Boost value smoothing for max speed 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. + boostinfo_t boostinfo; // Stores values used for setting speed and accel boosts. + UINT8 numsneakers; // Number of stacked sneakers + UINT8 numboosts; // Number of Boosts stacking this frame UINT8 tripwireState; // see tripwirestate_t UINT8 tripwirePass; // see tripwirepass_t @@ -622,7 +632,9 @@ struct player_t SINT8 stolentimer; // you are being stolen from UINT16 sneakertimer; // Duration of a Sneaker Boost (from Sneakers or level boosters) + UINT16 realsneakertimer;// Duration of a Sneaker Boosts acutal time that doesn't get chained.(used for chainoffroad and tripwires) UINT8 floorboost; // (0 to 3) - Prevents Sneaker sounds for a brief duration when triggered by a floor panel + UINT16 chaintimer; // Stores current chain timer length. UINT8 boostcharge; // Charge during race start diff --git a/src/info/mobjs.h b/src/info/mobjs.h index 420089a39..5a4646cfa 100644 --- a/src/info/mobjs.h +++ b/src/info/mobjs.h @@ -1058,6 +1058,8 @@ _(TUMBLECOIN) _(KARMAFIREWORK) _(GAINAX) +_(BOOSTSTACK) + _(FOLLOWER) _(FOLLOWERBUBBLE_FRONT) _(FOLLOWERBUBBLE_BACK) diff --git a/src/info/sounds.h b/src/info/sounds.h index f349a98e4..a1a04fa5e 100644 --- a/src/info/sounds.h +++ b/src/info/sounds.h @@ -1054,6 +1054,9 @@ _(kdtrg1) _(kdtrg2) _(kdtrg3) +// Chaining Sound +_(bstchn) + // Shout message sound effect _(sysmsg) diff --git a/src/info/sprites.h b/src/info/sprites.h index 55922f37c..718540c9c 100644 --- a/src/info/sprites.h +++ b/src/info/sprites.h @@ -715,6 +715,8 @@ _(WTRU) // Water Trail Underlay _(GCHA) // follower: generic chao _(CHEZ) // follower: cheese +_(BSSS) // Stacking effect + _(TRCK) // First person view sprites; this is a sprite so that it can be replaced by a specialized MD2 draw later diff --git a/src/info/states.h b/src/info/states.h index 4cfb6fb4e..ef8581667 100644 --- a/src/info/states.h +++ b/src/info/states.h @@ -4200,6 +4200,8 @@ _(GAINAX_HUGE) _(GAINAX_MID1) _(GAINAX_MID2) +_(BOOSTSTACK) + _(WAYPOINTORB) _(WAYPOINTSPLAT) _(EGOORB) diff --git a/src/k_kart.c b/src/k_kart.c index ff8fbaece..9aa561d04 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -49,6 +49,12 @@ #include "k_follower.h" #include "k_grandprix.h" +consvar_t cv_kartstacking_colorflame = CVAR_INIT ("kartstacking_colorflame", "On", 0, CV_OnOff, NULL); +consvar_t cv_kartstacking_sneakerstacksound = CVAR_INIT ("kartstacking_sneakerstacksound", "On", 0, CV_OnOff, NULL); +consvar_t cv_kartchainingsound = CVAR_INIT ("kartchaining_chainsound", "On", 0, CV_OnOff, NULL); +consvar_t cv_kartdriftsounds = CVAR_INIT ("kartdriftsounds", "On", 0, CV_OnOff, NULL); +consvar_t cv_kartdriftefx = CVAR_INIT ("kartdriftefx", "On", 0, CV_OnOff, NULL); + // SOME IMPORTANT VARIABLES DEFINED IN DOOMDEF.H: // gamespeed is cc (0 for easy, 1 for normal, 2 for hard) // franticitems is Frantic Mode items, bool @@ -253,6 +259,44 @@ void K_RegisterKartStuff(void) CV_RegisterVar(&cv_lessflicker); CV_RegisterVar(&cv_kartrings); + + // Stacking + CV_RegisterVar(&cv_kartstacking); + CV_RegisterVar(&cv_kartstacking_calc_arg_offset); + CV_RegisterVar(&cv_kartstacking_speedboostdropoff); + CV_RegisterVar(&cv_kartstacking_speedboostdropoff_brake); + CV_RegisterVar(&cv_kartstacking_colorflame); + CV_RegisterVar(&cv_kartstacking_sneakerstacksound); + + // Vanilla Boosts + CV_RegisterVar(&cv_kartstacking_sneaker_easyspeedboost); + CV_RegisterVar(&cv_kartstacking_sneaker_normalspeedboost); + CV_RegisterVar(&cv_kartstacking_sneaker_hardspeedboost); + CV_RegisterVar(&cv_kartstacking_sneaker_accelboost); + CV_RegisterVar(&cv_kartstacking_sneaker_maxgrade); + + CV_RegisterVar(&cv_kartstacking_invincibility_speedboost); + CV_RegisterVar(&cv_kartstacking_invincibility_accelboost); + + CV_RegisterVar(&cv_kartstacking_grow_speedboost); + CV_RegisterVar(&cv_kartstacking_grow_accelboost); + + CV_RegisterVar(&cv_kartstacking_flame_speedval); + CV_RegisterVar(&cv_kartstacking_flame_accelboost); + + CV_RegisterVar(&cv_kartstacking_start_speedboost); + CV_RegisterVar(&cv_kartstacking_start_accelboost); + + CV_RegisterVar(&cv_kartstacking_drift_speedboost); + CV_RegisterVar(&cv_kartstacking_drift_accelboost); + + CV_RegisterVar(&cv_kartstacking_ring_speedboost); + CV_RegisterVar(&cv_kartstacking_ring_accelboost); + + CV_RegisterVar(&cv_kartchaining); + CV_RegisterVar(&cv_kartchainingoffroad); + CV_RegisterVar(&cv_kartchainingsound); + CV_RegisterVar(&cv_kartitembreaker); CV_RegisterVar(&cv_newspeedometer); @@ -265,6 +309,10 @@ void K_RegisterKartStuff(void) CV_RegisterVar(&cv_kartbumpspark); CV_RegisterVar(&cv_kartbumpspring); + + CV_RegisterVar(&cv_kartdriftsounds); + + CV_RegisterVar(&cv_kartdriftefx); } //} @@ -2299,6 +2347,17 @@ void K_SpawnInvincibilitySpeedLines(mobj_t *mo) fast->destscale = 6*((mo->player->invincibilitytimer/TICRATE)*FRACUNIT)/8; } +static void K_SpawnStackingEffect(player_t *player) +{ + // Thanks to 1ndev for code used for booststack->scale and boosttack->frame! (taken and modified from BoostStack) + mobj_t *booststack = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_BOOSTSTACK); + P_SetTarget(&booststack->target, player->mo); + P_SetScale(booststack, FixedMul(FRACUNIT + FixedMul(2*FRACUNIT - FRACUNIT, FixedDiv(min(player->numboosts,4)*FRACUNIT, 4*FRACUNIT)), mapobjectscale)); + + booststack->angle = player->mo->angle + ANGLE_90; + booststack->color = player->mo->color; +} + void K_SpawnBumpEffect(mobj_t *mo) { mobj_t *fx = P_SpawnMobj(mo->x, mo->y, mo->z, MT_BUMP); @@ -3057,7 +3116,9 @@ void K_MomentumToFacing(player_t *player) boolean K_ApplyOffroad(player_t *player) { - if (player->invincibilitytimer || player->hyudorotimer || player->sneakertimer) + boolean sneakertimer = CANTCHAINOFFROAD ? (player->sneakertimer && player->realsneakertimer) : player->sneakertimer; + + if (player->invincibilitytimer || player->hyudorotimer || sneakertimer) return false; return true; } @@ -3097,7 +3158,7 @@ tripwirepass_t K_TripwirePassConditions(player_t *player) { if ( player->invincibilitytimer || - player->sneakertimer + (player->sneakertimer && player->realsneakertimer) ) return TRIPWIRE_BLASTER; @@ -3289,22 +3350,54 @@ static inline fixed_t K_GetSneakerBoostSpeed(void) switch (gamespeed) { case 0: - return 53740+768; + return EASYSNEAKERSPEEDBOOST; break; case 2: - return 17294+768; + return HARDSNEAKERSPEEDBOOST; break; default: - return 32768; + return NORMALSNEAKERSPEEDBOOST; break; } } +static fixed_t diminish(fixed_t speedboost) +{ + return FixedSqrt(speedboost + CALC_ARG_OFFSET) - CALC_RET_OFFSET; +} + +void K_DoBoost(player_t *player, fixed_t speedboost, fixed_t accelboost, boolean stack, boolean visible) +{ + if (stack && stackingactive) + { + player->boostinfo.stackspeedboost += speedboost; + } + + player->boostinfo.nonstackspeedboost = max(player->boostinfo.nonstackspeedboost, speedboost); + player->boostinfo.accelboost = max(player->boostinfo.accelboost, accelboost); + + if (visible) + { + player->boostinfo.grade = CLAMP(player->boostinfo.grade+1, 0, stackingactive ? UINT8_MAX : 1); + } +} + +void K_ClearBoost(player_t *player) +{ + player->boostinfo.stackspeedboost = 0; + player->boostinfo.nonstackspeedboost = 0; + player->boostinfo.accelboost = 0; + player->boostinfo.grade = 0; +} + // 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 finalspeedboost = 0; + fixed_t finalaccelboost = 0; + UINT8 finalgrade = 0; + fixed_t prevspeedboost = player->speedboost; if (player->spinouttimer && player->wipeoutslow == 1) // Slow down after you've been bumped { @@ -3330,26 +3423,26 @@ 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); \ -} - if (player->sneakertimer) // Sneaker { + UINT8 i; fixed_t sneakerspeedboost = K_GetSneakerBoostSpeed(); - ADDBOOST(sneakerspeedboost, 8*FRACUNIT); // + ???% top speed, + 800% acceleration + UINT8 numsneakers = player->numsneakers ? player->numsneakers : 1; + for (i = 0; i < numsneakers; i++) + { + K_DoBoost(player, sneakerspeedboost, SNEAKERACCELBOOST, true, true); // + ???% top speed, + 800% acceleration + } } if (player->invincibilitytimer) // Invincibility { - ADDBOOST(3*FRACUNIT/8, 3*FRACUNIT); // + 37.5% top speed, + 300% acceleration + K_DoBoost(player, INVINSPEEDBOOST, INVINACCELBOOST, false, false); // + 37.5% top speed, + 300% acceleration } if (player->growshrinktimer > 0) // Grow { - ADDBOOST(FRACUNIT/5, 0); // + 20% top speed, + 0% acceleration + K_DoBoost(player, GROWSPEEDBOOST, GROWACCELBOOST, false, false); // + 20% top speed, + 0% acceleration } if (player->flamestore) // Flame Shield dash @@ -3357,49 +3450,81 @@ static void K_GetKartBoostPower(player_t *player) fixed_t dash = K_FlameShieldDashVar(player->flamedash); fixed_t intermediate = 0; fixed_t boost = 0; - fixed_t val = 52428; // Rim idea: diminish starts around 1.2x sneaker speed and plateaus around 1.4-1.5x - fixed_t accel = 3*FRACUNIT; + fixed_t val = FLAMESPEEDVAL; // Rim idea: diminish starts around 1.2x sneaker speed and plateaus around 1.4-1.5x intermediate = FixedDiv(FixedMul(val, FRACUNIT*-1/2) - FRACUNIT/4,-val+FRACUNIT/2); boost = FixedMul(val,(FRACUNIT-FixedDiv(FRACUNIT,(dash+intermediate)))); - ADDBOOST(boost, accel); + K_DoBoost(player, boost, FLAMEACCELBOOST, false, false); } if (player->startboost) // Startup Boost { - ADDBOOST(FRACUNIT/4, 6*FRACUNIT); // + 25% top speed, + 300% acceleration + K_DoBoost(player, STARTSPEEDBOOST, STARTACCELBOOST, true, true); // + 25% top speed, + 600% acceleration } if (player->driftboost) // Drift Boost { - ADDBOOST(FRACUNIT/4, 4*FRACUNIT); // + 25% top speed, + 400% acceleration + K_DoBoost(player, DRIFTSPEEDBOOST, DRIFTACCELBOOST, true, true); // + 25% top speed, + 400% acceleration } if (player->ringboost) // Ring Boost { - ADDBOOST(FRACUNIT/5, 4*FRACUNIT); // + 20% top speed, + 400% acceleration + K_DoBoost(player, RINGSPEEDBOOST, RINGACCELBOOST, true, 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); + K_DoBoost(player, player->botvars.rubberband - FRACUNIT, 0, false, false); } player->boostpower = boostpower; + // Combine nonstack and stacking boosts here. + finalspeedboost = max(player->boostinfo.nonstackspeedboost, diminish(player->boostinfo.stackspeedboost)); + finalaccelboost = player->boostinfo.accelboost; + finalgrade = player->boostinfo.grade; + // value smoothing - if (speedboost > player->speedboost) + if (stackingactive) { - player->speedboost = speedboost; + if (player->offroad && K_ApplyOffroad(player)) + { + player->speedboost = max(finalspeedboost, player->speedboost)/2; + player->accelboost = max(finalaccelboost, player->accelboost)/2; + } + else if (finalspeedboost >= prevspeedboost) + { + player->speedboost = max(player->speedboost, finalspeedboost); + player->accelboost = max(finalaccelboost, 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(finalaccelboost, player->accelboost); + } + else + { + player->speedboost = prevspeedboost - SPEEDBOOSTDROPOFF; + player->accelboost = max(finalaccelboost, player->accelboost); + } } else { - player->speedboost += (speedboost - player->speedboost) / (TICRATE/2); + if (finalspeedboost > player->speedboost) + { + player->speedboost = finalspeedboost; + } + else + { + player->speedboost += (finalspeedboost - player->speedboost) / (TICRATE/2); + } } - player->accelboost = accelboost; + player->accelboost = finalaccelboost; + player->numboosts = finalgrade; + K_ClearBoost(player); } // Returns value based on being Grown or Shrunk otherwise returns FRACUNIT @@ -5128,22 +5253,27 @@ static void K_DoHyudoroSteal(player_t *player) } } -void K_DoSneaker(player_t *player, INT32 type) +// Handle these else where to reduce code duplication between panels and sneakers +static void K_SneakerPanelStackSound(player_t *player) { - const fixed_t intendedboost = K_GetSneakerBoostSpeed(); + const sfxenum_t normalsfx = sfx_cdfm01; + const sfxenum_t smallsfx = sfx_cdfm40; + sfxenum_t sfx = normalsfx; - if (player->floorboost == 0 || player->floorboost == 3) + if ((player->numsneakers > 0) && stackingactive) { - S_StopSoundByID(player->mo, sfx_cdfm01); - S_StartSound(player->mo, sfx_cdfm01); - - K_SpawnDashDustRelease(player); - if (intendedboost > player->speedboost) - player->karthud[khud_destboostcam] = FixedMul(FRACUNIT, FixedDiv((intendedboost - player->speedboost), intendedboost)); - + // Use a less annoying sound when stacking sneakers. + sfx = smallsfx; } - if (player->sneakertimer == 0) + S_StopSoundByID(player->mo, normalsfx); + S_StopSoundByID(player->mo, smallsfx); + S_StartSound(player->mo, sfx); +} + +static void K_SneakerPanelEffect(player_t *player, INT32 type) +{ + if (!player->sneakertimer) { if (type == 2) { @@ -5172,6 +5302,22 @@ void K_DoSneaker(player_t *player, INT32 type) K_FlipFromObject(overlay, player->mo); } } +} + +void K_DoSneaker(player_t *player, INT32 type) +{ + const fixed_t intendedboost = K_GetSneakerBoostSpeed(); + + if (player->floorboost == 0 || player->floorboost == 3) + { + K_SneakerPanelStackSound(player); + K_SpawnDashDustRelease(player); + if (intendedboost > player->speedboost) + player->karthud[khud_destboostcam] = FixedMul(FRACUNIT, FixedDiv((intendedboost - player->speedboost), intendedboost)); + + } + + K_SneakerPanelEffect(player, type); if (type != 0) { @@ -5179,6 +5325,12 @@ void K_DoSneaker(player_t *player, INT32 type) } player->sneakertimer = sneakertime; + player->realsneakertimer = sneakertime; + + if (player->sneakertimer && (player->floorboost == 0 || player->floorboost == 3)) + { + player->numsneakers = CLAMP(player->numsneakers+1, 0, stackingactive ? MAXSNEAKERSTACK : 1); + } // set angle for spun out players: player->boostangle = player->mo->angle; @@ -5190,25 +5342,22 @@ void K_DoWaterRunPanel(player_t *player) if (player->floorboost == 0 || player->floorboost == 3) { - S_StopSoundByID(player->mo, sfx_cdfm01); - S_StopSoundByID(player->mo, sfx_kc3c); - S_StartSound(player->mo, sfx_cdfm01); - S_StartSound(player->mo, sfx_kc3c); - + K_SneakerPanelStackSound(player); K_SpawnDashDustRelease(player); if (intendedboost > player->speedboost) player->karthud[khud_destboostcam] = FixedMul(FRACUNIT, FixedDiv((intendedboost - player->speedboost), intendedboost)); } - if (player->sneakertimer == 0) - { - mobj_t *overlay = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_BOOSTFLAME); - P_SetTarget(&overlay->target, player->mo); - P_SetScale(overlay, (overlay->destscale = player->mo->scale)); - K_FlipFromObject(overlay, player->mo); - } + K_SneakerPanelEffect(player, 0); player->sneakertimer = TICRATE*2; + player->realsneakertimer = TICRATE*2; + + if (player->sneakertimer && (player->floorboost == 0 || player->floorboost == 3)) + { + player->numsneakers = CLAMP(player->numsneakers+1, 0, stackingactive ? MAXSNEAKERSTACK : 1); + } + player->mo->flags2 |= MF2_WATERRUN; // set angle for spun out players: @@ -6854,6 +7003,7 @@ static void K_RaceStart(player_t *player) player->startboost = 0; K_DoSneaker(player, 0); player->sneakertimer = 70; // PERFECT BOOST!! + player->realsneakertimer = 70; if (!player->floorboost || player->floorboost == 3) // Let everyone hear this one S_StartSound(player->mo, sfx_s25f); @@ -6922,6 +7072,118 @@ static void K_TireGreaseEffect(player_t *player) S_StartSound(player->mo, sfx_screec); } +boolean K_BoostChain(player_t *player, INT32 timer, boolean chainsound) +{ + if (!chainingactive) + { + // You can't chain why bother? + return false; + } + + if (timer > player->chaintimer) + { + // Just what I needed! - Toad + if (cv_kartchainingsound.value && chainsound && player->chaintimer && player->sneakertimer) + { + if (player->mo) + { + // Chain Sound! + S_StartSound(player->mo, sfx_bstchn); + } + } + + player->chaintimer = timer; + } + + if (player->chaintimer) + { + // You can continue chaining! + return true; + } + + // Aw shucks, time to drop the chain.... + return false; +} + +INT32 K_ChainOrDeincrementTime(player_t *player, INT32 timer, INT32 deincrement, boolean chainsound) +{ + timer -= deincrement; + + if (K_BoostChain(player, timer, chainsound)) + { + // Its time to chain. + return max(1, timer); + } + + // Continue to drain the timer as normal. + return timer; +} + +// Get the tic inverse sum using kartspeed, kartweight and your number of boosts. +static INT32 ticinversesum(UINT8 kartspeed, UINT8 kartweight, UINT8 grade) +{ + return (TICRATE / kartspeed) + (TICRATE / CLAMP(kartweight, 1, 5)) + grade; +} + +// Get the maximum required stacks needed for the ringnerf based on kartspeed and kartweight +static INT32 statrangemap(UINT8 kartspeed, UINT8 kartweight) +{ + INT32 scaledsw = (9 - kartspeed) + (9 - kartweight); + + fixed_t scaled_input = (scaledsw)*FRACUNIT/16; + + // Scale the result to be within range [2, 4] + fixed_t result = 4*FRACUNIT - (FixedMul(scaled_input, 2*FRACUNIT)); + + // Stay within range please! + if (result < 2*FRACUNIT) + result = 2*FRACUNIT; + if (result > 4*FRACUNIT) + result = 4*FRACUNIT; + + result = result >> FRACBITS; + + return result; +} + +static void K_HandleRingDeincrement(player_t *player, boolean chainnerf) +{ + // Aggressively reduce extreme ringboost duration. + // Less aggressive for accel types. + UINT8 roller = TICRATE; + UINT16 finalringtimer; + roller += 4*(8-player->kartspeed); + + finalringtimer = max((player->ringboost / roller), 1); + + if (chainnerf) + { + UINT8 requiredgrade = statrangemap(player->kartspeed, player->kartweight); + + if (player->numboosts >= requiredgrade) + { + INT32 insum = ticinversesum(player->kartspeed, player->kartweight, player->numboosts); + INT32 subring = (player->ringboost*2)/insum; + + if (player->kartspeed == 1) + { + // fuck off chao you aren't chaining an entire race. + subring = (player->ringboost*4)/insum; + } + + finalringtimer += subring; + } + + if (player->ringboost - finalringtimer > player->chaintimer) + { + // Cap this to prevent displacement between chaintimer and ringtimer. + player->chaintimer = min(player->ringboost, (TICRATE - TICRATE/4)); + } + } + + player->ringboost = max(player->chaintimer ? 1: 0, player->ringboost - finalringtimer); +} + /** \brief Decreases various kart timers and powers per frame. Called in P_PlayerThink in p_user.c \param player player object passed from P_PlayerThink @@ -6931,8 +7193,6 @@ static void K_TireGreaseEffect(player_t *player) */ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) { - const boolean onground = P_IsObjectOnGround(player->mo); - /* reset sprite offsets :) */ player->mo->sprxoff = 0; player->mo->spryoff = 0; @@ -6996,25 +7256,11 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) } } - /*if (gametype == GT_RACE && player->rings <= 0 && (K_RingsActive() == true)) // spawn ring debt indicator + // Stacking Effect + if (stackingactive && player->numboosts > 1) { - mobj_t *debtflag = P_SpawnMobj(player->mo->x + player->mo->momx, player->mo->y + player->mo->momy, - player->mo->z + P_GetMobjZMovement(player->mo) + player->mo->height + (24*player->mo->scale), MT_THOK); - - P_SetMobjState(debtflag, S_RINGDEBT); - P_SetScale(debtflag, (debtflag->destscale = player->mo->scale)); - - K_MatchGenericExtraFlags(debtflag, player->mo); - debtflag->frame += (leveltime % 4); - - if ((leveltime/12) & 1) - debtflag->frame += 4; - - debtflag->color = player->skincolor; - debtflag->fuse = 2; - - debtflag->renderflags = K_GetPlayerDontDrawFlag(player); - }*/ + K_SpawnStackingEffect(player); + } } if (player->itemtype == KITEM_NONE) @@ -7111,37 +7357,34 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) player->ringboost = 0; else if (player->ringboost) { - // Aggressively reduce extreme ringboost duration. - // Less aggressive for accel types. - - UINT8 roller = TICRATE; - roller += 4*(8-player->kartspeed); - - player->ringboost -= max((player->ringboost / roller), 1); + K_HandleRingDeincrement(player, chainingactive); } if (player->sneakertimer) { - player->sneakertimer--; + player->sneakertimer = K_ChainOrDeincrementTime(player, player->sneakertimer, 1, false); + + if (player->sneakertimer <= 0) + { + player->mo->flags2 &= ~MF2_WATERRUN; + player->numsneakers = 0; + } } + if (player->realsneakertimer) + player->realsneakertimer--; + if (player->sneakertimer && player->wipeoutslow > 0 && player->wipeoutslow < wipeoutslowtime+1) player->wipeoutslow = wipeoutslowtime+1; if (player->floorboost > 0) player->floorboost--; - if (player->sneakertimer == 0) - { - // No more waterrunning for you pal! - player->mo->flags2 &= ~MF2_WATERRUN; - } - if (player->driftboost) - player->driftboost--; + player->driftboost = K_ChainOrDeincrementTime(player, player->driftboost, 1, true); if (player->startboost > 0) - player->startboost--; + player->startboost = K_ChainOrDeincrementTime(player, player->startboost, 1, false); if (player->invincibilitytimer) player->invincibilitytimer--; @@ -7240,7 +7483,10 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) player->outruntime--; if (player->tiregrease > 0) - player->tiregrease--;; + player->tiregrease--; + + if (player->chaintimer) + player->chaintimer--; if (player->itemblink && player->itemblink-- <= 0) { @@ -8616,7 +8862,14 @@ INT32 K_GetKartDriftSparkValueForStage(player_t *player, UINT8 stage) static void K_SpawnDriftEFX(player_t *player,SINT8 level) { + if (!cv_kartdriftefx.value) + { + // Not wanted sorry! + return; + } + mobj_t *overlay = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_BOOSTFLAME); + P_SetMobjState(overlay, S_DRIFTBOOSTFLAME); P_SetTarget(&overlay->target, player->mo); P_SetScale(overlay, (overlay->destscale = player->mo->scale)); K_FlipFromObject(overlay, player->mo); @@ -8672,8 +8925,11 @@ static void K_KartDrift(player_t *player, boolean onground) { if (player->driftboost < 50) player->driftboost = 50; + + if (cv_kartdriftsounds.value) + S_StartSound(player->mo, sfx_kc5b); S_StartSound(player->mo, sfx_s23c); - S_StartSound(player->mo, sfx_kc5b); + K_SpawnDriftEFX(player, 2); player->driftcharge = 0; } @@ -8683,9 +8939,16 @@ static void K_KartDrift(player_t *player, boolean onground) { if (player->driftboost < 80) player->driftboost = 80; - S_StartSound(player->mo, sfx_kc5b); - S_StartSound(player->mo, sfx_kc3c); - S_StartSound(player->mo, sfx_s3k47); + if (cv_kartdriftsounds.value) + { + S_StartSound(player->mo, sfx_kc5b); + S_StartSound(player->mo, sfx_kc3c); + S_StartSound(player->mo, sfx_s3k47); + } + else + { + S_StartSound(player->mo, sfx_s23c); + } K_SpawnDriftEFX(player, 3); player->driftcharge = 0; } @@ -8695,8 +8958,16 @@ static void K_KartDrift(player_t *player, boolean onground) { if (player->driftboost < 125) player->driftboost = 125; - S_StartSound(player->mo, sfx_kc5b); - S_StartSound(player->mo, sfx_kc4d); + if (cv_kartdriftsounds.value) + { + S_StartSound(player->mo, sfx_kc5b); + S_StartSound(player->mo, sfx_kc4d); + } + else + { + S_StartSound(player->mo, sfx_s23c); + } + K_SpawnDriftEFX(player, 4); player->driftcharge = 0; } @@ -10350,6 +10621,28 @@ boolean K_RingsActive(void) return true; } +boolean K_StackingActive(void) +{ + if (stackingactive) + { + // Booststacking is enabled! + return true; + } + + return false; +} + +boolean K_ChainingActive(void) +{ + if (chainingactive) + { + // Boostchaining is enabled! + return true; + } + + return false; +} + boolean K_UsingLegacyCheckpoints(void) { if (numbosswaypoints > 0) diff --git a/src/k_kart.h b/src/k_kart.h index c4d9bae67..45a1e6d8a 100644 --- a/src/k_kart.h +++ b/src/k_kart.h @@ -14,6 +14,12 @@ extern "C" { #endif +extern consvar_t cv_kartstacking_colorflame; +extern consvar_t cv_kartstacking_sneakerstacksound; +extern consvar_t cv_kartchainingsound; +extern consvar_t cv_kartdriftsounds; +extern consvar_t cv_kartdriftefx; + #define KART_FULLTURN 800 /* @@ -31,6 +37,35 @@ Make sure this matches the actual number of states #define FLAMESTOREMAX TICRATE*2 +// 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 cv_kartstacking_calc_arg_offset.value +#define CALC_RET_OFFSET FixedSqrt(CALC_ARG_OFFSET) +#define MAXVANILLABOOST cv_kartstacking_maxvanillaboost.value +#define SPEEDBOOSTDROPOFF cv_kartstacking_speedboostdropoff.value +#define SPEEDBOOSTDROPOFF_BRAKE cv_kartstacking_speedboostdropoff_brake.value + +// Vanilla Boosts +#define EASYSNEAKERSPEEDBOOST cv_kartstacking_sneaker_easyspeedboost.value +#define NORMALSNEAKERSPEEDBOOST cv_kartstacking_sneaker_normalspeedboost.value +#define HARDSNEAKERSPEEDBOOST cv_kartstacking_sneaker_hardspeedboost.value +#define SNEAKERACCELBOOST cv_kartstacking_sneaker_accelboost.value +#define MAXSNEAKERSTACK cv_kartstacking_sneaker_maxgrade.value +#define INVINSPEEDBOOST cv_kartstacking_invincibility_speedboost.value +#define INVINACCELBOOST cv_kartstacking_invincibility_accelboost.value +#define GROWSPEEDBOOST cv_kartstacking_grow_speedboost.value +#define GROWACCELBOOST cv_kartstacking_grow_accelboost.value +#define FLAMESPEEDVAL cv_kartstacking_flame_speedval.value +#define FLAMEACCELBOOST cv_kartstacking_flame_accelboost.value +#define STARTSPEEDBOOST cv_kartstacking_start_speedboost.value +#define STARTACCELBOOST cv_kartstacking_start_accelboost.value +#define DRIFTSPEEDBOOST cv_kartstacking_drift_speedboost.value +#define DRIFTACCELBOOST cv_kartstacking_drift_accelboost.value +#define RINGSPEEDBOOST cv_kartstacking_ring_speedboost.value +#define RINGACCELBOOST cv_kartstacking_ring_accelboost.value + +#define CANTCHAINOFFROAD (cv_kartchaining.value && !cv_kartchainingoffroad.value) + // Used for respawning checks. typedef struct respawnresult_s @@ -192,10 +227,17 @@ void K_UnsetItemOut(player_t *player); boolean K_SafeRespawnPosition(mobj_t * mo); boolean K_RingsActive(void); +boolean K_StackingActive(void); +boolean K_ChainingActive(void); +boolean K_BoostChain(player_t *player, INT32 timer, boolean chainsound); +INT32 K_ChainOrDeincrementTime(player_t *player, INT32 timer, INT32 deincrement, boolean chainsound); boolean K_UsingLegacyCheckpoints(void); void K_UpdateMobjItemOverlay(mobj_t *part, SINT8 itemType, UINT8 itemCount); +void K_DoBoost(player_t *player, fixed_t speedboost, fixed_t accelboost, boolean stack, boolean visible); +void K_ClearBoost(player_t *player); + #ifdef __cplusplus } // extern "C" #endif diff --git a/src/lua_baselib.c b/src/lua_baselib.c index c54a4a09a..eb69ae4df 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -3958,7 +3958,7 @@ static int lib_kSetIndirectItemCountdown(lua_State *L) return 0; } -// Sets the item cooldown before another shrink / SPB can be rolled +// Sets the item cooldown before another hyudoro can be rolled static int lib_kSetHyuCountdown(lua_State *L) { tic_t c = (tic_t)luaL_checkinteger(L, 1); @@ -3985,6 +3985,20 @@ static int lib_kRingsActive(lua_State *L) return 1; } +// Checks if Stacking is active. +static int lib_kStackingActive(lua_State *L) +{ + lua_pushboolean(L, K_StackingActive()); + return 1; +} + +// Checks if Chaining is active. +static int lib_kChainingActive(lua_State *L) +{ + lua_pushboolean(L, K_ChainingActive()); + return 1; +} + // Checks if current map is using legacy boss3 bassed checkpoints. Useful for map compat. static int lib_kUsingLegacyCheckpoints(lua_State *L) { @@ -3992,6 +4006,59 @@ static int lib_kUsingLegacyCheckpoints(lua_State *L) return 1; } +static int lib_kDoBoost(lua_State *L) +{ + player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER)); + fixed_t speedboost = luaL_checkfixed(L, 2); + fixed_t accelboost = luaL_checkfixed(L, 3); + boolean stacking = lua_optboolean(L, 4); + boolean visible = lua_isnoneornil(L, 5) ? true : luaL_checkboolean(L, 5); + + //HUDSAFE + if (!player) + return LUA_ErrInvalid(L, "player_t"); + K_DoBoost(player, speedboost, accelboost, stacking, visible); + return 0; +} + +static int lib_kClearBoost(lua_State *L) +{ + player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER)); + + //HUDSAFE + if (!player) + return LUA_ErrInvalid(L, "player_t"); + K_ClearBoost(player); + return 0; +} + +static int lib_kBoostChain(lua_State *L) +{ + player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER)); + INT32 timer = luaL_checkinteger(L, 2); + INT32 chainsound = lua_optboolean(L, 3); + + //HUDSAFE + if (!player) + return LUA_ErrInvalid(L, "player_t"); + lua_pushboolean(L, K_BoostChain(player, timer, chainsound)); + return 1; +} + +static int lib_kChainOrDeincrementTime(lua_State *L) +{ + player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER)); + INT32 timer = luaL_checkinteger(L, 2); + INT32 deincrement = luaL_checkinteger(L, 3); + INT32 chainsound = lua_optboolean(L, 4); + + //HUDSAFE + if (!player) + return LUA_ErrInvalid(L, "player_t"); + lua_pushinteger(L, K_ChainOrDeincrementTime(player, timer, deincrement, chainsound)); + return 1; +} + static int lib_getTimeMicros(lua_State *L) { lua_pushinteger(L, I_GetPreciseTime() / (I_GetPrecisePrecision() / 1000000)); @@ -4286,12 +4353,19 @@ static luaL_Reg lib[] = { {"K_SetExitCountdown",lib_kSetExitCountdown}, {"K_SetIndirectItemCooldown",lib_kSetIndirectItemCountdown}, {"K_SetHyudoroCooldown",lib_kSetHyuCountdown}, - {"K_SafeRespawnPosition", lib_kSafeRespawnPosition}, + {"K_SafeRespawnPosition",lib_kSafeRespawnPosition}, {"K_GetCollideAngle",lib_kGetCollideAngle}, {"K_RingsActive",lib_kRingsActive}, + {"K_StackingActive",lib_kStackingActive}, + {"K_ChainingActive",lib_kChainingActive}, {"K_UsingLegacyCheckpoints",lib_kUsingLegacyCheckpoints}, + {"K_DoBoost",lib_kDoBoost}, + {"K_ClearBoost",lib_kClearBoost}, + {"K_BoostChain",lib_kBoostChain}, + {"K_ChainOrDeincrementTime",lib_kChainOrDeincrementTime}, + // k_boss {"K_InitBossHealthBar", lib_kInitBossHealthBar}, diff --git a/src/lua_consolelib.c b/src/lua_consolelib.c index 233a7ee4c..d9cb4ef36 100644 --- a/src/lua_consolelib.c +++ b/src/lua_consolelib.c @@ -590,6 +590,8 @@ int LUA_ConsoleLib(lua_State *L) lua_setglobal(L, "CV_YesNo"); lua_pushlightuserdata(L, CV_Unsigned); lua_setglobal(L, "CV_Unsigned"); + lua_pushlightuserdata(L, CV_Signed); + lua_setglobal(L, "CV_Signed"); lua_pushlightuserdata(L, CV_Natural); lua_setglobal(L, "CV_Natural"); diff --git a/src/lua_playerlib.c b/src/lua_playerlib.c index 32a302a82..515c84032 100644 --- a/src/lua_playerlib.c +++ b/src/lua_playerlib.c @@ -229,6 +229,9 @@ enum player_e player_speedboost, player_accelboost, player_boostangle, + player_boostinfo, + player_numsneakers, + player_numboosts, player_tripwireState, player_tripwirePass, player_tripwireLeniency, @@ -260,7 +263,9 @@ enum player_e player_stealingtimer, player_stolentimer, player_sneakertimer, + player_realsneakertimer, player_floorboost, + player_chaintimer, player_growshrinktimer, player_growcancel, player_squishedtimer, @@ -398,6 +403,9 @@ static const char *const player_opt[] = { "speedboost", "accelboost", "boostangle", + "boostinfo", + "numsneakers", + "numboosts", "tripwireState", "tripwirePass", "tripwireLeniency", @@ -429,7 +437,9 @@ static const char *const player_opt[] = { "stealingtimer", "stolentimer", "sneakertimer", + "realsneakertimer", "floorboost", + "chaintimer", "growshrinktimer", "growcancel", "squishedtimer", @@ -699,6 +709,15 @@ static int player_get(lua_State *L) case player_boostangle: lua_pushangle(L, plr->boostangle); break; + case player_boostinfo: + luaL_error(L, "Don't directly read boostinfo. Use speedboost, accelboost and numboosts instead,\n"); + break; + case player_numsneakers: + lua_pushinteger(L, plr->numsneakers); + break; + case player_numboosts: + lua_pushinteger(L, plr->numboosts); + break; case player_tripwireState: lua_pushinteger(L, plr->tripwireState); break; @@ -792,9 +811,15 @@ static int player_get(lua_State *L) case player_sneakertimer: lua_pushinteger(L, plr->sneakertimer); break; + case player_realsneakertimer: + lua_pushinteger(L, plr->realsneakertimer); + break; case player_floorboost: lua_pushinteger(L, plr->floorboost); break; + case player_chaintimer: + lua_pushinteger(L, plr->chaintimer); + break; case player_growshrinktimer: lua_pushinteger(L, plr->growshrinktimer); break; @@ -1281,6 +1306,15 @@ static int player_set(lua_State *L) case player_boostangle: plr->boostangle = luaL_checkangle(L, 3); break; + case player_boostinfo: + NOSET; + break; + case player_numsneakers: + plr->numsneakers = luaL_checkinteger(L, 3); + break; + case player_numboosts: + plr->numboosts = luaL_checkinteger(L, 3); + break; case player_tripwireState: plr->tripwireState = luaL_checkinteger(L, 3); break; @@ -1374,9 +1408,15 @@ static int player_set(lua_State *L) case player_sneakertimer: plr->sneakertimer = luaL_checkinteger(L, 3); break; + case player_realsneakertimer: + plr->realsneakertimer = luaL_checkinteger(L, 3); + break; case player_floorboost: plr->floorboost = luaL_checkinteger(L, 3); break; + case player_chaintimer: + plr->chaintimer = luaL_checkinteger(L, 3); + break; case player_growshrinktimer: plr->growshrinktimer = luaL_checkinteger(L, 3); break; diff --git a/src/lua_script.c b/src/lua_script.c index fc5520665..d6dd46a87 100644 --- a/src/lua_script.c +++ b/src/lua_script.c @@ -360,6 +360,15 @@ int LUA_PushGlobals(lua_State *L, const char *word) } else if (fastcmp(word,"battleprisons")) { lua_pushinteger(L, itembreaker); return 1; + } else if (fastcmp(word,"ringsactive")) { + lua_pushinteger(L, ringsactive); + return 1; + } else if (fastcmp(word,"stackingactive")) { + lua_pushinteger(L, stackingactive); + return 1; + } else if (fastcmp(word,"chainingactive")) { + lua_pushinteger(L, chainingactive); + return 1; } else if (fastcmp(word,"hyubgone")) { lua_pushinteger(L, hyubgone); return 1; @@ -481,6 +490,12 @@ int LUA_WriteGlobals(lua_State *L, const char *word) introtime = (tic_t)luaL_checkinteger(L, 2); else if (fastcmp(word,"itembreaker")) itembreaker = (boolean)luaL_checkinteger(L, 2); + else if (fastcmp(word,"battleprisons")) + itembreaker = (boolean)luaL_checkinteger(L, 2); + else if (fastcmp(word,"chainingactive")) + stackingactive = (boolean)luaL_checkinteger(L, 2); + else if (fastcmp(word,"chainingactive")) + chainingactive = (boolean)luaL_checkinteger(L, 2); else if (fastcmp(word,"gamespeed")) gamespeed = (UINT8)luaL_checkinteger(L, 2); else if (fastcmp(word,"nummapboxes")) diff --git a/src/p_enemy.c b/src/p_enemy.c index b03409253..e79b11c4e 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -3583,6 +3583,9 @@ void A_AttractChase(mobj_t *actor) actor->target->player->ringboost += K_GetKartRingPower(actor->target->player, true) + 3; S_StartSoundAtVolume(actor->target, sfx_s1b5, actor->target->player->ringvolume); + if (actor->target->player->ringboost > (4*TICRATE + TICRATE/2)) + actor->target->player->ringboost = (4*TICRATE + TICRATE/2); + actor->target->player->ringvolume -= RINGVOLUMEUSEPENALTY; P_KillMobj(actor, actor->target, actor->target, DMG_NORMAL); @@ -3607,6 +3610,9 @@ void A_AttractChase(mobj_t *actor) if (!P_GivePlayerRings(actor->target->player, 1)) // returns 0 if addition failed actor->target->player->ringboost += K_GetKartRingPower(actor->target->player, true) + 3; + if (actor->target->player->ringboost > (4*TICRATE + TICRATE/2)) + actor->target->player->ringboost = (4*TICRATE + TICRATE/2); + if (actor->cvmem) // caching S_StartSound(actor->target, sfx_s1c5); else diff --git a/src/p_mobj.c b/src/p_mobj.c index 799bcf73c..2c3efefd2 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -7070,7 +7070,6 @@ static boolean P_MobjRegularThink(mobj_t *mobj) return false; } - { player_t *p = NULL; if (mobj->target->target && mobj->target->target->player) @@ -7080,12 +7079,16 @@ static boolean P_MobjRegularThink(mobj_t *mobj) mobj->angle = mobj->extravalue1 && p ? p->drawangle : mobj->target->angle; P_MoveOrigin(mobj, mobj->target->x + P_ReturnThrustX(mobj, mobj->angle+ANGLE_180, mobj->target->radius), - mobj->target->y + P_ReturnThrustY(mobj, mobj->angle+ANGLE_180, mobj->target->radius), mobj->target->z); + mobj->target->y + P_ReturnThrustY(mobj, mobj->angle+ANGLE_180, mobj->target->radius), mobj->target->z+5*mapobjectscale); + K_FlipFromObject(mobj, mobj->target); P_SetScale(mobj, mobj->target->scale); mobj->roll = mobj->target->roll; mobj->pitch = mobj->target->pitch; + mobj->sloperoll = mobj->target->sloperoll; + mobj->slopepitch = mobj->target->slopepitch; + if (p) { if (mobj->extravalue1) @@ -7120,6 +7123,38 @@ static boolean P_MobjRegularThink(mobj_t *mobj) } else { + if (stackingactive && cv_kartstacking_colorflame.value) + { + switch(p->numsneakers) + { + case 0: + case 1: + mobj->colorized = false; + break; + case 2: + mobj->colorized = true; + mobj->color = SKINCOLOR_BLUEBERRY; + break; + case 3: + mobj->colorized = true; + mobj->color = SKINCOLOR_PURPLE; + break; + case 4: + mobj->colorized = true; + mobj->color = SKINCOLOR_MOONSLAM; + break; + case 5: + mobj->colorized = true; + mobj->color = SKINCOLOR_WHITE; + break; + default: + mobj->colorized = true; + mobj->color = SKINCOLOR_WHITE; + break; + + } + } + if (p->sneakertimer > mobj->movecount) P_SetMobjState(mobj, S_BOOSTFLAME); mobj->movecount = p->sneakertimer; @@ -7129,7 +7164,6 @@ static boolean P_MobjRegularThink(mobj_t *mobj) if (mobj->extravalue1) { - if (leveltime % 2 == 1) { mobj->frame |= FF_TRANS60; @@ -7143,7 +7177,6 @@ static boolean P_MobjRegularThink(mobj_t *mobj) { mobj->color = K_RainbowColor(leveltime); } - } if (mobj->state == &states[S_BOOSTSMOKESPAWNER]) @@ -7307,6 +7340,28 @@ static boolean P_MobjRegularThink(mobj_t *mobj) } break; + case MT_BOOSTSTACK: + { + if (!mobj->target || P_MobjWasRemoved(mobj->target) || !mobj->target->health || (mobj->target->player && !mobj->target->player->numboosts)) + { + P_RemoveMobj(mobj); + return false; + } + + mobj->roll = mobj->target->roll; + mobj->pitch = mobj->target->pitch; + + mobj->sloperoll = mobj->target->sloperoll; + mobj->slopepitch = mobj->target->slopepitch; + + // Thx Indev! (taken and modified from BoostStack) + P_MoveOrigin(mobj, mobj->target->x + FixedMul(cos(mobj->target->angle), FixedMul(30*FRACUNIT, mapobjectscale)), mobj->target->y + FixedMul(sin(mobj->target->angle), FixedMul(30*FRACUNIT, mapobjectscale)), mobj->target->z); + K_FlipFromObject(mobj, mobj->target); + + // Leveltime based animation + mobj->frame = states[S_BOOSTSTACK].frame + (leveltime / 3) % 5; + break; + } case MT_THUNDERSHIELD: { if (!mobj->target || !mobj->target->health || !mobj->target->player diff --git a/src/p_mobj.h b/src/p_mobj.h index 109ea99bc..dc7c1e75d 100644 --- a/src/p_mobj.h +++ b/src/p_mobj.h @@ -578,6 +578,8 @@ extern UINT16 emeraldspawndelay; extern INT32 numstarposts; extern INT32 numbosswaypoints; extern boolean ringsactive; +extern boolean stackingactive; +extern boolean chainingactive; extern UINT16 bossdisabled; extern boolean stoppedclock; diff --git a/src/p_saveg.c b/src/p_saveg.c index 9dbcb6e0a..d05c02553 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -272,6 +272,14 @@ static void P_NetArchivePlayers(savebuffer_t *save) WRITEFIXED(save->p, players[i].speedboost); WRITEFIXED(save->p, players[i].accelboost); WRITEANGLE(save->p, players[i].boostangle); + WRITEUINT8(save->p, players[i].numsneakers); + WRITEUINT8(save->p, players[i].numboosts); + + // boostinfo_t + WRITEFIXED(save->p, players[i].boostinfo.stackspeedboost); + WRITEFIXED(save->p, players[i].boostinfo.nonstackspeedboost); + WRITEFIXED(save->p, players[i].boostinfo.accelboost); + WRITEUINT8(save->p, players[i].boostinfo.grade); WRITEUINT8(save->p, players[i].tripwireState); WRITEUINT8(save->p, players[i].tripwirePass); @@ -310,7 +318,9 @@ static void P_NetArchivePlayers(savebuffer_t *save) WRITESINT8(save->p, players[i].stealingtimer); WRITEUINT16(save->p, players[i].sneakertimer); + WRITEUINT16(save->p, players[i].realsneakertimer); WRITEUINT8(save->p, players[i].floorboost); + WRITEUINT16(save->p, players[i].chaintimer); WRITEUINT8(save->p, players[i].boostcharge); @@ -576,6 +586,14 @@ static void P_NetUnArchivePlayers(savebuffer_t *save) players[i].speedboost = READFIXED(save->p); players[i].accelboost = READFIXED(save->p); players[i].boostangle = READANGLE(save->p); + players[i].numsneakers = READUINT8(save->p); + players[i].numboosts = READUINT8(save->p); + + // boostinfo_t + players[i].boostinfo.stackspeedboost = READFIXED(save->p); + players[i].boostinfo.nonstackspeedboost = READFIXED(save->p); + players[i].boostinfo.accelboost = READFIXED(save->p); + players[i].boostinfo.grade = READUINT8(save->p); players[i].tripwireState = READUINT8(save->p); players[i].tripwirePass = READUINT8(save->p); @@ -614,7 +632,9 @@ static void P_NetUnArchivePlayers(savebuffer_t *save) players[i].stealingtimer = READSINT8(save->p); players[i].sneakertimer = READUINT16(save->p); + players[i].realsneakertimer = READUINT16(save->p); players[i].floorboost = READUINT8(save->p); + players[i].chaintimer = READUINT16(save->p); players[i].boostcharge = READUINT8(save->p); @@ -5067,6 +5087,8 @@ 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); + WRITEUINT8(save->p, chainingactive); for (i = 0; i < 4; i++) { @@ -5236,6 +5258,8 @@ 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); + chainingactive = READUINT8(save->p); for (i = 0; i < 4; i++) { diff --git a/src/p_setup.c b/src/p_setup.c index 8aeb9fd97..9977e7bf2 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -142,7 +142,9 @@ line_t *spawnlines; side_t *spawnsides; INT32 numstarposts; INT32 numbosswaypoints; -boolean ringsactive; +boolean ringsactive = false; +boolean stackingactive = false; +boolean chainingactive = false; UINT16 bossdisabled; boolean stoppedclock; boolean levelloading; @@ -7883,6 +7885,16 @@ static void P_InitLevelSettings(boolean reloadinggamestate) else ringsactive = false; + if (cv_kartstacking.value) + stackingactive = true; + else + stackingactive = false; + + if (cv_kartchaining.value) + chainingactive = true; + else + chainingactive = false; + // emerald hunt hunt1 = hunt2 = hunt3 = NULL; diff --git a/src/typedef.h b/src/typedef.h index ca33b24e9..467352019 100644 --- a/src/typedef.h +++ b/src/typedef.h @@ -43,6 +43,7 @@ TYPEDEF (discordRequest_t); // d_player.h TYPEDEF (botvars_t); +TYPEDEF (boostinfo_t); TYPEDEF (player_t); TYPEDEF (sonicloopcamvars_t); TYPEDEF (sonicloopvars_t);