diff --git a/src/d_netcmd.c b/src/d_netcmd.c index a3aa6782d..c1d60fa5b 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -153,6 +153,7 @@ static void KartEliminateLast_OnChange(void); static void KartRings_OnChange(void); static void KartStacking_OnChange(void); static void KartChaining_OnChange(void); +static void KartSlipdash_OnChange(void); static void KartItemBreaker_OnChange(void); static void Schedule_OnChange(void); @@ -478,7 +479,7 @@ consvar_t cv_kartstacking_ring_accelboost = CVAR_INIT ("vanillaboost_ring_accelb 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_kartitembreaker = CVAR_INIT ("kartitembreaker", "No", CV_NETVAR|CV_CALL|CV_NOINIT, CV_YesNo, KartItemBreaker_OnChange); consvar_t cv_kartwalltransfer = CVAR_INIT ("BG_forcewalltransfer", "Off", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL); @@ -490,6 +491,8 @@ consvar_t cv_kartbumpspark = CVAR_INIT ("kartbumpspark", "No", CV_NETVAR, CV_Yes consvar_t cv_kartbumpspring = CVAR_INIT ("kartbumpspring", "No", CV_NETVAR, CV_YesNo, NULL); +consvar_t cv_kartslipdash = CVAR_INIT ("kartslipdash", "No", CV_NETVAR|CV_CALL|CV_NOINIT, CV_YesNo, KartSlipdash_OnChange); + static CV_PossibleValue_t kartdebugitem_cons_t[] = { #define FOREACH( name, n ) { n, #name } @@ -7113,6 +7116,39 @@ static void KartChaining_OnChange(void) } } +static void KartSlipdash_OnChange(void) +{ + if (K_CanChangeRules() == false) + { + return; + } + + if (!slipdashactive && cv_kartslipdash.value) + { + if (leveltime < starttime) + { + slipdashactive = true; + CONS_Printf(M_GetText("Slipdashing has been turned \"On\".\n")); + } + else + { + CONS_Printf(M_GetText("Slipdashing will be turned \"On\" Next Round.\n")); + } + } + else if (slipdashactive && !cv_kartslipdash.value) + { + if (leveltime < starttime) + { + slipdashactive = false; + CONS_Printf(M_GetText("Slipdashing has been turned \"Off\".\n")); + } + else + { + CONS_Printf(M_GetText("Slipdashing will be turned \"Off\" next round.\n")); + } + } +} + static void KartItemBreaker_OnChange(void) { if (K_CanChangeRules() == false) diff --git a/src/d_netcmd.h b/src/d_netcmd.h index 6ddf593c8..c1e7dd2d2 100644 --- a/src/d_netcmd.h +++ b/src/d_netcmd.h @@ -157,8 +157,8 @@ extern consvar_t cv_kartitembreaker; extern consvar_t cv_kartwalltransfer; extern consvar_t cv_kartpurpledrift; extern consvar_t cv_kartbumpspark; - extern consvar_t cv_kartbumpspring; +extern consvar_t cv_kartslipdash; extern consvar_t cv_votetime; diff --git a/src/d_player.h b/src/d_player.h index f17621d82..5fb29aca0 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -577,6 +577,8 @@ struct player_t SINT8 aizdriftstrat; // (-1 to 1) - Let go of your drift while boosting? Helper for the SICK STRATZ (sliptiding!) you have just unlocked INT32 aizdrifttilt; INT32 aizdriftturn; + fixed_t slipdashcharge; // charge up a dash with a sliptide! + SINT8 slipdashdir; // no snaking allowed :^) fixed_t offroad; // In Super Mario Kart, going offroad has lee-way of about 1 second before you start losing speed UINT8 pogospring; // Pogo spring bounce effect diff --git a/src/k_kart.c b/src/k_kart.c index 2a49499ad..e3bb0fa7f 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -310,6 +310,8 @@ void K_RegisterKartStuff(void) CV_RegisterVar(&cv_kartbumpspring); + CV_RegisterVar(&cv_kartslipdash); + CV_RegisterVar(&cv_kartdriftsounds); CV_RegisterVar(&cv_kartdriftefx); @@ -8816,6 +8818,9 @@ INT16 K_GetKartTurnValue(player_t *player, INT16 turnvalue) turnvalue = FixedMul(turnvalue, adjustangle); // Weight has a small effect on turning + if (cv_kartslipdash.value && K_Sliptiding(player)) // slight handling boost based on weight + turnvalue = FixedMul(turnvalue, FRACUNIT + (10 - player->kartweight)*FRACUNIT/48); + if (player->invincibilitytimer || player->sneakertimer || player->growshrinktimer > 0) turnvalue = FixedMul(turnvalue, FixedDiv(5*FRACUNIT, 4*FRACUNIT)); @@ -9076,7 +9081,7 @@ static void K_KartDrift(player_t *player, boolean onground) else player->aizdriftstrat = ((player->drift > 0) ? 1 : -1); } - else if (player->aizdriftstrat && !player->drift) + else if (K_Sliptiding(player)) { K_SpawnAIZDust(player); @@ -9119,6 +9124,82 @@ static void K_KartDrift(player_t *player, boolean onground) player->pflags &= ~PF_BRAKEDRIFT; } +static void K_KartSlipdash(player_t *player, boolean onground) +{ + boolean snaked = player->slipdashdir && player->aizdriftstrat && player->slipdashdir != player->aizdriftstrat; + if (!cv_kartslipdash.value || P_PlayerInPain(player)) + { + player->slipdashcharge = 0; + player->slipdashdir = 0; + } + else if ((K_Sliptiding(player) || player->aizdriftturn) && !snaked) + { + if (!player->slipdashdir) // anti-snaking + player->slipdashdir = player->aizdriftstrat; + + if (onground && !player->drift) + { + fixed_t turn = max(0, player->cmd.turning * player->aizdriftstrat); + turn = FINETANGENT((turn*(ANGLE_45/KART_FULLTURN) + ANGLE_90) >> ANGLETOFINESHIFT); + player->slipdashcharge = min(player->slipdashcharge + turn/45, FRACUNIT); + + if (!(leveltime % 5)) + S_StartSoundAtVolume(player->mo, sfx_cdfm17, 133 + turn/555); + } + } + else if (player->slipdashcharge && onground) + { + INT32 i; + boolean driftbonus = player->driftcharge && !snaked; + + if (snaked) + player->slipdashcharge /= 4; + + S_StopSoundByID(player->mo, sfx_cdfm17); + S_StartSoundAtVolume(player->mo, player->slipdashcharge > FRACUNIT/3 ? sfx_cdfm62 : sfx_s23c, driftbonus ? 200 : 255); + P_Thrust(player->mo, player->mo->angle, FixedMul(K_GetKartSpeed(player, false, false), 2*player->slipdashcharge/3)); + K_DoBoost(player, (2*player->slipdashcharge/3)/2, 0, false, false); + + for (i = -1; i <= 1; i += 2) + { + mobj_t *strat = P_SpawnMobjFromMobj(player->mo, + P_ReturnThrustX(NULL, player->mo->angle + ANGLE_67h*i, -20*player->mo->scale), + P_ReturnThrustY(NULL, player->mo->angle + ANGLE_67h*i, -20*player->mo->scale), + 0, MT_AIZDRIFTSTRAT + ); + strat->angle = player->mo->angle + ANGLE_67h*i; + P_SetScale(strat, FixedMul(player->slipdashcharge + FRACUNIT/4, mapobjectscale)); + strat->destscale = strat->scale; + P_InstaThrust(strat, strat->angle, -8*mapobjectscale); + } + + if (driftbonus) + { + INT32 dsv = K_GetKartDriftSparkValue(player); + player->driftcharge = min(player->driftcharge + FixedMul(player->slipdashcharge, dsv), dsv-1); + S_StartSound(player->mo, sfx_s3k45); + } + + player->slipdashcharge = 0; + player->slipdashdir = 0; + } + else + player->slipdashdir = 0; + + if (player->slipdashcharge && leveltime & 1) + { + mobj_t *spark = P_SpawnMobjFromMobj(player->mo, 0, 0, -4*mapobjectscale, MT_DRIFTSPARK); + spark->color = SKINCOLOR_GREEN; + spark->angle = player->mo->angle + player->aizdriftstrat*ANGLE_45; + P_SetScale(spark, FixedMul(player->slipdashcharge + 2*FRACUNIT/3, mapobjectscale)); + spark->destscale = 0; + spark->scalespeed = mapobjectscale/4; + P_InstaThrust(spark, player->mo->angle, player->speed/2); + spark->momz = player->mo->z - player->mo->old_z; + spark->z += spark->momz; + } +} + INT32 K_GetDriftAngleOffset(player_t *player) { INT32 a = 0; @@ -10349,6 +10430,8 @@ void K_MoveKartPlayer(player_t *player, boolean onground) K_KartDrift(player, onground); + K_KartSlipdash(player, onground); + // Quick Turning // You can't turn your kart when you're not moving. // So now it's time to burn some rubber! @@ -10644,6 +10727,17 @@ boolean K_ChainingActive(void) return false; } +boolean K_SlipdashActive(void) +{ + if (slipdashactive) + { + // Slipdash 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 45a1e6d8a..913e11f9d 100644 --- a/src/k_kart.h +++ b/src/k_kart.h @@ -229,6 +229,7 @@ boolean K_SafeRespawnPosition(mobj_t * mo); boolean K_RingsActive(void); boolean K_StackingActive(void); boolean K_ChainingActive(void); +boolean K_SlipdashActive(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); diff --git a/src/lua_baselib.c b/src/lua_baselib.c index eb69ae4df..c620190b7 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -3999,6 +3999,13 @@ static int lib_kChainingActive(lua_State *L) return 1; } +// Checks if Chaining is active. +static int lib_kSlipdashActive(lua_State *L) +{ + lua_pushboolean(L, K_SlipdashActive()); + return 1; +} + // Checks if current map is using legacy boss3 bassed checkpoints. Useful for map compat. static int lib_kUsingLegacyCheckpoints(lua_State *L) { @@ -4360,6 +4367,7 @@ static luaL_Reg lib[] = { {"K_RingsActive",lib_kRingsActive}, {"K_StackingActive",lib_kStackingActive}, {"K_ChainingActive",lib_kChainingActive}, + {"K_SlipdashActive",lib_kSlipdashActive}, {"K_UsingLegacyCheckpoints",lib_kUsingLegacyCheckpoints}, {"K_DoBoost",lib_kDoBoost}, {"K_ClearBoost",lib_kClearBoost}, diff --git a/src/lua_playerlib.c b/src/lua_playerlib.c index 43be382df..59f9b3fb0 100644 --- a/src/lua_playerlib.c +++ b/src/lua_playerlib.c @@ -222,6 +222,8 @@ enum player_e player_aizdriftstrat, player_aizdrifttilt, player_aizdriftturn, + player_slipdashcharge, + player_slipdashdir, player_offroad, player_pogospring, player_brakestop, @@ -398,6 +400,8 @@ static const char *const player_opt[] = { "aizdriftstrat", "aizdrifttilt", "aizdriftturn", + "slipdashcharge", + "slipdashdir", "offroad", "pogospring", "brakestop", @@ -692,6 +696,12 @@ static int player_get(lua_State *L) case player_aizdriftturn: lua_pushinteger(L, plr->aizdriftturn); break; + case player_slipdashcharge: + lua_pushfixed(L, plr->slipdashcharge); + break; + case player_slipdashdir: + lua_pushinteger(L, plr->slipdashdir); + break; case player_offroad: lua_pushinteger(L, plr->offroad); break; @@ -1295,6 +1305,12 @@ static int player_set(lua_State *L) case player_aizdriftturn: plr->aizdriftturn = luaL_checkinteger(L, 3); break; + case player_slipdashcharge: + plr->slipdashcharge = luaL_checkfixed(L, 3); + break; + case player_slipdashdir: + plr->slipdashdir = luaL_checkinteger(L, 3); + break; case player_offroad: plr->offroad = luaL_checkinteger(L, 3); break; diff --git a/src/p_mobj.h b/src/p_mobj.h index dc7c1e75d..32edf7dde 100644 --- a/src/p_mobj.h +++ b/src/p_mobj.h @@ -580,6 +580,7 @@ extern INT32 numbosswaypoints; extern boolean ringsactive; extern boolean stackingactive; extern boolean chainingactive; +extern boolean slipdashactive; extern UINT16 bossdisabled; extern boolean stoppedclock; diff --git a/src/p_saveg.c b/src/p_saveg.c index d05c02553..b7a6f91e4 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -259,6 +259,8 @@ static void P_NetArchivePlayers(savebuffer_t *save) WRITESINT8(save->p, players[i].aizdriftstrat); WRITEINT32(save->p, players[i].aizdrifttilt); WRITEINT32(save->p, players[i].aizdriftturn); + WRITEFIXED(save->p, players[i].slipdashcharge); + WRITESINT8(save->p, players[i].slipdashdir); WRITEFIXED(save->p, players[i].offroad); WRITEFIXED(save->p, players[i].tiregrease); @@ -573,6 +575,8 @@ static void P_NetUnArchivePlayers(savebuffer_t *save) players[i].aizdriftstrat = READSINT8(save->p); players[i].aizdrifttilt = READINT32(save->p); players[i].aizdriftturn = READINT32(save->p); + players[i].slipdashcharge = READFIXED(save->p); + players[i].slipdashdir = READSINT8(save->p); players[i].offroad = READFIXED(save->p); players[i].tiregrease = READFIXED(save->p); diff --git a/src/p_setup.c b/src/p_setup.c index e38bdef63..9f3c0d0ea 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -145,6 +145,7 @@ INT32 numbosswaypoints; boolean ringsactive = false; boolean stackingactive = false; boolean chainingactive = false; +boolean slipdashactive = false; UINT16 bossdisabled; boolean stoppedclock; boolean levelloading; @@ -7879,21 +7880,23 @@ static void P_InitLevelSettings(boolean reloadinggamestate) nummapboxes = numgotboxes = 0; numtargets = 0; itembreaker = false; + ringsactive = false; + stackingactive = false; + chainingactive = false; + slipdashactive = false; + if (cv_kartrings.value) ringsactive = true; - else - ringsactive = false; if (cv_kartstacking.value) stackingactive = true; - else - stackingactive = false; if (cv_kartchaining.value) chainingactive = true; - else - chainingactive = false; + + if (cv_kartslipdash.value) + slipdashactive = true; // emerald hunt hunt1 = hunt2 = hunt3 = NULL;