Hardcoded Keep Stuff

Toggles allows certain item timers to maintain on death. Also handles setting up the state of said items again..
This commit is contained in:
NepDisk 2026-05-02 03:30:29 -04:00
parent c43b1228c5
commit 01ce7b0221
19 changed files with 306 additions and 9 deletions

View file

@ -103,7 +103,7 @@
#define ASSET_HASH_TEXTURES_KART 0xb4211b2f32b6a291
#define ASSET_HASH_CHARS_KART 0x1e68a3e01aa5c68b
#define ASSET_HASH_MAPS_KART 0x38558ed00da41ce9
#define ASSET_HASH_MAIN_PK3 0xd3852fcf75a24503
#define ASSET_HASH_MAIN_PK3 0x4ea7e79e2d5d0d63
#define ASSET_HASH_MAPPATCH_PK3 0x1745690024efbaf8
#define ASSET_HASH_BONUSCHARS_KART 0x60e6f13d822a7461
#ifdef USE_PATCH_FILE

View file

@ -171,6 +171,7 @@ static void KartDrafting_OnChange(void);
static void KartAirDrop_OnChange(void);
static void KartAirThrust_OnChange(void);
static void KartRecoveryDash_OnChange(void);
static void KartKeepStuff_OnChange(void);
static void KartWaterSkipLock_OnChange(void);
static void KartItemLitter_OnChange(void);
static void KartItemPush_OnChange(void);
@ -673,6 +674,9 @@ consvar_t cv_handleboostslip = CVAR_INIT ("karthandleboostsliptide", "Off", CV_N
consvar_t cv_kartrecoverydash = CVAR_INIT ("kartrecoverydash", "No", CV_NETVAR|CV_CALL|CV_NOINIT|CV_GUARD, CV_YesNo, KartRecoveryDash_OnChange);
consvar_t cv_kartrecoverydash_spinspeed = CVAR_INIT ("kartrecoverydash_spinspeed", "24.0", CV_NETVAR|CV_FLOAT|CV_CHEAT|CV_GUARD, CV_Unsigned, NULL);
consvar_t cv_kartkeepstuff = CVAR_INIT ("kartkeepstuff", "No", CV_NETVAR|CV_CALL|CV_NOINIT|CV_GUARD, CV_YesNo, KartKeepStuff_OnChange);
#define ANTIBUMP_MAX (UINT32_MAX / TICRATE)
static CV_PossibleValue_t antibump_cons_t[] = {{0, "MIN"}, {ANTIBUMP_MAX, "MAX"}, {0, NULL}};
consvar_t cv_kartantibump = CVAR_INIT ("kartantibump", "0", CV_NETVAR|CV_CALL|CV_NOINIT, antibump_cons_t, KartAntiBump_OnChange);
@ -9684,6 +9688,39 @@ static void KartRecoveryDash_OnChange(void)
}
}
static void KartKeepStuff_OnChange(void)
{
if (K_CanChangeRules(false) == false)
{
return;
}
if (!K_KeepStuffActive() && cv_kartkeepstuff.value)
{
if (leveltime < starttime)
{
keepstuffactive = true;
CONS_Printf(M_GetText("Keep Stuff has been turned \"On\".\n"));
}
else
{
CONS_Printf(M_GetText("Keep Stuff will be turned \"On\" Next Round.\n"));
}
}
else if (K_KeepStuffActive() && !cv_kartkeepstuff.value)
{
if (leveltime < starttime)
{
keepstuffactive = false;
CONS_Printf(M_GetText("Keep Stuff has been turned \"Off\".\n"));
}
else
{
CONS_Printf(M_GetText("Keep Stuff will be turned \"Off\" next round.\n"));
}
}
}
static void KartWaterSkipLock_OnChange(void)
{
if (K_CanChangeRules(false) == false)

View file

@ -269,6 +269,8 @@ extern consvar_t cv_handleboostslip;
extern consvar_t cv_kartrecoverydash;
extern consvar_t cv_kartrecoverydash_spinspeed;
extern consvar_t cv_kartkeepstuff;
extern consvar_t cv_kartoddsdist;
extern consvar_t cv_kartlegacyoddsdist;

View file

@ -493,6 +493,32 @@ typedef enum
LAP__MAX
} laptime_e;
typedef enum
{
KEEPSTUFF_ROCKET = 1,
KEEPSTUFF_INVIN = 1<<1,
KEEPSTUFF_SMON = 1<<2,
KEEPSTUFF_GROWSHRINK = 1<<3,
KEEPSTUFF_FLAME = 1<<4,
} keepstuffflags_t;
struct keepstuff_t
{
UINT16 flags;
UINT16 rocketsneakertimer;
UINT16 invincibilitytimer;
UINT16 smonitortimer;
UINT16 smonitorexpiring;
UINT16 maxsmonitortime;
INT16 growshrinktimer;
UINT16 flametimer;
};
// ========================================================================
// PLAYER STRUCTURE
// ========================================================================
@ -902,6 +928,8 @@ struct player_t
uint8_t public_key[PUBKEYLENGTH];
keepstuff_t keepstuff;
#ifdef HWRENDER
fixed_t fovadd; // adjust FOV for hw rendering
#endif

