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