djcev.com

//

Git Repos / fte_dogmode / qc / cl_hud.qc

Last update to this file was on 2024-03-24 at 02:40.

Show cl_hud.qc

//==============================================================================
// CSQC_HUDVANILLA
//==============================================================================

/*======================================================================
All CSQC functions (Vanilla ONLY version)

* This file is heavily influenced by QSS devkit (credit=spike)
* re-written some functions to make better sense to me
* Contains all HUD elements for full quake interface (SP/Coop/Dm)
* Sripped out the experimental stuff included in devkit
* Converted most of the hardcoded values into constants
* Added loads of extra comments to show what is going on

======================================================================*/

//======================================================================
// constants
//======================================================================

// Default sizes for HUD elements
const vector HUDSIZE_320 = '320 24 0'; // Background images
const vector HUDSIZE_24 = '24 24 0'; // Status Bar
const vector HUDSIZE_16 = '16 16 0'; // Inventory/Powerups
const vector HUDSIZE_816 = '8 16 0'; // Runes
const vector HUDSIZE_8 = '8 8 0'; // Ammo numbers
const vector HUDSIZE_C8 = '8 0 0'; // Character sizes

// 8 pixel font table (index positions)
const float HUDFONT_WHITE = 0; // Default index = 48-57
const float HUDFONT_YELLOW = 1; // index = index - 30
const float HUDFONT_RED = 2; // index = index + 128

// Default sizes for weapons
const vector HUDWPN_48 = '48 16 0'; // Vanilla LG
const vector HUDWPN_32 = '32 16 0'; // AD/Hipnotic LG
const vector HUDWPN_24 = '24 16 0'; // Default

const vector HUDRGB_DEF = '1 1 1';

//----------------------------------------------------------------------
// All weapon HUD graphics are prefixed with certain characters which
// means all weapon filenames can be generated with string commands
// CSQC is really an advanced (QSS/FTE/DP) engine only thing and its
// very likely that FTE_STRINGS is supported for string manipulation
//----------------------------------------------------------------------
// Special constants for weapons
const float WPN_ICONS = 7; // weapons precache pics + flash timers
const float WPN_WIDTHLG = 6; // Odd weapon gfx width (48)

// Statue, Inventory and Score bars (All 320 x 24)
const string backgrd[3] = { "gfx/sbar", "gfx/ibar", "gfx/scorebar" };

// Ranking (168 x 24), Complete (184 x 24), Inter (160 x 144)
// Require .lmp extensions if not loaded diectly from GFX file
const string backlmp[3] =
{
"gfx/ranking.lmp", "gfx/complete.lmp", "gfx/inter.lmp"
};

// Regular (24x24) brown numbers
const string number[10] =
{
"gfx/num_0", "gfx/num_1", "gfx/num_2", "gfx/num_3", "gfx/num_4",
"gfx/num_5", "gfx/num_6", "gfx/num_7", "gfx/num_8", "gfx/num_9"
};

// Red (24x24) numbers for no armour, low HP (<25) and no ammo
const string anumber[10] =
{
"gfx/anum_0", "gfx/anum_1", "gfx/anum_2", "gfx/anum_3", "gfx/anum_4",
"gfx/anum_5", "gfx/anum_6", "gfx/anum_7", "gfx/anum_8", "gfx/anum_9"
};

// Regular (24x24) characters for intermission
const string extrachar[3] =
{
"gfx/num_colon", "gfx/num_minus", "gfx/num_slash"
};

// 24x24 pixel icons for Status Bar
const string sbitems[8] =
{
"gfx/sb_shells", "gfx/sb_nails", "gfx/sb_rocket", "gfx/sb_cells",
"gfx/sb_armor1", "gfx/sb_armor2", "gfx/sb_armor3", "gfx/disc"
};

// 16x16 pixel icons for Information Bar
const string ibitems[6] =
{
"gfx/sb_key1", "gfx/sb_key2", "gfx/sb_invis", "gfx/sb_invuln",
"gfx/sb_suit", "gfx/sb_quad"
};

// 8x16 pixel runes for Information Bar
const string ibrunes[4] =
{
"gfx/sb_sigil1", "gfx/sb_sigil2", "gfx/sb_sigil3", "gfx/sb_sigil4"
};

// Shotgun, SuperShotgun, Nailgun, SuperNailGun, GrenadeLauncher
// RocketLauncher, LightningGun
const string wpnnames[7] =
{
"shotgun", "sshotgun", "nailgun", "snailgun", "rlaunch",
"srlaunch", "lightng"
};

// OFF / ON gfx (reflects active weapon)
const string wpnselect[2] = { "gfx/inv_", "gfx/inv2_" };

// Special flash set for when the player gets weapon
const string wpnflash[5] =
{
"gfx/inva1_","gfx/inva2_","gfx/inva3_","gfx/inva4_","gfx/inva5_"
};

