From 95cd51cada19a21b2cdf82e0e3163addab8db66c Mon Sep 17 00:00:00 2001 From: AJ Martinez Date: Thu, 1 May 2025 17:12:40 -0400 Subject: [PATCH] Dynamic tripwire --- src/deh_tables.c | 3 ++ src/f_finale.c | 23 ++++++++++-- src/info.c | 30 ++++++++++++++++ src/info.h | 4 +++ src/k_kart.c | 21 ++++++++++- src/k_kart.h | 2 ++ src/p_inter.c | 4 ++- src/p_mobj.c | 91 +++++++++++++++++++++++++++++++++++++++++++++++- 8 files changed, 172 insertions(+), 6 deletions(-) diff --git a/src/deh_tables.c b/src/deh_tables.c index 7182b5e1a..44195a340 100644 --- a/src/deh_tables.c +++ b/src/deh_tables.c @@ -2162,6 +2162,8 @@ const char *const STATE_LIST[] = { // array length left dynamic for sanity testi "S_TRIPWIREBOOST_BLAST_TOP", "S_TRIPWIREBOOST_BLAST_BOTTOM", + "S_TRIPWIREAPPROACH", + "S_SMOOTHLANDING", "S_TRICKINDICATOR_OVERLAY", @@ -3644,6 +3646,7 @@ const char *const MOBJTYPE_LIST[] = { // array length left dynamic for sanity t "MT_BATTLEBUMPER_BLAST", "MT_TRIPWIREBOOST", + "MT_TRIPWIREAPPROACH", "MT_SMOOTHLANDING", "MT_TRICKINDICATOR", diff --git a/src/f_finale.c b/src/f_finale.c index fa118eb42..e3a41e495 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -923,6 +923,16 @@ void F_IntroTicker(void) S_StartSound(NULL, sfx_supflk); } + if (skiptype == 5) // Quick Thunderdome + { + ResetSkipSequences(); + CV_StealthSetValue(&cv_kartbot, 13); + CV_StealthSetValue(&cv_maxplayers, 8); + CV_StealthSetValue(&cv_thunderdome, 1); + D_MapChange(G_RandMap(TOL_RACE, UINT16_MAX-1, true, false, NULL), GT_RACE, (cv_kartencore.value == 1), true, 0, false, false); + return; + } + if (doskip && disclaimerskippable) { if (dc_state == DISCLAIMER_FINAL) { @@ -1013,16 +1023,21 @@ static void AdvanceSkipSequences(UINT8 input) UINT8 s2cheat[] = {1, 1, 1}; UINT8 s3cheat[] = {2, 2, 2}; UINT8 s3kcheat[] = {3, 3, 3}; + UINT8 thundercheat[] = {4, 4, 4}; #else UINT8 s2cheat[] = {1, 1, 1, 3, 3, 3, 1}; UINT8 s3cheat[] = {1, 1, 3, 3, 1, 1, 1, 1}; UINT8 s3kcheat[] = {4, 4, 4, 2, 2, 2, 1, 1, 1}; + UINT8 thundercheat[] = {2, 4, 2, 4, 3, 3, 1, 1}; #endif UINT8 nicetry[] = {1, 1, 3, 3, 4, 2, 4, 2}; - UINT8 *cheats[4] = {s2cheat, s3cheat, s3kcheat, nicetry}; - UINT8 cheatlengths[4] = {sizeof(s2cheat), sizeof(s3cheat), sizeof(s3kcheat), sizeof(nicetry)}; - for (UINT8 i = 0; i < 4; i++) // for each cheat... + #define NUMCHEATSPLUSONE 5 + + UINT8 *cheats[NUMCHEATSPLUSONE] = {s2cheat, s3cheat, s3kcheat, nicetry, thundercheat}; + UINT8 cheatlengths[NUMCHEATSPLUSONE] = {sizeof(s2cheat), sizeof(s3cheat), sizeof(s3kcheat), sizeof(nicetry), sizeof(thundercheat)}; + + for (UINT8 i = 0; i < NUMCHEATSPLUSONE; i++) // for each cheat... { UINT8 cheatsize = cheatlengths[i]; boolean matched = true; @@ -1040,6 +1055,8 @@ static void AdvanceSkipSequences(UINT8 input) skiptype = i+1; } + #undef NUMCHEATSPLUSONE + skipinputindex++; } diff --git a/src/info.c b/src/info.c index 9dfca1d03..902575c82 100644 --- a/src/info.c +++ b/src/info.c @@ -399,6 +399,7 @@ char sprnames[NUMSPRITES + 1][5] = "BEXB", // Battle Bumper Explosion: Blast "TWBS", // Tripwire Boost "TWBT", // Tripwire BLASTER + "TWBP", // Tripwire approach "SMLD", // Smooth landing // Trick Effects @@ -2687,6 +2688,8 @@ state_t states[NUMSTATES] = {SPR_TWBT, FF_FULLBRIGHT|FF_ADD|FF_ANIMATE, -1, {NULL}, 6, 2, S_NULL}, // S_TRIPWIREBOOST_BLAST_TOP {SPR_TWBT, FF_FULLBRIGHT|FF_ADD|FF_ANIMATE|FF_VERTICALFLIP|FF_HORIZONTALFLIP, -1, {NULL}, 6, 2, S_NULL}, // S_TRIPWIREBOOST_BLAST_BOTTOM + {SPR_TWBP, FF_FULLBRIGHT|FF_ADD|FF_ANIMATE, -1, {NULL}, 11, 1, S_NULL}, // S_TRIPWIREAPPROACH + {SPR_SMLD, FF_FULLBRIGHT|FF_ADD|FF_ANIMATE, -1, {NULL}, 7, 2, S_NULL}, // S_SMOOTHLANDING {SPR_TRK1, FF_FULLBRIGHT|FF_ANIMATE|FF_PAPERSPRITE|FF_ADD, -1, {NULL}, 3, 3, S_NULL}, // S_TRICKINDICATOR_OVERLAY, @@ -16061,6 +16064,33 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL // raisestate }, + { // MT_TRIPWIREAPPROACH + -1, // doomednum + S_TRIPWIREAPPROACH, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 8*FRACUNIT, // radius + 16*FRACUNIT, // height + 1, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_NOGRAVITY|MF_NOCLIPHEIGHT|MF_NOCLIPTHING|MF_DONTENCOREMAP, // flags + S_NULL // raisestate + }, + { // MT_SMOOTHLANDING -1, // doomednum S_SMOOTHLANDING, // spawnstate diff --git a/src/info.h b/src/info.h index 2ae6aa5c9..0345073b7 100644 --- a/src/info.h +++ b/src/info.h @@ -938,6 +938,7 @@ typedef enum sprite SPR_BEXB, // Battle Bumper Explosion: Blast SPR_TWBS, // Tripwire Boost SPR_TWBT, // Tripwire BLASTER + SPR_TWBP, // Tripwire approach SPR_SMLD, // Smooth landing // Trick Effects @@ -3189,6 +3190,8 @@ typedef enum state S_TRIPWIREBOOST_BLAST_TOP, S_TRIPWIREBOOST_BLAST_BOTTOM, + S_TRIPWIREAPPROACH, + S_SMOOTHLANDING, S_TRICKINDICATOR_OVERLAY, @@ -4698,6 +4701,7 @@ typedef enum mobj_type MT_BATTLEBUMPER_BLAST, MT_TRIPWIREBOOST, + MT_TRIPWIREAPPROACH, MT_SMOOTHLANDING, MT_TRICKINDICATOR, diff --git a/src/k_kart.c b/src/k_kart.c index 063024c3c..f166a618e 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -448,7 +448,7 @@ boolean K_IsPlayerScamming(player_t *player) // "Why 8?" Consistency // "Why 2000?" Vibes - return (K_GetItemRouletteDistance(player, 8) < 2000); + return (K_GetItemRouletteDistance(player, 8) < SCAMDIST); } fixed_t K_GetKartGameSpeedScalar(SINT8 value) @@ -2998,6 +2998,18 @@ fixed_t K_PlayerTripwireSpeedThreshold(const player_t *player) { fixed_t required_speed = 2 * K_GetKartSpeed(player, false, false); // 200% + UINT32 distance = K_GetItemRouletteDistance(player, 8); + + if (gametype == GT_RACE) + { + if (distance < SCAMDIST) // Players near 1st need more speed! + { + fixed_t percentscam = FixedDiv(FRACUNIT*(SCAMDIST - distance), FRACUNIT*SCAMDIST); + required_speed += FixedMul(required_speed, percentscam); + } + } + + if (player->offroad && K_ApplyOffroad(player)) { // Increase to 300% if you're lawnmowering. @@ -8800,6 +8812,13 @@ static void K_UpdateTripwire(player_t *player) mobj_t *front = P_SpawnMobjFromMobj(player->mo, 0, 0, 0, MT_TRIPWIREBOOST); mobj_t *back = P_SpawnMobjFromMobj(player->mo, 0, 0, 0, MT_TRIPWIREBOOST); + if (P_IsDisplayPlayer(player)) + { + S_StartSound(player->mo, sfx_s3k40); + S_StopSoundByID(player->mo, sfx_gshaf); + } + + P_SetTarget(&front->target, player->mo); P_SetTarget(&back->target, player->mo); diff --git a/src/k_kart.h b/src/k_kart.h index fdd68292d..6830eb6fa 100644 --- a/src/k_kart.h +++ b/src/k_kart.h @@ -58,6 +58,8 @@ Make sure this matches the actual number of states #define RR_PROJECTILE_FUSE (8*TICRATE) +#define SCAMDIST (2000) + // 2023-08-26 +ang20 to Sal's OG values to make them friendlier - Tyron #define STUMBLE_STEEP_VAL (ANG60 + ANG20) #define STUMBLE_STEEP_VAL_AIR (ANG30 + ANG10 + ANG20) diff --git a/src/p_inter.c b/src/p_inter.c index 5a444163a..b5128ad49 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -448,7 +448,9 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) if (special->fuse) // This box is respawning, but was broken very recently (see P_FuseThink) { // What was this box broken as? - if (special->cvmem && !(special->flags2 & MF2_BOSSDEAD)) + if (cv_thunderdome.value) + K_StartItemRoulette(player, true); + else if (special->cvmem && !(special->flags2 & MF2_BOSSDEAD)) K_StartItemRoulette(player, false); else K_StartItemRoulette(player, true); diff --git a/src/p_mobj.c b/src/p_mobj.c index 13892657f..ee7a8f5e0 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -7747,6 +7747,78 @@ static boolean P_MobjRegularThink(mobj_t *mobj) } } break; + case MT_TRIPWIREAPPROACH: { + if (!mobj->target || !mobj->target->health || !mobj->target->player) + { + P_RemoveMobj(mobj); + return false; + } + + mobj_t *target = mobj->target; + player_t *player = target->player; + fixed_t myspeed = (player->speed); + + fixed_t maxspeed = K_PlayerTripwireSpeedThreshold(player); // Centered at this speed. + fixed_t minspeed = max(2 * maxspeed / 4, 16 * K_GetKartSpeed(player, false, false) / 10); // Starts appearing at this speed. + fixed_t alertspeed = 9 * maxspeed / 10; // When to flash? + fixed_t frontoffset = 5*target->scale; // How far in front? + + fixed_t percentvisible = 0; + if (myspeed > minspeed) + percentvisible = min(FRACUNIT, FixedDiv(myspeed - minspeed, maxspeed - minspeed)); + if (myspeed >= maxspeed || player->tripwireLeniency) + percentvisible = 0; + +#if 0 + fixed_t hang = 85*FRACUNIT/100; // Dampen inward movement past a certain point + if (percentvisible > hang && percentvisible < (95*FRACUNIT/100)) + percentvisible = (percentvisible + hang) / 2; +#endif + + fixed_t easedoffset = Easing_InOutCubic(percentvisible, 0, FRACUNIT); + fixed_t easedscale = FRACUNIT; + + fixed_t dynamicoffset = FixedMul(target->scale * 100, FRACUNIT - easedoffset); + + fixed_t xofs = (mobj->extravalue1) ? dynamicoffset : dynamicoffset * -1; + fixed_t zofs = (mobj->extravalue2) ? dynamicoffset : dynamicoffset * -1; + + angle_t facing = K_MomentumAngle(mobj->target); + fixed_t sin = FINESINE(facing >> ANGLETOFINESHIFT); + fixed_t cos = FINECOSINE(facing >> ANGLETOFINESHIFT); + + P_MoveOrigin(mobj, + target->x - FixedMul(xofs, sin) + FixedMul(frontoffset, cos), + target->y + FixedMul(xofs, cos) + FixedMul(frontoffset, sin), + target->z + zofs + (target->height / 2)); + mobj->angle = facing + ANGLE_90 + (mobj->extravalue1 ? ANGLE_45 : -1*ANGLE_45); + K_MatchGenericExtraFlags(mobj, target); + P_InstaScale(mobj, FixedMul(target->scale, easedscale)); + + UINT8 maxtranslevel = NUMTRANSMAPS - 2; + UINT8 trans = FixedInt(FixedMul(percentvisible, FRACUNIT*(maxtranslevel+1))); + if (trans > maxtranslevel) + trans = maxtranslevel; + trans = NUMTRANSMAPS - trans; + + mobj->renderflags &= ~(RF_TRANSMASK); + if (trans != 0) + { + mobj->renderflags |= (trans << RF_TRANSSHIFT); + } + + mobj->renderflags |= RF_PAPERSPRITE; + + mobj->colorized = true; + if (myspeed > alertspeed) + mobj->color = (leveltime & 1) ? SKINCOLOR_LILAC : SKINCOLOR_JAWZ; + else + mobj->color = SKINCOLOR_WHITE; + + mobj->renderflags |= (RF_DONTDRAW & ~K_GetPlayerDontDrawFlag(player)); + + break; + } case MT_TRIPWIREBOOST: { mobj_t *top; fixed_t newHeight; @@ -7755,12 +7827,18 @@ static boolean P_MobjRegularThink(mobj_t *mobj) if (!mobj->target || !mobj->target->health || !mobj->target->player || !mobj->target->player->tripwireLeniency) { + if (mobj->target && mobj->target->player && P_IsDisplayPlayer(mobj->target->player)) + { + S_StopSoundByID(mobj->target, sfx_s3k40); + S_StartSound(mobj->target, sfx_gshaf); + } + P_RemoveMobj(mobj); return false; } newHeight = mobj->target->height; - newScale = mobj->target->scale; + newScale = 3 * mobj->target->scale / 2; top = K_GetGardenTop(mobj->target->player); @@ -12229,6 +12307,17 @@ void P_SpawnPlayer(INT32 playernum) K_InitWavedashIndicator(p); K_InitTrickIndicator(p); + for (UINT8 approaches = 0; approaches < 4; approaches++) + { + mobj_t *approach = P_SpawnMobjFromMobj(p->mo, 0, 0, 0, MT_TRIPWIREAPPROACH); + P_SetTarget(&approach->target, p->mo); + approach->extravalue1 = (approaches == 0 || approaches == 2) ? 1 : 0; + approach->extravalue2 = (approaches == 0 || approaches == 1) ? 1 : 0; + approach->renderflags |= approach->extravalue1 ? 0 : RF_HORIZONTALFLIP; + approach->renderflags |= approach->extravalue2 ? 0 : RF_VERTICALFLIP; + } + + if ((gametyperules & GTR_BUMPERS) && !p->spectator) { mobj->health = K_BumpersToHealth(K_StartingBumperCount());