From a6fa84af3a42b3c24ee4e3d25f1f37237fd3a58a Mon Sep 17 00:00:00 2001 From: James R Date: Wed, 3 Jan 2024 01:13:32 -0800 Subject: [PATCH 01/21] HUD tracking: refactoring - Store tracking result on struct - Put flickering trackers in the vector anyway --- src/k_hud_track.cpp | 227 ++++++++++++++++++++++---------------------- 1 file changed, 116 insertions(+), 111 deletions(-) diff --git a/src/k_hud_track.cpp b/src/k_hud_track.cpp index c2e4cf564..d98ca7590 100644 --- a/src/k_hud_track.cpp +++ b/src/k_hud_track.cpp @@ -54,7 +54,7 @@ struct TargetTracking }; mobj_t* mobj; - vector3_t point; + trackingResult_t result; fixed_t camDist; skincolornum_t color() const @@ -194,15 +194,119 @@ private: } }; +bool is_player_tracking_target(player_t *player = stplyr) +{ + if ((gametyperules & (GTR_BUMPERS|GTR_CLOSERPLAYERS)) != (GTR_BUMPERS|GTR_CLOSERPLAYERS)) + { + return false; + } + + if (K_Cooperative()) + { + return false; + } + + if (player == nullptr) + { + return false; + } + + if (inDuel) + { + // Always draw targets in 1v1 but don't draw player's + // own target on their own viewport. + return player != stplyr; + } + + // Except for DUEL mode, Overtime hides all TARGETs except + // the kiosk. + if (battleovertime.enabled) + { + return false; + } + + if (player->emeralds != 0 && K_IsPlayerWanted(stplyr)) + { + // The player who is about to win because of emeralds + // gets a TARGET on them + if (K_NumEmeralds(player) == 6) // 6 out of 7 + { + return true; + } + + // WANTED player sees TARGETs on players holding + // emeralds + if (K_IsPlayerWanted(stplyr)) + { + return true; + } + } + + return K_IsPlayerWanted(player); +} + +bool is_object_tracking_target(const mobj_t* mobj) +{ + switch (mobj->type) + { + case MT_BATTLECAPSULE: + case MT_CDUFO: + return battleprisons; + + case MT_PLAYER: + return is_player_tracking_target(mobj->player); + + case MT_OVERTIME_CENTER: + return inDuel == false && battleovertime.enabled; + + case MT_EMERALD: + return Obj_EmeraldCanHUDTrack(mobj) && + ((specialstageinfo.valid && specialstageinfo.ufo) || is_player_tracking_target()); + + case MT_MONITOR: + return is_player_tracking_target() && Obj_MonitorGetEmerald(mobj) != 0; + + case MT_SUPER_FLICKY: + return Obj_IsSuperFlickyTargettingYou(mobj, stplyr->mo); + + case MT_SPRAYCAN: + return !(mobj->renderflags & (RF_TRANSMASK | RF_DONTDRAW)); // the spraycan wasn't collected yet + + default: + return false; + } +} + +bool is_object_visible(mobj_t* mobj) +{ + switch (mobj->type) + { + case MT_SUPER_FLICKY: + // Always flickers. + return (leveltime & 1); + + case MT_SPRAYCAN: + // Flickers, but only when visible. + return P_CheckSight(stplyr->mo, mobj) && (leveltime & 1); + + default: + // Flicker when not visible. + return P_CheckSight(stplyr->mo, mobj) || (leveltime & 1); + } +} + void K_DrawTargetTracking(const TargetTracking& target) { + if (is_object_visible(target.mobj) == false) + { + return; + } + const uint8_t* colormap = target.colormap(); - trackingResult_t result = {}; + const trackingResult_t& result = target.result; int32_t timer = 0; - K_ObjectTracking(&result, &target.point, false); - if (result.onScreen == false) { // Off-screen, draw alongside the borders of the screen. @@ -382,107 +486,6 @@ void K_DrawTargetTracking(const TargetTracking& target) } } -bool is_player_tracking_target(player_t *player = stplyr) -{ - if ((gametyperules & (GTR_BUMPERS|GTR_CLOSERPLAYERS)) != (GTR_BUMPERS|GTR_CLOSERPLAYERS)) - { - return false; - } - - if (K_Cooperative()) - { - return false; - } - - if (player == nullptr) - { - return false; - } - - if (inDuel) - { - // Always draw targets in 1v1 but don't draw player's - // own target on their own viewport. - return player != stplyr; - } - - // Except for DUEL mode, Overtime hides all TARGETs except - // the kiosk. - if (battleovertime.enabled) - { - return false; - } - - if (player->emeralds != 0 && K_IsPlayerWanted(stplyr)) - { - // The player who is about to win because of emeralds - // gets a TARGET on them - if (K_NumEmeralds(player) == 6) // 6 out of 7 - { - return true; - } - - // WANTED player sees TARGETs on players holding - // emeralds - if (K_IsPlayerWanted(stplyr)) - { - return true; - } - } - - return K_IsPlayerWanted(player); -} - -bool is_object_tracking_target(const mobj_t* mobj) -{ - switch (mobj->type) - { - case MT_BATTLECAPSULE: - case MT_CDUFO: - return battleprisons; - - case MT_PLAYER: - return is_player_tracking_target(mobj->player); - - case MT_OVERTIME_CENTER: - return inDuel == false && battleovertime.enabled; - - case MT_EMERALD: - return Obj_EmeraldCanHUDTrack(mobj) && - ((specialstageinfo.valid && specialstageinfo.ufo) || is_player_tracking_target()); - - case MT_MONITOR: - return is_player_tracking_target() && Obj_MonitorGetEmerald(mobj) != 0; - - case MT_SUPER_FLICKY: - return Obj_IsSuperFlickyTargettingYou(mobj, stplyr->mo); - - case MT_SPRAYCAN: - return !(mobj->renderflags & (RF_TRANSMASK | RF_DONTDRAW)); // the spraycan wasn't collected yet - - default: - return false; - } -} - -bool is_object_visible(mobj_t* mobj) -{ - switch (mobj->type) - { - case MT_SUPER_FLICKY: - // Always flickers. - return (leveltime & 1); - - case MT_SPRAYCAN: - // Flickers, but only when visible. - return P_CheckSight(stplyr->mo, mobj) && (leveltime & 1); - - default: - // Flicker when not visible. - return P_CheckSight(stplyr->mo, mobj) || (leveltime & 1); - } -} - }; // namespace void K_drawTargetHUD(const vector3_t* origin, player_t* player) @@ -506,18 +509,20 @@ void K_drawTargetHUD(const vector3_t* origin, player_t* player) continue; } - if (is_object_visible(mobj) == false) - { - continue; - } - vector3_t pos = { R_InterpolateFixed(mobj->old_x, mobj->x) + mobj->sprxoff, R_InterpolateFixed(mobj->old_y, mobj->y) + mobj->spryoff, R_InterpolateFixed(mobj->old_z, mobj->z) + mobj->sprzoff + (mobj->height >> 1), }; - targetList.push_back({mobj, pos, R_PointToDist2(origin->x, origin->y, pos.x, pos.y)}); + TargetTracking tr; + + tr.mobj = mobj; + tr.camDist = R_PointToDist2(origin->x, origin->y, pos.x, pos.y); + + K_ObjectTracking(&tr.result, &pos, false); + + targetList.push_back(tr); } // Sort by distance from camera. Further trackers get From 15775adcb91d4bbc7e311baf63145d41cce097f8 Mon Sep 17 00:00:00 2001 From: James R Date: Wed, 3 Jan 2024 01:15:27 -0800 Subject: [PATCH 02/21] HUD tracking: give overlapping trackers in the background transparency - Assuming every tracker is a 30x30 square, to determine overlap. --- src/cvars.cpp | 1 + src/k_hud_track.cpp | 71 ++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 71 insertions(+), 1 deletion(-) diff --git a/src/cvars.cpp b/src/cvars.cpp index 0f1b04344..959ca9f68 100644 --- a/src/cvars.cpp +++ b/src/cvars.cpp @@ -856,6 +856,7 @@ consvar_t cv_kartdebugnodes = ServerCheat("debugnodes", "Off").on_off().descript consvar_t cv_1pswap = PlayerCheat("1pswap", "1").min_max(1, MAXSPLITSCREENPLAYERS).description("Let P1's Profile control a different splitscreen player"); consvar_t cv_debugfinishline = PlayerCheat("debugfinishline", "Off").on_off().description("Highlight finish lines, respawn lines, death pits and instakill planes with high contrast colors"); +consvar_t cv_debughudtracker = PlayerCheat("debughudtracker", "Off").on_off().description("Highlight overlapping HUD tracker blocks"); consvar_t cv_debugrank = PlayerCheat("debugrank", "Off").description("Show GP rank state on the HUD; optionally force a rank grade").values({ {0, "Off"}, diff --git a/src/k_hud_track.cpp b/src/k_hud_track.cpp index d98ca7590..7c956bf94 100644 --- a/src/k_hud_track.cpp +++ b/src/k_hud_track.cpp @@ -26,6 +26,8 @@ using namespace srb2; +extern "C" consvar_t cv_debughudtracker; + namespace { @@ -56,6 +58,7 @@ struct TargetTracking mobj_t* mobj; trackingResult_t result; fixed_t camDist; + bool foreground; skincolornum_t color() const { @@ -467,6 +470,7 @@ void K_DrawTargetTracking(const TargetTracking& target) { // Draw simple overlay. vector2_t targetPos = {result.x, result.y}; + INT32 trans = target.foreground ? 0 : V_80TRANS; TargetTracking::Animation anim = target.animation(); @@ -478,7 +482,7 @@ void K_DrawTargetTracking(const TargetTracking& target) targetPos.x - ((patch->width << FRACBITS) >> 1), targetPos.y - ((patch->height << FRACBITS) >> 1), FRACUNIT, - V_SPLITSCREEN | anim.video_flags, + V_SPLITSCREEN | anim.video_flags | trans, patch, colormap ); @@ -486,6 +490,68 @@ void K_DrawTargetTracking(const TargetTracking& target) } } +void K_CullTargetList(std::vector& targetList) +{ + constexpr int kBlockSize = 20; + constexpr int kXBlocks = BASEVIDWIDTH / kBlockSize; + constexpr int kYBlocks = BASEVIDHEIGHT / kBlockSize; + bool map[kXBlocks][kYBlocks] = {}; + + constexpr fixed_t kTrackerRadius = 30*FRACUNIT/2; // just an approximation of common HUD tracker + + int debugColorCycle = 0; + + std::for_each( + targetList.rbegin(), + targetList.rend(), + [&](TargetTracking& tr) + { + if (tr.result.onScreen == false) + { + return; + } + + fixed_t x1 = std::max(((tr.result.x - kTrackerRadius) / kBlockSize) / FRACUNIT, 0); + fixed_t x2 = std::min(((tr.result.x + kTrackerRadius) / kBlockSize) / FRACUNIT, kXBlocks - 1); + fixed_t y1 = std::max(((tr.result.y - kTrackerRadius) / kBlockSize) / FRACUNIT, 0); + fixed_t y2 = std::min(((tr.result.y + kTrackerRadius) / kBlockSize) / FRACUNIT, kYBlocks - 1); + + bool allMine = true; + + for (fixed_t x = x1; x <= x2; ++x) + { + for (fixed_t y = y1; y <= y2; ++y) + { + if (map[x][y]) + { + allMine = false; + } + else + { + map[x][y] = true; + + if (cv_debughudtracker.value) + { + V_DrawFill(x * kBlockSize, y * kBlockSize, kBlockSize, kBlockSize, 39 + debugColorCycle); + } + } + } + } + + if (allMine) + { + // This tracker claims every square + tr.foreground = true; + } + + if (++debugColorCycle > 8) + { + debugColorCycle = 0; + } + } + ); +} + }; // namespace void K_drawTargetHUD(const vector3_t* origin, player_t* player) @@ -519,6 +585,7 @@ void K_drawTargetHUD(const vector3_t* origin, player_t* player) tr.mobj = mobj; tr.camDist = R_PointToDist2(origin->x, origin->y, pos.x, pos.y); + tr.foreground = false; K_ObjectTracking(&tr.result, &pos, false); @@ -529,5 +596,7 @@ void K_drawTargetHUD(const vector3_t* origin, player_t* player) // drawn first so nearer ones draw over them. std::sort(targetList.begin(), targetList.end(), [](const auto& a, const auto& b) { return a.camDist > b.camDist; }); + K_CullTargetList(targetList); + std::for_each(targetList.cbegin(), targetList.cend(), K_DrawTargetTracking); } From b7c9c9274998165adb46433bfddf01a19aa4cc9f Mon Sep 17 00:00:00 2001 From: James R Date: Wed, 3 Jan 2024 04:28:34 -0800 Subject: [PATCH 03/21] Music_Seek: argument in milliseconds instead of tics --- src/music.cpp | 2 +- src/music.h | 4 ++-- src/music_manager.cpp | 2 +- src/music_tune.hpp | 3 ++- src/p_setup.cpp | 2 +- src/s_sound.c | 2 +- 6 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/music.cpp b/src/music.cpp index d60c67c99..f6646e3bd 100644 --- a/src/music.cpp +++ b/src/music.cpp @@ -216,7 +216,7 @@ void Music_DelayEnd(const char* id, tic_t duration) } } -void Music_Seek(const char* id, tic_t set) +void Music_Seek(const char* id, UINT32 set) { Tune* tune = g_tunes.find(id); diff --git a/src/music.h b/src/music.h index eff0d660b..3931aedfa 100644 --- a/src/music.h +++ b/src/music.h @@ -89,8 +89,8 @@ void Music_UnSuspend(const char *id); // -// Seek to a specific time in the tune. -void Music_Seek(const char *id, tic_t set); +// Seek to a specific time in milliseconds in the tune. +void Music_Seek(const char *id, UINT32 set); // Remap a tune to another song. Use the lump name, with the // 'O_' at the beginning removed. song is case insensitive. diff --git a/src/music_manager.cpp b/src/music_manager.cpp index a0696e1a3..f9602166c 100644 --- a/src/music_manager.cpp +++ b/src/music_manager.cpp @@ -200,7 +200,7 @@ void TuneManager::seek(Tune* tune) uint32_t end = I_GetSongLength(); uint32_t loop = I_GetSongLoopPoint(); - uint32_t pos = detail::tics_to_msec(tune->seek + tune->elapsed()) * tune->speed(); + uint32_t pos = (tune->seek + detail::tics_to_msec(tune->elapsed())) * tune->speed(); if (pos > end && (end - loop) > 0u) { diff --git a/src/music_tune.hpp b/src/music_tune.hpp index b7c800058..635dfc02b 100644 --- a/src/music_tune.hpp +++ b/src/music_tune.hpp @@ -11,6 +11,7 @@ #define MUSIC_TUNE_HPP #include +#include #include #include @@ -68,7 +69,7 @@ public: bool nightcoreable = false; // Start playing this number of tics into the tune. - tic_t seek = 0; + std::uint32_t seek = 0; // these track state bool can_fade_out = true; diff --git a/src/p_setup.cpp b/src/p_setup.cpp index 6e9e225c5..f79c49422 100644 --- a/src/p_setup.cpp +++ b/src/p_setup.cpp @@ -8202,7 +8202,7 @@ void P_LoadLevelMusic(void) Music_Remap("level", music); tic_t level_music_start = starttime + (TICRATE/2); - Music_Seek("level", std::max(leveltime, level_music_start) - level_music_start); + Music_Seek("level", (std::max(leveltime, level_music_start) - level_music_start) * 1000UL / TICRATE); } } diff --git a/src/s_sound.c b/src/s_sound.c index 142eaa4ba..7190b014f 100644 --- a/src/s_sound.c +++ b/src/s_sound.c @@ -2296,7 +2296,7 @@ static void Command_Tunes_f(void) Music_Play("stereo"); if (argc > 3) - Music_Seek("stereo", (atoi(COM_Argv(3)) * TICRATE) / 1000); + Music_Seek("stereo", atoi(COM_Argv(3))); if (argc > 2) { From c192e5742661da188101bd9f23a096cfc92f2337 Mon Sep 17 00:00:00 2001 From: James R Date: Wed, 3 Jan 2024 04:31:27 -0800 Subject: [PATCH 04/21] Battle: Overtime music - Fade out level music for 1.5 seconds when "Hurry up!" plays. - Play SHWDWN when level music finishes fading out. - Switch to SHWDN2 when there are 2 players left and the Overtime Barrier has reached its smallest size. - Plays a loud noise to mask the transition. --- src/k_battle.c | 33 ++++++++++++++++++++++++++++++--- src/music.cpp | 16 ++++++++++++++++ 2 files changed, 46 insertions(+), 3 deletions(-) diff --git a/src/k_battle.c b/src/k_battle.c index 5fc1dc9e5..39f8fadc7 100644 --- a/src/k_battle.c +++ b/src/k_battle.c @@ -21,6 +21,10 @@ #include "p_spec.h" #include "k_objects.h" #include "k_rank.h" +#include "music.h" +#include "hu_stuff.h" + +#define BARRIER_MIN_RADIUS (768 * mapobjectscale) // Battle overtime info struct battleovertime battleovertime; @@ -142,6 +146,12 @@ void K_CheckBumpers(void) } } + if (numingame <= 2 && battleovertime.enabled && battleovertime.radius <= BARRIER_MIN_RADIUS) + { + Music_Stop("battle_overtime"); + S_StartSound(NULL, sfx_kc4b); // Loud noise helps mask transition + } + if (K_Cooperative()) { if (nobumpers > 0 && nobumpers >= numingame) @@ -678,19 +688,36 @@ void K_RunBattleOvertime(void) { battleovertime.enabled++; if (battleovertime.enabled == TICRATE) + { S_StartSound(NULL, sfx_bhurry); - if (battleovertime.enabled == 10*TICRATE) + Music_DelayEnd("level", 0); + } + else if (battleovertime.enabled == 10*TICRATE) S_StartSound(NULL, sfx_kc40); + + if (!Music_Playing("level") && !Music_Playing("battle_overtime")) + { + Music_Play("battle_overtime"); + Music_Play("battle_overtime_stress"); + + // Sync approximately with looping section of + // battle_overtime. (This is file dependant.) + Music_Seek("battle_overtime_stress", 1756); + } } else if (battleovertime.radius > 0) { - const fixed_t minradius = 768 * mapobjectscale; + const fixed_t minradius = BARRIER_MIN_RADIUS; + const fixed_t oldradius = battleovertime.radius; if (battleovertime.radius > minradius) battleovertime.radius -= (battleovertime.initial_radius / (30*TICRATE)); - if (battleovertime.radius < minradius) + if (battleovertime.radius <= minradius && oldradius > minradius) + { battleovertime.radius = minradius; + K_CheckBumpers(); + } // Subtract the 10 second grace period of the barrier if (battleovertime.enabled < 25*TICRATE) diff --git a/src/music.cpp b/src/music.cpp index f6646e3bd..56f048bd9 100644 --- a/src/music.cpp +++ b/src/music.cpp @@ -28,6 +28,8 @@ void Music_Init(void) Tune& tune = g_tunes.insert("level"); tune.priority = 1; + tune.fade_out = 1500; + tune.fade_out_inclusive = false; tune.resume_fade_in = 750; tune.sync = true; tune.credit = true; @@ -48,6 +50,20 @@ void Music_Init(void) tune.fade_out = 3500; } + { + Tune& tune = g_tunes.insert("battle_overtime", g_tunes.find("level")); + + tune.song = "shwdwn"; + tune.priority = 11; + } + + { + Tune& tune = g_tunes.insert("battle_overtime_stress", g_tunes.find("battle_overtime")); + + tune.song = "shwdn2"; + tune.priority = 10; + } + { Tune& tune = g_tunes.insert("grow"); From 2bfad76c1e6bfe6d45b116f234d1f17f22304db4 Mon Sep 17 00:00:00 2001 From: James R Date: Wed, 3 Jan 2024 04:52:25 -0800 Subject: [PATCH 05/21] Add HU_DoTitlecardCEchoForDuration; letter disappearing time scales by total cecho duration --- src/hu_stuff.c | 12 +++++++++--- src/hu_stuff.h | 1 + 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/hu_stuff.c b/src/hu_stuff.c index 427a0b8c4..5abc59fd1 100644 --- a/src/hu_stuff.c +++ b/src/hu_stuff.c @@ -1861,6 +1861,7 @@ static void HU_DrawTitlecardCEcho(size_t num) INT32 y = BASEVIDHEIGHT/2; INT32 pnumlines = 0; INT32 timeroffset = 0; + INT32 fadeout = state->duration * 2 / 3; char *line; char *echoptr; @@ -1916,7 +1917,7 @@ static void HU_DrawTitlecardCEcho(size_t num) *line = '\0'; ofs = V_CenteredTitleCardStringOffset(echoptr, p4); - V_DrawTitleCardString(x - ofs, y, echoptr, 0, false, timer, TICRATE*4, p4); + V_DrawTitleCardString(x - ofs, y, echoptr, 0, false, timer, fadeout, p4); y += p4 ? 18 : 32; @@ -2660,7 +2661,7 @@ void HU_ClearTitlecardCEcho(void) } // Similar but for titlecard CEcho and also way less convoluted because I have no clue whatever the fuck they were trying above. -void HU_DoTitlecardCEcho(player_t *player, const char *msg, boolean interrupt) +void HU_DoTitlecardCEchoForDuration(player_t *player, const char *msg, boolean interrupt, tic_t duration) { if (player && !P_IsDisplayPlayer(player)) { @@ -2687,5 +2688,10 @@ void HU_DoTitlecardCEcho(player_t *player, const char *msg, boolean interrupt) strncat(state->text, "\\", sizeof(state->text) - strlen(state->text) - 1); state->text[sizeof(state->text) - 1] = '\0'; state->start = gametic; - state->duration = TICRATE*6 + strlen(state->text); + state->duration = duration ? duration : TICRATE*6 + strlen(state->text); +} + +void HU_DoTitlecardCEcho(player_t *player, const char *msg, boolean interrupt) +{ + HU_DoTitlecardCEchoForDuration(player, msg, interrupt, 0u); } diff --git a/src/hu_stuff.h b/src/hu_stuff.h index 897e31c19..f9efdbf1c 100644 --- a/src/hu_stuff.h +++ b/src/hu_stuff.h @@ -167,6 +167,7 @@ void HU_DoCEcho(const char *msg); // Titlecard CECHO shite void HU_DoTitlecardCEcho(player_t *player, const char *msg, boolean interrupt); +void HU_DoTitlecardCEchoForDuration(player_t *player, const char *msg, boolean interrupt, tic_t duration); void HU_ClearTitlecardCEcho(void); void DoSayCommand(char *message, SINT8 target, UINT8 flags, UINT8 source); From c9398e21bebecc71d3942c2e57148058db1db869 Mon Sep 17 00:00:00 2001 From: James R Date: Wed, 3 Jan 2024 04:53:08 -0800 Subject: [PATCH 06/21] Battle: cecho "HURRY UP!!" when Barrier appears --- src/k_battle.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/k_battle.c b/src/k_battle.c index 39f8fadc7..c7993c410 100644 --- a/src/k_battle.c +++ b/src/k_battle.c @@ -690,6 +690,7 @@ void K_RunBattleOvertime(void) if (battleovertime.enabled == TICRATE) { S_StartSound(NULL, sfx_bhurry); + HU_DoTitlecardCEchoForDuration(NULL, "HURRY UP!!", true, 2*TICRATE); Music_DelayEnd("level", 0); } else if (battleovertime.enabled == 10*TICRATE) From 6431ef8250398f6f57b0283ec96805d325a86423 Mon Sep 17 00:00:00 2001 From: James R Date: Wed, 3 Jan 2024 05:39:13 -0800 Subject: [PATCH 07/21] Battle: screen shake when Barrier arms and once it reaches smallest radius - Plays sound effect when Barrier reaches minimum size. --- src/k_battle.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/k_battle.c b/src/k_battle.c index c7993c410..8fa3909ae 100644 --- a/src/k_battle.c +++ b/src/k_battle.c @@ -694,7 +694,10 @@ void K_RunBattleOvertime(void) Music_DelayEnd("level", 0); } else if (battleovertime.enabled == 10*TICRATE) + { S_StartSound(NULL, sfx_kc40); + P_StartQuake(5, 64 * mapobjectscale, 0, NULL); + } if (!Music_Playing("level") && !Music_Playing("battle_overtime")) { @@ -718,6 +721,8 @@ void K_RunBattleOvertime(void) { battleovertime.radius = minradius; K_CheckBumpers(); + S_StartSound(NULL, sfx_kc40); + P_StartQuake(5, 64 * mapobjectscale, 0, NULL); } // Subtract the 10 second grace period of the barrier From a75962633573381581ab8f8fadbe520ca13756de Mon Sep 17 00:00:00 2001 From: James R Date: Wed, 3 Jan 2024 21:28:44 -0800 Subject: [PATCH 08/21] Battle: flash emeralds on screen when someone wins by collecting all 7 - Modifies netsave --- src/hud/CMakeLists.txt | 1 + src/hud/emerald-win.cpp | 41 +++++++++++++++++++++++++++++++++++++++++ src/k_battle.c | 6 ++++++ src/k_battle.h | 1 + src/k_hud.cpp | 3 +++ src/k_hud.h | 1 + src/p_saveg.c | 2 ++ 7 files changed, 55 insertions(+) create mode 100644 src/hud/emerald-win.cpp diff --git a/src/hud/CMakeLists.txt b/src/hud/CMakeLists.txt index 8331e2871..629b708f4 100644 --- a/src/hud/CMakeLists.txt +++ b/src/hud/CMakeLists.txt @@ -2,4 +2,5 @@ target_sources(SRB2SDL2 PRIVATE powerup.cpp spectator.cpp timer.cpp + emerald-win.cpp ) diff --git a/src/hud/emerald-win.cpp b/src/hud/emerald-win.cpp new file mode 100644 index 000000000..f304b0f4e --- /dev/null +++ b/src/hud/emerald-win.cpp @@ -0,0 +1,41 @@ +#include "../v_draw.hpp" + +#include "../doomdef.h" +#include "../i_time.h" +#include "../k_hud.h" +#include "../screen.h" + +using srb2::Draw; + +void K_drawEmeraldWin(void) +{ + constexpr float kScale = 0.25; + constexpr int kH = 72 * kScale; + constexpr int kYPad = 12; + constexpr int kWidth = 34 + 4; + + if (I_GetTime() % 3) + { + return; + } + + Draw row = Draw(BASEVIDWIDTH / 2, BASEVIDHEIGHT / 2).scale(kScale).flags(V_ADD); + //Draw(0, row.y()).size(BASEVIDWIDTH, 1).fill(35); + + Draw top = row.y(-kYPad); + Draw bot = row.xy(-kWidth / 2, kH + kYPad); + + auto put = [](Draw& row, int x, int n) + { + row.x(x * kWidth).colormap(static_cast(SKINCOLOR_CHAOSEMERALD1 + n)).patch("EMRCA0"); + }; + + put(top, -1, 3); + put(top, 0, 0); + put(top, 1, 4); + + put(bot, -1, 5); + put(bot, 0, 1); + put(bot, 1, 2); + put(bot, 2, 6); +} diff --git a/src/k_battle.c b/src/k_battle.c index 8fa3909ae..78da21dc0 100644 --- a/src/k_battle.c +++ b/src/k_battle.c @@ -41,6 +41,9 @@ INT32 numgotboxes = 0; UINT8 maptargets = 0; // Capsules in map UINT8 numtargets = 0; // Capsules busted +// Battle: someone won by collecting all 7 Chaos Emeralds +boolean g_emeraldWin = false; + INT32 K_StartingBumperCount(void) { if (tutorialchallenge == TUTORIALSKIP_INPROGRESS) @@ -194,6 +197,7 @@ void K_CheckEmeralds(player_t *player) player->roundscore = 100; // lmao P_DoAllPlayersExit(0, false); + g_emeraldWin = true; } UINT16 K_GetChaosEmeraldColor(UINT32 emeraldType) @@ -855,6 +859,8 @@ void K_BattleInit(boolean singleplayercontext) g_battleufo.due = starttime; g_battleufo.previousId = Obj_RandomBattleUFOSpawnerID() - 1; + + g_emeraldWin = false; } UINT8 K_Bumpers(player_t *player) diff --git a/src/k_battle.h b/src/k_battle.h index 923367cda..023ba0c97 100644 --- a/src/k_battle.h +++ b/src/k_battle.h @@ -32,6 +32,7 @@ extern struct battleufo extern boolean battleprisons; extern INT32 nummapboxes, numgotboxes; // keep track of spawned battle mode items extern UINT8 maptargets, numtargets; +extern boolean g_emeraldWin; INT32 K_StartingBumperCount(void); boolean K_IsPlayerWanted(player_t *player); diff --git a/src/k_hud.cpp b/src/k_hud.cpp index 811eb8bab..f6bbcab2a 100644 --- a/src/k_hud.cpp +++ b/src/k_hud.cpp @@ -5663,6 +5663,9 @@ void K_drawKartHUD(void) if ((gametyperules & GTR_KARMA) && !r_splitscreen && (stplyr->karthud[khud_yougotem] % 2)) // * YOU GOT EM * V_DrawScaledPatch(BASEVIDWIDTH/2 - (SHORT(kp_yougotem->width)/2), 32, V_HUDTRANS, kp_yougotem); + if (g_emeraldWin) + K_drawEmeraldWin(); + // Draw FREE PLAY. K_drawKartFreePlay(); diff --git a/src/k_hud.h b/src/k_hud.h index c57a342dc..2f1096965 100644 --- a/src/k_hud.h +++ b/src/k_hud.h @@ -47,6 +47,7 @@ void K_drawSpectatorHUD(boolean director); void K_drawKartTimestamp(tic_t drawtime, INT32 TX, INT32 TY, INT32 splitflags, UINT8 mode); void K_drawKart2PTimestamp(void); void K_drawKart4PTimestamp(void); +void K_drawEmeraldWin(void); void K_DrawMapThumbnail(fixed_t x, fixed_t y, fixed_t width, UINT32 flags, UINT16 map, const UINT8 *colormap); void K_DrawLikeMapThumbnail(fixed_t x, fixed_t y, fixed_t width, UINT32 flags, patch_t *patch, const UINT8 *colormap); void K_drawTargetHUD(const vector3_t *origin, player_t *player); diff --git a/src/p_saveg.c b/src/p_saveg.c index 04b59c277..7aa5dfd02 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -6433,6 +6433,7 @@ static void P_NetArchiveMisc(savebuffer_t *save, boolean resending) WRITEINT32(save->p, numgotboxes); WRITEUINT8(save->p, numtargets); WRITEUINT8(save->p, battleprisons); + WRITEUINT8(save->p, g_emeraldWin); WRITEUINT8(save->p, gamespeed); WRITEUINT8(save->p, numlaps); @@ -6617,6 +6618,7 @@ static boolean P_NetUnArchiveMisc(savebuffer_t *save, boolean reloading) numgotboxes = READINT32(save->p); numtargets = READUINT8(save->p); battleprisons = (boolean)READUINT8(save->p); + g_emeraldWin = (boolean)READUINT8(save->p); gamespeed = READUINT8(save->p); numlaps = READUINT8(save->p); From 843048967333c11114975f5df7d26e2ef6ab768e Mon Sep 17 00:00:00 2001 From: James R Date: Fri, 5 Jan 2024 13:57:51 -0800 Subject: [PATCH 09/21] Replace darktimer/darkness with g_darkness Modifies netsave. - Instead of setting a timer, set a start time and end time - Interpolated darkness value itself doesn't need to be netsynced --- src/doomstat.h | 8 ++++++-- src/g_game.c | 3 +-- src/g_game.h | 3 --- src/k_kart.c | 2 +- src/objects/shrink.c | 3 ++- src/p_saveg.c | 8 ++++---- src/p_tick.c | 28 +++++++++++++++++----------- src/r_debug.cpp | 2 +- src/typedef.h | 1 + 9 files changed, 33 insertions(+), 25 deletions(-) diff --git a/src/doomstat.h b/src/doomstat.h index 92f4dce2d..458fd004e 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -803,8 +803,12 @@ struct exitcondition_t extern tic_t racecountdown, exitcountdown, musiccountdown; extern exitcondition_t g_exit; -extern tic_t darktimer; -extern fixed_t darkness; +#define DARKNESS_FADE_TIME (8) +extern struct darkness_t +{ + tic_t start, end; + fixed_t value; +} g_darkness; #define DEFAULT_GRAVITY (4*FRACUNIT/5) extern fixed_t gravity; diff --git a/src/g_game.c b/src/g_game.c index 2dfa5a1bc..877840150 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -277,8 +277,7 @@ UINT8 useSeal = 1; tic_t racecountdown, exitcountdown, musiccountdown; // for racing exitcondition_t g_exit; -tic_t darktimer; -fixed_t darkness; +darkness_t g_darkness; fixed_t gravity; fixed_t mapobjectscale; diff --git a/src/g_game.h b/src/g_game.h index f66b665f0..d1378ce30 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -85,9 +85,6 @@ extern boolean pausebreakkey; extern boolean promptactive; -extern tic_t darktimer; -extern fixed_t darkness; - extern consvar_t cv_tutorialprompt; extern consvar_t cv_chatwidth, cv_chatnotifications, cv_chatheight, cv_chattime, cv_consolechat, cv_chatbacktint, cv_chatspamprotection; diff --git a/src/k_kart.c b/src/k_kart.c index def73ecfd..eff55c946 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -116,7 +116,7 @@ static void K_SpawnDuelOnlyItems(void) void K_TimerReset(void) { starttime = introtime = 0; - darkness = darktimer = 0; + memset(&g_darkness, 0, sizeof g_darkness); numbulbs = 1; inDuel = rainbowstartavailable = false; linecrossed = 0; diff --git a/src/objects/shrink.c b/src/objects/shrink.c index 04b703328..58b6cf856 100644 --- a/src/objects/shrink.c +++ b/src/objects/shrink.c @@ -749,7 +749,8 @@ void Obj_CreateShrinkPohbees(player_t *owner) ownerPos = owner->position; - darktimer = POHBEE_TIME; + g_darkness.start = leveltime; + g_darkness.end = leveltime + POHBEE_TIME + DARKNESS_FADE_TIME; for (i = 0; i < MAXPLAYERS; i++) { diff --git a/src/p_saveg.c b/src/p_saveg.c index 7aa5dfd02..9d7f9aba5 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -6477,8 +6477,8 @@ static void P_NetArchiveMisc(savebuffer_t *save, boolean resending) WRITEUINT32(save->p, g_pointlimit); - WRITEUINT32(save->p, darktimer); - WRITEFIXED(save->p, darkness); + WRITEUINT32(save->p, g_darkness.start); + WRITEUINT32(save->p, g_darkness.end); WRITEUINT16(save->p, numchallengedestructibles); @@ -6662,8 +6662,8 @@ static boolean P_NetUnArchiveMisc(savebuffer_t *save, boolean reloading) g_pointlimit = READUINT32(save->p); - darktimer = READUINT32(save->p); - darkness = READFIXED(save->p); + g_darkness.start = READUINT32(save->p); + g_darkness.end = READUINT32(save->p); numchallengedestructibles = READUINT16(save->p); diff --git a/src/p_tick.c b/src/p_tick.c index 15bcd0baa..8a016597f 100644 --- a/src/p_tick.c +++ b/src/p_tick.c @@ -46,6 +46,7 @@ #include "k_objects.h" #include "music.h" #include "k_dialogue.h" +#include "m_easing.h" #include "lua_profile.h" @@ -1045,21 +1046,26 @@ void P_Ticker(boolean run) if (racecountdown > 1) racecountdown--; - const fixed_t darkdelta = FRACUNIT/50; - const fixed_t maxdark = FRACUNIT/7; - if (darktimer) // dark or darkening + if (leveltime <= g_darkness.end) { - darktimer--; - darkness += darkdelta; - darkness = min(darkness, maxdark); - } - else if (darkness >= darkdelta) // lightening - { - darkness -= darkdelta; + tic_t fade = g_darkness.end - DARKNESS_FADE_TIME; + tic_t t; + + if (leveltime < fade) // dark or darkening + { + t = leveltime - g_darkness.start; + t = min(t, DARKNESS_FADE_TIME); + } + else // lightening + { + t = g_darkness.end - leveltime; + } + + g_darkness.value = Easing_Linear((t * FRACUNIT) / DARKNESS_FADE_TIME, 0, FRACUNIT/7); } else // light { - darkness = 0; + g_darkness.value = 0; } if (exitcountdown >= 1) diff --git a/src/r_debug.cpp b/src/r_debug.cpp index f4774f9fc..b4f2409b7 100644 --- a/src/r_debug.cpp +++ b/src/r_debug.cpp @@ -43,7 +43,7 @@ INT32 R_AdjustLightLevel(INT32 light) if (!debugrender_highlight && cv_debugrender_contrast.value == 0) { - const fixed_t darken = FixedMul(FixedMul(darkness, mapheaderinfo[gamemap-1]->darkness), kRange); + const fixed_t darken = FixedMul(FixedMul(g_darkness.value, mapheaderinfo[gamemap-1]->darkness), kRange); return std::clamp((light * FRACUNIT) - darken, 0, kRange) / FRACUNIT; } diff --git a/src/typedef.h b/src/typedef.h index be029d99a..77625d4cd 100644 --- a/src/typedef.h +++ b/src/typedef.h @@ -141,6 +141,7 @@ TYPEDEF (tolinfo_t); TYPEDEF (cupheader_t); TYPEDEF (unloaded_cupheader_t); TYPEDEF (exitcondition_t); +TYPEDEF (darkness_t); // font.h TYPEDEF (font_t); From df0d342e0450f8adf0a09e0f2706289a83828fea Mon Sep 17 00:00:00 2001 From: James R Date: Fri, 5 Jan 2024 14:17:57 -0800 Subject: [PATCH 10/21] Let level darkness be changed per splitscreen, use player_t variables Modifies netsave. - Add darkness_start, darkness_end to player_t --- src/d_player.h | 3 +++ src/doomstat.h | 2 +- src/p_saveg.c | 8 +++++++ src/p_tick.c | 59 +++++++++++++++++++++++++++++++------------------ src/r_debug.cpp | 3 ++- 5 files changed, 52 insertions(+), 23 deletions(-) diff --git a/src/d_player.h b/src/d_player.h index 48cd80532..47a9e1bdf 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -982,6 +982,9 @@ struct player_t icecubevars_t icecube; level_tally_t tally; + + tic_t darkness_start; + tic_t darkness_end; }; // WARNING FOR ANYONE ABOUT TO ADD SOMETHING TO THE PLAYER STRUCT, G_PlayerReborn WANTS YOU TO SUFFER diff --git a/src/doomstat.h b/src/doomstat.h index 458fd004e..20ab4069b 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -807,7 +807,7 @@ extern exitcondition_t g_exit; extern struct darkness_t { tic_t start, end; - fixed_t value; + fixed_t value[MAXSPLITSCREENPLAYERS]; } g_darkness; #define DEFAULT_GRAVITY (4*FRACUNIT/5) diff --git a/src/p_saveg.c b/src/p_saveg.c index 9d7f9aba5..ea9b91275 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -787,6 +787,10 @@ static void P_NetArchivePlayers(savebuffer_t *save) WRITEUINT8(save->p, players[i].icecube.wiggle); WRITEUINT32(save->p, players[i].icecube.frozenat); WRITEUINT8(save->p, players[i].icecube.shaketimer); + + // darkness + WRITEUINT32(save->p, players[i].darkness_start); + WRITEUINT32(save->p, players[i].darkness_end); } TracyCZoneEnd(__zone); @@ -1358,6 +1362,10 @@ static void P_NetUnArchivePlayers(savebuffer_t *save) players[i].icecube.frozenat = READUINT32(save->p); players[i].icecube.shaketimer = READUINT8(save->p); + // darkness + players[i].darkness_start = READUINT32(save->p); + players[i].darkness_end = READUINT32(save->p); + //players[i].viewheight = P_GetPlayerViewHeight(players[i]); // scale cannot be factored in at this point } diff --git a/src/p_tick.c b/src/p_tick.c index 8a016597f..d8e26624f 100644 --- a/src/p_tick.c +++ b/src/p_tick.c @@ -768,6 +768,43 @@ void P_RunChaseCameras(void) } } +static fixed_t P_GetDarkness(tic_t start, tic_t end) +{ + if (leveltime <= end) + { + tic_t fade = end - DARKNESS_FADE_TIME; + tic_t t; + + if (leveltime < fade) // dark or darkening + { + t = leveltime - start; + t = min(t, DARKNESS_FADE_TIME); + } + else // lightening + { + t = end - leveltime; + } + + return Easing_Linear((t * FRACUNIT) / DARKNESS_FADE_TIME, 0, FRACUNIT/7); + } + + return 0; +} + +static void P_TickDarkness(void) +{ + const fixed_t globalValue = P_GetDarkness(g_darkness.start, g_darkness.end); + UINT8 i; + + for (i = 0; i <= r_splitscreen; ++i) + { + const player_t *p = &players[displayplayers[i]]; + fixed_t value = P_GetDarkness(p->darkness_start, p->darkness_end); + + g_darkness.value[i] = value ? value : globalValue; + } +} + // // P_Ticker // @@ -1046,27 +1083,7 @@ void P_Ticker(boolean run) if (racecountdown > 1) racecountdown--; - if (leveltime <= g_darkness.end) - { - tic_t fade = g_darkness.end - DARKNESS_FADE_TIME; - tic_t t; - - if (leveltime < fade) // dark or darkening - { - t = leveltime - g_darkness.start; - t = min(t, DARKNESS_FADE_TIME); - } - else // lightening - { - t = g_darkness.end - leveltime; - } - - g_darkness.value = Easing_Linear((t * FRACUNIT) / DARKNESS_FADE_TIME, 0, FRACUNIT/7); - } - else // light - { - g_darkness.value = 0; - } + P_TickDarkness(); if (exitcountdown >= 1) { diff --git a/src/r_debug.cpp b/src/r_debug.cpp index b4f2409b7..6cc42a50c 100644 --- a/src/r_debug.cpp +++ b/src/r_debug.cpp @@ -18,6 +18,7 @@ #include "i_time.h" #include "m_fixed.h" #include "r_draw.h" +#include "r_fps.h" #include "r_main.h" #include "g_game.h" @@ -43,7 +44,7 @@ INT32 R_AdjustLightLevel(INT32 light) if (!debugrender_highlight && cv_debugrender_contrast.value == 0) { - const fixed_t darken = FixedMul(FixedMul(g_darkness.value, mapheaderinfo[gamemap-1]->darkness), kRange); + const fixed_t darken = FixedMul(FixedMul(g_darkness.value[R_GetViewNumber()], mapheaderinfo[gamemap-1]->darkness), kRange); return std::clamp((light * FRACUNIT) - darken, 0, kRange) / FRACUNIT; } From 05ce2b78612e78be950dcd79818ce34edbe4750f Mon Sep 17 00:00:00 2001 From: James R Date: Wed, 3 Jan 2024 05:18:12 -0800 Subject: [PATCH 11/21] Battle: darken screen while outside of Overtime Barrier --- src/k_kart.c | 30 +++++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/src/k_kart.c b/src/k_kart.c index eff55c946..536fd929d 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -8796,18 +8796,38 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) K_UpdateTripwire(player); - if ((battleovertime.enabled >= 10*TICRATE) && !(player->pflags & PF_ELIMINATED) && !player->exiting) + if (battleovertime.enabled) { - fixed_t distanceToBarrier = 0; + fixed_t distanceToCenter = 0; if (battleovertime.radius > 0) { - distanceToBarrier = R_PointToDist2(player->mo->x, player->mo->y, battleovertime.x, battleovertime.y) - (player->mo->radius * 2); + distanceToCenter = R_PointToDist2(player->mo->x, player->mo->y, battleovertime.x, battleovertime.y); } - if (distanceToBarrier > battleovertime.radius) + if (distanceToCenter + player->mo->radius > battleovertime.radius) { - P_DamageMobj(player->mo, NULL, NULL, 1, DMG_TIMEOVER); + if (distanceToCenter - (player->mo->radius * 2) > battleovertime.radius && + (battleovertime.enabled >= 10*TICRATE) && + !(player->pflags & PF_ELIMINATED) && + !player->exiting) + { + P_DamageMobj(player->mo, NULL, NULL, 1, DMG_TIMEOVER); + } + + if (leveltime < player->darkness_end) + { + if (leveltime > player->darkness_end - DARKNESS_FADE_TIME) + { + player->darkness_start = leveltime - (player->darkness_end - leveltime); + } + } + else + { + player->darkness_start = leveltime; + } + + player->darkness_end = leveltime + (2 * DARKNESS_FADE_TIME); } } From 5c3783bf62a36c6463a4feb8578c96e82be6ff35 Mon Sep 17 00:00:00 2001 From: James R Date: Fri, 5 Jan 2024 15:00:12 -0800 Subject: [PATCH 12/21] HUD tracking: trackers behind walls are transparent, instead of flickering --- src/k_hud_track.cpp | 33 ++++++++++++++++++++++++++------- 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/src/k_hud_track.cpp b/src/k_hud_track.cpp index 7c956bf94..a0c53d26a 100644 --- a/src/k_hud_track.cpp +++ b/src/k_hud_track.cpp @@ -31,6 +31,13 @@ extern "C" consvar_t cv_debughudtracker; namespace { +enum class Visibility +{ + kHidden, + kVisible, + kTransparent, +}; + struct TargetTracking { static constexpr int kMaxLayers = 2; @@ -280,27 +287,29 @@ bool is_object_tracking_target(const mobj_t* mobj) } } -bool is_object_visible(mobj_t* mobj) +Visibility is_object_visible(mobj_t* mobj) { switch (mobj->type) { case MT_SUPER_FLICKY: // Always flickers. - return (leveltime & 1); + return (leveltime & 1) ? Visibility::kVisible : Visibility::kHidden; case MT_SPRAYCAN: // Flickers, but only when visible. - return P_CheckSight(stplyr->mo, mobj) && (leveltime & 1); + return P_CheckSight(stplyr->mo, mobj) && (leveltime & 1) ? Visibility::kVisible : Visibility::kHidden; default: - // Flicker when not visible. - return P_CheckSight(stplyr->mo, mobj) || (leveltime & 1); + // Transparent when not visible. + return P_CheckSight(stplyr->mo, mobj) ? Visibility::kVisible : Visibility::kTransparent; } } void K_DrawTargetTracking(const TargetTracking& target) { - if (is_object_visible(target.mobj) == false) + Visibility visibility = is_object_visible(target.mobj); + + if (visibility == Visibility::kHidden) { return; } @@ -470,7 +479,17 @@ void K_DrawTargetTracking(const TargetTracking& target) { // Draw simple overlay. vector2_t targetPos = {result.x, result.y}; - INT32 trans = target.foreground ? 0 : V_80TRANS; + INT32 trans = [&] + { + switch (visibility) + { + case Visibility::kTransparent: + return V_30TRANS; + + default: + return target.foreground ? 0 : V_80TRANS; + } + }(); TargetTracking::Animation anim = target.animation(); From cd405290c1d60b5e161abe93b00773763cd354a0 Mon Sep 17 00:00:00 2001 From: James R Date: Fri, 5 Jan 2024 17:30:10 -0800 Subject: [PATCH 13/21] HUD tracking: hide text for overlapping trackers --- src/k_hud_track.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/k_hud_track.cpp b/src/k_hud_track.cpp index a0c53d26a..3b3ddb98b 100644 --- a/src/k_hud_track.cpp +++ b/src/k_hud_track.cpp @@ -167,6 +167,7 @@ struct TargetTracking private: Graphics graphics() const { + using layers = decltype(Animation::layers); switch (mobj->type) { case MT_SUPER_FLICKY: @@ -196,7 +197,9 @@ private: {{8, 2, {kp_capsuletarget_near[1]}}}, // 4P }, {{ // Far - {2, 3, {kp_capsuletarget_far[0], kp_capsuletarget_far_text}}, // 1P + {2, 3, foreground ? + layers {kp_capsuletarget_far[0], kp_capsuletarget_far_text} : + layers {kp_capsuletarget_far[0]}}, // 1P {{2, 3, {kp_capsuletarget_far[1]}}}, // 4P }}, }; From fe60216559ff11f741515b2ef6ad28806f7aa3e2 Mon Sep 17 00:00:00 2001 From: James R Date: Fri, 5 Jan 2024 17:44:58 -0800 Subject: [PATCH 14/21] Battle UFO: slow down horizontal player momentum in tractor beam --- src/p_map.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/p_map.c b/src/p_map.c index 4bfa24462..26165ac47 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -786,6 +786,9 @@ static BlockItReturn_t PIT_CheckThing(mobj_t *thing) } P_SetObjectMomZ(tm.thing, FRACUNIT, true); + fixed_t friction = 33*FRACUNIT/35; + tm.thing->momx = FixedMul(tm.thing->momx, friction); + tm.thing->momy = FixedMul(tm.thing->momy, friction); return BMIT_CONTINUE; } From 8d2327c5c9c0045fc8358cc768928449e6c25c52 Mon Sep 17 00:00:00 2001 From: James R Date: Fri, 5 Jan 2024 17:48:44 -0800 Subject: [PATCH 15/21] Battle UFO: do not suck up into tractor beam if player is fast-falling --- src/p_map.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/p_map.c b/src/p_map.c index 26165ac47..6c0c75b72 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -785,7 +785,11 @@ static BlockItReturn_t PIT_CheckThing(mobj_t *thing) return BMIT_CONTINUE; // overhead } - P_SetObjectMomZ(tm.thing, FRACUNIT, true); + if (!tm.thing->player || !tm.thing->player->fastfall) + { + P_SetObjectMomZ(tm.thing, FRACUNIT, true); + } + fixed_t friction = 33*FRACUNIT/35; tm.thing->momx = FixedMul(tm.thing->momx, friction); tm.thing->momy = FixedMul(tm.thing->momy, friction); From 19d9d1e318efb67d6fff98c64f4cc756fb2a7d1a Mon Sep 17 00:00:00 2001 From: James R Date: Fri, 5 Jan 2024 18:05:40 -0800 Subject: [PATCH 16/21] Battle: use Easing_OutSine to shrink Overtime Barrier Modifies netsave. --- src/k_battle.c | 8 +++++++- src/k_battle.h | 1 + src/p_saveg.c | 2 ++ 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/k_battle.c b/src/k_battle.c index 78da21dc0..02aa9c24a 100644 --- a/src/k_battle.c +++ b/src/k_battle.c @@ -23,6 +23,7 @@ #include "k_rank.h" #include "music.h" #include "hu_stuff.h" +#include "m_easing.h" #define BARRIER_MIN_RADIUS (768 * mapobjectscale) @@ -701,6 +702,7 @@ void K_RunBattleOvertime(void) { S_StartSound(NULL, sfx_kc40); P_StartQuake(5, 64 * mapobjectscale, 0, NULL); + battleovertime.start = leveltime; } if (!Music_Playing("level") && !Music_Playing("battle_overtime")) @@ -719,7 +721,11 @@ void K_RunBattleOvertime(void) const fixed_t oldradius = battleovertime.radius; if (battleovertime.radius > minradius) - battleovertime.radius -= (battleovertime.initial_radius / (30*TICRATE)); + { + tic_t t = leveltime - battleovertime.start; + const tic_t duration = 30*TICRATE; + battleovertime.radius = Easing_OutSine(min(t, duration) * FRACUNIT / duration, battleovertime.initial_radius, minradius); + } if (battleovertime.radius <= minradius && oldradius > minradius) { diff --git a/src/k_battle.h b/src/k_battle.h index 023ba0c97..645821920 100644 --- a/src/k_battle.h +++ b/src/k_battle.h @@ -20,6 +20,7 @@ extern struct battleovertime UINT16 enabled; ///< Has this been initalized yet? fixed_t radius; ///< Radius of kill field fixed_t initial_radius; ///< Starting radius of kill field + tic_t start; ///< Leveltime to decrease kill field radius from fixed_t x, y, z; ///< Position to center on } battleovertime; diff --git a/src/p_saveg.c b/src/p_saveg.c index ea9b91275..26b600fa1 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -6454,6 +6454,7 @@ static void P_NetArchiveMisc(savebuffer_t *save, boolean resending) WRITEUINT16(save->p, battleovertime.enabled); WRITEFIXED(save->p, battleovertime.radius); WRITEFIXED(save->p, battleovertime.initial_radius); + WRITEUINT32(save->p, battleovertime.start); WRITEFIXED(save->p, battleovertime.x); WRITEFIXED(save->p, battleovertime.y); WRITEFIXED(save->p, battleovertime.z); @@ -6639,6 +6640,7 @@ static boolean P_NetUnArchiveMisc(savebuffer_t *save, boolean reloading) battleovertime.enabled = READUINT16(save->p); battleovertime.radius = READFIXED(save->p); battleovertime.initial_radius = READFIXED(save->p); + battleovertime.start = READUINT32(save->p); battleovertime.x = READFIXED(save->p); battleovertime.y = READFIXED(save->p); battleovertime.z = READFIXED(save->p); From 07e53b7b5098ea805232956f221728d05f871a96 Mon Sep 17 00:00:00 2001 From: James R Date: Fri, 5 Jan 2024 18:34:02 -0800 Subject: [PATCH 17/21] Battle: lose 5 spheres on guard instead of 10 --- src/p_inter.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/p_inter.c b/src/p_inter.c index 164cec39c..e7597cc7a 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -3098,7 +3098,7 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da if (clash) { - player->spheres = max(player->spheres - 10, 0); + player->spheres = max(player->spheres - 5, 0); if (inflictor) { From d0259b089653e74cc5c6239f721915a31b925cce Mon Sep 17 00:00:00 2001 From: James R Date: Fri, 5 Jan 2024 18:34:22 -0800 Subject: [PATCH 18/21] Super Flicky: speed changes - Slows down when close to its target - Slow when stunned (whipped or blocked) - Stun time increased - Whip: 5s -> 10s - Block: 1s -> 5s - Blocking launches the Flicky into the air --- src/objects/super-flicky.cpp | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/src/objects/super-flicky.cpp b/src/objects/super-flicky.cpp index 2578b0b7c..ae5e10cfd 100644 --- a/src/objects/super-flicky.cpp +++ b/src/objects/super-flicky.cpp @@ -56,14 +56,15 @@ constexpr int kSearchRadius = 1920; constexpr int kFlightRadius = 1280; constexpr int kPeckingRadius = 256; -constexpr int kFlightSpeed = 2; -constexpr int kPeckingSpeed = 8; +constexpr fixed_t kFlightSpeed = 2*FRACUNIT; +constexpr fixed_t kPeckingSpeed = FRACUNIT/2; +constexpr fixed_t kWeakSpeed = FRACUNIT/2; constexpr fixed_t kRebound = 8*FRACUNIT/9; constexpr tic_t kDelay = 8; -constexpr tic_t kStunTime = 5*TICRATE; -constexpr tic_t kBlockTime = 1*TICRATE; +constexpr tic_t kStunTime = 10*TICRATE; +constexpr tic_t kBlockTime = 5*TICRATE; constexpr int kRiseTime = 1*TICRATE; constexpr int kRiseSpeed = 4; @@ -394,15 +395,20 @@ struct Flicky : mobj_t const Fly oldFly = fly(); - if (d < ANGLE_11hh && dist < kPeckingRadius * mapobjectscale) + if (mode() == Mode::kWeak) + { + P_Thrust(this, th, FixedMul(kWeakSpeed, mapobjectscale)); + fly(Fly::kNormal); + } + else if (d < ANGLE_11hh && dist < kPeckingRadius * mapobjectscale) { // Drastically speed up when about to intersect - P_Thrust(this, th, kPeckingSpeed * mapobjectscale); + P_Thrust(this, th, FixedMul(kPeckingSpeed, mapobjectscale)); fly(Fly::kZoom); } else { - P_Thrust(this, th, kFlightSpeed * mapobjectscale); + P_Thrust(this, th, FixedMul(kFlightSpeed, mapobjectscale)); fly(Fly::kNormal); } @@ -493,6 +499,7 @@ struct Flicky : mobj_t { momx = -(momx); momy = -(momy); + P_SetObjectMomZ(this, 8*FRACUNIT, false); } void nerf() @@ -505,7 +512,6 @@ struct Flicky : mobj_t void whip() { reflect(); - P_SetObjectMomZ(this, 8*FRACUNIT, false); nerf(); From e07fbd9a6edccb8e6ba683ef701222b5804695bf Mon Sep 17 00:00:00 2001 From: James R Date: Fri, 5 Jan 2024 19:39:23 -0800 Subject: [PATCH 19/21] Do not spawn digits for overhead item display This fixes desyncs in Battle when picking up stacks of items :D --- src/p_mobj.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/p_mobj.c b/src/p_mobj.c index 85c2f2259..718a5520d 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -6400,7 +6400,7 @@ static void P_MobjSceneryThink(mobj_t *mobj) if (!(mobj->renderflags & RF_DONTDRAW)) { - const INT32 numberdisplaymin = ((mobj->target->player->itemtype == KITEM_ORBINAUT) ? 5 : 2); + //const INT32 numberdisplaymin = ((mobj->target->player->itemtype == KITEM_ORBINAUT) ? 5 : 2); // Set it to use the correct states for its condition if (mobj->target->player->itemRoulette.active) @@ -6490,6 +6490,7 @@ static void P_MobjSceneryThink(mobj_t *mobj) mobj->tracer->destscale = scale; +#if 0 if (mobj->target->player->itemamount >= numberdisplaymin && mobj->target->player->itemamount <= 10) // Meh, too difficult to support greater than this; convert this to a decent HUD object and then maybe :V { @@ -6507,6 +6508,7 @@ static void P_MobjSceneryThink(mobj_t *mobj) P_SetScale(numx, mobj->scale); numx->destscale = scale; } +#endif #if 0 if (K_IsPlayerWanted(mobj->target->player) && mobj->movecount != 1) From 2bdb7d434907df87c767e4d771a566a77df9bcac Mon Sep 17 00:00:00 2001 From: James R Date: Fri, 5 Jan 2024 20:59:18 -0800 Subject: [PATCH 20/21] Battle UFO: power-up drops take player momz, pick up immediately --- src/k_kart.c | 6 +++++- src/k_objects.h | 2 +- src/objects/battle-ufo.cpp | 12 ++++++++++-- src/p_inter.c | 9 +++++---- src/p_mobj.c | 2 +- 5 files changed, 22 insertions(+), 9 deletions(-) diff --git a/src/k_kart.c b/src/k_kart.c index 536fd929d..c481cb13a 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -7044,7 +7044,11 @@ mobj_t *K_CreatePaperItem(fixed_t x, fixed_t y, fixed_t z, angle_t angle, SINT8 drop->movecount = amount; } - drop->flags |= MF_NOCLIPTHING; + if (type < FIRSTPOWERUP) + { + // Pick up power-ups immediately + drop->flags |= MF_NOCLIPTHING; + } if (gametyperules & GTR_CLOSERPLAYERS) { diff --git a/src/k_objects.h b/src/k_objects.h index 3c68594c9..152f3ef6a 100644 --- a/src/k_objects.h +++ b/src/k_objects.h @@ -182,7 +182,7 @@ boolean Obj_IsSuperFlickyTargettingYou(const mobj_t *flicky, mobj_t *player); void Obj_BattleUFOLegThink(mobj_t *leg); void Obj_BattleUFOThink(mobj_t *ufo); void Obj_SpawnBattleUFOLegs(mobj_t *ufo); -void Obj_BattleUFODeath(mobj_t *ufo); +void Obj_BattleUFODeath(mobj_t *ufo, mobj_t *inflictor); void Obj_LinkBattleUFOSpawner(mobj_t *spawner); void Obj_UnlinkBattleUFOSpawner(mobj_t *spawner); void Obj_SpawnBattleUFOFromSpawner(void); diff --git a/src/objects/battle-ufo.cpp b/src/objects/battle-ufo.cpp index bbefa9672..cca89385a 100644 --- a/src/objects/battle-ufo.cpp +++ b/src/objects/battle-ufo.cpp @@ -137,14 +137,14 @@ void Obj_BattleUFOThink(mobj_t *mobj) K_BattleOvertimeKiller(mobj); } -void Obj_BattleUFODeath(mobj_t *mobj) +void Obj_BattleUFODeath(mobj_t *mobj, mobj_t *inflictor) { UFO* ufo = static_cast(mobj); const SINT8 flip = P_MobjFlip(ufo); ufo->momz = -(8*mapobjectscale)/2; - K_CreatePaperItem( + mobj_t* drop = K_CreatePaperItem( ufo->x, ufo->y, ufo->z + (flip), @@ -154,6 +154,14 @@ void Obj_BattleUFODeath(mobj_t *mobj) BATTLE_POWERUP_TIME ); + if (!P_MobjWasRemoved(inflictor) && inflictor->type == MT_INSTAWHIP) + { + // Take momentum of player who whips + inflictor = inflictor->target; + } + + drop->momz = !P_MobjWasRemoved(inflictor) ? inflictor->momz : 0; + if (ufo->spawner()) { g_battleufo.previousId = ufo->spawner()->id(); diff --git a/src/p_inter.c b/src/p_inter.c index e7597cc7a..ae931e8f9 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -396,9 +396,6 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) P_InstaThrust(player->mo, player->mo->angle, 20<scale < special->destscale/2) - return; if (special->threshold >= FIRSTPOWERUP) { if (P_PlayerInPain(player)) @@ -408,6 +405,10 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) } else { + // Avoid being picked up immediately + if (special->scale < special->destscale/2) + return; + if (!P_CanPickupItem(player, 3) || (player->itemamount && player->itemtype != special->threshold)) return; @@ -2347,7 +2348,7 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget Obj_MonitorOnDeath(target); break; case MT_BATTLEUFO: - Obj_BattleUFODeath(target); + Obj_BattleUFODeath(target, inflictor); break; case MT_BLENDEYE_MAIN: VS_BlendEye_Death(target); diff --git a/src/p_mobj.c b/src/p_mobj.c index 718a5520d..41f7ca8fc 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -7451,7 +7451,7 @@ static boolean P_MobjRegularThink(mobj_t *mobj) case MT_FLOATINGITEM: { P_ResetPitchRoll(mobj); - if (mobj->flags & MF_NOCLIPTHING) + if (!(mobj->flags & MF_NOGRAVITY)) { if (P_CheckDeathPitCollide(mobj)) { From 967cb65124edb0be30d7e979e73a5e195182488e Mon Sep 17 00:00:00 2001 From: James R Date: Fri, 5 Jan 2024 21:00:42 -0800 Subject: [PATCH 21/21] Battle UFO: extend hitbox down by 1/4 --- src/info.c | 2 +- src/objects/battle-ufo.cpp | 9 +++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/info.c b/src/info.c index bd6415f91..80167f48b 100644 --- a/src/info.c +++ b/src/info.c @@ -30946,7 +30946,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = sfx_cdfm19, // deathsound 0, // speed 60*FRACUNIT, // radius - 104*FRACUNIT, // height + 156*FRACUNIT, // height 0, // display offset 0, // mass 0, // damage diff --git a/src/objects/battle-ufo.cpp b/src/objects/battle-ufo.cpp index cca89385a..3dc932550 100644 --- a/src/objects/battle-ufo.cpp +++ b/src/objects/battle-ufo.cpp @@ -45,7 +45,7 @@ struct UFO : Mobj void spawn_beam() { - Mobj *x = spawn_from({0, 0, height / 4}, MT_BATTLEUFO_BEAM); + Mobj *x = spawn_from({0, 0, sprzoff() + 26}, MT_BATTLEUFO_BEAM); x->renderflags |= RF_FLOORSPRITE|RF_NOSPLATBILLBOARD|RF_SLOPESPLAT|RF_NOSPLATROLLANGLE; x->colorized = true; @@ -107,8 +107,12 @@ public: return; } + Fixed ofs = mobjinfo[MT_BATTLEUFO].height / 4; + Spawner* spawner = next(g_battleufo.previousId); - UFO* ufo = static_cast(P_SpawnMobjFromMobj(spawner, 0, 0, 250*FRACUNIT, MT_BATTLEUFO)); + UFO* ufo = static_cast(P_SpawnMobjFromMobj(spawner, 0, 0, 250*FRACUNIT - ofs, MT_BATTLEUFO)); + + ufo->sprzoff(ofs * spawner->scale()); ufo->spawner(spawner); } @@ -204,6 +208,7 @@ void Obj_BattleUFOLegThink(mobj_t *leg) // TODO: Take gravflip into account P_MoveOrigin(leg, x, y, leg->z); + leg->sprzoff = leg->target->sprzoff; } leg->momz = leg->target->momz;