mirror of
https://git.do.srb2.org/KartKrew/Kart-Public.git
synced 2025-01-27 03:30:50 +00:00
ec1af1bbf7
Co-Authored-By: Sally Coolatta <tehrealsalt@gmail.com> Co-Authored-By: James R <justsomejames2@gmail.com> Co-Authored-By: Monster Iestyn <iestynjealous@ntlworld.com> Co-Authored-By: katsy <katmint@live.com> Place Frame Interpolation in "Experimental" video options header This seems like an appropriate way to describe the feature for now. Add smooth level platter under interpolation, `renderdeltatics` `renderdeltatics` can be used as a standard delta time in any place, allowing for smooth menus. It will always be equal to `realtics` when frame interpolation is turned off, producing consistent framerate behavior everywhere it is used. Add smooth rendering to save select screen Add smooth rendering to Record/NiGHTS Attack, F_SkyScroll Ensure viewsector is accurate to viewx/viewy This fixes a potential crash in OpenGL when changing between levels. Ensure + commands get executed before map start Always have precise_t defined Fix misc dropshadow issues Reset view interpolation on level load Remove unnecessary precipmobj thinker hack Add reset interpolation state functions Reset precip interpolation on snap to ceil Reset mobj interp state on TeleportMove Only swap view interp state if a tick is run Run anti-lag chasecam at tic frequency Fixes jittery and unstable chasecam in high latency netgames Homogenize mobj interpolations Add sector plane level interpolations Add SectorScroll interpolator Add SideScroll interpolator Add Polyobj interpolator Intialize interpolator list at a better time Delete interpolators associated with thinkers Interpolate mobj angles and player drawangle Interpolate HWR_DrawModel Add functions to handle interpolation Much less code duplication P_InitAngle, to fix angle interpolation on spawning objects Fully fix drop shadows It used the thing's floorz / ceilingz directly -- that wouldn't account for interpolated coordinates. Do not speed up underwater/heatwave effect in OpenGL Closer OpenGL underwater/heatwave effect to Software Interpolate from time of previous tic Previously interpolated from last 35th of a second, which may be offset from game time due to connection lag. Consider this the proper fix to 54148a0dd0 too. Calculate FPS stuff even if frame is skipped I decided ultimately to actually keep the frame skip optimization disabled, because I think it is actually a little bit helpful that you can still get accurate rendering perfstats while paused, however if we decide otherwise then we can have this optimization back without making the game act like it's lagging. Keep rect in memory Feel better about this than creating one all da time Lots of FPS stuff - Disabled VSync, due to the numerous problems it has. - Instead, added an FPS cap. - Frame interpolation is now tied to fpscap != 35. - By default, the FPS cap is set to the monitor's refresh rate. - Rewrote the FPS counter. (This also consolidates several more commits ahead of this fixing various issues. -eid) Misc changes after Kart cherry-picks Fix renderdeltatics with new timing data Update mobj oldstates before all thinkers Allow FPS cap values Adjust how FPS cap is checked to improve FPS stability Fix precip crash from missing vars Improve the framerate limiter's timing for extreme stable FPS Handle the sleep at the end of D_SRB2Loop instead of the start Simplifies logic in the other parts of the loop, and fixes problems with it frequently waiting too long. Reset mobj interp state on add Add mobj interpolator on load netgame Move mobj interpolators to r_fps Dynamic slope interpolators I_GetFrameTime to try and improve frame pace (It doesn't feel that much better though.) Move I_FinishUpdate to D_SRB2Loop to sync screen updates with FPS cap, use timestamps in I_FrameCapSleep to simplify the code Fix plane interpolation light level flickering Fix flickering plane interpolation for OpenGL in the exact same way Funny OpenGL renderer being at least 50% copy-pasted Software code :) P_SetOrigin & P_MoveOrigin to replace P_TeleportMove Convert P_TeleportMove use to origin funcs Revert "P_InitAngle, to fix angle interpolation on spawning objects" This reverts commit a80c98bd164a2748cbbfad9027b34601185d93f5. Waypoint polyobjects interpolate z & children Add interpolation to more moving plane types Adds interpolation to the following: - Crumbling platforms - Mario blocks - Floatbob platforms (this one works really strangely due to two thinkers, maybe double-check this one?) Reset overlays interp states each TryRunTics Interpolate model interpolation (lol) Use interp tracer pos for GL linkdraw Papersprite angle interpolation Makes the ending signpost smooth Move intermission emerald bounce to ticker Bring back shadows on polyobjects Also optimizes the method used so rings can show their shadows too. Using just the subsector is a tad bit imprecise admittedly but any more precise methods get really laggy. Fix a bunch of ticking in hu_ drawing functions Revert "Reset overlays interp states each TryRunTics" This reverts commit a71a216faa20e8751b3bd0157354e8d748940c92. Move intro ticking out of the drawer Adjust 1up monitor icon z offsets Fixes interpolation issues with 1up monitors. Delta time choose player menu animations Add drawerlib deltaTime function Interpolate afterimages further back Use old sleep in dedicated mode Clamp cechotimer to 0 Fixes issues with cechos staying on-screen and glitching out (NiGHTS items for example). Revert "Remove unnecessary precipmobj thinker hack" This reverts commit 0e38208620d19ec2ab690740438ac2fc7862a49e. Fix frame pacing when game lags behind The frame timestamp should've been made at the start of the frame, not the end. Fix I_FrameCapSleep not respecting cpusleep Jonathan Joestar bruh Allow dedicated to use precise sleep timing again Instead of only using one old sleep, just enforce framerate cap to match TICRATE. Make Lua TeleportMove call MoveOrigin Reset Metal fume interp state on appear Add interpdebug Put interpdebug stuff in perfstats instead Add timescale cvar Slow the game down to debug animations / interpolation problems! Speed it up if you need to get somewhere quickly while mapping! Enable timescale outside of DEVELOP builds It has NETVAR, so it should be fine -- put an end to useful debugging features excluded in multiplayer! Force interpolation when timescale != 1.0 Reset old_z in MT_LOCKON think Fixes interpolation artifacting due to spawn pos. Fix cutscenes in interp Fix boss1 laser in interp Interpolate mobj scale Precalculate refresh rate Slower PCs can have issue querying mode over and over. This might kinda suck for windowed mode if you have different refresh rate displays but oh well Fix interp scaling crashing software Reset interp scale when Lua sets .scale Disable angle interp on fresh mobjs Fix interp scale crash for hires sprites Interp shadow scales Copy interp state in P_SpawnMobjFromMobj Fix multiplayer character select Don't interpolate mobj state if frac = 1.0 Fix Mario block item placement Interpolate spritescale/offset x/y Fix offset copies for SpawnMobjFromMobj THANKS SAL Add Lua HUD drawlists Buffers draw calls between tics to ensure hooks run at the originally intended rate. Rename drawerlib deltaTime to getDeltaTime Make renderisnewtic is false between tics I know what I'm doing! I swear Completely refactor timing system Time is now tracked internally in the game using I_GetPreciseTime and I_UpdateTime. I_Time now pulls from this internal timer. The system code no longer needs to keep track of time itself. This significantly improves frame and tic timing in interp mode, resulting in a much smoother image with essentially no judder at any framerate. Ensure mobj interpolators reset on level load Ensure view is not interpolated on first frame Disable sprite offset interpolation (for now) Refactor timing code even more System layer is greatly simplified and framecap logic has been moved internally. I_Sleep now takes a sleep duration and I_SleepDuration generically implements a precise sleep with spin loop.
2190 lines
67 KiB
C
2190 lines
67 KiB
C
// SONIC ROBO BLAST 2
|
|
//-----------------------------------------------------------------------------
|
|
// Copyright (C) 1993-1996 by id Software, Inc.
|
|
// Copyright (C) 1998-2000 by DooM Legacy Team.
|
|
// Copyright (C) 1999-2018 by Sonic Team Junior.
|
|
//
|
|
// This program is free software distributed under the
|
|
// terms of the GNU General Public License, version 2.
|
|
// See the 'LICENSE' file for more details.
|
|
//-----------------------------------------------------------------------------
|
|
/// \file st_stuff.c
|
|
/// \brief Status bar code
|
|
/// Does the face/direction indicator animatin.
|
|
/// Does palette indicators as well (red pain/berserk, bright pickup)
|
|
|
|
#include "doomdef.h"
|
|
#include "g_game.h"
|
|
#include "r_local.h"
|
|
#include "p_local.h"
|
|
#include "f_finale.h"
|
|
#include "st_stuff.h"
|
|
#include "i_video.h"
|
|
#include "v_video.h"
|
|
#include "z_zone.h"
|
|
#include "hu_stuff.h"
|
|
#include "s_sound.h"
|
|
#include "i_system.h"
|
|
#include "m_menu.h"
|
|
#include "m_cheat.h"
|
|
#include "p_setup.h" // NiGHTS grading
|
|
#include "k_kart.h" // SRB2kart
|
|
|
|
//random index
|
|
#include "m_random.h"
|
|
|
|
// item finder
|
|
#include "m_cond.h"
|
|
|
|
#ifdef HWRENDER
|
|
#include "hardware/hw_main.h"
|
|
#endif
|
|
|
|
#ifdef HAVE_BLUA
|
|
#include "lua_hud.h"
|
|
#include "lua_hudlib_drawlist.h"
|
|
#include "lua_hook.h"
|
|
#endif
|
|
|
|
#include "r_fps.h"
|
|
|
|
UINT16 objectsdrawn = 0;
|
|
|
|
//
|
|
// STATUS BAR DATA
|
|
//
|
|
|
|
patch_t *facerankprefix[MAXSKINS]; // ranking
|
|
patch_t *facewantprefix[MAXSKINS]; // wanted
|
|
patch_t *facemmapprefix[MAXSKINS]; // minimap
|
|
|
|
// ------------------------------------------
|
|
// status bar overlay
|
|
// ------------------------------------------
|
|
|
|
// icons for overlay
|
|
patch_t *sboscore; // Score logo
|
|
patch_t *sbotime; // Time logo
|
|
patch_t *sbocolon; // Colon for time
|
|
patch_t *sboperiod; // Period for time centiseconds
|
|
patch_t *livesback; // Lives icon background
|
|
static patch_t *nrec_timer; // Timer for NiGHTS records
|
|
static patch_t *sborings;
|
|
static patch_t *sboover;
|
|
static patch_t *timeover;
|
|
static patch_t *stlivex;
|
|
static patch_t *rrings;
|
|
static patch_t *getall; // Special Stage HUD
|
|
static patch_t *timeup; // Special Stage HUD
|
|
static patch_t *hunthoming[6];
|
|
static patch_t *itemhoming[6];
|
|
static patch_t *race1;
|
|
static patch_t *race2;
|
|
static patch_t *race3;
|
|
static patch_t *racego;
|
|
//static patch_t *ttlnum;
|
|
static patch_t *nightslink;
|
|
static patch_t *count5;
|
|
static patch_t *count4;
|
|
static patch_t *count3;
|
|
static patch_t *count2;
|
|
static patch_t *count1;
|
|
static patch_t *count0;
|
|
static patch_t *curweapon;
|
|
static patch_t *normring;
|
|
static patch_t *bouncering;
|
|
static patch_t *infinityring;
|
|
static patch_t *autoring;
|
|
static patch_t *explosionring;
|
|
static patch_t *scatterring;
|
|
static patch_t *grenadering;
|
|
static patch_t *railring;
|
|
static patch_t *jumpshield;
|
|
static patch_t *forceshield;
|
|
static patch_t *ringshield;
|
|
static patch_t *watershield;
|
|
static patch_t *bombshield;
|
|
static patch_t *pityshield;
|
|
static patch_t *invincibility;
|
|
static patch_t *sneakers;
|
|
static patch_t *gravboots;
|
|
static patch_t *nonicon;
|
|
static patch_t *bluestat;
|
|
static patch_t *byelstat;
|
|
static patch_t *orngstat;
|
|
static patch_t *redstat;
|
|
static patch_t *yelstat;
|
|
static patch_t *nbracket;
|
|
static patch_t *nhud[12];
|
|
static patch_t *nsshud;
|
|
static patch_t *narrow[9];
|
|
static patch_t *nredar[8]; // Red arrow
|
|
static patch_t *drillbar;
|
|
static patch_t *drillfill[3];
|
|
static patch_t *capsulebar;
|
|
static patch_t *capsulefill;
|
|
patch_t *ngradeletters[7];
|
|
static patch_t *minus5sec;
|
|
static patch_t *minicaps;
|
|
static patch_t *gotrflag;
|
|
static patch_t *gotbflag;
|
|
|
|
// Midnight Channel:
|
|
static patch_t *hud_tv1;
|
|
static patch_t *hud_tv2;
|
|
|
|
#ifdef HAVE_DISCORDRPC
|
|
// Discord Rich Presence
|
|
static patch_t *envelope;
|
|
#endif
|
|
|
|
// SRB2kart
|
|
|
|
hudinfo_t hudinfo[NUMHUDITEMS] =
|
|
{
|
|
{ 34, 176}, // HUD_LIVESNAME
|
|
{ 16, 176}, // HUD_LIVESPIC
|
|
{ 74, 184}, // HUD_LIVESNUM
|
|
{ 38, 186}, // HUD_LIVESX
|
|
|
|
{ 16, 42}, // HUD_RINGS
|
|
{ 220, 10}, // HUD_RINGSSPLIT
|
|
{ 112, 42}, // HUD_RINGSNUM
|
|
{ 288, 10}, // HUD_RINGSNUMSPLIT
|
|
|
|
{ 16, 10}, // HUD_SCORE
|
|
{ 128, 10}, // HUD_SCORENUM
|
|
|
|
{ 17, 26}, // HUD_TIME
|
|
{ 136, 10}, // HUD_TIMESPLIT
|
|
{ 88, 26}, // HUD_MINUTES
|
|
{ 188, 10}, // HUD_MINUTESSPLIT
|
|
{ 88, 26}, // HUD_TIMECOLON
|
|
{ 188, 10}, // HUD_TIMECOLONSPLIT
|
|
{ 112, 26}, // HUD_SECONDS
|
|
{ 212, 10}, // HUD_SECONDSSPLIT
|
|
{ 112, 26}, // HUD_TIMETICCOLON
|
|
{ 136, 26}, // HUD_TICS
|
|
|
|
{ 112, 56}, // HUD_SS_TOTALRINGS
|
|
{ 288, 40}, // HUD_SS_TOTALRINGS_SPLIT
|
|
|
|
{ 110, 93}, // HUD_GETRINGS
|
|
{ 160, 93}, // HUD_GETRINGSNUM
|
|
{ 124, 160}, // HUD_TIMELEFT
|
|
{ 168, 176}, // HUD_TIMELEFTNUM
|
|
{ 130, 93}, // HUD_TIMEUP
|
|
{ 152, 168}, // HUD_HUNTPICS
|
|
{ 152, 24}, // HUD_GRAVBOOTSICO
|
|
{ 240, 160}, // HUD_LAP
|
|
};
|
|
|
|
#ifdef HAVE_BLUA
|
|
static huddrawlist_h luahuddrawlist_game;
|
|
#endif
|
|
|
|
//
|
|
// STATUS BAR CODE
|
|
//
|
|
|
|
boolean ST_SameTeam(player_t *a, player_t *b)
|
|
{
|
|
// Just pipe team messages to everyone in co-op or race.
|
|
if (!G_BattleGametype())
|
|
return true;
|
|
|
|
// Spectator chat.
|
|
if (a->spectator && b->spectator)
|
|
return true;
|
|
|
|
// Team chat.
|
|
if (G_GametypeHasTeams())
|
|
return a->ctfteam == b->ctfteam;
|
|
|
|
if (G_TagGametype())
|
|
return ((a->pflags & PF_TAGIT) == (b->pflags & PF_TAGIT));
|
|
|
|
return false;
|
|
}
|
|
|
|
static boolean st_stopped = true;
|
|
|
|
void ST_Ticker(void)
|
|
{
|
|
if (st_stopped)
|
|
return;
|
|
}
|
|
|
|
// 0 is default, any others are special palettes.
|
|
INT32 st_palette = 0;
|
|
|
|
void ST_doPaletteStuff(void)
|
|
{
|
|
INT32 palette;
|
|
|
|
if (paused || P_AutoPause())
|
|
palette = 0;
|
|
else if (stplyr && stplyr->flashcount)
|
|
palette = stplyr->flashpal;
|
|
else
|
|
palette = 0;
|
|
|
|
#ifdef HWRENDER
|
|
if (rendermode == render_opengl)
|
|
palette = 0; // No flashpals here in OpenGL
|
|
#endif
|
|
|
|
palette = min(max(palette, 0), 13);
|
|
|
|
if (palette != st_palette)
|
|
{
|
|
st_palette = palette;
|
|
|
|
if (rendermode == render_soft)
|
|
{
|
|
//V_SetPaletteLump(GetPalette()); // Reset the palette -- is this needed?
|
|
if (!splitscreen)
|
|
V_SetPalette(palette);
|
|
}
|
|
}
|
|
}
|
|
|
|
void ST_UnloadGraphics(void)
|
|
{
|
|
Z_FreeTags(PU_HUDGFX, PU_HUDGFX);
|
|
}
|
|
|
|
void ST_LoadGraphics(void)
|
|
{
|
|
int i;
|
|
|
|
// SRB2 border patch
|
|
st_borderpatchnum = W_GetNumForName("GFZFLR01");
|
|
scr_borderpatch = W_CacheLumpNum(st_borderpatchnum, PU_HUDGFX);
|
|
|
|
// the original Doom uses 'STF' as base name for all face graphics
|
|
// Graue 04-08-2004: face/name graphics are now indexed by skins
|
|
// but load them in R_AddSkins, that gets called
|
|
// first anyway
|
|
// cache the status bar overlay icons (fullscreen mode)
|
|
sborings = W_CachePatchName("SBORINGS", PU_HUDGFX);
|
|
sboscore = W_CachePatchName("SBOSCORE", PU_HUDGFX);
|
|
sboover = W_CachePatchName("SBOOVER", PU_HUDGFX);
|
|
timeover = W_CachePatchName("TIMEOVER", PU_HUDGFX);
|
|
stlivex = W_CachePatchName("STLIVEX", PU_HUDGFX);
|
|
livesback = W_CachePatchName("STLIVEBK", PU_HUDGFX);
|
|
rrings = W_CachePatchName("RRINGS", PU_HUDGFX);
|
|
sbotime = W_CachePatchName("SBOTIME", PU_HUDGFX); // Time logo
|
|
sbocolon = W_CachePatchName("SBOCOLON", PU_HUDGFX); // Colon for time
|
|
sboperiod = W_CachePatchName("SBOPERIO", PU_HUDGFX); // Period for time centiseconds
|
|
nrec_timer = W_CachePatchName("NGRTIMER", PU_HUDGFX); // Timer for NiGHTS
|
|
getall = W_CachePatchName("GETALL", PU_HUDGFX); // Special Stage HUD
|
|
timeup = W_CachePatchName("TIMEUP", PU_HUDGFX); // Special Stage HUD
|
|
race1 = W_CachePatchName("RACE1", PU_HUDGFX);
|
|
race2 = W_CachePatchName("RACE2", PU_HUDGFX);
|
|
race3 = W_CachePatchName("RACE3", PU_HUDGFX);
|
|
racego = W_CachePatchName("RACEGO", PU_HUDGFX);
|
|
nightslink = W_CachePatchName("NGHTLINK", PU_HUDGFX);
|
|
count5 = W_CachePatchName("DRWNF0", PU_HUDGFX);
|
|
count4 = W_CachePatchName("DRWNE0", PU_HUDGFX);
|
|
count3 = W_CachePatchName("DRWND0", PU_HUDGFX);
|
|
count2 = W_CachePatchName("DRWNC0", PU_HUDGFX);
|
|
count1 = W_CachePatchName("DRWNB0", PU_HUDGFX);
|
|
count0 = W_CachePatchName("DRWNA0", PU_HUDGFX);
|
|
|
|
for (i = 0; i < 6; ++i)
|
|
{
|
|
hunthoming[i] = W_CachePatchName(va("HOMING%d", i+1), PU_HUDGFX);
|
|
itemhoming[i] = W_CachePatchName(va("HOMITM%d", i+1), PU_HUDGFX);
|
|
}
|
|
|
|
curweapon = W_CachePatchName("CURWEAP", PU_HUDGFX);
|
|
normring = W_CachePatchName("RINGIND", PU_HUDGFX);
|
|
bouncering = W_CachePatchName("BNCEIND", PU_HUDGFX);
|
|
infinityring = W_CachePatchName("INFNIND", PU_HUDGFX);
|
|
autoring = W_CachePatchName("AUTOIND", PU_HUDGFX);
|
|
explosionring = W_CachePatchName("BOMBIND", PU_HUDGFX);
|
|
scatterring = W_CachePatchName("SCATIND", PU_HUDGFX);
|
|
grenadering = W_CachePatchName("GRENIND", PU_HUDGFX);
|
|
railring = W_CachePatchName("RAILIND", PU_HUDGFX);
|
|
jumpshield = W_CachePatchName("WHTVB0", PU_HUDGFX);
|
|
forceshield = W_CachePatchName("BLTVB0", PU_HUDGFX);
|
|
ringshield = W_CachePatchName("YLTVB0", PU_HUDGFX);
|
|
watershield = W_CachePatchName("ELTVB0", PU_HUDGFX);
|
|
bombshield = W_CachePatchName("BKTVB0", PU_HUDGFX);
|
|
pityshield = W_CachePatchName("GRTVB0", PU_HUDGFX);
|
|
invincibility = W_CachePatchName("PINVB0", PU_HUDGFX);
|
|
sneakers = W_CachePatchName("SHTVB0", PU_HUDGFX);
|
|
gravboots = W_CachePatchName("GBTVB0", PU_HUDGFX);
|
|
|
|
tagico = W_CachePatchName("TAGICO", PU_HUDGFX);
|
|
rflagico = W_CachePatchName("RFLAGICO", PU_HUDGFX);
|
|
bflagico = W_CachePatchName("BFLAGICO", PU_HUDGFX);
|
|
rmatcico = W_CachePatchName("RMATCICO", PU_HUDGFX);
|
|
bmatcico = W_CachePatchName("BMATCICO", PU_HUDGFX);
|
|
gotrflag = W_CachePatchName("GOTRFLAG", PU_HUDGFX);
|
|
gotbflag = W_CachePatchName("GOTBFLAG", PU_HUDGFX);
|
|
nonicon = W_CachePatchName("NONICON", PU_HUDGFX);
|
|
|
|
// NiGHTS HUD things
|
|
bluestat = W_CachePatchName("BLUESTAT", PU_HUDGFX);
|
|
byelstat = W_CachePatchName("BYELSTAT", PU_HUDGFX);
|
|
orngstat = W_CachePatchName("ORNGSTAT", PU_HUDGFX);
|
|
redstat = W_CachePatchName("REDSTAT", PU_HUDGFX);
|
|
yelstat = W_CachePatchName("YELSTAT", PU_HUDGFX);
|
|
nbracket = W_CachePatchName("NBRACKET", PU_HUDGFX);
|
|
for (i = 0; i < 12; ++i)
|
|
nhud[i] = W_CachePatchName(va("NHUD%d", i+1), PU_HUDGFX);
|
|
nsshud = W_CachePatchName("NSSHUD", PU_HUDGFX);
|
|
minicaps = W_CachePatchName("MINICAPS", PU_HUDGFX);
|
|
|
|
for (i = 0; i < 8; ++i)
|
|
{
|
|
narrow[i] = W_CachePatchName(va("NARROW%d", i+1), PU_HUDGFX);
|
|
nredar[i] = W_CachePatchName(va("NREDAR%d", i+1), PU_HUDGFX);
|
|
}
|
|
|
|
// non-animated version
|
|
narrow[8] = W_CachePatchName("NARROW9", PU_HUDGFX);
|
|
|
|
drillbar = W_CachePatchName("DRILLBAR", PU_HUDGFX);
|
|
for (i = 0; i < 3; ++i)
|
|
drillfill[i] = W_CachePatchName(va("DRILLFI%d", i+1), PU_HUDGFX);
|
|
capsulebar = W_CachePatchName("CAPSBAR", PU_HUDGFX);
|
|
capsulefill = W_CachePatchName("CAPSFILL", PU_HUDGFX);
|
|
minus5sec = W_CachePatchName("MINUS5", PU_HUDGFX);
|
|
|
|
for (i = 0; i < 7; ++i)
|
|
ngradeletters[i] = W_CachePatchName(va("GRADE%d", i), PU_HUDGFX);
|
|
|
|
K_LoadKartHUDGraphics();
|
|
|
|
// Midnight Channel:
|
|
hud_tv1 = W_CachePatchName("HUD_TV1", PU_HUDGFX);
|
|
hud_tv2 = W_CachePatchName("HUD_TV2", PU_HUDGFX);
|
|
|
|
#ifdef HAVE_DISCORDRPC
|
|
// Discord Rich Presence
|
|
envelope = W_CachePatchName("K_REQUES", PU_HUDGFX);
|
|
#endif
|
|
}
|
|
|
|
// made separate so that skins code can reload custom face graphics
|
|
void ST_LoadFaceGraphics(char *rankstr, char *wantstr, char *mmapstr, INT32 skinnum)
|
|
{
|
|
facerankprefix[skinnum] = W_CachePatchName(rankstr, PU_HUDGFX);
|
|
facewantprefix[skinnum] = W_CachePatchName(wantstr, PU_HUDGFX);
|
|
facemmapprefix[skinnum] = W_CachePatchName(mmapstr, PU_HUDGFX);
|
|
}
|
|
|
|
void ST_ReloadSkinFaceGraphics(void)
|
|
{
|
|
INT32 i;
|
|
|
|
for (i = 0; i < numskins; i++)
|
|
ST_LoadFaceGraphics(skins[i].facerank, skins[i].facewant, skins[i].facemmap, i);
|
|
}
|
|
|
|
static inline void ST_InitData(void)
|
|
{
|
|
// 'link' the statusbar display to a player, which could be
|
|
// another player than consoleplayer, for example, when you
|
|
// change the view in a multiplayer demo with F12.
|
|
stplyr = &players[displayplayers[0]];
|
|
|
|
st_palette = -1;
|
|
}
|
|
|
|
static inline void ST_Stop(void)
|
|
{
|
|
if (st_stopped)
|
|
return;
|
|
|
|
#ifdef HWRENDER
|
|
if (rendermode != render_opengl)
|
|
#endif
|
|
V_SetPalette(0);
|
|
|
|
st_stopped = true;
|
|
}
|
|
|
|
void ST_Start(void)
|
|
{
|
|
if (!st_stopped)
|
|
ST_Stop();
|
|
|
|
ST_InitData();
|
|
st_stopped = false;
|
|
}
|
|
|
|
//
|
|
// Initializes the status bar, sets the defaults border patch for the window borders.
|
|
//
|
|
|
|
// used by OpenGL mode, holds lumpnum of flat used to fill space around the viewwindow
|
|
lumpnum_t st_borderpatchnum;
|
|
|
|
void ST_Init(void)
|
|
{
|
|
if (dedicated)
|
|
return;
|
|
|
|
ST_LoadGraphics();
|
|
|
|
#ifdef HAVE_BLUA
|
|
luahuddrawlist_game = LUA_HUD_CreateDrawList();
|
|
#endif
|
|
}
|
|
|
|
// change the status bar too, when pressing F12 while viewing a demo.
|
|
void ST_changeDemoView(void)
|
|
{
|
|
// the same routine is called at multiplayer deathmatch spawn
|
|
// so it can be called multiple times
|
|
ST_Start();
|
|
}
|
|
|
|
// =========================================================================
|
|
// STATUS BAR OVERLAY
|
|
// =========================================================================
|
|
|
|
boolean st_overlay;
|
|
|
|
/*
|
|
static INT32 SCZ(INT32 z)
|
|
{
|
|
return FixedInt(FixedMul(z<<FRACBITS, vid.fdupy));
|
|
}
|
|
*/
|
|
|
|
/*
|
|
static INT32 SCY(INT32 y)
|
|
{
|
|
//31/10/99: fixed by Hurdler so it _works_ also in hardware mode
|
|
// do not scale to resolution for hardware accelerated
|
|
// because these modes always scale by default
|
|
y = SCZ(y); // scale to resolution
|
|
if (splitscreen)
|
|
{
|
|
y >>= 1;
|
|
if (stplyr != &players[displayplayers[0]])
|
|
y += vid.height / 2;
|
|
}
|
|
return y;
|
|
}
|
|
*/
|
|
|
|
/*
|
|
static INT32 STRINGY(INT32 y)
|
|
{
|
|
//31/10/99: fixed by Hurdler so it _works_ also in hardware mode
|
|
// do not scale to resolution for hardware accelerated
|
|
// because these modes always scale by default
|
|
if (splitscreen)
|
|
{
|
|
y >>= 1;
|
|
if (stplyr != &players[displayplayers[0]])
|
|
y += BASEVIDHEIGHT / 2;
|
|
}
|
|
return y;
|
|
}
|
|
*/
|
|
|
|
/*
|
|
static INT32 SPLITFLAGS(INT32 f)
|
|
{
|
|
// Pass this V_SNAPTO(TOP|BOTTOM) and it'll trim them to account for splitscreen! -Red
|
|
if (splitscreen)
|
|
{
|
|
if (stplyr != &players[displayplayers[0]])
|
|
f &= ~V_SNAPTOTOP;
|
|
else
|
|
f &= ~V_SNAPTOBOTTOM;
|
|
}
|
|
return f;
|
|
}
|
|
*/
|
|
|
|
/*
|
|
static INT32 SCX(INT32 x)
|
|
{
|
|
return FixedInt(FixedMul(x<<FRACBITS, vid.fdupx));
|
|
}
|
|
*/
|
|
|
|
#if 0
|
|
static INT32 SCR(INT32 r)
|
|
{
|
|
fixed_t y;
|
|
//31/10/99: fixed by Hurdler so it _works_ also in hardware mode
|
|
// do not scale to resolution for hardware accelerated
|
|
// because these modes always scale by default
|
|
y = FixedMul(r*FRACUNIT, vid.fdupy); // scale to resolution
|
|
if (splitscreen)
|
|
{
|
|
y >>= 1;
|
|
if (stplyr != &players[displayplayers[0]])
|
|
y += vid.height / 2;
|
|
}
|
|
return FixedInt(FixedDiv(y, vid.fdupy));
|
|
}
|
|
#endif
|
|
|
|
// =========================================================================
|
|
// INTERNAL DRAWING
|
|
// =========================================================================
|
|
#define ST_DrawOverlayNum(x,y,n) V_DrawTallNum(x, y, V_NOSCALESTART|V_HUDTRANS, n)
|
|
#define ST_DrawPaddedOverlayNum(x,y,n,d) V_DrawPaddedTallNum(x, y, V_NOSCALESTART|V_HUDTRANS, n, d)
|
|
#define ST_DrawOverlayPatch(x,y,p) V_DrawScaledPatch(x, y, V_NOSCALESTART|V_HUDTRANS, p)
|
|
#define ST_DrawMappedOverlayPatch(x,y,p,c) V_DrawMappedScaledPatch(x, y, V_NOSCALESTART|V_HUDTRANS, p, c)
|
|
#define ST_DrawNumFromHud(h,n) V_DrawTallNum(SCX(hudinfo[h].x), SCY(hudinfo[h].y), V_NOSCALESTART|V_HUDTRANS, n)
|
|
#define ST_DrawPadNumFromHud(h,n,q) V_DrawPaddedTallNum(SCX(hudinfo[h].x), SCY(hudinfo[h].y), V_NOSCALESTART|V_HUDTRANS, n, q)
|
|
#define ST_DrawPatchFromHud(h,p) V_DrawScaledPatch(SCX(hudinfo[h].x), SCY(hudinfo[h].y), V_NOSCALESTART|V_HUDTRANS, p)
|
|
#define ST_DrawNumFromHudWS(h,n) V_DrawTallNum(SCX(hudinfo[h+!!splitscreen].x), SCY(hudinfo[h+!!splitscreen].y), V_NOSCALESTART|V_HUDTRANS, n)
|
|
#define ST_DrawPadNumFromHudWS(h,n,q) V_DrawPaddedTallNum(SCX(hudinfo[h+!!splitscreen].x), SCY(hudinfo[h+!!splitscreen].y), V_NOSCALESTART|V_HUDTRANS, n, q)
|
|
#define ST_DrawPatchFromHudWS(h,p) V_DrawScaledPatch(SCX(hudinfo[h+!!splitscreen].x), SCY(hudinfo[h+!!splitscreen].y), V_NOSCALESTART|V_HUDTRANS, p)
|
|
|
|
/*
|
|
// Draw a number, scaled, over the view, maybe with set translucency
|
|
// Always draw the number completely since it's overlay
|
|
//
|
|
// Supports different colors! woo!
|
|
static void ST_DrawNightsOverlayNum(INT32 x, INT32 y, INT32 a,
|
|
INT32 num, patch_t **numpat, skincolors_t colornum)
|
|
{
|
|
INT32 w = SHORT(numpat[0]->width);
|
|
const UINT8 *colormap;
|
|
|
|
// I want my V_SNAPTOx flags. :< -Red
|
|
//a &= V_ALPHAMASK;
|
|
|
|
if (colornum == 0)
|
|
colormap = colormaps;
|
|
else // Uses the player colors.
|
|
colormap = R_GetTranslationColormap(TC_DEFAULT, colornum, GTC_CACHE);
|
|
|
|
I_Assert(num >= 0); // this function does not draw negative numbers
|
|
|
|
// draw the number
|
|
do
|
|
{
|
|
x -= w;
|
|
V_DrawTranslucentMappedPatch(x, y, a, numpat[num % 10], colormap);
|
|
num /= 10;
|
|
} while (num);
|
|
|
|
// Sorry chum, this function only draws UNSIGNED values!
|
|
}
|
|
*/
|
|
|
|
// Devmode information
|
|
static void ST_drawDebugInfo(void)
|
|
{
|
|
INT32 height = 192;
|
|
|
|
if (!stplyr->mo)
|
|
return;
|
|
|
|
if (cv_debug & DBG_BASIC)
|
|
{
|
|
const fixed_t d = AngleFixed(stplyr->mo->angle);
|
|
V_DrawRightAlignedString(320, 168, V_MONOSPACE, va("X: %6d", stplyr->mo->x>>FRACBITS));
|
|
V_DrawRightAlignedString(320, 176, V_MONOSPACE, va("Y: %6d", stplyr->mo->y>>FRACBITS));
|
|
V_DrawRightAlignedString(320, 184, V_MONOSPACE, va("Z: %6d", stplyr->mo->z>>FRACBITS));
|
|
V_DrawRightAlignedString(320, 192, V_MONOSPACE, va("A: %6d", FixedInt(d)));
|
|
|
|
height = 152;
|
|
}
|
|
|
|
if (cv_debug & DBG_DETAILED)
|
|
{
|
|
//V_DrawRightAlignedString(320, height - 104, V_MONOSPACE, va("SHIELD: %5x", stplyr->powers[pw_shield]));
|
|
V_DrawRightAlignedString(320, height - 96, V_MONOSPACE, va("SCALE: %5d%%", (stplyr->mo->scale*100)/FRACUNIT));
|
|
//V_DrawRightAlignedString(320, height - 88, V_MONOSPACE, va("DASH: %3d/%3d", stplyr->dashspeed>>FRACBITS, FixedMul(stplyr->maxdash,stplyr->mo->scale)>>FRACBITS));
|
|
//V_DrawRightAlignedString(320, height - 80, V_MONOSPACE, va("AIR: %4d, %3d", stplyr->powers[pw_underwater], stplyr->powers[pw_spacetime]));
|
|
|
|
// Flags
|
|
//V_DrawRightAlignedString(304-64, height - 72, V_MONOSPACE, "Flags:");
|
|
//V_DrawString(304-60, height - 72, (stplyr->jumping) ? V_GREENMAP : V_REDMAP, "JM");
|
|
//V_DrawString(304-40, height - 72, (stplyr->pflags & PF_JUMPED) ? V_GREENMAP : V_REDMAP, "JD");
|
|
//V_DrawString(304-20, height - 72, (stplyr->pflags & PF_SPINNING) ? V_GREENMAP : V_REDMAP, "SP");
|
|
//V_DrawString(304, height - 72, (stplyr->pflags & PF_STARTDASH) ? V_GREENMAP : V_REDMAP, "ST");
|
|
|
|
V_DrawRightAlignedString(320, height - 64, V_MONOSPACE, va("CEILZ: %6d", stplyr->mo->ceilingz>>FRACBITS));
|
|
V_DrawRightAlignedString(320, height - 56, V_MONOSPACE, va("FLOORZ: %6d", stplyr->mo->floorz>>FRACBITS));
|
|
|
|
V_DrawRightAlignedString(320, height - 48, V_MONOSPACE, va("CNVX: %6d", stplyr->cmomx>>FRACBITS));
|
|
V_DrawRightAlignedString(320, height - 40, V_MONOSPACE, va("CNVY: %6d", stplyr->cmomy>>FRACBITS));
|
|
V_DrawRightAlignedString(320, height - 32, V_MONOSPACE, va("PLTZ: %6d", stplyr->mo->pmomz>>FRACBITS));
|
|
|
|
V_DrawRightAlignedString(320, height - 24, V_MONOSPACE, va("MOMX: %6d", stplyr->rmomx>>FRACBITS));
|
|
V_DrawRightAlignedString(320, height - 16, V_MONOSPACE, va("MOMY: %6d", stplyr->rmomy>>FRACBITS));
|
|
V_DrawRightAlignedString(320, height - 8, V_MONOSPACE, va("MOMZ: %6d", stplyr->mo->momz>>FRACBITS));
|
|
V_DrawRightAlignedString(320, height, V_MONOSPACE, va("SPEED: %6d", stplyr->speed>>FRACBITS));
|
|
|
|
height -= 120;
|
|
}
|
|
|
|
if (cv_debug & DBG_RANDOMIZER) // randomizer testing
|
|
{
|
|
fixed_t peekres = P_RandomPeek();
|
|
peekres *= 10000; // Change from fixed point
|
|
peekres >>= FRACBITS; // to displayable decimal
|
|
|
|
V_DrawRightAlignedString(320, height - 16, V_MONOSPACE, va("Init: %08x", P_GetInitSeed()));
|
|
V_DrawRightAlignedString(320, height - 8, V_MONOSPACE, va("Seed: %08x", P_GetRandSeed()));
|
|
V_DrawRightAlignedString(320, height, V_MONOSPACE, va("== : .%04d", peekres));
|
|
|
|
height -= 32;
|
|
}
|
|
|
|
if (cv_debug & DBG_MEMORY)
|
|
V_DrawRightAlignedString(320, height, V_MONOSPACE, va("Heap used: %7sKB", sizeu1(Z_TagsUsage(0, INT32_MAX)>>10)));
|
|
}
|
|
|
|
/*
|
|
static void ST_drawScore(void)
|
|
{
|
|
// SCORE:
|
|
ST_DrawPatchFromHud(HUD_SCORE, sboscore);
|
|
if (objectplacing)
|
|
{
|
|
if (op_displayflags > UINT16_MAX)
|
|
ST_DrawOverlayPatch(SCX(hudinfo[HUD_SCORENUM].x-tallminus->width), SCY(hudinfo[HUD_SCORENUM].y), tallminus);
|
|
else
|
|
ST_DrawNumFromHud(HUD_SCORENUM, op_displayflags);
|
|
}
|
|
else
|
|
ST_DrawNumFromHud(HUD_SCORENUM, stplyr->score);
|
|
}
|
|
*/
|
|
|
|
/*
|
|
static void ST_drawTime(void)
|
|
{
|
|
INT32 seconds, minutes, tictrn, tics;
|
|
|
|
// TIME:
|
|
ST_DrawPatchFromHudWS(HUD_TIME, sbotime);
|
|
|
|
if (objectplacing)
|
|
{
|
|
tics = objectsdrawn;
|
|
seconds = objectsdrawn%100;
|
|
minutes = objectsdrawn/100;
|
|
tictrn = 0;
|
|
}
|
|
else
|
|
{
|
|
tics = stplyr->realtime;
|
|
seconds = G_TicsToSeconds(tics);
|
|
minutes = G_TicsToMinutes(tics, true);
|
|
tictrn = G_TicsToCentiseconds(tics);
|
|
}
|
|
|
|
if (cv_timetic.value == 1) // Tics only -- how simple is this?
|
|
ST_DrawNumFromHudWS(HUD_SECONDS, tics);
|
|
else
|
|
{
|
|
ST_DrawNumFromHudWS(HUD_MINUTES, minutes); // Minutes
|
|
ST_DrawPatchFromHudWS(HUD_TIMECOLON, sbocolon); // Colon
|
|
ST_DrawPadNumFromHudWS(HUD_SECONDS, seconds, 2); // Seconds
|
|
|
|
if (!splitscreen && (cv_timetic.value == 2 || modeattacking)) // there's not enough room for tics in splitscreen, don't even bother trying!
|
|
{
|
|
ST_DrawPatchFromHud(HUD_TIMETICCOLON, sboperiod); // Period
|
|
ST_DrawPadNumFromHud(HUD_TICS, tictrn, 2); // Tics
|
|
}
|
|
}
|
|
}
|
|
*/
|
|
|
|
/*
|
|
static inline void ST_drawRings(void) // SRB2kart - unused.
|
|
{
|
|
INT32 ringnum = max(stplyr->health-1, 0);
|
|
|
|
ST_DrawPatchFromHudWS(HUD_RINGS, ((stplyr->health <= 1 && leveltime/5 & 1) ? rrings : sborings));
|
|
|
|
if (objectplacing)
|
|
ringnum = op_currentdoomednum;
|
|
else if (!useNightsSS && G_IsSpecialStage(gamemap))
|
|
{
|
|
INT32 i;
|
|
ringnum = 0;
|
|
for (i = 0; i < MAXPLAYERS; i++)
|
|
if (playeringame[i] && players[i].mo && players[i].mo->health > 1)
|
|
ringnum += players[i].mo->health - 1;
|
|
}
|
|
|
|
ST_DrawNumFromHudWS(HUD_RINGSNUM, ringnum);
|
|
}
|
|
*/
|
|
|
|
/*
|
|
static void ST_drawLives(void) // SRB2kart - unused.
|
|
{
|
|
const INT32 v_splitflag = (splitscreen && stplyr == &players[displayplayers[0]] ? V_SPLITSCREEN : 0);
|
|
|
|
if (!stplyr->skincolor)
|
|
return; // Just joined a server, skin isn't loaded yet!
|
|
|
|
// face background
|
|
V_DrawSmallScaledPatch(hudinfo[HUD_LIVESPIC].x, hudinfo[HUD_LIVESPIC].y + (v_splitflag ? -12 : 0),
|
|
V_SNAPTOLEFT|V_SNAPTOBOTTOM|V_HUDTRANS|v_splitflag, livesback);
|
|
|
|
// face
|
|
if (stplyr->mo && stplyr->mo->color)
|
|
{
|
|
// skincolor face/super
|
|
UINT8 *colormap = R_GetTranslationColormap(stplyr->skin, stplyr->mo->color, GTC_CACHE);
|
|
patch_t *face = facerankprefix[stplyr->skin];
|
|
if (stplyr->powers[pw_super] || stplyr->pflags & PF_NIGHTSMODE)
|
|
face = facewantprefix[stplyr->skin];
|
|
V_DrawSmallMappedPatch(hudinfo[HUD_LIVESPIC].x, hudinfo[HUD_LIVESPIC].y + (v_splitflag ? -12 : 0),
|
|
V_SNAPTOLEFT|V_SNAPTOBOTTOM|V_HUDTRANS|v_splitflag,face, colormap);
|
|
}
|
|
else if (stplyr->skincolor)
|
|
{
|
|
// skincolor face
|
|
UINT8 *colormap = R_GetTranslationColormap(stplyr->skin, stplyr->skincolor, GTC_CACHE);
|
|
V_DrawSmallMappedPatch(hudinfo[HUD_LIVESPIC].x, hudinfo[HUD_LIVESPIC].y + (v_splitflag ? -12 : 0),
|
|
V_SNAPTOLEFT|V_SNAPTOBOTTOM|V_HUDTRANS|v_splitflag,facerankprefix[stplyr->skin], colormap);
|
|
}
|
|
|
|
// name
|
|
if (strlen(skins[stplyr->skin].hudname) > 8)
|
|
V_DrawThinString(hudinfo[HUD_LIVESNAME].x, hudinfo[HUD_LIVESNAME].y + (v_splitflag ? -12 : 0),
|
|
V_HUDTRANS|V_SNAPTOLEFT|V_SNAPTOBOTTOM|V_MONOSPACE|V_YELLOWMAP|v_splitflag, skins[stplyr->skin].hudname);
|
|
else
|
|
V_DrawString(hudinfo[HUD_LIVESNAME].x, hudinfo[HUD_LIVESNAME].y + (v_splitflag ? -12 : 0),
|
|
V_HUDTRANS|V_SNAPTOLEFT|V_SNAPTOBOTTOM|V_MONOSPACE|V_YELLOWMAP|v_splitflag, skins[stplyr->skin].hudname);
|
|
// x
|
|
V_DrawScaledPatch(hudinfo[HUD_LIVESX].x, hudinfo[HUD_LIVESX].y + (v_splitflag ? -4 : 0),
|
|
V_SNAPTOLEFT|V_SNAPTOBOTTOM|V_HUDTRANS|v_splitflag, stlivex);
|
|
// lives
|
|
V_DrawRightAlignedString(hudinfo[HUD_LIVESNUM].x, hudinfo[HUD_LIVESNUM].y + (v_splitflag ? -4 : 0),
|
|
V_SNAPTOLEFT|V_SNAPTOBOTTOM|V_HUDTRANS|v_splitflag, va("%d",stplyr->lives));
|
|
}
|
|
*/
|
|
|
|
static void ST_drawLevelTitle(void)
|
|
{
|
|
char *lvlttl = mapheaderinfo[gamemap-1]->lvlttl;
|
|
char *subttl = mapheaderinfo[gamemap-1]->subttl;
|
|
char *zonttl = mapheaderinfo[gamemap-1]->zonttl; // SRB2kart
|
|
char *actnum = mapheaderinfo[gamemap-1]->actnum;
|
|
INT32 lvlttlxpos;
|
|
INT32 ttlnumxpos;
|
|
INT32 zonexpos;
|
|
INT32 dupcalc = (vid.width/vid.dupx);
|
|
UINT8 gtc = G_GetGametypeColor(gametype);
|
|
INT32 sub = 0;
|
|
INT32 bary = (splitscreen)
|
|
? BASEVIDHEIGHT/2
|
|
: 163;
|
|
INT32 lvlw;
|
|
|
|
if (timeinmap > 113)
|
|
return;
|
|
|
|
lvlw = V_LevelNameWidth(lvlttl);
|
|
|
|
if (actnum[0])
|
|
lvlttlxpos = ((BASEVIDWIDTH/2) - (lvlw/2)) - V_LevelNameWidth(actnum);
|
|
else
|
|
lvlttlxpos = ((BASEVIDWIDTH/2) - (lvlw/2));
|
|
|
|
zonexpos = ttlnumxpos = lvlttlxpos + lvlw;
|
|
if (!(mapheaderinfo[gamemap-1]->levelflags & LF_NOZONE))
|
|
{
|
|
if (zonttl[0])
|
|
zonexpos -= V_LevelNameWidth(zonttl); // SRB2kart
|
|
else
|
|
zonexpos -= V_LevelNameWidth(M_GetText("Zone"));
|
|
}
|
|
|
|
if (lvlttlxpos < 0)
|
|
lvlttlxpos = 0;
|
|
|
|
if (timeinmap > 105)
|
|
{
|
|
INT32 count = (113 - (INT32)(timeinmap));
|
|
sub = dupcalc;
|
|
while (count-- > 0)
|
|
sub >>= 1;
|
|
sub = -sub;
|
|
}
|
|
|
|
{
|
|
dupcalc = (dupcalc - BASEVIDWIDTH)>>1;
|
|
V_DrawFill(sub - dupcalc, bary+9, ttlnumxpos+dupcalc + 1, 2, 31);
|
|
V_DrawDiag(sub + ttlnumxpos + 1, bary, 11, 31);
|
|
V_DrawFill(sub - dupcalc, bary, ttlnumxpos+dupcalc, 10, gtc);
|
|
V_DrawDiag(sub + ttlnumxpos, bary, 10, gtc);
|
|
|
|
if (subttl[0])
|
|
V_DrawRightAlignedString(sub + zonexpos - 8, bary+1, V_ALLOWLOWERCASE, subttl);
|
|
//else
|
|
//V_DrawRightAlignedString(sub + zonexpos - 8, bary+1, V_ALLOWLOWERCASE, va("%s Mode", gametype_cons_t[gametype].strvalue));
|
|
}
|
|
|
|
ttlnumxpos += sub;
|
|
lvlttlxpos += sub;
|
|
zonexpos += sub;
|
|
|
|
V_DrawLevelTitle(lvlttlxpos, bary-18, 0, lvlttl);
|
|
|
|
if (strlen(zonttl) > 0)
|
|
V_DrawLevelTitle(zonexpos, bary+6, 0, zonttl);
|
|
else if (!(mapheaderinfo[gamemap-1]->levelflags & LF_NOZONE))
|
|
V_DrawLevelTitle(zonexpos, bary+6, 0, M_GetText("Zone"));
|
|
|
|
if (actnum[0])
|
|
V_DrawLevelTitle(ttlnumxpos+12, bary+6, 0, actnum);
|
|
}
|
|
|
|
/*
|
|
static void ST_drawFirstPersonHUD(void)
|
|
{
|
|
player_t *player = stplyr;
|
|
patch_t *p = NULL;
|
|
UINT16 invulntime = 0;
|
|
|
|
if (player->playerstate != PST_LIVE)
|
|
return;
|
|
|
|
// Graue 06-18-2004: no V_NOSCALESTART, no SCX, no SCY, snap to right
|
|
if (player->powers[pw_shield] & SH_FORCE)
|
|
{
|
|
if ((player->powers[pw_shield] & 0xFF) > 0 || leveltime & 1)
|
|
p = forceshield;
|
|
}
|
|
else switch (player->powers[pw_shield] & SH_NOSTACK)
|
|
{
|
|
case SH_JUMP: p = jumpshield; break;
|
|
case SH_ELEMENTAL: p = watershield; break;
|
|
case SH_BOMB: p = bombshield; break;
|
|
case SH_ATTRACT: p = ringshield; break;
|
|
case SH_PITY: p = pityshield; break;
|
|
default: break;
|
|
}
|
|
|
|
if (p)
|
|
{
|
|
if (splitscreen)
|
|
V_DrawSmallScaledPatch(312, STRINGY(24), V_SNAPTORIGHT|V_SNAPTOTOP|V_HUDTRANS, p);
|
|
else
|
|
V_DrawScaledPatch(304, 24, V_SNAPTORIGHT|V_SNAPTOTOP|V_HUDTRANS, p);
|
|
}
|
|
|
|
// pw_flashing just sets the icon to flash no matter what.
|
|
invulntime = player->powers[pw_flashing] ? 1 : player->powers[pw_invulnerability];
|
|
if (invulntime > 3*TICRATE || (invulntime && leveltime & 1))
|
|
{
|
|
if (splitscreen)
|
|
V_DrawSmallScaledPatch(312, STRINGY(24) + 14, V_SNAPTORIGHT|V_SNAPTOTOP|V_HUDTRANS, invincibility);
|
|
else
|
|
V_DrawScaledPatch(304, 24 + 28, V_SNAPTORIGHT|V_SNAPTOTOP|V_HUDTRANS, invincibility);
|
|
}
|
|
|
|
if (player->powers[pw_sneakers] > 3*TICRATE || (player->powers[pw_sneakers] && leveltime & 1))
|
|
{
|
|
if (splitscreen)
|
|
V_DrawSmallScaledPatch(312, STRINGY(24) + 28, V_SNAPTORIGHT|V_SNAPTOTOP|V_HUDTRANS, sneakers);
|
|
else
|
|
V_DrawScaledPatch(304, 24 + 56, V_SNAPTORIGHT|V_SNAPTOTOP|V_HUDTRANS, sneakers);
|
|
}
|
|
|
|
p = NULL;
|
|
|
|
// Display the countdown drown numbers!
|
|
if ((player->powers[pw_underwater] <= 11*TICRATE + 1
|
|
&& player->powers[pw_underwater] >= 10*TICRATE + 1)
|
|
|| (player->powers[pw_spacetime] <= 11*TICRATE + 1
|
|
&& player->powers[pw_spacetime] >= 10*TICRATE + 1))
|
|
{
|
|
p = count5;
|
|
}
|
|
else if ((player->powers[pw_underwater] <= 9*TICRATE + 1
|
|
&& player->powers[pw_underwater] >= 8*TICRATE + 1)
|
|
|| (player->powers[pw_spacetime] <= 9*TICRATE + 1
|
|
&& player->powers[pw_spacetime] >= 8*TICRATE + 1))
|
|
{
|
|
p = count4;
|
|
}
|
|
else if ((player->powers[pw_underwater] <= 7*TICRATE + 1
|
|
&& player->powers[pw_underwater] >= 6*TICRATE + 1)
|
|
|| (player->powers[pw_spacetime] <= 7*TICRATE + 1
|
|
&& player->powers[pw_spacetime] >= 6*TICRATE + 1))
|
|
{
|
|
p = count3;
|
|
}
|
|
else if ((player->powers[pw_underwater] <= 5*TICRATE + 1
|
|
&& player->powers[pw_underwater] >= 4*TICRATE + 1)
|
|
|| (player->powers[pw_spacetime] <= 5*TICRATE + 1
|
|
&& player->powers[pw_spacetime] >= 4*TICRATE + 1))
|
|
{
|
|
p = count2;
|
|
}
|
|
else if ((player->powers[pw_underwater] <= 3*TICRATE + 1
|
|
&& player->powers[pw_underwater] >= 2*TICRATE + 1)
|
|
|| (player->powers[pw_spacetime] <= 3*TICRATE + 1
|
|
&& player->powers[pw_spacetime] >= 2*TICRATE + 1))
|
|
{
|
|
p = count1;
|
|
}
|
|
else if ((player->powers[pw_underwater] <= 1*TICRATE + 1
|
|
&& player->powers[pw_underwater] > 1)
|
|
|| (player->powers[pw_spacetime] <= 1*TICRATE + 1
|
|
&& player->powers[pw_spacetime] > 1))
|
|
{
|
|
p = count0;
|
|
}
|
|
|
|
if (p)
|
|
V_DrawScaledPatch(SCX((BASEVIDWIDTH/2) - (SHORT(p->width)/2) + SHORT(p->leftoffset)), SCY(60 - SHORT(p->topoffset)),
|
|
V_NOSCALESTART|V_OFFSET|V_TRANSLUCENT, p);
|
|
}
|
|
*/
|
|
|
|
/*
|
|
// [21:42] <+Rob> Beige - Lavender - Steel Blue - Peach - Orange - Purple - Silver - Yellow - Pink - Red - Blue - Green - Cyan - Gold
|
|
static skincolors_t linkColor[14] =
|
|
{SKINCOLOR_BEIGE, SKINCOLOR_LAVENDER, SKINCOLOR_STEEL, SKINCOLOR_PEACH, SKINCOLOR_ORANGE,
|
|
SKINCOLOR_PURPLE, SKINCOLOR_SILVER, SKINCOLOR_SUPER4, SKINCOLOR_PINK, SKINCOLOR_RED,
|
|
SKINCOLOR_BLUE, SKINCOLOR_GREEN, SKINCOLOR_CYAN, SKINCOLOR_GOLD};
|
|
|
|
static void ST_drawNightsRecords(void)
|
|
{
|
|
INT32 aflag = 0;
|
|
|
|
if (!stplyr->texttimer)
|
|
return;
|
|
|
|
if (stplyr->texttimer < TICRATE/2)
|
|
aflag = (9 - 9*stplyr->texttimer/(TICRATE/2)) << V_ALPHASHIFT;
|
|
|
|
// A "Bonus Time Start" by any other name...
|
|
if (stplyr->textvar == 1)
|
|
{
|
|
V_DrawCenteredString(BASEVIDWIDTH/2, STRINGY(52), V_GREENMAP|aflag, M_GetText("GET TO THE GOAL!"));
|
|
V_DrawCenteredString(BASEVIDWIDTH/2, STRINGY(60), aflag, M_GetText("SCORE MULTIPLIER START!"));
|
|
|
|
if (stplyr->finishedtime)
|
|
{
|
|
V_DrawString(BASEVIDWIDTH/2 - 48, STRINGY(140), aflag, "TIME:");
|
|
V_DrawString(BASEVIDWIDTH/2 - 48, STRINGY(148), aflag, "BONUS:");
|
|
V_DrawRightAlignedString(BASEVIDWIDTH/2 + 48, STRINGY(140), V_ORANGEMAP|aflag, va("%d", (stplyr->startedtime - stplyr->finishedtime)/TICRATE));
|
|
V_DrawRightAlignedString(BASEVIDWIDTH/2 + 48, STRINGY(148), V_ORANGEMAP|aflag, va("%d", (stplyr->finishedtime/TICRATE) * 100));
|
|
}
|
|
}
|
|
|
|
// Get n [more] Spheres
|
|
else if (stplyr->textvar <= 3 && stplyr->textvar >= 2)
|
|
{
|
|
if (!stplyr->capsule)
|
|
return;
|
|
|
|
// Yes, this string is an abomination.
|
|
V_DrawCenteredString(BASEVIDWIDTH/2, STRINGY(60), aflag,
|
|
va(M_GetText("\x80GET\x82 %d\x80 %s%s%s!"), stplyr->capsule->health,
|
|
(stplyr->textvar == 3) ? M_GetText("MORE ") : "",
|
|
(G_IsSpecialStage(gamemap)) ? "SPHERE" : "RING",
|
|
(stplyr->capsule->health > 1) ? "S" : ""));
|
|
}
|
|
|
|
// End Bonus
|
|
else if (stplyr->textvar == 4)
|
|
{
|
|
V_DrawString(BASEVIDWIDTH/2 - 48, STRINGY(140), aflag, (G_IsSpecialStage(gamemap)) ? "ORBS:" : "RINGS:");
|
|
V_DrawString(BASEVIDWIDTH/2 - 48, STRINGY(148), aflag, "BONUS:");
|
|
V_DrawRightAlignedString(BASEVIDWIDTH/2 + 48, STRINGY(140), V_ORANGEMAP|aflag, va("%d", stplyr->finishedrings));
|
|
V_DrawRightAlignedString(BASEVIDWIDTH/2 + 48, STRINGY(148), V_ORANGEMAP|aflag, va("%d", stplyr->finishedrings * 50));
|
|
ST_DrawNightsOverlayNum(BASEVIDWIDTH/2 + 48, STRINGY(160), aflag, stplyr->lastmarescore, nightsnum, SKINCOLOR_STEEL);
|
|
|
|
// If new record, say so!
|
|
if (!(netgame || multiplayer) && G_GetBestNightsScore(gamemap, stplyr->lastmare + 1) <= stplyr->lastmarescore)
|
|
{
|
|
if (stplyr->texttimer & 16)
|
|
V_DrawCenteredString(BASEVIDWIDTH/2, STRINGY(184), V_YELLOWMAP|aflag, "* NEW RECORD *");
|
|
}
|
|
|
|
if (P_HasGrades(gamemap, stplyr->lastmare + 1))
|
|
{
|
|
if (aflag)
|
|
V_DrawTranslucentPatch(BASEVIDWIDTH/2 + 60, STRINGY(160), aflag,
|
|
ngradeletters[P_GetGrade(stplyr->lastmarescore, gamemap, stplyr->lastmare)]);
|
|
else
|
|
V_DrawScaledPatch(BASEVIDWIDTH/2 + 60, STRINGY(160), 0,
|
|
ngradeletters[P_GetGrade(stplyr->lastmarescore, gamemap, stplyr->lastmare)]);
|
|
}
|
|
}
|
|
}
|
|
*/
|
|
|
|
/*
|
|
static void ST_drawNiGHTSHUD(void) // SRB2kart - unused.
|
|
{
|
|
INT32 origamount;
|
|
INT32 minlink = 1;
|
|
INT32 total_ringcount;
|
|
UINT8 nosshack = 0;
|
|
|
|
// When debugging, show "0 Link".
|
|
if (cv_debug & DBG_NIGHTSBASIC)
|
|
minlink = 0;
|
|
|
|
// Cheap hack: don't display when the score is showing (it popping up for a split second when exiting a map is intentional)
|
|
if (stplyr->texttimer && stplyr->textvar == 4)
|
|
minlink = INT32_MAX;
|
|
|
|
if (G_IsSpecialStage(gamemap))
|
|
{ // Since special stages share score, time, rings, etc.
|
|
// disable splitscreen mode for its HUD.
|
|
if (stplyr != &players[displayplayers[0]])
|
|
return;
|
|
nosshack = splitscreen;
|
|
splitscreen = 0;
|
|
}
|
|
|
|
// Link drawing
|
|
if (
|
|
#ifdef HAVE_BLUA
|
|
LUA_HudEnabled(hud_nightslink) &&
|
|
#endif
|
|
stplyr->linkcount > minlink)
|
|
{
|
|
skincolors_t colornum = linkColor[((stplyr->linkcount-1) / 5) % (sizeof(linkColor) / sizeof(skincolors_t))];
|
|
if (stplyr->powers[pw_nights_linkfreeze])
|
|
colornum = SKINCOLOR_WHITE;
|
|
|
|
if (stplyr->linktimer < 2*TICRATE/3)
|
|
{
|
|
INT32 linktrans = (9 - 9*stplyr->linktimer/(2*TICRATE/3)) << V_ALPHASHIFT;
|
|
|
|
if (splitscreen)
|
|
{
|
|
ST_DrawNightsOverlayNum(256, STRINGY(152), SPLITFLAGS(V_SNAPTOBOTTOM)|V_SNAPTORIGHT|linktrans, (stplyr->linkcount-1), nightsnum, colornum);
|
|
V_DrawTranslucentMappedPatch(264, STRINGY(152), SPLITFLAGS(V_SNAPTOBOTTOM)|V_SNAPTORIGHT|linktrans, nightslink,
|
|
colornum == 0 ? colormaps : R_GetTranslationColormap(TC_DEFAULT, colornum, GTC_CACHE));
|
|
}
|
|
else
|
|
{
|
|
ST_DrawNightsOverlayNum(160, 160, V_SNAPTOBOTTOM|linktrans, (stplyr->linkcount-1), nightsnum, colornum);
|
|
V_DrawTranslucentMappedPatch(168, 160, V_SNAPTOBOTTOM|linktrans, nightslink,
|
|
colornum == 0 ? colormaps : R_GetTranslationColormap(TC_DEFAULT, colornum, GTC_CACHE));
|
|
}
|
|
}
|
|
else // normal, fullbright
|
|
{
|
|
#if 0 // Cool but silly number effect where the previous link number fades away
|
|
if (stplyr->linkcount > 2 && stplyr->linktimer > (2*TICRATE) - 9)
|
|
{
|
|
INT32 offs = 10 - (stplyr->linktimer - (2*TICRATE - 9));
|
|
INT32 ghosttrans = offs << V_ALPHASHIFT;
|
|
ST_DrawNightsOverlayNum(160, STRINGY(160+offs), SPLITFLAGS(V_SNAPTOBOTTOM)|ghosttrans, (stplyr->linkcount-2),
|
|
nightsnum, colornum);
|
|
}
|
|
#endif
|
|
|
|
if (splitscreen)
|
|
{
|
|
ST_DrawNightsOverlayNum(256, STRINGY(152), SPLITFLAGS(V_SNAPTOBOTTOM)|V_SNAPTORIGHT, (stplyr->linkcount-1), nightsnum, colornum);
|
|
V_DrawMappedPatch(264, STRINGY(152), SPLITFLAGS(V_SNAPTOBOTTOM)|V_SNAPTORIGHT, nightslink,
|
|
colornum == 0 ? colormaps : R_GetTranslationColormap(TC_DEFAULT, colornum, GTC_CACHE));
|
|
}
|
|
else
|
|
{
|
|
ST_DrawNightsOverlayNum(160, 160, V_SNAPTOBOTTOM, (stplyr->linkcount-1), nightsnum, colornum);
|
|
V_DrawMappedPatch(168, 160, V_SNAPTOBOTTOM, nightslink,
|
|
colornum == 0 ? colormaps : R_GetTranslationColormap(TC_DEFAULT, colornum, GTC_CACHE));
|
|
}
|
|
}
|
|
|
|
// Show remaining link time left in debug
|
|
if (cv_debug & DBG_NIGHTSBASIC)
|
|
V_DrawCenteredString(BASEVIDWIDTH/2, 180, V_SNAPTOBOTTOM, va("End in %d.%02d", stplyr->linktimer/TICRATE, G_TicsToCentiseconds(stplyr->linktimer)));
|
|
}
|
|
|
|
// Drill meter
|
|
if (
|
|
#ifdef HAVE_BLUA
|
|
LUA_HudEnabled(hud_nightsdrill) &&
|
|
#endif
|
|
stplyr->pflags & PF_NIGHTSMODE)
|
|
{
|
|
INT32 locx, locy;
|
|
INT32 dfill;
|
|
UINT8 fillpatch;
|
|
|
|
if (splitscreen || nosshack)
|
|
{
|
|
locx = 110;
|
|
locy = 188;
|
|
}
|
|
else
|
|
{
|
|
locx = 16;
|
|
locy = 180;
|
|
}
|
|
|
|
// Use which patch?
|
|
if (stplyr->pflags & PF_DRILLING)
|
|
fillpatch = (stplyr->drillmeter & 1) + 1;
|
|
else
|
|
fillpatch = 0;
|
|
|
|
if (splitscreen)
|
|
{ // 11-5-14 Replaced the old hack with a slightly better hack. -Red
|
|
V_DrawScaledPatch(locx, STRINGY(locy)-3, SPLITFLAGS(V_SNAPTOBOTTOM)|V_HUDTRANS, drillbar);
|
|
for (dfill = 0; dfill < stplyr->drillmeter/20 && dfill < 96; ++dfill)
|
|
V_DrawScaledPatch(locx + 2 + dfill, STRINGY(locy + 3), SPLITFLAGS(V_SNAPTOBOTTOM)|V_HUDTRANS, drillfill[fillpatch]);
|
|
}
|
|
else if (nosshack)
|
|
{ // Even dirtier hack-of-a-hack to draw seperate drill meters in splitscreen special stages but nothing else.
|
|
splitscreen = nosshack;
|
|
V_DrawScaledPatch(locx, STRINGY(locy)-3, V_HUDTRANS, drillbar);
|
|
for (dfill = 0; dfill < stplyr->drillmeter/20 && dfill < 96; ++dfill)
|
|
V_DrawScaledPatch(locx + 2 + dfill, STRINGY(locy + 3), V_HUDTRANS, drillfill[fillpatch]);
|
|
stplyr = &players[displayplayers[1]];
|
|
if (stplyr->pflags & PF_DRILLING)
|
|
fillpatch = (stplyr->drillmeter & 1) + 1;
|
|
else
|
|
fillpatch = 0;
|
|
V_DrawScaledPatch(locx, STRINGY(locy-3), V_SNAPTOBOTTOM|V_HUDTRANS, drillbar);
|
|
for (dfill = 0; dfill < stplyr->drillmeter/20 && dfill < 96; ++dfill)
|
|
V_DrawScaledPatch(locx + 2 + dfill, STRINGY(locy + 3), V_SNAPTOBOTTOM|V_HUDTRANS, drillfill[fillpatch]);
|
|
stplyr = &players[displayplayers[0]];
|
|
splitscreen = 0;
|
|
}
|
|
else
|
|
{ // Draw normally. <:3
|
|
V_DrawScaledPatch(locx, locy, V_SNAPTOLEFT|V_SNAPTOBOTTOM|V_HUDTRANS, drillbar);
|
|
for (dfill = 0; dfill < stplyr->drillmeter/20 && dfill < 96; ++dfill)
|
|
V_DrawScaledPatch(locx + 2 + dfill, locy + 3, V_SNAPTOLEFT|V_SNAPTOBOTTOM|V_HUDTRANS, drillfill[fillpatch]);
|
|
}
|
|
|
|
// Display actual drill amount and bumper time
|
|
if (cv_debug & DBG_NIGHTSBASIC)
|
|
{
|
|
if (stplyr->bumpertime)
|
|
V_DrawString(SCX(locx), SCY(locy - 8), V_NOSCALESTART|V_REDMAP|V_MONOSPACE, va("BUMPER: 0.%02d", G_TicsToCentiseconds(stplyr->bumpertime)));
|
|
else
|
|
V_DrawString(SCX(locx), SCY(locy - 8), V_NOSCALESTART|V_MONOSPACE, va("Drill: %3d%%", (stplyr->drillmeter*100)/(96*20)));
|
|
}
|
|
}
|
|
|
|
if (gametype == GT_RACE || gametype == GT_COMPETITION)
|
|
{
|
|
ST_drawScore();
|
|
ST_drawTime();
|
|
return;
|
|
}
|
|
|
|
// Begin drawing brackets/chip display
|
|
#ifdef HAVE_BLUA
|
|
if (LUA_HudEnabled(hud_nightsrings))
|
|
{
|
|
#endif
|
|
ST_DrawOverlayPatch(SCX(16), SCY(8), nbracket);
|
|
if (G_IsSpecialStage(gamemap))
|
|
ST_DrawOverlayPatch(SCX(24), SCY(8) + SCZ(8), nsshud);
|
|
else
|
|
ST_DrawOverlayPatch(SCX(24), SCY(8) + SCZ(8), nhud[(leveltime/2)%12]);
|
|
|
|
if (G_IsSpecialStage(gamemap))
|
|
{
|
|
INT32 i;
|
|
total_ringcount = 0;
|
|
for (i = 0; i < MAXPLAYERS; i++)
|
|
if (playeringame[i] && players[i].pflags & PF_NIGHTSMODE && players[i].health)
|
|
total_ringcount += players[i].health - 1;
|
|
}
|
|
else
|
|
total_ringcount = stplyr->health-1;
|
|
|
|
if (stplyr->capsule)
|
|
{
|
|
INT32 amount;
|
|
const INT32 length = 88;
|
|
|
|
origamount = stplyr->capsule->spawnpoint->angle;
|
|
I_Assert(origamount > 0); // should not happen now
|
|
|
|
ST_DrawOverlayPatch(SCX(72), SCY(8), nbracket);
|
|
ST_DrawOverlayPatch(SCX(74), SCY(8) + SCZ(4), minicaps);
|
|
|
|
if (stplyr->capsule->reactiontime != 0)
|
|
{
|
|
INT32 r;
|
|
const INT32 orblength = 20;
|
|
|
|
for (r = 0; r < 5; r++)
|
|
{
|
|
ST_DrawOverlayPatch(SCX(230 - (7*r)), SCY(144), redstat);
|
|
ST_DrawOverlayPatch(SCX(188 - (7*r)), SCY(144), orngstat);
|
|
ST_DrawOverlayPatch(SCX(146 - (7*r)), SCY(144), yelstat);
|
|
ST_DrawOverlayPatch(SCX(104 - (7*r)), SCY(144), byelstat);
|
|
}
|
|
|
|
amount = (origamount - stplyr->capsule->health);
|
|
amount = (amount * orblength)/origamount;
|
|
|
|
if (amount > 0)
|
|
{
|
|
INT32 t;
|
|
|
|
// Fill up the bar with blue orbs... in reverse! (yuck)
|
|
for (r = amount; r > 0; r--)
|
|
{
|
|
t = r;
|
|
|
|
if (r > 15) ++t;
|
|
if (r > 10) ++t;
|
|
if (r > 5) ++t;
|
|
|
|
ST_DrawOverlayPatch(SCX(69 + (7*t)), SCY(144), bluestat);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
INT32 cfill;
|
|
|
|
// Lil' white box!
|
|
V_DrawScaledPatch(15, STRINGY(8) + 34, V_SNAPTOLEFT|V_SNAPTOTOP|V_HUDTRANS, capsulebar);
|
|
|
|
amount = (origamount - stplyr->capsule->health);
|
|
amount = (amount * length)/origamount;
|
|
|
|
for (cfill = 0; cfill < amount && cfill < 88; ++cfill)
|
|
V_DrawScaledPatch(15 + cfill + 1, STRINGY(8) + 35, V_SNAPTOLEFT|V_SNAPTOTOP|V_HUDTRANS, capsulefill);
|
|
}
|
|
|
|
if (total_ringcount >= stplyr->capsule->health)
|
|
ST_DrawOverlayPatch(SCX(40), SCY(8) + SCZ(5), nredar[leveltime%8]);
|
|
else
|
|
ST_DrawOverlayPatch(SCX(40), SCY(8) + SCZ(5), narrow[(leveltime/2)%8]);
|
|
}
|
|
else
|
|
ST_DrawOverlayPatch(SCX(40), SCY(8) + SCZ(5), narrow[8]);
|
|
|
|
if (total_ringcount >= 100)
|
|
ST_DrawOverlayNum((total_ringcount >= 1000) ? SCX(76) : SCX(72), SCY(8) + SCZ(11), total_ringcount);
|
|
else
|
|
ST_DrawOverlayNum(SCX(68), SCY(8) + SCZ(11), total_ringcount);
|
|
#ifdef HAVE_BLUA
|
|
}
|
|
#endif
|
|
|
|
// Score
|
|
if (!stplyr->exiting
|
|
#ifdef HAVE_BLUA
|
|
&& LUA_HudEnabled(hud_nightsscore)
|
|
#endif
|
|
)
|
|
{
|
|
ST_DrawNightsOverlayNum(304, STRINGY(16), SPLITFLAGS(V_SNAPTOTOP)|V_SNAPTORIGHT, stplyr->marescore, nightsnum, SKINCOLOR_STEEL);
|
|
}
|
|
|
|
if (!stplyr->exiting
|
|
#ifdef HAVE_BLUA
|
|
// TODO give this its own section for Lua
|
|
&& LUA_HudEnabled(hud_nightsscore)
|
|
#endif
|
|
)
|
|
{
|
|
if (modeattacking == ATTACKING_NIGHTS)
|
|
{
|
|
INT32 maretime = max(stplyr->realtime - stplyr->marebegunat, 0);
|
|
fixed_t cornerx = vid.width, cornery = vid.height-SCZ(20);
|
|
|
|
#define ASSISHHUDFIX(n) (n*vid.dupx)
|
|
ST_DrawOverlayPatch(cornerx-ASSISHHUDFIX(22), cornery, W_CachePatchName("NGRTIMER", PU_HUDGFX));
|
|
ST_DrawPaddedOverlayNum(cornerx-ASSISHHUDFIX(22), cornery, G_TicsToCentiseconds(maretime), 2);
|
|
ST_DrawOverlayPatch(cornerx-ASSISHHUDFIX(46), cornery, sboperiod);
|
|
if (maretime < 60*TICRATE)
|
|
ST_DrawOverlayNum(cornerx-ASSISHHUDFIX(46), cornery, G_TicsToSeconds(maretime));
|
|
else
|
|
{
|
|
ST_DrawPaddedOverlayNum(cornerx-ASSISHHUDFIX(46), cornery, G_TicsToSeconds(maretime), 2);
|
|
ST_DrawOverlayPatch(cornerx-ASSISHHUDFIX(70), cornery, sbocolon);
|
|
ST_DrawOverlayNum(cornerx-ASSISHHUDFIX(70), cornery, G_TicsToMinutes(maretime, true));
|
|
}
|
|
}
|
|
#undef ASSISHHUDFIX
|
|
}
|
|
|
|
// Ideya time remaining
|
|
if (!stplyr->exiting && stplyr->nightstime > 0
|
|
#ifdef HAVE_BLUA
|
|
&& LUA_HudEnabled(hud_nightstime)
|
|
#endif
|
|
)
|
|
{
|
|
INT32 realnightstime = stplyr->nightstime/TICRATE;
|
|
INT32 numbersize;
|
|
|
|
if (G_IsSpecialStage(gamemap))
|
|
{
|
|
tic_t lowest_time = stplyr->nightstime;
|
|
INT32 i;
|
|
for (i = 0; i < MAXPLAYERS; i++)
|
|
if (playeringame[i] && players[i].pflags & PF_NIGHTSMODE && players[i].nightstime < lowest_time)
|
|
lowest_time = players[i].nightstime;
|
|
realnightstime = lowest_time/TICRATE;
|
|
}
|
|
|
|
if (stplyr->powers[pw_flashing] > TICRATE ) // was hit
|
|
{
|
|
UINT16 flashingLeft = stplyr->powers[pw_flashing]-(TICRATE);
|
|
if (flashingLeft < TICRATE/2) // Start fading out
|
|
{
|
|
UINT32 fadingFlag = (9 - 9*flashingLeft/(TICRATE/2)) << V_ALPHASHIFT;
|
|
V_DrawTranslucentPatch(SCX(160 - (minus5sec->width/2)), SCY(28), V_NOSCALESTART|fadingFlag, minus5sec);
|
|
}
|
|
else
|
|
V_DrawScaledPatch(SCX(160 - (minus5sec->width/2)), SCY(28), V_NOSCALESTART, minus5sec);
|
|
}
|
|
|
|
if (realnightstime < 10)
|
|
numbersize = 16/2;
|
|
else if (realnightstime < 100)
|
|
numbersize = 32/2;
|
|
else
|
|
numbersize = 48/2;
|
|
|
|
if (realnightstime < 10)
|
|
ST_DrawNightsOverlayNum(160 + numbersize, STRINGY(12), SPLITFLAGS(V_SNAPTOTOP), realnightstime,
|
|
nightsnum, SKINCOLOR_RED);
|
|
else
|
|
ST_DrawNightsOverlayNum(160 + numbersize, STRINGY(12), SPLITFLAGS(V_SNAPTOTOP), realnightstime,
|
|
nightsnum, SKINCOLOR_SUPER4);
|
|
|
|
// Show exact time in debug
|
|
if (cv_debug & DBG_NIGHTSBASIC)
|
|
V_DrawString(160 + numbersize + 8, 24, V_SNAPTOTOP|((realnightstime < 10) ? V_REDMAP : V_YELLOWMAP), va("%02d", G_TicsToCentiseconds(stplyr->nightstime)));
|
|
}
|
|
|
|
// Show pickup durations
|
|
if (cv_debug & DBG_NIGHTSBASIC)
|
|
{
|
|
UINT16 pwr;
|
|
|
|
if (stplyr->powers[pw_nights_superloop])
|
|
{
|
|
pwr = stplyr->powers[pw_nights_superloop];
|
|
V_DrawSmallScaledPatch(SCX(110), SCY(44), V_NOSCALESTART, W_CachePatchName("NPRUA0",PU_CACHE));
|
|
V_DrawThinString(SCX(106), SCY(52), V_NOSCALESTART|V_MONOSPACE, va("%2d.%02d", pwr/TICRATE, G_TicsToCentiseconds(pwr)));
|
|
}
|
|
|
|
if (stplyr->powers[pw_nights_helper])
|
|
{
|
|
pwr = stplyr->powers[pw_nights_helper];
|
|
V_DrawSmallScaledPatch(SCX(150), SCY(44), V_NOSCALESTART, W_CachePatchName("NPRUC0",PU_CACHE));
|
|
V_DrawThinString(SCX(146), SCY(52), V_NOSCALESTART|V_MONOSPACE, va("%2d.%02d", pwr/TICRATE, G_TicsToCentiseconds(pwr)));
|
|
}
|
|
|
|
if (stplyr->powers[pw_nights_linkfreeze])
|
|
{
|
|
pwr = stplyr->powers[pw_nights_linkfreeze];
|
|
V_DrawSmallScaledPatch(SCX(190), SCY(44), V_NOSCALESTART, W_CachePatchName("NPRUE0",PU_CACHE));
|
|
V_DrawThinString(SCX(186), SCY(52), V_NOSCALESTART|V_MONOSPACE, va("%2d.%02d", pwr/TICRATE, G_TicsToCentiseconds(pwr)));
|
|
}
|
|
}
|
|
|
|
// Records/extra text
|
|
#ifdef HAVE_BLUA
|
|
if (LUA_HudEnabled(hud_nightsrecords))
|
|
#endif
|
|
ST_drawNightsRecords();
|
|
|
|
splitscreen = nosshack;
|
|
}
|
|
*/
|
|
|
|
/*
|
|
static void ST_drawWeaponRing(powertype_t weapon, INT32 rwflag, INT32 wepflag, INT32 xoffs, patch_t *pat)
|
|
{
|
|
INT32 txtflags = 0, patflags = 0;
|
|
|
|
if (stplyr->powers[weapon])
|
|
{
|
|
if (stplyr->powers[weapon] >= rw_maximums[wepflag])
|
|
txtflags |= V_YELLOWMAP;
|
|
|
|
if (weapon == pw_infinityring
|
|
|| (stplyr->ringweapons & rwflag && stplyr->health > 1))
|
|
txtflags |= V_20TRANS;
|
|
else
|
|
{
|
|
txtflags |= V_TRANSLUCENT;
|
|
patflags = V_80TRANS;
|
|
}
|
|
|
|
V_DrawScaledPatch(8 + xoffs, STRINGY(162), V_SNAPTOLEFT|patflags, pat);
|
|
|
|
if (stplyr->powers[weapon] > 99)
|
|
V_DrawThinString(8 + xoffs + 1, STRINGY(162), V_SNAPTOLEFT|txtflags, va("%d", stplyr->powers[weapon]));
|
|
else
|
|
V_DrawString(8 + xoffs, STRINGY(162), V_SNAPTOLEFT|txtflags, va("%d", stplyr->powers[weapon]));
|
|
|
|
if (stplyr->currentweapon == wepflag)
|
|
V_DrawScaledPatch(6 + xoffs, STRINGY(162 - (splitscreen ? 4 : 2)), V_SNAPTOLEFT, curweapon);
|
|
}
|
|
else if (stplyr->ringweapons & rwflag)
|
|
V_DrawScaledPatch(8 + xoffs, STRINGY(162), V_SNAPTOLEFT|V_TRANSLUCENT, pat);
|
|
}
|
|
*/
|
|
|
|
/*
|
|
static void ST_drawMatchHUD(void) // SRB2kart - unused.
|
|
{
|
|
INT32 offset = (BASEVIDWIDTH / 2) - (NUM_WEAPONS * 10);
|
|
|
|
if (!G_BattleGametype())
|
|
return;
|
|
|
|
if (G_TagGametype() && !(stplyr->pflags & PF_TAGIT))
|
|
return;
|
|
|
|
#ifdef HAVE_BLUA
|
|
if (LUA_HudEnabled(hud_weaponrings)) {
|
|
#endif
|
|
|
|
if (stplyr->powers[pw_infinityring])
|
|
ST_drawWeaponRing(pw_infinityring, 0, 0, offset, infinityring);
|
|
else if (stplyr->health > 1)
|
|
V_DrawScaledPatch(8 + offset, STRINGY(162), V_SNAPTOLEFT, normring);
|
|
else
|
|
V_DrawTranslucentPatch(8 + offset, STRINGY(162), V_SNAPTOLEFT|V_80TRANS, normring);
|
|
|
|
if (!stplyr->currentweapon)
|
|
V_DrawScaledPatch(6 + offset, STRINGY(162 - (splitscreen ? 4 : 2)), V_SNAPTOLEFT, curweapon);
|
|
|
|
offset += 20;
|
|
ST_drawWeaponRing(pw_automaticring, RW_AUTO, WEP_AUTO, offset, autoring);
|
|
offset += 20;
|
|
ST_drawWeaponRing(pw_bouncering, RW_BOUNCE, WEP_BOUNCE, offset, bouncering);
|
|
offset += 20;
|
|
ST_drawWeaponRing(pw_scatterring, RW_SCATTER, WEP_SCATTER, offset, scatterring);
|
|
offset += 20;
|
|
ST_drawWeaponRing(pw_grenadering, RW_GRENADE, WEP_GRENADE, offset, grenadering);
|
|
offset += 20;
|
|
ST_drawWeaponRing(pw_explosionring, RW_EXPLODE, WEP_EXPLODE, offset, explosionring);
|
|
offset += 20;
|
|
ST_drawWeaponRing(pw_railring, RW_RAIL, WEP_RAIL, offset, railring);
|
|
|
|
#ifdef HAVE_BLUA
|
|
}
|
|
|
|
if (LUA_HudEnabled(hud_powerstones)) {
|
|
#endif
|
|
|
|
// Power Stones collected
|
|
offset = 136; // Used for Y now
|
|
|
|
if (stplyr->powers[pw_emeralds] & EMERALD1)
|
|
V_DrawScaledPatch(28, STRINGY(offset), V_SNAPTOLEFT, tinyemeraldpics[0]);
|
|
|
|
offset += 8;
|
|
|
|
if (stplyr->powers[pw_emeralds] & EMERALD2)
|
|
V_DrawScaledPatch(40, STRINGY(offset), V_SNAPTOLEFT, tinyemeraldpics[1]);
|
|
|
|
if (stplyr->powers[pw_emeralds] & EMERALD6)
|
|
V_DrawScaledPatch(16, STRINGY(offset), V_SNAPTOLEFT, tinyemeraldpics[5]);
|
|
|
|
offset += 16;
|
|
|
|
if (stplyr->powers[pw_emeralds] & EMERALD3)
|
|
V_DrawScaledPatch(40, STRINGY(offset), V_SNAPTOLEFT, tinyemeraldpics[2]);
|
|
|
|
if (stplyr->powers[pw_emeralds] & EMERALD5)
|
|
V_DrawScaledPatch(16, STRINGY(offset), V_SNAPTOLEFT, tinyemeraldpics[4]);
|
|
|
|
offset += 8;
|
|
|
|
if (stplyr->powers[pw_emeralds] & EMERALD4)
|
|
V_DrawScaledPatch(28, STRINGY(offset), V_SNAPTOLEFT, tinyemeraldpics[3]);
|
|
|
|
offset -= 16;
|
|
|
|
if (stplyr->powers[pw_emeralds] & EMERALD7)
|
|
V_DrawScaledPatch(28, STRINGY(offset), V_SNAPTOLEFT, tinyemeraldpics[6]);
|
|
|
|
#ifdef HAVE_BLUA
|
|
}
|
|
#endif
|
|
}
|
|
*/
|
|
|
|
/*
|
|
static inline void ST_drawRaceHUD(void) // SRB2kart - unused.
|
|
{
|
|
if (leveltime > starttime-(3*TICRATE) && leveltime <= starttime-(2*TICRATE))
|
|
V_DrawScaledPatch(SCX((BASEVIDWIDTH - SHORT(race3->width))/2), (INT32)(SCY(BASEVIDHEIGHT/2)), V_NOSCALESTART, race3);
|
|
else if (leveltime > starttime-(2*TICRATE) && leveltime <= starttime-TICRATE)
|
|
V_DrawScaledPatch(SCX((BASEVIDWIDTH - SHORT(race2->width))/2), (INT32)(SCY(BASEVIDHEIGHT/2)), V_NOSCALESTART, race2);
|
|
else if (leveltime > starttime-TICRATE && leveltime <= starttime)
|
|
V_DrawScaledPatch(SCX((BASEVIDWIDTH - SHORT(race1->width))/2), (INT32)(SCY(BASEVIDHEIGHT/2)), V_NOSCALESTART, race1);
|
|
else if (leveltime > starttime && leveltime <= starttime+TICRATE)
|
|
V_DrawScaledPatch(SCX((BASEVIDWIDTH - SHORT(racego->width))/2), (INT32)(SCY(BASEVIDHEIGHT/2)), V_NOSCALESTART, racego);
|
|
|
|
if (circuitmap)
|
|
{
|
|
if (stplyr->exiting)
|
|
V_DrawString(hudinfo[HUD_LAP].x, STRINGY(hudinfo[HUD_LAP].y), V_YELLOWMAP, "FINISHED!");
|
|
else
|
|
V_DrawString(hudinfo[HUD_LAP].x, STRINGY(hudinfo[HUD_LAP].y), 0, va("Lap: %u/%d", stplyr->laps+1, cv_numlaps.value));
|
|
}
|
|
}
|
|
*/
|
|
|
|
/*
|
|
static void ST_drawTagHUD(void) // SRB2kart - unused.
|
|
{
|
|
char pstime[33] = "";
|
|
char pstext[33] = "";
|
|
|
|
// Figure out what we're going to print.
|
|
if (leveltime < hidetime * TICRATE) //during the hide time, the seeker and hiders have different messages on their HUD.
|
|
{
|
|
if (hidetime)
|
|
sprintf(pstime, "%d", (hidetime - leveltime/TICRATE)); //hide time is in seconds, not tics.
|
|
|
|
if (stplyr->pflags & PF_TAGIT && !stplyr->spectator)
|
|
sprintf(pstext, "%s", M_GetText("WAITING FOR PLAYERS TO HIDE..."));
|
|
else
|
|
{
|
|
if (!stplyr->spectator) //spectators get a generic HUD message rather than a gametype specific one.
|
|
{
|
|
if (gametype == GT_HIDEANDSEEK) //hide and seek.
|
|
sprintf(pstext, "%s", M_GetText("HIDE BEFORE TIME RUNS OUT!"));
|
|
else //default
|
|
sprintf(pstext, "%s", M_GetText("FLEE BEFORE YOU ARE HUNTED!"));
|
|
}
|
|
else
|
|
sprintf(pstext, "%s", M_GetText("HIDE TIME REMAINING:"));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (cv_timelimit.value && timelimitintics >= leveltime)
|
|
sprintf(pstime, "%d", (timelimitintics-leveltime)/TICRATE);
|
|
|
|
if (stplyr->pflags & PF_TAGIT)
|
|
sprintf(pstext, "%s", M_GetText("YOU'RE IT!"));
|
|
else
|
|
{
|
|
if (cv_timelimit.value)
|
|
sprintf(pstext, "%s", M_GetText("TIME REMAINING:"));
|
|
else //Since having no hud message in tag is not characteristic:
|
|
sprintf(pstext, "%s", M_GetText("NO TIME LIMIT"));
|
|
}
|
|
}
|
|
|
|
// Print the stuff.
|
|
if (pstext[0])
|
|
{
|
|
if (splitscreen)
|
|
V_DrawCenteredString(BASEVIDWIDTH/2, STRINGY(168), 0, pstext);
|
|
else
|
|
V_DrawCenteredString(BASEVIDWIDTH/2, STRINGY(184), 0, pstext);
|
|
}
|
|
if (pstime[0])
|
|
{
|
|
if (splitscreen)
|
|
V_DrawCenteredString(BASEVIDWIDTH/2, STRINGY(184), 0, pstime);
|
|
else
|
|
V_DrawCenteredString(BASEVIDWIDTH/2, STRINGY(192), 0, pstime);
|
|
}
|
|
}
|
|
|
|
static void ST_drawCTFHUD(void) // SRB2kart - unused.
|
|
{
|
|
INT32 i;
|
|
UINT16 whichflag = 0;
|
|
|
|
// Draw the flags
|
|
V_DrawSmallScaledPatch(256, (splitscreen) ? STRINGY(160) : STRINGY(176), V_HUDTRANS, rflagico);
|
|
V_DrawSmallScaledPatch(288, (splitscreen) ? STRINGY(160) : STRINGY(176), V_HUDTRANS, bflagico);
|
|
|
|
for (i = 0; i < MAXPLAYERS; i++)
|
|
{
|
|
if (players[i].gotflag & GF_REDFLAG) // Red flag isn't at base
|
|
V_DrawScaledPatch(256, (splitscreen) ? STRINGY(156) : STRINGY(174), V_HUDTRANS, nonicon);
|
|
else if (players[i].gotflag & GF_BLUEFLAG) // Blue flag isn't at base
|
|
V_DrawScaledPatch(288, (splitscreen) ? STRINGY(156) : STRINGY(174), V_HUDTRANS, nonicon);
|
|
|
|
whichflag |= players[i].gotflag;
|
|
if ((whichflag & (GF_REDFLAG|GF_BLUEFLAG)) == (GF_REDFLAG|GF_BLUEFLAG))
|
|
break; // both flags were found, let's stop early
|
|
}
|
|
|
|
// YOU have a flag. Display a monitor-like icon for it.
|
|
if (stplyr->gotflag)
|
|
{
|
|
patch_t *p = (stplyr->gotflag & GF_REDFLAG) ? gotrflag : gotbflag;
|
|
|
|
if (splitscreen)
|
|
V_DrawSmallScaledPatch(312, STRINGY(24) + 42, V_SNAPTORIGHT|V_SNAPTOTOP|V_HUDTRANS, p);
|
|
else
|
|
V_DrawScaledPatch(304, 24 + 84, V_SNAPTORIGHT|V_SNAPTOTOP|V_HUDTRANS, p);
|
|
}
|
|
|
|
// Display a countdown timer showing how much time left until the flag your team dropped returns to base.
|
|
{
|
|
char timeleft[33];
|
|
if (redflag && redflag->fuse > 1)
|
|
{
|
|
sprintf(timeleft, "%u", (redflag->fuse / TICRATE));
|
|
V_DrawCenteredString(268, STRINGY(184), V_YELLOWMAP|V_HUDTRANS, timeleft);
|
|
}
|
|
|
|
if (blueflag && blueflag->fuse > 1)
|
|
{
|
|
sprintf(timeleft, "%u", (blueflag->fuse / TICRATE));
|
|
V_DrawCenteredString(300, STRINGY(184), V_YELLOWMAP|V_HUDTRANS, timeleft);
|
|
}
|
|
}
|
|
}
|
|
*/
|
|
|
|
// Draws "Red Team", "Blue Team", or "Spectator" for team gametypes.
|
|
/*
|
|
static inline void ST_drawTeamName(void) // SRB2kart - unused.
|
|
{
|
|
if (stplyr->ctfteam == 1)
|
|
V_DrawString(256, splitscreen ? STRINGY(184) : STRINGY(192), V_HUDTRANSHALF, "RED TEAM");
|
|
else if (stplyr->ctfteam == 2)
|
|
V_DrawString(248, splitscreen ? STRINGY(184) : STRINGY(192), V_HUDTRANSHALF, "BLUE TEAM");
|
|
else
|
|
V_DrawString(244, splitscreen ? STRINGY(184) : STRINGY(192), V_HUDTRANSHALF, "SPECTATOR");
|
|
}
|
|
*/
|
|
|
|
/*
|
|
static void ST_drawSpecialStageHUD(void) // SRB2kart - unused.
|
|
{
|
|
if (totalrings > 0)
|
|
ST_DrawNumFromHudWS(HUD_SS_TOTALRINGS, totalrings);
|
|
|
|
if (leveltime < 5*TICRATE && totalrings > 0)
|
|
{
|
|
ST_DrawPatchFromHud(HUD_GETRINGS, getall);
|
|
ST_DrawNumFromHud(HUD_GETRINGSNUM, totalrings);
|
|
}
|
|
|
|
if (sstimer)
|
|
{
|
|
V_DrawString(hudinfo[HUD_TIMELEFT].x, STRINGY(hudinfo[HUD_TIMELEFT].y), V_HUDTRANS, M_GetText("TIME LEFT"));
|
|
ST_DrawNumFromHud(HUD_TIMELEFTNUM, sstimer/TICRATE);
|
|
}
|
|
else
|
|
ST_DrawPatchFromHud(HUD_TIMEUP, timeup);
|
|
}
|
|
*/
|
|
|
|
/*
|
|
static INT32 ST_drawEmeraldHuntIcon(mobj_t *hunt, patch_t **patches, INT32 offset)
|
|
{
|
|
INT32 interval, i;
|
|
UINT32 dist = ((UINT32)P_AproxDistance(P_AproxDistance(stplyr->mo->x - hunt->x, stplyr->mo->y - hunt->y), stplyr->mo->z - hunt->z))>>FRACBITS;
|
|
|
|
if (dist < 128)
|
|
{
|
|
i = 5;
|
|
interval = 5;
|
|
}
|
|
else if (dist < 512)
|
|
{
|
|
i = 4;
|
|
interval = 10;
|
|
}
|
|
else if (dist < 1024)
|
|
{
|
|
i = 3;
|
|
interval = 20;
|
|
}
|
|
else if (dist < 2048)
|
|
{
|
|
i = 2;
|
|
interval = 30;
|
|
}
|
|
else if (dist < 3072)
|
|
{
|
|
i = 1;
|
|
interval = 35;
|
|
}
|
|
else
|
|
{
|
|
i = 0;
|
|
interval = 0;
|
|
}
|
|
|
|
V_DrawScaledPatch(hudinfo[HUD_HUNTPICS].x+offset, STRINGY(hudinfo[HUD_HUNTPICS].y), V_HUDTRANS, patches[i]);
|
|
return interval;
|
|
}
|
|
*/
|
|
|
|
/*
|
|
// Separated a few things to stop the SOUND EFFECTS BLARING UGH SHUT UP AAAA
|
|
static void ST_doHuntIconsAndSound(void) // SRB2kart - unused.
|
|
{
|
|
INT32 interval = 0, newinterval = 0;
|
|
|
|
if (hunt1 && hunt1->health)
|
|
interval = ST_drawEmeraldHuntIcon(hunt1, hunthoming, -20);
|
|
|
|
if (hunt2 && hunt2->health)
|
|
{
|
|
newinterval = ST_drawEmeraldHuntIcon(hunt2, hunthoming, 0);
|
|
if (newinterval && (!interval || newinterval < interval))
|
|
interval = newinterval;
|
|
}
|
|
|
|
if (hunt3 && hunt3->health)
|
|
{
|
|
newinterval = ST_drawEmeraldHuntIcon(hunt3, hunthoming, 20);
|
|
if (newinterval && (!interval || newinterval < interval))
|
|
interval = newinterval;
|
|
}
|
|
|
|
if (!(P_AutoPause() || paused) && interval > 0 && leveltime && leveltime % interval == 0)
|
|
S_StartSound(NULL, sfx_emfind);
|
|
}
|
|
|
|
static void ST_doItemFinderIconsAndSound(void) // SRB2kart - unused.
|
|
{
|
|
INT32 emblems[16];
|
|
thinker_t *th;
|
|
mobj_t *mo2;
|
|
|
|
UINT8 stemblems = 0, stunfound = 0;
|
|
INT32 i;
|
|
INT32 interval = 0, newinterval = 0;
|
|
INT32 soffset;
|
|
|
|
for (i = 0; i < numemblems; ++i)
|
|
{
|
|
if (emblemlocations[i].type > ET_SKIN || emblemlocations[i].level != gamemap)
|
|
continue;
|
|
|
|
emblems[stemblems++] = i;
|
|
|
|
if (!emblemlocations[i].collected)
|
|
++stunfound;
|
|
|
|
if (stemblems >= 16)
|
|
break;
|
|
}
|
|
// Found all/none exist? Don't waste our time
|
|
if (!stunfound)
|
|
return;
|
|
|
|
// Scan thinkers to find emblem mobj with these ids
|
|
for (th = thinkercap.next; th != &thinkercap; th = th->next)
|
|
{
|
|
if (th->function.acp1 != (actionf_p1)P_MobjThinker)
|
|
continue;
|
|
mo2 = (mobj_t *)th;
|
|
|
|
if (mo2->type == MT_EMBLEM)
|
|
{
|
|
if (!(mo2->flags & MF_SPECIAL))
|
|
continue;
|
|
|
|
for (i = 0; i < stemblems; ++i)
|
|
{
|
|
if (mo2->health == emblems[i]+1)
|
|
{
|
|
soffset = (i * 20) - ((stemblems-1) * 10);
|
|
|
|
newinterval = ST_drawEmeraldHuntIcon(mo2, itemhoming, soffset);
|
|
if (newinterval && (!interval || newinterval < interval))
|
|
interval = newinterval;
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!(P_AutoPause() || paused) && interval > 0 && leveltime && leveltime % interval == 0)
|
|
S_StartSound(NULL, sfx_emfind);
|
|
}
|
|
*/
|
|
|
|
// Draw the status bar overlay, customisable: the user chooses which
|
|
// kind of information to overlay
|
|
//
|
|
static void ST_overlayDrawer(void)
|
|
{
|
|
//hu_showscores = auto hide score/time/rings when tab rankings are shown
|
|
if (!(hu_showscores && (netgame || multiplayer)))
|
|
{
|
|
K_drawKartHUD();
|
|
|
|
/* SRB2kart doesn't need this stuff
|
|
if (maptol & TOL_NIGHTS)
|
|
ST_drawNiGHTSHUD();
|
|
else
|
|
{
|
|
#ifdef HAVE_BLUA
|
|
if (LUA_HudEnabled(hud_score))
|
|
#endif
|
|
ST_drawScore();
|
|
#ifdef HAVE_BLUA
|
|
if (LUA_HudEnabled(hud_time))
|
|
#endif
|
|
ST_drawTime();
|
|
#ifdef HAVE_BLUA
|
|
if (LUA_HudEnabled(hud_rings))
|
|
#endif
|
|
ST_drawRings();
|
|
if (G_GametypeUsesLives()
|
|
#ifdef HAVE_BLUA
|
|
&& LUA_HudEnabled(hud_lives)
|
|
#endif
|
|
)
|
|
ST_drawLives();
|
|
}
|
|
*/
|
|
}
|
|
|
|
// GAME OVER pic
|
|
/*if (G_GametypeUsesLives() && stplyr->lives <= 0 && !(hu_showscores && (netgame || multiplayer)))
|
|
{
|
|
patch_t *p;
|
|
|
|
if (racecountdown == 1)
|
|
p = timeover;
|
|
else
|
|
p = sboover;
|
|
|
|
V_DrawScaledPatch((BASEVIDWIDTH - SHORT(p->width))/2, STRINGY(BASEVIDHEIGHT/2 - (SHORT(p->height)/2)), 0, p);
|
|
}*/
|
|
|
|
if (!hu_showscores) // hide the following if TAB is held
|
|
{
|
|
// Countdown timer for Race Mode
|
|
// ...moved to k_kart.c so we can take advantage of the LAPS_Y value
|
|
|
|
/* SRB2kart doesn't need this stuff, I think
|
|
// If you are in overtime, put a big honkin' flashin' message on the screen.
|
|
if (G_BattleGametype() && cv_overtime.value
|
|
&& (leveltime > (timelimitintics + TICRATE/2)) && cv_timelimit.value && (leveltime/TICRATE % 2 == 0))
|
|
{
|
|
if (splitscreen)
|
|
V_DrawCenteredString(BASEVIDWIDTH/2, STRINGY(168), 0, M_GetText("OVERTIME!"));
|
|
else
|
|
V_DrawCenteredString(BASEVIDWIDTH/2, STRINGY(184), 0, M_GetText("OVERTIME!"));
|
|
}
|
|
|
|
// Draw Match-related stuff
|
|
//\note Match HUD is drawn no matter what gametype.
|
|
// ... just not if you're a spectator.
|
|
if (!stplyr->spectator)
|
|
ST_drawMatchHUD();
|
|
|
|
// Race HUD Stuff
|
|
if (gametype == GT_RACE || gametype == GT_COMPETITION)
|
|
ST_drawRaceHUD();
|
|
// Tag HUD Stuff
|
|
else if (gametype == GT_TAG || gametype == GT_HIDEANDSEEK)
|
|
ST_drawTagHUD();
|
|
// CTF HUD Stuff
|
|
else if (gametype == GT_CTF)
|
|
ST_drawCTFHUD();
|
|
|
|
// Team names for team gametypes
|
|
if (G_GametypeHasTeams())
|
|
ST_drawTeamName();
|
|
|
|
// Special Stage HUD
|
|
if (!useNightsSS && G_IsSpecialStage(gamemap) && stplyr == &players[displayplayers[0]])
|
|
ST_drawSpecialStageHUD();
|
|
|
|
// Emerald Hunt Indicators
|
|
if (cv_itemfinder.value && M_SecretUnlocked(SECRET_ITEMFINDER))
|
|
ST_doItemFinderIconsAndSound();
|
|
else
|
|
ST_doHuntIconsAndSound();
|
|
|
|
if (stplyr->powers[pw_gravityboots] > 3*TICRATE || (stplyr->powers[pw_gravityboots] && leveltime & 1))
|
|
V_DrawScaledPatch(hudinfo[HUD_GRAVBOOTSICO].x, STRINGY(hudinfo[HUD_GRAVBOOTSICO].y), V_SNAPTORIGHT, gravboots);
|
|
*/
|
|
|
|
if (!(multiplayer && demo.playback))
|
|
{
|
|
if(!P_IsLocalPlayer(stplyr))
|
|
{
|
|
/*char name[MAXPLAYERNAME+1];
|
|
// shorten the name if its more than twelve characters.
|
|
strlcpy(name, player_names[stplyr-players], 13);*/
|
|
|
|
// Show name of player being displayed
|
|
V_DrawCenteredString((BASEVIDWIDTH/2), BASEVIDHEIGHT-40, 0, M_GetText("Viewpoint:"));
|
|
V_DrawCenteredString((BASEVIDWIDTH/2), BASEVIDHEIGHT-32, V_ALLOWLOWERCASE, player_names[stplyr-players]);
|
|
}
|
|
}
|
|
else if (!demo.title)
|
|
{
|
|
|
|
if (!splitscreen)
|
|
{
|
|
V_DrawCenteredString((BASEVIDWIDTH/2), BASEVIDHEIGHT-40, V_HUDTRANSHALF, M_GetText("Viewpoint:"));
|
|
V_DrawCenteredString((BASEVIDWIDTH/2), BASEVIDHEIGHT-32, V_HUDTRANSHALF|V_ALLOWLOWERCASE, player_names[stplyr-players]);
|
|
}
|
|
else if (splitscreen == 1)
|
|
{
|
|
char name[MAXPLAYERNAME+12];
|
|
|
|
INT32 y = (stplyr == &players[displayplayers[0]]) ? 4 : BASEVIDHEIGHT/2-12;
|
|
sprintf(name, "VIEWPOINT: %s", player_names[stplyr-players]);
|
|
V_DrawRightAlignedThinString(BASEVIDWIDTH-40, y, V_HUDTRANSHALF|V_ALLOWLOWERCASE|K_calcSplitFlags(V_SNAPTOTOP|V_SNAPTOBOTTOM|V_SNAPTORIGHT), name);
|
|
}
|
|
else if (splitscreen)
|
|
{
|
|
V_DrawCenteredThinString((vid.width/vid.dupx)/4, BASEVIDHEIGHT/2 - 12, V_HUDTRANSHALF|V_ALLOWLOWERCASE|K_calcSplitFlags(V_SNAPTOBOTTOM|V_SNAPTOLEFT), player_names[stplyr-players]);
|
|
}
|
|
}
|
|
|
|
// This is where we draw all the fun cheese if you have the chasecam off!
|
|
/*if ((stplyr == &players[displayplayers[0]] && !camera[0].chase)
|
|
|| ((splitscreen && stplyr == &players[displayplayers[1]]) && !camera[1].chase)
|
|
|| ((splitscreen > 1 && stplyr == &players[displayplayers[2]]) && !camera[2].chase)
|
|
|| ((splitscreen > 2 && stplyr == &players[displayplayers[3]]) && !camera[3].chase))
|
|
{
|
|
ST_drawFirstPersonHUD();
|
|
}*/
|
|
}
|
|
|
|
#ifdef HAVE_BLUA
|
|
if (!(netgame || multiplayer) || !hu_showscores)
|
|
{
|
|
if (renderisnewtic)
|
|
{
|
|
LUA_HUD_ClearDrawList(luahuddrawlist_game);
|
|
LUAh_GameHUD(stplyr, luahuddrawlist_game);
|
|
}
|
|
LUA_HUD_DrawList(luahuddrawlist_game);
|
|
}
|
|
#endif
|
|
|
|
// draw level title Tails
|
|
if (*mapheaderinfo[gamemap-1]->lvlttl != '\0' && !(hu_showscores && (netgame || multiplayer) && !mapreset)
|
|
#ifdef HAVE_BLUA
|
|
&& LUA_HudEnabled(hud_stagetitle)
|
|
#endif
|
|
)
|
|
ST_drawLevelTitle();
|
|
|
|
if (!hu_showscores && netgame && !mapreset)
|
|
{
|
|
/*if (G_GametypeUsesLives() && stplyr->lives <= 0 && racecountdown != 1)
|
|
V_DrawCenteredString(BASEVIDWIDTH/2, STRINGY(132), 0, M_GetText("Press Viewpoint Key to watch a player."));
|
|
else if (gametype == GT_HIDEANDSEEK &&
|
|
(!stplyr->spectator && !(stplyr->pflags & PF_TAGIT)) && (leveltime > hidetime * TICRATE))
|
|
{
|
|
V_DrawCenteredString(BASEVIDWIDTH/2, STRINGY(116), 0, M_GetText("You cannot move while hiding."));
|
|
V_DrawCenteredString(BASEVIDWIDTH/2, STRINGY(132), 0, M_GetText("Press Viewpoint Key to watch a player."));
|
|
}
|
|
else if (!G_RaceGametype() && stplyr->playerstate == PST_DEAD && stplyr->lives) //Death overrides spectator text.
|
|
{
|
|
INT32 respawntime = cv_respawntime.value - stplyr->deadtimer/TICRATE;
|
|
if (respawntime > 0 && !stplyr->spectator)
|
|
V_DrawCenteredString(BASEVIDWIDTH/2, STRINGY(132), V_HUDTRANSHALF, va(M_GetText("Respawn in: %d second%s."), respawntime, respawntime == 1 ? "" : "s"));
|
|
else
|
|
V_DrawCenteredString(BASEVIDWIDTH/2, STRINGY(132), V_HUDTRANSHALF, M_GetText("Press Jump to respawn."));
|
|
}
|
|
else*/ if (stplyr->spectator
|
|
#ifdef HAVE_BLUA
|
|
&& LUA_HudEnabled(hud_textspectator)
|
|
#endif
|
|
)
|
|
{
|
|
const char *itemtxt = M_GetText("Item - Join Game");
|
|
|
|
if (stplyr->powers[pw_flashing])
|
|
itemtxt = M_GetText("Item - . . .");
|
|
else if (stplyr->pflags & PF_WANTSTOJOIN)
|
|
itemtxt = M_GetText("Item - Cancel Join");
|
|
else if (G_GametypeHasTeams())
|
|
itemtxt = M_GetText("Item - Join Team");
|
|
|
|
if (cv_ingamecap.value)
|
|
{
|
|
UINT8 numingame = 0;
|
|
UINT8 i;
|
|
|
|
for (i = 0; i < MAXPLAYERS; i++)
|
|
if (playeringame[i] && !players[i].spectator)
|
|
numingame++;
|
|
|
|
itemtxt = va("%s (%s: %d)", itemtxt, M_GetText("Slots left"), max(0, cv_ingamecap.value - numingame));
|
|
}
|
|
|
|
// SRB2kart: changed positions & text
|
|
if (splitscreen)
|
|
{
|
|
INT32 splitflags = K_calcSplitFlags(0);
|
|
V_DrawThinString(2, (BASEVIDHEIGHT/2)-20, V_YELLOWMAP|V_HUDTRANSHALF|splitflags, M_GetText("- SPECTATING -"));
|
|
V_DrawThinString(2, (BASEVIDHEIGHT/2)-10, V_HUDTRANSHALF|splitflags, itemtxt);
|
|
}
|
|
else
|
|
{
|
|
V_DrawString(2, BASEVIDHEIGHT-40, V_HUDTRANSHALF|V_YELLOWMAP, M_GetText("- SPECTATING -"));
|
|
V_DrawString(2, BASEVIDHEIGHT-30, V_HUDTRANSHALF, itemtxt);
|
|
V_DrawString(2, BASEVIDHEIGHT-20, V_HUDTRANSHALF, M_GetText("Accelerate - Float"));
|
|
V_DrawString(2, BASEVIDHEIGHT-10, V_HUDTRANSHALF, M_GetText("Brake - Sink"));
|
|
}
|
|
}
|
|
}
|
|
|
|
// Replay manual-save stuff
|
|
if (demo.recording && multiplayer && demo.savebutton && demo.savebutton + 3*TICRATE < leveltime)
|
|
{
|
|
switch (demo.savemode)
|
|
{
|
|
case DSM_NOTSAVING:
|
|
V_DrawRightAlignedThinString(BASEVIDWIDTH - 2, 2, V_HUDTRANS|V_SNAPTOTOP|V_SNAPTORIGHT|V_ALLOWLOWERCASE|(G_BattleGametype() ? V_REDMAP : V_SKYMAP), "Look Backward: Save replay");
|
|
break;
|
|
|
|
case DSM_WILLAUTOSAVE:
|
|
V_DrawRightAlignedThinString(BASEVIDWIDTH - 2, 2, V_HUDTRANS|V_SNAPTOTOP|V_SNAPTORIGHT|V_ALLOWLOWERCASE|(G_BattleGametype() ? V_REDMAP : V_SKYMAP), "Replay will be saved. (Look Backward: Change title)");
|
|
break;
|
|
|
|
case DSM_WILLSAVE:
|
|
V_DrawRightAlignedThinString(BASEVIDWIDTH - 2, 2, V_HUDTRANS|V_SNAPTOTOP|V_SNAPTORIGHT|V_ALLOWLOWERCASE|(G_BattleGametype() ? V_REDMAP : V_SKYMAP), "Replay will be saved.");
|
|
break;
|
|
|
|
case DSM_TITLEENTRY:
|
|
ST_DrawDemoTitleEntry();
|
|
break;
|
|
|
|
default: // Don't render anything
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void ST_DrawDemoTitleEntry(void)
|
|
{
|
|
static UINT8 skullAnimCounter = 0;
|
|
char *nametodraw;
|
|
|
|
skullAnimCounter++;
|
|
skullAnimCounter %= 8;
|
|
|
|
nametodraw = demo.titlename;
|
|
while (V_StringWidth(nametodraw, 0) > MAXSTRINGLENGTH*8 - 8)
|
|
nametodraw++;
|
|
|
|
#define x (BASEVIDWIDTH/2 - 139)
|
|
#define y (BASEVIDHEIGHT/2)
|
|
M_DrawTextBox(x, y + 4, MAXSTRINGLENGTH, 1);
|
|
V_DrawString(x + 8, y + 12, V_ALLOWLOWERCASE, nametodraw);
|
|
if (skullAnimCounter < 4)
|
|
V_DrawCharacter(x + 8 + V_StringWidth(nametodraw, 0), y + 12,
|
|
'_' | 0x80, false);
|
|
|
|
M_DrawTextBox(x + 30, y - 24, 26, 1);
|
|
V_DrawString(x + 38, y - 16, V_ALLOWLOWERCASE, "Enter the name of the replay.");
|
|
|
|
M_DrawTextBox(x + 50, y + 20, 20, 1);
|
|
V_DrawThinString(x + 58, y + 28, V_ALLOWLOWERCASE, "Escape - Cancel");
|
|
V_DrawRightAlignedThinString(x + 220, y + 28, V_ALLOWLOWERCASE, "Enter - Confirm");
|
|
#undef x
|
|
#undef y
|
|
}
|
|
|
|
// MayonakaStatic: draw Midnight Channel's TV-like borders
|
|
static void ST_MayonakaStatic(void)
|
|
{
|
|
INT32 flag = (leveltime%2) ? V_90TRANS : V_70TRANS;
|
|
|
|
V_DrawFixedPatch(0, 0, FRACUNIT, V_SNAPTOTOP|V_SNAPTOLEFT|flag, hud_tv1, NULL);
|
|
V_DrawFixedPatch(320<<FRACBITS, 0, FRACUNIT, V_SNAPTOTOP|V_SNAPTORIGHT|V_FLIP|flag, hud_tv1, NULL);
|
|
V_DrawFixedPatch(0, 142<<FRACBITS, FRACUNIT, V_SNAPTOBOTTOM|V_SNAPTOLEFT|flag, hud_tv2, NULL);
|
|
V_DrawFixedPatch(320<<FRACBITS, 142<<FRACBITS, FRACUNIT, V_SNAPTOBOTTOM|V_SNAPTORIGHT|V_FLIP|flag, hud_tv2, NULL);
|
|
}
|
|
|
|
#ifdef HAVE_DISCORDRPC
|
|
void ST_AskToJoinEnvelope(void)
|
|
{
|
|
const tic_t freq = TICRATE/2;
|
|
|
|
if (menuactive)
|
|
return;
|
|
|
|
if ((leveltime % freq) < freq/2)
|
|
return;
|
|
|
|
V_DrawFixedPatch(296*FRACUNIT, 2*FRACUNIT, FRACUNIT, V_SNAPTOTOP|V_SNAPTORIGHT, envelope, NULL);
|
|
// maybe draw number of requests with V_DrawPingNum ?
|
|
}
|
|
#endif
|
|
|
|
void ST_Drawer(void)
|
|
{
|
|
UINT8 i;
|
|
|
|
#ifdef SEENAMES
|
|
if (cv_seenames.value && cv_allowseenames.value && displayplayers[0] == consoleplayer && seenplayer && seenplayer->mo && !mapreset)
|
|
{
|
|
if (cv_seenames.value == 1)
|
|
V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT/2 + 15, V_HUDTRANSHALF, player_names[seenplayer-players]);
|
|
else if (cv_seenames.value == 2)
|
|
V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT/2 + 15, V_HUDTRANSHALF,
|
|
va("%s%s", G_GametypeHasTeams() ? ((seenplayer->ctfteam == 1) ? "\x85" : "\x84") : "", player_names[seenplayer-players]));
|
|
else //if (cv_seenames.value == 3)
|
|
V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT/2 + 15, V_HUDTRANSHALF,
|
|
va("%s%s", !G_BattleGametype() || (G_GametypeHasTeams() && players[consoleplayer].ctfteam == seenplayer->ctfteam)
|
|
? "\x83" : "\x85", player_names[seenplayer-players]));
|
|
}
|
|
#endif
|
|
|
|
// Doom's status bar only updated if necessary.
|
|
// However, ours updates every frame regardless, so the "refresh" param was removed
|
|
//(void)refresh;
|
|
|
|
// force a set of the palette by using doPaletteStuff()
|
|
if (vid.recalc)
|
|
st_palette = -1;
|
|
|
|
// Do red-/gold-shifts from damage/items
|
|
#ifdef HWRENDER
|
|
//25/08/99: Hurdler: palette changes is done for all players,
|
|
// not only player1! That's why this part
|
|
// of code is moved somewhere else.
|
|
if (rendermode == render_soft)
|
|
#endif
|
|
if (rendermode != render_none) ST_doPaletteStuff();
|
|
|
|
if (st_overlay)
|
|
{
|
|
// No deadview!
|
|
for (i = 0; i <= splitscreen; i++)
|
|
{
|
|
stplyr = &players[displayplayers[i]];
|
|
ST_overlayDrawer();
|
|
}
|
|
|
|
// draw Midnight Channel's overlay ontop
|
|
if (mapheaderinfo[gamemap-1]->typeoflevel & TOL_TV) // Very specific Midnight Channel stuff.
|
|
ST_MayonakaStatic();
|
|
}
|
|
|
|
// Draw a white fade on level opening
|
|
if (timeinmap < 15)
|
|
{
|
|
if (timeinmap <= 5)
|
|
V_DrawFill(0,0,BASEVIDWIDTH,BASEVIDHEIGHT,120); // Pure white on first few frames, to hide SRB2's awful level load artifacts
|
|
else
|
|
V_DrawFadeScreen(120, 15-timeinmap); // Then gradually fade out from there
|
|
}
|
|
ST_drawDebugInfo();
|
|
}
|