// Frame 00-04 : Regular HP 100/80/60/40/20
// Frame 05-09 : InPain HP 100/80/60/40/20
// Frame 10 : Invisibility Ring + Pentagram!
// Frame 11 : Quad Damage
// Frame 12 : Invisibility Ring
// Frame 13 : Pentagram (invulnerability)
const string facetab[14] =
{
"gfx/face5", "gfx/face4", "gfx/face3", "gfx/face2", "gfx/face1",
"gfx/face_p5", "gfx/face_p4", "gfx/face_p3", "gfx/face_p2",
"gfx/face_p1",
"gfx/face_inv2", "gfx/face_quad", "gfx/face_invis", "gfx/face_invul2"
};

//======================================================================
// globals
//======================================================================

float baralpha; // Read scr_sbaralpha variable
float hudalpha; // All gfx on hud bars
float flashtime[7]; // record when weapons have been added

//======================================================================
// forward declarations
//======================================================================

void(vector pos, float value, float threshhold) Hud_DrawNoFont24;
void(vector pos, string num) Hud_DrawCharFont24;
void(vector pos, float value, float digit, float zerofill, float fontcol)
Hud_DrawNoFont8;
void(vector pos) Hud_DrawFace;
static void(float num, vector pos) Hud_DrawWeapon;
void (vector pos, vector virtsize) Hud_DrawSBar;
void (vector pos, vector br) Hud_DrawIBar;
void(vector pos, float bx, float by, float bwidth, float bheight,
float pixelspeed, string draw_str) Hud_ScrollTextBox;
void(vector pos) Hud_QSScores_SBar;
void(vector pos) Hud_IDScores_SBar;
vector(string picname, float height) Hud_AspectSize;
void(string picname, float scrwidth, vector pos, float height) Hud_CentrePic;
void(vector virtmin, vector virtsize) Hud_DMScoreboard;
void(vector virtmin, vector virtsize) Hud_Intermission;
void(vector pos) Hud_InputMonitor;
void(vector pos) Hud_Speedometer;
void(vector virtsize, float showscores) CSQC_DrawHud;
void(vector virtsize, float showscores) CSQC_DrawScores;

//------------------------------------------------------------------------------

//----------------------------------------------------------------------
// Display 24pixel numbers to HUD (cope with red version)
//----------------------------------------------------------------------
void(vector pos, float value, float threshhold) Hud_DrawNoFont24 =
{
local string val_str, disp_str;
local float disp_col, disp_len, disp_no;

// Make sure value is within range
if (value < 0)
value = 0;
else if (value > 999)
value = 999;

disp_col = FALSE;

// Round number down (floor) and work out length
val_str = ftos (floor(value));
disp_len = strlen (val_str);
// Move to the lowest digit position first
pos_x = pos_x + (3 * HUDSIZE_24_x);

// Work out which number colour to use
if (value <= threshhold)
disp_col = TRUE;

while (disp_len > 0)
{
// Countdown early (range is 0-2, strlen returns 1-3)
disp_len = disp_len - 1;

// Move backward to display a digit
pos_x = pos_x - HUDSIZE_24_x;

// Convert str character to font index numbers
disp_no = (str2chr (val_str, disp_len) - '0');

// Double check for any wierd range issues
if (disp_no < 0 || disp_no > 9)
disp_no = 0;

// Work out which number colour to use
if (disp_col)
disp_str = anumber[disp_no];
else
disp_str = number[disp_no];

// Draw number in correct (right-justified) position
drawpic (pos, disp_str, HUDSIZE_24, HUDRGB_DEF, hudalpha, 0);
}
};

//----------------------------------------------------------------------
// Display 24pixel characters to HUD (limited chars available)
//----------------------------------------------------------------------
void(vector pos, string num) Hud_DrawCharFont24 =
{
float i, c;
// Endless loop until end of string
// Keep moving draw pos forward (pos_x)
for (i = 0; ; i++, pos_x += HUDSIZE_24_x)
{
// Read next character from string
c = str2chr (num, i);
// End of string found?
if (!c)
break;
// Check for special characters
else if (c == ':' || c == '.')
drawpic (pos, extrachar[0], HUDSIZE_24, HUDRGB_DEF,
hudalpha, 0);
else if (c == '-')
drawpic (pos, extrachar[1], HUDSIZE_24, HUDRGB_DEF,
hudalpha, 0);
else if (c == '/')
drawpic (pos, extrachar[2], HUDSIZE_24, HUDRGB_DEF,
hudalpha, 0);
// Draw rest of the numbers
else if (c >= '0' && c <= '9')
{
// Sanity check, make sure within range of array
c = c - 48;
if (c < 0 || c > 9) c = 0;
drawpic (pos, number[c], HUDSIZE_24, HUDRGB_DEF,
hudalpha, 0);
}
}
};

