quakeforge-old/common/sbar.c
Joseph Carter df559eaf9f Under a rare case in UQ (that you are playing with the QW HUD in a co-op
game), the color bar that was supposed to be the backdrop for your frag
counts would be drawn as if the statusbar was centered (which is never
the case if you're using the HUD), fixed.

I have more sbar.c fixes to do but I need a working UQ to be able to test
them out first.  We're _almost_ there...  We all owe Deek and taniwha big
for the progress made tonight I think---great job guys.  But save SOME of
the merge for the rest of us willya?  ;>
2000-02-10 09:36:00 +00:00

1996 lines
43 KiB
C

/*
sbar.c - status bar code
Copyright (C) 1996-1997 Id Software, Inc.
Portions Copyright (C) 1999,2000 Nelson Rush.
Copyright (C) 1999,2000 contributors of the QuakeForge project
Please see the file "AUTHORS" for a list of contributors
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <quakedef.h>
#include <qtypes.h>
#include <wad.h>
#include <common.h>
#include <client.h>
#include <draw.h>
#include <sbar.h>
#include <screen.h>
#include <cmd.h>
#include <protocol.h>
#ifdef UQUAKE
# include <server.h>
#endif
extern void M_DrawPic (int x, int y, qpic_t *pic);
int sb_updates; // if >= vid.numpages, no update needed
#define STAT_MINUS 10 // num frame for '-' stats digit
qpic_t *sb_nums[2][11];
qpic_t *sb_colon, *sb_slash;
qpic_t *sb_ibar;
qpic_t *sb_sbar;
qpic_t *sb_scorebar;
qpic_t *sb_weapons[7][8]; // 0 is active, 1 is owned, 2-5 are flashes
qpic_t *sb_ammo[4];
qpic_t *sb_sigil[4];
qpic_t *sb_armor[3];
qpic_t *sb_items[32];
qpic_t *sb_faces[7][2]; // 0 is gibbed, 1 is dead, 2-6 are alive
// 0 is static, 1 is temporary animation
qpic_t *sb_face_invis;
qpic_t *sb_face_quad;
qpic_t *sb_face_invuln;
qpic_t *sb_face_invis_invuln;
qboolean sb_showscores;
#ifdef QUAKEWORLD
qboolean sb_showteamscores;
#endif // QUAKEWORLD
int sb_lines; // scan lines to draw
#ifdef UQUAKE
qpic_t *rsb_invbar[2];
qpic_t *rsb_weapons[5];
qpic_t *rsb_items[2];
qpic_t *rsb_ammo[3];
qpic_t *rsb_teambord; // PGM 01/19/97 - team color border
//MED 01/04/97 added two more weapons + 3 alternates for grenade launcher
qpic_t *hsb_weapons[7][5]; // 0 is active, 1 is owned, 2-5 are flashes
//MED 01/04/97 added array to simplify weapon parsing
int hipweapons[4] = {HIT_LASER_CANNON_BIT,HIT_MJOLNIR_BIT,4,HIT_PROXIMITY_GUN_BIT};
//MED 01/04/97 added hipnotic items array
qpic_t *hsb_items[2];
#endif
#ifdef QUAKEWORLD
void Sbar_TeamOverlay (void);
#endif
void Sbar_DeathmatchOverlay (int start);
void Sbar_MiniDeathmatchOverlay (void);
#ifdef QUAKEWORLD
static qboolean largegame = false;
#endif
/*
Sbar_Items
Return a target-independant items list
*/
int
Sbar_Items ( void )
{
#ifdef QUAKEWORLD
return cl.stats[STAT_ITEMS];
#else
return cl.items;
#endif // QUAKEWORLD
}
/*
===============
Sbar_ShowScores
Tab key down
===============
*/
void Sbar_ShowScores (void)
{
if (sb_showscores)
return;
sb_showscores = true;
sb_updates = 0;
}
/*
===============
Sbar_DontShowScores
Tab key up
===============
*/
void Sbar_DontShowScores (void)
{
sb_showscores = false;
sb_updates = 0;
}
/*
===============
Sbar_ShowTeamScores
Tab key down
===============
*/
void Sbar_ShowTeamScores (void)
{
#ifdef QUAKEWORLD
if (sb_showteamscores)
return;
sb_showteamscores = true;
sb_updates = 0;
#endif // QUAKEWORLD
}
/*
===============
Sbar_DontShowTeamScores
Tab key up
===============
*/
void Sbar_DontShowTeamScores (void)
{
#ifdef QUAKEWORLD
sb_showteamscores = false;
sb_updates = 0;
#endif // QUAKEWORLD
}
/*
===============
Sbar_Changed
===============
*/
void Sbar_Changed (void)
{
sb_updates = 0; // update next frame
}
/*
===============
Sbar_Init
===============
*/
void Sbar_Init (void)
{
int i;
for (i=0 ; i<10 ; i++)
{
sb_nums[0][i] = Draw_PicFromWad (va("num_%i",i));
sb_nums[1][i] = Draw_PicFromWad (va("anum_%i",i));
}
sb_nums[0][10] = Draw_PicFromWad ("num_minus");
sb_nums[1][10] = Draw_PicFromWad ("anum_minus");
sb_colon = Draw_PicFromWad ("num_colon");
sb_slash = Draw_PicFromWad ("num_slash");
sb_weapons[0][0] = Draw_PicFromWad ("inv_shotgun");
sb_weapons[0][1] = Draw_PicFromWad ("inv_sshotgun");
sb_weapons[0][2] = Draw_PicFromWad ("inv_nailgun");
sb_weapons[0][3] = Draw_PicFromWad ("inv_snailgun");
sb_weapons[0][4] = Draw_PicFromWad ("inv_rlaunch");
sb_weapons[0][5] = Draw_PicFromWad ("inv_srlaunch");
sb_weapons[0][6] = Draw_PicFromWad ("inv_lightng");
sb_weapons[1][0] = Draw_PicFromWad ("inv2_shotgun");
sb_weapons[1][1] = Draw_PicFromWad ("inv2_sshotgun");
sb_weapons[1][2] = Draw_PicFromWad ("inv2_nailgun");
sb_weapons[1][3] = Draw_PicFromWad ("inv2_snailgun");
sb_weapons[1][4] = Draw_PicFromWad ("inv2_rlaunch");
sb_weapons[1][5] = Draw_PicFromWad ("inv2_srlaunch");
sb_weapons[1][6] = Draw_PicFromWad ("inv2_lightng");
for (i=0 ; i<5 ; i++)
{
sb_weapons[2+i][0] = Draw_PicFromWad (va("inva%i_shotgun",i+1));
sb_weapons[2+i][1] = Draw_PicFromWad (va("inva%i_sshotgun",i+1));
sb_weapons[2+i][2] = Draw_PicFromWad (va("inva%i_nailgun",i+1));
sb_weapons[2+i][3] = Draw_PicFromWad (va("inva%i_snailgun",i+1));
sb_weapons[2+i][4] = Draw_PicFromWad (va("inva%i_rlaunch",i+1));
sb_weapons[2+i][5] = Draw_PicFromWad (va("inva%i_srlaunch",i+1));
sb_weapons[2+i][6] = Draw_PicFromWad (va("inva%i_lightng",i+1));
}
sb_ammo[0] = Draw_PicFromWad ("sb_shells");
sb_ammo[1] = Draw_PicFromWad ("sb_nails");
sb_ammo[2] = Draw_PicFromWad ("sb_rocket");
sb_ammo[3] = Draw_PicFromWad ("sb_cells");
sb_armor[0] = Draw_PicFromWad ("sb_armor1");
sb_armor[1] = Draw_PicFromWad ("sb_armor2");
sb_armor[2] = Draw_PicFromWad ("sb_armor3");
sb_items[0] = Draw_PicFromWad ("sb_key1");
sb_items[1] = Draw_PicFromWad ("sb_key2");
sb_items[2] = Draw_PicFromWad ("sb_invis");
sb_items[3] = Draw_PicFromWad ("sb_invuln");
sb_items[4] = Draw_PicFromWad ("sb_suit");
sb_items[5] = Draw_PicFromWad ("sb_quad");
sb_sigil[0] = Draw_PicFromWad ("sb_sigil1");
sb_sigil[1] = Draw_PicFromWad ("sb_sigil2");
sb_sigil[2] = Draw_PicFromWad ("sb_sigil3");
sb_sigil[3] = Draw_PicFromWad ("sb_sigil4");
sb_faces[4][0] = Draw_PicFromWad ("face1");
sb_faces[4][1] = Draw_PicFromWad ("face_p1");
sb_faces[3][0] = Draw_PicFromWad ("face2");
sb_faces[3][1] = Draw_PicFromWad ("face_p2");
sb_faces[2][0] = Draw_PicFromWad ("face3");
sb_faces[2][1] = Draw_PicFromWad ("face_p3");
sb_faces[1][0] = Draw_PicFromWad ("face4");
sb_faces[1][1] = Draw_PicFromWad ("face_p4");
sb_faces[0][0] = Draw_PicFromWad ("face5");
sb_faces[0][1] = Draw_PicFromWad ("face_p5");
sb_face_invis = Draw_PicFromWad ("face_invis");
sb_face_invuln = Draw_PicFromWad ("face_invul2");
sb_face_invis_invuln = Draw_PicFromWad ("face_inv2");
sb_face_quad = Draw_PicFromWad ("face_quad");
Cmd_AddCommand ("+showscores", Sbar_ShowScores);
Cmd_AddCommand ("-showscores", Sbar_DontShowScores);
#ifdef QUAKEWORLD
Cmd_AddCommand ("+showteamscores", Sbar_ShowTeamScores);
Cmd_AddCommand ("-showteamscores", Sbar_DontShowTeamScores);
#endif
sb_sbar = Draw_PicFromWad ("sbar");
sb_ibar = Draw_PicFromWad ("ibar");
sb_scorebar = Draw_PicFromWad ("scorebar");
#ifdef UQUAKE
if (hipnotic) //MED 01/04/97 added new hipnotic weapons
{
hsb_weapons[0][0] = Draw_PicFromWad ("inv_laser");
hsb_weapons[0][1] = Draw_PicFromWad ("inv_mjolnir");
hsb_weapons[0][2] = Draw_PicFromWad ("inv_gren_prox");
hsb_weapons[0][3] = Draw_PicFromWad ("inv_prox_gren");
hsb_weapons[0][4] = Draw_PicFromWad ("inv_prox");
hsb_weapons[1][0] = Draw_PicFromWad ("inv2_laser");
hsb_weapons[1][1] = Draw_PicFromWad ("inv2_mjolnir");
hsb_weapons[1][2] = Draw_PicFromWad ("inv2_gren_prox");
hsb_weapons[1][3] = Draw_PicFromWad ("inv2_prox_gren");
hsb_weapons[1][4] = Draw_PicFromWad ("inv2_prox");
for (i=0 ; i<5 ; i++)
{
hsb_weapons[2+i][0] = Draw_PicFromWad (va("inva%i_laser",i+1));
hsb_weapons[2+i][1] = Draw_PicFromWad (va("inva%i_mjolnir",i+1));
hsb_weapons[2+i][2] = Draw_PicFromWad (va("inva%i_gren_prox",i+1));
hsb_weapons[2+i][3] = Draw_PicFromWad (va("inva%i_prox_gren",i+1));
hsb_weapons[2+i][4] = Draw_PicFromWad (va("inva%i_prox",i+1));
}
hsb_items[0] = Draw_PicFromWad ("sb_wsuit");
hsb_items[1] = Draw_PicFromWad ("sb_eshld");
}
if (rogue)
{
rsb_invbar[0] = Draw_PicFromWad ("r_invbar1");
rsb_invbar[1] = Draw_PicFromWad ("r_invbar2");
rsb_weapons[0] = Draw_PicFromWad ("r_lava");
rsb_weapons[1] = Draw_PicFromWad ("r_superlava");
rsb_weapons[2] = Draw_PicFromWad ("r_gren");
rsb_weapons[3] = Draw_PicFromWad ("r_multirock");
rsb_weapons[4] = Draw_PicFromWad ("r_plasma");
rsb_items[0] = Draw_PicFromWad ("r_shield1");
rsb_items[1] = Draw_PicFromWad ("r_agrav1");
// PGM 01/19/97 - team color border
rsb_teambord = Draw_PicFromWad ("r_teambord");
// PGM 01/19/97 - team color border
rsb_ammo[0] = Draw_PicFromWad ("r_ammolava");
rsb_ammo[1] = Draw_PicFromWad ("r_ammomulti");
rsb_ammo[2] = Draw_PicFromWad ("r_ammoplasma");
}
#endif // UQUAKE
}
//=============================================================================
// drawing routines are reletive to the status bar location
/*
=============
Sbar_DrawPic
=============
*/
void Sbar_DrawPic (int x, int y, qpic_t *pic)
{
#ifdef UQUAKE
if ((cl_sbar.value && !cl.gametype == GAME_DEATHMATCH)
&& (hipnotic || rogue))
Draw_Pic (x + ((vid.width - 320)>>1),
y + (vid.height-SBAR_HEIGHT), pic);
else
#endif
Draw_Pic (x, y + (vid.height-SBAR_HEIGHT), pic);
}
/*
=============
Sbar_DrawSubPic
=============
JACK: Draws a portion of the picture in the status bar.
*/
void Sbar_DrawSubPic(int x, int y, qpic_t *pic,
int srcx, int srcy, int width, int height)
{
#ifdef UQUAKE
if ((cl_sbar.value && !cl.gametype == GAME_DEATHMATCH)
&& (hipnotic || rogue))
Draw_SubPic (x + ((vid.width - 320)>>1),
y + (vid.height-SBAR_HEIGHT),
pic, srcx, srcy, width, height);
else
#endif
Draw_SubPic (x, y + (vid.height-SBAR_HEIGHT),
pic, srcx, srcy, width, height);
}
/*
=============
Sbar_DrawTransPic
=============
*/
void Sbar_DrawTransPic (int x, int y, qpic_t *pic)
{
#ifdef UQUAKE
if ((cl_sbar.value && !cl.gametype == GAME_DEATHMATCH)
&& (hipnotic || rogue))
Draw_TransPic (x + ((vid.width - 320)>>1),
y + (vid.height-SBAR_HEIGHT), pic);
else
#endif
Draw_TransPic (x, y + (vid.height-SBAR_HEIGHT), pic);
}
/*
================
Sbar_DrawCharacter
Draws one solid graphics character
================
*/
void Sbar_DrawCharacter (int x, int y, int num)
{
#ifdef UQUAKE
if ((cl_sbar.value && !cl.gametype == GAME_DEATHMATCH)
&& (hipnotic || rogue))
Draw_Character (x + ((vid.width - 320)>>1) + 4,
y + (vid.height-SBAR_HEIGHT), num);
else
#endif
Draw_Character (x + 4, y + (vid.height-SBAR_HEIGHT), num);
}
/*
================
Sbar_DrawString
================
*/
void Sbar_DrawString (int x, int y, char *str)
{
#ifdef UQUAKE
if ((cl_sbar.value && !cl.gametype == GAME_DEATHMATCH)
&& (hipnotic || rogue))
Draw_String (x + ((vid.width - 320)>>1),
y + (vid.height-SBAR_HEIGHT), str);
else
#endif
Draw_String (x, y + (vid.height-SBAR_HEIGHT), str);
}
/*
=============
Sbar_itoa
=============
*/
int Sbar_itoa (int num, char *buf)
{
char *str;
int pow10;
int dig;
str = buf;
if (num < 0)
{
*str++ = '-';
num = -num;
}
for (pow10 = 10 ; num >= pow10 ; pow10 *= 10);
do {
pow10 /= 10;
dig = num/pow10;
*str++ = '0'+dig;
num -= dig*pow10;
} while (pow10 != 1);
*str = 0;
return (str - buf);
}
/*
=============
Sbar_DrawNum
=============
*/
void Sbar_DrawNum (int x, int y, int num, int digits, int color)
{
char str[12];
char *ptr;
int l, frame;
l = Sbar_itoa (num, str);
ptr = str;
if (l > digits)
ptr += (l-digits);
if (l < digits)
x += (digits-l)*24;
while (*ptr)
{
if (*ptr == '-')
frame = STAT_MINUS;
else
frame = *ptr -'0';
Sbar_DrawTransPic (x,y,sb_nums[color][frame]);
x += 24;
ptr++;
}
}
//=============================================================================
#ifdef QUAKEWORLD
int fragsort[MAX_CLIENTS];
int scoreboardlines;
typedef struct {
char team[16+1];
int frags;
int players;
int plow, phigh, ptotal;
} team_t;
team_t teams[MAX_CLIENTS];
int teamsort[MAX_CLIENTS];
int scoreboardteams;
#else
int fragsort[MAX_SCOREBOARD];
char scoreboardtext[MAX_SCOREBOARD][20];
int scoreboardtop[MAX_SCOREBOARD];
int scoreboardbottom[MAX_SCOREBOARD];
int scoreboardcount[MAX_SCOREBOARD];
int scoreboardlines;
#endif // QUAKEWORLD
/*
===============
Sbar_SortFrags
===============
*/
#ifdef QUAKEWORLD
void Sbar_SortFrags (qboolean includespec)
{
int i, j, k;
// sort by frags
scoreboardlines = 0;
for (i=0 ; i<MAX_CLIENTS ; i++)
{
if (cl.players[i].name[0] &&
(!cl.players[i].spectator || includespec))
{
fragsort[scoreboardlines] = i;
scoreboardlines++;
if (cl.players[i].spectator)
cl.players[i].frags = -999;
}
}
for (i=0 ; i<scoreboardlines ; i++)
for (j=0 ; j<scoreboardlines-1-i ; j++)
if (cl.players[fragsort[j]].frags < cl.players[fragsort[j+1]].frags)
{
k = fragsort[j];
fragsort[j] = fragsort[j+1];
fragsort[j+1] = k;
}
}
#else
void Sbar_SortFrags (void)
{
int i, j, k;
// sort by frags
scoreboardlines = 0;
for (i=0 ; i<cl.maxclients ; i++) {
if (cl.scores[i].name[0]) {
fragsort[scoreboardlines] = i;
scoreboardlines++;
}
}
for (i=0 ; i<scoreboardlines ; i++) {
for (j=0 ; j<scoreboardlines-1-i ; j++) {
if (cl.scores[fragsort[j]].frags < cl.scores[fragsort[j+1]].frags) {
k = fragsort[j];
fragsort[j] = fragsort[j+1];
fragsort[j+1] = k;
}
}
}
}
#endif // QUAKEWORLD
void Sbar_SortTeams (void)
{
#ifdef QUAKEWORLD
int i, j, k;
player_info_t *s;
int teamplay;
char t[16+1];
// request new ping times every two second
scoreboardteams = 0;
teamplay = atoi(Info_ValueForKey(cl.serverinfo, "teamplay"));
if (!teamplay)
return;
// sort the teams
memset(teams, 0, sizeof(teams));
for (i = 0; i < MAX_CLIENTS; i++)
teams[i].plow = 999;
for (i = 0; i < MAX_CLIENTS; i++) {
s = &cl.players[i];
if (!s->name[0])
continue;
if (s->spectator)
continue;
// find his team in the list
t[16] = 0;
strncpy(t, Info_ValueForKey(s->userinfo, "team"), 16);
if (!t || !t[0])
continue; // not on team
for (j = 0; j < scoreboardteams; j++)
if (!strcmp(teams[j].team, t)) {
teams[j].frags += s->frags;
teams[j].players++;
goto addpinginfo;
}
if (j == scoreboardteams) { // must add him
j = scoreboardteams++;
strcpy(teams[j].team, t);
teams[j].frags = s->frags;
teams[j].players = 1;
addpinginfo:
if (teams[j].plow > s->ping)
teams[j].plow = s->ping;
if (teams[j].phigh < s->ping)
teams[j].phigh = s->ping;
teams[j].ptotal += s->ping;
}
}
// sort
for (i = 0; i < scoreboardteams; i++)
teamsort[i] = i;
// good 'ol bubble sort
for (i = 0; i < scoreboardteams - 1; i++)
for (j = i + 1; j < scoreboardteams; j++)
if (teams[teamsort[i]].frags < teams[teamsort[j]].frags) {
k = teamsort[i];
teamsort[i] = teamsort[j];
teamsort[j] = k;
}
#endif // QUAKEWORLD
}
int Sbar_ColorForMap (int m)
{
#ifdef QUAKEWORLD
m = (m < 0) ? 0 : ((m > 13) ? 13 : m);
m *= 16;
#endif // QUAKEWORLD
return m < 128 ? m + 8 : m + 8;
}
/*
===============
Sbar_SoloScoreboard
===============
*/
void Sbar_SoloScoreboard (void)
{
char str[80];
int minutes, seconds, tens, units;
#ifdef QUAKEWORLD
Sbar_DrawPic (0, 0, sb_scorebar);
#else
snprintf(str, sizeof(str),"Monsters:%3i /%3i", cl.stats[STAT_MONSTERS], cl.stats[STAT_TOTALMONSTERS]);
Sbar_DrawString (8, 4, str);
snprintf(str, sizeof(str),"Secrets :%3i /%3i", cl.stats[STAT_SECRETS], cl.stats[STAT_TOTALSECRETS]);
Sbar_DrawString (8, 12, str);
#endif // QUAKEWORLD
// time
minutes = cl.time / 60;
seconds = cl.time - 60*minutes;
tens = seconds / 10;
units = seconds - 10*tens;
snprintf(str, sizeof(str),"Time :%3i:%i%i", minutes, tens, units);
Sbar_DrawString (184, 4, str);
#ifdef UQUAKE
{
// draw level name
int l = strlen (cl.levelname);
Sbar_DrawString (232 - l*4, 12, cl.levelname);
}
#endif // UQUAKE
}
/*
===============
Sbar_DrawScoreboard
===============
*/
void Sbar_DrawScoreboard (void)
{
#ifdef UQUAKE
Sbar_SoloScoreboard ();
if (cl.gametype == GAME_DEATHMATCH)
Sbar_DeathmatchOverlay (0);
#endif // UQUAKE
}
//=============================================================================
/*
===============
Sbar_DrawInventory
===============
*/
void Sbar_DrawInventory (void)
{
int i;
char num[6];
float time;
int flashon;
qboolean headsup;
qboolean hudswap;
headsup = !(cl_sbar.value || scr_viewsize.value<100);
hudswap = cl_hudswap.value; // Get that nasty float out :)
#ifdef UQUAKE
if (hipnotic)
headsup = false;
if (rogue) {
headsup = false;
if ( cl.stats[STAT_ACTIVEWEAPON] >= RIT_LAVA_NAILGUN )
Sbar_DrawPic (0, -24, rsb_invbar[0]);
else
Sbar_DrawPic (0, -24, rsb_invbar[1]);
} else {
if (!headsup)
Sbar_DrawPic (0, -24, sb_ibar);
}
#else
if (!headsup)
Sbar_DrawPic (0, -24, sb_ibar);
#endif // !QUAKEWORLD
// weapons
for (i=0 ; i<7 ; i++)
{
if (Sbar_Items() & (IT_SHOTGUN << i) ) {
time = cl.item_gettime[i];
flashon = (int)((cl.time - time)*10);
if (flashon < 0)
flashon = 0;
if (flashon >= 10) {
if ( cl.stats[STAT_ACTIVEWEAPON] == (IT_SHOTGUN<<i) )
flashon = 1;
else
flashon = 0;
}
else
flashon = (flashon%5) + 2;
if (headsup) {
if (i || vid.height>200)
Sbar_DrawSubPic ((hudswap) ? 0 : (vid.width-24),-68-(7-i)*16 , sb_weapons[flashon][i],0,0,24,16);
} else
Sbar_DrawPic (i*24, -16, sb_weapons[flashon][i]);
if (flashon > 1)
sb_updates = 0; // force update to remove flash
}
}
#ifdef UQUAKE
// hipnotic weapons
if (hipnotic) {
int grenadeflashing=0;
for (i=0 ; i<4 ; i++) {
if (Sbar_Items() & (1<<hipweapons[i]) ) {
time = cl.item_gettime[hipweapons[i]];
flashon = (int)((cl.time - time)*10);
if (flashon < 0)
flashon = 0;
if (flashon >= 10) {
if ( cl.stats[STAT_ACTIVEWEAPON] == (1<<hipweapons[i]) )
flashon = 1;
else
flashon = 0;
} else
flashon = (flashon%5) + 2;
// check grenade launcher
if (i==2) {
if (Sbar_Items() & HIT_PROXIMITY_GUN) {
if (flashon) {
grenadeflashing = 1;
Sbar_DrawPic (96, -16, hsb_weapons[flashon][2]);
}
}
} else if (i==3) {
if (Sbar_Items() & (IT_SHOTGUN << 4)) {
if (flashon && !grenadeflashing) {
Sbar_DrawPic (96, -16, hsb_weapons[flashon][3]);
} else if (!grenadeflashing) {
Sbar_DrawPic (96, -16, hsb_weapons[0][3]);
}
} else
Sbar_DrawPic (96, -16, hsb_weapons[flashon][4]);
} else
Sbar_DrawPic (176 + (i*24), -16, hsb_weapons[flashon][i]);
if (flashon > 1)
sb_updates = 0; // force update to remove flash
}
}
}
if (rogue) {
// check for powered up weapon.
if ( cl.stats[STAT_ACTIVEWEAPON] >= RIT_LAVA_NAILGUN ) {
for (i=0;i<5;i++) {
if (cl.stats[STAT_ACTIVEWEAPON] == (RIT_LAVA_NAILGUN << i)) {
Sbar_DrawPic ((i+2)*24, -16, rsb_weapons[i]);
}
}
}
}
#endif // QUAKEWORLD
// ammo counts
for (i=0 ; i<4 ; i++)
{
snprintf(num, sizeof(num), "%3i",cl.stats[STAT_SHELLS+i] );
if (headsup) {
Sbar_DrawSubPic((hudswap) ? 0 : (vid.width-42), -24 - (4-i)*11, sb_ibar, 3+(i*48), 0, 42, 11);
if (num[0] != ' ')
Sbar_DrawCharacter ( (hudswap) ? 3 : (vid.width-39), -24 - (4-i)*11, 18 + num[0] - '0');
if (num[1] != ' ')
Sbar_DrawCharacter ( (hudswap) ? 11 : (vid.width-31), -24 - (4-i)*11, 18 + num[1] - '0');
if (num[2] != ' ')
Sbar_DrawCharacter ( (hudswap) ? 19 : (vid.width-23), -24 - (4-i)*11, 18 + num[2] - '0');
} else {
if (num[0] != ' ')
Sbar_DrawCharacter ( (6*i+1)*8 - 2, -24, 18 + num[0] - '0');
if (num[1] != ' ')
Sbar_DrawCharacter ( (6*i+2)*8 - 2, -24, 18 + num[1] - '0');
if (num[2] != ' ')
Sbar_DrawCharacter ( (6*i+3)*8 - 2, -24, 18 + num[2] - '0');
}
}
flashon = 0;
// items
for (i=0 ; i<6 ; i++)
if (Sbar_Items() & (1<<(17+i))) {
time = cl.item_gettime[17+i];
if (time && time > cl.time - 2 && flashon ) { // flash frame
sb_updates = 0;
}
else {
#ifdef UQUAKE
//MED 01/04/97 changed keys
if (!hipnotic || (i>1)) {
Sbar_DrawPic (192 + i*16, -16, sb_items[i]);
}
#else
Sbar_DrawPic (192 + i*16, -16, sb_items[i]);
#endif // !QUAKEWORLD
}
if (time && time > cl.time - 2)
sb_updates = 0;
}
#ifdef UQUAKE
// hipnotic items
if (hipnotic) {
for (i=0 ; i<2 ; i++) {
if (Sbar_Items() & (1<<(24+i))) {
time = cl.item_gettime[24+i];
if (time && time > cl.time - 2 && flashon ) { // flash frame
sb_updates = 0;
} else {
Sbar_DrawPic (288 + i*16, -16, hsb_items[i]);
}
if (time && time > cl.time - 2)
sb_updates = 0;
}
}
}
if (rogue) {
// new rogue items
for (i=0 ; i<2 ; i++) {
if (Sbar_Items() & (1<<(29+i))) {
time = cl.item_gettime[29+i];
if (time && time > cl.time - 2 && flashon ) { // flash frame
sb_updates = 0;
} else {
Sbar_DrawPic (288 + i*16, -16, rsb_items[i]);
}
if (time && time > cl.time - 2)
sb_updates = 0;
}
}
} else {
#endif // !QUAKEWORLD
// sigils
for (i=0 ; i<4 ; i++) {
if (Sbar_Items() & (1<<(28+i))) {
time = cl.item_gettime[28+i];
if (time && time > cl.time - 2 && flashon ) { // flash frame
sb_updates = 0;
} else
Sbar_DrawPic (320-32 + i*8, -16, sb_sigil[i]);
if (time && time > cl.time - 2)
sb_updates = 0;
}
}
#ifdef UQUAKE
}
#endif
}
//=============================================================================
/*
===============
Sbar_DrawFrags
===============
*/
void Sbar_DrawFrags (void)
{
int i, k, l;
int top, bottom;
int x, y, f;
char num[12];
int xofs;
#ifdef QUAKEWORLD
player_info_t *s;
Sbar_SortFrags (false);
#else
scoreboard_t *s;
Sbar_SortFrags ();
#endif // QUAKEWORLD
// draw the text
l = scoreboardlines <= 4 ? scoreboardlines : 4;
x = 23;
if (cl.gametype == GAME_DEATHMATCH || cl_sbar.value == 0)
xofs = 0;
else
xofs = (vid.width - 320)>>1;
y = vid.height - SBAR_HEIGHT - 23;
for (i=0 ; i < l ; i++)
{
k = fragsort[i];
#ifdef QUAKEWORLD
s = &cl.players[k];
#else
s = &cl.scores[k];
#endif // QUAKEWORLD
if (!s->name[0])
continue;
#ifdef QUAKEWORLD
if (s->spectator)
continue;
#endif // QUAKEWORLD
// draw background
#ifdef QUAKEWORLD
top = s->topcolor;
bottom = s->bottomcolor;
#else
top = s->colors & 0xf0;
bottom = (s->colors & 15)<<4;
#endif
top = Sbar_ColorForMap (top);
bottom = Sbar_ColorForMap (bottom);
Draw_Fill (xofs + x * 8 + 10, y, 28, 4, top);
Draw_Fill (xofs + x * 8 + 10, y + 4, 28, 3, bottom);
// draw number
f = s->frags;
snprintf(num, sizeof(num), "%3i", f);
Sbar_DrawCharacter ( (x + 1) * 8 , -24, num[0]);
Sbar_DrawCharacter ( (x + 2) * 8 , -24, num[1]);
Sbar_DrawCharacter ( (x + 3) * 8 , -24, num[2]);
if (k == cl.playernum) {
Sbar_DrawCharacter ( x * 8 + 2, -24, 16);
Sbar_DrawCharacter ( (x + 4) * 8 -4, -24, 17);
}
x += 4;
}
}
//=============================================================================
/*
===============
Sbar_DrawFace
===============
*/
void Sbar_DrawFace (void)
{
int f, anim;
#ifdef UQUAKE
// PGM 01/19/97 - team color drawing
// PGM 03/02/97 - fixed so color swatch only appears in CTF modes
if (rogue &&
(cl.maxclients != 1) &&
(teamplay.value>3) &&
(teamplay.value<7)) {
int top, bottom;
int xofs;
char num[12];
scoreboard_t *s;
s = &cl.scores[cl.playernum];
// draw background
top = s->colors & 0xf0;
bottom = (s->colors & 15)<<4;
top = Sbar_ColorForMap (top);
bottom = Sbar_ColorForMap (bottom);
if (cl.gametype == GAME_DEATHMATCH)
xofs = 113;
else
xofs = ((vid.width - 320)>>1) + 113;
Sbar_DrawPic (112, 0, rsb_teambord);
Draw_Fill (xofs, vid.height-SBAR_HEIGHT+3, 22, 9, top);
Draw_Fill (xofs, vid.height-SBAR_HEIGHT+12, 22, 9, bottom);
// draw number
f = s->frags;
snprintf(num, sizeof(num), "%3i",f);
if (top==8)
{
if (num[0] != ' ')
Sbar_DrawCharacter(109, 3, 18 + num[0] - '0');
if (num[1] != ' ')
Sbar_DrawCharacter(116, 3, 18 + num[1] - '0');
if (num[2] != ' ')
Sbar_DrawCharacter(123, 3, 18 + num[2] - '0');
}
else
{
Sbar_DrawCharacter ( 109, 3, num[0]);
Sbar_DrawCharacter ( 116, 3, num[1]);
Sbar_DrawCharacter ( 123, 3, num[2]);
}
return;
}
// PGM 01/19/97 - team color drawing
#endif // !QUAKEWORLD
if ( (Sbar_Items() & (IT_INVISIBILITY | IT_INVULNERABILITY) )
== (IT_INVISIBILITY | IT_INVULNERABILITY) ) {
Sbar_DrawPic (112, 0, sb_face_invis_invuln);
return;
}
if (Sbar_Items() & IT_QUAD) {
Sbar_DrawPic (112, 0, sb_face_quad );
return;
}
if (Sbar_Items() & IT_INVISIBILITY) {
Sbar_DrawPic (112, 0, sb_face_invis );
return;
}
if (Sbar_Items() & IT_INVULNERABILITY) {
Sbar_DrawPic (112, 0, sb_face_invuln);
return;
}
if (cl.stats[STAT_HEALTH] >= 100)
f = 4;
else {
f = cl.stats[STAT_HEALTH] / 20;
if (f < 0) f = 0;
}
if (cl.time <= cl.faceanimtime)
{
anim = 1;
sb_updates = 0; // make sure the anim gets drawn over
}
else
anim = 0;
Sbar_DrawPic (112, 0, sb_faces[f][anim]);
}
/*
=============
Sbar_DrawNormal
=============
*/
void Sbar_DrawNormal (void)
{
if (cl_sbar.value || scr_viewsize.value<100)
Sbar_DrawPic (0, 0, sb_sbar);
#ifdef UQUAKE
if (hipnotic) {
if (Sbar_Items() & IT_KEY1)
Sbar_DrawPic (209, 3, sb_items[0]);
if (Sbar_Items() & IT_KEY2)
Sbar_DrawPic (209, 12, sb_items[1]);
}
#endif // !QUAKEWORLD
// armor
if (Sbar_Items() & IT_INVULNERABILITY) {
Sbar_DrawNum (24, 0, 666, 3, 1);
Sbar_DrawPic (0, 0, draw_disc);
} else {
#ifdef UQUAKE
if (rogue) {
Sbar_DrawNum (24, 0, cl.stats[STAT_ARMOR], 3,
cl.stats[STAT_ARMOR] <= 25);
if (Sbar_Items() & RIT_ARMOR3)
Sbar_DrawPic (0, 0, sb_armor[2]);
else if (Sbar_Items() & RIT_ARMOR2)
Sbar_DrawPic (0, 0, sb_armor[1]);
else if (Sbar_Items() & RIT_ARMOR1)
Sbar_DrawPic (0, 0, sb_armor[0]);
} else {
#endif // QUAKEWORLD
Sbar_DrawNum (24, 0, cl.stats[STAT_ARMOR], 3
, cl.stats[STAT_ARMOR] <= 25);
if (Sbar_Items() & IT_ARMOR3)
Sbar_DrawPic (0, 0, sb_armor[2]);
else if (Sbar_Items() & IT_ARMOR2)
Sbar_DrawPic (0, 0, sb_armor[1]);
else if (Sbar_Items() & IT_ARMOR1)
Sbar_DrawPic (0, 0, sb_armor[0]);
#ifdef UQUAKE
}
#endif
}
// face
Sbar_DrawFace ();
// health
Sbar_DrawNum (136, 0, cl.stats[STAT_HEALTH], 3
, cl.stats[STAT_HEALTH] <= 25);
// ammo icon
#ifdef UQUAKE
if (rogue) {
if (Sbar_Items() & RIT_SHELLS)
Sbar_DrawPic (224, 0, sb_ammo[0]);
else if (Sbar_Items() & RIT_NAILS)
Sbar_DrawPic (224, 0, sb_ammo[1]);
else if (Sbar_Items() & RIT_ROCKETS)
Sbar_DrawPic (224, 0, sb_ammo[2]);
else if (Sbar_Items() & RIT_CELLS)
Sbar_DrawPic (224, 0, sb_ammo[3]);
else if (Sbar_Items() & RIT_LAVA_NAILS)
Sbar_DrawPic (224, 0, rsb_ammo[0]);
else if (Sbar_Items() & RIT_PLASMA_AMMO)
Sbar_DrawPic (224, 0, rsb_ammo[1]);
else if (Sbar_Items() & RIT_MULTI_ROCKETS)
Sbar_DrawPic (224, 0, rsb_ammo[2]);
} else {
#endif // !QUAKEWORLD
if (Sbar_Items() & IT_SHELLS)
Sbar_DrawPic (224, 0, sb_ammo[0]);
else if (Sbar_Items() & IT_NAILS)
Sbar_DrawPic (224, 0, sb_ammo[1]);
else if (Sbar_Items() & IT_ROCKETS)
Sbar_DrawPic (224, 0, sb_ammo[2]);
else if (Sbar_Items() & IT_CELLS)
Sbar_DrawPic (224, 0, sb_ammo[3]);
#ifdef UQUAKE
}
#endif // !QUAKEWORLD
Sbar_DrawNum (248, 0, cl.stats[STAT_AMMO], 3
, cl.stats[STAT_AMMO] <= 10);
}
/*
===============
Sbar_Draw
===============
*/
void Sbar_Draw (void)
{
qboolean headsup;
#ifdef QUAKEWORLD
char st[512];
#endif
headsup = !(cl_sbar.value || scr_viewsize.value<100);
if ((sb_updates >= vid.numpages) && !headsup)
return;
if (scr_con_current == vid.height)
return; // console is full screen
if (!headsup && sb_lines && vid.width > 320)
Draw_TileClear (0, vid.height - sb_lines, vid.width, sb_lines);
#ifdef UQUAKE
if (sb_lines > 24)
{
Sbar_DrawInventory ();
if (cl.maxclients != 1)
Sbar_DrawFrags ();
}
#endif // !QUAKEWORLD
scr_copyeverything = 1;
sb_updates++;
// top line
if (sb_lines > 24) {
#ifdef QUAKEWORLD
if (!cl.spectator || autocam == CAM_TRACK)
Sbar_DrawInventory ();
if (!headsup || vid.width<512)
#else
Sbar_DrawInventory ();
if (cl.maxclients != 1)
#endif // QUAKEWORLD
Sbar_DrawFrags ();
}
// main area
if (sb_lines > 0) {
#ifdef QUAKEWORLD
if (cl.spectator) {
if (autocam != CAM_TRACK) {
Sbar_DrawPic (0, 0, sb_scorebar);
Sbar_DrawString (160-7*8,4, "SPECTATOR MODE");
Sbar_DrawString(160-14*8+4, 12, "Press [ATTACK] for AutoCamera");
} else {
if (sb_showscores || cl.stats[STAT_HEALTH] <= 0)
Sbar_SoloScoreboard ();
else
Sbar_DrawNormal ();
// Sbar_DrawString (160-14*8+4,4, "SPECTATOR MODE - TRACK CAMERA");
snprintf(st, sizeof(st), "Tracking %-.13s, [JUMP] for next",
cl.players[spec_track].name);
Sbar_DrawString(0, -8, st);
}
} else if (sb_showscores || cl.stats[STAT_HEALTH] <= 0)
Sbar_SoloScoreboard ();
else
Sbar_DrawNormal ();
#else
Sbar_DrawNormal ();
#endif // QUAKEWORLD
}
#ifdef QUAKEWORLD
// main screen deathmatch rankings
// if we're dead show team scores in team games
if (cl.stats[STAT_HEALTH] <= 0 && !cl.spectator)
if (atoi(Info_ValueForKey(cl.serverinfo, "teamplay")) > 0 &&
!sb_showscores)
Sbar_TeamOverlay();
else
Sbar_DeathmatchOverlay (0);
else if (sb_showscores)
Sbar_DeathmatchOverlay (0);
else if (sb_showteamscores)
Sbar_TeamOverlay();
if (sb_showscores || sb_showteamscores ||
cl.stats[STAT_HEALTH] <= 0)
sb_updates = 0;
#if 0
// clear unused areas in gl
{
int x = (vid.width - 320)>>1;
// left
if (x > 0) {
Draw_TileClear (0, vid.height - sb_lines, x, sb_lines);
Draw_TileClear (x+320, vid.height - sb_lines, vid.width - x+320, sb_lines);
}
}
#endif
if (vid.width > 320 && !headsup)
Draw_TileClear (320, vid.height - sb_lines, vid.width - 320, sb_lines);
if (sb_lines > 0)
Sbar_MiniDeathmatchOverlay ();
#else
if (sb_showscores || cl.stats[STAT_HEALTH] <= 0) {
Sbar_DrawPic (0, 0, sb_scorebar);
Sbar_DrawScoreboard ();
sb_updates = 0;
}
#endif // QUAKEWORLD
}
//=============================================================================
/*
==================
Sbar_IntermissionNumber
==================
*/
void Sbar_IntermissionNumber (int x, int y, int num, int digits, int color)
{
char str[12];
char *ptr;
int l, frame;
l = Sbar_itoa (num, str);
ptr = str;
if (l > digits)
ptr += (l-digits);
if (l < digits)
x += (digits-l) * 24;
while (*ptr) {
if (*ptr == '-')
frame = STAT_MINUS;
else
frame = *ptr -'0';
Draw_TransPic (x, y, sb_nums[color][frame]);
x += 24;
ptr++;
}
}
/*
==================
Sbar_TeamOverlay
team frags
added by Zoid
==================
*/
void Sbar_TeamOverlay (void)
{
#ifdef QUAKEWORLD
qpic_t *pic;
int i, k, l;
int x, y;
char num[12];
int teamplay;
char team[5];
team_t *tm;
int plow, phigh, pavg;
// request new ping times every two second
teamplay = atoi(Info_ValueForKey(cl.serverinfo, "teamplay"));
if (!teamplay) {
Sbar_DeathmatchOverlay(0);
return;
}
scr_copyeverything = 1;
scr_fullupdate = 0;
pic = Draw_CachePic ("gfx/ranking.lmp");
Draw_Pic (160-pic->width/2, 0, pic);
y = 24;
x = 36;
Draw_String(x, y, "low/avg/high team total players");
y += 8;
// Draw_String(x, y, "------------ ---- ----- -------");
Draw_String(x, y, "\x1d\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1f \x1d\x1e\x1e\x1f \x1d\x1e\x1e\x1e\x1f \x1d\x1e\x1e\x1e\x1e\x1e\x1f");
y += 8;
// sort the teams
Sbar_SortTeams();
// draw the text
l = scoreboardlines;
for (i=0 ; i < scoreboardteams && y <= vid.height-10 ; i++)
{
k = teamsort[i];
tm = teams + k;
// draw pings
plow = tm->plow;
if (plow < 0 || plow > 999)
plow = 999;
phigh = tm->phigh;
if (phigh < 0 || phigh > 999)
phigh = 999;
if (!tm->players)
pavg = 999;
else
pavg = tm->ptotal / tm->players;
if (pavg < 0 || pavg > 999)
pavg = 999;
snprintf(num, sizeof(num), "%3i/%3i/%3i", plow, pavg, phigh);
Draw_String ( x, y, num);
// draw team
team[4] = 0;
strncpy (team, tm->team, 4);
Draw_String (x + 104, y, team);
// draw total
snprintf(num, sizeof(num), "%5i", tm->frags);
Draw_String (x + 104 + 40, y, num);
// draw players
snprintf(num, sizeof(num), "%5i", tm->players);
Draw_String (x + 104 + 88, y, num);
if (!strncmp(Info_ValueForKey(cl.players[cl.playernum].userinfo,
"team"), tm->team, 16)) {
Draw_Character ( x + 104 - 8, y, 16);
Draw_Character ( x + 104 + 32, y, 17);
}
y += 8;
}
y += 8;
Sbar_DeathmatchOverlay(y);
#endif // QUAKEWORLD
}
/*
==================
Sbar_DeathmatchOverlay
ping time frags name
==================
*/
#ifdef QUAKEWORLD
void Sbar_DeathmatchOverlay (int start)
{
qpic_t *pic;
int i, k, l;
int top, bottom;
int x, y, f;
char num[12];
player_info_t *s;
int total;
int minutes;
int p;
int teamplay;
char team[5];
int skip = 10;
if (largegame)
skip = 8;
// request new ping times every two second
if (realtime - cl.last_ping_request > 2)
{
cl.last_ping_request = realtime;
MSG_WriteByte (&cls.netchan.message, clc_stringcmd);
SZ_Print (&cls.netchan.message, "pings");
}
teamplay = atoi(Info_ValueForKey(cl.serverinfo, "teamplay"));
scr_copyeverything = 1;
scr_fullupdate = 0;
if (!start) {
pic = Draw_CachePic ("gfx/ranking.lmp");
Draw_Pic (160-pic->width/2, 0, pic);
}
// scores
Sbar_SortFrags (true);
// draw the text
l = scoreboardlines;
if (start)
y = start;
else
y = 24;
if (teamplay)
{
x = 4;
// 0 40 64 104 152 192
Draw_String ( x , y, "ping pl time frags team name");
y += 8;
// Draw_String ( x , y, "---- -- ---- ----- ---- ----------------");
Draw_String ( x , y, "\x1d\x1e\x1e\x1f \x1d\x1f \x1d\x1e\x1e\x1f \x1d\x1e\x1e\x1e\x1f \x1d\x1e\x1e\x1f \x1d\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1f");
y += 8;
}
else
{
x = 16;
// 0 40 64 104 152
Draw_String ( x , y, "ping pl time frags name");
y += 8;
// Draw_String ( x , y, "---- -- ---- ----- ----------------");
Draw_String ( x , y, "\x1d\x1e\x1e\x1f \x1d\x1f \x1d\x1e\x1e\x1f \x1d\x1e\x1e\x1e\x1f \x1d\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1f");
y += 8;
}
for (i=0 ; i<l && y <= vid.height-10 ; i++)
{
k = fragsort[i];
s = &cl.players[k];
if (!s->name[0])
continue;
// draw ping
p = s->ping;
if (p < 0 || p > 999)
p = 999;
snprintf(num, sizeof(num), "%4i", p);
Draw_String ( x, y, num);
// draw pl
p = s->pl;
snprintf(num, sizeof(num), "%3i", p);
if (p > 25)
Draw_Alt_String ( x+32, y, num);
else
Draw_String ( x+32, y, num);
if (s->spectator)
{
Draw_String (x+40, y, "(spectator)");
// draw name
if (teamplay)
Draw_String (x+152+40, y, s->name);
else
Draw_String (x+152, y, s->name);
y += skip;
continue;
}
// draw time
if (cl.intermission)
total = cl.completed_time - s->entertime;
else
total = realtime - s->entertime;
minutes = (int)total/60;
snprintf(num, sizeof(num), "%4i", minutes);
Draw_String ( x+64 , y, num);
// draw background
top = s->topcolor;
bottom = s->bottomcolor;
top = Sbar_ColorForMap (top);
bottom = Sbar_ColorForMap (bottom);
if (largegame)
Draw_Fill ( x+104, y+1, 40, 3, top);
else
Draw_Fill ( x+104, y, 40, 4, top);
Draw_Fill ( x+104, y+4, 40, 4, bottom);
// draw number
f = s->frags;
snprintf(num, sizeof(num), "%3i",f);
Draw_Character ( x+112 , y, num[0]);
Draw_Character ( x+120 , y, num[1]);
Draw_Character ( x+128 , y, num[2]);
if (k == cl.playernum)
{
Draw_Character ( x + 104, y, 16);
Draw_Character ( x + 136, y, 17);
}
// team
if (teamplay)
{
team[4] = 0;
strncpy (team, Info_ValueForKey(s->userinfo, "team"), 4);
Draw_String (x+152, y, team);
}
// draw name
if (teamplay)
Draw_String (x+152+40, y, s->name);
else
Draw_String (x+152, y, s->name);
y += skip;
}
if (y >= vid.height-10) // we ran over the screen size, squish
largegame = true;
}
/*
==================
Sbar_MiniDeathmatchOverlay
frags name
frags team name
displayed to right of status bar if there's room
==================
*/
void Sbar_MiniDeathmatchOverlay (void)
{
int i, k;
int top, bottom;
int x, y, f;
char num[12];
player_info_t *s;
int teamplay;
char team[5];
int numlines;
char name[16+1];
team_t *tm;
if (vid.width < 512 || !sb_lines)
return; // not enuff room
teamplay = atoi(Info_ValueForKey(cl.serverinfo, "teamplay"));
scr_copyeverything = 1;
scr_fullupdate = 0;
// scores
Sbar_SortFrags (false);
if (vid.width >= 640)
Sbar_SortTeams();
if (!scoreboardlines)
return; // no one there?
// draw the text
y = vid.height - sb_lines - 1;
numlines = sb_lines/8;
if (numlines < 3)
return; // not enough room
// find us
for (i=0 ; i < scoreboardlines; i++)
if (fragsort[i] == cl.playernum)
break;
if (i == scoreboardlines) // we're not there, we are probably a spectator, just display top
i = 0;
else // figure out start
i = i - numlines/2;
if (i > scoreboardlines - numlines)
i = scoreboardlines - numlines;
if (i < 0)
i = 0;
x = 324;
for (/* */ ; i < scoreboardlines && y < vid.height - 8 + 1; i++)
{
k = fragsort[i];
s = &cl.players[k];
if (!s->name[0])
continue;
// draw ping
top = s->topcolor;
bottom = s->bottomcolor;
top = Sbar_ColorForMap (top);
bottom = Sbar_ColorForMap (bottom);
Draw_Fill ( x, y+1, 40, 3, top);
Draw_Fill ( x, y+4, 40, 4, bottom);
// draw number
f = s->frags;
snprintf(num, sizeof(num), "%3i",f);
Draw_Character ( x+8 , y, num[0]);
Draw_Character ( x+16, y, num[1]);
Draw_Character ( x+24, y, num[2]);
if (k == cl.playernum)
{
Draw_Character ( x, y, 16);
Draw_Character ( x + 32, y, 17);
}
// team
if (teamplay)
{
team[4] = 0;
strncpy (team, Info_ValueForKey(s->userinfo, "team"), 4);
Draw_String (x+48, y, team);
}
// draw name
name[16] = 0;
strncpy(name, s->name, 16);
if (teamplay)
Draw_String (x+48+40, y, name);
else
Draw_String (x+48, y, name);
y += 8;
}
// draw teams if room
if (vid.width < 640 || !teamplay)
return;
// draw seperator
x += 208;
for (y = vid.height - sb_lines; y < vid.height - 6; y += 2)
Draw_Character(x, y, 14);
x += 16;
y = vid.height - sb_lines;
for (i=0 ; i < scoreboardteams && y <= vid.height; i++)
{
k = teamsort[i];
tm = teams + k;
// draw pings
team[4] = 0;
strncpy (team, tm->team, 4);
Draw_String (x, y, team);
// draw total
snprintf(num, sizeof(num), "%5i", tm->frags);
Draw_String (x + 40, y, num);
if (!strncmp(Info_ValueForKey(cl.players[cl.playernum].userinfo,
"team"), tm->team, 16)) {
Draw_Character ( x - 8, y, 16);
Draw_Character ( x + 32, y, 17);
}
y += 8;
}
}
#else
void Sbar_DeathmatchOverlay (int start)
{
qpic_t *pic;
int i, k, l;
int top, bottom;
int x, y, f;
char num[12];
scoreboard_t *s;
scr_copyeverything = 1;
scr_fullupdate = 0;
pic = Draw_CachePic ("gfx/ranking.lmp");
M_DrawPic ((320-pic->width)/2, 8, pic);
// scores
Sbar_SortFrags ();
// draw the text
l = scoreboardlines;
x = 80 + ((vid.width - 320)>>1);
y = 40;
for (i=0 ; i<l ; i++)
{
k = fragsort[i];
s = &cl.scores[k];
if (!s->name[0])
continue;
// draw background
top = s->colors & 0xf0;
bottom = (s->colors & 15)<<4;
top = Sbar_ColorForMap (top);
bottom = Sbar_ColorForMap (bottom);
Draw_Fill ( x, y, 40, 4, top);
Draw_Fill ( x, y+4, 40, 4, bottom);
// draw number
f = s->frags;
snprintf(num, sizeof(num), "%3i",f);
Draw_Character ( x+8 , y, num[0]);
Draw_Character ( x+16 , y, num[1]);
Draw_Character ( x+24 , y, num[2]);
if (k == cl.playernum)
Draw_Character ( x - 8, y, 12);
#if 0
{
int total;
int n, minutes, tens, units;
// draw time
total = cl.completed_time - s->entertime;
minutes = (int)total/60;
n = total - minutes*60;
tens = n/10;
units = n%10;
snprintf(num, sizeof(num), "%3i:%i%i", minutes, tens, units);
Draw_String ( x+48 , y, num);
}
#endif
// draw name
Draw_String (x+64, y, s->name);
y += 10;
}
}
/*
==================
Sbar_DeathmatchOverlay
==================
*/
void Sbar_MiniDeathmatchOverlay (void)
{
int i, k, l;
int top, bottom;
int x, y, f;
char num[12];
scoreboard_t *s;
int numlines;
if (vid.width < 512 || !sb_lines)
return;
scr_copyeverything = 1;
scr_fullupdate = 0;
// scores
Sbar_SortFrags ();
// draw the text
l = scoreboardlines;
y = vid.height - sb_lines;
numlines = sb_lines/8;
if (numlines < 3)
return;
//find us
for (i = 0; i < scoreboardlines; i++)
if (fragsort[i] == cl.playernum)
break;
if (i == scoreboardlines) // we're not there
i = 0;
else // figure out start
i = i - numlines/2;
if (i > scoreboardlines - numlines)
i = scoreboardlines - numlines;
if (i < 0)
i = 0;
x = 324;
for (/* */; i < scoreboardlines && y < vid.height - 8 ; i++)
{
k = fragsort[i];
s = &cl.scores[k];
if (!s->name[0])
continue;
// draw background
top = s->colors & 0xf0;
bottom = (s->colors & 15)<<4;
top = Sbar_ColorForMap (top);
bottom = Sbar_ColorForMap (bottom);
Draw_Fill ( x, y+1, 40, 3, top);
Draw_Fill ( x, y+4, 40, 4, bottom);
// draw number
f = s->frags;
snprintf(num, sizeof(num), "%3i",f);
Draw_Character ( x+8 , y, num[0]);
Draw_Character ( x+16 , y, num[1]);
Draw_Character ( x+24 , y, num[2]);
if (k == cl.playernum) {
Draw_Character ( x, y, 16);
Draw_Character ( x + 32, y, 17);
}
#if 0
{
int total;
int n, minutes, tens, units;
// draw time
total = cl.completed_time - s->entertime;
minutes = (int)total/60;
n = total - minutes*60;
tens = n/10;
units = n%10;
snprintf(num, sizeof(num), "%3i:%i%i", minutes, tens, units);
Draw_String ( x+48 , y, num);
}
#endif
// draw name
Draw_String (x+48, y, s->name);
y += 8;
}
}
#endif // QUAKEWORLD
/*
==================
Sbar_IntermissionOverlay
==================
*/
void Sbar_IntermissionOverlay (void)
{
#ifdef UQUAKE
qpic_t *pic;
int dig;
int num;
#endif // QUAKEWORLD
scr_copyeverything = 1;
scr_fullupdate = 0;
#ifdef QUAKEWORLD
if (atoi(Info_ValueForKey(cl.serverinfo, "teamplay")) > 0 && !sb_showscores)
Sbar_TeamOverlay ();
else
Sbar_DeathmatchOverlay (0);
#else
if (cl.gametype == GAME_DEATHMATCH) {
Sbar_DeathmatchOverlay (0);
return;
}
pic = Draw_CachePic ("gfx/complete.lmp");
Draw_Pic (64, 24, pic);
pic = Draw_CachePic ("gfx/inter.lmp");
Draw_TransPic (0, 56, pic);
// time
dig = cl.completed_time/60;
Sbar_IntermissionNumber (160, 64, dig, 3, 0);
num = cl.completed_time - dig*60;
Draw_TransPic (234,64,sb_colon);
Draw_TransPic (246,64,sb_nums[0][num/10]);
Draw_TransPic (266,64,sb_nums[0][num%10]);
Sbar_IntermissionNumber (160, 104, cl.stats[STAT_SECRETS], 3, 0);
Draw_TransPic (232,104,sb_slash);
Sbar_IntermissionNumber (240, 104, cl.stats[STAT_TOTALSECRETS], 3, 0);
Sbar_IntermissionNumber (160, 144, cl.stats[STAT_MONSTERS], 3, 0);
Draw_TransPic (232,144,sb_slash);
Sbar_IntermissionNumber (240, 144, cl.stats[STAT_TOTALMONSTERS], 3, 0);
#endif // QUAKEWORLD
}
/*
==================
Sbar_FinaleOverlay
==================
*/
void Sbar_FinaleOverlay (void)
{
qpic_t *pic;
scr_copyeverything = 1;
pic = Draw_CachePic ("gfx/finale.lmp");
Draw_TransPic ( (vid.width-pic->width)/2, 16, pic);
}