From ffa7850bb65540631abc4bffd2da437166ac7f13 Mon Sep 17 00:00:00 2001 From: NepDisk Date: Sat, 20 Sep 2025 00:17:05 -0400 Subject: [PATCH 1/9] AirDrop Starting Commit This introduces a new optional feature called Airdropping. When holding brake in the air you will start to fall faster. If you have rings active and have rings on you, you Ring Drop to fall even faster and with less delay. The ringboost output from this move is weaker then using rings normally making it so always using ring drop isn't the best play --- CMakeLists.txt | 1 + src/CMakeLists.txt | 4 ++ src/d_netcmd.c | 37 ++++++++++++++ src/d_netcmd.h | 2 + src/d_player.h | 5 +- src/deh_soc.c | 1 + src/doomdef.h | 2 +- src/g_demo.c | 2 + src/g_demo.h | 1 + src/g_game.c | 7 +-- src/k_hud.c | 3 +- src/k_kart.c | 120 +++++++++++++++++++++++++++++++++++++++++--- src/k_kart.h | 1 + src/lua_baselib.c | 8 +++ src/lua_playerlib.c | 16 ++++++ src/lua_script.c | 3 ++ src/m_menu.c | 14 ++++-- src/m_menu.h | 1 + src/p_enemy.c | 22 ++++++-- src/p_mobj.h | 2 + src/p_saveg.c | 19 +++++++ src/p_setup.c | 8 +++ 22 files changed, 259 insertions(+), 20 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 567ab0ee2..aac038881 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -86,6 +86,7 @@ option(SRB2_CONFIG_TRACY "Compile with Tracy profiling enabled" OFF) option(SRB2_CONFIG_ASAN "Compile with AddressSanitizer (libasan)." OFF) set(SRB2_CONFIG_ASSET_DIRECTORY "" CACHE PATH "Path to directory that contains all asset files for the installer. If set, assets will be part of installation and cpack.") option(SRB2_CONFIG_LTO "Enable link time optimizations, improves performance at the cost of longer link times." ON) +option(SRB2_CONFIG_TIDY "Enable clang tiny, checks compiled code for issues at the cost of longer compile times." OFF) if(SRB2_CONFIG_ENABLE_TESTS) # https://github.com/catchorg/Catch2 diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 07fc40d33..03cc0cb96 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -64,6 +64,10 @@ if(SRB2_CONFIG_ASAN) target_link_options(SRB2SDL2 PRIVATE -fsanitize=address) endif() +if(SRB2_CONFIG_TIDY) + set(CMAKE_CXX_CLANG_TIDY "clang-tidy;-checks=*") +endif() + add_subdirectory(blua) add_subdirectory(blan) add_subdirectory(sdl) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 99618fa4a..f55104ec7 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -160,6 +160,7 @@ static void KartChaining_OnChange(void); static void KartSlipdash_OnChange(void); static void KartSlopeBoost_OnChange(void); static void KartDrafting_OnChange(void); +static void KartAirDrop_OnChange(void); static void KartItemBreaker_OnChange(void); static void KartInvinType_OnChange(void); @@ -546,6 +547,8 @@ consvar_t cv_kartdrafting_closedraft = CVAR_INIT ("kartdrafting_closedraft", "Of consvar_t cv_kartdrafting_closedeadzone = CVAR_INIT ("kartdrafting_closedeadzone", "640", CV_NETVAR|CV_CHEAT, CV_Unsigned, NULL); consvar_t cv_kartdrafting_basedistance = CVAR_INIT ("kartdrafting_basedistance", "2560", CV_NETVAR|CV_CHEAT, CV_Unsigned, NULL); +consvar_t cv_kartairdrop = CVAR_INIT ("kartairdrop", "No", CV_NETVAR|CV_CALL|CV_NOINIT, CV_YesNo, KartAirDrop_OnChange); + // Invincibility modifiers static CV_PossibleValue_t invintype_cons_t[] = {{0, "Legacy"}, {1, "Alternative"}, {0, NULL}}; consvar_t cv_kartinvintype = CVAR_INIT ("kartinvintype", "Legacy", CV_NETVAR|CV_CALL, invintype_cons_t, KartInvinType_OnChange); @@ -7593,6 +7596,40 @@ static void KartDrafting_OnChange(void) } } + +static void KartAirDrop_OnChange(void) +{ + if (K_CanChangeRules() == false) + { + return; + } + + if (!K_AirDropActive() && cv_kartairdrop.value) + { + if (leveltime < starttime) + { + airdropactive = true; + CONS_Printf(M_GetText("Air Drop has been turned \"On\".\n")); + } + else + { + CONS_Printf(M_GetText("Air Drop will be turned \"On\" Next Round.\n")); + } + } + else if (K_AirDropActive() && !cv_kartairdrop.value) + { + if (leveltime < starttime) + { + airdropactive = false; + CONS_Printf(M_GetText("Drafting has been turned \"Off\".\n")); + } + else + { + CONS_Printf(M_GetText("Drafting 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 a0d2ea124..4fb975046 100644 --- a/src/d_netcmd.h +++ b/src/d_netcmd.h @@ -198,6 +198,8 @@ extern consvar_t cv_kartinvindistmul; extern consvar_t cv_kartinvin_maxtime; extern consvar_t cv_kartinvin_midtime; +extern consvar_t cv_kartairdrop; + extern consvar_t cv_encorevotes; extern consvar_t cv_votetime; diff --git a/src/d_player.h b/src/d_player.h index 04436637b..2b0a103c7 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -683,12 +683,15 @@ struct player_t SINT8 ringmax; // maximum rings UINT8 pickuprings; // Number of rings being picked up before added to the counter (prevents rings from being deleted forever over 20) UINT8 ringdelay; // (0 to 3) - 3 tic delay between every ring usage + UINT8 ringlock; // Timer for automatic handeling of ringlock UINT16 ringboost; // Ring boost timer UINT16 ringtime; // The current Ring boost timer if it wasn't capped. Used for spam prevention measures. UINT16 superring; // Spawn rings on top of you every tic! UINT8 nextringaward; // When should we spawn our next superring ring? UINT8 ringvolume; // When consuming lots of rings, lower the sound a little. - UINT8 ringtransparency; // When consuming lots of rings, fade out the rings again. + UINT8 ringtransparency; // When consuming lots of rings, fade out the rings again. + + UINT8 airdroptime; // Delay before airdrop kicks in. UINT8 curshield; // see kartshields_t UINT8 bubblecool; // Bubble Shield use cooldown diff --git a/src/deh_soc.c b/src/deh_soc.c index e75221663..0e0101559 100644 --- a/src/deh_soc.c +++ b/src/deh_soc.c @@ -1859,6 +1859,7 @@ static struct { const char *name; consvar_t *var; } HIDDENVARS[] = { { "DUMMYATTACKINGSLIPDASH", &cv_dummyattackingslipdash }, { "DUMMYATTACKINGPURPLEDRIFT", &cv_dummyattackingpurpledrift }, { "DUMMYATTACKINGSLOPEBOOST", &cv_dummyattackingslopeboost }, + { "DUMMYATTACKINGAIRDROP", &cv_dummyattackingairdrop }, { "DUMMYSTAFF", &cv_dummystaff }, { "DUMMYMULTIPLAYER", &cv_dummymultiplayer }, { "DUMMYIP", &cv_dummyip }, diff --git a/src/doomdef.h b/src/doomdef.h index f1e9a57fd..8355f8528 100644 --- a/src/doomdef.h +++ b/src/doomdef.h @@ -103,7 +103,7 @@ extern "C" { // Special Hashing. //#define NOFILEHASH -//#define NOVERIFYIWADS +#define NOVERIFYIWADS // Uncheck this to compile debugging code //#define RANGECHECK diff --git a/src/g_demo.c b/src/g_demo.c index ba55c2863..9e4ddb426 100644 --- a/src/g_demo.c +++ b/src/g_demo.c @@ -2740,6 +2740,8 @@ void G_BeginRecording(void) raflags |= RAF_PURPLEDRIFT; if (cv_dummyattackingslopeboost.value) raflags |= RAF_SLOPEBOOST; + if (cv_dummyattackingairdrop.value) + raflags |= RAF_AIRDROP; } else { diff --git a/src/g_demo.h b/src/g_demo.h index 9271d2240..818974bed 100644 --- a/src/g_demo.h +++ b/src/g_demo.h @@ -41,6 +41,7 @@ typedef enum RAF_SLIPDASH = 1<<3, RAF_PURPLEDRIFT = 1<<4, RAF_SLOPEBOOST = 1<<5, + RAF_AIRDROP = 1<<6, // up to 1<<31 is free } raflags_t; diff --git a/src/g_game.c b/src/g_game.c index 56a9c2f1c..3b5d026f1 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -483,14 +483,15 @@ SINT8 G_RecordPresetIndex(void) boolean slipdash = cv_dummyattackingslipdash.value; boolean purpledrift = cv_dummyattackingpurpledrift.value; boolean slopeboost = cv_dummyattackingslopeboost.value; + boolean airdrop = cv_dummyattackingairdrop.value; - if (!rings && !stacking && !chaining && !slipdash && !purpledrift && !slopeboost) + if (!rings && !stacking && !chaining && !slipdash && !purpledrift && !slopeboost && !airdrop) return RP_KART; - if (stacking && chaining && slopeboost && !rings && !slipdash && !purpledrift) + if (stacking && chaining && slopeboost && airdrop && !rings && !slipdash && !purpledrift) return RP_TECH; - if (rings && stacking && chaining && slipdash && purpledrift && slopeboost) + if (rings && stacking && chaining && slipdash && purpledrift && slopeboost && airdrop) return RP_BLAN; return RP_CUST; diff --git a/src/k_hud.c b/src/k_hud.c index a31b2238a..0a35d58fa 100644 --- a/src/k_hud.c +++ b/src/k_hud.c @@ -2363,7 +2363,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 11 +#define BASEMODS 12 static void K_DrawServerMods(INT32 x, INT32 y) { UINT8 i, j; @@ -2380,6 +2380,7 @@ static void K_DrawServerMods(INT32 x, INT32 y) {"Chain Offroad", 0, &cv_kartchainingoffroad, -1, true}, {"Slope Boost", 0, NULL, K_PurpleDriftActive() > 0, true}, {"Drafting", 0, NULL, K_DraftingActive() > 0, true}, + {"Air Drop", 0, NULL, K_AirDropActive() > 0, true}, {"Bump Spark", 0, &cv_kartbumpspark, -1, true}, {"Bump Spring", 0, &cv_kartbumpspring, -1, true}, {"Alt. Invin.", 0, NULL, K_GetKartInvinType() == KARTINVIN_ALTERN, true} diff --git a/src/k_kart.c b/src/k_kart.c index 7a9697293..46b4b8296 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -6592,11 +6592,7 @@ static void K_HandleRingDeincrement(player_t *player, boolean chainnerf) 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->chaintimer = max(player->ringboost, player->chaintimer); } player->ringboost = max(0, player->ringboost - finalringtimer); @@ -6633,6 +6629,93 @@ void K_AwardScaledPlayerRings(player_t *player, SINT8 mode) K_AwardPlayerRings(player, awardamount, (mode == ASR_SUPERRING) ? true : false); } +void K_SpawnFallLines(player_t *player, boolean ringdrop) +{ + fixed_t rand_x; + fixed_t rand_y; + fixed_t rand_z; + + rand_z = player->mo->z + player->mo->height + (16 * player->mo->scale) + (P_RandomRange(-15,15) * player->mo->scale); + rand_y = player->mo->y + (P_RandomRange(-25,25) * player->mo->scale); + rand_x = player->mo->x + (P_RandomRange(-25,25) * player->mo->scale); + + mobj_t *fast = P_SpawnMobj(rand_x, rand_y, rand_z, MT_FASTLINE); + + P_SetTarget(&fast->target, player->mo); + fast->momx = 3*player->mo->momx/4; + fast->momy = 3*player->mo->momy/4; + fast->momz = 3*P_GetMobjZMovement(player->mo)/4; + + P_SetScale(fast, fast->scale/4); + fast->angle = player->mo->angle+ANGLE_90; + fast->rollangle = ANGLE_90; + + fast->colorized = true; + + if (ringdrop) + { + fast->color = SKINCOLOR_CROCODILE; + fast->renderflags |= RF_TRANS10; + } + else + fast->color = SKINCOLOR_IVORY; + + fast->renderflags |= RF_ADD; + + K_MatchGenericExtraFlags(fast, player->mo); +} + +void K_AirDrop(player_t *player, ticcmd_t *cmd) +{ + if (player->cmd.buttons & BT_BRAKE + && !P_IsObjectOnGround(player->mo) + && !player->loop.radius + && !(player->mo->tracer && player->mo->tracer->type == MT_TUBEWAYPOINT) + && !player->respawn) + { + SINT8 airbrakedelay = (player->rings > 0) ? TICRATE/4 : TICRATE/3; + if (player->airdroptime < airbrakedelay) + { + if (player->rings > 0) + { + player->ringlock = 6; + } + } + else + { + if (!player->ringdelay && player->rings > 0) + { + mobj_t *ring = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_RING); + P_SetMobjState(ring, S_FASTRING1); + + ring->renderflags |= RF_ADD; + ring->renderflags |= RF_TRANS60; + ring->colorized = true; + ring->color = SKINCOLOR_SILVER; + + ring->extravalue1 = 18; // Ring use animation timer + ring->extravalue2 = 1; // Ring use animation flag + ring->extravalue3 = 1; // Ring airdrop use flag + ring->shadowscale = 0; + P_SetTarget(&ring->target, player->mo); // user + player->rings--; + player->ringdelay = 5; + player->ringlock = 6; + } + + K_SpawnFallLines(player, player->rings > 0); + player->mo->momz -= FixedMul(gravity, mapobjectscale)*P_MobjFlip(player->mo); + } + + if (player->airdroptime < UINT8_MAX) + player->airdroptime++; + } + else + { + player->airdroptime = 0; + } +} + /** \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 @@ -6859,6 +6942,19 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) K_HandleRingDeincrement(player, chainingactive); } + K_AirDrop(player, cmd); + + if (player->ringlock) + { + player->chaintimer = max(player->chaintimer, player->ringboost); + player->ringlock--; + + if (!player->ringlock) + player->pflags &= ~PF_RINGLOCK; + else + player->pflags |= PF_RINGLOCK; + } + if (!player->ringboost && !player->chaintimer) player->ringtime = 0; @@ -9832,7 +9928,8 @@ void K_MoveKartPlayer(player_t *player, boolean onground) || ((K_GetKartInvinType() == KARTINVIN_ALTERN) && player->invincibilitytimer) || (player->growshrinktimer > 0) || player->flametimer - || (leveltime < starttime))) + || (leveltime < starttime) + || (player->pflags & PF_RINGLOCK))) player->itemflags |= IF_USERINGS; else player->itemflags &= ~IF_USERINGS; @@ -10956,6 +11053,17 @@ boolean K_DraftingActive(void) return false; } +boolean K_AirDropActive(void) +{ + if (airdropactive) + { + // Air Drop is enabled! + return true; + } + + return false; +} + boolean K_GetKartInvinType(void) { return invintype; diff --git a/src/k_kart.h b/src/k_kart.h index c96fada84..b7db43748 100644 --- a/src/k_kart.h +++ b/src/k_kart.h @@ -322,6 +322,7 @@ boolean K_ChainingActive(void); boolean K_SlipdashActive(void); boolean K_SlopeBoostActive(void); boolean K_DraftingActive(void); +boolean K_AirDropActive(void); boolean K_GetKartInvinType(void); boolean K_BoostChain(player_t *player, INT32 timer, boolean chainsound); INT32 K_ChainOrDeincrementTime(player_t *player, INT32 timer, INT32 deincrement, boolean chainsound); diff --git a/src/lua_baselib.c b/src/lua_baselib.c index 8d9b23125..c98d3582f 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -4167,6 +4167,13 @@ static int lib_kDraftingActive(lua_State *L) return 1; } +// Checks if Air Drop is active. +static int lib_kAirDropActive(lua_State *L) +{ + lua_pushboolean(L, K_AirDropActive()); + return 1; +} + // Grabs the currently active invintype. static int lib_kGetKartInvinType(lua_State *L) { @@ -5263,6 +5270,7 @@ static luaL_Reg lib[] = { {"K_SlipdashActive",lib_kSlipdashActive}, {"K_SlopeBoostActive",lib_kSlopeBoostActive}, {"K_DraftingActive",lib_kDraftingActive}, + {"K_AirDropActive",lib_kAirDropActive}, {"K_GetKartInvinType",lib_kGetKartInvinType}, {"K_UsingLegacyCheckpoints",lib_kUsingLegacyCheckpoints}, {"K_DoBoost",lib_kDoBoost}, diff --git a/src/lua_playerlib.c b/src/lua_playerlib.c index ee90e99b0..54f15264b 100644 --- a/src/lua_playerlib.c +++ b/src/lua_playerlib.c @@ -256,12 +256,14 @@ enum player_e player_ringmax, player_pickuprings, player_ringdelay, + player_ringlock, player_ringboost, player_ringtime, player_superring, player_nextringaward, player_ringvolume, player_ringtransparency, + player_airdroptime, player_curshield, player_bubblecool, player_bubbleblowup, @@ -453,12 +455,14 @@ static const char *const player_opt[] = { "ringmax", "pickuprings", "ringdelay", + "ringlock", "ringboost", "ringtime", "superring", "nextringaward", "ringvolume", "ringtransparency", + "airdroptime", "curshield", "bubblecool", "bubbleblowup", @@ -854,6 +858,9 @@ static int player_get(lua_State *L) case player_ringdelay: lua_pushinteger(L, plr->ringdelay); break; + case player_ringlock: + lua_pushinteger(L, plr->ringlock); + break; case player_ringboost: lua_pushinteger(L, plr->ringboost); break; @@ -872,6 +879,9 @@ static int player_get(lua_State *L) case player_ringtransparency: lua_pushinteger(L, plr->ringtransparency); break; + case player_airdroptime: + lua_pushinteger(L, plr->airdroptime); + break; case player_curshield: lua_pushinteger(L, plr->curshield); break; @@ -1534,6 +1544,9 @@ static int player_set(lua_State *L) case player_ringdelay: plr->ringdelay = luaL_checkinteger(L, 3); break; + case player_ringlock: + plr->ringlock = luaL_checkinteger(L, 3); + break; case player_ringboost: plr->ringboost = luaL_checkinteger(L, 3); break; @@ -1552,6 +1565,9 @@ static int player_set(lua_State *L) case player_ringtransparency: plr->ringtransparency = luaL_checkinteger(L, 3); break; + case player_airdroptime: + plr->airdroptime = luaL_checkinteger(L, 3); + break; case player_curshield: plr->curshield = luaL_checkinteger(L, 3); break; diff --git a/src/lua_script.c b/src/lua_script.c index f646db2ac..6a2fb7f13 100644 --- a/src/lua_script.c +++ b/src/lua_script.c @@ -397,6 +397,9 @@ int LUA_PushGlobals(lua_State *L, const char *word) } else if (fastcmp(word,"draftingactive")) { lua_pushinteger(L, draftingactive); return 1; + } else if (fastcmp(word,"airdropactive")) { + lua_pushinteger(L, airdropactive); + return 1; } else if (fastcmp(word,"purpledriftactive")) { lua_pushinteger(L, purpledriftactive); return 1; diff --git a/src/m_menu.c b/src/m_menu.c index 17558333c..10730ac67 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -455,6 +455,8 @@ consvar_t cv_dummyattackingchaining = CVAR_INIT ("dummyattackingchaining", "Off" consvar_t cv_dummyattackingslipdash = CVAR_INIT ("dummyattackingslipdash", "Off", CV_HIDEN|CV_CALL|CV_NOINIT, CV_OnOff, Nextmap_OnChange); consvar_t cv_dummyattackingpurpledrift = CVAR_INIT ("dummyattackingpurpledrift", "Off", CV_HIDEN|CV_CALL|CV_NOINIT, CV_OnOff, Nextmap_OnChange); consvar_t cv_dummyattackingslopeboost = CVAR_INIT ("dummyattackingslopeboost", "Off", CV_HIDEN|CV_CALL|CV_NOINIT, CV_OnOff, Nextmap_OnChange); +consvar_t cv_dummyattackingairdrop = CVAR_INIT ("dummyattackingairdrop", "Off", CV_HIDEN|CV_CALL|CV_NOINIT, CV_OnOff, Nextmap_OnChange); + static CV_PossibleValue_t dummygpdifficulty_cons_t[] = {{KARTSPEED_EASY, "Easy"}, {KARTSPEED_NORMAL, "Normal"}, {KARTSPEED_HARD, "Hard"}, {KARTSPEED_EXPERT, "Expert"}, {KARTGP_MASTER, "Master"}, {KARTGP_NIGHTMARE, "Nightmare"}, {0, NULL}}; static CV_PossibleValue_t dummygpcup_cons_t[50] = {{1, "TEMP"}}; // A REALLY BIG NUMBER, SINCE THIS IS TEMP UNTIL NEW MENUS @@ -649,6 +651,7 @@ char *M_AppendGametypeAndModName(void) ADD(cv_dummyattackingslipdash, "SD-") ADD(cv_dummyattackingpurpledrift, "PD-") ADD(cv_dummyattackingslopeboost, "SB-") + ADD(cv_dummyattackingairdrop, "AD-") new_str[len-1] = '\0'; @@ -2159,6 +2162,7 @@ void M_Init(void) CV_RegisterVar(&cv_dummyattackingslipdash); CV_RegisterVar(&cv_dummyattackingpurpledrift); CV_RegisterVar(&cv_dummyattackingslopeboost); + CV_RegisterVar(&cv_dummyattackingairdrop); CV_RegisterVar(&cv_dummygpdifficulty); CV_RegisterVar(&cv_dummygpencore); @@ -5851,11 +5855,11 @@ INT32 MR_ReplayStaff(INT32 choice) } #define NUMPRESETS 3 -static boolean presets[NUMPRESETS][6] = { - //rings stacking chaining slipdash purpledrift slopeboost - { false, false, false, false, false, false}, // SRB2Kart - { false, true, true, false, false, true}, // Tech - { true, true, true, true, true, true}, // BlanKart +static boolean presets[NUMPRESETS][7] = { + //rings stacking chaining slipdash purpledrift slopeboost airdrop + { false, false, false, false, false, false, false }, // SRB2Kart + { false, true, true, false, false, true, true }, // Tech + { true, true, true, true, true, true, true }, // BlanKart }; INT32 MR_TimeAttackPreset(INT32 arg) diff --git a/src/m_menu.h b/src/m_menu.h index 82fc059fe..103a8609c 100644 --- a/src/m_menu.h +++ b/src/m_menu.h @@ -422,6 +422,7 @@ extern consvar_t cv_dummygpdifficulty, cv_dummygpencore, cv_dummygpcup; extern consvar_t cv_dummymenuplayer, cv_dummyteam, cv_dummyspectate, cv_dummyscramble; extern consvar_t cv_dummyattackingrings, cv_dummyattackingstacking, cv_dummyattackingchaining; extern consvar_t cv_dummyattackingslipdash, cv_dummyattackingpurpledrift, cv_dummyattackingslopeboost; +extern consvar_t cv_dummyattackingairdrop; extern consvar_t cv_dummystaff; extern consvar_t cv_dummymultiplayer, cv_dummyip, cv_dummyname, cv_dummyfollower, cv_dummycolor; extern consvar_t cv_dummyserverpage; diff --git a/src/p_enemy.c b/src/p_enemy.c index 82566adf1..ca08878c4 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -3170,11 +3170,26 @@ void A_AttractChase(mobj_t *actor) if (actor->extravalue1 >= 21) { - // Base add is 4 tics for 9,9, adds 1 tic for each point closer to the 1,1 end - actor->target->player->ringboost += K_GetKartRingPower(actor->target->player, true); - actor->target->player->ringtime += K_GetKartRingPower(actor->target->player, true); + if (actor->extravalue3 && !P_IsObjectOnGround(actor->target)) + { + actor->target->momz -= (FixedMul(gravity, mapobjectscale))*P_MobjFlip(actor->target); + actor->target->player->ringboost += 5; + actor->target->player->ringtime += 5; + } + else + { + // Base add is 4 tics for 9,9, adds 1 tic for each point closer to the 1,1 end + actor->target->player->ringboost += K_GetKartRingPower(actor->target->player, true); + actor->target->player->ringtime += K_GetKartRingPower(actor->target->player, true); + } + S_StartSoundAtVolume(actor->target, sfx_s1b5, actor->target->player->ringvolume); + if (actor->extravalue3 && !P_IsObjectOnGround(actor->target)) + { + actor->target->momz -= (FixedMul(gravity, mapobjectscale)/2)*P_MobjFlip(actor->target); + } + if (actor->target->player->rings <= 10) { S_StartSoundAtVolume(actor->target, sfx_ringlw, 255 - actor->target->player->rings*10); @@ -3199,6 +3214,7 @@ void A_AttractChase(mobj_t *actor) ( actor->target->height + offz )* P_MobjFlip(actor)); actor->extravalue1++; } + } else // Collecting { diff --git a/src/p_mobj.h b/src/p_mobj.h index 81f51cb21..d45c54e0e 100644 --- a/src/p_mobj.h +++ b/src/p_mobj.h @@ -407,6 +407,7 @@ struct mobj_t // Extra values are for internal use for whatever you want INT32 extravalue1; INT32 extravalue2; + INT32 extravalue3; // Custom values are not to be altered by us! // They are for SOCs to store things in. @@ -606,6 +607,7 @@ extern boolean slipdashactive; extern boolean purpledriftactive; extern boolean slopeboostactive; extern boolean draftingactive; +extern boolean airdropactive; extern UINT16 bossdisabled; extern boolean stoppedclock; diff --git a/src/p_saveg.c b/src/p_saveg.c index 5e211359b..82811fae4 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -327,6 +327,7 @@ static void P_NetArchivePlayers(savebuffer_t *save) WRITESINT8(save->p, players[i].ringmax); WRITEUINT8(save->p, players[i].pickuprings); WRITEUINT8(save->p, players[i].ringdelay); + WRITEUINT8(save->p, players[i].ringlock); WRITEUINT16(save->p, players[i].ringboost); WRITEUINT16(save->p, players[i].ringtime); WRITEUINT16(save->p, players[i].superring); @@ -334,6 +335,8 @@ static void P_NetArchivePlayers(savebuffer_t *save) WRITEUINT8(save->p, players[i].ringvolume); WRITEUINT8(save->p, players[i].ringtransparency); + WRITEUINT8(save->p, players[i].airdroptime); + WRITEUINT8(save->p, players[i].curshield); WRITEUINT8(save->p, players[i].bubblecool); WRITEUINT8(save->p, players[i].bubbleblowup); @@ -680,6 +683,7 @@ static void P_NetUnArchivePlayers(savebuffer_t *save) players[i].ringmax = READSINT8(save->p); players[i].pickuprings = READUINT8(save->p); players[i].ringdelay = READUINT8(save->p); + players[i].ringlock = READUINT8(save->p); players[i].ringboost = READUINT16(save->p); players[i].ringtime = READUINT16(save->p);; players[i].superring = READUINT16(save->p); @@ -687,6 +691,8 @@ static void P_NetUnArchivePlayers(savebuffer_t *save) players[i].ringvolume = READUINT8(save->p); players[i].ringtransparency = READUINT8(save->p); + players[i].airdroptime = READUINT8(save->p); + players[i].curshield = READUINT8(save->p); players[i].bubblecool = READUINT8(save->p); players[i].bubbleblowup = READUINT8(save->p); @@ -2095,6 +2101,7 @@ typedef enum MD3_GRAVITY = 1, MD3_MISCCAP = 1<<1, MD3_BAKEDOFFSET = 1<<2, + MD3_EXTVAL3 = 1<<3, } mobj_diff3_t; typedef enum @@ -2410,6 +2417,8 @@ static void SaveMobjThinker(savebuffer_t *save, const thinker_t *th, const UINT8 if (mobj->bakexoff || mobj->bakeyoff || mobj->bakezoff || mobj->bakexpiv || mobj->bakeypiv || mobj->bakezpiv) diff3 |= MD3_BAKEDOFFSET; + if (mobj->extravalue3) + diff3 |= MD3_EXTVAL3; if (diff3 != 0) diff2 |= MD2_MORE; @@ -2696,6 +2705,10 @@ static void SaveMobjThinker(savebuffer_t *save, const thinker_t *th, const UINT8 WRITEFIXED(save->p, mobj->bakeypiv); WRITEFIXED(save->p, mobj->bakezpiv); } + if (diff3 & MD3_EXTVAL3) + { + WRITEINT32(save->p, mobj->extravalue3); + } WRITEUINT32(save->p, mobj->mobjnum); } @@ -3995,6 +4008,10 @@ static thinker_t* LoadMobjThinker(savebuffer_t *save, actionf_p1 thinker, UINT8 mobj->bakexoff = mobj->bakeyoff = mobj->bakezoff = 0; mobj->bakexpiv = mobj->bakeypiv = mobj->bakezpiv = 0; } + if (diff3 & MD3_EXTVAL3) + { + mobj->extravalue3 = READINT32(save->p); + } // Reset some non-synch values mobj->sloperoll = 0; @@ -5298,6 +5315,7 @@ static void P_NetArchiveMisc(savebuffer_t *save, boolean resending) WRITEUINT8(save->p, purpledriftactive); WRITEUINT8(save->p, slopeboostactive); WRITEUINT8(save->p, draftingactive); + WRITEUINT8(save->p, airdropactive); for (i = 0; i < 12; i++) { @@ -5685,6 +5703,7 @@ FUNCINLINE static ATTRINLINE boolean P_NetUnArchiveMisc(savebuffer_t *save, bool purpledriftactive = READUINT8(save->p); slopeboostactive = READUINT8(save->p); draftingactive = READUINT8(save->p); + airdropactive = READUINT8(save->p); for (i = 0; i < 12; i++) { diff --git a/src/p_setup.c b/src/p_setup.c index 427a7ab4c..b42fe89ea 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -154,6 +154,7 @@ boolean slipdashactive; boolean purpledriftactive; boolean slopeboostactive; boolean draftingactive; +boolean airdropactive; UINT16 bossdisabled; boolean stoppedclock; boolean levelloading; @@ -8034,6 +8035,7 @@ static void P_InitLevelSettings(boolean reloadinggamestate) purpledriftactive = false; slopeboostactive = false; draftingactive = false; + airdropactive = false; if (cv_kartrings.value) ringsactive = true; @@ -8056,6 +8058,9 @@ static void P_InitLevelSettings(boolean reloadinggamestate) if (cv_kartdrafting.value) draftingactive = true; + if (cv_kartairdrop.value) + airdropactive = false; + invintype = (UINT8)cv_kartinvintype.value; // emerald hunt @@ -8146,6 +8151,8 @@ static void P_InitLevelSettings(boolean reloadinggamestate) purpledriftactive = true; if (raflags & RAF_SLOPEBOOST) slopeboostactive = true; + if (raflags & RAF_AIRDROP) + airdropactive = true; } else { @@ -8155,6 +8162,7 @@ static void P_InitLevelSettings(boolean reloadinggamestate) chainingactive = cv_dummyattackingchaining.value; slipdashactive = cv_dummyattackingslipdash.value; slopeboostactive = cv_dummyattackingslopeboost.value; + airdropactive = cv_dummyattackingairdrop.value; } } else From 7de3cc3b25f85f626c867835ce318bc9b66abe60 Mon Sep 17 00:00:00 2001 From: NepDisk Date: Sat, 20 Sep 2025 00:42:47 -0400 Subject: [PATCH 2/9] Add toggle logic for Air Drop --- src/k_kart.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/k_kart.c b/src/k_kart.c index 46b4b8296..3673b54cc 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -6667,7 +6667,8 @@ void K_SpawnFallLines(player_t *player, boolean ringdrop) void K_AirDrop(player_t *player, ticcmd_t *cmd) { - if (player->cmd.buttons & BT_BRAKE + if ((player->cmd.buttons & BT_BRAKE) + && K_AirDropActive() && !P_IsObjectOnGround(player->mo) && !player->loop.radius && !(player->mo->tracer && player->mo->tracer->type == MT_TUBEWAYPOINT) From ca3d5337712722dcaada7a6676484cc44f9db2b7 Mon Sep 17 00:00:00 2001 From: NepDisk Date: Sat, 20 Sep 2025 00:57:21 -0400 Subject: [PATCH 3/9] Don't break the airdrop toggle, you BAKA! --- src/k_kart.c | 2 ++ src/p_setup.c | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/k_kart.c b/src/k_kart.c index 3673b54cc..5ef87f031 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -364,6 +364,8 @@ void K_RegisterKartStuff(void) CV_RegisterVar(&cv_kartchainingoffroad); CV_RegisterVar(&cv_kartchainingsound); + CV_RegisterVar(&cv_kartairdrop); + CV_RegisterVar(&cv_kartitembreaker); //CV_RegisterVar(&cv_kartwalltransfer); diff --git a/src/p_setup.c b/src/p_setup.c index b42fe89ea..7579b04d6 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -8059,7 +8059,7 @@ static void P_InitLevelSettings(boolean reloadinggamestate) draftingactive = true; if (cv_kartairdrop.value) - airdropactive = false; + airdropactive = true; invintype = (UINT8)cv_kartinvintype.value; From aba9e23a0d4b2cc519521e23cfa527997d24181a Mon Sep 17 00:00:00 2001 From: NepDisk Date: Sat, 20 Sep 2025 09:40:27 -0400 Subject: [PATCH 4/9] Readd bot airbrake logic for bot controllers --- src/deh_tables.c | 3 ++- src/k_bot.cpp | 15 +++++++++++++++ src/p_spec.h | 1 + 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/src/deh_tables.c b/src/deh_tables.c index 73d87d268..4d13434bc 100644 --- a/src/deh_tables.c +++ b/src/deh_tables.c @@ -1597,7 +1597,8 @@ struct int_const_s const INT_CONST[] = { {"TMBOT_NORUBBERBAND",TMBOT_NORUBBERBAND}, {"TMBOT_NOCONTROL",TMBOT_NOCONTROL}, {"TMBOT_FORCEDIR",TMBOT_FORCEDIR}, - //{"TMBOT_FASTFALL",TMBOT_FASTFALL}, + {"TMBOT_AIRDROP",TMBOT_AIRDROP}, + {"TMBOT_FASTFALL",TMBOT_AIRDROP}, // textmapbottrick_t /* diff --git a/src/k_bot.cpp b/src/k_bot.cpp index e0ca166a9..3fde63cf6 100644 --- a/src/k_bot.cpp +++ b/src/k_bot.cpp @@ -1611,6 +1611,21 @@ void K_BotTicker(const player_t *player) forcedDir = true; } + if (P_IsObjectOnGround(player->mo) == false) + { + if (player->airdroptime == 0 && !player->respawn) + { + if (botController != nullptr && (botController->flags & TMBOT_AIRDROP) == TMBOT_AIRDROP) + { + // Air Drop! + bd->brakedown = true; + return; + } + } + + //return; // Don't allow bots to turn in the air. + } + if (forcedDir == true) { destangle = R_PointToAngle2(player->mo->x, player->mo->y, bd->predict.x, bd->predict.y); diff --git a/src/p_spec.h b/src/p_spec.h index af15e96de..0386b3866 100644 --- a/src/p_spec.h +++ b/src/p_spec.h @@ -541,6 +541,7 @@ typedef enum TMBOT_NORUBBERBAND = 1, TMBOT_NOCONTROL = 1<<1, TMBOT_FORCEDIR = 1<<2, + TMBOT_AIRDROP = 1<<3, } textmapbotcontroller_t; typedef enum From de5a8594b98eb8d662ffdefcc384cab7e64259db Mon Sep 17 00:00:00 2001 From: NepDisk Date: Sat, 20 Sep 2025 09:43:32 -0400 Subject: [PATCH 5/9] Add more conditions here --- src/k_bot.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/k_bot.cpp b/src/k_bot.cpp index 3fde63cf6..2f26e012a 100644 --- a/src/k_bot.cpp +++ b/src/k_bot.cpp @@ -1613,7 +1613,11 @@ void K_BotTicker(const player_t *player) if (P_IsObjectOnGround(player->mo) == false) { - if (player->airdroptime == 0 && !player->respawn) + if (player->airdroptime == 0 + && K_AirDropActive() + && !player->loop.radius + && !(player->mo->tracer && player->mo->tracer->type == MT_TUBEWAYPOINT) + && !player->respawn) { if (botController != nullptr && (botController->flags & TMBOT_AIRDROP) == TMBOT_AIRDROP) { From 49c0b2c00ef0572905ba03bf4312ea1ca7476134 Mon Sep 17 00:00:00 2001 From: NepDisk Date: Sat, 20 Sep 2025 10:03:57 -0400 Subject: [PATCH 6/9] Make Airdrop drop lines only turn yellow when you have ringboost --- src/d_player.h | 3 ++- src/k_bot.cpp | 1 + src/k_kart.c | 11 ++++++++++- src/lua_playerlib.c | 8 ++++++++ src/p_enemy.c | 1 + src/p_saveg.c | 2 ++ 6 files changed, 24 insertions(+), 2 deletions(-) diff --git a/src/d_player.h b/src/d_player.h index 2b0a103c7..69bea329f 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -691,7 +691,8 @@ struct player_t UINT8 ringvolume; // When consuming lots of rings, lower the sound a little. UINT8 ringtransparency; // When consuming lots of rings, fade out the rings again. - UINT8 airdroptime; // Delay before airdrop kicks in. + UINT8 airdroptime; // Tracks how long airdrop has been active, used for delay before airdrop kicks in. + boolean ringdrop; // Set when having ringdrop applied. UINT8 curshield; // see kartshields_t UINT8 bubblecool; // Bubble Shield use cooldown diff --git a/src/k_bot.cpp b/src/k_bot.cpp index 2f26e012a..18f24bfcd 100644 --- a/src/k_bot.cpp +++ b/src/k_bot.cpp @@ -1615,6 +1615,7 @@ void K_BotTicker(const player_t *player) { if (player->airdroptime == 0 && K_AirDropActive() + && !P_PlayerInPain(player) && !player->loop.radius && !(player->mo->tracer && player->mo->tracer->type == MT_TUBEWAYPOINT) && !player->respawn) diff --git a/src/k_kart.c b/src/k_kart.c index 5ef87f031..2039a148f 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -6672,6 +6672,7 @@ void K_AirDrop(player_t *player, ticcmd_t *cmd) if ((player->cmd.buttons & BT_BRAKE) && K_AirDropActive() && !P_IsObjectOnGround(player->mo) + && !P_PlayerInPain(player) && !player->loop.radius && !(player->mo->tracer && player->mo->tracer->type == MT_TUBEWAYPOINT) && !player->respawn) @@ -6683,6 +6684,8 @@ void K_AirDrop(player_t *player, ticcmd_t *cmd) { player->ringlock = 6; } + + player->ringdrop = false; } else { @@ -6706,7 +6709,12 @@ void K_AirDrop(player_t *player, ticcmd_t *cmd) player->ringlock = 6; } - K_SpawnFallLines(player, player->rings > 0); + if (player->rings <= 0) + { + player->ringdrop = false; + } + + K_SpawnFallLines(player, player->ringdrop); player->mo->momz -= FixedMul(gravity, mapobjectscale)*P_MobjFlip(player->mo); } @@ -6716,6 +6724,7 @@ void K_AirDrop(player_t *player, ticcmd_t *cmd) else { player->airdroptime = 0; + player->ringdrop = false; } } diff --git a/src/lua_playerlib.c b/src/lua_playerlib.c index 54f15264b..ac764112a 100644 --- a/src/lua_playerlib.c +++ b/src/lua_playerlib.c @@ -264,6 +264,7 @@ enum player_e player_ringvolume, player_ringtransparency, player_airdroptime, + player_ringdrop, player_curshield, player_bubblecool, player_bubbleblowup, @@ -463,6 +464,7 @@ static const char *const player_opt[] = { "ringvolume", "ringtransparency", "airdroptime", + "ringdrop", "curshield", "bubblecool", "bubbleblowup", @@ -882,6 +884,9 @@ static int player_get(lua_State *L) case player_airdroptime: lua_pushinteger(L, plr->airdroptime); break; + case player_ringdrop: + lua_pushinteger(L, plr->ringdrop); + break; case player_curshield: lua_pushinteger(L, plr->curshield); break; @@ -1568,6 +1573,9 @@ static int player_set(lua_State *L) case player_airdroptime: plr->airdroptime = luaL_checkinteger(L, 3); break; + case player_ringdrop: + plr->ringdrop = luaL_checkinteger(L, 3); + break; case player_curshield: plr->curshield = luaL_checkinteger(L, 3); break; diff --git a/src/p_enemy.c b/src/p_enemy.c index ca08878c4..96a566a7c 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -3175,6 +3175,7 @@ void A_AttractChase(mobj_t *actor) actor->target->momz -= (FixedMul(gravity, mapobjectscale))*P_MobjFlip(actor->target); actor->target->player->ringboost += 5; actor->target->player->ringtime += 5; + actor->target->player->ringdrop = true; } else { diff --git a/src/p_saveg.c b/src/p_saveg.c index 82811fae4..e68bf2d3b 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -336,6 +336,7 @@ static void P_NetArchivePlayers(savebuffer_t *save) WRITEUINT8(save->p, players[i].ringtransparency); WRITEUINT8(save->p, players[i].airdroptime); + WRITEUINT8(save->p, players[i].ringdrop); WRITEUINT8(save->p, players[i].curshield); WRITEUINT8(save->p, players[i].bubblecool); @@ -692,6 +693,7 @@ static void P_NetUnArchivePlayers(savebuffer_t *save) players[i].ringtransparency = READUINT8(save->p); players[i].airdroptime = READUINT8(save->p); + players[i].ringdrop = READUINT8(save->p); players[i].curshield = READUINT8(save->p); players[i].bubblecool = READUINT8(save->p); From 91f71a3cf55d6444e3e03af18288a8726907d78a Mon Sep 17 00:00:00 2001 From: NepDisk Date: Sun, 21 Sep 2025 15:27:22 -0400 Subject: [PATCH 7/9] Fix menu preset for airdrop --- src/m_menu.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/m_menu.c b/src/m_menu.c index 10730ac67..cbb7e3608 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -5735,7 +5735,7 @@ void MD_DrawTimeAttackMenu(void) // Draw current RA preset mode. { - const char *mode = "Unkown mode"; + const char *mode = "Unknown mode"; if (preset == 0) { mode = "SRB2Kart Mode"; @@ -5874,6 +5874,7 @@ INT32 MR_TimeAttackPreset(INT32 arg) CV_Set(&cv_dummyattackingslipdash, preset[3] ? "On" : "Off"); CV_Set(&cv_dummyattackingpurpledrift, preset[4] ? "On" : "Off"); CV_Set(&cv_dummyattackingslopeboost, preset[5] ? "On" : "Off"); + CV_Set(&cv_dummyattackingairdrop, preset[6] ? "On" : "Off"); return true; } #undef NUMPRESETS From 9acbd66a9ef14f37884fe07b61d1eddd4fb97588 Mon Sep 17 00:00:00 2001 From: NepDisk Date: Sun, 21 Sep 2025 16:16:46 -0400 Subject: [PATCH 8/9] Don't add ghosts that don't match our current record attack mode --- src/g_demo.c | 36 +++++++++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/src/g_demo.c b/src/g_demo.c index 791efa19c..3c97929a0 100644 --- a/src/g_demo.c +++ b/src/g_demo.c @@ -112,7 +112,7 @@ demoghost *ghosts = NULL; // DEMO RECORDING // -#define DEMOVERSION 0x000B +#define DEMOVERSION 0x000C #define DEMOHEADER "\xF0" "BlanReplay" "\x0F" #define DF_GHOST 0x01 // This demo contains ghost data too! @@ -3830,6 +3830,7 @@ void G_AddGhost(char *defdemoname) CLEANUP(Z_Pfree) char *pdemoname = NULL; const char *n; UINT64 demohash; + UINT32 raflags; demoghost *gh; UINT8 flags; CLEANUP(Z_Pfree) UINT8 *buffer = NULL; @@ -3893,6 +3894,7 @@ void G_AddGhost(char *defdemoname) flags = header.demoflags; + raflags = header.raflags; if (!(flags & DF_GHOST)) { CONS_Alert(CONS_NOTICE, M_GetText("Ghost %s: No ghost data in this demo.\n"), pdemoname); @@ -3911,6 +3913,38 @@ void G_AddGhost(char *defdemoname) return; } + // Check RA flags. + { + UINT32 ourraflags = 0; + UINT16 demoversion = header.demoversion; + + if (cv_dummyattackingrings.value) + ourraflags |= RAF_RINGS; + if (cv_dummyattackingstacking.value) + ourraflags |= RAF_STACKING; + if (cv_dummyattackingchaining.value) + ourraflags |= RAF_CHAINING; + if (cv_dummyattackingslipdash.value) + ourraflags |= RAF_SLIPDASH; + if (cv_dummyattackingpurpledrift.value) + ourraflags |= RAF_PURPLEDRIFT; + if (cv_dummyattackingslopeboost.value) + ourraflags |= RAF_SLOPEBOOST; + if (cv_dummyattackingairdrop.value) + ourraflags |= RAF_AIRDROP; + + if (demoversion <= 0x000B) + { + ourraflags &= ~RAF_AIRDROP; + } + + if (ourraflags != raflags) + { + CONS_Alert(CONS_NOTICE, M_GetText("Failed to add ghost %s: Replay doesn't match current RA mode.\n"), pdemoname); + return; + } + } + demoplayer_t *plr = &header.playerdata[0]; // any invalidating flags? From 474e613354484150056a4de87015a38fff502bd2 Mon Sep 17 00:00:00 2001 From: NepDisk Date: Mon, 22 Sep 2025 17:20:49 -0400 Subject: [PATCH 9/9] Fix bumpspark merge conflict --- src/g_game.c | 2 +- src/m_menu.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/g_game.c b/src/g_game.c index c31fdbb0b..14ed674fd 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -486,7 +486,7 @@ SINT8 G_RecordPresetIndex(void) boolean airdrop = cv_dummyattackingairdrop.value; UINT8 bumpspark = cv_dummyattackingbumpspark.value; - if (!rings && !stacking && !chaining && !slipdash && !purpledrift && !slopeboost && !airdrop) + if (!rings && !stacking && !chaining && !slipdash && !purpledrift && !slopeboost && !airdrop && (bumpspark == BUMPSPARK_NONE)) return RP_KART; if (stacking && chaining && slopeboost && airdrop && !rings && !slipdash && !purpledrift && (bumpspark == BUMPSPARK_ALL)) diff --git a/src/m_menu.c b/src/m_menu.c index cb48078c3..a0ceccc36 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -458,7 +458,7 @@ consvar_t cv_dummyattackingslopeboost = CVAR_INIT ("dummyattackingslopeboost", " consvar_t cv_dummyattackingairdrop = CVAR_INIT ("dummyattackingairdrop", "Off", CV_HIDEN|CV_CALL|CV_NOINIT, CV_OnOff, Nextmap_OnChange); -static CV_PossibleValue_t dummybumpspark_cons_t[] = {{BUMPSPARK_NONE, "Off"}, {BUMPSPARK_NOCHARGE, "NoCharge"}, {BUMPSPARK_ALL, "On"}}; +static CV_PossibleValue_t dummybumpspark_cons_t[] = {{BUMPSPARK_NONE, "Off"}, {BUMPSPARK_NOCHARGE, "NoCharge"}, {BUMPSPARK_ALL, "On"}, {0, NULL}}; consvar_t cv_dummyattackingbumpspark = CVAR_INIT ("dummyattackingbumpspark", "Off", CV_HIDEN|CV_CALL|CV_NOINIT, dummybumpspark_cons_t, Nextmap_OnChange); static CV_PossibleValue_t dummygpdifficulty_cons_t[] = {{KARTSPEED_EASY, "Easy"}, {KARTSPEED_NORMAL, "Normal"}, {KARTSPEED_HARD, "Hard"}, {KARTSPEED_EXPERT, "Expert"}, {KARTGP_MASTER, "Master"}, {KARTGP_NIGHTMARE, "Nightmare"}, {0, NULL}};