From d223019e156e1584ec47f4fd4319165e299b281c Mon Sep 17 00:00:00 2001 From: James R Date: Thu, 29 Jun 2023 18:40:19 -0700 Subject: [PATCH 01/38] OPPRF and PINGF font: use bunched character spacing Intermission, Vote and ZVote affected. --- src/v_video.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/v_video.cpp b/src/v_video.cpp index ae65de142..63e03068a 100644 --- a/src/v_video.cpp +++ b/src/v_video.cpp @@ -2416,7 +2416,7 @@ void V_DrawStringScaled( if (chw) dim_fn = FixedCharacterDim; else - dim_fn = VariableCharacterDim; + dim_fn = BunchedCharacterDim; break; } @@ -2696,7 +2696,7 @@ fixed_t V_StringScaledWidth( if (chw) dim_fn = FixedCharacterDim; else - dim_fn = VariableCharacterDim; + dim_fn = BunchedCharacterDim; break; } From 8c0f7d57574d0c3a468198e052ff4404a78acbac Mon Sep 17 00:00:00 2001 From: James R Date: Thu, 29 Jun 2023 18:41:19 -0700 Subject: [PATCH 02/38] Add Draw::Font::kZVote and Draw::Font::kPing - OPPRF_FONT - PINGF_FONT --- src/v_draw.cpp | 6 ++++++ src/v_draw.hpp | 2 ++ 2 files changed, 8 insertions(+) diff --git a/src/v_draw.cpp b/src/v_draw.cpp index 7b994330e..c10933707 100644 --- a/src/v_draw.cpp +++ b/src/v_draw.cpp @@ -115,6 +115,12 @@ int Draw::font_to_fontno(Font font) case Font::kFreeplay: return KART_FONT; + + case Font::kZVote: + return OPPRF_FONT; + + case Font::kPing: + return PINGF_FONT; } return TINY_FONT; diff --git a/src/v_draw.hpp b/src/v_draw.hpp index 7acd82bfb..6234170b4 100644 --- a/src/v_draw.hpp +++ b/src/v_draw.hpp @@ -34,6 +34,8 @@ public: kGamemode, kConsole, kFreeplay, + kZVote, + kPing, }; enum class Align From 299a8b707c58286a16a54c64519e656ce79c1e9d Mon Sep 17 00:00:00 2001 From: James R Date: Thu, 29 Jun 2023 19:09:00 -0700 Subject: [PATCH 03/38] Add 2P and 3P/4P timer HUD variations --- src/CMakeLists.txt | 1 + src/hud/CMakeLists.txt | 3 +++ src/hud/timer.cpp | 52 ++++++++++++++++++++++++++++++++++++++++++ src/k_hud.c | 31 +++++++++---------------- src/k_hud.h | 2 ++ 5 files changed, 69 insertions(+), 20 deletions(-) create mode 100644 src/hud/CMakeLists.txt create mode 100644 src/hud/timer.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 24b59ae08..666c208c1 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -581,6 +581,7 @@ add_subdirectory(menus) if(SRB2_CONFIG_ENABLE_WEBM_MOVIES) add_subdirectory(media) endif() +add_subdirectory(hud) # strip debug symbols into separate file when using gcc. # to be consistent with Makefile, don't generate for OS X. diff --git a/src/hud/CMakeLists.txt b/src/hud/CMakeLists.txt new file mode 100644 index 000000000..7ef234ac1 --- /dev/null +++ b/src/hud/CMakeLists.txt @@ -0,0 +1,3 @@ +target_sources(SRB2SDL2 PRIVATE + timer.cpp +) diff --git a/src/hud/timer.cpp b/src/hud/timer.cpp new file mode 100644 index 000000000..e59955473 --- /dev/null +++ b/src/hud/timer.cpp @@ -0,0 +1,52 @@ +#include + +#include "../doomstat.h" +#include "../g_game.h" +#include "../k_hud.h" +#include "../p_local.h" +#include "../v_draw.hpp" + +using srb2::Draw; + +namespace +{ + +constexpr INT32 kHudFlags = V_HUDTRANS | V_SLIDEIN; + +}; // namespace + +void K_drawKart2PTimestamp(void) +{ + auto get_row = [] + { + if (stplyr == &players[displayplayers[0]]) + { + return Draw(286, 31).flags(V_SNAPTOTOP); + } + else + { + return Draw(286, 163).flags(V_SNAPTOBOTTOM); + } + }; + + Draw row = get_row().flags(kHudFlags | V_SNAPTORIGHT).font(Draw::Font::kZVote); + + row.patch("K_STTIMS"); + row.xy(12, 2).text("{:03}", stplyr->realtime / TICRATE); +} + +void K_drawKart4PTimestamp(void) +{ + Draw row = Draw(154, 0).flags(kHudFlags).font(Draw::Font::kZVote).align(Draw::Align::kCenter); + + auto draw = [](const Draw& row, tic_t time) + { + row.patch("K_STTIMS"); + row.xy(5, 12).text("{:03}", time / TICRATE); + }; + + auto time_of = [](int k) -> tic_t { return k <= r_splitscreen ? players[displayplayers[k]].realtime : 0u; }; + + draw(row.y(1).flags(V_SNAPTOTOP), std::max(time_of(0), time_of(1))); + draw(row.y(178).flags(V_SNAPTOBOTTOM), std::max(time_of(2), time_of(3))); +} diff --git a/src/k_hud.c b/src/k_hud.c index ecfbc6e59..acbaa24c2 100644 --- a/src/k_hud.c +++ b/src/k_hud.c @@ -5294,7 +5294,6 @@ void K_drawKartHUD(void) boolean islonesome = false; boolean battlefullscreen = false; boolean freecam = demo.freecam; //disable some hud elements w/ freecam - UINT8 i; UINT8 viewnum = R_GetViewNumber(); // Define the X and Y for each drawn object @@ -5376,27 +5375,19 @@ void K_drawKartHUD(void) islonesome = K_drawKartPositionFaces(); } - else if (viewnum == r_splitscreen - && (gametyperules & GTR_TIMELIMIT) - && timelimitintics > 0) + else if (r_splitscreen == 1) { - tic_t highestrealtime = players[displayplayers[1]].realtime; - - // Uses the highest time across all players (handles paused timer on exiting) - for (i = 1; i <= r_splitscreen; i++) - { - if (players[displayplayers[i]].realtime <= highestrealtime) - continue; - highestrealtime = players[displayplayers[i]].realtime; - } - - // Draw the timestamp (mostly) CENTERED if (LUA_HudEnabled(hud_time)) - K_drawKartTimestamp(highestrealtime, - (r_splitscreen == 1 ? TIME_X : ((BASEVIDWIDTH/2) - 69)), - TIME_Y, - V_HUDTRANS|V_SLIDEIN|V_SNAPTOTOP|(r_splitscreen == 1 ? V_SNAPTORIGHT : 0), - 0); + { + K_drawKart2PTimestamp(); + } + } + else if (viewnum == r_splitscreen) + { + if (LUA_HudEnabled(hud_time)) + { + K_drawKart4PTimestamp(); + } } if (!stplyr->spectator && !demo.freecam) // Bottom of the screen elements, don't need in spectate mode diff --git a/src/k_hud.h b/src/k_hud.h index df17214e2..9f6f7c3c9 100644 --- a/src/k_hud.h +++ b/src/k_hud.h @@ -41,6 +41,8 @@ void K_LoadKartHUDGraphics(void); void K_drawKartHUD(void); void K_drawKartFreePlay(void); void K_drawKartTimestamp(tic_t drawtime, INT32 TX, INT32 TY, INT32 splitflags, UINT8 mode); +void K_drawKart2PTimestamp(void); +void K_drawKart4PTimestamp(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); From b0b7bf8185e47a698ddd6600f1740fe8fcdc6a62 Mon Sep 17 00:00:00 2001 From: James R Date: Thu, 29 Jun 2023 18:48:05 -0700 Subject: [PATCH 04/38] Add S-Monitor power-up - Give Invincibility effect to player - Bumping players does not extend Invincibility time while power-up is active --- src/d_player.h | 1 + src/k_kart.c | 5 +++++ src/k_powerup.cpp | 21 +++++++++++++++++++++ src/p_inter.c | 3 ++- src/p_saveg.c | 6 ++++++ 5 files changed, 35 insertions(+), 1 deletion(-) diff --git a/src/d_player.h b/src/d_player.h index 39a25a8fd..008b4f731 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -463,6 +463,7 @@ typedef struct { // player_t struct for power-ups struct powerupvars_t { + UINT16 superTimer; mobj_t *flickyController; }; diff --git a/src/k_kart.c b/src/k_kart.c index ed58a5b19..cd5d81e77 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -8090,6 +8090,11 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) } } + if (player->powerup.superTimer > 0) + { + player->powerup.superTimer--; + } + if (player->guardCooldown) player->guardCooldown--; diff --git a/src/k_powerup.cpp b/src/k_powerup.cpp index f646ec4f7..1b42fa8da 100644 --- a/src/k_powerup.cpp +++ b/src/k_powerup.cpp @@ -8,6 +8,9 @@ tic_t K_PowerUpRemaining(const player_t* player, kartitems_t powerup) { switch (powerup) { + case POWERUP_SMONITOR: + return player->powerup.superTimer; + case POWERUP_SUPERFLICKY: return Obj_SuperFlickySwarmTime(player->powerup.flickyController); @@ -20,6 +23,11 @@ void K_GivePowerUp(player_t* player, kartitems_t powerup, tic_t time) { switch (powerup) { + case POWERUP_SMONITOR: + K_DoInvincibility(player, time); + player->powerup.superTimer += time; + break; + case POWERUP_SUPERFLICKY: if (K_PowerUpRemaining(player, POWERUP_SUPERFLICKY)) { @@ -38,6 +46,19 @@ void K_GivePowerUp(player_t* player, kartitems_t powerup, tic_t time) void K_DropPowerUps(player_t* player) { + auto simple_drop = [player](kartitems_t powerup, auto& timer) + { + tic_t remaining = K_PowerUpRemaining(player, powerup); + + if (remaining) + { + K_DropPaperItem(player, powerup, remaining); + timer = 0; + } + }; + + simple_drop(POWERUP_SMONITOR, player->powerup.superTimer); + if (K_PowerUpRemaining(player, POWERUP_SUPERFLICKY)) { mobj_t* swarm = player->powerup.flickyController; diff --git a/src/p_inter.c b/src/p_inter.c index e2c5ed6fc..86de35c03 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -2418,7 +2418,8 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da if (source && source != player->mo && source->player) { // Extend the invincibility if the hit was a direct hit. - if (inflictor == source && source->player->invincibilitytimer) + if (inflictor == source && source->player->invincibilitytimer && + !K_PowerUpRemaining(player, POWERUP_SMONITOR)) { tic_t kinvextend; diff --git a/src/p_saveg.c b/src/p_saveg.c index 6fea134e7..55d228f4b 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -634,6 +634,9 @@ static void P_NetArchivePlayers(savebuffer_t *save) // ACS has read access to this, so it has to be net-communicated. // It is the ONLY roundcondition that is sent over the wire and I'd like it to stay that way. WRITEUINT32(save->p, players[i].roundconditions.unlocktriggers); + + // powerupvars_t + WRITEUINT16(save->p, players[i].powerup.superTimer); } } @@ -1059,6 +1062,9 @@ static void P_NetUnArchivePlayers(savebuffer_t *save) // It is the ONLY roundcondition that is sent over the wire and I'd like it to stay that way. players[i].roundconditions.unlocktriggers = READUINT32(save->p); + // powerupvars_t + players[i].powerup.superTimer = READUINT16(save->p); + //players[i].viewheight = P_GetPlayerViewHeight(players[i]); // scale cannot be factored in at this point } } From e67ab6a1164822ed96b21b5d8254d98afdad32cc Mon Sep 17 00:00:00 2001 From: James R Date: Thu, 29 Jun 2023 19:00:07 -0700 Subject: [PATCH 05/38] Spawn Guard visual when player spawns, do not tie spawning to e-brake Object already handles turning invisible if player has no Guard. --- src/k_kart.c | 20 -------------------- src/objects/block.c | 4 ++-- src/p_mobj.c | 20 ++++++++++++++++++++ 3 files changed, 22 insertions(+), 22 deletions(-) diff --git a/src/k_kart.c b/src/k_kart.c index cd5d81e77..9d12f203c 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -10106,26 +10106,6 @@ void K_KartEbrakeVisuals(player_t *p) if (!S_SoundPlaying(p->mo, sfx_s3kd9s)) S_ReducedVFXSound(p->mo, sfx_s3kd9s, p); - // Block visuals - // (These objects track whether a player is block-eligible on their own, no worries) - if (!p->ebrakefor) - { - mobj_t *ring = P_SpawnMobj(p->mo->x, p->mo->y, p->mo->z, MT_BLOCKRING); - P_SetTarget(&ring->target, p->mo); - P_SetScale(ring, p->mo->scale); - K_MatchGenericExtraFlags(ring, p->mo); - ring->renderflags &= ~RF_DONTDRAW; - - mobj_t *body = P_SpawnMobj(p->mo->x, p->mo->y, p->mo->z, MT_BLOCKBODY); - P_SetTarget(&body->target, p->mo); - P_SetScale(body, p->mo->scale); - K_MatchGenericExtraFlags(body, p->mo); - body->renderflags |= RF_DONTDRAW; - - if (K_PlayerGuard(p)) - S_StartSound(body, sfx_s1af); - } - // HOLD! bubble. if (!p->ebrakefor) { diff --git a/src/objects/block.c b/src/objects/block.c index b2d70ed49..ee56a5d5e 100644 --- a/src/objects/block.c +++ b/src/objects/block.c @@ -6,7 +6,7 @@ void Obj_BlockRingThink (mobj_t *ring) { - if (P_MobjWasRemoved(ring->target) || !ring->target->player || !ring->target->player->ebrakefor) + if (P_MobjWasRemoved(ring->target) || !ring->target->player) { P_RemoveMobj(ring); } @@ -42,7 +42,7 @@ void Obj_BlockRingThink (mobj_t *ring) void Obj_BlockBodyThink (mobj_t *body) { - if (P_MobjWasRemoved(body->target) || !body->target->player || !body->target->player->ebrakefor) + if (P_MobjWasRemoved(body->target) || !body->target->player) { P_RemoveMobj(body); } diff --git a/src/p_mobj.c b/src/p_mobj.c index 6592fab7b..a700dcac7 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -11866,6 +11866,26 @@ void P_SpawnPlayer(INT32 playernum) } } + // Block visuals + // (These objects track whether a player is block-eligible on their own, no worries) + if (!p->spectator) + { + mobj_t *ring = P_SpawnMobj(p->mo->x, p->mo->y, p->mo->z, MT_BLOCKRING); + P_SetTarget(&ring->target, p->mo); + P_SetScale(ring, p->mo->scale); + K_MatchGenericExtraFlags(ring, p->mo); + ring->renderflags &= ~RF_DONTDRAW; + + mobj_t *body = P_SpawnMobj(p->mo->x, p->mo->y, p->mo->z, MT_BLOCKBODY); + P_SetTarget(&body->target, p->mo); + P_SetScale(body, p->mo->scale); + K_MatchGenericExtraFlags(body, p->mo); + body->renderflags |= RF_DONTDRAW; + + if (K_PlayerGuard(p)) + S_StartSound(body, sfx_s1af); + } + // I'm not refactoring the loop at the top of this file. pcount = 0; From ba114022b9dc4a2bd14868d5e62fe27aff0b7d15 Mon Sep 17 00:00:00 2001 From: James R Date: Thu, 29 Jun 2023 19:01:56 -0700 Subject: [PATCH 06/38] Add Barrier Power-Up - Guard is always up, not activated by e-brake or spheres - Guard can still be broken by player contact - No instawhip cooldown from Guard being up - No sphere loss while Guard is up - Guard appears at max size --- src/d_player.h | 1 + src/k_kart.c | 29 +++++++++++++++++++++++++---- src/k_powerup.cpp | 8 ++++++++ src/p_saveg.c | 2 ++ 4 files changed, 36 insertions(+), 4 deletions(-) diff --git a/src/d_player.h b/src/d_player.h index 008b4f731..ca73652f9 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -464,6 +464,7 @@ typedef struct { // player_t struct for power-ups struct powerupvars_t { UINT16 superTimer; + UINT16 barrierTimer; mobj_t *flickyController; }; diff --git a/src/k_kart.c b/src/k_kart.c index 9d12f203c..0db4a2046 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -45,6 +45,7 @@ #include "k_specialstage.h" #include "k_roulette.h" #include "k_podium.h" +#include "k_powerup.h" // SOME IMPORTANT VARIABLES DEFINED IN DOOMDEF.H: // gamespeed is cc (0 for easy, 1 for normal, 2 for hard) @@ -7997,7 +7998,7 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) player->spheredigestion = spheredigestion; } - if (K_PlayerGuard(player) && (player->ebrakefor%6 == 0)) + if (K_PlayerGuard(player) && !K_PowerUpRemaining(player, POWERUP_BARRIER) && (player->ebrakefor%6 == 0)) player->spheres--; } else @@ -8090,6 +8091,11 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) } } + if (player->powerup.barrierTimer > 0) + { + player->powerup.barrierTimer--; + } + if (player->powerup.superTimer > 0) { player->powerup.superTimer--; @@ -8339,7 +8345,7 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) player->pflags &= ~PF_DRIFTINPUT; } - if (K_PlayerGuard(player)) + if (K_PlayerGuard(player) && !K_PowerUpRemaining(player, POWERUP_BARRIER)) player->instaShieldCooldown = max(player->instaShieldCooldown, INSTAWHIP_DROPGUARD); // Roulette Code @@ -10062,7 +10068,17 @@ boolean K_PlayerEBrake(player_t *player) boolean K_PlayerGuard(player_t *player) { - return (K_PlayerEBrake(player) && player->spheres > 0 && player->guardCooldown == 0); + if (player->guardCooldown != 0) + { + return false; + } + + if (K_PowerUpRemaining(player, POWERUP_BARRIER)) + { + return true; + } + + return (K_PlayerEBrake(player) && player->spheres > 0); } SINT8 K_Sliptiding(player_t *player) @@ -10849,7 +10865,12 @@ void K_MoveKartPlayer(player_t *player, boolean onground) else { player->instaShieldCooldown = INSTAWHIP_COOLDOWN; - player->guardCooldown = INSTAWHIP_COOLDOWN; + + if (!K_PowerUpRemaining(player, POWERUP_BARRIER)) + { + player->guardCooldown = INSTAWHIP_COOLDOWN; + } + S_StartSound(player->mo, sfx_iwhp); mobj_t *whip = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_INSTAWHIP); P_SetTarget(&player->whip, whip); diff --git a/src/k_powerup.cpp b/src/k_powerup.cpp index 1b42fa8da..5abcc2a42 100644 --- a/src/k_powerup.cpp +++ b/src/k_powerup.cpp @@ -11,6 +11,9 @@ tic_t K_PowerUpRemaining(const player_t* player, kartitems_t powerup) case POWERUP_SMONITOR: return player->powerup.superTimer; + case POWERUP_BARRIER: + return player->powerup.barrierTimer; + case POWERUP_SUPERFLICKY: return Obj_SuperFlickySwarmTime(player->powerup.flickyController); @@ -28,6 +31,10 @@ void K_GivePowerUp(player_t* player, kartitems_t powerup, tic_t time) player->powerup.superTimer += time; break; + case POWERUP_BARRIER: + player->powerup.barrierTimer += time; + break; + case POWERUP_SUPERFLICKY: if (K_PowerUpRemaining(player, POWERUP_SUPERFLICKY)) { @@ -58,6 +65,7 @@ void K_DropPowerUps(player_t* player) }; simple_drop(POWERUP_SMONITOR, player->powerup.superTimer); + simple_drop(POWERUP_BARRIER, player->powerup.barrierTimer); if (K_PowerUpRemaining(player, POWERUP_SUPERFLICKY)) { diff --git a/src/p_saveg.c b/src/p_saveg.c index 55d228f4b..ce68fa36c 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -637,6 +637,7 @@ static void P_NetArchivePlayers(savebuffer_t *save) // powerupvars_t WRITEUINT16(save->p, players[i].powerup.superTimer); + WRITEUINT16(save->p, players[i].powerup.barrierTimer); } } @@ -1064,6 +1065,7 @@ static void P_NetUnArchivePlayers(savebuffer_t *save) // powerupvars_t players[i].powerup.superTimer = READUINT16(save->p); + players[i].powerup.barrierTimer = READUINT16(save->p); //players[i].viewheight = P_GetPlayerViewHeight(players[i]); // scale cannot be factored in at this point } From dafdb0fc10bface86011c4a3dff16ca8b1cd09eb Mon Sep 17 00:00:00 2001 From: James R Date: Thu, 29 Jun 2023 18:43:36 -0700 Subject: [PATCH 07/38] Add K_GiveBumpersToPlayer, subset of K_TakeBumpersFromPlayer functionality --- src/k_kart.c | 29 +++++++++++++++++++---------- src/k_kart.h | 1 + 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/src/k_kart.c b/src/k_kart.c index 0db4a2046..2c1acc0d9 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -4483,19 +4483,12 @@ void K_DebtStingPlayer(player_t *player, mobj_t *source) P_SetPlayerMobjState(player->mo, S_KART_SPINOUT); } -void K_TakeBumpersFromPlayer(player_t *player, player_t *victim, UINT8 amount) +void K_GiveBumpersToPlayer(player_t *player, player_t *victim, UINT8 amount) { const UINT8 oldPlayerBumpers = K_Bumpers(player); UINT8 tookBumpers = 0; - amount = min(amount, K_Bumpers(victim)); - - if (amount == 0) - { - return; - } - while (tookBumpers < amount) { const UINT8 newbumper = (oldPlayerBumpers + tookBumpers); @@ -4521,11 +4514,15 @@ void K_TakeBumpersFromPlayer(player_t *player, player_t *victim, UINT8 amount) newmo = P_SpawnMobj(newx, newy, player->mo->z, MT_BATTLEBUMPER); newmo->threshold = newbumper; - P_SetTarget(&newmo->tracer, victim->mo); + if (victim) + { + P_SetTarget(&newmo->tracer, victim->mo); + } + P_SetTarget(&newmo->target, player->mo); newmo->angle = (diff * (newbumper-1)); - newmo->color = victim->skincolor; + newmo->color = (victim ? victim : player)->skincolor; if (newbumper+1 < 2) { @@ -4545,6 +4542,18 @@ void K_TakeBumpersFromPlayer(player_t *player, player_t *victim, UINT8 amount) // :jartcookiedance: player->mo->health += tookBumpers; +} + +void K_TakeBumpersFromPlayer(player_t *player, player_t *victim, UINT8 amount) +{ + amount = min(amount, K_Bumpers(victim)); + + if (amount == 0) + { + return; + } + + K_GiveBumpersToPlayer(player, victim, amount); // Play steal sound S_StartSound(player->mo, sfx_3db06); diff --git a/src/k_kart.h b/src/k_kart.h index 9c9d876d8..b51e324e1 100644 --- a/src/k_kart.h +++ b/src/k_kart.h @@ -113,6 +113,7 @@ void K_UpdateStumbleIndicator(player_t *player); void K_UpdateSliptideZipIndicator(player_t *player); INT32 K_ExplodePlayer(player_t *player, mobj_t *inflictor, mobj_t *source); void K_DebtStingPlayer(player_t *player, mobj_t *source); +void K_GiveBumpersToPlayer(player_t *player, player_t *victim, UINT8 amount); void K_TakeBumpersFromPlayer(player_t *player, player_t *victim, UINT8 amount); void K_MineFlashScreen(mobj_t *source); void K_SpawnMineExplosion(mobj_t *source, UINT8 color, tic_t delay); From 065475ea29ed25776795b7dda2bc636f8db56da0 Mon Sep 17 00:00:00 2001 From: James R Date: Thu, 29 Jun 2023 19:06:22 -0700 Subject: [PATCH 08/38] Add Bumper power-up, give 5 bumpers to the player --- src/k_powerup.cpp | 4 ++++ src/objects/block.c | 10 ++++++++-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/k_powerup.cpp b/src/k_powerup.cpp index 5abcc2a42..c8b637955 100644 --- a/src/k_powerup.cpp +++ b/src/k_powerup.cpp @@ -35,6 +35,10 @@ void K_GivePowerUp(player_t* player, kartitems_t powerup, tic_t time) player->powerup.barrierTimer += time; break; + case POWERUP_BUMPER: + K_GiveBumpersToPlayer(player, nullptr, 5); + break; + case POWERUP_SUPERFLICKY: if (K_PowerUpRemaining(player, POWERUP_SUPERFLICKY)) { diff --git a/src/objects/block.c b/src/objects/block.c index ee56a5d5e..d9f1dbd82 100644 --- a/src/objects/block.c +++ b/src/objects/block.c @@ -3,6 +3,12 @@ #include "../k_objects.h" #include "../p_local.h" #include "../k_kart.h" +#include "../k_powerup.h" + +static INT16 guard_upscale (player_t *player) +{ + return K_PowerUpRemaining(player, POWERUP_BARRIER) ? 40 : player->spheres; +} void Obj_BlockRingThink (mobj_t *ring) { @@ -22,7 +28,7 @@ void Obj_BlockRingThink (mobj_t *ring) ring->color = mo->color; fixed_t baseScale = mo->scale / 2; - baseScale += (mo->scale / 30) * player->spheres; + baseScale += (mo->scale / 30) * guard_upscale(player); P_SetScale(ring, baseScale); // Twirl @@ -55,7 +61,7 @@ void Obj_BlockBodyThink (mobj_t *body) body->flags &= ~(MF_NOCLIPTHING); fixed_t baseScale = mo->scale / 2; - baseScale += (mo->scale / 30) * player->spheres; + baseScale += (mo->scale / 30) * guard_upscale(player); P_SetScale(body, baseScale); P_MoveOrigin(body, mo->x, mo->y, mo->z + mo->height/2); From 47a5a0b6dced9c74443e08f446932c01cb824357 Mon Sep 17 00:00:00 2001 From: James R Date: Thu, 29 Jun 2023 19:04:50 -0700 Subject: [PATCH 09/38] Add Rhythm Badge power-up, no instawhip cooldown --- src/d_player.h | 1 + src/k_kart.c | 17 +++++++++++++---- src/k_powerup.cpp | 8 ++++++++ src/p_saveg.c | 2 ++ 4 files changed, 24 insertions(+), 4 deletions(-) diff --git a/src/d_player.h b/src/d_player.h index ca73652f9..a30d5d895 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -465,6 +465,7 @@ typedef struct { struct powerupvars_t { UINT16 superTimer; UINT16 barrierTimer; + UINT16 rhythmBadgeTimer; mobj_t *flickyController; }; diff --git a/src/k_kart.c b/src/k_kart.c index 2c1acc0d9..f2ce208e2 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -8100,6 +8100,12 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) } } + if (player->powerup.rhythmBadgeTimer > 0) + { + player->instaShieldCooldown = min(player->instaShieldCooldown, 1); + player->powerup.rhythmBadgeTimer--; + } + if (player->powerup.barrierTimer > 0) { player->powerup.barrierTimer--; @@ -10891,10 +10897,13 @@ void K_MoveKartPlayer(player_t *player, boolean onground) player->flashing = max(player->flashing, 12); player->mo->momz += 4*mapobjectscale; - // Spawn in triangle formation - Obj_SpawnInstaWhipRecharge(player, 0); - Obj_SpawnInstaWhipRecharge(player, ANGLE_120); - Obj_SpawnInstaWhipRecharge(player, ANGLE_240); + if (!K_PowerUpRemaining(player, POWERUP_BADGE)) + { + // Spawn in triangle formation + Obj_SpawnInstaWhipRecharge(player, 0); + Obj_SpawnInstaWhipRecharge(player, ANGLE_120); + Obj_SpawnInstaWhipRecharge(player, ANGLE_240); + } } } diff --git a/src/k_powerup.cpp b/src/k_powerup.cpp index c8b637955..a452d307e 100644 --- a/src/k_powerup.cpp +++ b/src/k_powerup.cpp @@ -14,6 +14,9 @@ tic_t K_PowerUpRemaining(const player_t* player, kartitems_t powerup) case POWERUP_BARRIER: return player->powerup.barrierTimer; + case POWERUP_BADGE: + return player->powerup.rhythmBadgeTimer; + case POWERUP_SUPERFLICKY: return Obj_SuperFlickySwarmTime(player->powerup.flickyController); @@ -39,6 +42,10 @@ void K_GivePowerUp(player_t* player, kartitems_t powerup, tic_t time) K_GiveBumpersToPlayer(player, nullptr, 5); break; + case POWERUP_BADGE: + player->powerup.rhythmBadgeTimer += time; + break; + case POWERUP_SUPERFLICKY: if (K_PowerUpRemaining(player, POWERUP_SUPERFLICKY)) { @@ -70,6 +77,7 @@ void K_DropPowerUps(player_t* player) simple_drop(POWERUP_SMONITOR, player->powerup.superTimer); simple_drop(POWERUP_BARRIER, player->powerup.barrierTimer); + simple_drop(POWERUP_BADGE, player->powerup.rhythmBadgeTimer); if (K_PowerUpRemaining(player, POWERUP_SUPERFLICKY)) { diff --git a/src/p_saveg.c b/src/p_saveg.c index ce68fa36c..e6f7a61d6 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -638,6 +638,7 @@ static void P_NetArchivePlayers(savebuffer_t *save) // powerupvars_t WRITEUINT16(save->p, players[i].powerup.superTimer); WRITEUINT16(save->p, players[i].powerup.barrierTimer); + WRITEUINT16(save->p, players[i].powerup.rhythmBadgeTimer); } } @@ -1066,6 +1067,7 @@ static void P_NetUnArchivePlayers(savebuffer_t *save) // powerupvars_t players[i].powerup.superTimer = READUINT16(save->p); players[i].powerup.barrierTimer = READUINT16(save->p); + players[i].powerup.rhythmBadgeTimer = READUINT16(save->p); //players[i].viewheight = P_GetPlayerViewHeight(players[i]); // scale cannot be factored in at this point } From d747f312253d21cf47deb76eff2698cc7fcdaa26 Mon Sep 17 00:00:00 2001 From: James R Date: Thu, 29 Jun 2023 18:53:35 -0700 Subject: [PATCH 10/38] Add Power-Up Aura states MT_POWERUP_AURA SPR_RBOW S_POWERUP_AURA --- src/deh_tables.c | 4 ++++ src/info.c | 30 ++++++++++++++++++++++++++++++ src/info.h | 5 +++++ 3 files changed, 39 insertions(+) diff --git a/src/deh_tables.c b/src/deh_tables.c index 9c4b19c88..191fcc187 100644 --- a/src/deh_tables.c +++ b/src/deh_tables.c @@ -4586,6 +4586,8 @@ const char *const STATE_LIST[] = { // array length left dynamic for sanity testi "S_GACHABOM_RETURNING", "S_SUPER_FLICKY", + + "S_POWERUP_AURA", }; // RegEx to generate this from info.h: ^\tMT_([^,]+), --> \t"MT_\1", @@ -5717,6 +5719,8 @@ const char *const MOBJTYPE_LIST[] = { // array length left dynamic for sanity t "MT_SUPER_FLICKY", "MT_SUPER_FLICKY_CONTROLLER", + + "MT_POWERUP_AURA", }; const char *const MOBJFLAG_LIST[] = { diff --git a/src/info.c b/src/info.c index 37e2a9034..e4c0cbb2d 100644 --- a/src/info.c +++ b/src/info.c @@ -652,6 +652,7 @@ char sprnames[NUMSPRITES + 1][5] = "ITMI", "ITMN", "PWRB", + "RBOW", // power-up aura "WANT", "PBOM", // player bomb @@ -5256,6 +5257,8 @@ state_t states[NUMSTATES] = {SPR_GBOM, FF_INVERT, -1, {A_SetScale}, FRACUNIT/2, 1, S_NULL}, // S_GACHABOM_RETURNING {SPR_3DFR, 1|FF_ANIMATE, -1, {NULL}, 2, 5, S_NULL}, // S_SUPER_FLICKY + + {SPR_RBOW, FF_PAPERSPRITE|FF_ADD|FF_FULLBRIGHT|FF_ANIMATE, -1, {NULL}, 14, 2, S_NULL}, // S_POWERUP_AURA }; mobjinfo_t mobjinfo[NUMMOBJTYPES] = @@ -29896,6 +29899,33 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = MF_NOSECTOR|MF_NOBLOCKMAP|MF_NOGRAVITY|MF_NOCLIPHEIGHT|MF_SCENERY, // flags S_NULL // raisestate }, + + { // MT_POWERUP_AURA + -1, // doomednum + S_POWERUP_AURA, // spawnstate + 1000, // 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_None, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 106*FRACUNIT, // height + 0, // display offset + 0, // mass + 0, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_NOGRAVITY|MF_NOCLIPHEIGHT|MF_SCENERY, // flags + S_NULL // raisestate + }, }; skincolor_t skincolors[MAXSKINCOLORS] = { diff --git a/src/info.h b/src/info.h index 289bbe438..99c7e5bb8 100644 --- a/src/info.h +++ b/src/info.h @@ -1203,6 +1203,7 @@ typedef enum sprite SPR_ITMI, SPR_ITMN, SPR_PWRB, + SPR_RBOW, // power-up aura SPR_WANT, SPR_PBOM, // player bomb @@ -5687,6 +5688,8 @@ typedef enum state S_SUPER_FLICKY, + S_POWERUP_AURA, + S_FIRSTFREESLOT, S_LASTFREESLOT = S_FIRSTFREESLOT + NUMSTATEFREESLOTS - 1, NUMSTATES @@ -6837,6 +6840,8 @@ typedef enum mobj_type MT_SUPER_FLICKY, MT_SUPER_FLICKY_CONTROLLER, + MT_POWERUP_AURA, + MT_FIRSTFREESLOT, MT_LASTFREESLOT = MT_FIRSTFREESLOT + NUMMOBJFREESLOTS - 1, NUMMOBJTYPES From b97dede82c0df68c7159acf83360c7e8817a79e5 Mon Sep 17 00:00:00 2001 From: James R Date: Thu, 29 Jun 2023 18:42:18 -0700 Subject: [PATCH 11/38] kartitems_t: add ENDOFPOWERUPS and NUMPOWERUPS --- src/d_player.h | 2 ++ src/deh_tables.c | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/d_player.h b/src/d_player.h index a30d5d895..30cf9c0de 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -189,6 +189,8 @@ typedef enum POWERUP_BUMPER, POWERUP_BADGE, POWERUP_SUPERFLICKY, + ENDOFPOWERUPS, + NUMPOWERUPS = ENDOFPOWERUPS - FIRSTPOWERUP, } kartitems_t; typedef enum diff --git a/src/deh_tables.c b/src/deh_tables.c index 191fcc187..9453f1cba 100644 --- a/src/deh_tables.c +++ b/src/deh_tables.c @@ -6884,6 +6884,8 @@ struct int_const_s const INT_CONST[] = { {"POWERUP_BUMPER",POWERUP_BUMPER}, {"POWERUP_BADGE",POWERUP_BADGE}, {"POWERUP_SUPERFLICKY",POWERUP_SUPERFLICKY}, + {"ENDOFPOWERUPS",ENDOFPOWERUPS}, + {"NUMPOWERUPS",NUMPOWERUPS}, // kartshields_t {"KSHIELD_NONE",KSHIELD_NONE}, From c01a29c42a90ad3b257868eda3bf9c02ce4a8e3e Mon Sep 17 00:00:00 2001 From: James R Date: Thu, 29 Jun 2023 18:51:13 -0700 Subject: [PATCH 12/38] Add Power-Up Aura - Spawns on player when they use their first power-up - Lasts as long as player has any power-up - A hexagon of animated, additive, fullbright papersprites surround and move with the player, takes player's angle --- src/k_objects.h | 4 ++ src/k_powerup.cpp | 18 ++++++ src/k_powerup.h | 1 + src/objects/CMakeLists.txt | 1 + src/objects/powerup-aura.cpp | 121 +++++++++++++++++++++++++++++++++++ src/p_mobj.c | 8 +++ 6 files changed, 153 insertions(+) create mode 100644 src/objects/powerup-aura.cpp diff --git a/src/k_objects.h b/src/k_objects.h index cd645a1e7..b5cbb6e70 100644 --- a/src/k_objects.h +++ b/src/k_objects.h @@ -161,6 +161,10 @@ void Obj_SuperFlickyPlayerCollide(mobj_t *flicky, mobj_t *player); void Obj_SuperFlickyLanding(mobj_t *flicky); boolean Obj_IsSuperFlickyWhippable(const mobj_t *flicky); +/* Power-Up Aura */ +void Obj_SpawnPowerUpAura(player_t* player); +void Obj_PowerUpAuraThink(mobj_t* mobj); + #ifdef __cplusplus } // extern "C" #endif diff --git a/src/k_powerup.cpp b/src/k_powerup.cpp index a452d307e..84a1e27f3 100644 --- a/src/k_powerup.cpp +++ b/src/k_powerup.cpp @@ -25,8 +25,26 @@ tic_t K_PowerUpRemaining(const player_t* player, kartitems_t powerup) } } +boolean K_AnyPowerUpRemaining(const player_t* player) +{ + for (int k = FIRSTPOWERUP; k < ENDOFPOWERUPS; ++k) + { + if (K_PowerUpRemaining(player, static_cast(k))) + { + return true; + } + } + + return false; +} + void K_GivePowerUp(player_t* player, kartitems_t powerup, tic_t time) { + if (!K_AnyPowerUpRemaining(player)) + { + Obj_SpawnPowerUpAura(player); + } + switch (powerup) { case POWERUP_SMONITOR: diff --git a/src/k_powerup.h b/src/k_powerup.h index 736ce68fe..0598e45ce 100644 --- a/src/k_powerup.h +++ b/src/k_powerup.h @@ -9,6 +9,7 @@ extern "C" { #endif tic_t K_PowerUpRemaining(const player_t *player, kartitems_t powerup); +boolean K_AnyPowerUpRemaining(const player_t *player); void K_GivePowerUp(player_t *player, kartitems_t powerup, tic_t timer); void K_DropPowerUps(player_t *player); diff --git a/src/objects/CMakeLists.txt b/src/objects/CMakeLists.txt index 1bbf55729..2c1e68030 100644 --- a/src/objects/CMakeLists.txt +++ b/src/objects/CMakeLists.txt @@ -22,4 +22,5 @@ target_sources(SRB2SDL2 PRIVATE gachabom-rebound.cpp servant-hand.c super-flicky.cpp + powerup-aura.cpp ) diff --git a/src/objects/powerup-aura.cpp b/src/objects/powerup-aura.cpp new file mode 100644 index 000000000..80620010d --- /dev/null +++ b/src/objects/powerup-aura.cpp @@ -0,0 +1,121 @@ +#include "../info.h" +#include "../g_game.h" +#include "../m_fixed.h" +#include "../k_objects.h" +#include "../k_powerup.h" +#include "../p_local.h" +#include "../p_mobj.h" +#include "../tables.h" + +// copied from objects/monitor.c +#define FINE90 (FINEANGLES/4) +#define FINE180 (FINEANGLES/2) +#define TRUETAN(n) FINETANGENT(FINE90 + (n)) // bruh + +#define part_theta(o) ((o)->movedir) +#define part_seek(o) ((o)->extravalue1) + +namespace +{ + +constexpr int kSpriteWidth = 32; +constexpr int kNumSides = 6; + +struct Aura : mobj_t +{ + angle_t theta() const { return part_theta(this); } + void theta(angle_t n) { part_theta(this) = n; } + + unsigned seek() const { return part_seek(this); } + void seek(unsigned n) { part_seek(this) = n; } + + mobj_t* origin() const { return players[seek()].mo; } + + static void spawn(int player) + { + const fixed_t angle_factor = ANGLE_MAX / kNumSides; + + angle_t ang = 0u; + + for (int i = 0; i < kNumSides; ++i) + { + Aura* x = static_cast(P_SpawnMobj(0, 0, 0, MT_POWERUP_AURA)); + + x->theta(ang); + x->seek(player); + + ang += angle_factor; + } + } + + // copied from objects/monitor.c + static fixed_t get_inradius(fixed_t length) + { + return FixedDiv(length, 2 * TRUETAN(FINE180 / kNumSides)); + } + + bool valid() const + { + if (seek() >= MAXPLAYERS) + { + return false; + } + + if (!playeringame[seek()]) + { + return false; + } + + if (!K_AnyPowerUpRemaining(&players[seek()])) + { + return false; + } + + return true; + } + + void move() + { + if (P_MobjWasRemoved(origin())) + { + return; + } + + P_MoveOrigin(this, origin()->x, origin()->y, origin()->z); + P_InstaScale(this, 11 * origin()->scale / 10); + + translate(); + } + + void translate() + { + const fixed_t width = scale * kSpriteWidth; + const fixed_t rad = get_inradius(width); + const angle_t ang = theta() + origin()->angle; + + angle = (ang - ANGLE_90); + + sprxoff = FixedMul(FCOS(ang), rad); + spryoff = FixedMul(FSIN(ang), rad); + } +}; + +}; // namespace + +void Obj_SpawnPowerUpAura(player_t* player) +{ + Aura::spawn(player - players); +} + +void Obj_PowerUpAuraThink(mobj_t* mobj) +{ + Aura* x = static_cast(mobj); + + if (!x->valid()) + { + P_RemoveMobj(x); + return; + } + + x->move(); +} diff --git a/src/p_mobj.c b/src/p_mobj.c index a700dcac7..5e89fefbf 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -6698,6 +6698,14 @@ static void P_MobjSceneryThink(mobj_t *mobj) case MT_SUPER_FLICKY_CONTROLLER: Obj_SuperFlickyControllerThink(mobj); + if (P_MobjWasRemoved(mobj)) + { + return; + } + break; + case MT_POWERUP_AURA: + Obj_PowerUpAuraThink(mobj); + if (P_MobjWasRemoved(mobj)) { return; From 81dab762ff73a0d66b68647d3d692c618c963f99 Mon Sep 17 00:00:00 2001 From: James R Date: Thu, 29 Jun 2023 19:10:18 -0700 Subject: [PATCH 13/38] Add power-up HUD - Power-up icons are sorted by time remaining, most to least, left to right --- src/hud/CMakeLists.txt | 1 + src/hud/powerup.cpp | 131 +++++++++++++++++++++++++++++++++++++++++ src/k_hud.c | 2 + src/k_hud.h | 1 + 4 files changed, 135 insertions(+) create mode 100644 src/hud/powerup.cpp diff --git a/src/hud/CMakeLists.txt b/src/hud/CMakeLists.txt index 7ef234ac1..b30d1156e 100644 --- a/src/hud/CMakeLists.txt +++ b/src/hud/CMakeLists.txt @@ -1,3 +1,4 @@ target_sources(SRB2SDL2 PRIVATE + powerup.cpp timer.cpp ) diff --git a/src/hud/powerup.cpp b/src/hud/powerup.cpp new file mode 100644 index 000000000..c4d19ef6d --- /dev/null +++ b/src/hud/powerup.cpp @@ -0,0 +1,131 @@ +#include +#include + +#include + +#include "../core/static_vec.hpp" + +#include "../doomstat.h" +#include "../g_game.h" +#include "../k_hud.h" +#include "../k_powerup.h" +#include "../p_local.h" +#include "../r_fps.h" +#include "../v_draw.hpp" + +using srb2::Draw; + +namespace +{ + +struct Icon +{ + kartitems_t powerup; + tic_t time; + + Icon() {} + + explicit Icon(int k) : + powerup(static_cast(k)), + time(K_PowerUpRemaining(stplyr, powerup)) + { + } + + int letter() const { return 'A' + (powerup - FIRSTPOWERUP); } + + bool operator <(const Icon& b) const { return time < b.time; } + bool operator >(const Icon& b) const { return time > b.time; } +}; + +srb2::StaticVec get_powerup_list(bool ascending) +{ + srb2::StaticVec v; + + for (int k = FIRSTPOWERUP; k < ENDOFPOWERUPS; ++k) + { + Icon ico(k); + + if (ico.time) + { + v.push_back(ico); + } + } + + if (ascending) + { + std::sort(v.begin(), v.end(), std::less()); + } + else + { + std::sort(v.begin(), v.end(), std::greater()); + } + + return v; +} + +}; // namespace + +void K_drawKartPowerUps(void) +{ + struct Offsets + { + Draw row; + const char* sprite; + int spr_x; + int spr_y; + int shift_x; + int dir; + }; + + auto make_offsets = []() -> Offsets + { + auto make_drawer = [](int x, int y, Draw::Font font) -> Draw + { + return Draw(x, y).font(font).align(Draw::Align::kRight); + }; + + const int viewnum = R_GetViewNumber(); + + // 1/2P + switch (r_splitscreen) + { + case 0: + return { make_drawer(307, 55, Draw::Font::kZVote), "PWRU", -17, 7, -35, -1 }; + + case 1: + return { make_drawer(318, viewnum == 0 ? 55 : 155, Draw::Font::kPing), "PWRS", -9, 6, -19, -1 }; + } + + // 3/4P + int x = 21; + int y = 47; + + int dir = 1; + + switch (viewnum) + { + case 1: + case 3: + x = 318; + dir = -1; + } + + switch (viewnum) + { + case 2: + case 3: + y += 100; + } + + return { make_drawer(x, y, Draw::Font::kPing), "PWRS", -9, 5, 19 * dir, dir }; + }; + + Offsets i = make_offsets(); + + for (const Icon& ico : get_powerup_list(i.dir == -1)) + { + i.row.xy(i.spr_x, i.spr_y).patch(fmt::format("{0}{1:c}L{1:c}R", i.sprite, ico.letter()).c_str()); + i.row.text("{}", (ico.time + (TICRATE / 2)) / TICRATE); + i.row = i.row.x(i.shift_x); + } +} diff --git a/src/k_hud.c b/src/k_hud.c index acbaa24c2..c6d71dec9 100644 --- a/src/k_hud.c +++ b/src/k_hud.c @@ -5521,6 +5521,8 @@ void K_drawKartHUD(void) K_drawMiniPing(); } + K_drawKartPowerUps(); + if (G_IsPartyLocal(displayplayers[viewnum]) == false && !demo.playback) { K_drawDirectorHUD(); diff --git a/src/k_hud.h b/src/k_hud.h index 9f6f7c3c9..9c6d4bebd 100644 --- a/src/k_hud.h +++ b/src/k_hud.h @@ -40,6 +40,7 @@ const char *K_GetItemPatch(UINT8 item, boolean tiny); void K_LoadKartHUDGraphics(void); void K_drawKartHUD(void); void K_drawKartFreePlay(void); +void K_drawKartPowerUps(void); void K_drawKartTimestamp(tic_t drawtime, INT32 TX, INT32 TY, INT32 splitflags, UINT8 mode); void K_drawKart2PTimestamp(void); void K_drawKart4PTimestamp(void); From da80096a67c90d1c557017b1ec9b5187ebf017b2 Mon Sep 17 00:00:00 2001 From: James R Date: Thu, 29 Jun 2023 19:07:22 -0700 Subject: [PATCH 14/38] Super Flicky: pad timer to compensate for exit time --- src/objects/super-flicky.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/objects/super-flicky.cpp b/src/objects/super-flicky.cpp index c28c3250d..f48590df3 100644 --- a/src/objects/super-flicky.cpp +++ b/src/objects/super-flicky.cpp @@ -141,7 +141,7 @@ struct Controller : mobj_t x->source(player->mo); x->mode(Mode::kDescend); x->zofs(0); - x->expiry(leveltime + time); + x->expiry(leveltime + time + kRiseTime); P_SetTarget(&player->powerup.flickyController, x); From 6e80957e4fedb88e424f20beb6d27f5b31f59370 Mon Sep 17 00:00:00 2001 From: James R Date: Thu, 29 Jun 2023 19:20:33 -0700 Subject: [PATCH 15/38] Super Flicky: fix erroneous timer past flicky exit --- src/k_objects.h | 2 +- src/objects/super-flicky.cpp | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/k_objects.h b/src/k_objects.h index b5cbb6e70..9cc199bb0 100644 --- a/src/k_objects.h +++ b/src/k_objects.h @@ -151,7 +151,7 @@ void Obj_SpawnSuperFlickySwarm(player_t *owner, tic_t time); void Obj_SuperFlickyControllerThink(mobj_t *controller); void Obj_EndSuperFlickySwarm(mobj_t *controller); void Obj_ExtendSuperFlickySwarm(mobj_t *controller, tic_t time); -tic_t Obj_SuperFlickySwarmTime(const mobj_t *controller); +tic_t Obj_SuperFlickySwarmTime(mobj_t *controller); /* Super Flicky */ void Obj_SuperFlickyThink(mobj_t *flicky); diff --git a/src/objects/super-flicky.cpp b/src/objects/super-flicky.cpp index f48590df3..287fa7c7f 100644 --- a/src/objects/super-flicky.cpp +++ b/src/objects/super-flicky.cpp @@ -754,11 +754,11 @@ void Obj_ExtendSuperFlickySwarm(mobj_t* mobj, tic_t time) x->expiry(x->expiry() + time); } -tic_t Obj_SuperFlickySwarmTime(const mobj_t* mobj) +tic_t Obj_SuperFlickySwarmTime(mobj_t* mobj) { - const Controller* x = static_cast(mobj); + Controller* x = static_cast(mobj); - return x ? x->powerup_remaining() : 0u; + return !P_MobjWasRemoved(x) ? x->powerup_remaining() : 0u; } boolean Obj_IsSuperFlickyWhippable(const mobj_t* mobj) From adaec93c447b1c674f15c3df7ca5edfdb65bbbfb Mon Sep 17 00:00:00 2001 From: James R Date: Thu, 29 Jun 2023 19:23:42 -0700 Subject: [PATCH 16/38] Super Flicky: don't whip your own flickys --- src/objects/super-flicky.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/objects/super-flicky.cpp b/src/objects/super-flicky.cpp index 287fa7c7f..6e65e51ad 100644 --- a/src/objects/super-flicky.cpp +++ b/src/objects/super-flicky.cpp @@ -765,5 +765,5 @@ boolean Obj_IsSuperFlickyWhippable(const mobj_t* mobj) { const Flicky* x = static_cast(mobj); - return !x->stunned(); + return mobj == x->chasing() && !x->stunned(); } From 68f162625607fdfcf45bd1c7fcee4950f04dc592 Mon Sep 17 00:00:00 2001 From: SteelT Date: Tue, 27 Jun 2023 22:52:33 -0400 Subject: [PATCH 17/38] Add Battle UFO body/leg states and objects --- src/deh_tables.c | 14 ++++++-- src/info.c | 90 +++++++++++++++++++++++++++++++++++++++++++++++- src/info.h | 10 ++++++ 3 files changed, 110 insertions(+), 4 deletions(-) diff --git a/src/deh_tables.c b/src/deh_tables.c index 9453f1cba..f517e4484 100644 --- a/src/deh_tables.c +++ b/src/deh_tables.c @@ -4587,6 +4587,10 @@ const char *const STATE_LIST[] = { // array length left dynamic for sanity testi "S_SUPER_FLICKY", + "S_BATTLEUFO", + "S_BATTLEUFO_LEG", + "S_BATTLEUFO_DIE", + "S_POWERUP_AURA", }; @@ -5353,7 +5357,7 @@ const char *const MOBJTYPE_LIST[] = { // array length left dynamic for sanity t "MT_MONITOR_PART", "MT_MONITOR_SHARD", "MT_MAGICIANBOX", - + "MT_SLIPTIDEZIP", "MT_INSTAWHIP", @@ -5536,7 +5540,7 @@ const char *const MOBJTYPE_LIST[] = { // array length left dynamic for sanity t "MT_POWERCLASH", // Invinc/Grow no damage clash VFX "MT_GUARDBREAK", // Guard break - + "MT_PLAYERARROW", "MT_PLAYERWANTED", @@ -5720,6 +5724,10 @@ const char *const MOBJTYPE_LIST[] = { // array length left dynamic for sanity t "MT_SUPER_FLICKY", "MT_SUPER_FLICKY_CONTROLLER", + "MT_BATTLEUFO_SPAWNER", + "MT_BATTLEUFO", + "MT_BATTLEUFO_LEG", + "MT_POWERUP_AURA", }; @@ -6164,7 +6172,7 @@ const char *COLOR_ENUMS[] = { "POSNUM_BEST4", "POSNUM_BEST5", "POSNUM_BEST6", - + "INTERMISSION", }; diff --git a/src/info.c b/src/info.c index e4c0cbb2d..2a9fbdcf5 100644 --- a/src/info.c +++ b/src/info.c @@ -822,6 +822,8 @@ char sprnames[NUMSPRITES + 1][5] = "3DFR", + "BUFO", // Battle/Power-UP UFO + // First person view sprites; this is a sprite so that it can be replaced by a specialized MD2 draw later "VIEW", }; @@ -5258,6 +5260,11 @@ state_t states[NUMSTATES] = {SPR_3DFR, 1|FF_ANIMATE, -1, {NULL}, 2, 5, S_NULL}, // S_SUPER_FLICKY + // Battle/Power-UP UFO + {SPR_BUFO, 0, -1, {A_SetScale}, 3*FRACUNIT/2 , 0, S_NULL}, // S_BATTLEUFO + {SPR_BUFO, 1, -1, {A_SetScale}, 2*FRACUNIT/2, 0, S_NULL}, // S_BATTLEUFO_LEG + {SPR_BUFO, 0, 4, {A_BossScream}, 0, MT_EXPLODE, S_BATTLEUFO_DIE}, // S_BATTLEUFO_DIE + {SPR_RBOW, FF_PAPERSPRITE|FF_ADD|FF_FULLBRIGHT|FF_ANIMATE, -1, {NULL}, 14, 2, S_NULL}, // S_POWERUP_AURA }; @@ -29900,6 +29907,87 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL // raisestate }, + { // MT_BATTLEUFO_SPAWNER + -1, // doomednum + S_INVISIBLE, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 55*FRACUNIT, // radius + 95*FRACUNIT, // height + 0, // display offset + 0, // mass + 0, // damage + sfx_None, // activesound + MF_NOGRAVITY|MF_NOCLIPHEIGHT|MF_SCENERY, // flags + S_NULL // raisestate + }, + + { // MT_BATTLEUFO + -1, // doomednum + S_BATTLEUFO, // spawnstate + 1, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_BATTLEUFO_DIE, // deathstate + S_NULL, // xdeathstate + sfx_cdfm19, // deathsound + 0, // speed + 55*FRACUNIT, // radius + 96*FRACUNIT, // height + 0, // display offset + 0, // mass + 0, // damage + sfx_None, // activesound + MF_NOGRAVITY|MF_NOCLIPHEIGHT|MF_SPECIAL|MF_SHOOTABLE|MF_DONTENCOREMAP|MF_RUNSPAWNFUNC, // flags + S_NULL // raisestate + }, + + { // MT_BATTLEUFO_LEG + -1, // doomednum + S_BATTLEUFO_LEG, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + -4*FRACUNIT, // speed + 64*FRACUNIT, // radius + 55*FRACUNIT, // height + 0, // display offset + 0, // mass + 0, // damage + sfx_None, // activesound + MF_NOGRAVITY|MF_NOCLIPHEIGHT|MF_DONTENCOREMAP|MF_RUNSPAWNFUNC, // flags + S_NULL // raisestate + }, + { // MT_POWERUP_AURA -1, // doomednum S_POWERUP_AURA, // spawnstate @@ -30110,7 +30198,7 @@ skincolor_t skincolors[MAXSKINCOLORS] = { {"Position Best 4", {255, 255, 122, 122, 123, 123, 141, 141, 142, 142, 143, 143, 138, 139, 254, 30}, SKINCOLOR_NONE, 0, 0, false}, // SKINCOLOR_POSNUM_BEST4 {"Position Best 5", {152, 152, 153, 153, 154, 154, 155, 155, 156, 156, 157, 158, 159, 253, 254, 30}, SKINCOLOR_NONE, 0, 0, false}, // SKINCOLOR_POSNUM_BEST5 {"Position Best 6", {181, 181, 182, 182, 183, 183, 184, 184, 185, 185, 186, 186, 187, 187, 29, 30}, SKINCOLOR_NONE, 0, 0, false}, // SKINCOLOR_POSNUM_BEST6 - + {"Intermission", {0,80,80,81,81,81,84,85,86,87,246,248,251,26,28,31}, SKINCOLOR_NONE, 0, 0, false} // SKINCOLOR_INTERMISSION }; diff --git a/src/info.h b/src/info.h index 99c7e5bb8..b8e47715f 100644 --- a/src/info.h +++ b/src/info.h @@ -1373,6 +1373,8 @@ typedef enum sprite SPR_3DFR, + SPR_BUFO, // Battle/Power-UP UFO + // First person view sprites; this is a sprite so that it can be replaced by a specialized MD2 draw later SPR_VIEW, @@ -5688,6 +5690,10 @@ typedef enum state S_SUPER_FLICKY, + S_BATTLEUFO, + S_BATTLEUFO_LEG, + S_BATTLEUFO_DIE, + S_POWERUP_AURA, S_FIRSTFREESLOT, @@ -6840,6 +6846,10 @@ typedef enum mobj_type MT_SUPER_FLICKY, MT_SUPER_FLICKY_CONTROLLER, + MT_BATTLEUFO_SPAWNER, + MT_BATTLEUFO, + MT_BATTLEUFO_LEG, + MT_POWERUP_AURA, MT_FIRSTFREESLOT, From a24e9bb19f9d1bb738334f013dd6d5451cf061e3 Mon Sep 17 00:00:00 2001 From: SteelT Date: Tue, 27 Jun 2023 22:53:16 -0400 Subject: [PATCH 18/38] Add basic Battle UFO object functionality --- src/k_objects.h | 6 ++++ src/objects/CMakeLists.txt | 1 + src/objects/battle-ufo.c | 68 ++++++++++++++++++++++++++++++++++++++ src/p_inter.c | 6 ++-- src/p_mobj.c | 17 ++++++++-- 5 files changed, 94 insertions(+), 4 deletions(-) create mode 100644 src/objects/battle-ufo.c diff --git a/src/k_objects.h b/src/k_objects.h index b5cbb6e70..ec7093e44 100644 --- a/src/k_objects.h +++ b/src/k_objects.h @@ -161,6 +161,12 @@ void Obj_SuperFlickyPlayerCollide(mobj_t *flicky, mobj_t *player); void Obj_SuperFlickyLanding(mobj_t *flicky); boolean Obj_IsSuperFlickyWhippable(const mobj_t *flicky); +/* Battle/Power-UP UFO */ +void Obj_BattleUFOLegThink(mobj_t *leg); +void Obj_BattleUFOThink(mobj_t *ufo); +void Obj_SpawnBattleUFOLegs(mobj_t *ufo); +void Obj_BattleUFODeath(mobj_t *ufo); + /* Power-Up Aura */ void Obj_SpawnPowerUpAura(player_t* player); void Obj_PowerUpAuraThink(mobj_t* mobj); diff --git a/src/objects/CMakeLists.txt b/src/objects/CMakeLists.txt index 2c1e68030..f85b01ee4 100644 --- a/src/objects/CMakeLists.txt +++ b/src/objects/CMakeLists.txt @@ -22,5 +22,6 @@ target_sources(SRB2SDL2 PRIVATE gachabom-rebound.cpp servant-hand.c super-flicky.cpp + battle-ufo.c powerup-aura.cpp ) diff --git a/src/objects/battle-ufo.c b/src/objects/battle-ufo.c new file mode 100644 index 000000000..b3d4ad7be --- /dev/null +++ b/src/objects/battle-ufo.c @@ -0,0 +1,68 @@ +#include "../doomdef.h" +#include "../p_local.h" +#include "../k_objects.h" + +#define BATTLEUFO_LEG_ZOFFS (3*FRACUNIT) // Spawn height offset from the body +#define BATTLEUFO_LEGS (3) // Number of UFO legs to spawn +#define BATTLEUFO_BOB_AMP (4) // UFO bob strength +#define BATTLEUFO_BOB_SPEED (TICRATE*2) // UFO bob speed + +void Obj_BattleUFOThink(mobj_t *ufo) +{ + // Copied and slightly modified from k_kart.c + fixed_t sine = FixedMul(ufo->scale, BATTLEUFO_BOB_AMP * FINESINE((((M_TAU_FIXED * BATTLEUFO_BOB_SPEED) * leveltime) >> ANGLETOFINESHIFT) & FINEMASK)); + fixed_t targz = FixedMul(ufo->scale, sine) * P_MobjFlip(ufo); + ufo->momz = targz; +} + +void Obj_BattleUFODeath(mobj_t *ufo) +{ + ufo->momz = -(8*mapobjectscale)/2; + ufo->fuse = TICRATE; +} + +void Obj_SpawnBattleUFOLegs(mobj_t *ufo) +{ + INT32 i; + angle_t ang = 0; + const fixed_t angle_factor = ANGLE_MAX / BATTLEUFO_LEGS; + + for (i = 0; i < BATTLEUFO_LEGS; i++) + { + mobj_t *leg = P_SpawnMobjFromMobj(ufo, 0, 0, BATTLEUFO_LEG_ZOFFS, MT_BATTLEUFO_LEG); + P_SetTarget(&leg->target, ufo); + ang += angle_factor; + leg->angle = ang; + } +} + +void Obj_BattleUFOLegThink(mobj_t *leg) +{ + if (!leg->target || P_MobjWasRemoved(leg->target)) + { + P_RemoveMobj(leg); + return; + } + + // Rotate around the UFO + if (leg->target->health > 0) + { + leg->angle += FixedAngle(leg->info->speed); + + const angle_t fa = leg->angle>>ANGLETOFINESHIFT; + const fixed_t radius = FixedMul(14*leg->info->speed, leg->target->scale); + fixed_t x = leg->target->x + FixedMul(FINECOSINE(fa),radius); + fixed_t y = leg->target->y + FixedMul(FINESINE(fa),radius); + + // TODO: Take gravflip into account + P_MoveOrigin(leg, x, y, leg->z); + } + + leg->momz = leg->target->momz; + + if (leg->target->hitlag) + { + leg->hitlag = leg->target->hitlag; + leg->eflags |= (leg->target->eflags & MFE_DAMAGEHITLAG); + } +} diff --git a/src/p_inter.c b/src/p_inter.c index 86de35c03..a4ebc3b95 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -799,7 +799,7 @@ void P_CheckTimeLimit(void) { if (((timelimitintics + starttime - leveltime) % TICRATE) == 0) S_StartSound(NULL, sfx_s3ka7); - } + } } return; } @@ -1725,7 +1725,9 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget case MT_MONITOR: Obj_MonitorOnDeath(target); break; - + case MT_BATTLEUFO: + Obj_BattleUFODeath(target); + break; default: break; } diff --git a/src/p_mobj.c b/src/p_mobj.c index 5e89fefbf..8518b8b7b 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -8069,7 +8069,7 @@ static boolean P_MobjRegularThink(mobj_t *mobj) // cusval: responsible for disappear FX (should only happen once) // S_MAGICANBOX: sides, starting angle is set in the spawner (SetRandomFakePlayerSkin) - // S_MAGICIANBOX_TOP, S_MAGICIANBOX_BOTTOM: splats with their own offset sprite sets + // S_MAGICIANBOX_TOP, S_MAGICIANBOX_BOTTOM: splats with their own offset sprite sets mobj->extravalue2--; @@ -8436,6 +8436,16 @@ static boolean P_MobjRegularThink(mobj_t *mobj) Obj_ItemDebrisThink(mobj); break; } + case MT_BATTLEUFO: + { + Obj_BattleUFOThink(mobj); + break; + } + case MT_BATTLEUFO_LEG: + { + Obj_BattleUFOLegThink(mobj); + break; + } case MT_ROCKETSNEAKER: if (!mobj->target || !mobj->target->health) { @@ -10920,6 +10930,9 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) case MT_SPHEREBOX: Obj_RandomItemSpawn(mobj); break; + case MT_BATTLEUFO: + Obj_SpawnBattleUFOLegs(mobj); + break; default: break; } @@ -12268,7 +12281,7 @@ static mobjtype_t P_GetMobjtypeSubstitute(mapthing_t *mthing, mobjtype_t i) if ((i == MT_RANDOMITEM) && (gametyperules & (GTR_PAPERITEMS|GTR_CIRCUIT)) == (GTR_PAPERITEMS|GTR_CIRCUIT)) return MT_PAPERITEMSPOT; - + return i; } From 2ce05f018e2de70c6c9acf0779b32dbb852ccc63 Mon Sep 17 00:00:00 2001 From: James R Date: Tue, 27 Jun 2023 18:02:22 -0700 Subject: [PATCH 19/38] Add g_battleufo global, add to netsave --- src/k_battle.c | 1 + src/k_battle.h | 6 ++++++ src/objects/{battle-ufo.c => battle-ufo.cpp} | 0 src/p_saveg.c | 8 ++++++++ 4 files changed, 15 insertions(+) rename src/objects/{battle-ufo.c => battle-ufo.cpp} (100%) diff --git a/src/k_battle.c b/src/k_battle.c index 7c6dd7d09..86f4c6be7 100644 --- a/src/k_battle.c +++ b/src/k_battle.c @@ -24,6 +24,7 @@ // Battle overtime info struct battleovertime battleovertime; +struct battleufo g_battleufo; // Capsules mode enabled for this map? boolean battleprisons = false; diff --git a/src/k_battle.h b/src/k_battle.h index bd15f8b55..caa68c58a 100644 --- a/src/k_battle.h +++ b/src/k_battle.h @@ -19,6 +19,12 @@ extern struct battleovertime fixed_t x, y, z; ///< Position to center on } battleovertime; +extern struct battleufo +{ + INT32 previousId; + tic_t due; +} g_battleufo; + extern boolean battleprisons; extern INT32 nummapboxes, numgotboxes; // keep track of spawned battle mode items extern UINT8 maptargets, numtargets; diff --git a/src/objects/battle-ufo.c b/src/objects/battle-ufo.cpp similarity index 100% rename from src/objects/battle-ufo.c rename to src/objects/battle-ufo.cpp diff --git a/src/p_saveg.c b/src/p_saveg.c index e6f7a61d6..87a8f636b 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -5738,6 +5738,10 @@ static void P_NetArchiveMisc(savebuffer_t *save, boolean resending) WRITEFIXED(save->p, battleovertime.y); WRITEFIXED(save->p, battleovertime.z); + // battleufo_t + WRITEINT32(save->p, g_battleufo.previousId); + WRITEUINT32(save->p, g_battleufo.due); + WRITEUINT32(save->p, wantedcalcdelay); for (i = 0; i < NUMKARTITEMS-1; i++) WRITEUINT32(save->p, itemCooldowns[i]); @@ -5908,6 +5912,10 @@ static boolean P_NetUnArchiveMisc(savebuffer_t *save, boolean reloading) battleovertime.y = READFIXED(save->p); battleovertime.z = READFIXED(save->p); + // battleufo_t + g_battleufo.previousId = READINT32(save->p); + g_battleufo.due = READUINT32(save->p); + wantedcalcdelay = READUINT32(save->p); for (i = 0; i < NUMKARTITEMS-1; i++) itemCooldowns[i] = READUINT32(save->p); From f5d68783fc12c8293333d75ef28d08409ae86482 Mon Sep 17 00:00:00 2001 From: James R Date: Tue, 27 Jun 2023 18:04:26 -0700 Subject: [PATCH 20/38] Battle UFO spawning behavior - MT_BATTLEUFO_SPAWNER args[0] is the ID - Spawn a random UFO from the list spawner at the start of Battle - UFO spawns 200 units above the spawner - After destroyig a UFO, wait 25 seconds before spawning the next UFO (next ID in the list) --- src/k_battle.c | 8 +++ src/k_battle.h | 1 + src/k_objects.h | 5 ++ src/m_random.h | 2 + src/objects/CMakeLists.txt | 2 +- src/objects/battle-ufo.cpp | 137 ++++++++++++++++++++++++++++++++++++- src/p_mobj.c | 10 +++ src/p_tick.c | 3 + 8 files changed, 166 insertions(+), 2 deletions(-) diff --git a/src/k_battle.c b/src/k_battle.c index 86f4c6be7..c5292f9f9 100644 --- a/src/k_battle.c +++ b/src/k_battle.c @@ -350,6 +350,11 @@ void K_RunPaperItemSpawners(void) return; } + if (leveltime == g_battleufo.due) + { + Obj_SpawnBattleUFOFromSpawner(); + } + if (!IsOnInterval(interval)) { return; @@ -797,6 +802,9 @@ void K_BattleInit(boolean singleplayercontext) K_SpawnPlayerBattleBumpers(players+i); } } + + g_battleufo.due = starttime; + g_battleufo.previousId = Obj_GetFirstBattleUFOSpawnerID(); } UINT8 K_Bumpers(player_t *player) diff --git a/src/k_battle.h b/src/k_battle.h index caa68c58a..1acac3432 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 (20*TICRATE) +#define BATTLE_UFO_TIME (25*TICRATE) extern struct battleovertime { diff --git a/src/k_objects.h b/src/k_objects.h index ec7093e44..f81ddfa98 100644 --- a/src/k_objects.h +++ b/src/k_objects.h @@ -166,6 +166,11 @@ 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_LinkBattleUFOSpawner(mobj_t *spawner); +void Obj_UnlinkBattleUFOSpawner(mobj_t *spawner); +void Obj_SpawnBattleUFOFromSpawner(void); +INT32 Obj_GetFirstBattleUFOSpawnerID(void); +void Obj_ResetUFOSpawners(void); /* Power-Up Aura */ void Obj_SpawnPowerUpAura(player_t* player); diff --git a/src/m_random.h b/src/m_random.h index 039dcb6ad..54d3698a8 100644 --- a/src/m_random.h +++ b/src/m_random.h @@ -74,6 +74,8 @@ typedef enum PR_MOVINGTARGET, // Randomised moving targets + PR_BATTLEUFO, // Battle UFO spawning + PR_BOTS, // Bot spawning PRNUMCLASS diff --git a/src/objects/CMakeLists.txt b/src/objects/CMakeLists.txt index f85b01ee4..0aa872933 100644 --- a/src/objects/CMakeLists.txt +++ b/src/objects/CMakeLists.txt @@ -22,6 +22,6 @@ target_sources(SRB2SDL2 PRIVATE gachabom-rebound.cpp servant-hand.c super-flicky.cpp - battle-ufo.c + battle-ufo.cpp powerup-aura.cpp ) diff --git a/src/objects/battle-ufo.cpp b/src/objects/battle-ufo.cpp index b3d4ad7be..09a6bc954 100644 --- a/src/objects/battle-ufo.cpp +++ b/src/objects/battle-ufo.cpp @@ -1,5 +1,11 @@ +#include +#include +#include + #include "../doomdef.h" +#include "../m_random.h" #include "../p_local.h" +#include "../k_battle.h" #include "../k_objects.h" #define BATTLEUFO_LEG_ZOFFS (3*FRACUNIT) // Spawn height offset from the body @@ -7,6 +13,102 @@ #define BATTLEUFO_BOB_AMP (4) // UFO bob strength #define BATTLEUFO_BOB_SPEED (TICRATE*2) // UFO bob speed +#define spawner_id(o) ((o)->args[0]) + +#define ufo_spawner(o) ((o)->target) + +namespace +{ + +struct Spawner : mobj_t +{ + INT32 id() const { return spawner_id(this); } +}; + +struct UFO : mobj_t +{ + Spawner* spawner() const { return static_cast(ufo_spawner(this)); } + void spawner(Spawner* n) { P_SetTarget(&ufo_spawner(this), n); } +}; + +struct SpawnerCompare +{ + bool operator()(const Spawner* a, const Spawner* b) const + { + return a->id() < b->id(); + } +}; + +class SpawnerList +{ +private: + std::set set_; + +public: + void insert(Spawner* spawner) + { + auto [it, inserted] = set_.insert(spawner); + + if (inserted) + { + mobj_t* dummy = nullptr; + P_SetTarget(&dummy, spawner); + } + } + + void erase(Spawner* spawner) + { + if (set_.erase(spawner)) + { + mobj_t* dummy = spawner; + P_SetTarget(&dummy, nullptr); + } + } + + Spawner* next(INT32 order) const + { + auto it = std::upper_bound( + set_.begin(), + set_.end(), + order, + [](INT32 a, const Spawner* b) { return a < b->id(); } + ); + + return it != set_.end() ? *it : *set_.begin(); + } + + INT32 random_id() const + { + if (set_.empty()) + { + return 0; + } + + auto it = set_.begin(); + + std::advance(it, P_RandomKey(PR_BATTLEUFO, set_.size())); + + return (*std::prev(it == set_.begin() ? set_.end() : it))->id(); + } + + void spawn_ufo() const + { + if (set_.empty()) + { + return; + } + + Spawner* spawner = next(g_battleufo.previousId); + UFO* ufo = static_cast(P_SpawnMobjFromMobj(spawner, 0, 0, 200*FRACUNIT, MT_BATTLEUFO)); + + ufo->spawner(spawner); + } +}; + +SpawnerList g_spawners; + +}; // namespace + void Obj_BattleUFOThink(mobj_t *ufo) { // Copied and slightly modified from k_kart.c @@ -15,10 +117,18 @@ void Obj_BattleUFOThink(mobj_t *ufo) ufo->momz = targz; } -void Obj_BattleUFODeath(mobj_t *ufo) +void Obj_BattleUFODeath(mobj_t *mobj) { + UFO* ufo = static_cast(mobj); + ufo->momz = -(8*mapobjectscale)/2; ufo->fuse = TICRATE; + + if (ufo->spawner()) + { + g_battleufo.previousId = ufo->spawner()->id(); + g_battleufo.due = leveltime + BATTLE_UFO_TIME; + } } void Obj_SpawnBattleUFOLegs(mobj_t *ufo) @@ -66,3 +176,28 @@ void Obj_BattleUFOLegThink(mobj_t *leg) leg->eflags |= (leg->target->eflags & MFE_DAMAGEHITLAG); } } + +void Obj_LinkBattleUFOSpawner(mobj_t *spawner) +{ + g_spawners.insert(static_cast(spawner)); +} + +void Obj_UnlinkBattleUFOSpawner(mobj_t *spawner) +{ + g_spawners.erase(static_cast(spawner)); +} + +void Obj_SpawnBattleUFOFromSpawner(void) +{ + g_spawners.spawn_ufo(); +} + +INT32 Obj_GetFirstBattleUFOSpawnerID(void) +{ + return g_spawners.random_id(); +} + +void Obj_ResetUFOSpawners(void) +{ + g_spawners = {}; +} diff --git a/src/p_mobj.c b/src/p_mobj.c index 8518b8b7b..62cd0b10e 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -11175,6 +11175,11 @@ void P_RemoveMobj(mobj_t *mobj) Obj_RingShooterDelete(mobj); break; } + case MT_BATTLEUFO_SPAWNER: + { + Obj_UnlinkBattleUFOSpawner(mobj); + break; + } default: { break; @@ -13442,6 +13447,11 @@ static boolean P_SetupSpawnedMapThing(mapthing_t *mthing, mobj_t *mobj) Obj_InitLoopCenter(mobj); break; } + case MT_BATTLEUFO_SPAWNER: + { + Obj_LinkBattleUFOSpawner(mobj); + break; + } default: break; } diff --git a/src/p_tick.c b/src/p_tick.c index 871420055..1c756a8e5 100644 --- a/src/p_tick.c +++ b/src/p_tick.c @@ -41,6 +41,7 @@ #include "k_director.h" #include "k_specialstage.h" #include "acs/interface.h" +#include "k_objects.h" #ifdef PARANOIA #include "deh_tables.h" // MOBJTYPE_LIST @@ -230,6 +231,8 @@ void P_InitThinkers(void) { skyboxcenterpnts[i] = skyboxviewpnts[i] = NULL; } + + Obj_ResetUFOSpawners(); } // Adds a new thinker at the end of the list. From d3d6d4d67189f2e4f054de59b818e506e30a86b1 Mon Sep 17 00:00:00 2001 From: James R Date: Tue, 27 Jun 2023 18:06:45 -0700 Subject: [PATCH 21/38] MT_BATTLEUFO_SPAWNER: spawn with thing number 3786 Binary maps: angle becomes args[0] (ID for spawning order) --- src/info.c | 2 +- src/p_setup.c | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/info.c b/src/info.c index 2a9fbdcf5..7d82f46e4 100644 --- a/src/info.c +++ b/src/info.c @@ -29908,7 +29908,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = }, { // MT_BATTLEUFO_SPAWNER - -1, // doomednum + 3786, // doomednum S_INVISIBLE, // spawnstate 1000, // spawnhealth S_NULL, // seestate diff --git a/src/p_setup.c b/src/p_setup.c index e7c4e9fad..6d28c3828 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -7145,6 +7145,9 @@ static void P_ConvertBinaryThingTypes(void) case 2018: // MT_PETSMOKER mapthings[i].args[0] = !!(mapthings[i].options & MTF_OBJECTSPECIAL); break; + case 3786: // MT_BATTLEUFO_SPAWNER + mapthings[i].args[0] = mapthings[i].angle; + break; case FLOOR_SLOPE_THING: case CEILING_SLOPE_THING: mapthings[i].args[0] = mapthings[i].extrainfo; From 3ef583040eb56642e2c575fbcc7d420db20af249 Mon Sep 17 00:00:00 2001 From: SteelT Date: Tue, 27 Jun 2023 23:36:49 -0400 Subject: [PATCH 22/38] Add shadow to Battle UFO Also add it to the CD SS ufo per request --- src/p_mobj.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/p_mobj.c b/src/p_mobj.c index 62cd0b10e..53b668b15 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -10321,6 +10321,8 @@ static void P_DefaultMobjShadowScale(mobj_t *thing) case MT_KART_LEFTOVER: case MT_BATTLECAPSULE: case MT_SPECIAL_UFO: + case MT_CDUFO: + case MT_BATTLEUFO: thing->shadowscale = FRACUNIT; break; case MT_SMALLMACE: From b91489bec2de357c68688964819dd9c52b76b61a Mon Sep 17 00:00:00 2001 From: James R Date: Thu, 29 Jun 2023 21:10:25 -0700 Subject: [PATCH 23/38] Power-up HUD: use player color as colormap --- src/hud/powerup.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/hud/powerup.cpp b/src/hud/powerup.cpp index c4d19ef6d..dfdabca15 100644 --- a/src/hud/powerup.cpp +++ b/src/hud/powerup.cpp @@ -124,7 +124,9 @@ void K_drawKartPowerUps(void) for (const Icon& ico : get_powerup_list(i.dir == -1)) { - i.row.xy(i.spr_x, i.spr_y).patch(fmt::format("{0}{1:c}L{1:c}R", i.sprite, ico.letter()).c_str()); + i.row.xy(i.spr_x, i.spr_y) + .colormap(static_cast(stplyr->skincolor)) + .patch(fmt::format("{0}{1:c}L{1:c}R", i.sprite, ico.letter()).c_str()); i.row.text("{}", (ico.time + (TICRATE / 2)) / TICRATE); i.row = i.row.x(i.shift_x); } From 34b65a7c599404cc984aa47e218ce5e219097612 Mon Sep 17 00:00:00 2001 From: James R Date: Thu, 29 Jun 2023 21:44:17 -0700 Subject: [PATCH 24/38] Add K_TranslateTimer, get the correct timer value for time limit; use this function for splitscreen timer --- src/hud/timer.cpp | 9 +++++++-- src/k_hud.c | 24 +++++++++++++++++++----- src/k_hud.h | 2 ++ 3 files changed, 28 insertions(+), 7 deletions(-) diff --git a/src/hud/timer.cpp b/src/hud/timer.cpp index e59955473..12c09d592 100644 --- a/src/hud/timer.cpp +++ b/src/hud/timer.cpp @@ -13,6 +13,11 @@ namespace constexpr INT32 kHudFlags = V_HUDTRANS | V_SLIDEIN; +tic_t player_timer(const player_t* player) +{ + return K_TranslateTimer(player->realtime, 0, nullptr); +} + }; // namespace void K_drawKart2PTimestamp(void) @@ -32,7 +37,7 @@ void K_drawKart2PTimestamp(void) Draw row = get_row().flags(kHudFlags | V_SNAPTORIGHT).font(Draw::Font::kZVote); row.patch("K_STTIMS"); - row.xy(12, 2).text("{:03}", stplyr->realtime / TICRATE); + row.xy(12, 2).text("{:03}", player_timer(stplyr) / TICRATE); } void K_drawKart4PTimestamp(void) @@ -45,7 +50,7 @@ void K_drawKart4PTimestamp(void) row.xy(5, 12).text("{:03}", time / TICRATE); }; - auto time_of = [](int k) -> tic_t { return k <= r_splitscreen ? players[displayplayers[k]].realtime : 0u; }; + auto time_of = [](int k) -> tic_t { return k <= r_splitscreen ? player_timer(&players[displayplayers[k]]) : 0u; }; draw(row.y(1).flags(V_SNAPTOTOP), std::max(time_of(0), time_of(1))); draw(row.y(178).flags(V_SNAPTOBOTTOM), std::max(time_of(2), time_of(3))); diff --git a/src/k_hud.c b/src/k_hud.c index c6d71dec9..57d3f3fbf 100644 --- a/src/k_hud.c +++ b/src/k_hud.c @@ -1684,12 +1684,8 @@ static void K_drawKartSlotMachine(void) V_ClearClipRect(); } -void K_drawKartTimestamp(tic_t drawtime, INT32 TX, INT32 TY, INT32 splitflags, UINT8 mode) +tic_t K_TranslateTimer(tic_t drawtime, UINT8 mode, INT32 *return_jitter) { - // TIME_X = BASEVIDWIDTH-124; // 196 - // TIME_Y = 6; // 6 - - tic_t worktime; INT32 jitter = 0; if (!mode) @@ -1725,6 +1721,24 @@ void K_drawKartTimestamp(tic_t drawtime, INT32 TX, INT32 TY, INT32 splitflags, U } } + if (return_jitter) + { + *return_jitter = jitter; + } + + return drawtime; +} + +void K_drawKartTimestamp(tic_t drawtime, INT32 TX, INT32 TY, INT32 splitflags, UINT8 mode) +{ + // TIME_X = BASEVIDWIDTH-124; // 196 + // TIME_Y = 6; // 6 + + tic_t worktime; + INT32 jitter = 0; + + drawtime = K_TranslateTimer(drawtime, mode, &jitter); + V_DrawScaledPatch(TX, TY, splitflags, ((mode == 2) ? kp_lapstickerwide : kp_timestickerwide)); TX += 33; diff --git a/src/k_hud.h b/src/k_hud.h index 9c6d4bebd..055906290 100644 --- a/src/k_hud.h +++ b/src/k_hud.h @@ -36,6 +36,8 @@ struct trackingResult_t void K_ObjectTracking(trackingResult_t *result, const vector3_t *point, boolean reverse); +tic_t K_TranslateTimer(tic_t drawtime, UINT8 mode, INT32 *return_jitter); + const char *K_GetItemPatch(UINT8 item, boolean tiny); void K_LoadKartHUDGraphics(void); void K_drawKartHUD(void); From c836d27448d4bfc7e8d011f155fd5df20f30203e Mon Sep 17 00:00:00 2001 From: SteelT Date: Wed, 28 Jun 2023 00:14:57 -0400 Subject: [PATCH 25/38] Thrust player if they are under the UFO --- src/p_map.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/p_map.c b/src/p_map.c index a5cb837d6..db62c9343 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -753,6 +753,19 @@ static BlockItReturn_t PIT_CheckThing(mobj_t *thing) return BMIT_CONTINUE; } + if (thing->type == MT_BATTLEUFO) + { + if (tm.thing->type != MT_PLAYER) + { + return BMIT_CONTINUE; + } + + if (tm.thing->z > thing->z + thing->height) + return BMIT_CONTINUE; // overhead + P_SetObjectMomZ(tm.thing, FRACUNIT, true); + return BMIT_CONTINUE; + } + if (thing->type == MT_SPB) { if (tm.thing->type != MT_PLAYER From 275358e394717a8682da12eb899cec8ac0b654c9 Mon Sep 17 00:00:00 2001 From: SteelT Date: Wed, 28 Jun 2023 00:45:27 -0400 Subject: [PATCH 26/38] Increase UFO radius --- src/info.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/info.c b/src/info.c index 7d82f46e4..92f852d71 100644 --- a/src/info.c +++ b/src/info.c @@ -29951,7 +29951,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL, // xdeathstate sfx_cdfm19, // deathsound 0, // speed - 55*FRACUNIT, // radius + 60*FRACUNIT, // radius 96*FRACUNIT, // height 0, // display offset 0, // mass From bf394f1f38da6ec31d4b769359ebae325855d9bc Mon Sep 17 00:00:00 2001 From: SteelT Date: Thu, 29 Jun 2023 11:54:18 -0400 Subject: [PATCH 27/38] UFO beam spawning behavior - Spawned from underneath the UFO and is thrusted downwards - Is spawned as splats instead of papersprites - Colorized to sapphire - Despawns on any ground contact --- src/deh_tables.c | 3 +++ src/info.c | 31 ++++++++++++++++++++++++++++++- src/info.h | 3 +++ src/k_objects.h | 1 + src/objects/battle-ufo.cpp | 28 +++++++++++++++++++++++++++- src/p_mobj.c | 5 +++++ 6 files changed, 69 insertions(+), 2 deletions(-) diff --git a/src/deh_tables.c b/src/deh_tables.c index f517e4484..bec4d9eb7 100644 --- a/src/deh_tables.c +++ b/src/deh_tables.c @@ -4590,6 +4590,8 @@ const char *const STATE_LIST[] = { // array length left dynamic for sanity testi "S_BATTLEUFO", "S_BATTLEUFO_LEG", "S_BATTLEUFO_DIE", + "S_BATTLEUFO_BEAM1", + "S_BATTLEUFO_BEAM2", "S_POWERUP_AURA", }; @@ -5727,6 +5729,7 @@ const char *const MOBJTYPE_LIST[] = { // array length left dynamic for sanity t "MT_BATTLEUFO_SPAWNER", "MT_BATTLEUFO", "MT_BATTLEUFO_LEG", + "MT_BATTLEUFO_BEAM", "MT_POWERUP_AURA", }; diff --git a/src/info.c b/src/info.c index 92f852d71..71ebf8855 100644 --- a/src/info.c +++ b/src/info.c @@ -5264,6 +5264,8 @@ state_t states[NUMSTATES] = {SPR_BUFO, 0, -1, {A_SetScale}, 3*FRACUNIT/2 , 0, S_NULL}, // S_BATTLEUFO {SPR_BUFO, 1, -1, {A_SetScale}, 2*FRACUNIT/2, 0, S_NULL}, // S_BATTLEUFO_LEG {SPR_BUFO, 0, 4, {A_BossScream}, 0, MT_EXPLODE, S_BATTLEUFO_DIE}, // S_BATTLEUFO_DIE + {SPR_DEZL, 1|FF_ANIMATE, 15, {NULL}, 2, 5, S_BATTLEUFO_BEAM2}, // S_BATTLEUFO_BEAM1 + {SPR_DEZL, 3, -1, {NULL}, 0, 0, S_NULL}, // S_BATTLEUFO_BEAM2 {SPR_RBOW, FF_PAPERSPRITE|FF_ADD|FF_FULLBRIGHT|FF_ANIMATE, -1, {NULL}, 14, 2, S_NULL}, // S_POWERUP_AURA }; @@ -22881,7 +22883,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = MF_NOGRAVITY|MF_NOCLIPHEIGHT|MF_DONTENCOREMAP, // flags S_NULL // raisestate }, - + { // MT_SIGNSPARKLE -1, // doomednum S_SIGNSPARK1, // spawnstate @@ -29988,6 +29990,33 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL // raisestate }, + { // MT_BATTLEUFO_BEAM + -1, // doomednum + S_BATTLEUFO_BEAM1, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + -(FRACUNIT/2), // speed + 64*FRACUNIT, // radius + 55*FRACUNIT, // height + 0, // display offset + 0, // mass + 0, // damage + sfx_None, // activesound + MF_NOGRAVITY|MF_NOCLIP|MF_DONTENCOREMAP, // flags + S_NULL // raisestate + }, + { // MT_POWERUP_AURA -1, // doomednum S_POWERUP_AURA, // spawnstate diff --git a/src/info.h b/src/info.h index b8e47715f..f5f402566 100644 --- a/src/info.h +++ b/src/info.h @@ -5693,6 +5693,8 @@ typedef enum state S_BATTLEUFO, S_BATTLEUFO_LEG, S_BATTLEUFO_DIE, + S_BATTLEUFO_BEAM1, + S_BATTLEUFO_BEAM2, S_POWERUP_AURA, @@ -6849,6 +6851,7 @@ typedef enum mobj_type MT_BATTLEUFO_SPAWNER, MT_BATTLEUFO, MT_BATTLEUFO_LEG, + MT_BATTLEUFO_BEAM, MT_POWERUP_AURA, diff --git a/src/k_objects.h b/src/k_objects.h index f81ddfa98..f48fb7e21 100644 --- a/src/k_objects.h +++ b/src/k_objects.h @@ -171,6 +171,7 @@ void Obj_UnlinkBattleUFOSpawner(mobj_t *spawner); void Obj_SpawnBattleUFOFromSpawner(void); INT32 Obj_GetFirstBattleUFOSpawnerID(void); void Obj_ResetUFOSpawners(void); +void Obj_BattleUFOBeamThink(mobj_t *beam); /* Power-Up Aura */ void Obj_SpawnPowerUpAura(player_t* player); diff --git a/src/objects/battle-ufo.cpp b/src/objects/battle-ufo.cpp index 09a6bc954..e4d45551d 100644 --- a/src/objects/battle-ufo.cpp +++ b/src/objects/battle-ufo.cpp @@ -29,6 +29,15 @@ struct UFO : mobj_t { Spawner* spawner() const { return static_cast(ufo_spawner(this)); } void spawner(Spawner* n) { P_SetTarget(&ufo_spawner(this), n); } + void spawn_beam() + { + mobj_t *x; + + x = P_SpawnMobjFromMobj(this, 0, 0, this->z - this->height, MT_BATTLEUFO_BEAM); + x->renderflags |= RF_FLOORSPRITE|RF_NOSPLATBILLBOARD|RF_SLOPESPLAT|RF_NOSPLATROLLANGLE; + x->colorized = true; + x->color = SKINCOLOR_SAPPHIRE; + } }; struct SpawnerCompare @@ -109,12 +118,19 @@ SpawnerList g_spawners; }; // namespace -void Obj_BattleUFOThink(mobj_t *ufo) +void Obj_BattleUFOThink(mobj_t *mobj) { + UFO* ufo = static_cast(mobj); + // Copied and slightly modified from k_kart.c fixed_t sine = FixedMul(ufo->scale, BATTLEUFO_BOB_AMP * FINESINE((((M_TAU_FIXED * BATTLEUFO_BOB_SPEED) * leveltime) >> ANGLETOFINESHIFT) & FINEMASK)); fixed_t targz = FixedMul(ufo->scale, sine) * P_MobjFlip(ufo); ufo->momz = targz; + + if ((leveltime/2) & 1) + { + ufo->spawn_beam(); + } } void Obj_BattleUFODeath(mobj_t *mobj) @@ -201,3 +217,13 @@ void Obj_ResetUFOSpawners(void) { g_spawners = {}; } + +void Obj_BattleUFOBeamThink(mobj_t *beam) +{ + P_SetObjectMomZ(beam, beam->info->speed, true); + + if (P_IsObjectOnGround(beam)) + { + P_RemoveMobj(beam); + } +} diff --git a/src/p_mobj.c b/src/p_mobj.c index 53b668b15..1e0c6f905 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -8446,6 +8446,11 @@ static boolean P_MobjRegularThink(mobj_t *mobj) Obj_BattleUFOLegThink(mobj); break; } + case MT_BATTLEUFO_BEAM: + { + Obj_BattleUFOBeamThink(mobj); + break; + } case MT_ROCKETSNEAKER: if (!mobj->target || !mobj->target->health) { From dd958dd502ae7c2796b699cebf997b135bc19123 Mon Sep 17 00:00:00 2001 From: SteelT Date: Thu, 29 Jun 2023 12:12:36 -0400 Subject: [PATCH 28/38] Make UFO beam fullbright --- src/info.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/info.c b/src/info.c index 71ebf8855..cedeaee2e 100644 --- a/src/info.c +++ b/src/info.c @@ -5264,8 +5264,8 @@ state_t states[NUMSTATES] = {SPR_BUFO, 0, -1, {A_SetScale}, 3*FRACUNIT/2 , 0, S_NULL}, // S_BATTLEUFO {SPR_BUFO, 1, -1, {A_SetScale}, 2*FRACUNIT/2, 0, S_NULL}, // S_BATTLEUFO_LEG {SPR_BUFO, 0, 4, {A_BossScream}, 0, MT_EXPLODE, S_BATTLEUFO_DIE}, // S_BATTLEUFO_DIE - {SPR_DEZL, 1|FF_ANIMATE, 15, {NULL}, 2, 5, S_BATTLEUFO_BEAM2}, // S_BATTLEUFO_BEAM1 - {SPR_DEZL, 3, -1, {NULL}, 0, 0, S_NULL}, // S_BATTLEUFO_BEAM2 + {SPR_DEZL, 1|FF_ANIMATE|FF_FULLBRIGHT, 15, {NULL}, 2, 5, S_BATTLEUFO_BEAM2}, // S_BATTLEUFO_BEAM1 + {SPR_DEZL, 3|FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL}, // S_BATTLEUFO_BEAM2 {SPR_RBOW, FF_PAPERSPRITE|FF_ADD|FF_FULLBRIGHT|FF_ANIMATE, -1, {NULL}, 14, 2, S_NULL}, // S_POWERUP_AURA }; From ad3c2e0b21af3af0cd255ed6b272b91dfac21cf5 Mon Sep 17 00:00:00 2001 From: SteelT Date: Thu, 29 Jun 2023 12:19:51 -0400 Subject: [PATCH 29/38] UFO spawns 250 units above the spawner instead --- src/objects/battle-ufo.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/objects/battle-ufo.cpp b/src/objects/battle-ufo.cpp index e4d45551d..d300bce08 100644 --- a/src/objects/battle-ufo.cpp +++ b/src/objects/battle-ufo.cpp @@ -108,7 +108,7 @@ public: } Spawner* spawner = next(g_battleufo.previousId); - UFO* ufo = static_cast(P_SpawnMobjFromMobj(spawner, 0, 0, 200*FRACUNIT, MT_BATTLEUFO)); + UFO* ufo = static_cast(P_SpawnMobjFromMobj(spawner, 0, 0, 250*FRACUNIT, MT_BATTLEUFO)); ufo->spawner(spawner); } From cfe1e44428f3f727bf94560ccb3c9897362b54fc Mon Sep 17 00:00:00 2001 From: SteelT Date: Thu, 29 Jun 2023 13:29:31 -0400 Subject: [PATCH 30/38] No player contact damage Make UFO solid --- src/info.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/info.c b/src/info.c index cedeaee2e..4ecdd9af4 100644 --- a/src/info.c +++ b/src/info.c @@ -29959,7 +29959,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 0, // mass 0, // damage sfx_None, // activesound - MF_NOGRAVITY|MF_NOCLIPHEIGHT|MF_SPECIAL|MF_SHOOTABLE|MF_DONTENCOREMAP|MF_RUNSPAWNFUNC, // flags + MF_NOGRAVITY|MF_SOLID|MF_SHOOTABLE|MF_DONTENCOREMAP|MF_RUNSPAWNFUNC, // flags S_NULL // raisestate }, From fd56b67b1b7e98acc88a50bd5a56c314ad48928c Mon Sep 17 00:00:00 2001 From: SteelT Date: Thu, 29 Jun 2023 13:58:00 -0400 Subject: [PATCH 31/38] Battle UFO instawhip damage --- src/k_collide.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/k_collide.cpp b/src/k_collide.cpp index cc3dd492d..ad780a044 100644 --- a/src/k_collide.cpp +++ b/src/k_collide.cpp @@ -920,11 +920,12 @@ boolean K_InstaWhipCollide(mobj_t *shield, mobj_t *victim) || victim->type == MT_BANANA || victim->type == MT_EGGMANITEM || victim->type == MT_BALLHOG || victim->type == MT_SSMINE || victim->type == MT_LANDMINE || victim->type == MT_SINK || victim->type == MT_GARDENTOP || victim->type == MT_DROPTARGET || victim->type == MT_BATTLECAPSULE - || victim->type == MT_MONITOR || victim->type == MT_SPECIAL_UFO) + || victim->type == MT_MONITOR || victim->type == MT_SPECIAL_UFO || victim->type == MT_BATTLEUFO) { // Monitor hack. We can hit monitors once per instawhip, no multihit shredding! // Damage values in Obj_MonitorGetDamage. - if (victim->type == MT_MONITOR) + // Apply to UFO also -- steelt 29062023 + if (victim->type == MT_MONITOR || victim->type == MT_BATTLEUFO) { if (shield->extravalue1 == 1) return false; From 30adb8559eec8984908a82140fcebef25232d2ff Mon Sep 17 00:00:00 2001 From: SteelT Date: Thu, 29 Jun 2023 17:08:22 -0400 Subject: [PATCH 32/38] Increase UFO height --- src/info.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/info.c b/src/info.c index 4ecdd9af4..360e3d887 100644 --- a/src/info.c +++ b/src/info.c @@ -29954,7 +29954,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = sfx_cdfm19, // deathsound 0, // speed 60*FRACUNIT, // radius - 96*FRACUNIT, // height + 104*FRACUNIT, // height 0, // display offset 0, // mass 0, // damage From 41ca39788128c014891d66f8202deea02a0f13db Mon Sep 17 00:00:00 2001 From: SteelT Date: Thu, 29 Jun 2023 17:10:28 -0400 Subject: [PATCH 33/38] Don't thrust player if the UFO is dead --- src/p_map.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/p_map.c b/src/p_map.c index db62c9343..2d00b808e 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -757,11 +757,19 @@ static BlockItReturn_t PIT_CheckThing(mobj_t *thing) { if (tm.thing->type != MT_PLAYER) { - return BMIT_CONTINUE; + return BMIT_CONTINUE; // not a player + } + + if (thing->health <= 0) + { + return BMIT_CONTINUE; // dead } if (tm.thing->z > thing->z + thing->height) + { return BMIT_CONTINUE; // overhead + } + P_SetObjectMomZ(tm.thing, FRACUNIT, true); return BMIT_CONTINUE; } From 6e33281baf0c282f5aafabda769356a239458195 Mon Sep 17 00:00:00 2001 From: SteelT Date: Thu, 29 Jun 2023 17:10:44 -0400 Subject: [PATCH 34/38] Despawn UFO after touching the ground --- src/objects/battle-ufo.cpp | 2 +- src/p_mobj.c | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/objects/battle-ufo.cpp b/src/objects/battle-ufo.cpp index d300bce08..27255029a 100644 --- a/src/objects/battle-ufo.cpp +++ b/src/objects/battle-ufo.cpp @@ -138,7 +138,6 @@ void Obj_BattleUFODeath(mobj_t *mobj) UFO* ufo = static_cast(mobj); ufo->momz = -(8*mapobjectscale)/2; - ufo->fuse = TICRATE; if (ufo->spawner()) { @@ -185,6 +184,7 @@ void Obj_BattleUFOLegThink(mobj_t *leg) } leg->momz = leg->target->momz; + leg->fuse = leg->target->fuse; if (leg->target->hitlag) { diff --git a/src/p_mobj.c b/src/p_mobj.c index 1e0c6f905..59203fe52 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -6951,6 +6951,14 @@ static boolean P_MobjDeadThink(mobj_t *mobj) Obj_UFOPieceDead(mobj); break; } + case MT_BATTLEUFO: + { + if (P_IsObjectOnGround(mobj) && mobj->fuse == 0) + { + mobj->fuse = TICRATE; + } + break; + } default: break; } @@ -9672,6 +9680,8 @@ static boolean P_CanFlickerFuse(mobj_t *mobj) case MT_SNAPPER_LEG: case MT_MINECARTSEG: case MT_MONITOR_PART: + case MT_BATTLEUFO: + case MT_BATTLEUFO_LEG: return true; case MT_RANDOMITEM: From dae2142fbedaf6faf1dc97bfd6ba0f0c7eeac652 Mon Sep 17 00:00:00 2001 From: SteelT Date: Thu, 29 Jun 2023 17:11:40 -0400 Subject: [PATCH 35/38] Fix UFO beam spawn height on scaled maps --- src/objects/battle-ufo.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/objects/battle-ufo.cpp b/src/objects/battle-ufo.cpp index 27255029a..12e0f7585 100644 --- a/src/objects/battle-ufo.cpp +++ b/src/objects/battle-ufo.cpp @@ -33,7 +33,7 @@ struct UFO : mobj_t { mobj_t *x; - x = P_SpawnMobjFromMobj(this, 0, 0, this->z - this->height, MT_BATTLEUFO_BEAM); + x = P_SpawnMobjFromMobj(this, 0, 0, FixedDiv(this->height / 4, this->scale), MT_BATTLEUFO_BEAM); x->renderflags |= RF_FLOORSPRITE|RF_NOSPLATBILLBOARD|RF_SLOPESPLAT|RF_NOSPLATROLLANGLE; x->colorized = true; x->color = SKINCOLOR_SAPPHIRE; From 06acc1c07f907364c53c2286f5e590fdf06cd6fc Mon Sep 17 00:00:00 2001 From: SteelT Date: Thu, 29 Jun 2023 21:13:21 -0400 Subject: [PATCH 36/38] Spawn powerup orb on death Spawns random powerup --- src/d_player.h | 1 + src/deh_tables.c | 1 + src/objects/battle-ufo.cpp | 12 ++++++++++++ 3 files changed, 14 insertions(+) diff --git a/src/d_player.h b/src/d_player.h index 30cf9c0de..a3f3143aa 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -190,6 +190,7 @@ typedef enum POWERUP_BADGE, POWERUP_SUPERFLICKY, ENDOFPOWERUPS, + LASTPOWERUP = ENDOFPOWERUPS - 1, NUMPOWERUPS = ENDOFPOWERUPS - FIRSTPOWERUP, } kartitems_t; diff --git a/src/deh_tables.c b/src/deh_tables.c index bec4d9eb7..78aaeca84 100644 --- a/src/deh_tables.c +++ b/src/deh_tables.c @@ -6896,6 +6896,7 @@ struct int_const_s const INT_CONST[] = { {"POWERUP_BADGE",POWERUP_BADGE}, {"POWERUP_SUPERFLICKY",POWERUP_SUPERFLICKY}, {"ENDOFPOWERUPS",ENDOFPOWERUPS}, + {"LASTPOWERUP",LASTPOWERUP}, {"NUMPOWERUPS",NUMPOWERUPS}, // kartshields_t diff --git a/src/objects/battle-ufo.cpp b/src/objects/battle-ufo.cpp index 12e0f7585..db8ef23c9 100644 --- a/src/objects/battle-ufo.cpp +++ b/src/objects/battle-ufo.cpp @@ -7,6 +7,7 @@ #include "../p_local.h" #include "../k_battle.h" #include "../k_objects.h" +#include "../k_kart.h" #define BATTLEUFO_LEG_ZOFFS (3*FRACUNIT) // Spawn height offset from the body #define BATTLEUFO_LEGS (3) // Number of UFO legs to spawn @@ -136,9 +137,20 @@ void Obj_BattleUFOThink(mobj_t *mobj) void Obj_BattleUFODeath(mobj_t *mobj) { UFO* ufo = static_cast(mobj); + const SINT8 flip = P_MobjFlip(ufo); ufo->momz = -(8*mapobjectscale)/2; + K_CreatePaperItem( + ufo->x, + ufo->y, + ufo->z + (flip), + 0, + flip, + P_RandomRange(PR_BATTLEUFO, FIRSTPOWERUP, LASTPOWERUP), + BATTLE_POWERUP_TIME + ); + if (ufo->spawner()) { g_battleufo.previousId = ufo->spawner()->id(); From d8afc7597d4676ef95eee66f86299f6787d99367 Mon Sep 17 00:00:00 2001 From: James R Date: Thu, 29 Jun 2023 20:18:02 -0700 Subject: [PATCH 37/38] Add K_FlingPaperItem, split off random thrust functionality Battle UFO drops do not fling. --- src/k_battle.c | 2 +- src/k_kart.c | 24 ++++++++++++++++-------- src/k_kart.h | 1 + src/objects/monitor.c | 4 ++-- 4 files changed, 20 insertions(+), 11 deletions(-) diff --git a/src/k_battle.c b/src/k_battle.c index c5292f9f9..a34cc9cdb 100644 --- a/src/k_battle.c +++ b/src/k_battle.c @@ -417,7 +417,7 @@ void K_RunPaperItemSpawners(void) } else { - K_CreatePaperItem( + K_FlingPaperItem( battleovertime.x, battleovertime.y, battleovertime.z + (128 * mapobjectscale * flip), FixedAngle(P_RandomRange(PR_ITEM_ROULETTE, 0, 359) * FRACUNIT), flip, 0, 0 diff --git a/src/k_kart.c b/src/k_kart.c index f2ce208e2..509897819 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -6613,13 +6613,6 @@ mobj_t *K_CreatePaperItem(fixed_t x, fixed_t y, fixed_t z, angle_t angle, SINT8 drop->destscale = (3*drop->destscale)/2; drop->angle = angle; - P_Thrust(drop, - FixedAngle(P_RandomFixed(PR_ITEM_ROULETTE) * 180) + angle, - 16*mapobjectscale); - - drop->momz = flip * 3 * mapobjectscale; - if (drop->eflags & MFE_UNDERWATER) - drop->momz = (117 * drop->momz) / 200; if (type == 0) { @@ -6665,6 +6658,21 @@ mobj_t *K_CreatePaperItem(fixed_t x, fixed_t y, fixed_t z, angle_t angle, SINT8 return drop; } +mobj_t *K_FlingPaperItem(fixed_t x, fixed_t y, fixed_t z, angle_t angle, SINT8 flip, UINT8 type, UINT16 amount) +{ + mobj_t *drop = K_CreatePaperItem(x, y, z, angle, flip, type, amount); + + P_Thrust(drop, + FixedAngle(P_RandomFixed(PR_ITEM_ROULETTE) * 180) + angle, + 16*mapobjectscale); + + drop->momz = flip * 3 * mapobjectscale; + if (drop->eflags & MFE_UNDERWATER) + drop->momz = (117 * drop->momz) / 200; + + return drop; +} + void K_DropPaperItem(player_t *player, UINT8 itemtype, UINT16 itemamount) { if (!player->mo || P_MobjWasRemoved(player->mo)) @@ -6672,7 +6680,7 @@ void K_DropPaperItem(player_t *player, UINT8 itemtype, UINT16 itemamount) return; } - mobj_t *drop = K_CreatePaperItem( + mobj_t *drop = K_FlingPaperItem( player->mo->x, player->mo->y, player->mo->z + player->mo->height/2, player->mo->angle + ANGLE_90, P_MobjFlip(player->mo), itemtype, itemamount diff --git a/src/k_kart.h b/src/k_kart.h index b51e324e1..ecf32b771 100644 --- a/src/k_kart.h +++ b/src/k_kart.h @@ -152,6 +152,7 @@ void K_KartUpdatePosition(player_t *player); void K_UpdateAllPlayerPositions(void); SINT8 K_GetTotallyRandomResult(UINT8 useodds); mobj_t *K_CreatePaperItem(fixed_t x, fixed_t y, fixed_t z, angle_t angle, SINT8 flip, UINT8 type, UINT16 amount); +mobj_t *K_FlingPaperItem(fixed_t x, fixed_t y, fixed_t z, angle_t angle, SINT8 flip, UINT8 type, UINT16 amount); void K_DropPaperItem(player_t *player, UINT8 itemtype, UINT16 itemamount); void K_PopPlayerShield(player_t *player); void K_DropItems(player_t *player); diff --git a/src/objects/monitor.c b/src/objects/monitor.c index 072cfbe84..acde862a1 100644 --- a/src/objects/monitor.c +++ b/src/objects/monitor.c @@ -668,13 +668,13 @@ Obj_MonitorOnDeath (mobj_t *monitor) const UINT32 localseed = restore_item_rng(sharedseed); adjust_monitor_drop(monitor, - K_CreatePaperItem( + K_FlingPaperItem( monitor->x, monitor->y, monitor->z + (128 * mapobjectscale * flip), i * ang, flip, K_ItemResultToType(result), K_ItemResultToAmount(result))); - // K_CreatePaperItem may advance RNG, so update our + // K_FlingPaperItem may advance RNG, so update our // copy of the seed afterward sharedseed = restore_item_rng(localseed); } From 38c5703020783930f7fb5ed1cd9686b996415337 Mon Sep 17 00:00:00 2001 From: James R Date: Thu, 29 Jun 2023 23:01:27 -0700 Subject: [PATCH 38/38] Add Battle UFO to minimap --- src/k_hud.c | 6 ++++++ src/p_mobj.c | 1 + 2 files changed, 7 insertions(+) diff --git a/src/k_hud.c b/src/k_hud.c index c6d71dec9..ebff13085 100644 --- a/src/k_hud.c +++ b/src/k_hud.c @@ -83,6 +83,7 @@ static patch_t *kp_wouldyoustillcatchmeifiwereaworm; static patch_t *kp_catcherminimap; static patch_t *kp_emeraldminimap[2]; static patch_t *kp_capsuleminimap[3]; +static patch_t *kp_battleufominimap; static patch_t *kp_ringsticker[2]; static patch_t *kp_ringstickersplit[4]; @@ -372,6 +373,8 @@ void K_LoadKartHUDGraphics(void) HU_UpdatePatch(&kp_capsuleminimap[1], "MINICAP2"); HU_UpdatePatch(&kp_capsuleminimap[2], "MINICAP3"); + HU_UpdatePatch(&kp_battleufominimap, "MINIBUFO"); + // Rings & Lives HU_UpdatePatch(&kp_ringsticker[0], "RNGBACKA"); HU_UpdatePatch(&kp_ringsticker[1], "RNGBACKB"); @@ -3998,6 +4001,9 @@ static void K_drawKartMinimap(void) if (battleprisons) workingPic = kp_capsuleminimap[2]; break; + case MT_BATTLEUFO: + workingPic = kp_battleufominimap; + break; default: break; } diff --git a/src/p_mobj.c b/src/p_mobj.c index 59203fe52..b2470decd 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -5331,6 +5331,7 @@ static boolean P_IsTrackerType(INT32 type) case MT_OVERTIME_CENTER: case MT_MONITOR: case MT_EMERALD: + case MT_BATTLEUFO: return true; default: