1 /* 2 Copyright (C) 1996-1997 Id Software, Inc. 3 4 This program is free software; you can redistribute it and/or 5 modify it under the terms of the GNU General Public License 6 as published by the Free Software Foundation; either version 2 7 of the License, or (at your option) any later version. 8 9 This program is distributed in the hope that it will be useful, 10 but WITHOUT ANY WARRANTY; without even the implied warranty of 11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 12 13 See the GNU General Public License for more details. 14 15 You should have received a copy of the GNU General Public License 16 along with this program; if not, write to the Free Software 17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 18 19 */ 20 // sbar.c -- status bar code 21 22 #include "quakedef.h" 23 24 25 int sb_updates; // if >= vid.numpages, no update needed 26 27 #define STAT_MINUS 10 // num frame for '-' stats digit 28 qpic_t *sb_nums[2][11]; 29 qpic_t *sb_colon, *sb_slash; 30 qpic_t *sb_ibar; 31 qpic_t *sb_sbar; 32 qpic_t *sb_scorebar; 33 34 qpic_t *sb_weapons[7][8]; // 0 is active, 1 is owned, 2-5 are flashes 35 qpic_t *sb_ammo[4]; 36 qpic_t *sb_sigil[4]; 37 qpic_t *sb_armor[3]; 38 qpic_t *sb_items[32]; 39 40 qpic_t *sb_faces[7][2]; // 0 is gibbed, 1 is dead, 2-6 are alive 41 // 0 is static, 1 is temporary animation 42 qpic_t *sb_face_invis; 43 qpic_t *sb_face_quad; 44 qpic_t *sb_face_invuln; 45 qpic_t *sb_face_invis_invuln; 46 47 qboolean sb_showscores; 48 qboolean sb_showteamscores; 49 50 int sb_lines; // scan lines to draw 51 52 void Sbar_DeathmatchOverlay (int start); 53 void Sbar_TeamOverlay (void); 54 void Sbar_MiniDeathmatchOverlay (void); 55 56 static qboolean largegame = false; 57 58 /* 59 =============== 60 Sbar_ShowTeamScores 61 62 Tab key down 63 =============== 64 */ 65 void Sbar_ShowTeamScores (void) 66 { 67 if (sb_showteamscores) 68 return; 69 70 sb_showteamscores = true; 71 sb_updates = 0; 72 } 73 74 /* 75 =============== 76 Sbar_DontShowTeamScores 77 78 Tab key up 79 =============== 80 */ 81 void Sbar_DontShowTeamScores (void) 82 { 83 sb_showteamscores = false; 84 sb_updates = 0; 85 } 86 87 /* 88 =============== 89 Sbar_ShowScores 90 91 Tab key down 92 =============== 93 */ 94 void Sbar_ShowScores (void) 95 { 96 if (sb_showscores) 97 return; 98 99 sb_showscores = true; 100 sb_updates = 0; 101 } 102 103 /* 104 =============== 105 Sbar_DontShowScores 106 107 Tab key up 108 =============== 109 */ 110 void Sbar_DontShowScores (void) 111 { 112 sb_showscores = false; 113 sb_updates = 0; 114 } 115 116 /* 117 =============== 118 Sbar_Changed 119 =============== 120 */ 121 void Sbar_Changed (void) 122 { 123 sb_updates = 0; // update next frame 124 } 125 126 /* 127 =============== 128 Sbar_Init 129 =============== 130 */ 131 void Sbar_Init (void) 132 { 133 int i; 134 135 for (i=0 ; i<10 ; i++) 136 { 137 sb_nums[0][i] = Draw_PicFromWad (va("num_%i",i)); 138 sb_nums[1][i] = Draw_PicFromWad (va("anum_%i",i)); 139 } 140 141 sb_nums[0][10] = Draw_PicFromWad ("num_minus"); 142 sb_nums[1][10] = Draw_PicFromWad ("anum_minus"); 143 144 sb_colon = Draw_PicFromWad ("num_colon"); 145 sb_slash = Draw_PicFromWad ("num_slash"); 146 147 sb_weapons[0][0] = Draw_PicFromWad ("inv_shotgun"); 148 sb_weapons[0][1] = Draw_PicFromWad ("inv_sshotgun"); 149 sb_weapons[0][2] = Draw_PicFromWad ("inv_nailgun"); 150 sb_weapons[0][3] = Draw_PicFromWad ("inv_snailgun"); 151 sb_weapons[0][4] = Draw_PicFromWad ("inv_rlaunch"); 152 sb_weapons[0][5] = Draw_PicFromWad ("inv_srlaunch"); 153 sb_weapons[0][6] = Draw_PicFromWad ("inv_lightng"); 154 155 sb_weapons[1][0] = Draw_PicFromWad ("inv2_shotgun"); 156 sb_weapons[1][1] = Draw_PicFromWad ("inv2_sshotgun"); 157 sb_weapons[1][2] = Draw_PicFromWad ("inv2_nailgun"); 158 sb_weapons[1][3] = Draw_PicFromWad ("inv2_snailgun"); 159 sb_weapons[1][4] = Draw_PicFromWad ("inv2_rlaunch"); 160 sb_weapons[1][5] = Draw_PicFromWad ("inv2_srlaunch"); 161 sb_weapons[1][6] = Draw_PicFromWad ("inv2_lightng"); 162 163 for (i=0 ; i<5 ; i++) 164 { 165 sb_weapons[2+i][0] = Draw_PicFromWad (va("inva%i_shotgun",i+1)); 166 sb_weapons[2+i][1] = Draw_PicFromWad (va("inva%i_sshotgun",i+1)); 167 sb_weapons[2+i][2] = Draw_PicFromWad (va("inva%i_nailgun",i+1)); 168 sb_weapons[2+i][3] = Draw_PicFromWad (va("inva%i_snailgun",i+1)); 169 sb_weapons[2+i][4] = Draw_PicFromWad (va("inva%i_rlaunch",i+1)); 170 sb_weapons[2+i][5] = Draw_PicFromWad (va("inva%i_srlaunch",i+1)); 171 sb_weapons[2+i][6] = Draw_PicFromWad (va("inva%i_lightng",i+1)); 172 } 173 174 sb_ammo[0] = Draw_PicFromWad ("sb_shells"); 175 sb_ammo[1] = Draw_PicFromWad ("sb_nails"); 176 sb_ammo[2] = Draw_PicFromWad ("sb_rocket"); 177 sb_ammo[3] = Draw_PicFromWad ("sb_cells"); 178 179 sb_armor[0] = Draw_PicFromWad ("sb_armor1"); 180 sb_armor[1] = Draw_PicFromWad ("sb_armor2"); 181 sb_armor[2] = Draw_PicFromWad ("sb_armor3"); 182 183 sb_items[0] = Draw_PicFromWad ("sb_key1"); 184 sb_items[1] = Draw_PicFromWad ("sb_key2"); 185 sb_items[2] = Draw_PicFromWad ("sb_invis"); 186 sb_items[3] = Draw_PicFromWad ("sb_invuln"); 187 sb_items[4] = Draw_PicFromWad ("sb_suit"); 188 sb_items[5] = Draw_PicFromWad ("sb_quad"); 189 190 sb_sigil[0] = Draw_PicFromWad ("sb_sigil1"); 191 sb_sigil[1] = Draw_PicFromWad ("sb_sigil2"); 192 sb_sigil[2] = Draw_PicFromWad ("sb_sigil3"); 193 sb_sigil[3] = Draw_PicFromWad ("sb_sigil4"); 194 195 sb_faces[4][0] = Draw_PicFromWad ("face1"); 196 sb_faces[4][1] = Draw_PicFromWad ("face_p1"); 197 sb_faces[3][0] = Draw_PicFromWad ("face2"); 198 sb_faces[3][1] = Draw_PicFromWad ("face_p2"); 199 sb_faces[2][0] = Draw_PicFromWad ("face3"); 200 sb_faces[2][1] = Draw_PicFromWad ("face_p3"); 201 sb_faces[1][0] = Draw_PicFromWad ("face4"); 202 sb_faces[1][1] = Draw_PicFromWad ("face_p4"); 203 sb_faces[0][0] = Draw_PicFromWad ("face5"); 204 sb_faces[0][1] = Draw_PicFromWad ("face_p5"); 205 206 sb_face_invis = Draw_PicFromWad ("face_invis"); 207 sb_face_invuln = Draw_PicFromWad ("face_invul2"); 208 sb_face_invis_invuln = Draw_PicFromWad ("face_inv2"); 209 sb_face_quad = Draw_PicFromWad ("face_quad"); 210 211 Cmd_AddCommand ("+showscores", Sbar_ShowScores); 212 Cmd_AddCommand ("-showscores", Sbar_DontShowScores); 213 214 Cmd_AddCommand ("+showteamscores", Sbar_ShowTeamScores); 215 Cmd_AddCommand ("-showteamscores", Sbar_DontShowTeamScores); 216 217 sb_sbar = Draw_PicFromWad ("sbar"); 218 sb_ibar = Draw_PicFromWad ("ibar"); 219 sb_scorebar = Draw_PicFromWad ("scorebar"); 220 } 221 222 223 //============================================================================= 224 225 // drawing routines are reletive to the status bar location 226 227 /* 228 ============= 229 Sbar_DrawPic 230 ============= 231 */ 232 void Sbar_DrawPic (int x, int y, qpic_t *pic) 233 { 234 Draw_Pic (x /* + ((vid.width - 320)>>1) */, y + (vid.height-SBAR_HEIGHT), pic); 235 } 236 237 /* 238 ============= 239 Sbar_DrawSubPic 240 ============= 241 JACK: Draws a portion of the picture in the status bar. 242 */ 243 244 void Sbar_DrawSubPic(int x, int y, qpic_t *pic, int srcx, int srcy, int width, int height) 245 { 246 Draw_SubPic (x, y+(vid.height-SBAR_HEIGHT), pic, srcx, srcy, width, height); 247 } 248 249 250 /* 251 ============= 252 Sbar_DrawTransPic 253 ============= 254 */ 255 void Sbar_DrawTransPic (int x, int y, qpic_t *pic) 256 { 257 Draw_TransPic (x /*+ ((vid.width - 320)>>1) */, y + (vid.height-SBAR_HEIGHT), pic); 258 } 259 260 /* 261 ================ 262 Sbar_DrawCharacter 263 264 Draws one solid graphics character 265 ================ 266 */ 267 void Sbar_DrawCharacter (int x, int y, int num) 268 { 269 Draw_Character ( x /*+ ((vid.width - 320)>>1) */ + 4, y + vid.height-SBAR_HEIGHT, num); 270 } 271 272 /* 273 ================ 274 Sbar_DrawString 275 ================ 276 */ 277 void Sbar_DrawString (int x, int y, char *str) 278 { 279 Draw_String (x /*+ ((vid.width - 320)>>1) */, y+ vid.height-SBAR_HEIGHT, str); 280 } 281 282 /* 283 ============= 284 Sbar_itoa 285 ============= 286 */ 287 int Sbar_itoa (int num, char *buf) 288 { 289 char *str; 290 int pow10; 291 int dig; 292 293 str = buf; 294 295 if (num < 0) 296 { 297 *str++ = '-'; 298 num = -num; 299 } 300 301 for (pow10 = 10 ; num >= pow10 ; pow10 *= 10) 302 ; 303 304 do 305 { 306 pow10 /= 10; 307 dig = num/pow10; 308 *str++ = '0'+dig; 309 num -= dig*pow10; 310 } while (pow10 != 1); 311 312 *str = 0; 313 314 return str-buf; 315 } 316 317 318 /* 319 ============= 320 Sbar_DrawNum 321 ============= 322 */ 323 void Sbar_DrawNum (int x, int y, int num, int digits, int color) 324 { 325 char str[12]; 326 char *ptr; 327 int l, frame; 328 329 l = Sbar_itoa (num, str); 330 ptr = str; 331 if (l > digits) 332 ptr += (l-digits); 333 if (l < digits) 334 x += (digits-l)*24; 335 336 while (*ptr) 337 { 338 if (*ptr == '-') 339 frame = STAT_MINUS; 340 else 341 frame = *ptr -'0'; 342 343 Sbar_DrawTransPic (x,y,sb_nums[color][frame]); 344 x += 24; 345 ptr++; 346 } 347 } 348 349 //============================================================================= 350 351 //ZOID: this should be MAX_CLIENTS, not MAX_SCOREBOARD!! 352 //int fragsort[MAX_SCOREBOARD]; 353 int fragsort[MAX_CLIENTS]; 354 int scoreboardlines; 355 typedef struct { 356 char team[16+1]; 357 int frags; 358 int players; 359 int plow, phigh, ptotal; 360 } team_t; 361 team_t teams[MAX_CLIENTS]; 362 int teamsort[MAX_CLIENTS]; 363 int scoreboardteams; 364 365 /* 366 =============== 367 Sbar_SortFrags 368 =============== 369 */ 370 void Sbar_SortFrags (qboolean includespec) 371 { 372 int i, j, k; 373 374 // sort by frags 375 scoreboardlines = 0; 376 for (i=0 ; i<MAX_CLIENTS ; i++) 377 { 378 if (cl.players[i].name[0] && 379 (!cl.players[i].spectator || includespec)) 380 { 381 fragsort[scoreboardlines] = i; 382 scoreboardlines++; 383 if (cl.players[i].spectator) 384 cl.players[i].frags = -999; 385 } 386 } 387 388 for (i=0 ; i<scoreboardlines ; i++) 389 for (j=0 ; j<scoreboardlines-1-i ; j++) 390 if (cl.players[fragsort[j]].frags < cl.players[fragsort[j+1]].frags) 391 { 392 k = fragsort[j]; 393 fragsort[j] = fragsort[j+1]; 394 fragsort[j+1] = k; 395 } 396 } 397 398 void Sbar_SortTeams (void) 399 { 400 int i, j, k; 401 player_info_t *s; 402 int teamplay; 403 char t[16+1]; 404 405 // request new ping times every two second 406 scoreboardteams = 0; 407 408 teamplay = atoi(Info_ValueForKey(cl.serverinfo, "teamplay")); 409 if (!teamplay) 410 return; 411 412 // sort the teams 413 memset(teams, 0, sizeof(teams)); 414 for (i = 0; i < MAX_CLIENTS; i++) 415 teams[i].plow = 999; 416 417 for (i = 0; i < MAX_CLIENTS; i++) { 418 s = &cl.players[i]; 419 if (!s->name[0]) 420 continue; 421 if (s->spectator) 422 continue; 423 424 // find his team in the list 425 t[16] = 0; 426 strncpy(t, Info_ValueForKey(s->userinfo, "team"), 16); 427 if (!t || !t[0]) 428 continue; // not on team 429 for (j = 0; j < scoreboardteams; j++) 430 if (!strcmp(teams[j].team, t)) { 431 teams[j].frags += s->frags; 432 teams[j].players++; 433 goto addpinginfo; 434 } 435 if (j == scoreboardteams) { // must add him 436 j = scoreboardteams++; 437 strcpy(teams[j].team, t); 438 teams[j].frags = s->frags; 439 teams[j].players = 1; 440 addpinginfo: 441 if (teams[j].plow > s->ping) 442 teams[j].plow = s->ping; 443 if (teams[j].phigh < s->ping) 444 teams[j].phigh = s->ping; 445 teams[j].ptotal += s->ping; 446 } 447 } 448 449 // sort 450 for (i = 0; i < scoreboardteams; i++) 451 teamsort[i] = i; 452 453 // good 'ol bubble sort 454 for (i = 0; i < scoreboardteams - 1; i++) 455 for (j = i + 1; j < scoreboardteams; j++) 456 if (teams[teamsort[i]].frags < teams[teamsort[j]].frags) { 457 k = teamsort[i]; 458 teamsort[i] = teamsort[j]; 459 teamsort[j] = k; 460 } 461 } 462 463 int Sbar_ColorForMap (int m) 464 { 465 m = (m < 0) ? 0 : ((m > 13) ? 13 : m); 466 467 m *= 16; 468 return m < 128 ? m + 8 : m + 8; 469 } 470 471 472 /* 473 =============== 474 Sbar_SoloScoreboard 475 =============== 476 */ 477 void Sbar_SoloScoreboard (void) 478 { 479 char str[80]; 480 int minutes, seconds, tens, units; 481 482 Sbar_DrawPic (0, 0, sb_scorebar); 483 484 // time 485 minutes = cl.time / 60; 486 seconds = cl.time - 60*minutes; 487 tens = seconds / 10; 488 units = seconds - 10*tens; 489 sprintf (str,"Time :%3i:%i%i", minutes, tens, units); 490 Sbar_DrawString (184, 4, str); 491 } 492 493 //============================================================================= 494 495 /* 496 =============== 497 Sbar_DrawInventory 498 =============== 499 */ 500 void Sbar_DrawInventory (void) 501 { 502 int i; 503 char num[6]; 504 float time; 505 int flashon; 506 qboolean headsup; 507 qboolean hudswap; 508 509 headsup = !(cl_sbar.value || scr_viewsize.value<100); 510 hudswap = cl_hudswap.value; // Get that nasty float out :) 511 512 if (!headsup) 513 Sbar_DrawPic (0, -24, sb_ibar); 514 // weapons 515 for (i=0 ; i<7 ; i++) 516 { 517 if (cl.stats[STAT_ITEMS] & (IT_SHOTGUN<<i) ) 518 { 519 time = cl.item_gettime[i]; 520 flashon = (int)((cl.time - time)*10); 521 if (flashon < 0) 522 flashon = 0; 523 if (flashon >= 10) 524 { 525 if ( cl.stats[STAT_ACTIVEWEAPON] == (IT_SHOTGUN<<i) ) 526 flashon = 1; 527 else 528 flashon = 0; 529 } 530 else 531 flashon = (flashon%5) + 2; 532 533 if (headsup) { 534 if (i || vid.height>200) 535 Sbar_DrawSubPic ((hudswap) ? 0 : (vid.width-24),-68-(7-i)*16 , sb_weapons[flashon][i],0,0,24,16); 536 537 } else 538 Sbar_DrawPic (i*24, -16, sb_weapons[flashon][i]); 539 // Sbar_DrawSubPic (0,0,20,20,i*24, -16, sb_weapons[flashon][i]); 540 541 if (flashon > 1) 542 sb_updates = 0; // force update to remove flash 543 } 544 } 545 546 // ammo counts 547 for (i=0 ; i<4 ; i++) 548 { 549 sprintf (num, "%3i",cl.stats[STAT_SHELLS+i] ); 550 if (headsup) { 551 // Sbar_DrawSubPic(3, -24, sb_ibar, 3, 0, 42,11); 552 Sbar_DrawSubPic((hudswap) ? 0 : (vid.width-42), -24 - (4-i)*11, sb_ibar, 3+(i*48), 0, 42, 11); 553 if (num[0] != ' ') 554 Sbar_DrawCharacter ( (hudswap) ? 3 : (vid.width-39), -24 - (4-i)*11, 18 + num[0] - '0'); 555 if (num[1] != ' ') 556 Sbar_DrawCharacter ( (hudswap) ? 11 : (vid.width-31), -24 - (4-i)*11, 18 + num[1] - '0'); 557 if (num[2] != ' ') 558 Sbar_DrawCharacter ( (hudswap) ? 19 : (vid.width-23), -24 - (4-i)*11, 18 + num[2] - '0'); 559 } else { 560 if (num[0] != ' ') 561 Sbar_DrawCharacter ( (6*i+1)*8 - 2, -24, 18 + num[0] - '0'); 562 if (num[1] != ' ') 563 Sbar_DrawCharacter ( (6*i+2)*8 - 2, -24, 18 + num[1] - '0'); 564 if (num[2] != ' ') 565 Sbar_DrawCharacter ( (6*i+3)*8 - 2, -24, 18 + num[2] - '0'); 566 } 567 } 568 569 flashon = 0; 570 // items 571 for (i=0 ; i<6 ; i++) 572 if (cl.stats[STAT_ITEMS] & (1<<(17+i))) 573 { 574 time = cl.item_gettime[17+i]; 575 if (time && time > cl.time - 2 && flashon ) 576 { // flash frame 577 sb_updates = 0; 578 } 579 else 580 Sbar_DrawPic (192 + i*16, -16, sb_items[i]); 581 if (time && time > cl.time - 2) 582 sb_updates = 0; 583 } 584 585 // sigils 586 for (i=0 ; i<4 ; i++) 587 if (cl.stats[STAT_ITEMS] & (1<<(28+i))) 588 { 589 time = cl.item_gettime[28+i]; 590 if (time && time > cl.time - 2 && flashon ) 591 { // flash frame 592 sb_updates = 0; 593 } 594 else 595 Sbar_DrawPic (320-32 + i*8, -16, sb_sigil[i]); 596 if (time && time > cl.time - 2) 597 sb_updates = 0; 598 } 599 } 600 601 //============================================================================= 602 603 /* 604 =============== 605 Sbar_DrawFrags 606 =============== 607 */ 608 void Sbar_DrawFrags (void) 609 { 610 int i, k, l; 611 int top, bottom; 612 int x, y, f; 613 char num[12]; 614 player_info_t *s; 615 616 Sbar_SortFrags (false); 617 618 // draw the text 619 l = scoreboardlines <= 4 ? scoreboardlines : 4; 620 621 x = 23; 622 // xofs = (vid.width - 320)>>1; 623 y = vid.height - SBAR_HEIGHT - 23; 624 625 for (i=0 ; i<l ; i++) 626 { 627 k = fragsort[i]; 628 s = &cl.players[k]; 629 if (!s->name[0]) 630 continue; 631 if (s->spectator) 632 continue; 633 634 // draw background 635 top = s->topcolor; 636 bottom = s->bottomcolor; 637 top = (top < 0) ? 0 : ((top > 13) ? 13 : top); 638 bottom = (bottom < 0) ? 0 : ((bottom > 13) ? 13 : bottom); 639 640 top = Sbar_ColorForMap (top); 641 bottom = Sbar_ColorForMap (bottom); 642 643 // Draw_Fill (xofs + x*8 + 10, y, 28, 4, top); 644 // Draw_Fill (xofs + x*8 + 10, y+4, 28, 3, bottom); 645 Draw_Fill (x*8 + 10, y, 28, 4, top); 646 Draw_Fill (x*8 + 10, y+4, 28, 3, bottom); 647 648 // draw number 649 f = s->frags; 650 sprintf (num, "%3i",f); 651 652 Sbar_DrawCharacter ( (x+1)*8 , -24, num[0]); 653 Sbar_DrawCharacter ( (x+2)*8 , -24, num[1]); 654 Sbar_DrawCharacter ( (x+3)*8 , -24, num[2]); 655 656 if (k == cl.playernum) 657 { 658 Sbar_DrawCharacter (x*8+2, -24, 16); 659 Sbar_DrawCharacter ( (x+4)*8-4, -24, 17); 660 } 661 x+=4; 662 } 663 } 664 665 //============================================================================= 666 667 668 /* 669 =============== 670 Sbar_DrawFace 671 =============== 672 */ 673 void Sbar_DrawFace (void) 674 { 675 int f, anim; 676 677 if ( (cl.stats[STAT_ITEMS] & (IT_INVISIBILITY | IT_INVULNERABILITY) ) 678 == (IT_INVISIBILITY | IT_INVULNERABILITY) ) 679 { 680 Sbar_DrawPic (112, 0, sb_face_invis_invuln); 681 return; 682 } 683 if (cl.stats[STAT_ITEMS] & IT_QUAD) 684 { 685 Sbar_DrawPic (112, 0, sb_face_quad ); 686 return; 687 } 688 if (cl.stats[STAT_ITEMS] & IT_INVISIBILITY) 689 { 690 Sbar_DrawPic (112, 0, sb_face_invis ); 691 return; 692 } 693 if (cl.stats[STAT_ITEMS] & IT_INVULNERABILITY) 694 { 695 Sbar_DrawPic (112, 0, sb_face_invuln); 696 return; 697 } 698 699 if (cl.stats[STAT_HEALTH] >= 100) 700 f = 4; 701 else 702 f = cl.stats[STAT_HEALTH] / 20; 703 704 if (cl.time <= cl.faceanimtime) 705 { 706 anim = 1; 707 sb_updates = 0; // make sure the anim gets drawn over 708 } 709 else 710 anim = 0; 711 Sbar_DrawPic (112, 0, sb_faces[f][anim]); 712 } 713 714 /* 715 ============= 716 Sbar_DrawNormal 717 ============= 718 */ 719 void Sbar_DrawNormal (void) 720 { 721 if (cl_sbar.value || scr_viewsize.value<100) 722 Sbar_DrawPic (0, 0, sb_sbar); 723 724 // armor 725 if (cl.stats[STAT_ITEMS] & IT_INVULNERABILITY) 726 { 727 Sbar_DrawNum (24, 0, 666, 3, 1); 728 Sbar_DrawPic (0, 0, draw_disc); 729 } 730 else 731 { 732 Sbar_DrawNum (24, 0, cl.stats[STAT_ARMOR], 3 733 , cl.stats[STAT_ARMOR] <= 25); 734 if (cl.stats[STAT_ITEMS] & IT_ARMOR3) 735 Sbar_DrawPic (0, 0, sb_armor[2]); 736 else if (cl.stats[STAT_ITEMS] & IT_ARMOR2) 737 Sbar_DrawPic (0, 0, sb_armor[1]); 738 else if (cl.stats[STAT_ITEMS] & IT_ARMOR1) 739 Sbar_DrawPic (0, 0, sb_armor[0]); 740 } 741 742 // face 743 Sbar_DrawFace (); 744 745 // health 746 Sbar_DrawNum (136, 0, cl.stats[STAT_HEALTH], 3 747 , cl.stats[STAT_HEALTH] <= 25); 748 749 // ammo icon 750 if (cl.stats[STAT_ITEMS] & IT_SHELLS) 751 Sbar_DrawPic (224, 0, sb_ammo[0]); 752 else if (cl.stats[STAT_ITEMS] & IT_NAILS) 753 Sbar_DrawPic (224, 0, sb_ammo[1]); 754 else if (cl.stats[STAT_ITEMS] & IT_ROCKETS) 755 Sbar_DrawPic (224, 0, sb_ammo[2]); 756 else if (cl.stats[STAT_ITEMS] & IT_CELLS) 757 Sbar_DrawPic (224, 0, sb_ammo[3]); 758 759 Sbar_DrawNum (248, 0, cl.stats[STAT_AMMO], 3 760 , cl.stats[STAT_AMMO] <= 10); 761 } 762 763 /* 764 =============== 765 Sbar_Draw 766 =============== 767 */ 768 void Sbar_Draw (void) 769 { 770 qboolean headsup; 771 char st[512]; 772 773 headsup = !(cl_sbar.value || scr_viewsize.value<100); 774 if ((sb_updates >= vid.numpages) && !headsup) 775 return; 776 777 if (scr_con_current == vid.height) 778 return; // console is full screen 779 780 scr_copyeverything = 1; 781 // scr_fullupdate = 0; 782 783 sb_updates++; 784 785 // top line 786 if (sb_lines > 24) 787 { 788 if (!cl.spectator || autocam == CAM_TRACK) 789 Sbar_DrawInventory (); 790 if (!headsup || vid.width<512) 791 Sbar_DrawFrags (); 792 } 793 794 // main area 795 if (sb_lines > 0) 796 { 797 if (cl.spectator) { 798 if (autocam != CAM_TRACK) { 799 Sbar_DrawPic (0, 0, sb_scorebar); 800 Sbar_DrawString (160-7*8,4, "SPECTATOR MODE"); 801 Sbar_DrawString(160-14*8+4, 12, "Press [ATTACK] for AutoCamera"); 802 } else { 803 if (sb_showscores || cl.stats[STAT_HEALTH] <= 0) 804 Sbar_SoloScoreboard (); 805 else 806 Sbar_DrawNormal (); 807 808 // Sbar_DrawString (160-14*8+4,4, "SPECTATOR MODE - TRACK CAMERA"); 809 sprintf(st, "Tracking %-.13s, [JUMP] for next", 810 cl.players[spec_track].name); 811 Sbar_DrawString(0, -8, st); 812 } 813 } else if (sb_showscores || cl.stats[STAT_HEALTH] <= 0) 814 Sbar_SoloScoreboard (); 815 else 816 Sbar_DrawNormal (); 817 } 818 819 // main screen deathmatch rankings 820 // if we're dead show team scores in team games 821 if (cl.stats[STAT_HEALTH] <= 0 && !cl.spectator) 822 if (atoi(Info_ValueForKey(cl.serverinfo, "teamplay")) > 0 && 823 !sb_showscores) 824 Sbar_TeamOverlay(); 825 else 826 Sbar_DeathmatchOverlay (0); 827 else if (sb_showscores) 828 Sbar_DeathmatchOverlay (0); 829 else if (sb_showteamscores) 830 Sbar_TeamOverlay(); 831 832 #ifdef GLQUAKE 833 if (sb_showscores || sb_showteamscores || 834 cl.stats[STAT_HEALTH] <= 0) 835 sb_updates = 0; 836 // clear unused areas in gl 837 #if 0 838 { 839 int x = (vid.width - 320)>>1; 840 841 // left 842 if (x > 0) { 843 Draw_TileClear (0, vid.height - sb_lines, x, sb_lines); 844 Draw_TileClear (x+320, vid.height - sb_lines, vid.width - x+320, sb_lines); 845 } 846 } 847 #endif 848 if (vid.width > 320 && !headsup) 849 Draw_TileClear (320, vid.height - sb_lines, vid.width - 320, sb_lines); 850 #endif 851 852 if (sb_lines > 0) 853 Sbar_MiniDeathmatchOverlay (); 854 } 855 856 //============================================================================= 857 858 /* 859 ================== 860 Sbar_IntermissionNumber 861 862 ================== 863 */ 864 void Sbar_IntermissionNumber (int x, int y, int num, int digits, int color) 865 { 866 char str[12]; 867 char *ptr; 868 int l, frame; 869 870 l = Sbar_itoa (num, str); 871 ptr = str; 872 if (l > digits) 873 ptr += (l-digits); 874 if (l < digits) 875 x += (digits-l)*24; 876 877 while (*ptr) 878 { 879 if (*ptr == '-') 880 frame = STAT_MINUS; 881 else 882 frame = *ptr -'0'; 883 884 Draw_TransPic (x,y,sb_nums[color][frame]); 885 x += 24; 886 ptr++; 887 } 888 } 889 890 /* 891 ================== 892 Sbar_TeamOverlay 893 894 team frags 895 added by Zoid 896 ================== 897 */ 898 void Sbar_TeamOverlay (void) 899 { 900 qpic_t *pic; 901 int i, k, l; 902 int x, y; 903 char num[12]; 904 int teamplay; 905 char team[5]; 906 team_t *tm; 907 int plow, phigh, pavg; 908 909 // request new ping times every two second 910 teamplay = atoi(Info_ValueForKey(cl.serverinfo, "teamplay")); 911 912 if (!teamplay) { 913 Sbar_DeathmatchOverlay(0); 914 return; 915 } 916 917 scr_copyeverything = 1; 918 scr_fullupdate = 0; 919 920 pic = Draw_CachePic ("gfx/ranking.lmp"); 921 Draw_Pic (160-pic->width/2, 0, pic); 922 923 y = 24; 924 x = 36; 925 Draw_String(x, y, "low/avg/high team total players"); 926 y += 8; 927 // Draw_String(x, y, "------------ ---- ----- -------"); 928 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"); 929 y += 8; 930 931 // sort the teams 932 Sbar_SortTeams(); 933 934 // draw the text 935 l = scoreboardlines; 936 937 for (i=0 ; i < scoreboardteams && y <= (int) (vid.height-10) ; i++) 938 { 939 k = teamsort[i]; 940 tm = teams + k; 941 942 // draw pings 943 plow = tm->plow; 944 if (plow < 0 || plow > 999) 945 plow = 999; 946 phigh = tm->phigh; 947 if (phigh < 0 || phigh > 999) 948 phigh = 999; 949 if (!tm->players) 950 pavg = 999; 951 else 952 pavg = tm->ptotal / tm->players; 953 if (pavg < 0 || pavg > 999) 954 pavg = 999; 955 956 sprintf (num, "%3i/%3i/%3i", plow, pavg, phigh); 957 Draw_String ( x, y, num); 958 959 // draw team 960 team[4] = 0; 961 strncpy (team, tm->team, 4); 962 Draw_String (x + 104, y, team); 963 964 // draw total 965 sprintf (num, "%5i", tm->frags); 966 Draw_String (x + 104 + 40, y, num); 967 968 // draw players 969 sprintf (num, "%5i", tm->players); 970 Draw_String (x + 104 + 88, y, num); 971 972 if (!strncmp(Info_ValueForKey(cl.players[cl.playernum].userinfo, 973 "team"), tm->team, 16)) { 974 Draw_Character ( x + 104 - 8, y, 16); 975 Draw_Character ( x + 104 + 32, y, 17); 976 } 977 978 y += 8; 979 } 980 y += 8; 981 Sbar_DeathmatchOverlay(y); 982 } 983 984 /* 985 ================== 986 Sbar_DeathmatchOverlay 987 988 ping time frags name 989 ================== 990 */ 991 void Sbar_DeathmatchOverlay (int start) 992 { 993 qpic_t *pic; 994 int i, k, l; 995 int top, bottom; 996 int x, y, f; 997 char num[12]; 998 player_info_t *s; 999 int total; 1000 int minutes; 1001 int p; 1002 int teamplay; 1003 char team[5]; 1004 int skip = 10; 1005 1006 if (largegame) 1007 skip = 8; 1008 1009 // request new ping times every two second 1010 if (realtime - cl.last_ping_request > 2) 1011 { 1012 cl.last_ping_request = realtime; 1013 MSG_WriteByte (&cls.netchan.message, clc_stringcmd); 1014 SZ_Print (&cls.netchan.message, "pings"); 1015 } 1016 1017 teamplay = atoi(Info_ValueForKey(cl.serverinfo, "teamplay")); 1018 1019 scr_copyeverything = 1; 1020 scr_fullupdate = 0; 1021 1022 if (!start) { 1023 pic = Draw_CachePic ("gfx/ranking.lmp"); 1024 Draw_Pic (160-pic->width/2, 0, pic); 1025 } 1026 1027 // scores 1028 Sbar_SortFrags (true); 1029 1030 // draw the text 1031 l = scoreboardlines; 1032 1033 if (start) 1034 y = start; 1035 else 1036 y = 24; 1037 if (teamplay) 1038 { 1039 x = 4; 1040 // 0 40 64 104 152 192 1041 Draw_String ( x , y, "ping pl time frags team name"); 1042 y += 8; 1043 // Draw_String ( x , y, "---- -- ---- ----- ---- ----------------"); 1044 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"); 1045 y += 8; 1046 } 1047 else 1048 { 1049 x = 16; 1050 // 0 40 64 104 152 1051 Draw_String ( x , y, "ping pl time frags name"); 1052 y += 8; 1053 // Draw_String ( x , y, "---- -- ---- ----- ----------------"); 1054 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"); 1055 y += 8; 1056 } 1057 1058 for (i=0 ; i<l && y <= (int) (vid.height-10) ; i++) 1059 { 1060 k = fragsort[i]; 1061 s = &cl.players[k]; 1062 if (!s->name[0]) 1063 continue; 1064 1065 // draw ping 1066 p = s->ping; 1067 if (p < 0 || p > 999) 1068 p = 999; 1069 sprintf (num, "%4i", p); 1070 Draw_String ( x, y, num); 1071 1072 // draw pl 1073 p = s->pl; 1074 sprintf (num, "%3i", p); 1075 if (p > 25) 1076 Draw_Alt_String ( x+32, y, num); 1077 else 1078 Draw_String ( x+32, y, num); 1079 1080 if (s->spectator) 1081 { 1082 Draw_String (x+40, y, "(spectator)"); 1083 // draw name 1084 if (teamplay) 1085 Draw_String (x+152+40, y, s->name); 1086 else 1087 Draw_String (x+152, y, s->name); 1088 y += skip; 1089 continue; 1090 } 1091 1092 1093 // draw time 1094 if (cl.intermission) 1095 total = cl.completed_time - s->entertime; 1096 else 1097 total = realtime - s->entertime; 1098 minutes = (int)total/60; 1099 sprintf (num, "%4i", minutes); 1100 Draw_String ( x+64 , y, num); 1101 1102 // draw background 1103 top = s->topcolor; 1104 bottom = s->bottomcolor; 1105 top = Sbar_ColorForMap (top); 1106 bottom = Sbar_ColorForMap (bottom); 1107 1108 if (largegame) 1109 Draw_Fill ( x+104, y+1, 40, 3, top); 1110 else 1111 Draw_Fill ( x+104, y, 40, 4, top); 1112 Draw_Fill ( x+104, y+4, 40, 4, bottom); 1113 1114 // draw number 1115 f = s->frags; 1116 sprintf (num, "%3i",f); 1117 1118 Draw_Character ( x+112 , y, num[0]); 1119 Draw_Character ( x+120 , y, num[1]); 1120 Draw_Character ( x+128 , y, num[2]); 1121 1122 if (k == cl.playernum) 1123 { 1124 Draw_Character ( x + 104, y, 16); 1125 Draw_Character ( x + 136, y, 17); 1126 } 1127 1128 // team 1129 if (teamplay) 1130 { 1131 team[4] = 0; 1132 strncpy (team, Info_ValueForKey(s->userinfo, "team"), 4); 1133 Draw_String (x+152, y, team); 1134 } 1135 1136 // draw name 1137 if (teamplay) 1138 Draw_String (x+152+40, y, s->name); 1139 else 1140 Draw_String (x+152, y, s->name); 1141 1142 y += skip; 1143 } 1144 1145 if (y >= (int) (vid.height-10)) // we ran over the screen size, squish 1146 largegame = true; 1147 } 1148 1149 /* 1150 ================== 1151 Sbar_MiniDeathmatchOverlay 1152 1153 frags name 1154 frags team name 1155 displayed to right of status bar if there's room 1156 ================== 1157 */ 1158 void Sbar_MiniDeathmatchOverlay (void) 1159 { 1160 int i, k; 1161 int top, bottom; 1162 int x, y, f; 1163 char num[12]; 1164 player_info_t *s; 1165 int teamplay; 1166 char team[5]; 1167 int numlines; 1168 char name[16+1]; 1169 team_t *tm; 1170 1171 if (vid.width < 512 || !sb_lines) 1172 return; // not enuff room 1173 1174 teamplay = atoi(Info_ValueForKey(cl.serverinfo, "teamplay")); 1175 1176 scr_copyeverything = 1; 1177 scr_fullupdate = 0; 1178 1179 // scores 1180 Sbar_SortFrags (false); 1181 if (vid.width >= 640) 1182 Sbar_SortTeams(); 1183 1184 if (!scoreboardlines) 1185 return; // no one there? 1186 1187 // draw the text 1188 y = vid.height - sb_lines - 1; 1189 numlines = sb_lines/8; 1190 if (numlines < 3) 1191 return; // not enough room 1192 1193 // find us 1194 for (i=0 ; i < scoreboardlines; i++) 1195 if (fragsort[i] == cl.playernum) 1196 break; 1197 1198 if (i == scoreboardlines) // we're not there, we are probably a spectator, just display top 1199 i = 0; 1200 else // figure out start 1201 i = i - numlines/2; 1202 1203 if (i > scoreboardlines - numlines) 1204 i = scoreboardlines - numlines; 1205 if (i < 0) 1206 i = 0; 1207 1208 x = 324; 1209 1210 for (/* */ ; i < scoreboardlines && y < (int) (vid.height - 8 + 1); i++) 1211 { 1212 k = fragsort[i]; 1213 s = &cl.players[k]; 1214 if (!s->name[0]) 1215 continue; 1216 1217 // draw ping 1218 top = s->topcolor; 1219 bottom = s->bottomcolor; 1220 top = Sbar_ColorForMap (top); 1221 bottom = Sbar_ColorForMap (bottom); 1222 1223 Draw_Fill ( x, y+1, 40, 3, top); 1224 Draw_Fill ( x, y+4, 40, 4, bottom); 1225 1226 // draw number 1227 f = s->frags; 1228 sprintf (num, "%3i",f); 1229 1230 Draw_Character ( x+8 , y, num[0]); 1231 Draw_Character ( x+16, y, num[1]); 1232 Draw_Character ( x+24, y, num[2]); 1233 1234 if (k == cl.playernum) 1235 { 1236 Draw_Character ( x, y, 16); 1237 Draw_Character ( x + 32, y, 17); 1238 } 1239 1240 // team 1241 if (teamplay) 1242 { 1243 team[4] = 0; 1244 strncpy (team, Info_ValueForKey(s->userinfo, "team"), 4); 1245 Draw_String (x+48, y, team); 1246 } 1247 1248 // draw name 1249 name[16] = 0; 1250 strncpy(name, s->name, 16); 1251 if (teamplay) 1252 Draw_String (x+48+40, y, name); 1253 else 1254 Draw_String (x+48, y, name); 1255 y += 8; 1256 } 1257 1258 // draw teams if room 1259 if (vid.width < 640 || !teamplay) 1260 return; 1261 1262 // draw seperator 1263 x += 208; 1264 for (y = vid.height - sb_lines; y < (int) (vid.height - 6); y += 2) 1265 Draw_Character(x, y, 14); 1266 1267 x += 16; 1268 1269 y = vid.height - sb_lines; 1270 for (i=0 ; i < scoreboardteams && y <= (int) vid.height; i++) 1271 { 1272 k = teamsort[i]; 1273 tm = teams + k; 1274 1275 // draw pings 1276 team[4] = 0; 1277 strncpy (team, tm->team, 4); 1278 Draw_String (x, y, team); 1279 1280 // draw total 1281 sprintf (num, "%5i", tm->frags); 1282 Draw_String (x + 40, y, num); 1283 1284 if (!strncmp(Info_ValueForKey(cl.players[cl.playernum].userinfo, 1285 "team"), tm->team, 16)) { 1286 Draw_Character ( x - 8, y, 16); 1287 Draw_Character ( x + 32, y, 17); 1288 } 1289 1290 y += 8; 1291 } 1292 1293 } 1294 1295 1296 /* 1297 ================== 1298 Sbar_IntermissionOverlay 1299 1300 ================== 1301 */ 1302 void Sbar_IntermissionOverlay (void) 1303 { 1304 scr_copyeverything = 1; 1305 scr_fullupdate = 0; 1306 1307 if (atoi(Info_ValueForKey(cl.serverinfo, "teamplay")) > 0 && !sb_showscores) 1308 Sbar_TeamOverlay (); 1309 else 1310 Sbar_DeathmatchOverlay (0); 1311 } 1312 1313 1314 /* 1315 ================== 1316 Sbar_FinaleOverlay 1317 1318 ================== 1319 */ 1320 void Sbar_FinaleOverlay (void) 1321 { 1322 qpic_t *pic; 1323 1324 scr_copyeverything = 1; 1325 1326 pic = Draw_CachePic ("gfx/finale.lmp"); 1327 Draw_TransPic ( (vid.width-pic->width)/2, 16, pic); 1328 } 1329 1330 1331