st_stuff.c
1 // 2 // Copyright(C) 1993-1996 Id Software, Inc. 3 // Copyright(C) 2005-2014 Simon Howard 4 // 5 // This program is free software; you can redistribute it and/or 6 // modify it under the terms of the GNU General Public License 7 // as published by the Free Software Foundation; either version 2 8 // of the License, or (at your option) any later version. 9 // 10 // This program is distributed in the hope that it will be useful, 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU General Public License for more details. 14 // 15 // DESCRIPTION: 16 // Status bar code. 17 // Does the face/direction indicator animatin. 18 // Does palette indicators as well (red pain/berserk, bright pickup) 19 // 20 21 22 23 #include <stdio.h> 24 25 #include "i_system.h" 26 #include "i_video.h" 27 #include "z_zone.h" 28 #include "m_misc.h" 29 #include "m_random.h" 30 #include "w_wad.h" 31 32 #include "deh_main.h" 33 #include "deh_misc.h" 34 #include "doomdef.h" 35 #include "doomkeys.h" 36 37 #include "g_game.h" 38 39 #include "st_stuff.h" 40 #include "st_lib.h" 41 #include "r_local.h" 42 43 #include "p_local.h" 44 #include "p_inter.h" 45 46 #include "am_map.h" 47 #include "m_cheat.h" 48 49 #include "s_sound.h" 50 51 // Needs access to LFB. 52 #include "v_video.h" 53 54 // State. 55 #include "doomstat.h" 56 57 // Data. 58 #include "dstrings.h" 59 #include "sounds.h" 60 61 // 62 // STATUS BAR DATA 63 // 64 65 66 // Palette indices. 67 // For damage/bonus red-/gold-shifts 68 #define STARTREDPALS 1 69 #define STARTBONUSPALS 9 70 #define NUMREDPALS 8 71 #define NUMBONUSPALS 4 72 // Radiation suit, green shift. 73 #define RADIATIONPAL 13 74 75 // N/256*100% probability 76 // that the normal face state will change 77 #define ST_FACEPROBABILITY 96 78 79 // For Responder 80 #define ST_TOGGLECHAT KEY_ENTER 81 82 // Location of status bar 83 #define ST_X 0 84 #define ST_X2 104 85 86 #define ST_FX 143 87 #define ST_FY 169 88 89 // Should be set to patch width 90 // for tall numbers later on 91 #define ST_TALLNUMWIDTH (tallnum[0]->width) 92 93 // Number of status faces. 94 #define ST_NUMPAINFACES 5 95 #define ST_NUMSTRAIGHTFACES 3 96 #define ST_NUMTURNFACES 2 97 #define ST_NUMSPECIALFACES 3 98 99 #define ST_FACESTRIDE \ 100 (ST_NUMSTRAIGHTFACES+ST_NUMTURNFACES+ST_NUMSPECIALFACES) 101 102 #define ST_NUMEXTRAFACES 2 103 104 #define ST_NUMFACES \ 105 (ST_FACESTRIDE*ST_NUMPAINFACES+ST_NUMEXTRAFACES) 106 107 #define ST_TURNOFFSET (ST_NUMSTRAIGHTFACES) 108 #define ST_OUCHOFFSET (ST_TURNOFFSET + ST_NUMTURNFACES) 109 #define ST_EVILGRINOFFSET (ST_OUCHOFFSET + 1) 110 #define ST_RAMPAGEOFFSET (ST_EVILGRINOFFSET + 1) 111 #define ST_GODFACE (ST_NUMPAINFACES*ST_FACESTRIDE) 112 #define ST_DEADFACE (ST_GODFACE+1) 113 114 #define ST_FACESX 143 115 #define ST_FACESY 168 116 117 #define ST_EVILGRINCOUNT (2*TICRATE) 118 #define ST_STRAIGHTFACECOUNT (TICRATE/2) 119 #define ST_TURNCOUNT (1*TICRATE) 120 #define ST_OUCHCOUNT (1*TICRATE) 121 #define ST_RAMPAGEDELAY (2*TICRATE) 122 123 #define ST_MUCHPAIN 20 124 125 126 // Location and size of statistics, 127 // justified according to widget type. 128 // Problem is, within which space? STbar? Screen? 129 // Note: this could be read in by a lump. 130 // Problem is, is the stuff rendered 131 // into a buffer, 132 // or into the frame buffer? 133 134 // AMMO number pos. 135 #define ST_AMMOWIDTH 3 136 #define ST_AMMOX 44 137 #define ST_AMMOY 171 138 139 // HEALTH number pos. 140 #define ST_HEALTHWIDTH 3 141 #define ST_HEALTHX 90 142 #define ST_HEALTHY 171 143 144 // Weapon pos. 145 #define ST_ARMSX 111 146 #define ST_ARMSY 172 147 #define ST_ARMSBGX 104 148 #define ST_ARMSBGY 168 149 #define ST_ARMSXSPACE 12 150 #define ST_ARMSYSPACE 10 151 152 // Frags pos. 153 #define ST_FRAGSX 138 154 #define ST_FRAGSY 171 155 #define ST_FRAGSWIDTH 2 156 157 // ARMOR number pos. 158 #define ST_ARMORWIDTH 3 159 #define ST_ARMORX 221 160 #define ST_ARMORY 171 161 162 // Key icon positions. 163 #define ST_KEY0WIDTH 8 164 #define ST_KEY0HEIGHT 5 165 #define ST_KEY0X 239 166 #define ST_KEY0Y 171 167 #define ST_KEY1WIDTH ST_KEY0WIDTH 168 #define ST_KEY1X 239 169 #define ST_KEY1Y 181 170 #define ST_KEY2WIDTH ST_KEY0WIDTH 171 #define ST_KEY2X 239 172 #define ST_KEY2Y 191 173 174 // Ammunition counter. 175 #define ST_AMMO0WIDTH 3 176 #define ST_AMMO0HEIGHT 6 177 #define ST_AMMO0X 288 178 #define ST_AMMO0Y 173 179 #define ST_AMMO1WIDTH ST_AMMO0WIDTH 180 #define ST_AMMO1X 288 181 #define ST_AMMO1Y 179 182 #define ST_AMMO2WIDTH ST_AMMO0WIDTH 183 #define ST_AMMO2X 288 184 #define ST_AMMO2Y 191 185 #define ST_AMMO3WIDTH ST_AMMO0WIDTH 186 #define ST_AMMO3X 288 187 #define ST_AMMO3Y 185 188 189 // Indicate maximum ammunition. 190 // Only needed because backpack exists. 191 #define ST_MAXAMMO0WIDTH 3 192 #define ST_MAXAMMO0HEIGHT 5 193 #define ST_MAXAMMO0X 314 194 #define ST_MAXAMMO0Y 173 195 #define ST_MAXAMMO1WIDTH ST_MAXAMMO0WIDTH 196 #define ST_MAXAMMO1X 314 197 #define ST_MAXAMMO1Y 179 198 #define ST_MAXAMMO2WIDTH ST_MAXAMMO0WIDTH 199 #define ST_MAXAMMO2X 314 200 #define ST_MAXAMMO2Y 191 201 #define ST_MAXAMMO3WIDTH ST_MAXAMMO0WIDTH 202 #define ST_MAXAMMO3X 314 203 #define ST_MAXAMMO3Y 185 204 205 // pistol 206 #define ST_WEAPON0X 110 207 #define ST_WEAPON0Y 172 208 209 // shotgun 210 #define ST_WEAPON1X 122 211 #define ST_WEAPON1Y 172 212 213 // chain gun 214 #define ST_WEAPON2X 134 215 #define ST_WEAPON2Y 172 216 217 // missile launcher 218 #define ST_WEAPON3X 110 219 #define ST_WEAPON3Y 181 220 221 // plasma gun 222 #define ST_WEAPON4X 122 223 #define ST_WEAPON4Y 181 224 225 // bfg 226 #define ST_WEAPON5X 134 227 #define ST_WEAPON5Y 181 228 229 // WPNS title 230 #define ST_WPNSX 109 231 #define ST_WPNSY 191 232 233 // DETH title 234 #define ST_DETHX 109 235 #define ST_DETHY 191 236 237 //Incoming messages window location 238 //UNUSED 239 // #define ST_MSGTEXTX (viewwindowx) 240 // #define ST_MSGTEXTY (viewwindowy+viewheight-18) 241 #define ST_MSGTEXTX 0 242 #define ST_MSGTEXTY 0 243 // Dimensions given in characters. 244 #define ST_MSGWIDTH 52 245 // Or shall I say, in lines? 246 #define ST_MSGHEIGHT 1 247 248 #define ST_OUTTEXTX 0 249 #define ST_OUTTEXTY 6 250 251 // Width, in characters again. 252 #define ST_OUTWIDTH 52 253 // Height, in lines. 254 #define ST_OUTHEIGHT 1 255 256 #define ST_MAPTITLEX \ 257 (SCREENWIDTH - ST_MAPWIDTH * ST_CHATFONTWIDTH) 258 259 #define ST_MAPTITLEY 0 260 #define ST_MAPHEIGHT 1 261 262 // graphics are drawn to a backing screen and blitted to the real screen 263 byte *st_backing_screen; 264 265 // main player in game 266 static player_t* plyr; 267 268 // ST_Start() has just been called 269 static boolean st_firsttime; 270 271 // lump number for PLAYPAL 272 static int lu_palette; 273 274 // used for timing 275 static unsigned int st_clock; 276 277 // used for making messages go away 278 static int st_msgcounter=0; 279 280 // used when in chat 281 static st_chatstateenum_t st_chatstate; 282 283 // whether in automap or first-person 284 static st_stateenum_t st_gamestate; 285 286 // whether left-side main status bar is active 287 static boolean st_statusbaron; 288 289 // whether status bar chat is active 290 static boolean st_chat; 291 292 // value of st_chat before message popped up 293 static boolean st_oldchat; 294 295 // whether chat window has the cursor on 296 static boolean st_cursoron; 297 298 // !deathmatch 299 static boolean st_notdeathmatch; 300 301 // !deathmatch && st_statusbaron 302 static boolean st_armson; 303 304 // !deathmatch 305 static boolean st_fragson; 306 307 // main bar left 308 static patch_t* sbar; 309 310 // 0-9, tall numbers 311 static patch_t* tallnum[10]; 312 313 // tall % sign 314 static patch_t* tallpercent; 315 316 // 0-9, short, yellow (,different!) numbers 317 static patch_t* shortnum[10]; 318 319 // 3 key-cards, 3 skulls 320 static patch_t* keys[NUMCARDS]; 321 322 // face status patches 323 static patch_t* faces[ST_NUMFACES]; 324 325 // face background 326 static patch_t* faceback; 327 328 // main bar right 329 static patch_t* armsbg; 330 331 // weapon ownership patches 332 static patch_t* arms[6][2]; 333 334 // ready-weapon widget 335 static st_number_t w_ready; 336 337 // in deathmatch only, summary of frags stats 338 static st_number_t w_frags; 339 340 // health widget 341 static st_percent_t w_health; 342 343 // arms background 344 static st_binicon_t w_armsbg; 345 346 347 // weapon ownership widgets 348 static st_multicon_t w_arms[6]; 349 350 // face status widget 351 static st_multicon_t w_faces; 352 353 // keycard widgets 354 static st_multicon_t w_keyboxes[3]; 355 356 // armor widget 357 static st_percent_t w_armor; 358 359 // ammo widgets 360 static st_number_t w_ammo[4]; 361 362 // max ammo widgets 363 static st_number_t w_maxammo[4]; 364 365 366 367 // number of frags so far in deathmatch 368 static int st_fragscount; 369 370 // used to use appopriately pained face 371 static int st_oldhealth = -1; 372 373 // used for evil grin 374 static boolean oldweaponsowned[NUMWEAPONS]; 375 376 // count until face changes 377 static int st_facecount = 0; 378 379 // current face index, used by w_faces 380 static int st_faceindex = 0; 381 382 // holds key-type for each key box on bar 383 static int keyboxes[3]; 384 385 // a random number per tick 386 static int st_randomnumber; 387 388 cheatseq_t cheat_mus = CHEAT("idmus", 2); 389 cheatseq_t cheat_god = CHEAT("iddqd", 0); 390 cheatseq_t cheat_ammo = CHEAT("idkfa", 0); 391 cheatseq_t cheat_ammonokey = CHEAT("idfa", 0); 392 cheatseq_t cheat_noclip = CHEAT("idspispopd", 0); 393 cheatseq_t cheat_commercial_noclip = CHEAT("idclip", 0); 394 395 cheatseq_t cheat_powerup[7] = 396 { 397 CHEAT("idbeholdv", 0), 398 CHEAT("idbeholds", 0), 399 CHEAT("idbeholdi", 0), 400 CHEAT("idbeholdr", 0), 401 CHEAT("idbeholda", 0), 402 CHEAT("idbeholdl", 0), 403 CHEAT("idbehold", 0), 404 }; 405 406 cheatseq_t cheat_choppers = CHEAT("idchoppers", 0); 407 cheatseq_t cheat_clev = CHEAT("idclev", 2); 408 cheatseq_t cheat_mypos = CHEAT("idmypos", 0); 409 410 411 // 412 // STATUS BAR CODE 413 // 414 void ST_Stop(void); 415 416 void ST_refreshBackground(void) 417 { 418 419 if (st_statusbaron) 420 { 421 V_UseBuffer(st_backing_screen); 422 423 V_DrawPatch(ST_X, 0, sbar); 424 425 if (netgame) 426 V_DrawPatch(ST_FX, 0, faceback); 427 428 V_RestoreBuffer(); 429 430 V_CopyRect(ST_X, 0, st_backing_screen, ST_WIDTH, ST_HEIGHT, ST_X, ST_Y); 431 } 432 433 } 434 435 436 // Respond to keyboard input events, 437 // intercept cheats. 438 boolean 439 ST_Responder (event_t* ev) 440 { 441 int i; 442 443 // Filter automap on/off. 444 if (ev->type == ev_keyup 445 && ((ev->data1 & 0xffff0000) == AM_MSGHEADER)) 446 { 447 switch(ev->data1) 448 { 449 case AM_MSGENTERED: 450 st_gamestate = AutomapState; 451 st_firsttime = true; 452 break; 453 454 case AM_MSGEXITED: 455 // fprintf(stderr, "AM exited\n"); 456 st_gamestate = FirstPersonState; 457 break; 458 } 459 } 460 461 // if a user keypress... 462 else if (ev->type == ev_keydown) 463 { 464 if (!netgame && gameskill != sk_nightmare) 465 { 466 // 'dqd' cheat for toggleable god mode 467 if (cht_CheckCheat(&cheat_god, ev->data2)) 468 { 469 plyr->cheats ^= CF_GODMODE; 470 if (plyr->cheats & CF_GODMODE) 471 { 472 if (plyr->mo) 473 plyr->mo->health = 100; 474 475 plyr->health = deh_god_mode_health; 476 plyr->message = DEH_String(STSTR_DQDON); 477 } 478 else 479 plyr->message = DEH_String(STSTR_DQDOFF); 480 } 481 // 'fa' cheat for killer fucking arsenal 482 else if (cht_CheckCheat(&cheat_ammonokey, ev->data2)) 483 { 484 plyr->armorpoints = deh_idfa_armor; 485 plyr->armortype = deh_idfa_armor_class; 486 487 for (i=0;i<NUMWEAPONS;i++) 488 plyr->weaponowned[i] = true; 489 490 for (i=0;i<NUMAMMO;i++) 491 plyr->ammo[i] = plyr->maxammo[i]; 492 493 plyr->message = DEH_String(STSTR_FAADDED); 494 } 495 // 'kfa' cheat for key full ammo 496 else if (cht_CheckCheat(&cheat_ammo, ev->data2)) 497 { 498 plyr->armorpoints = deh_idkfa_armor; 499 plyr->armortype = deh_idkfa_armor_class; 500 501 for (i=0;i<NUMWEAPONS;i++) 502 plyr->weaponowned[i] = true; 503 504 for (i=0;i<NUMAMMO;i++) 505 plyr->ammo[i] = plyr->maxammo[i]; 506 507 for (i=0;i<NUMCARDS;i++) 508 plyr->cards[i] = true; 509 510 plyr->message = DEH_String(STSTR_KFAADDED); 511 } 512 // 'mus' cheat for changing music 513 else if (cht_CheckCheat(&cheat_mus, ev->data2)) 514 { 515 516 char buf[3]; 517 int musnum; 518 519 plyr->message = DEH_String(STSTR_MUS); 520 cht_GetParam(&cheat_mus, buf); 521 522 // Note: The original v1.9 had a bug that tried to play back 523 // the Doom II music regardless of gamemode. This was fixed 524 // in the Ultimate Doom executable so that it would work for 525 // the Doom 1 music as well. 526 527 if (gamemode == commercial || gameversion < exe_ultimate) 528 { 529 musnum = mus_runnin + (buf[0]-'0')*10 + buf[1]-'0' - 1; 530 531 if (((buf[0]-'0')*10 + buf[1]-'0') > 35) 532 plyr->message = DEH_String(STSTR_NOMUS); 533 else 534 S_ChangeMusic(musnum, 1); 535 } 536 else 537 { 538 musnum = mus_e1m1 + (buf[0]-'1')*9 + (buf[1]-'1'); 539 540 if (((buf[0]-'1')*9 + buf[1]-'1') > 31) 541 plyr->message = DEH_String(STSTR_NOMUS); 542 else 543 S_ChangeMusic(musnum, 1); 544 } 545 } 546 else if ( (logical_gamemission == doom 547 && cht_CheckCheat(&cheat_noclip, ev->data2)) 548 || (logical_gamemission != doom 549 && cht_CheckCheat(&cheat_commercial_noclip,ev->data2))) 550 { 551 // Noclip cheat. 552 // For Doom 1, use the idspipsopd cheat; for all others, use 553 // idclip 554 555 plyr->cheats ^= CF_NOCLIP; 556 557 if (plyr->cheats & CF_NOCLIP) 558 plyr->message = DEH_String(STSTR_NCON); 559 else 560 plyr->message = DEH_String(STSTR_NCOFF); 561 } 562 // 'behold?' power-up cheats 563 for (i=0;i<6;i++) 564 { 565 if (cht_CheckCheat(&cheat_powerup[i], ev->data2)) 566 { 567 if (!plyr->powers[i]) 568 P_GivePower( plyr, i); 569 else if (i!=pw_strength) 570 plyr->powers[i] = 1; 571 else 572 plyr->powers[i] = 0; 573 574 plyr->message = DEH_String(STSTR_BEHOLDX); 575 } 576 } 577 578 // 'behold' power-up menu 579 if (cht_CheckCheat(&cheat_powerup[6], ev->data2)) 580 { 581 plyr->message = DEH_String(STSTR_BEHOLD); 582 } 583 // 'choppers' invulnerability & chainsaw 584 else if (cht_CheckCheat(&cheat_choppers, ev->data2)) 585 { 586 plyr->weaponowned[wp_chainsaw] = true; 587 plyr->powers[pw_invulnerability] = true; 588 plyr->message = DEH_String(STSTR_CHOPPERS); 589 } 590 // 'mypos' for player position 591 else if (cht_CheckCheat(&cheat_mypos, ev->data2)) 592 { 593 static char buf[ST_MSGWIDTH]; 594 M_snprintf(buf, sizeof(buf), "ang=0x%x;x,y=(0x%x,0x%x)", 595 players[consoleplayer].mo->angle, 596 players[consoleplayer].mo->x, 597 players[consoleplayer].mo->y); 598 plyr->message = buf; 599 } 600 } 601 602 // 'clev' change-level cheat 603 if (!netgame && cht_CheckCheat(&cheat_clev, ev->data2)) 604 { 605 char buf[3]; 606 int epsd; 607 int map; 608 609 cht_GetParam(&cheat_clev, buf); 610 611 if (gamemode == commercial) 612 { 613 epsd = 1; 614 map = (buf[0] - '0')*10 + buf[1] - '0'; 615 } 616 else 617 { 618 epsd = buf[0] - '0'; 619 map = buf[1] - '0'; 620 } 621 622 // Chex.exe always warps to episode 1. 623 624 if (gameversion == exe_chex) 625 { 626 epsd = 1; 627 } 628 629 // Catch invalid maps. 630 if (epsd < 1) 631 return false; 632 633 if (map < 1) 634 return false; 635 636 // Ohmygod - this is not going to work. 637 if ((gamemode == retail) 638 && ((epsd > 4) || (map > 9))) 639 return false; 640 641 if ((gamemode == registered) 642 && ((epsd > 3) || (map > 9))) 643 return false; 644 645 if ((gamemode == shareware) 646 && ((epsd > 1) || (map > 9))) 647 return false; 648 649 // The source release has this check as map > 34. However, Vanilla 650 // Doom allows IDCLEV up to MAP40 even though it normally crashes. 651 if ((gamemode == commercial) 652 && (( epsd > 1) || (map > 40))) 653 return false; 654 655 // So be it. 656 plyr->message = DEH_String(STSTR_CLEV); 657 G_DeferedInitNew(gameskill, epsd, map); 658 } 659 } 660 return false; 661 } 662 663 664 665 int ST_calcPainOffset(void) 666 { 667 int health; 668 static int lastcalc; 669 static int oldhealth = -1; 670 671 health = plyr->health > 100 ? 100 : plyr->health; 672 673 if (health != oldhealth) 674 { 675 lastcalc = ST_FACESTRIDE * (((100 - health) * ST_NUMPAINFACES) / 101); 676 oldhealth = health; 677 } 678 return lastcalc; 679 } 680 681 682 // 683 // This is a not-very-pretty routine which handles 684 // the face states and their timing. 685 // the precedence of expressions is: 686 // dead > evil grin > turned head > straight ahead 687 // 688 void ST_updateFaceWidget(void) 689 { 690 int i; 691 angle_t badguyangle; 692 angle_t diffang; 693 static int lastattackdown = -1; 694 static int priority = 0; 695 boolean doevilgrin; 696 697 if (priority < 10) 698 { 699 // dead 700 if (!plyr->health) 701 { 702 priority = 9; 703 st_faceindex = ST_DEADFACE; 704 st_facecount = 1; 705 } 706 } 707 708 if (priority < 9) 709 { 710 if (plyr->bonuscount) 711 { 712 // picking up bonus 713 doevilgrin = false; 714 715 for (i=0;i<NUMWEAPONS;i++) 716 { 717 if (oldweaponsowned[i] != plyr->weaponowned[i]) 718 { 719 doevilgrin = true; 720 oldweaponsowned[i] = plyr->weaponowned[i]; 721 } 722 } 723 if (doevilgrin) 724 { 725 // evil grin if just picked up weapon 726 priority = 8; 727 st_facecount = ST_EVILGRINCOUNT; 728 st_faceindex = ST_calcPainOffset() + ST_EVILGRINOFFSET; 729 } 730 } 731 732 } 733 734 if (priority < 8) 735 { 736 if (plyr->damagecount 737 && plyr->attacker 738 && plyr->attacker != plyr->mo) 739 { 740 // being attacked 741 priority = 7; 742 743 if (plyr->health - st_oldhealth > ST_MUCHPAIN) 744 { 745 st_facecount = ST_TURNCOUNT; 746 st_faceindex = ST_calcPainOffset() + ST_OUCHOFFSET; 747 } 748 else 749 { 750 badguyangle = R_PointToAngle2(plyr->mo->x, 751 plyr->mo->y, 752 plyr->attacker->x, 753 plyr->attacker->y); 754 755 if (badguyangle > plyr->mo->angle) 756 { 757 // whether right or left 758 diffang = badguyangle - plyr->mo->angle; 759 i = diffang > ANG180; 760 } 761 else 762 { 763 // whether left or right 764 diffang = plyr->mo->angle - badguyangle; 765 i = diffang <= ANG180; 766 } // confusing, aint it? 767 768 769 st_facecount = ST_TURNCOUNT; 770 st_faceindex = ST_calcPainOffset(); 771 772 if (diffang < ANG45) 773 { 774 // head-on 775 st_faceindex += ST_RAMPAGEOFFSET; 776 } 777 else if (i) 778 { 779 // turn face right 780 st_faceindex += ST_TURNOFFSET; 781 } 782 else 783 { 784 // turn face left 785 st_faceindex += ST_TURNOFFSET+1; 786 } 787 } 788 } 789 } 790 791 if (priority < 7) 792 { 793 // getting hurt because of your own damn stupidity 794 if (plyr->damagecount) 795 { 796 if (plyr->health - st_oldhealth > ST_MUCHPAIN) 797 { 798 priority = 7; 799 st_facecount = ST_TURNCOUNT; 800 st_faceindex = ST_calcPainOffset() + ST_OUCHOFFSET; 801 } 802 else 803 { 804 priority = 6; 805 st_facecount = ST_TURNCOUNT; 806 st_faceindex = ST_calcPainOffset() + ST_RAMPAGEOFFSET; 807 } 808 809 } 810 811 } 812 813 if (priority < 6) 814 { 815 // rapid firing 816 if (plyr->attackdown) 817 { 818 if (lastattackdown==-1) 819 lastattackdown = ST_RAMPAGEDELAY; 820 else if (!--lastattackdown) 821 { 822 priority = 5; 823 st_faceindex = ST_calcPainOffset() + ST_RAMPAGEOFFSET; 824 st_facecount = 1; 825 lastattackdown = 1; 826 } 827 } 828 else 829 lastattackdown = -1; 830 831 } 832 833 if (priority < 5) 834 { 835 // invulnerability 836 if ((plyr->cheats & CF_GODMODE) 837 || plyr->powers[pw_invulnerability]) 838 { 839 priority = 4; 840 841 st_faceindex = ST_GODFACE; 842 st_facecount = 1; 843 844 } 845 846 } 847 848 // look left or look right if the facecount has timed out 849 if (!st_facecount) 850 { 851 st_faceindex = ST_calcPainOffset() + (st_randomnumber % 3); 852 st_facecount = ST_STRAIGHTFACECOUNT; 853 priority = 0; 854 } 855 856 st_facecount--; 857 858 } 859 860 void ST_updateWidgets(void) 861 { 862 static int largeammo = 1994; // means "n/a" 863 int i; 864 865 // must redirect the pointer if the ready weapon has changed. 866 // if (w_ready.data != plyr->readyweapon) 867 // { 868 if (weaponinfo[plyr->readyweapon].ammo == am_noammo) 869 w_ready.num = &largeammo; 870 else 871 w_ready.num = &plyr->ammo[weaponinfo[plyr->readyweapon].ammo]; 872 //{ 873 // static int tic=0; 874 // static int dir=-1; 875 // if (!(tic&15)) 876 // plyr->ammo[weaponinfo[plyr->readyweapon].ammo]+=dir; 877 // if (plyr->ammo[weaponinfo[plyr->readyweapon].ammo] == -100) 878 // dir = 1; 879 // tic++; 880 // } 881 w_ready.data = plyr->readyweapon; 882 883 // if (*w_ready.on) 884 // STlib_updateNum(&w_ready, true); 885 // refresh weapon change 886 // } 887 888 // update keycard multiple widgets 889 for (i=0;i<3;i++) 890 { 891 keyboxes[i] = plyr->cards[i] ? i : -1; 892 893 if (plyr->cards[i+3]) 894 keyboxes[i] = i+3; 895 } 896 897 // refresh everything if this is him coming back to life 898 ST_updateFaceWidget(); 899 900 // used by the w_armsbg widget 901 st_notdeathmatch = !deathmatch; 902 903 // used by w_arms[] widgets 904 st_armson = st_statusbaron && !deathmatch; 905 906 // used by w_frags widget 907 st_fragson = deathmatch && st_statusbaron; 908 st_fragscount = 0; 909 910 for (i=0 ; i<MAXPLAYERS ; i++) 911 { 912 if (i != consoleplayer) 913 st_fragscount += plyr->frags[i]; 914 else 915 st_fragscount -= plyr->frags[i]; 916 } 917 918 // get rid of chat window if up because of message 919 if (!--st_msgcounter) 920 st_chat = st_oldchat; 921 922 } 923 924 void ST_Ticker (void) 925 { 926 927 st_clock++; 928 st_randomnumber = M_Random(); 929 ST_updateWidgets(); 930 st_oldhealth = plyr->health; 931 932 } 933 934 static int st_palette = 0; 935 936 void ST_doPaletteStuff(void) 937 { 938 939 int palette; 940 byte* pal; 941 int cnt; 942 int bzc; 943 944 cnt = plyr->damagecount; 945 946 if (plyr->powers[pw_strength]) 947 { 948 // slowly fade the berzerk out 949 bzc = 12 - (plyr->powers[pw_strength]>>6); 950 951 if (bzc > cnt) 952 cnt = bzc; 953 } 954 955 if (cnt) 956 { 957 palette = (cnt+7)>>3; 958 959 if (palette >= NUMREDPALS) 960 palette = NUMREDPALS-1; 961 962 palette += STARTREDPALS; 963 } 964 965 else if (plyr->bonuscount) 966 { 967 palette = (plyr->bonuscount+7)>>3; 968 969 if (palette >= NUMBONUSPALS) 970 palette = NUMBONUSPALS-1; 971 972 palette += STARTBONUSPALS; 973 } 974 975 else if ( plyr->powers[pw_ironfeet] > 4*32 976 || plyr->powers[pw_ironfeet]&8) 977 palette = RADIATIONPAL; 978 else 979 palette = 0; 980 981 // In Chex Quest, the player never sees red. Instead, the 982 // radiation suit palette is used to tint the screen green, 983 // as though the player is being covered in goo by an 984 // attacking flemoid. 985 986 if (gameversion == exe_chex 987 && palette >= STARTREDPALS && palette < STARTREDPALS + NUMREDPALS) 988 { 989 palette = RADIATIONPAL; 990 } 991 992 if (palette != st_palette) 993 { 994 st_palette = palette; 995 pal = (byte *) W_CacheLumpNum (lu_palette, PU_CACHE)+palette*768; 996 I_SetPalette (pal); 997 } 998 999 } 1000 1001 void ST_drawWidgets(boolean refresh) 1002 { 1003 int i; 1004 1005 // used by w_arms[] widgets 1006 st_armson = st_statusbaron && !deathmatch; 1007 1008 // used by w_frags widget 1009 st_fragson = deathmatch && st_statusbaron; 1010 1011 STlib_updateNum(&w_ready, refresh); 1012 1013 for (i=0;i<4;i++) 1014 { 1015 STlib_updateNum(&w_ammo[i], refresh); 1016 STlib_updateNum(&w_maxammo[i], refresh); 1017 } 1018 1019 STlib_updatePercent(&w_health, refresh); 1020 STlib_updatePercent(&w_armor, refresh); 1021 1022 STlib_updateBinIcon(&w_armsbg, refresh); 1023 1024 for (i=0;i<6;i++) 1025 STlib_updateMultIcon(&w_arms[i], refresh); 1026 1027 STlib_updateMultIcon(&w_faces, refresh); 1028 1029 for (i=0;i<3;i++) 1030 STlib_updateMultIcon(&w_keyboxes[i], refresh); 1031 1032 STlib_updateNum(&w_frags, refresh); 1033 1034 } 1035 1036 void ST_doRefresh(void) 1037 { 1038 1039 st_firsttime = false; 1040 1041 // draw status bar background to off-screen buff 1042 ST_refreshBackground(); 1043 1044 // and refresh all widgets 1045 ST_drawWidgets(true); 1046 1047 } 1048 1049 void ST_diffDraw(void) 1050 { 1051 // update all widgets 1052 ST_drawWidgets(false); 1053 } 1054 1055 void ST_Drawer (boolean fullscreen, boolean refresh) 1056 { 1057 1058 st_statusbaron = (!fullscreen) || automapactive; 1059 st_firsttime = st_firsttime || refresh; 1060 1061 // Do red-/gold-shifts from damage/items 1062 ST_doPaletteStuff(); 1063 1064 // If just after ST_Start(), refresh all 1065 if (st_firsttime) ST_doRefresh(); 1066 // Otherwise, update as little as possible 1067 else ST_diffDraw(); 1068 1069 } 1070 1071 typedef void (*load_callback_t)(char *lumpname, patch_t **variable); 1072 1073 // Iterates through all graphics to be loaded or unloaded, along with 1074 // the variable they use, invoking the specified callback function. 1075 1076 static void ST_loadUnloadGraphics(load_callback_t callback) 1077 { 1078 1079 int i; 1080 int j; 1081 int facenum; 1082 1083 char namebuf[9]; 1084 1085 // Load the numbers, tall and short 1086 for (i=0;i<10;i++) 1087 { 1088 DEH_snprintf(namebuf, 9, "STTNUM%d", i); 1089 callback(namebuf, &tallnum[i]); 1090 1091 DEH_snprintf(namebuf, 9, "STYSNUM%d", i); 1092 callback(namebuf, &shortnum[i]); 1093 } 1094 1095 // Load percent key. 1096 //Note: why not load STMINUS here, too? 1097 1098 callback(DEH_String("STTPRCNT"), &tallpercent); 1099 1100 // key cards 1101 for (i=0;i<NUMCARDS;i++) 1102 { 1103 DEH_snprintf(namebuf, 9, "STKEYS%d", i); 1104 callback(namebuf, &keys[i]); 1105 } 1106 1107 // arms background 1108 callback(DEH_String("STARMS"), &armsbg); 1109 1110 // arms ownership widgets 1111 for (i=0; i<6; i++) 1112 { 1113 DEH_snprintf(namebuf, 9, "STGNUM%d", i+2); 1114 1115 // gray # 1116 callback(namebuf, &arms[i][0]); 1117 1118 // yellow # 1119 arms[i][1] = shortnum[i+2]; 1120 } 1121 1122 // face backgrounds for different color players 1123 DEH_snprintf(namebuf, 9, "STFB%d", consoleplayer); 1124 callback(namebuf, &faceback); 1125 1126 // status bar background bits 1127 callback(DEH_String("STBAR"), &sbar); 1128 1129 // face states 1130 facenum = 0; 1131 for (i=0; i<ST_NUMPAINFACES; i++) 1132 { 1133 for (j=0; j<ST_NUMSTRAIGHTFACES; j++) 1134 { 1135 DEH_snprintf(namebuf, 9, "STFST%d%d", i, j); 1136 callback(namebuf, &faces[facenum]); 1137 ++facenum; 1138 } 1139 DEH_snprintf(namebuf, 9, "STFTR%d0", i); // turn right 1140 callback(namebuf, &faces[facenum]); 1141 ++facenum; 1142 DEH_snprintf(namebuf, 9, "STFTL%d0", i); // turn left 1143 callback(namebuf, &faces[facenum]); 1144 ++facenum; 1145 DEH_snprintf(namebuf, 9, "STFOUCH%d", i); // ouch! 1146 callback(namebuf, &faces[facenum]); 1147 ++facenum; 1148 DEH_snprintf(namebuf, 9, "STFEVL%d", i); // evil grin ;) 1149 callback(namebuf, &faces[facenum]); 1150 ++facenum; 1151 DEH_snprintf(namebuf, 9, "STFKILL%d", i); // pissed off 1152 callback(namebuf, &faces[facenum]); 1153 ++facenum; 1154 } 1155 1156 callback(DEH_String("STFGOD0"), &faces[facenum]); 1157 ++facenum; 1158 callback(DEH_String("STFDEAD0"), &faces[facenum]); 1159 ++facenum; 1160 } 1161 1162 static void ST_loadCallback(char *lumpname, patch_t **variable) 1163 { 1164 *variable = W_CacheLumpName(lumpname, PU_STATIC); 1165 } 1166 1167 void ST_loadGraphics(void) 1168 { 1169 ST_loadUnloadGraphics(ST_loadCallback); 1170 } 1171 1172 void ST_loadData(void) 1173 { 1174 lu_palette = W_GetNumForName (DEH_String("PLAYPAL")); 1175 ST_loadGraphics(); 1176 } 1177 1178 static void ST_unloadCallback(char *lumpname, patch_t **variable) 1179 { 1180 W_ReleaseLumpName(lumpname); 1181 *variable = NULL; 1182 } 1183 1184 void ST_unloadGraphics(void) 1185 { 1186 ST_loadUnloadGraphics(ST_unloadCallback); 1187 } 1188 1189 void ST_unloadData(void) 1190 { 1191 ST_unloadGraphics(); 1192 } 1193 1194 void ST_initData(void) 1195 { 1196 1197 int i; 1198 1199 st_firsttime = true; 1200 plyr = &players[consoleplayer]; 1201 1202 st_clock = 0; 1203 st_chatstate = StartChatState; 1204 st_gamestate = FirstPersonState; 1205 1206 st_statusbaron = true; 1207 st_oldchat = st_chat = false; 1208 st_cursoron = false; 1209 1210 st_faceindex = 0; 1211 st_palette = -1; 1212 1213 st_oldhealth = -1; 1214 1215 for (i=0;i<NUMWEAPONS;i++) 1216 oldweaponsowned[i] = plyr->weaponowned[i]; 1217 1218 for (i=0;i<3;i++) 1219 keyboxes[i] = -1; 1220 1221 STlib_init(); 1222 1223 } 1224 1225 1226 1227 void ST_createWidgets(void) 1228 { 1229 1230 int i; 1231 1232 // ready weapon ammo 1233 STlib_initNum(&w_ready, 1234 ST_AMMOX, 1235 ST_AMMOY, 1236 tallnum, 1237 &plyr->ammo[weaponinfo[plyr->readyweapon].ammo], 1238 &st_statusbaron, 1239 ST_AMMOWIDTH ); 1240 1241 // the last weapon type 1242 w_ready.data = plyr->readyweapon; 1243 1244 // health percentage 1245 STlib_initPercent(&w_health, 1246 ST_HEALTHX, 1247 ST_HEALTHY, 1248 tallnum, 1249 &plyr->health, 1250 &st_statusbaron, 1251 tallpercent); 1252 1253 // arms background 1254 STlib_initBinIcon(&w_armsbg, 1255 ST_ARMSBGX, 1256 ST_ARMSBGY, 1257 armsbg, 1258 &st_notdeathmatch, 1259 &st_statusbaron); 1260 1261 // weapons owned 1262 for(i=0;i<6;i++) 1263 { 1264 STlib_initMultIcon(&w_arms[i], 1265 ST_ARMSX+(i%3)*ST_ARMSXSPACE, 1266 ST_ARMSY+(i/3)*ST_ARMSYSPACE, 1267 arms[i], (int *) &plyr->weaponowned[i+1], 1268 &st_armson); 1269 } 1270 1271 // frags sum 1272 STlib_initNum(&w_frags, 1273 ST_FRAGSX, 1274 ST_FRAGSY, 1275 tallnum, 1276 &st_fragscount, 1277 &st_fragson, 1278 ST_FRAGSWIDTH); 1279 1280 // faces 1281 STlib_initMultIcon(&w_faces, 1282 ST_FACESX, 1283 ST_FACESY, 1284 faces, 1285 &st_faceindex, 1286 &st_statusbaron); 1287 1288 // armor percentage - should be colored later 1289 STlib_initPercent(&w_armor, 1290 ST_ARMORX, 1291 ST_ARMORY, 1292 tallnum, 1293 &plyr->armorpoints, 1294 &st_statusbaron, tallpercent); 1295 1296 // keyboxes 0-2 1297 STlib_initMultIcon(&w_keyboxes[0], 1298 ST_KEY0X, 1299 ST_KEY0Y, 1300 keys, 1301 &keyboxes[0], 1302 &st_statusbaron); 1303 1304 STlib_initMultIcon(&w_keyboxes[1], 1305 ST_KEY1X, 1306 ST_KEY1Y, 1307 keys, 1308 &keyboxes[1], 1309 &st_statusbaron); 1310 1311 STlib_initMultIcon(&w_keyboxes[2], 1312 ST_KEY2X, 1313 ST_KEY2Y, 1314 keys, 1315 &keyboxes[2], 1316 &st_statusbaron); 1317 1318 // ammo count (all four kinds) 1319 STlib_initNum(&w_ammo[0], 1320 ST_AMMO0X, 1321 ST_AMMO0Y, 1322 shortnum, 1323 &plyr->ammo[0], 1324 &st_statusbaron, 1325 ST_AMMO0WIDTH); 1326 1327 STlib_initNum(&w_ammo[1], 1328 ST_AMMO1X, 1329 ST_AMMO1Y, 1330 shortnum, 1331 &plyr->ammo[1], 1332 &st_statusbaron, 1333 ST_AMMO1WIDTH); 1334 1335 STlib_initNum(&w_ammo[2], 1336 ST_AMMO2X, 1337 ST_AMMO2Y, 1338 shortnum, 1339 &plyr->ammo[2], 1340 &st_statusbaron, 1341 ST_AMMO2WIDTH); 1342 1343 STlib_initNum(&w_ammo[3], 1344 ST_AMMO3X, 1345 ST_AMMO3Y, 1346 shortnum, 1347 &plyr->ammo[3], 1348 &st_statusbaron, 1349 ST_AMMO3WIDTH); 1350 1351 // max ammo count (all four kinds) 1352 STlib_initNum(&w_maxammo[0], 1353 ST_MAXAMMO0X, 1354 ST_MAXAMMO0Y, 1355 shortnum, 1356 &plyr->maxammo[0], 1357 &st_statusbaron, 1358 ST_MAXAMMO0WIDTH); 1359 1360 STlib_initNum(&w_maxammo[1], 1361 ST_MAXAMMO1X, 1362 ST_MAXAMMO1Y, 1363 shortnum, 1364 &plyr->maxammo[1], 1365 &st_statusbaron, 1366 ST_MAXAMMO1WIDTH); 1367 1368 STlib_initNum(&w_maxammo[2], 1369 ST_MAXAMMO2X, 1370 ST_MAXAMMO2Y, 1371 shortnum, 1372 &plyr->maxammo[2], 1373 &st_statusbaron, 1374 ST_MAXAMMO2WIDTH); 1375 1376 STlib_initNum(&w_maxammo[3], 1377 ST_MAXAMMO3X, 1378 ST_MAXAMMO3Y, 1379 shortnum, 1380 &plyr->maxammo[3], 1381 &st_statusbaron, 1382 ST_MAXAMMO3WIDTH); 1383 1384 } 1385 1386 static boolean st_stopped = true; 1387 1388 1389 void ST_Start (void) 1390 { 1391 1392 if (!st_stopped) 1393 ST_Stop(); 1394 1395 ST_initData(); 1396 ST_createWidgets(); 1397 st_stopped = false; 1398 1399 } 1400 1401 void ST_Stop (void) 1402 { 1403 if (st_stopped) 1404 return; 1405 1406 I_SetPalette (W_CacheLumpNum (lu_palette, PU_CACHE)); 1407 1408 st_stopped = true; 1409 } 1410 1411 void ST_Init (void) 1412 { 1413 ST_loadData(); 1414 st_backing_screen = (byte *) Z_Malloc(ST_WIDTH * ST_HEIGHT, PU_STATIC, 0); 1415 } 1416