stacking pt.3: start work on chaining

This commit is contained in:
NepDisk 2025-03-25 18:01:18 -04:00
parent 7091195a95
commit f0b6ef89eb
11 changed files with 269 additions and 19 deletions

View file

@ -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"));
}

View file

@ -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;

View file

@ -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

View file

@ -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)

View file

@ -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);

View file

@ -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},

View file

@ -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;

View file

@ -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"))

View file

@ -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;

View file

@ -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++)
{

View file

@ -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;