View file

@ -1912,5 +1912,12 @@ struct int_const_s const INT_CONST[] = {
{"RINGMOD_SAW", RINGMOD_SAW},
{"RINGMOD_SQUARE", RINGMOD_SQUARE},
// keepstuffflags_t
{"KEEPSTUFF_ROCKET", KEEPSTUFF_ROCKET},
{"KEEPSTUFF_INVIN", KEEPSTUFF_INVIN},
{"KEEPSTUFF_SMON", KEEPSTUFF_SMON},
{"KEEPSTUFF_GROWSHRINK", KEEPSTUFF_GROWSHRINK},
{"KEEPSTUFF_FLAME", KEEPSTUFF_FLAME},
{NULL,0}
};

View file

@ -2999,6 +2999,21 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
tic_t laptime[LAP__MAX];
// Keep stuff shit
UINT16 ksflags;
UINT16 ksrocketsneakertimer;
UINT16 ksinvincibilitytimer;
UINT16 kssmonitortimer;
UINT16 kssmonitorexpiring;
UINT16 ksmaxsmonitortime;
INT16 ksgrowshrinktimer;
UINT16 ksflametimer;
// This needs to be first, to permit it to wipe extra information
jointime = players[player].jointime;
if (jointime <= 1)
@ -3094,6 +3109,16 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
prevcheck = 0;
nextcheck = 0;
// keepstuff
ksflags = 0;
ksrocketsneakertimer = 0;
ksinvincibilitytimer = 0;
kssmonitortimer = 0;
kssmonitorexpiring = 0;
ksmaxsmonitortime = 0;
ksgrowshrinktimer = 0;
ksflametimer = 0;
for (i = 0; i < LAP__MAX; i++)
{
laptime[i] = 0;
@ -3159,6 +3184,27 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
else
growshrinktimer = 0;
// keepstuff
ksflags = 0;
ksrocketsneakertimer = players[player].rocketsneakertimer;
ksinvincibilitytimer = players[player].invincibilitytimer;
kssmonitortimer = players[player].smonitortimer;
kssmonitorexpiring = players[player].smonitorexpiring;
ksmaxsmonitortime = players[player].maxsmonitortime;
ksgrowshrinktimer = players[player].growshrinktimer;
ksflametimer = players[player].flametimer;
if (ksrocketsneakertimer)
ksflags |= KEEPSTUFF_ROCKET;
if (ksinvincibilitytimer)
ksflags |= KEEPSTUFF_INVIN;
if (kssmonitortimer || kssmonitorexpiring || ksmaxsmonitortime)
ksflags |= KEEPSTUFF_SMON;
if (ksgrowshrinktimer)
ksflags |= KEEPSTUFF_GROWSHRINK;
if (ksflametimer)
ksflags |= KEEPSTUFF_FLAME;
// deplete your item stack if you died with zero bubble health
bubblehealth = players[player].bubblehealth;
if (bubblehealth == 0 && itemtype == KITEM_BUBBLESHIELD && itemamount > 0)
@ -3320,6 +3366,16 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
p->kickstartaccel = kickstartaccel;
p->jitterlegacy = jitterlegacy;
// keepstuff
p->keepstuff.flags = ksflags;
p->keepstuff.rocketsneakertimer = ksrocketsneakertimer;
p->keepstuff.invincibilitytimer = ksinvincibilitytimer;
p->keepstuff.smonitortimer = kssmonitortimer;
p->keepstuff.smonitorexpiring = kssmonitorexpiring;
p->keepstuff.maxsmonitortime = ksmaxsmonitortime;
p->keepstuff.growshrinktimer = ksgrowshrinktimer;
p->keepstuff.flametimer = ksflametimer;
p->ringvolume = 255;
p->ringtransparency = 255;
p->spinoutrot = 0;

View file

@ -2683,7 +2683,7 @@ void K_SetScoreboardModStatus(const char *name, SINT8 active)
CONS_Alert(CONS_WARNING, "Server mod '%s' does not exist so status cannot be changed.\n", name);
}
#define BASEMODS 19
#define BASEMODS 20
static void K_DrawServerMods(INT32 x, INT32 y)
{
UINT8 i, j;
@ -2710,7 +2710,8 @@ static void K_DrawServerMods(INT32 x, INT32 y)
{"Bump Spark", 0, &cv_kartbumpspark, -1, true},
{"Bump Drift", 0, NULL, K_GetBumpSpark() > 0, true},
{"Bump Spark", 0, NULL, K_GetBumpSpark() > BUMPSPARK_NOCHARGE, true},
{"Bump Spring", 0, &cv_kartbumpspring, -1, true}
{"Bump Spring", 0, &cv_kartbumpspring, -1, true},
{"Keep Stuff", 0, NULL, K_KeepStuffActive() > 0, true},
//TODO: separate drawer that enumerates item changes?
};

