From 1bb3df7435bd9af674617ca150b5af1c07f39d56 Mon Sep 17 00:00:00 2001 From: minenice55 Date: Tue, 3 Feb 2026 23:39:05 -0500 Subject: [PATCH] two(!!) new modes for airdrop bouncy = a-la ring racers heavy = even faster and gives a small boost on landing --- src/d_netcmd.c | 24 +++------ src/d_player.h | 7 +-- src/k_hud.c | 3 +- src/k_kart.c | 143 +++++++++++++++++++++++++++++++++++-------------- src/k_kart.h | 8 +++ src/p_mobj.h | 2 +- src/p_saveg.c | 2 +- src/p_setup.c | 7 ++- 8 files changed, 131 insertions(+), 65 deletions(-) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 3ee92edd0..86329f65c 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -613,7 +613,12 @@ 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_GUARD, CV_YesNo, KartAirDrop_OnChange); +static CV_PossibleValue_t airdrop_cons_t[] = {{AIRDROP_NONE, "Off"}, + {AIRDROP_LIGHT, "Light"}, + {AIRDROP_BOUNCY, "Bouncy"}, + {AIRDROP_HEAVY, "Heavy"}, + {0, NULL}}; +consvar_t cv_kartairdrop = CVAR_INIT ("kartairdrop", "Off", CV_NETVAR|CV_CALL|CV_NOINIT|CV_GUARD, airdrop_cons_t, KartAirDrop_OnChange); consvar_t cv_kartairthrust = CVAR_INIT ("kartairthrust", "No", CV_NETVAR|CV_CALL|CV_NOINIT|CV_GUARD, CV_YesNo, KartAirThrust_OnChange); consvar_t cv_kartairthrust_reductionrate = CVAR_INIT ("kartairthrust_reductionrate", "0.5", CV_NETVAR|CV_FLOAT|CV_CHEAT|CV_GUARD, CV_Unsigned, NULL); @@ -8473,24 +8478,11 @@ static void KartAirDrop_OnChange(void) { if (leveltime < starttime) { - airdropactive = true; - CONS_Printf(M_GetText("Air Drop has been turned \"On\".\n")); + CONS_Printf(M_GetText("Air Drop has been set to \"%s\".\n"), cv_kartairdrop.string); } 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("Air Drop has been turned \"Off\".\n")); - } - else - { - CONS_Printf(M_GetText("Air Drop will be turned \"Off\" next round.\n")); + CONS_Printf(M_GetText("Air Drop will be set to \"%s\" Next Round.\n"), cv_kartairdrop.string); } } } diff --git a/src/d_player.h b/src/d_player.h index 1842884a5..a134bfff9 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -71,8 +71,9 @@ typedef enum // TODO: Is there a better way to track this? PF_GAINAX = 1<<3, PF_KICKSTARTACCEL = 1<<4, // Accessibility feature: Is accelerate in kickstart mode? - // 1<<5 free - // 1<<6 free + + PF_WANTSAIRDROP = 1<<5, // Wants air drop (active while holding down brake, used for bouncy air drop) + PF_AIRDROP = 1<<6, // Is in Air Drop (activation / deactivation criteria change if light or heavy) PF_WANTSTOJOIN = 1<<7, // Spectator that wants to join @@ -672,7 +673,7 @@ 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; // Tracks how long airdrop has been active, used for delay before airdrop kicks in. + fixed_t airdroptime; // Tracks how long airdrop has been active, used for delay before airdrop kicks in. //boolean ringdrop; // Set when having ringdrop applied. mobj_t *shieldtracer; // Blankart: Shield mobj diff --git a/src/k_hud.c b/src/k_hud.c index 6e6247a2a..34ab6a275 100644 --- a/src/k_hud.c +++ b/src/k_hud.c @@ -2542,7 +2542,8 @@ 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}, + {"Light Air Drop", 0, NULL, K_AirDropActive() == AIRDROP_LIGHT, true}, + {"Heavy Air Drop", 0, NULL, K_AirDropActive() >= AIRDROP_HEAVY, true}, {"Air Thrust", 0, NULL, K_AirThrustActive() > 0, true}, {"Recovery Dash", 0, NULL, K_RecoveryDashActive() > 0, true}, {"Bump Spark", 0, &cv_kartbumpspark, -1, true}, diff --git a/src/k_kart.c b/src/k_kart.c index 1da21f895..645088e5e 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -6978,65 +6978,130 @@ static void K_SpawnFallLines(player_t *player, boolean ringdrop) static void K_AirDrop(player_t *player, ticcmd_t *cmd) { + if (!(cmd->buttons & BT_BRAKE)) + { + player->pflags &= ~PF_WANTSAIRDROP; + } + if (!K_AirDropActive() || P_IsObjectOnGround(player->mo) || P_PlayerInPain(player) || player->loop.radius || (player->mo->tracer && player->mo->tracer->type == MT_TUBEWAYPOINT) || player->respawn ) { - // Conditions! + if ((player->pflags & PF_AIRDROP)) + { + if (airdropactive == AIRDROP_BOUNCY) + { + const fixed_t maxBounce = mapobjectscale * 10; + const fixed_t minBounce = mapobjectscale; + fixed_t bounce = 2 * abs(player->airdroptime) / 3; + + // Lose speed on bad bounce. + // Slow down more as horizontal momentum shrinks + // compared to vertical momentum. + angle_t a = R_PointToAngle2(0, 0, 4 * maxBounce, player->speed); + fixed_t f = FSIN(a); + player->mo->momx = FixedMul(player->mo->momx, f); + player->mo->momy = FixedMul(player->mo->momy, f); + if (bounce > maxBounce) + { + bounce = maxBounce; + } + else if (bounce < minBounce) + { + bounce = minBounce; + } + + if (player->mo->eflags & MFE_UNDERWATER) + bounce = (117 * bounce) / 200; + + // Nudge the player in their facing angle, and provide a little starting momentum if they need it. + // The bounce is already a strong tradeoff, so this allows it to be used for saves and get you back into flow. + angle_t momangle = K_MomentumAngle(player->mo); + fixed_t minspeed = K_GetKartSpeed(player, false, false)/2; + fixed_t returnspeed = max(FixedHypot(player->mo->momx, player->mo->momy), minspeed); + + // Initial momentum set uses real speed to avoid some weird twitchy behavior at low XY speed + P_InstaThrust(player->mo, momangle, FixedHypot(player->mo->momx, player->mo->momy)/2); + P_Thrust(player->mo, player->mo->angle, returnspeed/2); + + player->mo->z += P_MobjFlip(player->mo); + player->mo->momz = bounce * P_MobjFlip(player->mo); + + if (S_SoundPlaying(player->mo, sfx_s3kd9l)) + { + S_StopSoundByID(player->mo, sfx_s3kd9l); + } + } + else if (airdropactive == AIRDROP_HEAVY) + { + if (player->rings > 0) + { + P_PlayerRingBurst(player, min(2, player->rings)); + } + player->startboost = TICRATE/2; + } + } player->airdroptime = 0; - //player->ringdrop = false; + player->pflags &= ~PF_AIRDROP; return; } - if (cmd->buttons & BT_BRAKE) + if ((cmd->buttons & BT_BRAKE) && !(player->pflags & PF_WANTSAIRDROP)) { - SINT8 airbrakedelay = TICRATE/3; - if (player->airdroptime < airbrakedelay) + if (airdropactive == AIRDROP_HEAVY && !(player->pflags & PF_AIRDROP)) { - /*if (player->rings > 0) - { - player->ringlock = 6; - } + // TODO: heavy air drop should allow keeping current boost stack + S_StartSound(player->mo, sfx_cdfm01); + S_StartSound(player->mo, sfx_s3k51); - player->ringdrop = false;*/ + player->mo->momx = FixedMul(player->mo->momx, 90*FRACUNIT/100); + player->mo->momy = FixedMul(player->mo->momy, 90*FRACUNIT/100); + player->mo->momz -= 8*P_MobjFlip(player->mo)*mapobjectscale; + } + player->pflags |= PF_AIRDROP|PF_WANTSAIRDROP; + } + else + { + if (airdropactive == AIRDROP_LIGHT) + player->pflags &= ~PF_AIRDROP; + } + + if (player->pflags & PF_AIRDROP) + { + + K_SpawnFallLines(player, false); + + if (airdropactive == AIRDROP_BOUNCY) + { + player->airdroptime = player->mo->momz; + if (!S_SoundPlaying(player->mo, sfx_s3kd9l)) + { + S_StartSound(player->mo, sfx_s3kd9l); + } } 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 = 17; // 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 = 7; - player->ringlock = 6; - } - - if (player->rings <= 0) - { - player->ringdrop = false; - }*/ - - K_SpawnFallLines(player, /*player->ringdrop*/ false); + if (player->airdroptime < UINT8_MAX) + player->airdroptime++; + } + + if (airdropactive == AIRDROP_HEAVY && player->airdroptime <= TICRATE/4) + { + player->mo->momz -= FixedMul(4*gravity, mapobjectscale)*P_MobjFlip(player->mo); K_SpawnAirdropTrail(player); + } + else if (airdropactive == AIRDROP_LIGHT) + { player->mo->momz -= FixedMul(gravity, mapobjectscale)*P_MobjFlip(player->mo); + K_SpawnAirdropTrail(player); + } + else + { + player->mo->momz -= FixedMul(2*gravity, mapobjectscale)*P_MobjFlip(player->mo); } } - - if (player->airdroptime < UINT8_MAX) - player->airdroptime++; } // Returns the bumpspark value as an enum. diff --git a/src/k_kart.h b/src/k_kart.h index 5b4d9830c..0d071ae16 100644 --- a/src/k_kart.h +++ b/src/k_kart.h @@ -419,6 +419,14 @@ typedef enum BUMPSPARK_ALL } bumpsparktype_t; +typedef enum +{ + AIRDROP_NONE = 0, + AIRDROP_LIGHT, + AIRDROP_HEAVY, + AIRDROP_BOUNCY, +} airdroptype_t; + #ifdef __cplusplus } // extern "C" #endif diff --git a/src/p_mobj.h b/src/p_mobj.h index 80f0447ba..01bab7ad1 100644 --- a/src/p_mobj.h +++ b/src/p_mobj.h @@ -617,7 +617,7 @@ extern boolean slipdashactive; extern boolean purpledriftactive; extern boolean slopeboostactive; extern boolean draftingactive; -extern boolean airdropactive; +extern UINT8 airdropactive; extern boolean airthrustactive; extern boolean recoverydashactive; extern boolean waterskipbricks; diff --git a/src/p_saveg.c b/src/p_saveg.c index cd3bc4a5b..5c027e292 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -4239,13 +4239,13 @@ static boolean P_NetSyncMisc(savebuffer_t *save, boolean resending) SYNCBOOLEAN(purpledriftactive); SYNCBOOLEAN(slopeboostactive); SYNCBOOLEAN(draftingactive); - SYNCBOOLEAN(airdropactive); SYNCBOOLEAN(airthrustactive); SYNCBOOLEAN(recoverydashactive); SYNCBOOLEAN(waterskipbricks); SYNCBOOLEAN(itemlittering); SYNCBOOLEAN(itempushing); SYNCBOOLEAN(itemlistactive); + SYNC(airdropactive); SYNC(bumpsparkactive); SYNC(antibumptime); diff --git a/src/p_setup.c b/src/p_setup.c index 35dc4b2f6..ab04a1aa3 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -160,7 +160,7 @@ boolean slipdashactive; boolean purpledriftactive; boolean slopeboostactive; boolean draftingactive; -boolean airdropactive; +UINT8 airdropactive; boolean airthrustactive; boolean recoverydashactive; boolean waterskipbricks; @@ -8183,7 +8183,7 @@ static void P_InitLevelSettings(boolean reloadinggamestate) purpledriftactive = false; slopeboostactive = false; draftingactive = false; - airdropactive = false; + airdropactive = 0; airthrustactive = false; recoverydashactive = false; waterskipbricks = false; @@ -8214,8 +8214,7 @@ static void P_InitLevelSettings(boolean reloadinggamestate) if (cv_kartdrafting.value) draftingactive = true; - if (cv_kartairdrop.value) - airdropactive = true; + airdropactive = (UINT8)cv_kartairdrop.value; if (cv_kartairthrust.value) airthrustactive = true;