From f0b6ef89eba85c5b67534d9b9c1399e58c9f2dd2 Mon Sep 17 00:00:00 2001 From: NepDisk Date: Tue, 25 Mar 2025 18:01:18 -0400 Subject: [PATCH] stacking pt.3: start work on chaining --- src/d_netcmd.c | 72 ++++++++++++++++++++--- src/d_netcmd.h | 1 + src/d_player.h | 1 + src/k_kart.c | 138 ++++++++++++++++++++++++++++++++++++++++---- src/k_kart.h | 2 + src/lua_baselib.c | 16 +++++ src/lua_playerlib.c | 32 ++++++++++ src/lua_script.c | 15 +++++ src/p_mobj.h | 1 + src/p_saveg.c | 4 ++ src/p_setup.c | 6 ++ 11 files changed, 269 insertions(+), 19 deletions(-) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index fe08bcf11..5bfebc63f 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -152,6 +152,7 @@ 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); @@ -442,6 +443,7 @@ consvar_t cv_karteliminatelast = CVAR_INIT ("karteliminatelast", "Yes", CV_NETVA // Toggles for new features 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_kartchaining = CVAR_INIT ("kartchaining", "No", CV_NETVAR|CV_CALL|CV_NOINIT, CV_YesNo, KartChaining_OnChange); consvar_t cv_kartitembreaker = CVAR_INIT ("kartitembreaker", "No", CV_NETVAR|CV_CHEAT|CV_CALL|CV_NOINIT, CV_YesNo, KartItemBreaker_OnChange); @@ -6943,11 +6945,11 @@ 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")); } @@ -6960,13 +6962,62 @@ static void KartStacking_OnChange(void) return; } - if (cv_kartstacking.value) + if (!stackingactive && cv_kartstacking.value) { - CONS_Printf(M_GetText("Boost Stacking will be turned \"On\" Next Round.\n")); + 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 + else if (stackingactive && !cv_kartstacking.value) { - CONS_Printf(M_GetText("Boost Stacking will be turned \"Off\" Next Round.\n")); + 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")); + } } } @@ -6977,11 +7028,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 b0c118248..35914b448 100644 --- a/src/d_netcmd.h +++ b/src/d_netcmd.h @@ -97,6 +97,7 @@ extern consvar_t cv_karteliminatelast; extern consvar_t cv_kartusepwrlv; extern consvar_t cv_kartrings; extern consvar_t cv_kartstacking; +extern consvar_t cv_kartchaining; 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 d954c52cc..0866cc122 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -633,6 +633,7 @@ struct player_t UINT16 sneakertimer; // Duration of a Sneaker Boost (from Sneakers or level boosters) 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/k_kart.c b/src/k_kart.c index 6a69df303..e5f939e95 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -254,6 +254,7 @@ void K_RegisterKartStuff(void) CV_RegisterVar(&cv_kartrings); CV_RegisterVar(&cv_kartstacking); + CV_RegisterVar(&cv_kartchaining); CV_RegisterVar(&cv_kartitembreaker); CV_RegisterVar(&cv_newspeedometer); @@ -7007,6 +7008,101 @@ static void K_TireGreaseEffect(player_t *player) S_StartSound(player->mo, sfx_screec); } +boolean K_BoostChain(player_t *player, INT32 timer) +{ + if (!chainingactive) + { + // You can't chain why bother? + return false; + } + + if (timer > player->chaintimer) + { + // Just what I needed! - Toad + 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) +{ + if (K_BoostChain(player, timer)) + { + // Its time to chain. + return max(1, timer - deincrement); + } + + // Continue to drain the timer as normal. + return timer - deincrement; +} + +// 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; + } + } + + player->ringboost = K_ChainOrDeincrementTime(player, 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 @@ -7196,18 +7292,13 @@ 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); + if (player->sneakertimer <= 0) { player->mo->flags2 &= ~MF2_WATERRUN; @@ -7222,10 +7313,10 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) player->floorboost--; if (player->driftboost) - player->driftboost--; + player->driftboost = K_ChainOrDeincrementTime(player, player->driftboost, 1); if (player->startboost > 0) - player->startboost--; + player->startboost = K_ChainOrDeincrementTime(player, player->startboost, 1); if (player->invincibilitytimer) player->invincibilitytimer--; @@ -7324,7 +7415,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) { @@ -10434,6 +10528,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 fd1a8a712..db8b09002 100644 --- a/src/k_kart.h +++ b/src/k_kart.h @@ -194,6 +194,8 @@ 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_UsingLegacyCheckpoints(void); void K_UpdateMobjItemOverlay(mobj_t *part, SINT8 itemType, UINT8 itemCount); diff --git a/src/lua_baselib.c b/src/lua_baselib.c index 35cc252e5..f5527f5c3 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -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) { @@ -4317,6 +4331,8 @@ static luaL_Reg lib[] = { {"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}, diff --git a/src/lua_playerlib.c b/src/lua_playerlib.c index 32a302a82..0dc5ccf63 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, @@ -261,6 +264,7 @@ enum player_e player_stolentimer, player_sneakertimer, player_floorboost, + player_chaintimer, player_growshrinktimer, player_growcancel, player_squishedtimer, @@ -398,6 +402,9 @@ static const char *const player_opt[] = { "speedboost", "accelboost", "boostangle", + "boostinfo", + "numsneakers", + "numboosts", "tripwireState", "tripwirePass", "tripwireLeniency", @@ -430,6 +437,7 @@ static const char *const player_opt[] = { "stolentimer", "sneakertimer", "floorboost", + "chaintimer", "growshrinktimer", "growcancel", "squishedtimer", @@ -699,6 +707,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; @@ -795,6 +812,9 @@ static int player_get(lua_State *L) 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 +1301,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; @@ -1377,6 +1406,9 @@ static int player_set(lua_State *L) 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 f203d765c..ac0966b1a 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_mobj.h b/src/p_mobj.h index 0b69fda9c..dc7c1e75d 100644 --- a/src/p_mobj.h +++ b/src/p_mobj.h @@ -579,6 +579,7 @@ 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 0251cdd19..3a6bd771a 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -319,6 +319,7 @@ static void P_NetArchivePlayers(savebuffer_t *save) WRITEUINT16(save->p, players[i].sneakertimer); WRITEUINT8(save->p, players[i].floorboost); + WRITEUINT16(save->p, players[i].chaintimer); WRITEUINT8(save->p, players[i].boostcharge); @@ -631,6 +632,7 @@ static void P_NetUnArchivePlayers(savebuffer_t *save) players[i].sneakertimer = READUINT16(save->p); players[i].floorboost = READUINT8(save->p); + players[i].chaintimer = READUINT16(save->p); players[i].boostcharge = READUINT8(save->p); @@ -5084,6 +5086,7 @@ static void P_NetArchiveMisc(savebuffer_t *save, boolean resending) WRITEUINT16(save->p, bossdisabled); WRITEUINT8(save->p, ringsactive); WRITEUINT8(save->p, stackingactive); + WRITEUINT8(save->p, chainingactive); for (i = 0; i < 4; i++) { @@ -5254,6 +5257,7 @@ FUNCINLINE static ATTRINLINE boolean P_NetUnArchiveMisc(savebuffer_t *save, bool 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 2d80ad9ad..f45142c36 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -144,6 +144,7 @@ INT32 numstarposts; INT32 numbosswaypoints; boolean ringsactive; boolean stackingactive; +boolean chainingactive; UINT16 bossdisabled; boolean stoppedclock; boolean levelloading; @@ -7889,6 +7890,11 @@ static void P_InitLevelSettings(boolean reloadinggamestate) else stackingactive = false; + if (cv_kartchaining.value) + chainingactive = true; + else + chainingactive = false; + // emerald hunt hunt1 = hunt2 = hunt3 = NULL;