From 4ccb9b22c81d49367375571ecdbf0f77cdf100a2 Mon Sep 17 00:00:00 2001 From: James R Date: Thu, 29 Feb 2024 03:28:49 -0800 Subject: [PATCH 1/8] Ring Shooter: add a 2 second cooldown after respawning before you can touch a Ring Shooter This does not prevent you from using the respawn button to summon a Ring Shooter. - Ring Shooter only tracks the last player who touched it, to prevent that player from reusing it - If another player touches the Ring Shooter, it loses track of the original user - Near a Block Lightsnake waypoint, this would enter an endless loop where both players are able to touch the Ring Shooter and use it to respawn, placing them right above the Ring Shooter (and the cycle repeats) --- src/d_player.h | 1 + src/k_kart.c | 3 +++ src/k_respawn.c | 3 +++ src/p_inter.c | 5 ++++- 4 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/d_player.h b/src/d_player.h index e164e1afe..a9e486825 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -952,6 +952,7 @@ struct player_t UINT16 infinitether; // Generic infinitether time, used for infinitether leniency. UINT8 finalfailsafe; // When you can't Ringshooter, force respawn as a last ditch effort! + UINT8 freeRingShooterCooldown; // Can't use a free Ring Shooter again too soon after respawning. UINT8 lastsafelap; UINT8 lastsafecheatcheck; diff --git a/src/k_kart.c b/src/k_kart.c index 6084a259d..4cb21e27c 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -8738,6 +8738,9 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) player->finalfailsafe = 0; } + if (player->freeRingShooterCooldown && !player->mo->hitlag) + player->freeRingShooterCooldown--; + if (player->superring) { player->nextringaward++; diff --git a/src/k_respawn.c b/src/k_respawn.c index f72cb61e2..3cd82d1d0 100644 --- a/src/k_respawn.c +++ b/src/k_respawn.c @@ -885,6 +885,9 @@ static void K_HandleDropDash(player_t *player) player->respawn.state = RESPAWNST_NONE; player->mo->flags &= ~(MF_NOCLIPTHING); + + // Don't touch another Ring Shooter (still lets you summon a Ring Shooter yourself) + player->freeRingShooterCooldown = 2*TICRATE; } } diff --git a/src/p_inter.c b/src/p_inter.c index f0f953715..11e32dbff 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -915,7 +915,10 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) return; case MT_RINGSHOOTER: - Obj_PlayerUsedRingShooter(special, player); + if (player->freeRingShooterCooldown) + player->pflags |= PF_CASTSHADOW; // you can't use this right now! + else + Obj_PlayerUsedRingShooter(special, player); return; case MT_SUPER_FLICKY: From 3402c3af647cc2d62e9d100f1898a1dee8050479 Mon Sep 17 00:00:00 2001 From: James R Date: Thu, 29 Feb 2024 03:36:04 -0800 Subject: [PATCH 2/8] Polyobjects: add po_movecount member to mobj_t instead of using lastlook - Polyobject carrying set lastlook on mobjs for internal tracking - lastlook is used by some objects to track their own state - Ring Shooter uses lastlook to remember which player summoned it - A Ring Shooter spawned right next to a polyobject would become buggy; If its owner player pressed the respawn button again before the Ring Shooter despawned, that player would be teleported back to the Ring Shooter instead of spawning a new Ring Shooter (which would be the correct behavior) --- src/p_mobj.h | 2 ++ src/p_polyobj.c | 16 ++++------------ 2 files changed, 6 insertions(+), 12 deletions(-) diff --git a/src/p_mobj.h b/src/p_mobj.h index 1e429aa26..1002bac46 100644 --- a/src/p_mobj.h +++ b/src/p_mobj.h @@ -447,6 +447,8 @@ struct mobj_t mobj_t *owner; + INT32 po_movecount; // Polyobject carrying (NOT savegame, NOT Lua) + // WARNING: New fields must be added separately to savegame and Lua. }; diff --git a/src/p_polyobj.c b/src/p_polyobj.c index a27b2d847..021b8520e 100644 --- a/src/p_polyobj.c +++ b/src/p_polyobj.c @@ -879,14 +879,10 @@ static void Polyobj_carryThings(polyobj_t *po, fixed_t dx, fixed_t dy) for (; mo; mo = mo->bnext) { - // lastlook is used by the SPB to determine targets, do not let it affect it - if (mo->type == MT_SPB) + if (mo->po_movecount == pomovecount) continue; - if (mo->lastlook == pomovecount) - continue; - - mo->lastlook = pomovecount; + mo->po_movecount = pomovecount; // Don't scroll objects that aren't affected by gravity if (mo->flags & MF_NOGRAVITY) @@ -1115,14 +1111,10 @@ static void Polyobj_rotateThings(polyobj_t *po, vector2_t origin, angle_t delta, for (; mo; mo = mo->bnext) { - // lastlook is used by the SPB to determine targets, do not let it affect it - if (mo->type == MT_SPB) + if (mo->po_movecount == pomovecount) continue; - if (mo->lastlook == pomovecount) - continue; - - mo->lastlook = pomovecount; + mo->po_movecount = pomovecount; // Don't scroll objects that aren't affected by gravity if (mo->flags & MF_NOGRAVITY) From 4f5063f71f9e5f477e327835b53ae5f286f9f68a Mon Sep 17 00:00:00 2001 From: AJ Martinez Date: Thu, 29 Feb 2024 18:34:36 -0700 Subject: [PATCH 3/8] Fix sliptide extensions activating out of fast drifts --- src/d_player.h | 1 + src/k_kart.c | 27 +++++++++++++++++---------- src/lua_playerlib.c | 2 ++ src/p_saveg.c | 2 ++ 4 files changed, 22 insertions(+), 10 deletions(-) diff --git a/src/d_player.h b/src/d_player.h index 9659340ed..e7beb4e22 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -696,6 +696,7 @@ struct player_t UINT8 gateSound; // Sound effect combo SINT8 aizdriftstrat; // (-1 to 1) - Let go of your drift while boosting? Helper for the SICK STRATZ (sliptiding!) you have just unlocked + SINT8 aizdriftextend; // Nonzero when you were sliptiding last tic, sign indicates direction. INT32 aizdrifttilt; INT32 aizdriftturn; diff --git a/src/k_kart.c b/src/k_kart.c index 0444d3c11..013a6939f 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -10533,20 +10533,21 @@ static void K_KartDrift(player_t *player, boolean onground) // No longer meet the conditions to sliptide? // We'll spot you the sliptide as long as you keep turning, but no charging wavedashes. - boolean keepsliptide = false; + boolean extendedSliptide = false; + // We don't meet sliptide conditions! if ((player->handleboost < (SLIPTIDEHANDLING/2)) || (!player->steering) || (!player->aizdriftstrat) || (player->steering > 0) != (player->aizdriftstrat > 0)) { - if (!player->drift && player->steering && player->aizdriftstrat && player->wavedash // If we were sliptiding last tic, - && (player->steering > 0) == (player->aizdriftstrat > 0) // we're steering in the right direction, + if (!player->drift && player->steering && player->aizdriftextend // If we were sliptiding last tic, + && (player->steering > 0) == (player->aizdriftextend > 0) // we're steering in the right direction, && player->speed >= K_GetKartSpeed(player, false, true)) // and we're above the threshold to spawn dust... { - keepsliptide = true; // Then keep your current sliptide, but note the behavior change for wavedash handling. + extendedSliptide = true; // Then keep your current sliptide, but note the behavior change for wavedash handling. } - else + else // Otherwise, update sliptide status as usual. { if (!player->drift) player->aizdriftstrat = 0; @@ -10558,16 +10559,22 @@ static void K_KartDrift(player_t *player, boolean onground) if (player->airtime > 2) // Arbitrary number. Small discontinuities due to Super Jank shouldn't thrash your handling properties. { player->aizdriftstrat = 0; - keepsliptide = false; + extendedSliptide = false; } + // If we're sliptiding, whether through an extension or otherwise, allow sliptide extensions next tic. + if (K_Sliptiding(player)) + player->aizdriftextend = player->aizdriftstrat; + else + player->aizdriftextend = 0; + if ((player->aizdriftstrat && !player->drift) - || (keepsliptide)) + || (extendedSliptide)) { K_SpawnAIZDust(player); - if (!keepsliptide) + if (!extendedSliptide) { // Give charge proportional to your angle. Sharp turns are rewarding, slow analog slides are not—remember, this is giving back the speed you gave up. UINT16 addCharge = FixedInt( @@ -10605,9 +10612,9 @@ static void K_KartDrift(player_t *player, boolean onground) player->aizdriftstrat = 0; */ - if (!K_Sliptiding(player) || keepsliptide) + if (!K_Sliptiding(player) || extendedSliptide) { - if (!keepsliptide && K_IsLosingWavedash(player) && player->wavedash > 0) + if (!extendedSliptide && K_IsLosingWavedash(player) && player->wavedash > 0) { if (player->wavedash > HIDEWAVEDASHCHARGE && !S_SoundPlaying(player->mo, sfx_waved2)) S_StartSoundAtVolume(player->mo, sfx_waved2, 255); // Losing combo time, going to boost diff --git a/src/lua_playerlib.c b/src/lua_playerlib.c index fbd93153a..d912e1fca 100644 --- a/src/lua_playerlib.c +++ b/src/lua_playerlib.c @@ -287,6 +287,8 @@ static int player_get(lua_State *L) lua_pushinteger(L, plr->gateSound); else if (fastcmp(field,"aizdriftstraft")) lua_pushinteger(L, plr->aizdriftstrat); + else if (fastcmp(field,"aizdriftextend")) + lua_pushinteger(L, plr->aizdriftextend); else if (fastcmp(field,"aizdrifttilt")) lua_pushinteger(L, plr->aizdrifttilt); else if (fastcmp(field,"aizdriftturn")) diff --git a/src/p_saveg.c b/src/p_saveg.c index 8a423f5ec..9c450c667 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -443,6 +443,7 @@ static void P_NetArchivePlayers(savebuffer_t *save) WRITEUINT8(save->p, players[i].gateSound); WRITESINT8(save->p, players[i].aizdriftstrat); + WRITESINT8(save->p, players[i].aizdriftextend); WRITEINT32(save->p, players[i].aizdrifttilt); WRITEINT32(save->p, players[i].aizdriftturn); @@ -1025,6 +1026,7 @@ static void P_NetUnArchivePlayers(savebuffer_t *save) players[i].gateSound = READUINT8(save->p); players[i].aizdriftstrat = READSINT8(save->p); + players[i].aizdriftextend = READSINT8(save->p); players[i].aizdrifttilt = READINT32(save->p); players[i].aizdriftturn = READINT32(save->p); From a87e557e4e545384a9f1a94914e605415214437b Mon Sep 17 00:00:00 2001 From: AJ Martinez Date: Fri, 1 Mar 2024 15:51:18 -0700 Subject: [PATCH 4/8] Immediately update UFO health hum --- src/objects/ufo.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/objects/ufo.c b/src/objects/ufo.c index be59b425e..2c4e280d3 100644 --- a/src/objects/ufo.c +++ b/src/objects/ufo.c @@ -960,6 +960,12 @@ boolean Obj_SpecialUFODamage(mobj_t *ufo, mobj_t *inflictor, mobj_t *source, UIN S_StartSound(ufo, sfx_clawht); S_StopSoundByID(ufo, sfx_clawzm); + + for (int i = 0; i <= maxhum; i++) + { + S_StopSoundByID(ufo, hums[i]); + } + P_StartQuake(10, 64 * ufo->scale, 0, NULL); return true; From 385fc2730353bf1eaf6820b10a507f4ab98fb3af Mon Sep 17 00:00:00 2001 From: AJ Martinez Date: Fri, 1 Mar 2024 15:53:57 -0700 Subject: [PATCH 5/8] Special UFO: Don't wait for hitstop to play new damage hum --- src/objects/ufo.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/objects/ufo.c b/src/objects/ufo.c index 2c4e280d3..e75c823cc 100644 --- a/src/objects/ufo.c +++ b/src/objects/ufo.c @@ -966,6 +966,8 @@ boolean Obj_SpecialUFODamage(mobj_t *ufo, mobj_t *inflictor, mobj_t *source, UIN S_StopSoundByID(ufo, hums[i]); } + UFOUpdateSound(ufo); + P_StartQuake(10, 64 * ufo->scale, 0, NULL); return true; From 20cb01fb940333be3ece12b65a1f36b9ace095bc Mon Sep 17 00:00:00 2001 From: Eidolon Date: Fri, 1 Mar 2024 17:27:41 -0600 Subject: [PATCH 6/8] (demo v9) Demo save unlocks and mapmusrng Fixes KartKrew/Kart#1093 --- src/g_demo.cpp | 29 ++++++++++++++++++++++++++++- src/m_cond.c | 2 +- src/p_setup.cpp | 36 +++++++++++++++++++++++++++--------- 3 files changed, 56 insertions(+), 11 deletions(-) diff --git a/src/g_demo.cpp b/src/g_demo.cpp index fea181a6a..0ce6612ce 100644 --- a/src/g_demo.cpp +++ b/src/g_demo.cpp @@ -110,7 +110,7 @@ demoghost *ghosts = NULL; // DEMO RECORDING // -#define DEMOVERSION 0x0008 +#define DEMOVERSION 0x0009 #define DEMOHEADER "\xF0" "KartReplay" "\x0F" #define DF_ATTACKMASK (ATTACKING_TIME|ATTACKING_LAP|ATTACKING_SPB) // This demo contains time/lap data @@ -2205,6 +2205,18 @@ void G_BeginRecording(void) WRITEUINT8(demobuf.p, grandprixinfo.eventmode); } + // Save netUnlocked from actual unlocks + // (netUnlocked is used in m_cond.c M_CheckNetUnlockByID) + WRITEUINT32(demobuf.p, MAXUNLOCKABLES); + for (size_t unlockindex = 0; unlockindex < MAXUNLOCKABLES; unlockindex++) + { + UINT8 unlock = gamedata->unlocked[unlockindex]; + WRITEUINT8(demobuf.p, unlock); + } + + // Save "mapmusrng" used for altmusic selection + WRITEUINT8(demobuf.p, mapmusrng); + // Now store some info for each in-game player // Lat' 12/05/19: Do note that for the first game you load, everything that gets saved here is total garbage; @@ -3163,6 +3175,21 @@ void G_DoPlayDemo(const char *defdemoname) grandprixinfo.eventmode = static_cast(READUINT8(demobuf.p)); } + // Load unlocks into netUnlocked + { + UINT32 unlockables = READUINT32(demobuf.p); + UINT32 unlocksread = std::min(unlockables, MAXUNLOCKABLES); + for (size_t i = 0; i < unlocksread; i++) + { + netUnlocked[i] = static_cast(READUINT8(demobuf.p)); + } + // skip remainder + demobuf.p += unlockables - unlocksread; + } + + // Load "mapmusrng" used for altmusic selection + mapmusrng = READUINT8(demobuf.p); + // Sigh ... it's an empty demo. if (*demobuf.p == DEMOMARKER) { diff --git a/src/m_cond.c b/src/m_cond.c index a306e4844..345641454 100644 --- a/src/m_cond.c +++ b/src/m_cond.c @@ -3270,7 +3270,7 @@ boolean M_CheckNetUnlockByID(UINT16 unlockid) return true; // default permit } - if (netgame) + if (netgame || demo.playback) { return netUnlocked[unlockid]; } diff --git a/src/p_setup.cpp b/src/p_setup.cpp index 8305d680b..8b195aa46 100644 --- a/src/p_setup.cpp +++ b/src/p_setup.cpp @@ -8177,20 +8177,33 @@ void P_ResetLevelMusic(void) { UINT8 idx = 0; - if (mapheaderinfo[gamemap-1]->musname_size > 1) + mapheader_t* mapheader = mapheaderinfo[gamemap - 1]; + + // To keep RNG in sync, we will always pull from RNG, even if unused + UINT32 random = P_Random(PR_MUSICSELECT); + + if (demo.playback) + { + // mapmusrng has already been set by the demo; just make sure it's valid + if (mapmusrng >= mapheader->musname_size) + { + mapmusrng = 0; + } + return; + } + + if (mapheader->musname_size > 1) { UINT8 tempmapmus[MAXMUSNAMES], tempmapmus_size = 1, i; tempmapmus[0] = 0; - for (i = 1; i < mapheaderinfo[gamemap-1]->musname_size; i++) + for (i = 1; i < mapheader->musname_size; i++) { - if (mapheaderinfo[gamemap-1]->cache_muslock[i-1] < MAXUNLOCKABLES - && !M_CheckNetUnlockByID(mapheaderinfo[gamemap-1]->cache_muslock[i-1])) + if (mapheader->cache_muslock[i-1] < MAXUNLOCKABLES + && !M_CheckNetUnlockByID(mapheader->cache_muslock[i-1])) continue; - //CONS_Printf("TEST - %u\n", i); - tempmapmus[tempmapmus_size++] = i; } @@ -8204,9 +8217,8 @@ void P_ResetLevelMusic(void) } else { - idx = P_RandomKey(PR_MUSICSELECT, tempmapmus_size); + idx = random % tempmapmus_size; } - //CONS_Printf("Rolled position %u, maps to %u\n", mapmusrng, tempmapmus[mapmusrng]); idx = tempmapmus[idx]; } } @@ -8216,7 +8228,13 @@ void P_ResetLevelMusic(void) void P_LoadLevelMusic(void) { - const char *music = mapheaderinfo[gamemap-1]->musname[mapmusrng]; + mapheader_t* mapheader = mapheaderinfo[gamemap-1]; + const char *music = mapheader->musname[0]; + + if (mapmusrng < mapheader->musname_size) + { + music = mapheader->musname[mapmusrng]; + } if (gametyperules & GTR_NOPOSITION || modeattacking != ATTACKING_NONE) { From ad538b3bb939329dc714b50e0a187e997db79f54 Mon Sep 17 00:00:00 2001 From: Eidolon Date: Fri, 1 Mar 2024 17:38:22 -0600 Subject: [PATCH 7/8] Fix returning to menu after TA replay --- src/g_demo.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/g_demo.cpp b/src/g_demo.cpp index 0ce6612ce..56a0f83e9 100644 --- a/src/g_demo.cpp +++ b/src/g_demo.cpp @@ -3938,11 +3938,12 @@ boolean G_CheckDemoStatus(void) G_FinishExitLevel(); else { + UINT8 wasmodeattacking = modeattacking; G_StopDemo(); if (timedemo_quit) COM_ImmedExecute("quit"); - else if (modeattacking) + else if (wasmodeattacking) M_EndModeAttackRun(); else if (demo.attract == DEMO_ATTRACT_CREDITS) F_ContinueCredits(); From 0d417a5055399f719df930907e2c348347fb5e0a Mon Sep 17 00:00:00 2001 From: AJ Martinez Date: Fri, 1 Mar 2024 18:36:19 -0700 Subject: [PATCH 8/8] Use guard break sound for Special UFO destruction --- src/objects/ufo.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/objects/ufo.c b/src/objects/ufo.c index e75c823cc..2a2148088 100644 --- a/src/objects/ufo.c +++ b/src/objects/ufo.c @@ -951,6 +951,7 @@ boolean Obj_SpecialUFODamage(mobj_t *ufo, mobj_t *inflictor, mobj_t *source, UIN ACS_RunCatcherScript(source); S_StopSound(ufo); + S_StartSound(ufo, sfx_gbrk); S_StartSound(ufo, sfx_clawk2); P_StartQuake(20, 64 * ufo->scale, 0, NULL);