//----------------------------------------------------------------------
// Draws small 8 pixel numbers to HUD (white/yellow/red text options)
//----------------------------------------------------------------------
void(vector pos, float value, float digit, float zerofill, float fontcol)
Hud_DrawNoFont8 =
{
local string val_str;
local float disp_len, disp_no;

// Make sure value is within range
if (value < 0)
value = 0;
// Check max range against max digits
else if (value > 999 && digit >= 3)
value = 999;
else if (value > 99 && digit == 2)
value = 99;
else if (value > 9 && digit <= 1)
value = 9;

// Round number down (floor) and work out length
val_str = ftos (floor(value));
disp_len = strlen (val_str);

// Zero fill number?
if (zerofill)
{
while (disp_len < digit)
{
// Keep adding more zero's
val_str = strcat ("0", val_str);
// Exit condition?
disp_len = strlen (val_str);
}
}

// Move to the lowest digit position first
pos_x = pos_x + (digit * HUDSIZE_8_x);

while (disp_len > 0)
{
// Countdown first (digit positions = 0-2)
disp_len = disp_len - 1;
// Move backward to display a digit
pos_x = pos_x - HUDSIZE_8_x;
// Convert character to number (font table index 48-57)
disp_no = str2chr (val_str, disp_len);
if (fontcol == HUDFONT_YELLOW)
disp_no = disp_no - 30;
else if (fontcol == HUDFONT_RED)
disp_no = disp_no + 128;
// Draw character from ascii font table (right-justified)
drawcharacter (pos, disp_no, HUDSIZE_8, HUDRGB_DEF,
hudalpha, 0);
}
};

//----------------------------------------------------------------------
// Change HUD face to reflect Health, Pain or Powerups
//----------------------------------------------------------------------
void(vector pos) Hud_DrawFace =
{
string face;
local float hpframe;

// Start with InvRing as it has two states
if (sitems & IT_INVISIBILITY)
{
if (sitems & IT_INVULNERABILITY)
// InvRing + Pentagram!?! WTF!?! SandyP E4 design!
face = facetab[10];
else
// Just InvRing only
face = facetab[12];
}
else if (sitems & IT_QUAD)
{
// Quad only
face = facetab[11];
}
else if (sitems & IT_INVULNERABILITY)
{
// Pentagram only
face = facetab[13];
}
else
{
// Regular face
// Work out face based on HP (100/80/60/40/20)
hpframe = floor (shealth / 20);

// Check for negative and upper (MegaHP) limits
if (hpframe < 0)
hpframe = 0;
else if (hpframe > 4)
hpframe = 4;

// Check for any pain/flinch updates
if (painfinishtime > time)
hpframe = hpframe + 5;

// Final HP face
face = facetab[hpframe];
}

// Draw face - always 24x24 size, full rgb/alpha
drawpic (pos, face, HUDSIZE_24, HUDRGB_DEF, hudalpha, 0);
};

//----------------------------------------------------------------------
// Update a weapon icon with selection or flash features
//----------------------------------------------------------------------
static void(float num, vector pos) Hud_DrawWeapon =
{
local string prefix, file_str;
local vector gfx_size;
local float flash;

// The weapon flash is done every 0.1s and repeated twice!
// When the player gets a new weapon the time is reset
// This function will count the time difference for flashing
// Convert the flash time to a 0-10+ range
flash = (time - flashtime[num]) * 10;

// Has the flash happened twice? (finished)
if (flash >= 10)
{
// Work out if this weapon is currently selected
if (sweapon == (1 << num))
prefix = wpnselect[1];
// Default is no highlight
else
prefix = wpnselect[0];
}
else
{
// Flashing!
// Is the flash into second phase?
if (flash < 0)
flash = 0;
else if (flash >= 5)
flash = flash - 5;

// flash is only 0-4 frames
prefix = wpnflash[flash];
}

// Merge prefix type (defined above) to weapon filename
// Without string (str) functions this would involve a giant table
// This sorta assumes that CSQC is running on an advanced engine
// QSS/FTE/DP all support FTE_STRINGS extra str functions
file_str = strcat (prefix, wpnnames[num]);

// Most weapons are 24 pixels wide (half of ammo above)
// As always there is an exception (lightning gun)
if (num == WPN_WIDTHLG)
gfx_size = HUDWPN_48;
else
gfx_size = HUDWPN_24;

// Show weapon GFX (active/deactive/flashing)
drawpic (pos, file_str, gfx_size, HUDRGB_DEF, hudalpha, 0);
};

