A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita audio rust zig deno mpris rockbox mpd
at master 1984 lines 50 kB view raw
1/* Emacs style mode select -*- C++ -*- 2 *----------------------------------------------------------------------------- 3 * 4 * 5 * PrBoom a Doom port merged with LxDoom and LSDLDoom 6 * based on BOOM, a modified and improved DOOM engine 7 * Copyright (C) 1999 by 8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman 9 * Copyright (C) 1999-2000 by 10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze 11 * 12 * This program is free software; you can redistribute it and/or 13 * modify it under the terms of the GNU General Public License 14 * as published by the Free Software Foundation; either version 2 15 * of the License, or (at your option) any later version. 16 * 17 * This program is distributed in the hope that it will be useful, 18 * but WITHOUT ANY WARRANTY; without even the implied warranty of 19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 * GNU General Public License for more details. 21 * 22 * You should have received a copy of the GNU General Public License 23 * along with this program; if not, write to the Free Software 24 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 25 * 02111-1307, USA. 26 * 27 * DESCRIPTION: 28 * Intermission screens. 29 * 30 *----------------------------------------------------------------------------- 31 */ 32 33#include "doomstat.h" 34#include "m_random.h" 35#include "w_wad.h" 36#include "g_game.h" 37#include "r_main.h" 38#include "v_video.h" 39#include "wi_stuff.h" 40#include "s_sound.h" 41#include "sounds.h" 42#include "m_swap.h" 43#include "r_draw.h" 44 45// 46// Data needed to add patches to full screen intermission pics. 47// Patches are statistics messages, and animations. 48// Loads of by-pixel layout and placement, offsets etc. 49// 50 51// 52// Different vetween registered DOOM (1994) and 53// Ultimate DOOM - Final edition (retail, 1995?). 54// This is supposedly ignored for commercial 55// release (aka DOOM II), which had 34 maps 56// in one episode. So there. 57#define NUMEPISODES 4 58#define NUMMAPS 9 59 60 61// Not used 62// in tics 63//U #define PAUSELEN (TICRATE*2) 64//U #define SCORESTEP 100 65//U #define ANIMPERIOD 32 66// pixel distance from "(YOU)" to "PLAYER N" 67//U #define STARDIST 10 68//U #define WK 1 69 70 71// GLOBAL LOCATIONS 72#define WI_TITLEY 2 73#define WI_SPACINGY 33 74 75// SINGLE-PLAYER STUFF 76#define SP_STATSX 50 77#define SP_STATSY 50 78 79#define SP_TIMEX 8 80// proff/nicolas 09/20/98 -- changed for hi-res 81#define SP_TIMEY 160 82//#define SP_TIMEY (SCREENHEIGHT-32) 83 84 85// NET GAME STUFF 86#define NG_STATSY 50 87#define NG_STATSX (32 + V_NamePatchWidth(star)/2 + 32*!dofrags) 88 89#define NG_SPACINGX 64 90 91 92// Used to display the frags matrix at endgame 93// DEATHMATCH STUFF 94#define DM_MATRIXX 42 95#define DM_MATRIXY 68 96 97#define DM_SPACINGX 40 98 99#define DM_TOTALSX 269 100 101#define DM_KILLERSX 10 102#define DM_KILLERSY 100 103#define DM_VICTIMSX 5 104#define DM_VICTIMSY 50 105 106 107// These animation variables, structures, etc. are used for the 108// DOOM/Ultimate DOOM intermission screen animations. This is 109// totally different from any sprite or texture/flat animations 110enum 111{ 112 ANIM_ALWAYS, // determined by patch entry 113 ANIM_RANDOM, // occasional 114 ANIM_LEVEL // continuous 115}; 116typedef unsigned animenum_t; 117 118typedef struct 119{ 120 int x; // x/y coordinate pair structure 121 int y; 122} point_t; 123 124 125// 126// Animation. 127// There is another anim_t used in p_spec. 128// 129typedef struct 130{ 131 animenum_t type; 132 133 // period in tics between animations 134 int period; 135 136 // number of animation frames 137 int nanims; 138 139 // location of animation 140 point_t loc; 141 142 // ALWAYS: n/a, 143 // RANDOM: period deviation (<256), 144 // LEVEL: level 145 int data1; 146 147 // ALWAYS: n/a, 148 // RANDOM: random base period, 149 // LEVEL: n/a 150 int data2; 151 152 /* actual graphics for frames of animations 153 * cphipps - const 154 */ 155 const patch_t* p[3]; 156 157 // following must be initialized to zero before use! 158 159 // next value of bcnt (used in conjunction with period) 160 int nexttic; 161 162 // last drawn animation frame 163 int lastdrawn; 164 165 // next frame number to animate 166 int ctr; 167 168 // used by RANDOM and LEVEL when animating 169 int state; 170} anim_t; 171 172 173static point_t lnodes[NUMEPISODES][NUMMAPS] = 174 { 175 // Episode 0 World Map 176 { 177 { 185, 164 }, // location of level 0 (CJ) 178 { 148, 143 }, // location of level 1 (CJ) 179 { 69, 122 }, // location of level 2 (CJ) 180 { 209, 102 }, // location of level 3 (CJ) 181 { 116, 89 }, // location of level 4 (CJ) 182 { 166, 55 }, // location of level 5 (CJ) 183 { 71, 56 }, // location of level 6 (CJ) 184 { 135, 29 }, // location of level 7 (CJ) 185 { 71, 24 } // location of level 8 (CJ) 186 }, 187 188 // Episode 1 World Map should go here 189 { 190 { 254, 25 }, // location of level 0 (CJ) 191 { 97, 50 }, // location of level 1 (CJ) 192 { 188, 64 }, // location of level 2 (CJ) 193 { 128, 78 }, // location of level 3 (CJ) 194 { 214, 92 }, // location of level 4 (CJ) 195 { 133, 130 }, // location of level 5 (CJ) 196 { 208, 136 }, // location of level 6 (CJ) 197 { 148, 140 }, // location of level 7 (CJ) 198 { 235, 158 } // location of level 8 (CJ) 199 }, 200 201 // Episode 2 World Map should go here 202 { 203 { 156, 168 }, // location of level 0 (CJ) 204 { 48, 154 }, // location of level 1 (CJ) 205 { 174, 95 }, // location of level 2 (CJ) 206 { 265, 75 }, // location of level 3 (CJ) 207 { 130, 48 }, // location of level 4 (CJ) 208 { 279, 23 }, // location of level 5 (CJ) 209 { 198, 48 }, // location of level 6 (CJ) 210 { 140, 25 }, // location of level 7 (CJ) 211 { 281, 136 } // location of level 8 (CJ) 212 } 213 214 }; 215 216 217// 218// Animation locations for episode 0 (1). 219// Using patches saves a lot of space, 220// as they replace 320x200 full screen frames. 221// 222static anim_t epsd0animinfo[] = 223 { 224 { ANIM_ALWAYS, TICRATE/3, 3, { 224, 104 }, 0, 0, { 0, 0, 0 }, 0, 0, 0, 0 }, 225 { ANIM_ALWAYS, TICRATE/3, 3, { 184, 160 }, 0, 0, { 0, 0, 0 }, 0, 0, 0, 0 }, 226 { ANIM_ALWAYS, TICRATE/3, 3, { 112, 136 }, 0, 0, { 0, 0, 0 }, 0, 0, 0, 0 }, 227 { ANIM_ALWAYS, TICRATE/3, 3, { 72, 112 }, 0, 0, { 0, 0, 0 }, 0, 0, 0, 0 }, 228 { ANIM_ALWAYS, TICRATE/3, 3, { 88, 96 }, 0, 0, { 0, 0, 0 }, 0, 0, 0, 0 }, 229 { ANIM_ALWAYS, TICRATE/3, 3, { 64, 48 }, 0, 0, { 0, 0, 0 }, 0, 0, 0, 0 }, 230 { ANIM_ALWAYS, TICRATE/3, 3, { 192, 40 }, 0, 0, { 0, 0, 0 }, 0, 0, 0, 0 }, 231 { ANIM_ALWAYS, TICRATE/3, 3, { 136, 16 }, 0, 0, { 0, 0, 0 }, 0, 0, 0, 0 }, 232 { ANIM_ALWAYS, TICRATE/3, 3, { 80, 16 }, 0, 0, { 0, 0, 0 }, 0, 0, 0, 0 }, 233 { ANIM_ALWAYS, TICRATE/3, 3, { 64, 24 }, 0, 0, { 0, 0, 0 }, 0, 0, 0, 0 } 234 }; 235 236static anim_t epsd1animinfo[] = 237 { 238 { ANIM_LEVEL, TICRATE/3, 1, { 128, 136 }, 1, 0, { 0, 0, 0 }, 0, 0, 0, 0 }, 239 { ANIM_LEVEL, TICRATE/3, 1, { 128, 136 }, 2, 0, { 0, 0, 0 }, 0, 0, 0, 0 }, 240 { ANIM_LEVEL, TICRATE/3, 1, { 128, 136 }, 3, 0, { 0, 0, 0 }, 0, 0, 0, 0 }, 241 { ANIM_LEVEL, TICRATE/3, 1, { 128, 136 }, 4, 0, { 0, 0, 0 }, 0, 0, 0, 0 }, 242 { ANIM_LEVEL, TICRATE/3, 1, { 128, 136 }, 5, 0, { 0, 0, 0 }, 0, 0, 0, 0 }, 243 { ANIM_LEVEL, TICRATE/3, 1, { 128, 136 }, 6, 0, { 0, 0, 0 }, 0, 0, 0, 0 }, 244 { ANIM_LEVEL, TICRATE/3, 1, { 128, 136 }, 7, 0, { 0, 0, 0 }, 0, 0, 0, 0 }, 245 { ANIM_LEVEL, TICRATE/3, 3, { 192, 144 }, 8, 0, { 0, 0, 0 }, 0, 0, 0, 0 }, 246 { ANIM_LEVEL, TICRATE/3, 1, { 128, 136 }, 8, 0, { 0, 0, 0 }, 0, 0, 0, 0 } 247 }; 248 249static anim_t epsd2animinfo[] = 250 { 251 { ANIM_ALWAYS, TICRATE/3, 3, { 104, 168 }, 0, 0, { 0, 0, 0 }, 0, 0, 0, 0 }, 252 { ANIM_ALWAYS, TICRATE/3, 3, { 40, 136 }, 0, 0, { 0, 0, 0 }, 0, 0, 0, 0 }, 253 { ANIM_ALWAYS, TICRATE/3, 3, { 160, 96 }, 0, 0, { 0, 0, 0 }, 0, 0, 0, 0 }, 254 { ANIM_ALWAYS, TICRATE/3, 3, { 104, 80 }, 0, 0, { 0, 0, 0 }, 0, 0, 0, 0 }, 255 { ANIM_ALWAYS, TICRATE/3, 3, { 120, 32 }, 0, 0, { 0, 0, 0 }, 0, 0, 0, 0 }, 256 { ANIM_ALWAYS, TICRATE/4, 3, { 40, 0 }, 0, 0, { 0, 0, 0 }, 0, 0, 0, 0 } 257 }; 258 259static int NUMANIMS[NUMEPISODES] = 260 { 261 sizeof(epsd0animinfo)/sizeof(anim_t), 262 sizeof(epsd1animinfo)/sizeof(anim_t), 263 sizeof(epsd2animinfo)/sizeof(anim_t) 264 }; 265 266static anim_t *anims[NUMEPISODES] = 267 { 268 epsd0animinfo, 269 epsd1animinfo, 270 epsd2animinfo 271 }; 272 273 274// 275// GENERAL DATA 276// 277 278// 279// Locally used stuff. 280// 281#define FB 0 282 283 284// States for single-player 285#define SP_KILLS 0 286#define SP_ITEMS 2 287#define SP_SECRET 4 288#define SP_FRAGS 6 289#define SP_TIME 8 290#define SP_PAR ST_TIME 291 292#define SP_PAUSE 1 293 294// in seconds 295#define SHOWNEXTLOCDELAY 4 296//#define SHOWLASTLOCDELAY SHOWNEXTLOCDELAY 297 298 299// used to accelerate or skip a stage 300int acceleratestage; // killough 3/28/98: made global 301 302// wbs->pnum 303static int me; 304 305// specifies current state 306static stateenum_t state; 307 308// contains information passed into intermission 309static wbstartstruct_t* wbs; 310 311static wbplayerstruct_t* plrs; // wbs->plyr[] 312 313// used for general timing 314static int cnt; 315 316// used for timing of background animation 317static int bcnt; 318 319// signals to refresh everything for one frame 320static int firstrefresh; 321 322static int cnt_time; 323static int cnt_total_time; 324static int cnt_par; 325static int cnt_pause; 326 327 328// 329// GRAPHICS 330// 331 332// You Are Here graphic 333static const char* yah[2] = { "WIURH0", "WIURH1" }; 334 335// splat 336static const char* splat = "WISPLAT"; 337 338// %, : graphics 339static const char percent[] = {"WIPCNT"}; 340static const char colon[] = {"WICOLON"}; 341 342// 0-9 graphic 343static const patch_t * num[10]; 344 345// minus sign 346static const char wiminus[] = {"WIMINUS"}; 347 348// "Finished!" graphics 349static const char finished[] = {"WIF"}; 350 351// "Entering" graphic 352static const char entering[] = {"WIENTER"}; 353 354// "secret" 355static const char sp_secret[] = {"WISCRT2"}; 356 357// "Kills", "Scrt", "Items", "Frags" 358static const char kills[] = {"WIOSTK"}; 359static const char secret[] = {"WIOSTS"}; 360static const char items[] = {"WIOSTI"}; 361static const char frags[] = {"WIFRGS"}; 362 363// Time sucks. 364static const char time1[] = {"WITIME"}; 365static const char par[] = {"WIPAR"}; 366static const char sucks[] = {"WISUCKS"}; 367 368// "killers", "victims" 369static const char killers[] = {"WIKILRS"}; 370static const char victims[] = {"WIVCTMS"}; 371 372// "Total", your face, your dead face 373static const char total[] = {"WIMSTT"}; 374static const char star[] = {"STFST01"}; 375static const char bstar[] = {"STFDEAD0"}; 376 377// "red P[1..MAXPLAYERS]" 378static const char facebackp[] = {"STPB0"}; 379 380 381// 382// CODE 383// 384 385static void WI_endDeathmatchStats(void); 386static void WI_endNetgameStats(void); 387void WI_unloadData(void); 388#define WI_endStats WI_endNetgameStats 389 390/* ==================================================================== 391 * WI_levelNameLump 392 * Purpore: Returns the name of the graphic lump containing the name of 393 * the given level. 394 * Args: Episode and level, and buffer (must by 9 chars) to write to 395 * Returns: void 396 */ 397void WI_levelNameLump(int epis, int map, char* buf, int bsize) 398{ 399 if (gamemode == commercial) { 400 snprintf(buf,bsize, "CWILV%2.2d", map); 401 } else { 402 snprintf(buf,bsize, "WILV%d%d", epis, map); 403 } 404} 405 406// ==================================================================== 407// WI_slamBackground 408// Purpose: Put the full-screen background up prior to patches 409// Args: none 410// Returns: void 411// 412static void WI_slamBackground(void) 413{ 414 char name[9]; // limited to 8 characters 415 416 if (gamemode == commercial || (gamemode == retail && wbs->epsd == 3)) 417 strcpy(name, "INTERPIC"); 418 else 419 snprintf(name, sizeof(name), "WIMAP%d", wbs->epsd); 420 421 // background 422 V_DrawNamePatch(0, 0, FB, name, CR_DEFAULT, VPT_STRETCH); 423} 424 425// ==================================================================== 426// WI_Responder 427// Purpose: Draw animations on intermission background screen 428// Args: ev -- event pointer, not actually used here. 429// Returns: False -- dummy routine 430// 431// The ticker is used to detect keys 432// because of timing issues in netgames. 433boolean WI_Responder(event_t* ev) 434{ 435 (void)ev; 436 return false; 437} 438 439// ==================================================================== 440// WI_drawLF 441// Purpose: Draw the "Finished" level name before showing stats 442// Args: none 443// Returns: void 444// 445void WI_drawLF(void) 446{ 447 int y = WI_TITLEY; 448 char lname[9]; 449 450 // draw <LevelName> 451 /* cph - get the graphic lump name and use it */ 452 WI_levelNameLump(wbs->epsd, wbs->last, lname, sizeof(lname)); 453 // CPhipps - patch drawing updated 454 V_DrawNamePatch((320 - V_NamePatchWidth(lname))/2, y, 455 FB, lname, CR_DEFAULT, VPT_STRETCH); 456 457 // draw "Finished!" 458 y += (5*V_NamePatchHeight(lname))/4; 459 460 // CPhipps - patch drawing updated 461 V_DrawNamePatch((320 - V_NamePatchWidth(finished))/2, y, 462 FB, finished, CR_DEFAULT, VPT_STRETCH); 463} 464 465// ==================================================================== 466// WI_drawEL 467// Purpose: Draw introductory "Entering" and level name 468// Args: none 469// Returns: void 470// 471void WI_drawEL(void) 472{ 473 int y = WI_TITLEY; 474 char lname[9]; 475 476 /* cph - get the graphic lump name */ 477 WI_levelNameLump(wbs->epsd, wbs->next, lname, sizeof(lname)); 478 479 // draw "Entering" 480 // CPhipps - patch drawing updated 481 V_DrawNamePatch((320 - V_NamePatchWidth(entering))/2, 482 y, FB, entering, CR_DEFAULT, VPT_STRETCH); 483 484 // draw level 485 y += (5*V_NamePatchHeight(lname))/4; 486 487 // CPhipps - patch drawing updated 488 V_DrawNamePatch((320 - V_NamePatchWidth(lname))/2, y, FB, 489 lname, CR_DEFAULT, VPT_STRETCH); 490} 491 492 493/* ==================================================================== 494 * WI_drawOnLnode 495 * Purpose: Draw patches at a location based on episode/map 496 * Args: n -- index to map# within episode 497 * c[] -- array of names of patches to be drawn 498 * Returns: void 499 */ 500void 501WI_drawOnLnode // draw stuff at a location by episode/map# 502( int n, 503 const char* const c[] ) 504{ 505 int i; 506 boolean fits = false; 507 508 i = 0; 509 do 510 { 511 int left; 512 int top; 513 int right; 514 int bottom; 515 int lump = W_GetNumForName(c[i]); 516 const patch_t* p = W_CacheLumpNum(lump); 517 518 left = lnodes[wbs->epsd][n].x - SHORT(p->leftoffset); 519 top = lnodes[wbs->epsd][n].y - SHORT(p->topoffset); 520 right = left + SHORT(p->width); 521 bottom = top + SHORT(p->height); 522 W_UnlockLumpNum(lump); 523 524 if (left >= 0 525 && right < 320 526 && top >= 0 527 && bottom < 200) 528 { 529 fits = true; 530 } 531 else 532 { 533 i++; 534 } 535 } while (!fits && i!=2); 536 537 if (fits && i<2) 538 { 539 // CPhipps - patch drawing updated 540 V_DrawNamePatch(lnodes[wbs->epsd][n].x, lnodes[wbs->epsd][n].y, 541 FB, c[i], CR_DEFAULT, VPT_STRETCH); 542 } 543 else 544 { 545 // DEBUG 546 //jff 8/3/98 use logical output routine 547 printf("Could not place patch on level %d", n+1); 548 } 549} 550 551 552// ==================================================================== 553// WI_initAnimatedBack 554// Purpose: Initialize pointers and styles for background animation 555// Args: none 556// Returns: void 557// 558void WI_initAnimatedBack(void) 559{ 560 int i; 561 anim_t* a; 562 563 if (gamemode == commercial) // no animation for DOOM2 564 return; 565 566 if (wbs->epsd > 2) 567 return; 568 569 for (i=0;i<NUMANIMS[wbs->epsd];i++) 570 { 571 a = &anims[wbs->epsd][i]; 572 573 // init variables 574 a->ctr = -1; 575 576 // specify the next time to draw it 577 if (a->type == ANIM_ALWAYS) 578 a->nexttic = bcnt + 1 + (M_Random()%a->period); 579 else 580 if (a->type == ANIM_RANDOM) 581 a->nexttic = bcnt + 1 + a->data2+(M_Random()%a->data1); 582 else 583 if (a->type == ANIM_LEVEL) 584 a->nexttic = bcnt + 1; 585 } 586} 587 588 589// ==================================================================== 590// WI_updateAnimatedBack 591// Purpose: Figure out what animation we do on this iteration 592// Args: none 593// Returns: void 594// 595void WI_updateAnimatedBack(void) 596{ 597 int i; 598 anim_t* a; 599 600 if (gamemode == commercial) 601 return; 602 603 if (wbs->epsd > 2) 604 return; 605 606 for (i=0;i<NUMANIMS[wbs->epsd];i++) 607 { 608 a = &anims[wbs->epsd][i]; 609 610 if (bcnt == a->nexttic) 611 { 612 switch (a->type) 613 { 614 case ANIM_ALWAYS: 615 if (++a->ctr >= a->nanims) a->ctr = 0; 616 a->nexttic = bcnt + a->period; 617 break; 618 619 case ANIM_RANDOM: 620 a->ctr++; 621 if (a->ctr == a->nanims) 622 { 623 a->ctr = -1; 624 a->nexttic = bcnt+a->data2+(M_Random()%a->data1); 625 } 626 else 627 a->nexttic = bcnt + a->period; 628 break; 629 630 case ANIM_LEVEL: 631 // gawd-awful hack for level anims 632 if (!(state == StatCount && i == 7) 633 && wbs->next == a->data1) 634 { 635 a->ctr++; 636 if (a->ctr == a->nanims) a->ctr--; 637 a->nexttic = bcnt + a->period; 638 } 639 break; 640 } 641 } 642 } 643} 644 645 646// ==================================================================== 647// WI_drawAnimatedBack 648// Purpose: Actually do the animation (whew!) 649// Args: none 650// Returns: void 651// 652void WI_drawAnimatedBack(void) 653{ 654 int i; 655 anim_t* a; 656 657 if (gamemode==commercial) //jff 4/25/98 Someone forgot commercial an enum 658 return; 659 660 if (wbs->epsd > 2) 661 return; 662 663 for (i=0 ; i<NUMANIMS[wbs->epsd] ; i++) 664 { 665 a = &anims[wbs->epsd][i]; 666 667 if (a->ctr >= 0) 668 // CPhipps - patch drawing updated 669 V_DrawMemPatch(a->loc.x, a->loc.y, FB, a->p[a->ctr], CR_DEFAULT, VPT_STRETCH); 670 } 671} 672 673 674// ==================================================================== 675// WI_drawNum 676// Purpose: Draws a number. If digits > 0, then use that many digits 677// minimum, otherwise only use as many as necessary 678// Args: x, y -- location 679// n -- the number to be drawn 680// digits -- number of digits minimum or zero 681// Returns: new x position after drawing (note we are going to the left) 682// CPhipps - static 683static int WI_drawNum (int x, int y, int n, int digits) 684{ 685 int fontwidth = SHORT(num[0]->width); 686 int neg; 687 int temp; 688 689 if (digits < 0) 690 { 691 if (!n) 692 { 693 // make variable-length zeros 1 digit long 694 digits = 1; 695 } 696 else 697 { 698 // figure out # of digits in # 699 digits = 0; 700 temp = n; 701 702 while (temp) 703 { 704 temp /= 10; 705 digits++; 706 } 707 } 708 } 709 710 neg = n < 0; 711 if (neg) 712 n = -n; 713 714 // if non-number, do not draw it 715 if (n == 1994) 716 return 0; 717 718 // draw the new number 719 while (digits--) 720 { 721 x -= fontwidth; 722 // CPhipps - patch drawing updated 723 V_DrawMemPatch(x, y, FB, num[ n % 10 ], CR_DEFAULT, VPT_STRETCH); 724 n /= 10; 725 } 726 727 // draw a minus sign if necessary 728 if (neg) 729 // CPhipps - patch drawing updated 730 V_DrawNamePatch(x-=8, y, FB, wiminus, CR_DEFAULT, VPT_STRETCH); 731 732 return x; 733} 734 735 736// ==================================================================== 737// WI_drawPercent 738// Purpose: Draws a percentage, really just a call to WI_drawNum 739// after putting a percent sign out there 740// Args: x, y -- location 741// p -- the percentage value to be drawn, no negatives 742// Returns: void 743// CPhipps - static 744static void WI_drawPercent(int x, int y, int p) 745{ 746 if (p < 0) 747 return; 748 749 // CPhipps - patch drawing updated 750 V_DrawNamePatch(x, y, FB, percent, CR_DEFAULT, VPT_STRETCH); 751 WI_drawNum(x, y, p, -1); 752} 753 754 755// ==================================================================== 756// WI_drawTime 757// Purpose: Draws the level completion time or par time, or "Sucks" 758// if 1 hour or more 759// Args: x, y -- location 760// t -- the time value to be drawn 761// Returns: void 762// 763// CPhipps - static 764// - largely rewritten to display hours and use slightly better algorithm 765 766static void WI_drawTime(int x, int y, int t) 767{ 768 int n; 769 770 if (t<0) 771 return; 772 773 if (t < 100*60*60) 774 for(;;) { 775 n = t % 60; 776 t /= 60; 777 x = WI_drawNum(x, y, n, (t || n>9) ? 2 : 1) - V_NamePatchWidth(colon); 778 779 // draw 780 if (t) 781 // CPhipps - patch drawing updated 782 V_DrawNamePatch(x, y, FB, colon, CR_DEFAULT, VPT_STRETCH); 783 else break; 784 } 785 else // "sucks" (maybe should be "addicted", even I've never had a 100 hour game ;) 786 V_DrawNamePatch(x - V_NamePatchWidth(sucks), 787 y, FB, sucks, CR_DEFAULT, VPT_STRETCH); 788} 789 790 791// ==================================================================== 792// WI_End 793// Purpose: Unloads data structures (inverse of WI_Start) 794// Args: none 795// Returns: void 796// 797void WI_End(void) 798{ 799 WI_unloadData(); 800 801 if (deathmatch) 802 WI_endDeathmatchStats(); 803 else if (netgame) 804 WI_endNetgameStats(); 805 else 806 WI_endStats(); 807} 808 809 810// ==================================================================== 811// WI_initNoState 812// Purpose: Clear state, ready for end of level activity 813// Args: none 814// Returns: void 815// 816void WI_initNoState(void) 817{ 818 state = NoState; 819 acceleratestage = 0; 820 cnt = 10; 821} 822 823 824// ==================================================================== 825// WI_drawTimeStats 826// Purpose: Put the times on the screen 827// Args: time, total time, par time, in seconds 828// Returns: void 829// 830// cph - pulled from WI_drawStats below 831 832static void WI_drawTimeStats(int cnt_time, int cnt_total_time, int cnt_par) 833{ 834 V_DrawNamePatch(SP_TIMEX, SP_TIMEY, FB, time1, CR_DEFAULT, VPT_STRETCH); 835 WI_drawTime(320/2 - SP_TIMEX, SP_TIMEY, cnt_time); 836 837 V_DrawNamePatch(SP_TIMEX, (SP_TIMEY+200)/2, FB, total, CR_DEFAULT, VPT_STRETCH); 838 WI_drawTime(320/2 - SP_TIMEX, (SP_TIMEY+200)/2, cnt_total_time); 839 840 // Ty 04/11/98: redid logic: should skip only if with pwad but 841 // without deh patch 842 // killough 2/22/98: skip drawing par times on pwads 843 // Ty 03/17/98: unless pars changed with deh patch 844 845 if (!(modifiedgame)) //&& !deh_pars)) 846 { 847 if (wbs->epsd < 3) 848 { 849 V_DrawNamePatch(320/2 + SP_TIMEX, SP_TIMEY, FB, par, CR_DEFAULT, VPT_STRETCH); 850 WI_drawTime(320 - SP_TIMEX, SP_TIMEY, cnt_par); 851 } 852 } 853} 854 855// ==================================================================== 856// WI_updateNoState 857// Purpose: Cycle until end of level activity is done 858// Args: none 859// Returns: void 860// 861void WI_updateNoState(void) 862{ 863 864 WI_updateAnimatedBack(); 865 866 if (!--cnt) 867 G_WorldDone(); 868} 869 870static boolean snl_pointeron = false; 871 872 873 874// ==================================================================== 875// WI_initShowNextLoc 876// Purpose: Prepare to show the next level's location 877// Args: none 878// Returns: void 879// 880void WI_initShowNextLoc(void) 881{ 882 if ((gamemode != commercial) && (gamemap == 8)) { 883 G_WorldDone(); 884 return; 885 } 886 887 state = ShowNextLoc; 888 acceleratestage = 0; 889 cnt = SHOWNEXTLOCDELAY * TICRATE; 890 891 WI_initAnimatedBack(); 892} 893 894// ==================================================================== 895// WI_updateShowNextLoc 896// Purpose: Prepare to show the next level's location 897// Args: none 898// Returns: void 899// 900void WI_updateShowNextLoc(void) 901{ 902 WI_updateAnimatedBack(); 903 904 if (!--cnt || acceleratestage) 905 WI_initNoState(); 906 else 907 snl_pointeron = (cnt & 31) < 20; 908} 909 910 911// ==================================================================== 912// WI_drawShowNextLoc 913// Purpose: Show the next level's location on animated backgrounds 914// Args: none 915// Returns: void 916// 917void WI_drawShowNextLoc(void) 918{ 919 int i; 920 int last; 921 922 WI_slamBackground(); 923 924 // draw animated background 925 WI_drawAnimatedBack(); 926 927 if ( gamemode != commercial) 928 { 929 if (wbs->epsd > 2) 930 { 931 WI_drawEL(); // "Entering..." if not E1 or E2 932 return; 933 } 934 935 last = (wbs->last == 8) ? wbs->next - 1 : wbs->last; 936 937 // draw a splat on taken cities. 938 for (i=0 ; i<=last ; i++) 939 WI_drawOnLnode(i, &splat); 940 941 // splat the secret level? 942 if (wbs->didsecret) 943 WI_drawOnLnode(8, &splat); 944 945 // draw flashing ptr 946 if (snl_pointeron) 947 WI_drawOnLnode(wbs->next, yah); 948 } 949 950 // draws which level you are entering.. 951 if ( (gamemode != commercial) 952 || wbs->next != 30) // check for MAP30 end game 953 WI_drawEL(); 954} 955 956// ==================================================================== 957// WI_drawNoState 958// Purpose: Draw the pointer and next location 959// Args: none 960// Returns: void 961// 962void WI_drawNoState(void) 963{ 964 snl_pointeron = true; 965 WI_drawShowNextLoc(); 966} 967 968 969// ==================================================================== 970// WI_fragSum 971// Purpose: Calculate frags for this player based on the current totals 972// of all the other players. Subtract self-frags. 973// Args: playernum -- the player to be calculated 974// Returns: the total frags for this player 975// 976int WI_fragSum(int playernum) 977{ 978 int i; 979 int frags = 0; 980 981 for (i=0 ; i<MAXPLAYERS ; i++) 982 { 983 if (playeringame[i] // is this player playing? 984 && i!=playernum) // and it's not the player we're calculating 985 { 986 frags += plrs[playernum].frags[i]; 987 } 988 } 989 990 991 // JDC hack - negative frags. 992 frags -= plrs[playernum].frags[playernum]; 993 994 return frags; 995} 996 997 998static int dm_state; 999// CPhipps - short, dynamically allocated 1000static short int **dm_frags; // frags matrix 1001static short int *dm_totals; // totals by player 1002 1003// ==================================================================== 1004// WI_initDeathmatchStats 1005// Purpose: Set up to display DM stats at end of level. Calculate 1006// frags for all players. 1007// Args: none 1008// Returns: void 1009// 1010void WI_initDeathmatchStats(void) 1011{ 1012 int i; // looping variables 1013 1014 // CPhipps - allocate data structures needed 1015 dm_frags = calloc(MAXPLAYERS, sizeof(*dm_frags)); 1016 dm_totals = calloc(MAXPLAYERS, sizeof(*dm_totals)); 1017 1018 state = StatCount; // We're doing stats 1019 acceleratestage = 0; 1020 dm_state = 1; // count how many times we've done a complete stat 1021 1022 cnt_pause = TICRATE; 1023 1024 for (i=0 ; i<MAXPLAYERS ; i++) 1025 { 1026 if (playeringame[i]) 1027 { 1028 // CPhipps - allocate frags line 1029 dm_frags[i] = calloc(MAXPLAYERS, sizeof(**dm_frags)); // set all counts to zero 1030 1031 dm_totals[i] = 0; 1032 } 1033 } 1034 WI_initAnimatedBack(); 1035} 1036 1037 1038// ==================================================================== 1039// CPhipps - WI_endDeathmatchStats 1040// Purpose: Deallocate dynamically allocated DM stats data 1041// Args: none 1042// Returns: void 1043// 1044 1045void WI_endDeathmatchStats(void) 1046{ 1047 int i; 1048 for (i=0; i<MAXPLAYERS; i++) 1049 free(dm_frags[i]); 1050 1051 free(dm_frags); free(dm_totals); 1052} 1053 1054// ==================================================================== 1055// WI_updateDeathmatchStats 1056// Purpose: Advance Deathmatch stats screen animation. Calculate 1057// frags for all players. Lots of noise and drama around 1058// the presentation. 1059// Args: none 1060// Returns: void 1061// 1062void WI_updateDeathmatchStats(void) 1063{ 1064 int i; 1065 int j; 1066 1067 boolean stillticking; 1068 1069 WI_updateAnimatedBack(); 1070 1071 if (acceleratestage && dm_state != 4) // still ticking 1072 { 1073 acceleratestage = 0; 1074 1075 for (i=0 ; i<MAXPLAYERS ; i++) 1076 { 1077 if (playeringame[i]) 1078 { 1079 for (j=0 ; j<MAXPLAYERS ; j++) 1080 if (playeringame[j]) 1081 dm_frags[i][j] = plrs[i].frags[j]; 1082 1083 dm_totals[i] = WI_fragSum(i); 1084 } 1085 } 1086 1087 1088 S_StartSound(0, sfx_barexp); // bang 1089 dm_state = 4; // we're done with all 4 (or all we have to do) 1090 } 1091 1092 1093 if (dm_state == 2) 1094 { 1095 if (!(bcnt&3)) 1096 S_StartSound(0, sfx_pistol); // noise while counting 1097 1098 stillticking = false; 1099 1100 for (i=0 ; i<MAXPLAYERS ; i++) 1101 { 1102 if (playeringame[i]) 1103 { 1104 for (j=0 ; j<MAXPLAYERS ; j++) 1105 { 1106 if (playeringame[j] 1107 && dm_frags[i][j] != plrs[i].frags[j]) 1108 { 1109 if (plrs[i].frags[j] < 0) 1110 dm_frags[i][j]--; 1111 else 1112 dm_frags[i][j]++; 1113 1114 if (dm_frags[i][j] > 999) // Ty 03/17/98 3-digit frag count 1115 dm_frags[i][j] = 999; 1116 1117 if (dm_frags[i][j] < -999) 1118 dm_frags[i][j] = -999; 1119 1120 stillticking = true; 1121 } 1122 } 1123 dm_totals[i] = WI_fragSum(i); 1124 1125 if (dm_totals[i] > 999) 1126 dm_totals[i] = 999; 1127 1128 if (dm_totals[i] < -999) 1129 dm_totals[i] = -999; // Ty 03/17/98 end 3-digit frag count 1130 } 1131 } 1132 1133 if (!stillticking) 1134 { 1135 S_StartSound(0, sfx_barexp); 1136 dm_state++; 1137 } 1138 } 1139 else if (dm_state == 4) 1140 { 1141 if (acceleratestage) 1142 { 1143 S_StartSound(0, sfx_slop); 1144 1145 if ( gamemode == commercial) 1146 WI_initNoState(); 1147 else 1148 WI_initShowNextLoc(); 1149 } 1150 } 1151 else if (dm_state & 1) 1152 { 1153 if (!--cnt_pause) 1154 { 1155 dm_state++; 1156 cnt_pause = TICRATE; 1157 } 1158 } 1159} 1160 1161 1162// ==================================================================== 1163// WI_drawDeathmatchStats 1164// Purpose: Draw the stats on the screen in a matrix 1165// Args: none 1166// Returns: void 1167// 1168// proff/nicolas 09/20/98 -- changed for hi-res 1169// CPhipps - patch drawing updated 1170void WI_drawDeathmatchStats(void) 1171{ 1172 int i; 1173 int j; 1174 int x; 1175 int y; 1176 int w; 1177 1178 int halfface = V_NamePatchWidth(facebackp)/2; 1179 1180 WI_slamBackground(); 1181 1182 // draw animated background 1183 WI_drawAnimatedBack(); 1184 WI_drawLF(); 1185 1186 // draw stat titles (top line) 1187 V_DrawNamePatch(DM_TOTALSX-V_NamePatchWidth(total)/2, 1188 DM_MATRIXY-WI_SPACINGY+10, FB, total, CR_DEFAULT, VPT_STRETCH); 1189 1190 V_DrawNamePatch(DM_KILLERSX, DM_KILLERSY, FB, killers, CR_DEFAULT, VPT_STRETCH); 1191 V_DrawNamePatch(DM_VICTIMSX, DM_VICTIMSY, FB, victims, CR_DEFAULT, VPT_STRETCH); 1192 1193 // draw P? 1194 x = DM_MATRIXX + DM_SPACINGX; 1195 y = DM_MATRIXY; 1196 1197 for (i=0 ; i<MAXPLAYERS ; i++) 1198 { 1199 if (playeringame[i]) { 1200 //int trans = playernumtotrans[i]; 1201 V_DrawNamePatch(x-halfface, DM_MATRIXY - WI_SPACINGY, 1202 FB, facebackp, i ? CR_LIMIT+i : CR_DEFAULT, 1203 VPT_STRETCH | (i ? VPT_TRANS : 0)); 1204 V_DrawNamePatch(DM_MATRIXX-halfface, y, 1205 FB, facebackp, i ? CR_LIMIT+i : CR_DEFAULT, 1206 VPT_STRETCH | (i ? VPT_TRANS : 0)); 1207 1208 if (i == me) 1209 { 1210 V_DrawNamePatch(x-halfface, DM_MATRIXY - WI_SPACINGY, 1211 FB, bstar, CR_DEFAULT, VPT_STRETCH); 1212 V_DrawNamePatch(DM_MATRIXX-halfface, y, 1213 FB, star, CR_DEFAULT, VPT_STRETCH); 1214 } 1215 } 1216 x += DM_SPACINGX; 1217 y += WI_SPACINGY; 1218 } 1219 1220 // draw stats 1221 y = DM_MATRIXY+10; 1222 w = SHORT(num[0]->width); 1223 1224 for (i=0 ; i<MAXPLAYERS ; i++) 1225 { 1226 x = DM_MATRIXX + DM_SPACINGX; 1227 1228 if (playeringame[i]) 1229 { 1230 for (j=0 ; j<MAXPLAYERS ; j++) 1231 { 1232 if (playeringame[j]) 1233 WI_drawNum(x+w, y, dm_frags[i][j], 2); 1234 1235 x += DM_SPACINGX; 1236 } 1237 WI_drawNum(DM_TOTALSX+w, y, dm_totals[i], 2); 1238 } 1239 y += WI_SPACINGY; 1240 } 1241} 1242 1243 1244// 1245// Note: The term "Netgame" means a coop game 1246// 1247static short *cnt_kills; 1248static short *cnt_items; 1249static short *cnt_secret; 1250static short *cnt_frags; 1251static int dofrags; 1252static int ng_state; 1253 1254// ==================================================================== 1255// CPhipps - WI_endNetgameStats 1256// Purpose: Clean up coop game stats 1257// Args: none 1258// Returns: void 1259// 1260static void WI_endNetgameStats(void) 1261{ 1262 free(cnt_frags); 1263 free(cnt_secret); 1264 free(cnt_items); 1265 free(cnt_kills); 1266} 1267 1268// ==================================================================== 1269// WI_initNetgameStats 1270// Purpose: Prepare for coop game stats 1271// Args: none 1272// Returns: void 1273// 1274void WI_initNetgameStats(void) 1275{ 1276 int i; 1277 1278 state = StatCount; 1279 acceleratestage = 0; 1280 ng_state = 1; 1281 1282 cnt_pause = TICRATE; 1283 1284 // CPhipps - allocate these dynamically, blank with calloc 1285 cnt_kills = calloc(MAXPLAYERS, sizeof(*cnt_kills)); 1286 cnt_items = calloc(MAXPLAYERS, sizeof(*cnt_items)); 1287 cnt_secret= calloc(MAXPLAYERS, sizeof(*cnt_secret)); 1288 cnt_frags = calloc(MAXPLAYERS, sizeof(*cnt_frags)); 1289 1290 for (i=0 ; i<MAXPLAYERS ; i++) 1291 if (playeringame[i]) 1292 dofrags += WI_fragSum(i); 1293 1294 dofrags = !!dofrags; // set to true or false - did we have frags? 1295 1296 WI_initAnimatedBack(); 1297} 1298 1299 1300// ==================================================================== 1301// WI_updateNetgameStats 1302// Purpose: Calculate coop stats as we display them with noise and fury 1303// Args: none 1304// Returns: void 1305// Comment: This stuff sure is complicated for what it does 1306// 1307void WI_updateNetgameStats(void) 1308{ 1309 int i; 1310 int fsum; 1311 1312 boolean stillticking; 1313 1314 WI_updateAnimatedBack(); 1315 1316 if (acceleratestage && ng_state != 10) 1317 { 1318 acceleratestage = 0; 1319 1320 for (i=0 ; i<MAXPLAYERS ; i++) 1321 { 1322 if (!playeringame[i]) 1323 continue; 1324 1325 cnt_kills[i] = (plrs[i].skills * 100) / wbs->maxkills; 1326 cnt_items[i] = (plrs[i].sitems * 100) / wbs->maxitems; 1327 1328 // killough 2/22/98: Make secrets = 100% if maxsecret = 0: 1329 cnt_secret[i] = wbs->maxsecret ? 1330 (plrs[i].ssecret * 100) / wbs->maxsecret : 100; 1331 if (dofrags) 1332 cnt_frags[i] = WI_fragSum(i); // we had frags 1333 } 1334 S_StartSound(0, sfx_barexp); // bang 1335 ng_state = 10; 1336 } 1337 1338 if (ng_state == 2) 1339 { 1340 if (!(bcnt&3)) 1341 S_StartSound(0, sfx_pistol); // pop 1342 1343 stillticking = false; 1344 1345 for (i=0 ; i<MAXPLAYERS ; i++) 1346 { 1347 if (!playeringame[i]) 1348 continue; 1349 1350 cnt_kills[i] += 2; 1351 1352 if (cnt_kills[i] >= (plrs[i].skills * 100) / wbs->maxkills) 1353 cnt_kills[i] = (plrs[i].skills * 100) / wbs->maxkills; 1354 else 1355 stillticking = true; // still got stuff to tally 1356 } 1357 1358 if (!stillticking) 1359 { 1360 S_StartSound(0, sfx_barexp); 1361 ng_state++; 1362 } 1363 } 1364 else if (ng_state == 4) 1365 { 1366 if (!(bcnt&3)) 1367 S_StartSound(0, sfx_pistol); 1368 1369 stillticking = false; 1370 1371 for (i=0 ; i<MAXPLAYERS ; i++) 1372 { 1373 if (!playeringame[i]) 1374 continue; 1375 1376 cnt_items[i] += 2; 1377 if (cnt_items[i] >= (plrs[i].sitems * 100) / wbs->maxitems) 1378 cnt_items[i] = (plrs[i].sitems * 100) / wbs->maxitems; 1379 else 1380 stillticking = true; 1381 } 1382 1383 if (!stillticking) 1384 { 1385 S_StartSound(0, sfx_barexp); 1386 ng_state++; 1387 } 1388 } 1389 else if (ng_state == 6) 1390 { 1391 if (!(bcnt&3)) 1392 S_StartSound(0, sfx_pistol); 1393 1394 stillticking = false; 1395 1396 for (i=0 ; i<MAXPLAYERS ; i++) 1397 { 1398 if (!playeringame[i]) 1399 continue; 1400 1401 cnt_secret[i] += 2; 1402 1403 // killough 2/22/98: Make secrets = 100% if maxsecret = 0: 1404 1405 if (cnt_secret[i] >= (wbs->maxsecret ? (plrs[i].ssecret * 100) / wbs->maxsecret : compatibility_level < lxdoom_1_compatibility ? 0 : 100)) 1406 cnt_secret[i] = wbs->maxsecret ? (plrs[i].ssecret * 100) / wbs->maxsecret : 100; 1407 else 1408 stillticking = true; 1409 } 1410 1411 if (!stillticking) 1412 { 1413 S_StartSound(0, sfx_barexp); 1414 ng_state += 1 + 2*!dofrags; 1415 } 1416 } 1417 else if (ng_state == 8) 1418 { 1419 if (!(bcnt&3)) 1420 S_StartSound(0, sfx_pistol); 1421 1422 stillticking = false; 1423 1424 for (i=0 ; i<MAXPLAYERS ; i++) 1425 { 1426 if (!playeringame[i]) 1427 continue; 1428 1429 cnt_frags[i] += 1; 1430 1431 if (cnt_frags[i] >= (fsum = WI_fragSum(i))) 1432 cnt_frags[i] = fsum; 1433 else 1434 stillticking = true; 1435 } 1436 1437 if (!stillticking) 1438 { 1439 S_StartSound(0, sfx_pldeth); 1440 ng_state++; 1441 } 1442 } 1443 else if (ng_state == 10) 1444 { 1445 if (acceleratestage) 1446 { 1447 S_StartSound(0, sfx_sgcock); 1448 if ( gamemode == commercial ) 1449 WI_initNoState(); 1450 else 1451 WI_initShowNextLoc(); 1452 } 1453 } 1454 else if (ng_state & 1) 1455 { 1456 if (!--cnt_pause) 1457 { 1458 ng_state++; 1459 cnt_pause = TICRATE; 1460 } 1461 } 1462} 1463 1464 1465// ==================================================================== 1466// WI_drawNetgameStats 1467// Purpose: Put the coop stats on the screen 1468// Args: none 1469// Returns: void 1470// 1471// proff/nicolas 09/20/98 -- changed for hi-res 1472// CPhipps - patch drawing updated 1473void WI_drawNetgameStats(void) 1474{ 1475 int i; 1476 int x; 1477 int y; 1478 int pwidth = V_NamePatchWidth(percent); 1479 int fwidth = V_NamePatchWidth(facebackp); 1480 1481 WI_slamBackground(); 1482 1483 // draw animated background 1484 WI_drawAnimatedBack(); 1485 1486 WI_drawLF(); 1487 1488 // draw stat titles (top line) 1489 V_DrawNamePatch(NG_STATSX+NG_SPACINGX-V_NamePatchWidth(kills), 1490 NG_STATSY, FB, kills, CR_DEFAULT, VPT_STRETCH); 1491 1492 V_DrawNamePatch(NG_STATSX+2*NG_SPACINGX-V_NamePatchWidth(items), 1493 NG_STATSY, FB, items, CR_DEFAULT, VPT_STRETCH); 1494 1495 V_DrawNamePatch(NG_STATSX+3*NG_SPACINGX-V_NamePatchWidth(secret), 1496 NG_STATSY, FB, secret, CR_DEFAULT, VPT_STRETCH); 1497 1498 if (dofrags) 1499 V_DrawNamePatch(NG_STATSX+4*NG_SPACINGX-V_NamePatchWidth(frags), 1500 NG_STATSY, FB, frags, CR_DEFAULT, VPT_STRETCH); 1501 1502 // draw stats 1503 y = NG_STATSY + V_NamePatchHeight(kills); 1504 1505 for (i=0 ; i<MAXPLAYERS ; i++) 1506 { 1507 //int trans = playernumtotrans[i]; 1508 if (!playeringame[i]) 1509 continue; 1510 1511 x = NG_STATSX; 1512 V_DrawNamePatch(x-fwidth, y, FB, facebackp, 1513 i ? CR_LIMIT+i : CR_DEFAULT, 1514 VPT_STRETCH | (i ? VPT_TRANS : 0)); 1515 1516 if (i == me) 1517 V_DrawNamePatch(x-fwidth, y, FB, star, CR_DEFAULT, VPT_STRETCH); 1518 1519 x += NG_SPACINGX; 1520 WI_drawPercent(x-pwidth, y+10, cnt_kills[i]); x += NG_SPACINGX; 1521 WI_drawPercent(x-pwidth, y+10, cnt_items[i]); x += NG_SPACINGX; 1522 WI_drawPercent(x-pwidth, y+10, cnt_secret[i]); x += NG_SPACINGX; 1523 1524 if (dofrags) 1525 WI_drawNum(x, y+10, cnt_frags[i], -1); 1526 1527 y += WI_SPACINGY; 1528 } 1529 1530 if (y <= SP_TIMEY) 1531 // cph - show times in coop on the entering screen 1532 WI_drawTimeStats(plrs[me].stime / TICRATE, wbs->totaltimes / TICRATE, wbs->partime / TICRATE); 1533} 1534 1535static int sp_state; 1536 1537// ==================================================================== 1538// WI_initStats 1539// Purpose: Get ready for single player stats 1540// Args: none 1541// Returns: void 1542// Comment: Seems like we could do all these stats in a more generic 1543// set of routines that weren't duplicated for dm, coop, sp 1544// 1545void WI_initStats(void) 1546{ 1547 state = StatCount; 1548 acceleratestage = 0; 1549 sp_state = 1; 1550 1551 // CPhipps - allocate (awful code, I know, but saves changing it all) and initialise 1552 *(cnt_kills = malloc(sizeof(*cnt_kills))) = 1553 *(cnt_items = malloc(sizeof(*cnt_items))) = 1554 *(cnt_secret= malloc(sizeof(*cnt_secret))) = -1; 1555 cnt_time = cnt_par = cnt_total_time = -1; 1556 cnt_pause = TICRATE; 1557 1558 WI_initAnimatedBack(); 1559} 1560 1561// ==================================================================== 1562// WI_updateStats 1563// Purpose: Calculate solo stats 1564// Args: none 1565// Returns: void 1566// 1567void WI_updateStats(void) 1568{ 1569 WI_updateAnimatedBack(); 1570 1571 if (acceleratestage && sp_state != 10) 1572 { 1573 acceleratestage = 0; 1574 cnt_kills[0] = (plrs[me].skills * 100) / wbs->maxkills; 1575 cnt_items[0] = (plrs[me].sitems * 100) / wbs->maxitems; 1576 1577 // killough 2/22/98: Make secrets = 100% if maxsecret = 0: 1578 cnt_secret[0] = (wbs->maxsecret ? 1579 (plrs[me].ssecret * 100) / wbs->maxsecret : 100); 1580 1581 cnt_total_time = wbs->totaltimes / TICRATE; 1582 cnt_time = plrs[me].stime / TICRATE; 1583 cnt_par = wbs->partime / TICRATE; 1584 S_StartSound(0, sfx_barexp); 1585 sp_state = 10; 1586 } 1587 1588 if (sp_state == 2) 1589 { 1590 cnt_kills[0] += 2; 1591 1592 if (!(bcnt&3)) 1593 S_StartSound(0, sfx_pistol); 1594 1595 if (cnt_kills[0] >= (plrs[me].skills * 100) / wbs->maxkills) 1596 { 1597 cnt_kills[0] = (plrs[me].skills * 100) / wbs->maxkills; 1598 S_StartSound(0, sfx_barexp); 1599 sp_state++; 1600 } 1601 } 1602 else if (sp_state == 4) 1603 { 1604 cnt_items[0] += 2; 1605 1606 if (!(bcnt&3)) 1607 S_StartSound(0, sfx_pistol); 1608 1609 if (cnt_items[0] >= (plrs[me].sitems * 100) / wbs->maxitems) 1610 { 1611 cnt_items[0] = (plrs[me].sitems * 100) / wbs->maxitems; 1612 S_StartSound(0, sfx_barexp); 1613 sp_state++; 1614 } 1615 } 1616 else if (sp_state == 6) 1617 { 1618 cnt_secret[0] += 2; 1619 1620 if (!(bcnt&3)) 1621 S_StartSound(0, sfx_pistol); 1622 1623 // killough 2/22/98: Make secrets = 100% if maxsecret = 0: 1624 if ((!wbs->maxsecret && compatibility_level < lxdoom_1_compatibility) || 1625 cnt_secret[0] >= (wbs->maxsecret ? 1626 (plrs[me].ssecret * 100) / wbs->maxsecret : 100)) 1627 { 1628 cnt_secret[0] = (wbs->maxsecret ? 1629 (plrs[me].ssecret * 100) / wbs->maxsecret : 100); 1630 S_StartSound(0, sfx_barexp); 1631 sp_state++; 1632 } 1633 } 1634 else if (sp_state == 8) 1635 { 1636 if (!(bcnt&3)) 1637 S_StartSound(0, sfx_pistol); 1638 1639 cnt_time += 3; 1640 1641 if (cnt_time >= plrs[me].stime / TICRATE) 1642 cnt_time = plrs[me].stime / TICRATE; 1643 1644 cnt_total_time += 3; 1645 1646 if (cnt_total_time >= wbs->totaltimes / TICRATE) 1647 cnt_total_time = wbs->totaltimes / TICRATE; 1648 1649 cnt_par += 3; 1650 1651 if (cnt_par >= wbs->partime / TICRATE) 1652 { 1653 cnt_par = wbs->partime / TICRATE; 1654 1655 if ((cnt_time >= plrs[me].stime / TICRATE) && (compatibility_level < lxdoom_1_compatibility || cnt_total_time >= wbs->totaltimes / TICRATE)) 1656 { 1657 S_StartSound(0, sfx_barexp); 1658 sp_state++; 1659 } 1660 } 1661 } 1662 else if (sp_state == 10) 1663 { 1664 if (acceleratestage) 1665 { 1666 S_StartSound(0, sfx_sgcock); 1667 1668 if (gamemode == commercial) 1669 WI_initNoState(); 1670 else 1671 WI_initShowNextLoc(); 1672 } 1673 } 1674 else if (sp_state & 1) 1675 { 1676 if (!--cnt_pause) 1677 { 1678 sp_state++; 1679 cnt_pause = TICRATE; 1680 } 1681 } 1682} 1683 1684 1685// ==================================================================== 1686// WI_drawStats 1687// Purpose: Put the solo stats on the screen 1688// Args: none 1689// Returns: void 1690// 1691// proff/nicolas 09/20/98 -- changed for hi-res 1692// CPhipps - patch drawing updated 1693void WI_drawStats(void) 1694{ 1695 // line height 1696 int lh; 1697 1698 lh = (3*SHORT(num[0]->height))/2; 1699 1700 WI_slamBackground(); 1701 1702 // draw animated background 1703 WI_drawAnimatedBack(); 1704 1705 WI_drawLF(); 1706 1707 V_DrawNamePatch(SP_STATSX, SP_STATSY, FB, kills, CR_DEFAULT, VPT_STRETCH); 1708 WI_drawPercent(320 - SP_STATSX, SP_STATSY, cnt_kills[0]); 1709 1710 V_DrawNamePatch(SP_STATSX, SP_STATSY+lh, FB, items, CR_DEFAULT, VPT_STRETCH); 1711 WI_drawPercent(320 - SP_STATSX, SP_STATSY+lh, cnt_items[0]); 1712 1713 V_DrawNamePatch(SP_STATSX, SP_STATSY+2*lh, FB, sp_secret, CR_DEFAULT, VPT_STRETCH); 1714 WI_drawPercent(320 - SP_STATSX, SP_STATSY+2*lh, cnt_secret[0]); 1715 1716 WI_drawTimeStats(cnt_time, cnt_total_time, cnt_par); 1717} 1718 1719// ==================================================================== 1720// WI_checkForAccelerate 1721// Purpose: See if the player has hit either the attack or use key 1722// or mouse button. If so we set acceleratestage to 1 and 1723// all those display routines above jump right to the end. 1724// Args: none 1725// Returns: void 1726// 1727void WI_checkForAccelerate(void) 1728{ 1729 int i; 1730 player_t *player; 1731 1732 // check for button presses to skip delays 1733 for (i=0, player = players ; i<MAXPLAYERS ; i++, player++) 1734 { 1735 if (playeringame[i]) 1736 { 1737 if (player->cmd.buttons & BT_ATTACK) 1738 { 1739 if (!player->attackdown) 1740 acceleratestage = 1; 1741 player->attackdown = true; 1742 } 1743 else 1744 player->attackdown = false; 1745 1746 if (player->cmd.buttons & BT_USE) 1747 { 1748 if (!player->usedown) 1749 acceleratestage = 1; 1750 player->usedown = true; 1751 } 1752 else 1753 player->usedown = false; 1754 } 1755 } 1756} 1757 1758// ==================================================================== 1759// WI_Ticker 1760// Purpose: Do various updates every gametic, for stats, animation, 1761// checking that intermission music is running, etc. 1762// Args: none 1763// Returns: void 1764// 1765void WI_Ticker(void) 1766{ 1767 // counter for general background animation 1768 bcnt++; 1769 1770 if (bcnt == 1) 1771 { 1772 // intermission music 1773 if ( gamemode == commercial ) 1774 S_ChangeMusic(mus_dm2int, true); 1775 else 1776 S_ChangeMusic(mus_inter, true); 1777 } 1778 1779 WI_checkForAccelerate(); 1780 1781 switch (state) 1782 { 1783 case StatCount: 1784 if (deathmatch) WI_updateDeathmatchStats(); 1785 else if (netgame) WI_updateNetgameStats(); 1786 else WI_updateStats(); 1787 break; 1788 1789 case ShowNextLoc: 1790 WI_updateShowNextLoc(); 1791 break; 1792 1793 case NoState: 1794 WI_updateNoState(); 1795 break; 1796 } 1797} 1798 1799/* ==================================================================== 1800 * WI_loadData 1801 * Purpose: Initialize intermission data such as background graphics, 1802 * patches, map names, etc. 1803 * Args: none 1804 * Returns: void 1805 * 1806 * CPhipps - modified for new wad lump handling. 1807 * - no longer preload most graphics, other funcs can use 1808 * them by name 1809 */ 1810 1811void WI_loadData(void) 1812{ 1813 int i; 1814 int j; 1815 char name[9]; // limited to 8 characters 1816 anim_t* a; 1817 1818 if (gamemode != commercial) 1819 { 1820 if (wbs->epsd < 3) 1821 { 1822 for (j=0;j<NUMANIMS[wbs->epsd];j++) 1823 { 1824 a = &anims[wbs->epsd][j]; 1825 for (i=0;i<a->nanims;i++) 1826 { 1827 // MONDO HACK! 1828 if (wbs->epsd != 1 || j != 8) 1829 { 1830 // animations 1831 snprintf(name, sizeof(name),"WIA%d%.2d%.2d", wbs->epsd, j, i); 1832 a->p[i] = W_CacheLumpName(name); 1833 } 1834 else 1835 { 1836 // HACK ALERT! 1837 a->p[i] = anims[1][4].p[i]; 1838 } 1839 } 1840 } 1841 } 1842 } 1843 1844 for (i=0;i<10;i++) 1845 { 1846 // numbers 0-9 1847 snprintf(name,sizeof(name),"WINUM%d", i); 1848 num[i] = W_CacheLumpName(name); 1849 } 1850} 1851 1852// ==================================================================== 1853// WI_unloadData 1854// Purpose: Free up the space allocated during WI_loadData 1855// Args: none 1856// Returns: void 1857// 1858// CPhipps - reverse of WI_loadData, goes through the same lumps, but unlocking 1859void WI_unloadData(void) 1860{ 1861 int i,j; 1862 char name[9]; // limited to 8 characters 1863 1864 // cph - unlock gamemode dependent stuff here 1865 if (gamemode != commercial) { 1866 if (wbs->epsd < 3) { 1867 for (j=0;j<NUMANIMS[wbs->epsd];j++) { 1868 anim_t* a = &anims[wbs->epsd][j]; 1869 for (i=0; i<a->nanims; i++) { 1870 // MONDO HACK! 1871 if (wbs->epsd != 1 || j != 8) { 1872 // animations 1873 snprintf(name,sizeof(name), "WIA%d%.2d%.2d", wbs->epsd, j, i); 1874 W_UnlockLumpName(name); 1875 } 1876 } 1877 } 1878 } 1879 } 1880 1881 for (i=0;i<10;i++) { 1882 // numbers 0-9 1883 snprintf(name, sizeof(name),"WINUM%d", i); 1884 W_UnlockLumpName(name); 1885 } 1886} 1887 1888 1889// ==================================================================== 1890// WI_Drawer 1891// Purpose: Call the appropriate stats drawing routine depending on 1892// what kind of game is being played (DM, coop, solo) 1893// Args: none 1894// Returns: void 1895// 1896void WI_Drawer (void) 1897{ 1898 switch (state) 1899 { 1900 case StatCount: 1901 if (deathmatch) 1902 WI_drawDeathmatchStats(); 1903 else if (netgame) 1904 WI_drawNetgameStats(); 1905 else 1906 WI_drawStats(); 1907 break; 1908 1909 case ShowNextLoc: 1910 WI_drawShowNextLoc(); 1911 break; 1912 1913 case NoState: 1914 WI_drawNoState(); 1915 break; 1916 } 1917} 1918 1919// ==================================================================== 1920// WI_initVariables 1921// Purpose: Initialize the intermission information structure 1922// Note: wbstartstruct_t is defined in d_player.h 1923// Args: wbstartstruct -- pointer to the structure with the data 1924// Returns: void 1925// 1926void WI_initVariables(wbstartstruct_t* wbstartstruct) 1927{ 1928 1929 wbs = wbstartstruct; 1930 1931#ifdef RANGECHECKING 1932 if (gamemode != commercial) 1933 { 1934 if ( gamemode == retail ) 1935 RNGCHECK(wbs->epsd, 0, 3); 1936 else 1937 RNGCHECK(wbs->epsd, 0, 2); 1938 } 1939 else 1940 { 1941 RNGCHECK(wbs->last, 0, 8); 1942 RNGCHECK(wbs->next, 0, 8); 1943 } 1944 RNGCHECK(wbs->pnum, 0, MAXPLAYERS); 1945 RNGCHECK(wbs->pnum, 0, MAXPLAYERS); 1946#endif 1947 1948 acceleratestage = 0; 1949 cnt = bcnt = 0; 1950 firstrefresh = 1; 1951 me = wbs->pnum; 1952 plrs = wbs->plyr; 1953 1954 if (!wbs->maxkills) 1955 wbs->maxkills = 1; // probably only useful in MAP30 1956 1957 if (!wbs->maxitems) 1958 wbs->maxitems = 1; 1959 1960 if ( gamemode != retail ) 1961 if (wbs->epsd > 2) 1962 wbs->epsd -= 3; 1963} 1964 1965// ==================================================================== 1966// WI_Start 1967// Purpose: Call the various init routines 1968// Note: wbstartstruct_t is defined in d_player.h 1969// Args: wbstartstruct -- pointer to the structure with the 1970// intermission data 1971// Returns: void 1972// 1973void WI_Start(wbstartstruct_t* wbstartstruct) 1974{ 1975 WI_initVariables(wbstartstruct); 1976 WI_loadData(); 1977 1978 if (deathmatch) 1979 WI_initDeathmatchStats(); 1980 else if (netgame) 1981 WI_initNetgameStats(); 1982 else 1983 WI_initStats(); 1984}