From 0450fe8b9e4bf157b79a60f7e7a65ce564c440f8 Mon Sep 17 00:00:00 2001 From: Antonio Martinez Date: Wed, 2 Jul 2025 19:29:54 -0400 Subject: [PATCH 1/3] Do fast transfer fall with C, add FX --- src/d_player.h | 4 +++- src/k_hud_track.cpp | 9 +++++++ src/k_kart.c | 57 +++++++++++++++++++++++++++++++++++++-------- src/k_kart.h | 2 ++ src/lua_playerlib.c | 4 ---- src/p_mobj.c | 49 ++++++++++++++++++++++++++++++++------ src/p_saveg.cpp | 2 -- 7 files changed, 103 insertions(+), 24 deletions(-) diff --git a/src/d_player.h b/src/d_player.h index 0dcaf03ec..d440ecbfe 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -139,9 +139,12 @@ typedef enum PF2_SELFDEAFEN = 1<<2, PF2_SERVERMUTE = 1<<3, PF2_SERVERDEAFEN = 1<<4, + PF2_STRICTFASTFALL = 1<<5, // Fastfall only with C, never with A+X. Profile preference. + PF2_ALWAYSDAMAGED = 1<<6, // Ignore invulnerability or clash conditions when evaulating damage (P_DamageMobj). Unset after use! PF2_BUBBLECONTACT = 1<<7, // ACHTUNG VERY BAD HACK - Don't allow Bubble Shield to contact certain objects unless this is a fresh blowup. + PF2_SUPERTRANSFERVFX = 1<<8, // Don't respawn the "super transfer available" VFX. } pflags2_t; typedef enum @@ -1114,7 +1117,6 @@ struct player_t fixed_t outrun; // Milky Way road effect fixed_t transfer; // Tired of Ramp Park fastfalls - boolean transfersound; uint8_t public_key[PUBKEYLENGTH]; diff --git a/src/k_hud_track.cpp b/src/k_hud_track.cpp index a99eda70f..1f8268095 100644 --- a/src/k_hud_track.cpp +++ b/src/k_hud_track.cpp @@ -461,6 +461,14 @@ std::optional object_tooltip(const mobj_t* mobj) ); case MT_PLAYER: + { + if (stplyr->fastfall == 0 && K_CanSuperTransfer(stplyr)) + return Tooltip( + TextElement( + TextElement().parse("").font(splitfont)) + ) + .offset3d(0, 0, 64 * mobj->scale * P_MobjFlip(mobj)); + return conditional( mobj->player == stplyr && stplyr->icecube.frozen, [&] { return Tooltip(TextElement( @@ -470,6 +478,7 @@ std::optional object_tooltip(const mobj_t* mobj) )).offset3d(0, 0, 64 * mobj->scale * P_MobjFlip(mobj)); } // I will be trying to figure out why the return value didn't accept a straightforward call to parse() for the rest of my life (apprx. 15 seconds) ); + } default: return {}; diff --git a/src/k_kart.c b/src/k_kart.c index dc2afcef1..1de53e917 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -7635,6 +7635,13 @@ void K_DoPogoSpring(mobj_t *mo, fixed_t vertispeed, UINT8 sound) } } +boolean K_CanSuperTransfer(player_t *player) +{ + if (!player->transfer) + return false; + return (abs(player->mo->momz) < (2*abs(player->transfer)/4)) || (player->mo->momz > 0) != (player->transfer > 0); +} + static void K_ThrowLandMine(player_t *player) { mobj_t *landMine; @@ -9565,16 +9572,16 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) K_TryMoveBackupItem(player); - if (onground || player->transfer < 10*player->mo->scale) + if (onground && player->transfer) { + player->fastfall = 0; player->transfer = 0; - player->transfersound = false; + player->pflags2 &= ~PF2_SUPERTRANSFERVFX; } if (player->transfer) { - boolean eligible = (abs(player->mo->momz) < (2*abs(player->transfer)/4)) || (player->mo->momz > 0) != (player->transfer > 0); - if ((player->cmd.buttons & BT_ACCELERATE) && eligible) + if (player->fastfall) { fixed_t fuckfactor = FRACUNIT; fixed_t transfergravity = 10*FRACUNIT/100; @@ -9587,11 +9594,6 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) { fuckfactor = FRACUNIT/2; } - else if (!player->transfersound) - { - S_StartSound(player->mo, sfx_ggfall); - player->transfersound = true; - } fixed_t sx, sy; sx = P_RandomRange(PR_DECORATION, -48, 48)*FRACUNIT; @@ -9612,6 +9614,18 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) { if (leveltime % 2) K_SpawnFireworkTrail(player->mo); + + if (K_CanSuperTransfer(player) && !(player->pflags2 & PF2_SUPERTRANSFERVFX)) + { + if (P_IsDisplayPlayer(player)) + S_StartSound(player->mo, sfx_gshdc); + mobj_t *gainax = P_SpawnMobjFromMobj(player->mo, 0, 0, 0, MT_GAINAX); + gainax->movedir = 0; + P_SetTarget(&gainax->target, player->mo); + P_SetMobjState(gainax, S_GAINAX_MID1); + gainax->flags2 |= MF2_BOSSNOTRAP; + player->pflags2 |= PF2_SUPERTRANSFERVFX; + } } } @@ -12800,6 +12814,13 @@ boolean K_PlayerEBrake(const player_t *player) return false; } + // A little gross, but when fastfalling from a transfer, we are "transferring" for 1 tic of landing. + // Prevents a single tic of ebrake friction janking everything out. + if (player->transfer && player->mo && !P_MobjWasRemoved(player->mo) && P_IsObjectOnGround(player->mo)) + { + return false; + } + if (player->fastfall != 0) { return true; @@ -13205,18 +13226,33 @@ static void K_KartSpindash(player_t *player) if (player->fastfall == 0) { + // Starting fastfall... + // ...unless this is a macro input with a strict profile. + // Then this is probably an attempted brakedrift or e-brake. if (player->pflags2 & PF2_STRICTFASTFALL) if (!(player->cmd.buttons & BT_SPINDASH)) return; // Factors 3D momentum. player->fastfallBase = FixedHypot(player->speed, player->mo->momz); + + if (K_CanSuperTransfer(player)) + { + S_StartSound(player->mo, sfx_ggfall); + } + else + { + player->transfer = 0; + } } // Update fastfall. player->fastfall = player->mo->momz; + player->spindash = 0; - P_ResetPitchRoll(player->mo); + + if (!player->transfer) + P_ResetPitchRoll(player->mo); return; } @@ -13315,6 +13351,7 @@ boolean K_FastFallBounce(player_t *player) // Handle fastfall bounce. if (player->fastfall != 0) { + CONS_Printf("ffb\n"); const fixed_t maxBounce = mapobjectscale * 10; const fixed_t minBounce = mapobjectscale; fixed_t bounce = 2 * abs(player->fastfall) / 3; diff --git a/src/k_kart.h b/src/k_kart.h index 67d4fb31a..7c644e0ad 100644 --- a/src/k_kart.h +++ b/src/k_kart.h @@ -352,6 +352,8 @@ fixed_t K_TeamComebackMultiplier(player_t *player); void K_ApplyStun(player_t *player, mobj_t *inflictor, mobj_t *source, INT32 damage, UINT8 damagetype); +boolean K_CanSuperTransfer(player_t *player); + #ifdef __cplusplus } // extern "C" #endif diff --git a/src/lua_playerlib.c b/src/lua_playerlib.c index 6cad86a53..65e2b894a 100644 --- a/src/lua_playerlib.c +++ b/src/lua_playerlib.c @@ -274,8 +274,6 @@ static int player_get(lua_State *L) lua_pushboolean(L, plr->analoginput); else if (fastcmp(field,"transfer")) lua_pushboolean(L, plr->transfer); - else if (fastcmp(field,"transfersound")) - lua_pushboolean(L, plr->transfersound); else if (fastcmp(field,"markedfordeath")) lua_pushboolean(L, plr->markedfordeath); else if (fastcmp(field,"incontrol")) @@ -933,8 +931,6 @@ static int player_set(lua_State *L) plr->analoginput = luaL_checkboolean(L, 3); else if (fastcmp(field,"transfer")) plr->transfer = luaL_checkboolean(L, 3); - else if (fastcmp(field,"transfersound")) - plr->transfersound = luaL_checkboolean(L, 3); else if (fastcmp(field,"markedfordeath")) plr->markedfordeath = luaL_checkboolean(L, 3); else if (fastcmp(field,"dotrickfx")) diff --git a/src/p_mobj.c b/src/p_mobj.c index 389ae45ed..21e0eb317 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -1197,7 +1197,7 @@ fixed_t P_GetMobjGravity(mobj_t *mo) { gravityadd *= 3; } - else if (mo->player->fastfall != 0) + else if (mo->player->fastfall != 0 && mo->player->transfer == 0) { // Fast falling @@ -1801,8 +1801,15 @@ boolean P_XYMovement(mobj_t *mo) mo->momz = transfermomz; if (mo->player) { - mo->player->transfer = transfermomz; - S_StartSound(mo, sfx_s3k98); + if (abs(transfermomz) > 10*mo->scale) + { + mo->player->transfer = transfermomz; + S_StartSound(mo, sfx_s3k98); + } + else + { + mo->player->transfer = 0; + } } mo->standingslope = NULL; @@ -8211,26 +8218,53 @@ static boolean P_MobjRegularThink(mobj_t *mobj) mobj->z + (mobj->target->height * P_MobjFlip(mobj))); break; case MT_GAINAX: + { + boolean vfx = !!(mobj->flags2 & MF2_BOSSNOTRAP); + if (!mobj->target || P_MobjWasRemoved(mobj->target) // sanity - || !mobj->target->player // ditto - || !mobj->target->player->glanceDir // still glancing? - || mobj->target->player->aizdriftturn // only other circumstance where can glance - || ((K_GetKartButtons(mobj->target->player) & BT_LOOKBACK) != BT_LOOKBACK)) // it's a lookback indicator... + || !mobj->target->player) // ditto { P_RemoveMobj(mobj); return false; } + if (!vfx) + { + if (!mobj->target->player->glanceDir // still glancing? + || mobj->target->player->aizdriftturn // only other circumstance where can glance + || ((K_GetKartButtons(mobj->target->player) & BT_LOOKBACK) != BT_LOOKBACK)) // it's a lookback indicator... + { + P_RemoveMobj(mobj); + return false; + } + } + + if (vfx) + { + if (P_IsObjectOnGround(mobj->target) || mobj->target->player->fastfall + || !K_CanSuperTransfer(mobj->target->player)) + { + P_RemoveMobj(mobj); + return false; + } + } + mobj->angle = mobj->target->player->drawangle; mobj->z = mobj->target->z; K_MatchGenericExtraFlags(mobj, mobj->target); + mobj->renderflags = (mobj->renderflags & ~RF_DONTDRAW)|K_GetPlayerDontDrawFlag(mobj->target->player); + if (vfx) + mobj->renderflags ^= INT32_MAX; P_MoveOrigin(mobj, mobj->target->x + FixedMul(34 * mapobjectscale, FINECOSINE((mobj->angle + mobj->movedir) >> ANGLETOFINESHIFT)), mobj->target->y + FixedMul(34 * mapobjectscale, FINESINE((mobj->angle + mobj->movedir) >> ANGLETOFINESHIFT)), mobj->z + (32 * mapobjectscale * P_MobjFlip(mobj))); + if (vfx) + break; + { statenum_t gainaxstate = mobj->state-states; if (gainaxstate == S_GAINAX_TINY) @@ -8254,6 +8288,7 @@ static boolean P_MobjRegularThink(mobj_t *mobj) } break; + } case MT_FLAMESHIELDPAPER: if (!mobj->target || P_MobjWasRemoved(mobj->target)) { diff --git a/src/p_saveg.cpp b/src/p_saveg.cpp index 3f80ce27c..2351cc64b 100644 --- a/src/p_saveg.cpp +++ b/src/p_saveg.cpp @@ -696,7 +696,6 @@ static void P_NetArchivePlayers(savebuffer_t *save) WRITEFIXED(save->p, players[i].outrun); WRITEFIXED(save->p, players[i].transfer); - WRITEUINT8(save->p, players[i].transfersound); WRITEUINT8(save->p, players[i].rideroid); WRITEUINT8(save->p, players[i].rdnodepull); @@ -1358,7 +1357,6 @@ static void P_NetUnArchivePlayers(savebuffer_t *save) players[i].outrun = READFIXED(save->p); players[i].transfer = READFIXED(save->p); - players[i].transfersound = READUINT8(save->p); players[i].rideroid = (boolean)READUINT8(save->p); players[i].rdnodepull = (boolean)READUINT8(save->p); From 7378cf2cd675b26d6f9ff9cb5481246fd8630c07 Mon Sep 17 00:00:00 2001 From: VelocitOni Date: Wed, 2 Jul 2025 20:41:09 -0400 Subject: [PATCH 2/3] Comment out ffb print Comment out fast-fall bounce print --- src/k_kart.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/k_kart.c b/src/k_kart.c index 1de53e917..7a1526090 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -13351,7 +13351,7 @@ boolean K_FastFallBounce(player_t *player) // Handle fastfall bounce. if (player->fastfall != 0) { - CONS_Printf("ffb\n"); + //CONS_Printf("ffb\n"); const fixed_t maxBounce = mapobjectscale * 10; const fixed_t minBounce = mapobjectscale; fixed_t bounce = 2 * abs(player->fastfall) / 3; From 4ee8ec15d32d253f4758fd7d846e93abb2b80f2c Mon Sep 17 00:00:00 2001 From: Antonio Martinez Date: Wed, 2 Jul 2025 21:07:33 -0400 Subject: [PATCH 3/3] Disallow failsafe when doing super transfer --- src/k_kart.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/k_kart.c b/src/k_kart.c index 7a1526090..43f26ac71 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -13476,7 +13476,7 @@ static void K_AirFailsafe(player_t *player) // Accel inputs queue air-failsafe for when they're released, // as long as they're not part of a fastfall attempt. - if ((buttons & (BT_ACCELERATE|BT_BRAKE)) == BT_ACCELERATE || K_GetForwardMove(player) != 0) + if ((buttons & (BT_ACCELERATE|BT_BRAKE)) == BT_ACCELERATE || K_GetForwardMove(player) != 0 || (player->fastfall && player->transfer)) { player->pflags |= PF_AIRFAILSAFE; return;