//----------------------------------------------------------------------
// STATUS BAR ( Armour / Health quantities and current Ammo selected)
//----------------------------------------------------------------------
void (vector pos, vector virtsize) Hud_DrawSBar =
{
// Draw primary HUD bar (Armour/Face/Health/Ammo)
drawpic (pos, backgrd[0], HUDSIZE_320, HUDRGB_DEF, baralpha, 0);

// Deal with Pentagram first, its a simple test/update
if (sitems & IT_INVULNERABILITY)
{
// Make sure 666 is in 24 pixel giant red numbers!
Hud_DrawNoFont24 (pos + [24, 0], 666, 666);
// Draw a pentagram symbol in the armour HUD slot
drawpic (pos, sbitems[7], HUDSIZE_24, HUDRGB_DEF, hudalpha, 0);
}
else
{
// Show armour type/quantity active
Hud_DrawNoFont24 (pos + '24 0 0', getstatf(STAT_ARMOR), 25);
// Only 3 armour types (green/yellow/red)
if (sitems & IT_ARMOR1)
drawpic (pos, sbitems[4], HUDSIZE_24, HUDRGB_DEF,
hudalpha, 0);
else if (sitems & IT_ARMOR2)
drawpic (pos, sbitems[5], HUDSIZE_24, HUDRGB_DEF,
hudalpha, 0);
else if (sitems & IT_ARMOR3)
drawpic (pos, sbitems[6], HUDSIZE_24, HUDRGB_DEF,
hudalpha, 0);
}

// Draw face + HP value
Hud_DrawFace (pos + [112, 0]);
Hud_DrawNoFont24 (pos + [136, 0], shealth, 25);

// Only update ammo type/quantity if not using axe!
if (sweapon != IT_AXE)
{
Hud_DrawNoFont24 (pos + [248, 0], getstatf(STAT_AMMO), 10);
if (sitems & IT_SHELLS)
drawpic (pos + [224, 0], sbitems[0], HUDSIZE_24,
HUDRGB_DEF, hudalpha, 0);
else if (sitems & IT_NAILS)
drawpic (pos + [224, 0], sbitems[1], HUDSIZE_24,
HUDRGB_DEF, hudalpha, 0);
else if (sitems & IT_ROCKETS)
drawpic (pos + [224, 0], sbitems[2], HUDSIZE_24,
HUDRGB_DEF, hudalpha, 0);
else if (sitems & IT_CELLS)
drawpic (pos + [224, 0], sbitems[3], HUDSIZE_24,
HUDRGB_DEF, hudalpha, 0);
}
};

//----------------------------------------------------------------------
// INVENTORY BAR ( Ammo quantities, keys/runes and powerups )
//----------------------------------------------------------------------
void (vector pos, vector br) Hud_DrawIBar =
{
local vector topcol, botcol;
local string player_frags;

// Draw background bar using scr_sbaralpha default
drawpic (pos, backgrd[1], HUDSIZE_320, HUDRGB_DEF, baralpha, 0);

// Always draw ammo scores
Hud_DrawNoFont8 (pos + [10, 0], getstatf(STAT_SHELLS), 3,
FALSE, HUDFONT_YELLOW);
Hud_DrawNoFont8 (pos + [58, 0], getstatf(STAT_NAILS), 3,
FALSE, HUDFONT_YELLOW);
Hud_DrawNoFont8 (pos + [106, 0], getstatf(STAT_ROCKETS), 3,
FALSE, HUDFONT_YELLOW);
Hud_DrawNoFont8 (pos + [154, 0], getstatf(STAT_CELLS), 3,
FALSE, HUDFONT_YELLOW);

// Draw weapons and highlight current one
if (sitems & IT_SHOTGUN)
Hud_DrawWeapon (0, pos + [24 * 0, 8]);
if (sitems & IT_SUPER_SHOTGUN)
Hud_DrawWeapon (1, pos + [24 * 1, 8]);
if (sitems & IT_NAILGUN)
Hud_DrawWeapon (2, pos + [24 * 2, 8]);
if (sitems & IT_SUPER_NAILGUN)
Hud_DrawWeapon (3, pos + [24 * 3, 8]);
if (sitems & IT_GRENADE_LAUNCHER)
Hud_DrawWeapon (4, pos + [24 * 4, 8]);
if (sitems & IT_ROCKET_LAUNCHER)
Hud_DrawWeapon (5, pos + [24 * 5, 8]);
if (sitems & IT_LIGHTNING)
Hud_DrawWeapon (6, pos + [24 * 6, 8]);

// Draw inventory items
if (sitems & IT_KEY1)
drawpic (pos + [192, 8], ibitems[0], HUDSIZE_16, HUDRGB_DEF,
hudalpha, 0);
if (sitems & IT_KEY2)
drawpic (pos + [208, 8], ibitems[1], HUDSIZE_16, HUDRGB_DEF,
hudalpha, 0);
if (sitems & IT_INVISIBILITY)
drawpic (pos + [224, 8], ibitems[2], HUDSIZE_16, HUDRGB_DEF,
hudalpha, 0);
if (sitems & IT_INVULNERABILITY)
drawpic (pos + [240, 8], ibitems[3], HUDSIZE_16, HUDRGB_DEF,
hudalpha, 0);
if (sitems & IT_SUIT)
drawpic (pos + [256, 8], ibitems[4], HUDSIZE_16, HUDRGB_DEF,
hudalpha, 0);
if (sitems & IT_QUAD)
drawpic (pos + [272, 8], ibitems[5], HUDSIZE_16, HUDRGB_DEF,
hudalpha, 0);

// Draw Runes (special size + location)
if (sitems2 & SERVERFLAGS_RUNE1)
drawpic (pos + [288, 8], ibrunes[0], HUDSIZE_816, HUDRGB_DEF,
hudalpha, 0);
if (sitems2 & SERVERFLAGS_RUNE2)
drawpic (pos + [296, 8], ibrunes[1], HUDSIZE_816, HUDRGB_DEF,
hudalpha, 0);
if (sitems2 & SERVERFLAGS_RUNE3)
drawpic (pos + [304, 8], ibrunes[2], HUDSIZE_816, HUDRGB_DEF,
hudalpha, 0);
if (sitems2 & SERVERFLAGS_RUNE4)
drawpic (pos + [312, 8], ibrunes[3], HUDSIZE_816, HUDRGB_DEF,
hudalpha, 0);

//should probably show team scores, but this mimics vanilla
if (deathmatch)
{
// Move to space above powerups
pos_x += 194;

// Loop through 4 players
for (float i = -1; i >= -4; i--)
{
// Read frag score of next player
player_frags = getplayerkeyvalue (i, "frags");

// No frags? stop loop
if (player_frags == "")
break;

// Read deathmatch player top/bottom skin colours
topcol = stov (getplayerkeyvalue(i, "topcolor_rgb"));
botcol = stov (getplayerkeyvalue(i, "bottomcolor_rgb"));

// Draw skin colours (alpha was 0.75 hardcoded)
drawfill (pos + [0, 1], [28, 3], topcol, 0.75, 0);
drawfill (pos + [0, 4], [28, 4], botcol, 0.75, 0);

// Draw frag score (New global small font function)
Hud_DrawNoFont8 (pos + '2 0 0', stof(player_frags), 3,
FALSE, HUDFONT_WHITE);

// Find player entity attached to this HUD
if (player_localentnum == stof(getplayerkeyvalue(i,
"viewentity")))
{
// special characters = []
drawcharacter (pos + [-4, 0], 0xe010,
HUDSIZE_8, HUDRGB_DEF, hudalpha, 0);
drawcharacter (pos + [24, 0], 0xe011,
HUDSIZE_8, HUDRGB_DEF, hudalpha, 0);
}

// Move forward to next hud space
pos_x += 8 * 4;
}
}
};

