diff --git a/src/k_hud.c b/src/k_hud.c index b245aa91d..e6f88d224 100644 --- a/src/k_hud.c +++ b/src/k_hud.c @@ -197,11 +197,14 @@ patch_t *kp_autoroulette; patch_t *kp_capsuletarget_arrow[2][2]; patch_t *kp_capsuletarget_icon[2]; -patch_t *kp_capsuletarget_far[2]; +patch_t *kp_capsuletarget_far[2][2]; patch_t *kp_capsuletarget_far_text[2]; -patch_t *kp_capsuletarget_near[8]; +patch_t *kp_capsuletarget_near[2][8]; -patch_t *kp_superflickytarget[4]; +patch_t *kp_superflickytarget[2][4]; + +patch_t *kp_spraycantarget_far[2][6]; +patch_t *kp_spraycantarget_near[2][6]; patch_t *kp_button_a[2][2]; patch_t *kp_button_b[2][2]; @@ -758,23 +761,72 @@ void K_LoadKartHUDGraphics(void) for (i = 0; i < 2; i++) { buffer[7] = '0'+i; - HU_UpdatePatch(&kp_capsuletarget_far[i], "%s", buffer); + HU_UpdatePatch(&kp_capsuletarget_far[0][i], "%s", buffer); + } + + sprintf(buffer, "HUDC4PBx"); + for (i = 0; i < 2; i++) + { + buffer[7] = '0'+i; + HU_UpdatePatch(&kp_capsuletarget_far[1][i], "%s", buffer); } sprintf(buffer, "HUDCAPAx"); for (i = 0; i < 8; i++) { buffer[7] = '0'+i; - HU_UpdatePatch(&kp_capsuletarget_near[i], "%s", buffer); + HU_UpdatePatch(&kp_capsuletarget_near[0][i], "%s", buffer); + } + + sprintf(buffer, "HUDC4PAx"); + for (i = 0; i < 8; i++) + { + buffer[7] = '0'+i; + HU_UpdatePatch(&kp_capsuletarget_near[1][i], "%s", buffer); } sprintf(buffer, "HUDFLKAx"); for (i = 0; i < 4; i++) { buffer[7] = '0'+i; - HU_UpdatePatch(&kp_superflickytarget[i], "%s", buffer); + HU_UpdatePatch(&kp_superflickytarget[0][i], "%s", buffer); } + sprintf(buffer, "H4PFLKAx"); + for (i = 0; i < 4; i++) + { + buffer[7] = '0'+i; + HU_UpdatePatch(&kp_superflickytarget[1][i], "%s", buffer); + } + + sprintf(buffer, "SPCNBFAx"); + for (i = 0; i < 6; i++) + { + buffer[7] = '1'+i; + HU_UpdatePatch(&kp_spraycantarget_far[0][i], "%s", buffer); + } + + sprintf(buffer, "SPCNSFAx"); + for (i = 0; i < 6; i++) + { + buffer[7] = '1'+i; + HU_UpdatePatch(&kp_spraycantarget_far[1][i], "%s", buffer); + } + + sprintf(buffer, "SPCNBCLx"); + for (i = 0; i < 6; i++) + { + buffer[7] = '1'+i; + HU_UpdatePatch(&kp_spraycantarget_near[0][i], "%s", buffer); + } + + sprintf(buffer, "SPCNSCLx"); + for (i = 0; i < 6; i++) + { + buffer[7] = '1'+i; + HU_UpdatePatch(&kp_spraycantarget_near[1][i], "%s", buffer); + } + K_LoadButtonGraphics(kp_button_a[0], 'A'); K_LoadButtonGraphics(kp_button_a[1], 'N'); K_LoadButtonGraphics(kp_button_b[0], 'B'); diff --git a/src/k_hud.h b/src/k_hud.h index d982c851b..b16c15e2c 100644 --- a/src/k_hud.h +++ b/src/k_hud.h @@ -55,11 +55,14 @@ void K_DrawSticker(INT32 x, INT32 y, INT32 width, INT32 flags, boolean isSmall); extern patch_t *kp_capsuletarget_arrow[2][2]; extern patch_t *kp_capsuletarget_icon[2]; -extern patch_t *kp_capsuletarget_far[2]; +extern patch_t *kp_capsuletarget_far[2][2]; extern patch_t *kp_capsuletarget_far_text[2]; -extern patch_t *kp_capsuletarget_near[8]; +extern patch_t *kp_capsuletarget_near[2][8]; -extern patch_t *kp_superflickytarget[4]; +extern patch_t *kp_superflickytarget[2][4]; + +extern patch_t *kp_spraycantarget_far[2][6]; +extern patch_t *kp_spraycantarget_near[2][6]; extern patch_t *kp_autoroulette; diff --git a/src/k_hud_track.cpp b/src/k_hud_track.cpp index 5b07a975f..d6c108dc6 100644 --- a/src/k_hud_track.cpp +++ b/src/k_hud_track.cpp @@ -1,5 +1,6 @@ #include #include +#include #include #include "core/static_vec.hpp" @@ -18,6 +19,11 @@ #include "st_stuff.h" #include "v_video.h" +#ifdef WIN32 +#undef near +#undef far +#endif + using namespace srb2; namespace @@ -25,6 +31,28 @@ namespace struct TargetTracking { + static constexpr int kMaxLayers = 2; + + struct Animation + { + int frames; + int tics_per_frame; + StaticVec layers; + int32_t video_flags = 0; + }; + + struct Graphics + { + struct SplitscreenPair + { + Animation p1; + std::optional p4; + }; + + SplitscreenPair near; + std::optional far; + }; + mobj_t* mobj; vector3_t point; fixed_t camDist; @@ -45,11 +73,36 @@ struct TargetTracking case MT_SUPER_FLICKY: return static_cast(Obj_SuperFlickyOwner(mobj)->color); + default: return SKINCOLOR_NONE; } } + Animation animation() const + { + const fixed_t farDistance = 1280 * mapobjectscale; + bool useNear = (camDist < farDistance); + + Graphics gfx = graphics(); + Graphics::SplitscreenPair& pair = useNear || !gfx.far ? gfx.near : *gfx.far; + Animation& anim = r_splitscreen <= 1 || !pair.p4 ? pair.p1 : *pair.p4; + + return anim; + } + + bool uses_off_screen_arrow() const + { + switch (mobj->type) + { + case MT_SPRAYCAN: + return false; + + default: + return true; + } + } + StaticVec player_emeralds_vec() const { StaticVec emeralds; @@ -100,6 +153,45 @@ struct TargetTracking return nullptr; } + +private: + Graphics graphics() const + { + switch (mobj->type) + { + case MT_SUPER_FLICKY: + return { + { // Near + {4, 2, {kp_superflickytarget[0]}}, // 1P + {{4, 2, {kp_superflickytarget[1]}}}, // 4P + }, + }; + + case MT_SPRAYCAN: + return { + { // Near + {6, 2, {kp_spraycantarget_near[0]}, V_ADD}, // 1P + {{6, 2, {kp_spraycantarget_near[1]}, V_ADD}}, // 4P + }, + {{ // Far + {6, 2, {kp_spraycantarget_far[0]}, V_ADD}, // 1P + {{6, 2, {kp_spraycantarget_far[1]}, V_ADD}}, // 4P + }}, + }; + + default: + return { + { // Near + {8, 2, {kp_capsuletarget_near[0]}}, // 1P + {{8, 2, {kp_capsuletarget_near[1]}}}, // 4P + }, + {{ // Far + {2, 3, {kp_capsuletarget_far[0], kp_capsuletarget_far_text}}, // 1P + {{2, 3, {kp_capsuletarget_far[1]}}}, // 4P + }}, + }; + } + } }; void K_DrawTargetTracking(const TargetTracking& target) @@ -116,6 +208,11 @@ void K_DrawTargetTracking(const TargetTracking& target) // Off-screen, draw alongside the borders of the screen. // Probably the most complicated thing. + if (target.uses_off_screen_arrow() == false) + { + return; + } + int32_t scrVal = 240; vector2_t screenSize = {}; @@ -265,54 +362,23 @@ void K_DrawTargetTracking(const TargetTracking& target) else { // Draw simple overlay. - const fixed_t farDistance = 1280 * mapobjectscale; - bool useNear = (target.camDist < farDistance); + vector2_t targetPos = {result.x, result.y}; - vector2_t targetPos = {}; + TargetTracking::Animation anim = target.animation(); - bool visible = P_CheckSight(stplyr->mo, target.mobj); - - if ((visible == false || target.mobj->type == MT_SUPER_FLICKY) && (leveltime & 1)) + for (patch_t** array : anim.layers) { - // Flicker when not visible. - return; - } + patch_t* patch = array[(leveltime / anim.tics_per_frame) % anim.frames]; - targetPos.x = result.x; - targetPos.y = result.y; - - auto draw = [&](patch_t* patch) - { V_DrawFixedPatch( targetPos.x - ((patch->width << FRACBITS) >> 1), targetPos.y - ((patch->height << FRACBITS) >> 1), FRACUNIT, - V_SPLITSCREEN, + V_SPLITSCREEN | anim.video_flags, patch, colormap ); }; - - if (target.mobj->type == MT_SUPER_FLICKY) - { - timer = (leveltime / 2); - draw(kp_superflickytarget[timer % 4]); - } - else if (useNear == true) - { - timer = (leveltime / 2); - draw(kp_capsuletarget_near[timer % 8]); - } - else - { - timer = (leveltime / 3); - draw(kp_capsuletarget_far[timer & 1]); - - if (r_splitscreen <= 1) - { - draw(kp_capsuletarget_far_text[timer & 1]); - } - } } } @@ -390,11 +456,32 @@ bool is_object_tracking_target(const mobj_t* mobj) 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) @@ -418,6 +505,11 @@ 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, diff --git a/src/p_mobj.c b/src/p_mobj.c index 50f05b680..77e2872cf 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -5342,6 +5342,7 @@ static boolean P_IsTrackerType(INT32 type) case MT_EMERALD: case MT_BATTLEUFO: case MT_SUPER_FLICKY: + case MT_SPRAYCAN: return true; default: @@ -10412,6 +10413,7 @@ static void P_DefaultMobjShadowScale(mobj_t *thing) case MT_SPECIAL_UFO: case MT_CDUFO: case MT_BATTLEUFO: + case MT_SPRAYCAN: thing->shadowscale = FRACUNIT; break; case MT_SMALLMACE: