From 9eeb583670c5a87bf66884e020ce004953c3df30 Mon Sep 17 00:00:00 2001 From: James R Date: Fri, 8 Mar 2024 00:24:41 -0800 Subject: [PATCH 01/26] Menus: fix multi-line message box text not fitting in the box --- src/k_menudraw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/k_menudraw.c b/src/k_menudraw.c index 666add657..9099279e8 100644 --- a/src/k_menudraw.c +++ b/src/k_menudraw.c @@ -918,7 +918,7 @@ void M_DrawMenuMessage(void) } V_DrawString((BASEVIDWIDTH - V_StringWidth(string, 0))/2, y, 0, string); - y += 9; + y += 8; } } From 7305afa5ea94dffcdd5e71eb0533c59cb4fc8f3e Mon Sep 17 00:00:00 2001 From: James R Date: Fri, 8 Mar 2024 04:52:03 -0800 Subject: [PATCH 02/26] D_ProcessEvents: fix old input events repeating themselves when pressing Y button in Time Attack --- src/d_main.cpp | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/d_main.cpp b/src/d_main.cpp index 9d1b25edb..3eafa8c67 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -272,9 +272,19 @@ void D_ProcessEvents(boolean callresponders) boolean eaten; G_ResetAllDeviceResponding(); - for (; eventtail != eventhead; eventtail = (eventtail+1) & (MAXEVENTS-1)) + + // Save these in local variables because eventtail != + // eventhead was evaluating true when they were equal, + // but only when using the Y button to restart a Time + // Attack?? + INT32 tail = eventtail; + INT32 head = eventhead; + + eventtail = eventhead; + + for (; tail != head; tail = (tail+1) & (MAXEVENTS-1)) { - ev = &events[eventtail]; + ev = &events[tail]; HandleGamepadDeviceEvents(ev); From 061e3c282c1a43800eb95393233f93aa86f7f9e6 Mon Sep 17 00:00:00 2001 From: James R Date: Fri, 8 Mar 2024 06:07:15 -0800 Subject: [PATCH 03/26] Broly: fix underflow on remaining timer - Fix Fuel Canister setting player's hitlag to -1, causing SPB to stop thinking --- src/objects/broly.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/objects/broly.hpp b/src/objects/broly.hpp index d75a7fc4b..64f7f58da 100644 --- a/src/objects/broly.hpp +++ b/src/objects/broly.hpp @@ -44,7 +44,7 @@ struct Broly : Mobj bool valid() const { return duration(); } - tic_t remaining() const { return tics - kBufferTics; } + tic_t remaining() const { return tics > kBufferTics ? tics - kBufferTics : 0u; } Fixed linear() const { return (remaining() * FRACUNIT) / duration(); } From 9c436763c2b3ce39dc7afa416fd1370914bbd47b Mon Sep 17 00:00:00 2001 From: James R Date: Fri, 8 Mar 2024 06:10:43 -0800 Subject: [PATCH 04/26] SPB: only stop thinking if chase targt hitlag is >0 - Mobjs only actually freeze if hitlag >0 - This will probably stop something like 061e3c282 happening to SPB again --- src/objects/spb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/objects/spb.c b/src/objects/spb.c index 89ac8f174..2c0d51fa9 100644 --- a/src/objects/spb.c +++ b/src/objects/spb.c @@ -679,7 +679,7 @@ static void SPBChase(mobj_t *spb, mobj_t *bestMobj) return; } - if (chase->hitlag) + if (chase->hitlag > 0) { // If the player is frozen, the SPB should be too. spb->hitlag = max(spb->hitlag, chase->hitlag); From 0ce209428fbfea03823b4afeb90ea499b3f69146 Mon Sep 17 00:00:00 2001 From: James R Date: Fri, 8 Mar 2024 06:29:12 -0800 Subject: [PATCH 05/26] Respawn manual drop: check e-brake inputs directly instead of whether player can e-brake --- src/k_respawn.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/k_respawn.c b/src/k_respawn.c index 3cd82d1d0..8196c438b 100644 --- a/src/k_respawn.c +++ b/src/k_respawn.c @@ -556,7 +556,7 @@ static void K_MovePlayerToRespawnPoint(player_t *player) if (player->respawn.init == false && player->respawn.fromRingShooter == false - && K_PlayerEBrake(player) == true) + && K_PressingEBrake(player) == true) { // Manual drop! player->respawn.state = RESPAWNST_DROP; From 21f7f277351edf3c90de62e5f39516beba9881a7 Mon Sep 17 00:00:00 2001 From: James R Date: Fri, 8 Mar 2024 07:36:56 -0800 Subject: [PATCH 06/26] Battle: measure overtime barrier radius by minimap corners, instead of edges --- src/p_inter.c | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/src/p_inter.c b/src/p_inter.c index 048034486..aa77ea26c 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -1362,8 +1362,6 @@ void P_CheckTimeLimit(void) thinker_t *th; mobj_t *center = NULL; - fixed_t rx, ry; - for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next) { mobj_t *thismo; @@ -1397,18 +1395,17 @@ void P_CheckTimeLimit(void) // Get largest radius from center point to minimap edges - rx = max( - abs(battleovertime.x - (minimapinfo.min_x * FRACUNIT)), - abs(battleovertime.x - (minimapinfo.max_x * FRACUNIT)) - ); - - ry = max( - abs(battleovertime.y - (minimapinfo.min_y * FRACUNIT)), - abs(battleovertime.y - (minimapinfo.max_y * FRACUNIT)) - ); + fixed_t r = 0; + fixed_t n; +#define corner(px, py) ((n = FixedHypot(battleovertime.x - (px), battleovertime.y - (py))), r = max(r, n)) + corner(minimapinfo.min_x * FRACUNIT, minimapinfo.min_y * FRACUNIT); + corner(minimapinfo.min_x * FRACUNIT, minimapinfo.max_y * FRACUNIT); + corner(minimapinfo.max_x * FRACUNIT, minimapinfo.min_y * FRACUNIT); + corner(minimapinfo.max_x * FRACUNIT, minimapinfo.max_y * FRACUNIT); +#undef corner battleovertime.initial_radius = min( - max(max(rx, ry), 4096 * mapobjectscale), + max(r, 4096 * mapobjectscale), // Prevent overflow in K_RunBattleOvertime FixedDiv(INT32_MAX, M_PI_FIXED) / 2 ); From a23a632082b1cfa331ffcef97f7c2597053053af Mon Sep 17 00:00:00 2001 From: James R Date: Fri, 8 Mar 2024 08:10:09 -0800 Subject: [PATCH 07/26] Sealed Star Window: make light rays noclip, so they are not offset by level geometry --- src/info.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/info.c b/src/info.c index 6aa10a510..6bf1a02b6 100644 --- a/src/info.c +++ b/src/info.c @@ -21532,7 +21532,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 0, // mass 0, // damage sfx_None, // activesound - MF_SCENERY|MF_NOGRAVITY|MF_NOCLIP, // flags + MF_SCENERY|MF_NOGRAVITY|MF_NOCLIP|MF_NOCLIPHEIGHT, // flags S_NULL // raisestate }, { // MT_SSCHAINSOUND From 36a1fd15f3012134f13ee4208678e63207dc695c Mon Sep 17 00:00:00 2001 From: James R Date: Fri, 8 Mar 2024 08:19:07 -0800 Subject: [PATCH 08/26] Audience: scale jump height to map scale, not audience scale --- src/objects/audience.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/objects/audience.c b/src/objects/audience.c index b5814ae16..9558dfe9f 100644 --- a/src/objects/audience.c +++ b/src/objects/audience.c @@ -123,11 +123,11 @@ Obj_AudienceInit // The following is derived from the default bobamp if (mobj->type != MT_EMBLEM && !(mobj->flags & MF_NOGRAVITY) && followers[followerpick].bobamp < 4*FRACUNIT) { - audience_bobamp(mobj) = 4*mobj->scale; + audience_bobamp(mobj) = 4*mapobjectscale; } else { - audience_bobamp(mobj) = FixedMul(mobj->scale, followers[followerpick].bobamp); + audience_bobamp(mobj) = FixedMul(mapobjectscale, followers[followerpick].bobamp); } } From 3aee4b1ac28957ca2ffcbc6deef3704084affde6 Mon Sep 17 00:00:00 2001 From: James R Date: Fri, 8 Mar 2024 08:29:23 -0800 Subject: [PATCH 09/26] Add Z height check to glancing --- src/k_kart.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/k_kart.c b/src/k_kart.c index 97a6bef56..4e1526140 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -2212,6 +2212,7 @@ static SINT8 K_GlanceAtPlayers(player_t *glancePlayer, boolean horn) if (!podiumspecial) { distance = R_PointToDist2(glancePlayer->mo->x, glancePlayer->mo->y, victim->x, victim->y); + distance = R_PointToDist2(0, glancePlayer->mo->z, distance, victim->z); if (distance > maxdistance) { From a06bfea4eb75967d8f01d7ace4d2674aa0edd69a Mon Sep 17 00:00:00 2001 From: Eidolon Date: Fri, 8 Mar 2024 14:26:46 -0600 Subject: [PATCH 10/26] Fix interpolation of ring debt indicator --- src/k_kart.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/k_kart.c b/src/k_kart.c index 97a6bef56..85c8978c8 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -8435,6 +8435,10 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) mobj_t *debtflag = P_SpawnMobj(player->mo->x + player->mo->momx, player->mo->y + player->mo->momy, player->mo->z + P_GetMobjZMovement(player->mo) + player->mo->height + (24*player->mo->scale), MT_THOK); + debtflag->old_x = player->mo->old_x; + debtflag->old_y = player->mo->old_y; + debtflag->old_z = player->mo->old_z + P_GetMobjZMovement(player->mo) + player->mo->height + (24*player->mo->scale); + P_SetMobjState(debtflag, S_RINGDEBT); P_SetScale(debtflag, (debtflag->destscale = player->mo->scale)); From 19418ff1a63b9d80632205c4d7788c4d4822dcd2 Mon Sep 17 00:00:00 2001 From: James R Date: Thu, 7 Mar 2024 00:23:12 -0800 Subject: [PATCH 11/26] Power-ups: play loud Gunstar pickup sound --- src/k_powerup.cpp | 2 +- src/sounds.c | 1 + src/sounds.h | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/k_powerup.cpp b/src/k_powerup.cpp index 8bc504cbc..e4827a230 100644 --- a/src/k_powerup.cpp +++ b/src/k_powerup.cpp @@ -54,7 +54,7 @@ void K_GivePowerUp(player_t* player, kartitems_t powerup, tic_t time) Obj_SpawnPowerUpAura(player); } - S_StartSound(NULL, sfx_gsha7); + S_StartSound(NULL, sfx_gsha7l); player->flashing = 2*TICRATE; K_AddHitLag(player->mo, BATTLE_POWERUP_VFX_TIME, false); player->powerupVFXTimer = BATTLE_POWERUP_VFX_TIME; diff --git a/src/sounds.c b/src/sounds.c index ffe57da83..d1e4a7f65 100644 --- a/src/sounds.c +++ b/src/sounds.c @@ -1420,6 +1420,7 @@ sfxinfo_t S_sfx[NUMSFX] = {"gsha5", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, {"gsha6", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, {"gsha7", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"gsha7l",false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, {"gsha8", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, {"gsha9", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, {"gshaa", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, diff --git a/src/sounds.h b/src/sounds.h index 4a7c0bfc7..86f012c11 100644 --- a/src/sounds.h +++ b/src/sounds.h @@ -1496,6 +1496,7 @@ typedef enum sfx_gsha5, sfx_gsha6, sfx_gsha7, + sfx_gsha7l, sfx_gsha8, sfx_gsha9, sfx_gshaa, From f7d396d150b3f0ec5162a425adecdc33760c32be Mon Sep 17 00:00:00 2001 From: James R Date: Thu, 7 Mar 2024 00:33:43 -0800 Subject: [PATCH 12/26] Power-ups: spawn spinning power-up icon on player - Spins for 40 tics, speeds up over duration - Starts wide stretched, ends thin and tall - Additive, fades into translucency --- src/deh_tables.c | 1 + src/info.c | 27 +++++++++++++ src/info.h | 1 + src/k_objects.h | 4 ++ src/k_powerup.cpp | 1 + src/objects/CMakeLists.txt | 1 + src/objects/powerup-spinner.cpp | 70 +++++++++++++++++++++++++++++++++ src/p_mobj.c | 5 +++ 8 files changed, 110 insertions(+) create mode 100644 src/objects/powerup-spinner.cpp diff --git a/src/deh_tables.c b/src/deh_tables.c index 5bd5700f9..513a50c46 100644 --- a/src/deh_tables.c +++ b/src/deh_tables.c @@ -3455,6 +3455,7 @@ const char *const MOBJTYPE_LIST[] = { // array length left dynamic for sanity t "MT_RANDOMITEM", "MT_SPHEREBOX", "MT_FLOATINGITEM", + "MT_GOTPOWERUP", "MT_ITEMCAPSULE", "MT_ITEMCAPSULE_PART", "MT_MONITOR", diff --git a/src/info.c b/src/info.c index 6aa10a510..d48a3debd 100644 --- a/src/info.c +++ b/src/info.c @@ -13188,6 +13188,33 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL // raisestate }, + { // MT_GOTPOWERUP + -1, // doomednum + S_ITEMICON, // spawnstate + 1, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 0, // 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_itpick, // deathsound + 0, // speed + 48*FRACUNIT, // radius + 64*FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SCENERY|MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOSQUISH|MF_DONTENCOREMAP, // flags + S_NULL // raisestate + }, + { // MT_ITEMCAPSULE 2010, // doomednum S_ITEMCAPSULE, // spawnstate diff --git a/src/info.h b/src/info.h index 3b26cfefc..442581ac8 100644 --- a/src/info.h +++ b/src/info.h @@ -4475,6 +4475,7 @@ typedef enum mobj_type MT_RANDOMITEM, MT_SPHEREBOX, MT_FLOATINGITEM, + MT_GOTPOWERUP, MT_ITEMCAPSULE, MT_ITEMCAPSULE_PART, MT_MONITOR, diff --git a/src/k_objects.h b/src/k_objects.h index 93e6692d0..ee1a24290 100644 --- a/src/k_objects.h +++ b/src/k_objects.h @@ -398,6 +398,10 @@ void Obj_TalkPointInit(mobj_t* mo); void Obj_TalkPointThink(mobj_t* mo); void Obj_TalkPointOrbThink(mobj_t* mo); +/* Power-up Spinner */ +void Obj_SpawnPowerUpSpinner(mobj_t *source, INT32 powerup, tic_t duration); +void Obj_TickPowerUpSpinner(mobj_t *mobj); + #ifdef __cplusplus } // extern "C" #endif diff --git a/src/k_powerup.cpp b/src/k_powerup.cpp index e4827a230..da40ca68f 100644 --- a/src/k_powerup.cpp +++ b/src/k_powerup.cpp @@ -58,6 +58,7 @@ void K_GivePowerUp(player_t* player, kartitems_t powerup, tic_t time) player->flashing = 2*TICRATE; K_AddHitLag(player->mo, BATTLE_POWERUP_VFX_TIME, false); player->powerupVFXTimer = BATTLE_POWERUP_VFX_TIME; + Obj_SpawnPowerUpSpinner(player->mo, powerup, BATTLE_POWERUP_VFX_TIME); g_darkness.start = leveltime; g_darkness.end = leveltime + BATTLE_POWERUP_VFX_TIME + DARKNESS_FADE_TIME; diff --git a/src/objects/CMakeLists.txt b/src/objects/CMakeLists.txt index fce16395a..0dde3da9f 100644 --- a/src/objects/CMakeLists.txt +++ b/src/objects/CMakeLists.txt @@ -54,6 +54,7 @@ target_sources(SRB2SDL2 PRIVATE waterfall-particle.c sealed-star.c talk-point.cpp + powerup-spinner.cpp ) add_subdirectory(versus) diff --git a/src/objects/powerup-spinner.cpp b/src/objects/powerup-spinner.cpp new file mode 100644 index 000000000..d709b1a0e --- /dev/null +++ b/src/objects/powerup-spinner.cpp @@ -0,0 +1,70 @@ +// DR. ROBOTNIK'S RING RACERS +//----------------------------------------------------------------------------- +// Copyright (C) 2024 by James Robert Roman +// +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. +//----------------------------------------------------------------------------- + +#include + +#include "objects.hpp" + +#include "../m_easing.h" +#include "../m_fixed.h" +#include "../tables.h" + +using namespace srb2::objects; + +namespace +{ + +struct Spinner : Mobj +{ + static constexpr int kDuration = 40; + + void extravalue1() = delete; + INT32 powerup() const { return mobj_t::extravalue1; } + void powerup(INT32 n) { mobj_t::extravalue1 = n; } + + void extravalue2() = delete; + INT32 duration() const { return mobj_t::extravalue2; } + void duration(INT32 n) { mobj_t::extravalue2 = n; } + + static void spawn(Mobj* source, INT32 powerup, tic_t duration) + { + Spinner* x = Mobj::spawn(source->pos(), MT_GOTPOWERUP); + K_UpdateMobjItemOverlay(x, powerup, 1); + x->frame |= FF_PAPERSPRITE | FF_ADD; + x->fuse = duration; + x->powerup(powerup); + x->duration(duration); + } + + void think() + { + fixed_t f = FRACUNIT - std::clamp(fuse, 0, duration()) * FRACUNIT / std::max(duration(), 1); + + angle += Easing_InQuad(f, ANGLE_11hh, ANGLE_45); + renderflags = (renderflags & ~RF_TRANSMASK) | (Easing_Linear(f, 0, 9) << RF_TRANSSHIFT); + spritescale({Easing_Linear(f, 4*FRACUNIT, FRACUNIT/4), Easing_Linear(f, FRACUNIT, 6*FRACUNIT)}); + + if (--fuse <= 0) + { + remove(); + } + } +}; + +}; // namespace + +void Obj_SpawnPowerUpSpinner(mobj_t *source, INT32 powerup, tic_t duration) +{ + Spinner::spawn(static_cast(source), powerup, duration); +} + +void Obj_TickPowerUpSpinner(mobj_t *mobj) +{ + static_cast(mobj)->think(); +} diff --git a/src/p_mobj.c b/src/p_mobj.c index 497275b93..488193e3a 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -6596,6 +6596,11 @@ static void P_MobjSceneryThink(mobj_t *mobj) Obj_SSGobletMobjThink(mobj); return; } + case MT_GOTPOWERUP: + { + Obj_TickPowerUpSpinner(mobj); + return; + } default: if (mobj->fuse) { // Scenery object fuse! Very basic! From 549865ce2d17bc3fce00a2d5d50432a0d8563097 Mon Sep 17 00:00:00 2001 From: James R Date: Thu, 7 Mar 2024 00:35:02 -0800 Subject: [PATCH 13/26] Power-ups: delay voice clips by 10 tics --- src/k_powerup.cpp | 6 ------ src/objects/powerup-spinner.cpp | 27 +++++++++++++++++++++++++++ 2 files changed, 27 insertions(+), 6 deletions(-) diff --git a/src/k_powerup.cpp b/src/k_powerup.cpp index da40ca68f..9e8203c12 100644 --- a/src/k_powerup.cpp +++ b/src/k_powerup.cpp @@ -66,33 +66,28 @@ void K_GivePowerUp(player_t* player, kartitems_t powerup, tic_t time) switch (powerup) { case POWERUP_SMONITOR: - S_StartSound(NULL, sfx_bpwrua); K_AddMessageForPlayer(player, "Got S MONITOR!", true, false); K_DoInvincibility(player, player->invincibilitytimer + time); player->powerup.superTimer += time; break; case POWERUP_BARRIER: - S_StartSound(NULL, sfx_bpwrub); K_AddMessageForPlayer(player, "Got MEGA BARRIER!", true, false); player->powerup.barrierTimer += time; Obj_SpawnMegaBarrier(player); break; case POWERUP_BUMPER: - S_StartSound(NULL, sfx_bpwruc); K_AddMessageForPlayer(player, "Got BUMPER RESTOCK!", true, false); K_GiveBumpersToPlayer(player, nullptr, 5); break; case POWERUP_BADGE: - S_StartSound(NULL, sfx_bpwrud); K_AddMessageForPlayer(player, "Got RHYTHM BADGE!", true, false); player->powerup.rhythmBadgeTimer += time; break; case POWERUP_SUPERFLICKY: - S_StartSound(NULL, sfx_bpwrue); K_AddMessageForPlayer(player, "Got SUPER FLICKY!", true, false); if (K_PowerUpRemaining(player, POWERUP_SUPERFLICKY)) { @@ -105,7 +100,6 @@ void K_GivePowerUp(player_t* player, kartitems_t powerup, tic_t time) break; case POWERUP_POINTS: - S_StartSound(NULL, sfx_bpwruf); K_AddMessageForPlayer(player, "Got 6 POINTS!", true, false); K_GivePointsToPlayer(player, nullptr, 6); diff --git a/src/objects/powerup-spinner.cpp b/src/objects/powerup-spinner.cpp index d709b1a0e..248a95b69 100644 --- a/src/objects/powerup-spinner.cpp +++ b/src/objects/powerup-spinner.cpp @@ -46,6 +46,11 @@ struct Spinner : Mobj { fixed_t f = FRACUNIT - std::clamp(fuse, 0, duration()) * FRACUNIT / std::max(duration(), 1); + if (fuse == duration() - 20) + { + S_StartSound(nullptr, sound()); + } + angle += Easing_InQuad(f, ANGLE_11hh, ANGLE_45); renderflags = (renderflags & ~RF_TRANSMASK) | (Easing_Linear(f, 0, 9) << RF_TRANSSHIFT); spritescale({Easing_Linear(f, 4*FRACUNIT, FRACUNIT/4), Easing_Linear(f, FRACUNIT, 6*FRACUNIT)}); @@ -55,6 +60,28 @@ struct Spinner : Mobj remove(); } } + +private: + sfxenum_t sound() const + { + switch (powerup()) + { + case POWERUP_SMONITOR: + return sfx_bpwrua; + case POWERUP_BARRIER: + return sfx_bpwrub; + case POWERUP_BUMPER: + return sfx_bpwruc; + case POWERUP_BADGE: + return sfx_bpwrud; + case POWERUP_SUPERFLICKY: + return sfx_bpwrue; + case POWERUP_POINTS: + return sfx_bpwruf; + default: + return sfx_thok; + } + } }; }; // namespace From 0707c9e5ec07d775caa1a7a2d497a2be4bf6dc70 Mon Sep 17 00:00:00 2001 From: James R Date: Thu, 7 Mar 2024 00:37:06 -0800 Subject: [PATCH 14/26] Add g_musicfade, generic system to fade out the level music for a brief period --- src/doomstat.h | 6 ++++++ src/g_game.c | 1 + src/k_kart.c | 1 + src/p_saveg.c | 10 ++++++++++ src/p_tick.c | 17 +++++++++++++++++ src/typedef.h | 1 + 6 files changed, 36 insertions(+) diff --git a/src/doomstat.h b/src/doomstat.h index c74dda7ac..ce0782cd9 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -811,6 +811,12 @@ extern struct darkness_t fixed_t value[MAXSPLITSCREENPLAYERS]; } g_darkness; +extern struct musicfade_t +{ + tic_t start, end, fade; + boolean ticked; +} g_musicfade; + #define DEFAULT_GRAVITY (4*FRACUNIT/5) extern fixed_t gravity; extern fixed_t mapobjectscale; diff --git a/src/g_game.c b/src/g_game.c index 4a4d25f1a..5d181a536 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -279,6 +279,7 @@ tic_t racecountdown, exitcountdown, musiccountdown; // for racing exitcondition_t g_exit; darkness_t g_darkness; +musicfade_t g_musicfade; fixed_t gravity; fixed_t mapobjectscale; diff --git a/src/k_kart.c b/src/k_kart.c index 97a6bef56..d3f5f757a 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -118,6 +118,7 @@ void K_TimerReset(void) { starttime = introtime = 0; memset(&g_darkness, 0, sizeof g_darkness); + memset(&g_musicfade, 0, sizeof g_musicfade); numbulbs = 1; inDuel = rainbowstartavailable = false; linecrossed = 0; diff --git a/src/p_saveg.c b/src/p_saveg.c index b89ee4412..8a1956ba4 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -6567,6 +6567,11 @@ static void P_NetArchiveMisc(savebuffer_t *save, boolean resending) WRITEUINT32(save->p, g_darkness.start); WRITEUINT32(save->p, g_darkness.end); + WRITEUINT32(save->p, g_musicfade.start); + WRITEUINT32(save->p, g_musicfade.end); + WRITEUINT32(save->p, g_musicfade.fade); + WRITEUINT8(save->p, g_musicfade.ticked); + WRITEUINT16(save->p, numchallengedestructibles); // Is it paused? @@ -6753,6 +6758,11 @@ static boolean P_NetUnArchiveMisc(savebuffer_t *save, boolean reloading) g_darkness.start = READUINT32(save->p); g_darkness.end = READUINT32(save->p); + g_musicfade.start = READUINT32(save->p); + g_musicfade.end = READUINT32(save->p); + g_musicfade.fade = READUINT32(save->p); + g_musicfade.ticked = READUINT8(save->p); + numchallengedestructibles = READUINT16(save->p); // Is it paused? diff --git a/src/p_tick.c b/src/p_tick.c index 9f0b33da7..bc78f291a 100644 --- a/src/p_tick.c +++ b/src/p_tick.c @@ -808,6 +808,22 @@ static void P_TickDarkness(void) } } +static void P_TickMusicFade(void) +{ + if (leveltime >= g_musicfade.start && leveltime <= g_musicfade.end) + { + INT32 half = (g_musicfade.end - g_musicfade.start) / 2; + INT32 fade = max(1, g_musicfade.fade); + INT32 mid = half - fade; + INT32 t = abs((INT32)leveltime - (INT32)(g_musicfade.start + half)); + Music_LevelVolume((max(t, mid) - mid) * 100 / fade); + } + else if (!g_musicfade.ticked) + Music_LevelVolume(100); + + g_musicfade.ticked = true; +} + // // P_Ticker // @@ -1102,6 +1118,7 @@ void P_Ticker(boolean run) racecountdown--; P_TickDarkness(); + P_TickMusicFade(); if (exitcountdown >= 1) { diff --git a/src/typedef.h b/src/typedef.h index e866a22a9..ac9bbff5f 100644 --- a/src/typedef.h +++ b/src/typedef.h @@ -143,6 +143,7 @@ TYPEDEF (cupheader_t); TYPEDEF (unloaded_cupheader_t); TYPEDEF (exitcondition_t); TYPEDEF (darkness_t); +TYPEDEF (musicfade_t); // font.h TYPEDEF (font_t); From 215446f42ad0ca44124db5048b7ae8cd56329e30 Mon Sep 17 00:00:00 2001 From: James R Date: Thu, 7 Mar 2024 00:37:41 -0800 Subject: [PATCH 15/26] Power-ups: fade out level music while voice clip is playing --- src/k_powerup.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/k_powerup.cpp b/src/k_powerup.cpp index 9e8203c12..90cec3f4e 100644 --- a/src/k_powerup.cpp +++ b/src/k_powerup.cpp @@ -63,6 +63,11 @@ void K_GivePowerUp(player_t* player, kartitems_t powerup, tic_t time) g_darkness.start = leveltime; g_darkness.end = leveltime + BATTLE_POWERUP_VFX_TIME + DARKNESS_FADE_TIME; + g_musicfade.start = leveltime; + g_musicfade.end = g_musicfade.start + 90; + g_musicfade.fade = 20; + g_musicfade.ticked = false; + switch (powerup) { case POWERUP_SMONITOR: From e4f5e3c78e31c8e906ef906a6093231e02af0348 Mon Sep 17 00:00:00 2001 From: James R Date: Thu, 7 Mar 2024 02:25:33 -0800 Subject: [PATCH 16/26] P_CheckBumpers: do not end round with 1 player - Fixes round ending instantly when warping to Battle with 1 human player and at least 1 other bot loaded --- src/k_battle.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/k_battle.c b/src/k_battle.c index d08fcee2c..ffd370ee2 100644 --- a/src/k_battle.c +++ b/src/k_battle.c @@ -175,7 +175,8 @@ void K_CheckBumpers(void) { // If every other player is eliminated, the // last player standing wins by default. - K_EndBattleRound(kingofthehill != -1 ? &players[kingofthehill] : NULL); + if (numingame > 1) + K_EndBattleRound(kingofthehill != -1 ? &players[kingofthehill] : NULL); return; } From a7979e973e689fc846bd86a510790ce92d4cd5db Mon Sep 17 00:00:00 2001 From: James R Date: Thu, 7 Mar 2024 02:27:19 -0800 Subject: [PATCH 17/26] Battle: cap lasers at player's last known floorz - Do not use camera_t.floorz - Fixes lasers bobbing up and down sometimes --- src/k_battle.c | 4 ++-- src/p_local.h | 4 ++++ src/p_user.c | 5 +++++ 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/k_battle.c b/src/k_battle.c index ffd370ee2..5d284bb77 100644 --- a/src/k_battle.c +++ b/src/k_battle.c @@ -654,12 +654,12 @@ static void K_SpawnOvertimeLaser(fixed_t x, fixed_t y, fixed_t scale) if (player->mo->eflags & MFE_VERTICALFLIP) { zpos = cam->z + player->mo->height; - zpos = min(zpos + heightPadding, cam->ceilingz); + zpos = min(zpos + heightPadding, cam->centerceilingz); } else { zpos = cam->z; - zpos = max(zpos - heightPadding, cam->floorz); + zpos = max(zpos - heightPadding, cam->centerfloorz); } flip = P_MobjFlip(player->mo); diff --git a/src/p_local.h b/src/p_local.h index f36337615..c9e1860c1 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -112,6 +112,10 @@ struct camera_t fixed_t floorz; fixed_t ceilingz; + // From the player + fixed_t centerfloorz; + fixed_t centerceilingz; + // For movement checking. fixed_t radius; fixed_t height; diff --git a/src/p_user.c b/src/p_user.c index 1fdafd4aa..de8c4234e 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -3053,6 +3053,8 @@ void P_ResetCamera(player_t *player, camera_t *thiscam) thiscam->x = x; thiscam->y = y; thiscam->z = z; + thiscam->centerfloorz = player->mo->floorz; + thiscam->centerceilingz = player->mo->ceilingz; thiscam->angle = player->mo->angle; thiscam->aiming = 0; @@ -3570,6 +3572,9 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall R_ResetViewInterpolation(num + 1); } + thiscam->centerfloorz = mo->floorz; + thiscam->centerceilingz = mo->ceilingz; + return (x == thiscam->x && y == thiscam->y && z == thiscam->z && angle == thiscam->aiming); } From d35edcac9c6b5b37010c2be16de18fdc3905b6ef Mon Sep 17 00:00:00 2001 From: James R Date: Thu, 7 Mar 2024 03:15:56 -0800 Subject: [PATCH 18/26] Invinc, Grow: fade with in-level music volume Fade S-Monitor music with voice clip --- src/music.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/music.cpp b/src/music.cpp index 953f20071..7205c2535 100644 --- a/src/music.cpp +++ b/src/music.cpp @@ -71,6 +71,7 @@ void Music_Init(void) tune.song = "kgrow"; tune.priority = 20; tune.resume_fade_in = 200; + tune.use_level_volume = true; } { @@ -78,6 +79,7 @@ void Music_Init(void) tune.song = "kinvnc"; tune.priority = 21; + tune.use_level_volume = true; } { From 79177f6aff46cf19c4884c1452f1ca695cc0ad9c Mon Sep 17 00:00:00 2001 From: James R Date: Thu, 7 Mar 2024 07:22:13 -0800 Subject: [PATCH 19/26] Power-ups: fix HUD not sliding away on tally --- src/hud/powerup.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/hud/powerup.cpp b/src/hud/powerup.cpp index 5861791be..449236099 100644 --- a/src/hud/powerup.cpp +++ b/src/hud/powerup.cpp @@ -1,3 +1,12 @@ +// DR. ROBOTNIK'S RING RACERS +//----------------------------------------------------------------------------- +// Copyright (C) 2023-2024 by Kart Krew. +// +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. +//----------------------------------------------------------------------------- + #include #include @@ -81,7 +90,7 @@ void K_drawKartPowerUps(void) { auto make_drawer = [](int x, int y, Draw::Font font) -> Draw { - return Draw(x, y).font(font).align(Draw::Align::kRight); + return Draw(x, y).font(font).align(Draw::Align::kRight).flags(V_SLIDEIN); }; const int viewnum = R_GetViewNumber(); From 80a65cd61ffe2679501925f5da9b109f6b18fc82 Mon Sep 17 00:00:00 2001 From: James R Date: Thu, 7 Mar 2024 07:44:32 -0800 Subject: [PATCH 20/26] Do not Guard-Break player in power-up collect animation --- 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 d3f5f757a..32c72b807 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -1016,7 +1016,8 @@ boolean K_KartBouncing(mobj_t *mobj1, mobj_t *mobj2) K_SpawnBumpForObjs(mobj1, mobj2); - if (mobj1->type == MT_PLAYER && mobj2->type == MT_PLAYER) + if (mobj1->type == MT_PLAYER && mobj2->type == MT_PLAYER + && !mobj1->player->powerupVFXTimer && !mobj2->player->powerupVFXTimer) { boolean guard1 = K_PlayerGuard(mobj1->player); boolean guard2 = K_PlayerGuard(mobj2->player); From 54240ac96b2c746405cc52d2888022f2d2ea1516 Mon Sep 17 00:00:00 2001 From: James R Date: Thu, 7 Mar 2024 07:46:26 -0800 Subject: [PATCH 21/26] Power-ups: always give player consistent hitlag on collect, even if they are near MAXHITLAGTICS --- src/k_powerup.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/k_powerup.cpp b/src/k_powerup.cpp index 90cec3f4e..b2f7c720e 100644 --- a/src/k_powerup.cpp +++ b/src/k_powerup.cpp @@ -56,7 +56,7 @@ void K_GivePowerUp(player_t* player, kartitems_t powerup, tic_t time) S_StartSound(NULL, sfx_gsha7l); player->flashing = 2*TICRATE; - K_AddHitLag(player->mo, BATTLE_POWERUP_VFX_TIME, false); + player->mo->hitlag += BATTLE_POWERUP_VFX_TIME; player->powerupVFXTimer = BATTLE_POWERUP_VFX_TIME; Obj_SpawnPowerUpSpinner(player->mo, powerup, BATTLE_POWERUP_VFX_TIME); From 6993f12dff9634bc35caa1562865c780159b8143 Mon Sep 17 00:00:00 2001 From: James R Date: Thu, 7 Mar 2024 00:40:24 -0800 Subject: [PATCH 22/26] Power-ups: dropped power-ups always have at least 15 seconds --- src/k_battle.h | 1 + src/k_powerup.cpp | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/k_battle.h b/src/k_battle.h index f1310e4d1..7806894e5 100644 --- a/src/k_battle.h +++ b/src/k_battle.h @@ -11,6 +11,7 @@ extern "C" { #define BATTLE_SPAWN_INTERVAL (4*TICRATE) #define BATTLE_DESPAWN_TIME (15*TICRATE) #define BATTLE_POWERUP_TIME (30*TICRATE) +#define BATTLE_POWERUP_DROPPED_TIME (15*TICRATE) #define BATTLE_UFO_TIME (20*TICRATE) extern struct battleovertime diff --git a/src/k_powerup.cpp b/src/k_powerup.cpp index b2f7c720e..5472eec34 100644 --- a/src/k_powerup.cpp +++ b/src/k_powerup.cpp @@ -2,6 +2,7 @@ #include +#include "k_battle.h" #include "k_kart.h" #include "k_objects.h" #include "k_powerup.h" @@ -127,7 +128,7 @@ void K_DropPowerUps(player_t* player) if (remaining) { - K_DropPaperItem(player, powerup, remaining); + K_DropPaperItem(player, powerup, std::max(remaining, BATTLE_POWERUP_DROPPED_TIME)); callback(); } }; From f0935551f38891faca73a29ef429ed23a722eaee Mon Sep 17 00:00:00 2001 From: AJ Martinez Date: Fri, 8 Mar 2024 20:05:19 -0700 Subject: [PATCH 23/26] Don't play TA jingles for failed SPB Attack --- src/p_user.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/p_user.c b/src/p_user.c index 1fdafd4aa..741aec1d5 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -712,7 +712,7 @@ void P_EndingMusic(void) jingle = "_win"; } - if (modeattacking) + if (modeattacking && !K_IsPlayerLosing(bestPlayer)) { if (players[consoleplayer].realtime < oldbest && oldbest != (tic_t)UINT32_MAX) jingle = "newrec"; From c969e886057a02eda04ccedfaff4ab7ee27a42df Mon Sep 17 00:00:00 2001 From: AJ Martinez Date: Fri, 8 Mar 2024 21:23:40 -0700 Subject: [PATCH 24/26] Don't play local Ring Sting sound postrace --- 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 fa0306027..fa76cfd7d 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -4822,7 +4822,7 @@ void K_DebtStingPlayer(player_t *player, mobj_t *source) player->ringvisualwarning = TICRATE*2; player->stingfx = true; - if (P_IsDisplayPlayer(player)) + if (P_IsDisplayPlayer(player) && !player->exiting) S_StartSoundAtVolume(NULL, sfx_sting0, 200); P_SetPlayerMobjState(player->mo, S_KART_SPINOUT); From ed6743911abf253c9bf78c8fe33b6341a8cdcff7 Mon Sep 17 00:00:00 2001 From: AJ Martinez Date: Fri, 8 Mar 2024 22:15:22 -0700 Subject: [PATCH 25/26] Scale Shrink time to laser particle size --- src/objects/shrink.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/objects/shrink.c b/src/objects/shrink.c index 58b6cf856..c36eea9da 100644 --- a/src/objects/shrink.c +++ b/src/objects/shrink.c @@ -341,6 +341,7 @@ static void ShrinkLaserThinker(mobj_t *pohbee, mobj_t *gun, mobj_t *laser) particle->color = laser->color; P_SetScale(particle, particle->scale * 2); + particle->cusval = particle->scale; // Store for later. particle->destscale = 0; //particle->momz = 2 * particle->scale * P_MobjFlip(particle); @@ -535,6 +536,12 @@ boolean Obj_ShrinkLaserCollide(mobj_t *gun, mobj_t *victim) owner = pohbee_owner(pohbee); prevTimer = victim->player->growshrinktimer; + fixed_t normalizer = FixedDiv(FRACUNIT, gun->cusval); + fixed_t scale = FixedMul(gun->scale, normalizer); + + if (gun->type != MT_SHRINK_PARTICLE) // You hit the gun/laser! + scale = FRACUNIT; // (Which doesn't have a cusval for its original scale, because it never changes) + if (owner != NULL && victim == owner) { // Belongs to us. Give us Grow! @@ -576,17 +583,21 @@ boolean Obj_ShrinkLaserCollide(mobj_t *gun, mobj_t *victim) } else { + // Bullshit contact. Let 'em off fof free. + if (scale < FRACUNIT/4) + return true; + if (prevTimer > 0) { // Dock some Grow time. // (Hack-adjacent: Always make sure there's a tic left so standard timer handling can remove the effect properly.) - victim->player->growshrinktimer -= min(3*TICRATE/2, victim->player->growshrinktimer - 1); + victim->player->growshrinktimer -= min(FixedInt(FixedMul(FRACUNIT*3*TICRATE/2, scale)), victim->player->growshrinktimer - 1); S_StartSound(victim, sfx_s3k40); } else { // Start shrinking! - victim->player->growshrinktimer -= 5*TICRATE; + victim->player->growshrinktimer -= FixedInt(FixedMul(FRACUNIT*5*TICRATE, scale)); S_StartSound(victim, sfx_kc59); // I don't think you ever get to hear this while the pohbee laser is in your teeth, but best effort. if (prevTimer >= 0) From 9e76eed839555ad1ad1019af452978eceb9ffd15 Mon Sep 17 00:00:00 2001 From: AJ Martinez Date: Fri, 8 Mar 2024 22:52:50 -0700 Subject: [PATCH 26/26] Don't SIGINT when doing shrink scaling (uninitialized cusval on gun) --- src/objects/shrink.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/objects/shrink.c b/src/objects/shrink.c index c36eea9da..1aa3fc3d0 100644 --- a/src/objects/shrink.c +++ b/src/objects/shrink.c @@ -536,11 +536,13 @@ boolean Obj_ShrinkLaserCollide(mobj_t *gun, mobj_t *victim) owner = pohbee_owner(pohbee); prevTimer = victim->player->growshrinktimer; - fixed_t normalizer = FixedDiv(FRACUNIT, gun->cusval); - fixed_t scale = FixedMul(gun->scale, normalizer); + fixed_t scale = FRACUNIT; // Used if you hit the gun/laser. - if (gun->type != MT_SHRINK_PARTICLE) // You hit the gun/laser! - scale = FRACUNIT; // (Which doesn't have a cusval for its original scale, because it never changes) + if (gun->type == MT_SHRINK_PARTICLE && gun->cusval != 0) // Hit the laser trail, scale the punishment down. + { + fixed_t normalizer = FixedDiv(FRACUNIT, gun->cusval); // cusval = original scale of the particle, as it eases down to 0 + scale = FixedMul(gun->scale, normalizer); + } if (owner != NULL && victim == owner) { @@ -583,7 +585,7 @@ boolean Obj_ShrinkLaserCollide(mobj_t *gun, mobj_t *victim) } else { - // Bullshit contact. Let 'em off fof free. + // Bullshit contact. Let 'em off for free. if (scale < FRACUNIT/4) return true;