//----------------------------------------------------------------------
// Scoreboard Bar (shows monster/secret quantities and map info)
//----------------------------------------------------------------------
void(vector pos, float bx, float by, float bwidth, float bheight,
float pixelspeed, string draw_str) Hud_ScrollTextBox =
{
local float str_width, str_double, str_speed;
local string wide_str;

// draw debug visual box to show area on screen
//drawfill (pos + [bx, by], [bwidth, bheight], HUDRGB_DEF, 0.1, 0);

// Find out width of string in pixels (using font 8)
str_width = stringwidth (draw_str, TRUE, HUDSIZE_8);

// String less than window width?
if (str_width < bwidth)
{
// Center the map name string in the box area
str_double = (bwidth - str_width) / 2;

// Display string normally (no scrolling required)
drawstring (pos + [bx + str_double, by], draw_str, HUDSIZE_8,
HUDRGB_DEF, hudalpha, 0);
}
else
{
// Create double length string with boundary marker
wide_str = strcat (draw_str, " /// ", draw_str);

// Setup clip (scissor) area for exclusive drawing
drawsetcliparea (pos_x + bx, pos_y + by, bwidth, bheight);
str_double = stringwidth (wide_str, TRUE, HUDSIZE_8);

// create offset of string to make it look like its scrolling
str_speed = mod (cltime * pixelspeed, (str_double - str_width));

// draw string (with offset) inside of clip (scissor) area only
drawstring (pos + [bx - str_speed, by], wide_str, HUDSIZE_8,
HUDRGB_DEF, hudalpha, 0);

// Reset clip string area to default
drawresetcliparea ();
}
};