View file

@ -1627,7 +1627,7 @@ INT32 KO_SPBRaceOdds(INT32 odds, const kartroulette_t *roulette, const kartresul
#define NEIGHBOR_IFRAMES (TICRATE / 2)
#define BASE_IFRAMES (2 * TICRATE)
static void K_DoGrowShrink(player_t *player, boolean shrinking)
void K_DoGrowShrink(player_t *player, boolean shrinking)
{
player->mo->scalespeed = mapobjectscale/TICRATE;
player->mo->destscale = FixedMul(mapobjectscale, (shrinking) ? SHRINK_SCALE : GROW_SCALE);
@ -3014,4 +3014,4 @@ mobj_t *K_SpawnEquippedItem(player_t *player, kartitemequip_e equipstyle, mobjty
P_SetTarget(&prev->hnext, mo);
}
return mo;
}
}

View file

@ -249,6 +249,8 @@ extern consvar_t cv_kartthunder_radius;
#define ATTRACTIONATTACKTIME_MAX (3*TICRATE/4)
#define ATTRACTIONATTACKTIME_MIN (TICRATE/2)
void K_DoGrowShrink(player_t *player, boolean shrinking);
#ifdef __cplusplus
} // extern "C"
#endif

View file

@ -488,6 +488,8 @@ void K_RegisterKartStuff(void)
CV_RegisterVar(&cv_karteggmine_slotbrick);
CV_RegisterVar(&cv_kartthunder_radius);
CV_RegisterVar(&cv_kartkeepstuff);
}
//}
@ -1727,6 +1729,80 @@ static SINT8 K_GlanceAtPlayers(player_t *glancePlayer)
return lastValidGlance;
}
static void K_UpdateKeepstuff(player_t *player)
{
if (!K_KeepStuffActive())
{
// Keep Stuff isn't on
return;
}
UINT16 flags = player->keepstuff.flags;
if (flags & KEEPSTUFF_ROCKET)
{
if (!player->rocketsneakertimer)
{
INT32 moloop;
mobj_t *mo = NULL;
mobj_t *prev = player->mo;
K_SetItemOut(player, KITEM_ROCKETSNEAKER, 0);
K_UpdateHnextList(player, true);
for (moloop = 0; moloop < 2; moloop++)
{
mo = K_SpawnEquippedItem(player, KITEMEQUIP_ROCKETS, MT_ROCKETSNEAKER, moloop, prev);
prev = mo;
}
}
player->rocketsneakertimer = player->keepstuff.rocketsneakertimer;
}
if (flags & KEEPSTUFF_INVIN)
{
if (!player->invincibilitytimer)
{
K_DoInvincibility(player, INVINTIME);
}
player->invincibilitytimer = player->keepstuff.invincibilitytimer;
}
if (flags & KEEPSTUFF_SMON)
{
if (!player->smonitortimer)
{
K_DoSMonitor(player, SMONITORTIME);
}
player->smonitortimer = player->keepstuff.smonitortimer;
player->smonitorexpiring = player->keepstuff.smonitorexpiring;
player->maxsmonitortime = player->keepstuff.maxsmonitortime;
}
if (flags & KEEPSTUFF_GROWSHRINK)
{
if (!player->growshrinktimer)
{
K_DoGrowShrink(player, player->keepstuff.growshrinktimer < 0);
}
player->growshrinktimer = player->keepstuff.growshrinktimer;
}
if (flags & KEEPSTUFF_FLAME)
{
if (!player->flametimer)
{
K_SpawnEquippedItem(player, KITEMEQUIP_SHIELD, MT_FLAMESHIELD, 0, NULL);
}
player->flametimer = player->keepstuff.flametimer;
}
}
/** \brief Calculates the respawn timer and drop-boosting
\param player player object passed from K_KartPlayerThink
@ -1741,6 +1817,8 @@ static void K_RespawnChecker(player_t *player)
if (player->respawn > 1)
{
K_UpdateKeepstuff(player);
player->respawn--;
player->mo->momz = 0;
player->flashing = 2;
@ -1780,6 +1858,8 @@ static void K_RespawnChecker(player_t *player)
}
else if (player->respawn == 1)
{
K_UpdateKeepstuff(player);
if (player->growshrinktimer < 0)
{
player->mo->scalespeed = mapobjectscale/TICRATE;
@ -5725,8 +5805,6 @@ void K_DropRocketSneaker(player_t *player)
leftshoe = false;
}
P_SetTarget(&player->mo->hnext, NULL);
player->rocketsneakertimer = 0;
player->equippeditem = KITEM_NONE;
}
void K_DropKitchenSink(player_t *player)
@ -10784,6 +10862,7 @@ void K_StripItems(player_t *player)
player->hyudorotimer = 0;
player->stealingtimer = 0;
player->stolentimer = 0;
player->rocketsneakertimer = 0;
if (!P_MobjWasRemoved(player->shieldtracer))
P_RemoveMobj(player->shieldtracer);
@ -11770,6 +11849,18 @@ boolean K_RecoveryDashActive(void)
return false;
}
boolean K_KeepStuffActive(void)
{
if (keepstuffactive)
{
// Keep Stuff is enabled!
return true;
}
return false;
}
boolean K_WaterskipBricksActive(void)
{
if (waterskipbricks)

View file

@ -385,6 +385,7 @@ SINT8 K_AirDropActive(void);
boolean K_AirThrustActive(void);
boolean K_RecoveryDashActive(void);
boolean K_WaterskipBricksActive(void);
boolean K_KeepStuffActive(void);
boolean K_ItemLitterActive(void);
boolean K_ItemListActive(void);
boolean K_ItemPushingActive(void);

View file

@ -4552,6 +4552,27 @@ static int lib_kAirDropActive(lua_State *L)
return 1;
}
// Checks if Air Thrust is active.
static int lib_kAirThrustActive(lua_State *L)
{
lua_pushboolean(L, K_AirThrustActive());
return 1;
}
// Checks if Recovery Dash is active.
static int lib_kRecoveryDashActive(lua_State *L)
{
lua_pushboolean(L, K_RecoveryDashActive());
return 1;
}
// Checks if Keep Stuff is active.
static int lib_kKeepStuffActive(lua_State *L)
{
lua_pushboolean(L, K_KeepStuffActive());
return 1;
}
// Checks if item littering is active.
static int lib_kItemLitterActive(lua_State *L)
{
@ -5926,6 +5947,9 @@ static luaL_Reg lib[] = {
{"K_SlopeBoostActive",lib_kSlopeBoostActive},
{"K_DraftingActive",lib_kDraftingActive},
{"K_AirDropActive",lib_kAirDropActive},
{"K_AirThrustActive",lib_kAirThrustActive},
{"K_RecoveryDashActive",lib_kRecoveryDashActive},
{"K_KeepStuffActive",lib_kKeepStuffActive},
{"K_ItemLitterActive",lib_kItemLitterActive},
{"K_ItemListActive", lib_kItemListActive},
{"K_GetBumpSpark",lib_kGetBumpSpark},

View file

@ -13,6 +13,7 @@
#include "doomdef.h"
#include "dehacked.h"
#include "deh_lua.h"
#include "p_mobj.h"
#include "z_zone.h"
#include "w_wad.h"
#include "p_setup.h"
@ -419,6 +420,12 @@ int LUA_PushGlobals(lua_State *L, const char *word)
} else if (fastcmp(word,"purpledriftactive")) {
lua_pushinteger(L, purpledriftactive);
return 1;
} else if (fastcmp(word,"recoverydashactive")) {
lua_pushinteger(L, recoverydashactive);
return 1;
} else if (fastcmp(word,"keepstuffactive")) {
lua_pushinteger(L, keepstuffactive);
return 1;
} else if (fastcmp(word,"itemlittering")) {
lua_pushinteger(L, itemlittering);
return 1;
@ -581,10 +588,32 @@ int LUA_WriteGlobals(lua_State *L, const char *word)
itembreaker = (boolean)luaL_checkinteger(L, 2);
else if (fastcmp(word,"battleprisons"))
itembreaker = (boolean)luaL_checkinteger(L, 2);
else if (fastcmp(word,"chainingactive"))
else if (fastcmp(word,"ringsactive"))
ringsactive = (boolean)luaL_checkinteger(L, 2);
else if (fastcmp(word,"stackingactive"))
stackingactive = (boolean)luaL_checkinteger(L, 2);
else if (fastcmp(word,"chainingactive"))
chainingactive = (boolean)luaL_checkinteger(L, 2);
else if (fastcmp(word,"slipdashactive"))
slipdashactive = (boolean)luaL_checkinteger(L, 2);
else if (fastcmp(word,"slopeboostactive"))
slopeboostactive = (boolean)luaL_checkinteger(L, 2);
else if (fastcmp(word,"draftingactive"))
draftingactive = (boolean)luaL_checkinteger(L, 2);
else if (fastcmp(word,"airdropactive"))
airdropactive = luaL_checkinteger(L, 2);
else if (fastcmp(word,"bumpsparkactive"))
bumpsparkactive = luaL_checkinteger(L, 2);
else if (fastcmp(word,"purpledriftactive"))
purpledriftactive = (boolean)luaL_checkinteger(L, 2);
else if (fastcmp(word,"recoverydashactive"))
recoverydashactive = (boolean)luaL_checkinteger(L, 2);
else if (fastcmp(word,"itemlittering"))
itemlittering = (boolean)luaL_checkinteger(L, 2);
else if (fastcmp(word,"keepstuffactive"))
keepstuffactive = (boolean)luaL_checkinteger(L, 2);
else if (fastcmp(word,"itempushing"))
itempushing = (boolean)luaL_checkinteger(L, 2);
else if (fastcmp(word,"gamespeed"))
gamespeed = (UINT8)luaL_checkinteger(L, 2);
else if (fastcmp(word,"nummapboxes"))

View file

@ -1426,6 +1426,7 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget
{
K_DisableSeekingReticule(target->player);
K_DropRocketSneaker(target->player);
target->player->equippeditem = KITEM_NONE;
}
// Let EVERYONE know what happened to a player! 01-29-2002 Tails

View file

@ -9471,6 +9471,7 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
if (!mobj->extravalue2)
{
K_DropRocketSneaker(mobj->target->player);
mobj->target->player->equippeditem = KITEM_NONE;
}
else if (P_IsObjectOnGround(mobj))
{
@ -10207,7 +10208,6 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
S_StartSound(mobj->tracer, sfx_s3k77);
mobj->tracer->flags &= ~MF_NOGRAVITY;
P_KillMobj(mobj, mobj->tracer, mobj->tracer, DMG_NORMAL);
player->respawn = 1;
break;
}

View file

@ -628,6 +628,7 @@ extern boolean draftingactive;
extern UINT8 airdropactive;
extern boolean airthrustactive;
extern boolean recoverydashactive;
extern boolean keepstuffactive;
extern boolean waterskipbricks;
extern boolean itemlittering;
extern boolean itempushing;

View file

@ -865,6 +865,16 @@ static void P_NetSyncPlayers(savebuffer_t *save)
P_SyncMem(save, players[i].public_key, PUBKEYLENGTH);
SYNC(players[i].bumpyroadside);
// keepstuff_t
SYNC(players[i].keepstuff.flags);
SYNC(players[i].keepstuff.rocketsneakertimer);
SYNC(players[i].keepstuff.invincibilitytimer);
SYNC(players[i].keepstuff.smonitortimer);
SYNC(players[i].keepstuff.smonitorexpiring);
SYNC(players[i].keepstuff.maxsmonitortime);
SYNC(players[i].keepstuff.growshrinktimer);
SYNC(players[i].keepstuff.flametimer);
}
TracyCZoneEnd(__zone);
}
@ -4333,6 +4343,7 @@ static boolean P_NetSyncMisc(savebuffer_t *save, boolean resending)
SYNCBOOLEAN(draftingactive);
SYNCBOOLEAN(airthrustactive);
SYNCBOOLEAN(recoverydashactive);
SYNCBOOLEAN(keepstuffactive);
SYNCBOOLEAN(waterskipbricks);
SYNCBOOLEAN(itemlittering);
SYNCBOOLEAN(itempushing);

View file

@ -168,6 +168,7 @@ boolean draftingactive;
UINT8 airdropactive;
boolean airthrustactive;
boolean recoverydashactive;
boolean keepstuffactive;
boolean waterskipbricks;
boolean itemlittering;
boolean itempushing;
@ -8245,6 +8246,7 @@ static void P_InitLevelSettings(boolean reloadinggamestate)
airdropactive = 0;
airthrustactive = false;
recoverydashactive = false;
keepstuffactive = false;
waterskipbricks = false;
itemlittering = false;
itempushing = false;
@ -8281,6 +8283,9 @@ static void P_InitLevelSettings(boolean reloadinggamestate)
if (cv_kartrecoverydash.value)
recoverydashactive = true;
if (cv_kartkeepstuff.value)
keepstuffactive = true;
if (cv_kartwaterskiplock.value)
waterskipbricks = true;

View file

@ -48,6 +48,7 @@ TYPEDEF (player_t);
TYPEDEF (sonicloopcamvars_t);
TYPEDEF (sonicloopvars_t);
TYPEDEF (saltyhop_t);
TYPEDEF (keepstuff_t);
// d_clisrv.h
TYPEDEF (clientcmd_pak);