//----------------------------------------------------------------------
// Quakespasm scoreboard layout (no time)
//----------------------------------------------------------------------
void(vector pos) Hud_QSScores_SBar =
{
local string skill_str, map_str;
local float digit;

// Clear status bar ready for map info/scores
drawpic (pos, backgrd[2], HUDSIZE_320, HUDRGB_DEF, baralpha, 0);

// Display headings
drawstring (pos + [8, 12], "Kills:", HUDSIZE_8, HUDRGB_DEF,
hudalpha, 0);
drawstring (pos + [80, 12], "/", HUDSIZE_8, HUDRGB_DEF,
hudalpha, 0);
drawstring (pos + [132, 12], "Skill ", HUDSIZE_8, HUDRGB_DEF,
hudalpha, 0);
drawstring (pos + [208, 12], "Secrets:", HUDSIZE_8, HUDRGB_DEF,
hudalpha, 0);
drawstring (pos + [288, 12], "/", HUDSIZE_8, HUDRGB_DEF,
hudalpha, 0);

// Display monster/secret totals
Hud_DrawNoFont8 (pos + [56, 12], getstatf(STAT_KILLEDMONSTERS), 3,
FALSE, HUDFONT_WHITE);
if (getstatf(STAT_TOTALMONSTERS) < 100)
digit = 2;
else
digit = 3;
Hud_DrawNoFont8 (pos + [88, 12], getstatf(STAT_TOTALMONSTERS), digit,
FALSE, HUDFONT_WHITE);
Hud_DrawNoFont8 (pos + [272, 12], getstatf(STAT_FOUNDSECRETS), 2,
FALSE, HUDFONT_WHITE);
Hud_DrawNoFont8 (pos + [296, 12], getstatf(STAT_TOTALSECRETS), 2,
FALSE, HUDFONT_WHITE);

// Display map skill level
skill_str = autocvar (skill, "1");
drawstring (pos + [180, 12], skill_str, HUDSIZE_8, HUDRGB_DEF,
hudalpha, 0);

// Level designers Map name + File name
map_str = strcat (world.message, " (", mapname, ")");
Hud_ScrollTextBox (pos, 8, 4, 304, 8, 16, map_str);
};

//----------------------------------------------------------------------
// The original ID scoreboard layout (no skill, map filename)
//----------------------------------------------------------------------
void(vector pos) Hud_IDScores_SBar =
{
local float nsecs, nmins;

// Clear status bar ready for map info/scores
drawpic (pos, backgrd[2], HUDSIZE_320, HUDRGB_DEF, baralpha, 0);
// Display headings
drawstring (pos+[8,4], "Monsters:", HUDSIZE_8, HUDRGB_DEF, hudalpha, 0);
drawstring (pos+[104,4], "/", HUDSIZE_8, HUDRGB_DEF, hudalpha, 0);
drawstring (pos+[8,12], "Secrets :", HUDSIZE_8, HUDRGB_DEF, hudalpha,0);
drawstring (pos+[104,12], "/", HUDSIZE_8, HUDRGB_DEF, hudalpha, 0);
drawstring (pos+[184,4], "Time :", HUDSIZE_8, HUDRGB_DEF, hudalpha, 0);
drawstring (pos+[256,4], ":", HUDSIZE_8, HUDRGB_DEF, hudalpha, 0);
// Display monster/secret totals
Hud_DrawNoFont8 (pos + [80, 4], getstatf(STAT_KILLEDMONSTERS), 3,
FALSE, HUDFONT_WHITE);
Hud_DrawNoFont8 (pos + [112, 4], getstatf(STAT_TOTALMONSTERS), 3,
FALSE, HUDFONT_WHITE);
Hud_DrawNoFont8 (pos + [80, 12], getstatf(STAT_FOUNDSECRETS), 3,
FALSE, HUDFONT_WHITE);
Hud_DrawNoFont8 (pos + [112, 12], getstatf(STAT_TOTALSECRETS), 3,
FALSE, HUDFONT_WHITE);
// Work out time passed
nmins = floor (time / 60);
nsecs = floor (time - nmins * 60);
Hud_DrawNoFont8 (pos + [232, 4], nmins, 3, FALSE, HUDFONT_WHITE);
Hud_DrawNoFont8 (pos + [264, 4], nsecs, 2, TRUE, HUDFONT_WHITE);
// Level designers Map name
Hud_ScrollTextBox (pos, 140, 12, 176, 8, 16, world.message);
};

//----------------------------------------------------------------------
// Deathmatch scoreboard
//----------------------------------------------------------------------
vector(string picname, float height) Hud_AspectSize =
{
local vector sz;
sz = drawgetimagesize (picname);
return [sz_x * height / sz_y, height];
};

//----------------------------------------------------------------------
void(string picname, float scrwidth, vector pos, float height) Hud_CentrePic =
{
local vector sz;
sz = Hud_AspectSize (picname, height);
pos_x += (scrwidth - sz_x) / 2;
drawpic (pos, picname, sz, HUDRGB_DEF, hudalpha, 0);
};

//----------------------------------------------------------------------
void(vector virtmin, vector virtsize) Hud_DMScoreboard =
{
local float isspec;
local vector pos, topcol, botcol;
string player_name, player_frags, player_ping;

// Working copy
pos = virtmin;

// Check for 16 players?
player_name = getplayerkeyvalue (-16, "name");
if (player_name == "")
pos_y += (virtsize_y - 200) / 2;

// Only draw the header when its not a really big game
player_name = getplayerkeyvalue (-24, "name");
if (player_name == "")
{
pos_y += 8;
// Display header (ranking.lmp) gfx for DM scoreboard
Hud_CentrePic (backlmp[0], virtsize_x, pos, 24);
// A double update of Y, only spike knows why!?!
pos_y += 24;
pos_y += 10;
}

// Another double X update, no idea why!
pos_x += (virtsize_x - 320) / 2;
pos_x += 80;

// negative numbers are players sorted by frags.
for (float i = -1; ; i--, pos_y += 10)
{
// Check for next player name
player_name = getplayerkeyvalue (i, "name");
// No more in list, end loop
if (player_name == "")
break;

// Read player stats (frag/ping)
isspec = stof (getplayerkeyvalue(i, "*spectator"));
player_frags = getplayerkeyvalue (i, "frags");
player_ping = getplayerkeyvalue (i, "ping");
// Read deathmatch player top/bottom skin colours
topcol = stov (getplayerkeyvalue(i, "topcolor_rgb"));
botcol = stov (getplayerkeyvalue(i, "bottomcolor_rgb"));

// Re-format the player name (no case conversion, force red)
player_name = strconv (0,2,2, player_name);
// Draw frag score (New global small font function)
Hud_DrawNoFont8 (pos - [8 * 5, 0], stof(player_ping), 3,
FALSE, HUDFONT_WHITE);

// Which type of player? Spectator or Active?
if (isspec)
{
drawstring (pos + [4, 0], "spec", [8, 8],
HUDRGB_DEF, hudalpha, 0);
}
else
{
// Draw skin colours (alpha was 0.75 hardcoded)
drawfill (pos + [0, 0], [40, 4], topcol, 0.75, 0);
drawfill (pos + [0, 4], [40, 4], botcol, 0.75, 0);

// Draw frag score (New global small font function)
Hud_DrawNoFont8 (pos + [8, 0], stof(player_frags), 3,
FALSE, HUDFONT_WHITE);
// Find player entity attached to this HUD
if (player_localentnum == stof(getplayerkeyvalue(i,
"viewentity")))
{
// special characters = []
drawcharacter (pos + [0, 0], 0xe010,
HUDSIZE_8, HUDRGB_DEF, hudalpha, 0);
drawcharacter (pos + [32, 0], 0xe011,
HUDSIZE_8, HUDRGB_DEF, hudalpha, 0);
}
}
// Finally draw player name
drawstring (pos + [64, 0], player_name, HUDSIZE_8,
HUDRGB_DEF, hudalpha, 0);
}
};

//----------------------------------------------------------------------
// Final Intermission
//----------------------------------------------------------------------
void(vector virtmin, vector virtsize) Hud_Intermission =
{
local vector pos;
// Create positions based on virtual screen
pos = virtmin + (virtsize - [320, 200]) / 2;

// Draw Intermission title and table info (Time/secret/kill)
Hud_CentrePic (backlmp[1], 320, pos + [0, 24], 24);
drawpic (pos + [0,56], backlmp[2], [160,144], HUDRGB_DEF, hudalpha, 0);

// Generate complete string and then draw 1 character at time
// Uses Sprintf function to feed values into final string
// This function should be supported by Advanced engines
Hud_DrawCharFont24 (pos + [144, 64], sprintf("%3.0f:%02.0f",
intermission_time / 60, intermission_time % 60));
Hud_DrawCharFont24 (pos + [144, 104],
sprintf ("%3.0f/%.0f",
getstatf (STAT_FOUNDSECRETS),
getstatf (STAT_TOTALSECRETS)
)
);
Hud_DrawCharFont24 (pos + [144, 144],
sprintf ("%3.0f/%.0f",
getstatf (STAT_KILLEDMONSTERS),
getstatf (STAT_TOTALMONSTERS)
)
);
};


//----------------------------------------------------------------------
// Input Monitor -- CEV
//----------------------------------------------------------------------
void(vector pos) Hud_InputMonitor =
{
if (input_movevalues_x)
if (input_movevalues_x < 0)
// backward
drawcharacter ([pos_x, pos_y, pos_z],
str2chr ("-", 0),
HUDSIZE_8, HUDRGB_DEF, hudalpha, 0);
else if (input_movevalues_x > 0)
// forward
drawcharacter ([pos_x, pos_y - 8, pos_z],
str2chr ("^", 0),
HUDSIZE_8, HUDRGB_DEF, hudalpha, 0);

if (input_movevalues_y)
if (input_movevalues_y < 0)
// left
drawcharacter ([pos_x - 12, pos_y, pos_z],
str2chr ("<", 0),
HUDSIZE_8, HUDRGB_DEF, hudalpha, 0);
else if (input_movevalues_y > 0)
// right
drawcharacter ([pos_x + 12, pos_y, pos_z],
str2chr (">", 0),
HUDSIZE_8, HUDRGB_DEF, hudalpha, 0);

if (input_movevalues_z)
if (input_movevalues_z < 0)
// down
drawcharacter ([pos_x - 38, pos_y, pos_z],
str2chr ("#", 0),
HUDSIZE_8, HUDRGB_DEF, hudalpha, 0);
else if (input_movevalues_z > 0)
// up
drawcharacter ([pos_x - 24, pos_y, pos_z],
str2chr ("^", 0),
HUDSIZE_8, HUDRGB_DEF, hudalpha, 0);

if (input_buttons & 0x00000002)
// INPUT_BUTTON2 jumping
drawcharacter ([pos_x - 24, pos_y, pos_z], str2chr ("^", 0),
HUDSIZE_8, HUDRGB_DEF, hudalpha, 0);
};

//----------------------------------------------------------------------
// Speedometer -- CEV
//----------------------------------------------------------------------
void(vector pos) Hud_Speedometer =
{
// fancy -- CEV
local vector v = [player_local.velocity_x, player_local.velocity_y, 0];

Hud_DrawNoFont8 (pos, ceil(vlen(v)), 3, FALSE, HUDFONT_WHITE);
};

//----------------------------------------------------------------------
// MAIN ENTRY POINT FOR HUD!!!
//----------------------------------------------------------------------
void(vector virtsize, float showscores) CSQC_DrawHud =
{
local vector pos, pos_speedo;
local float oitems, hudviewsize, i;

// Save previous HUD versions for flash function
oitems = sitems;

//------------------------------------------------------------------
// All variables have to be specially setup and passed between
// progs and csprogs as they are not connected in VM space
// By default CSQC has 30 (most commonly used) parameters setup
// Unfortunately some of them need to be converted (bitswapped)
// to make them readable again (I blame spike for this mess)
// The downside to this bitswapping mess is that the serverflags
// is not passed to CSQC completely, only the first 4bits (runes)
//------------------------------------------------------------------
sitems = getstatf (STAT_ITEMS, 0, 23);
sitems2 = getstatf (STAT_ITEMS, 23, 9);
sweapon = getstatf (STAT_ACTIVEWEAPON);
shealth = getstatf (STAT_HEALTH);

// Don't show HUD, intermission or dead
if (intermission || shealth <= 0)
return;

//--------------------------------------------------------------
// Read console variable for background HUD alpha
baralpha = cvar ("scr_sbaralpha");
if (baralpha == 0)
baralpha = 0.75;
// Default is 1 for everything else
hudalpha = 1;

//--------------------------------------------------------------
// Check if any weapons have been added to the inventory
// Update time so the flash function can detect it
// Check for player count for splitscreen!?! QSS/FTE feature
if (numclientseats <= 1)
{
// Player alive and inventory changd?
if (shealth && sitems != oitems)
{
// Go through all weapon flash counters
for (i = 0; i < WPN_ICONS; i++)
{
// Found weapon and its new?
if ((sitems & (1<<i)) && !(oitems & (1<<i)))
// Reset timer
flashtime[i] = time;
}
}
}

//--------------------------------------------------------------
// Find out how much of the HUD is being displayed
// 100 = InfoBar & StatusBar (ALL=Default)
// 110 = StatusBar Only
// 120 = Speedometer
// 130 = Nothing
//--------------------------------------------------------------

// Read current HUD size
hudviewsize = cvar ("viewsize");

// Any HUD to display?
if (hudviewsize < 130)
{
// Override scoreboard - check if no player health
if (shealth <= 0)
showscores = TRUE;

// Find out mid point of screen
pos_x = (virtsize_x - 320) / 2;
pos_y = virtsize_y;
pos_z = 0;

// trying to center the speedometer display just below
// the crosshair. This doesn't seem to be right but it
// works on my 960x720 window. -- CEV.
pos_speedo_x = virtsize_x / 2.0;
pos_speedo_y = virtsize_y / 2.0;
pos_speedo_z = 0;
Hud_Speedometer (pos_speedo - [8 * 1.5, -8]);

// Input Monitor TODO CEV
if (!cvar("crosshair"))
Hud_InputMonitor (pos_speedo - [4, 4, 0]);

if (hudviewsize < 120)
{
// Either show Sbar or Scores (bars are centered)
if (showscores)
Hud_QSScores_SBar (pos - '0 24 0');
else
Hud_DrawSBar (pos - '0 24 0', virtsize);
}

// Can the Info Bar be displayed?
if (hudviewsize < 110)
Hud_DrawIBar (pos - '0 48 0', virtsize);
}
};

//----------------------------------------------------------------------
void(vector virtsize, float showscores) CSQC_DrawScores =
{
shealth = getstatf (STAT_HEALTH);

if (intermission || showscores || shealth <= 0)
{
if (deathmatch)
Hud_DMScoreboard ('0 0 0', virtsize);
else if (intermission)
Hud_Intermission ('0 0 0', virtsize);
}
};

Return to the top of this page or return to the overview of this repo.

Log cl_hud.qc

Date Commit Message Author + -
2024-03-24 2nd pass refactor, rework QC class structure cev +1033  

Return to the top of this page or return to the overview of this repo.