Doom plugin: In anticipation of moving to the EABI toolchain, because of its assumpti...
[kugel-rb.git] / apps / plugins / doom / wi_stuff.c
blob5aec3660264228c0d697fb173d43d0a2ea84058c
1 /* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
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
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.
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.
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.
27 * DESCRIPTION:
28 * Intermission screens.
30 *-----------------------------------------------------------------------------
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"
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.
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
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
71 // GLOBAL LOCATIONS
72 #define WI_TITLEY 2
73 #define WI_SPACINGY 33
75 // SINGLE-PLAYER STUFF
76 #define SP_STATSX 50
77 #define SP_STATSY 50
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)
85 // NET GAME STUFF
86 #define NG_STATSY 50
87 #define NG_STATSX (32 + V_NamePatchWidth(star)/2 + 32*!dofrags)
89 #define NG_SPACINGX 64
92 // Used to display the frags matrix at endgame
93 // DEATHMATCH STUFF
94 #define DM_MATRIXX 42
95 #define DM_MATRIXY 68
97 #define DM_SPACINGX 40
99 #define DM_TOTALSX 269
101 #define DM_KILLERSX 10
102 #define DM_KILLERSY 100
103 #define DM_VICTIMSX 5
104 #define DM_VICTIMSY 50
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
110 enum
112 ANIM_ALWAYS, // determined by patch entry
113 ANIM_RANDOM, // occasional
114 ANIM_LEVEL // continuous
116 typedef unsigned animenum_t;
118 typedef struct
120 int x; // x/y coordinate pair structure
121 int y;
122 } point_t;
126 // Animation.
127 // There is another anim_t used in p_spec.
129 typedef struct
131 animenum_t type;
133 // period in tics between animations
134 int period;
136 // number of animation frames
137 int nanims;
139 // location of animation
140 point_t loc;
142 // ALWAYS: n/a,
143 // RANDOM: period deviation (<256),
144 // LEVEL: level
145 int data1;
147 // ALWAYS: n/a,
148 // RANDOM: random base period,
149 // LEVEL: n/a
150 int data2;
152 /* actual graphics for frames of animations
153 * cphipps - const
155 const patch_t* p[3];
157 // following must be initialized to zero before use!
159 // next value of bcnt (used in conjunction with period)
160 int nexttic;
162 // last drawn animation frame
163 int lastdrawn;
165 // next frame number to animate
166 int ctr;
168 // used by RANDOM and LEVEL when animating
169 int state;
170 } anim_t;
173 static point_t lnodes[NUMEPISODES][NUMMAPS] =
175 // Episode 0 World Map
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)
188 // Episode 1 World Map should go here
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)
201 // Episode 2 World Map should go here
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)
218 // Animation locations for episode 0 (1).
219 // Using patches saves a lot of space,
220 // as they replace 320x200 full screen frames.
222 static anim_t epsd0animinfo[] =
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 }
236 static anim_t epsd1animinfo[] =
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 }
249 static anim_t epsd2animinfo[] =
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 }
259 static int NUMANIMS[NUMEPISODES] =
261 sizeof(epsd0animinfo)/sizeof(anim_t),
262 sizeof(epsd1animinfo)/sizeof(anim_t),
263 sizeof(epsd2animinfo)/sizeof(anim_t)
266 static anim_t *anims[NUMEPISODES] =
268 epsd0animinfo,
269 epsd1animinfo,
270 epsd2animinfo
275 // GENERAL DATA
279 // Locally used stuff.
281 #define FB 0
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
292 #define SP_PAUSE 1
294 // in seconds
295 #define SHOWNEXTLOCDELAY 4
296 //#define SHOWLASTLOCDELAY SHOWNEXTLOCDELAY
299 // used to accelerate or skip a stage
300 int acceleratestage; // killough 3/28/98: made global
302 // wbs->pnum
303 static int me;
305 // specifies current state
306 static stateenum_t state;
308 // contains information passed into intermission
309 static wbstartstruct_t* wbs;
311 static wbplayerstruct_t* plrs; // wbs->plyr[]
313 // used for general timing
314 static int cnt;
316 // used for timing of background animation
317 static int bcnt;
319 // signals to refresh everything for one frame
320 static int firstrefresh;
322 static int cnt_time;
323 static int cnt_total_time;
324 static int cnt_par;
325 static int cnt_pause;
329 // GRAPHICS
332 // You Are Here graphic
333 static const char* yah[2] = { "WIURH0", "WIURH1" };
335 // splat
336 static const char* splat = "WISPLAT";
338 // %, : graphics
339 static const char percent[] = {"WIPCNT"};
340 static const char colon[] = {"WICOLON"};
342 // 0-9 graphic
343 static const patch_t * num[10];
345 // minus sign
346 static const char wiminus[] = {"WIMINUS"};
348 // "Finished!" graphics
349 static const char finished[] = {"WIF"};
351 // "Entering" graphic
352 static const char entering[] = {"WIENTER"};
354 // "secret"
355 static const char sp_secret[] = {"WISCRT2"};
357 // "Kills", "Scrt", "Items", "Frags"
358 static const char kills[] = {"WIOSTK"};
359 static const char secret[] = {"WIOSTS"};
360 static const char items[] = {"WIOSTI"};
361 static const char frags[] = {"WIFRGS"};
363 // Time sucks.
364 static const char time1[] = {"WITIME"};
365 static const char par[] = {"WIPAR"};
366 static const char sucks[] = {"WISUCKS"};
368 // "killers", "victims"
369 static const char killers[] = {"WIKILRS"};
370 static const char victims[] = {"WIVCTMS"};
372 // "Total", your face, your dead face
373 static const char total[] = {"WIMSTT"};
374 static const char star[] = {"STFST01"};
375 static const char bstar[] = {"STFDEAD0"};
377 // "red P[1..MAXPLAYERS]"
378 static const char facebackp[] = {"STPB0"};
382 // CODE
385 static void WI_endDeathmatchStats(void);
386 static void WI_endNetgameStats(void);
387 void WI_unloadData(void);
388 #define WI_endStats WI_endNetgameStats
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
397 void WI_levelNameLump(int epis, int map, char* buf, int bsize)
399 if (gamemode == commercial) {
400 snprintf(buf, bsize,"CWILV%s%d",(map/10>0?"":"0"), map); //ANOTHER ROCKHACK "CWILV%2.2d"
401 //snprintf(buf,bsize, "CWILV%2.2d", map);
402 } else {
403 snprintf(buf,bsize, "WILV%d%d", epis, map);
407 // ====================================================================
408 // WI_slamBackground
409 // Purpose: Put the full-screen background up prior to patches
410 // Args: none
411 // Returns: void
413 static void WI_slamBackground(void)
415 char name[9]; // limited to 8 characters
417 if (gamemode == commercial || (gamemode == retail && wbs->epsd == 3))
418 strcpy(name, "INTERPIC");
419 else
420 snprintf(name, sizeof(name), "WIMAP%d", wbs->epsd);
422 // background
423 V_DrawNamePatch(0, 0, FB, name, CR_DEFAULT, VPT_STRETCH);
426 // ====================================================================
427 // WI_Responder
428 // Purpose: Draw animations on intermission background screen
429 // Args: ev -- event pointer, not actually used here.
430 // Returns: False -- dummy routine
432 // The ticker is used to detect keys
433 // because of timing issues in netgames.
434 boolean WI_Responder(event_t* ev)
436 (void)ev;
437 return false;
440 // ====================================================================
441 // WI_drawLF
442 // Purpose: Draw the "Finished" level name before showing stats
443 // Args: none
444 // Returns: void
446 void WI_drawLF(void)
448 int y = WI_TITLEY;
449 char lname[9];
451 // draw <LevelName>
452 /* cph - get the graphic lump name and use it */
453 WI_levelNameLump(wbs->epsd, wbs->last, lname, sizeof(lname));
454 // CPhipps - patch drawing updated
455 V_DrawNamePatch((320 - V_NamePatchWidth(lname))/2, y,
456 FB, lname, CR_DEFAULT, VPT_STRETCH);
458 // draw "Finished!"
459 y += (5*V_NamePatchHeight(lname))/4;
461 // CPhipps - patch drawing updated
462 V_DrawNamePatch((320 - V_NamePatchWidth(finished))/2, y,
463 FB, finished, CR_DEFAULT, VPT_STRETCH);
466 // ====================================================================
467 // WI_drawEL
468 // Purpose: Draw introductory "Entering" and level name
469 // Args: none
470 // Returns: void
472 void WI_drawEL(void)
474 int y = WI_TITLEY;
475 char lname[9];
477 /* cph - get the graphic lump name */
478 WI_levelNameLump(wbs->epsd, wbs->next, lname, sizeof(lname));
480 // draw "Entering"
481 // CPhipps - patch drawing updated
482 V_DrawNamePatch((320 - V_NamePatchWidth(entering))/2,
483 y, FB, entering, CR_DEFAULT, VPT_STRETCH);
485 // draw level
486 y += (5*V_NamePatchHeight(lname))/4;
488 // CPhipps - patch drawing updated
489 V_DrawNamePatch((320 - V_NamePatchWidth(lname))/2, y, FB,
490 lname, CR_DEFAULT, VPT_STRETCH);
494 /* ====================================================================
495 * WI_drawOnLnode
496 * Purpose: Draw patches at a location based on episode/map
497 * Args: n -- index to map# within episode
498 * c[] -- array of names of patches to be drawn
499 * Returns: void
501 void
502 WI_drawOnLnode // draw stuff at a location by episode/map#
503 ( int n,
504 const char* const c[] )
506 int i;
507 boolean fits = false;
509 i = 0;
512 int left;
513 int top;
514 int right;
515 int bottom;
516 int lump = W_GetNumForName(c[i]);
517 const patch_t* p = W_CacheLumpNum(lump);
519 left = lnodes[wbs->epsd][n].x - SHORT(p->leftoffset);
520 top = lnodes[wbs->epsd][n].y - SHORT(p->topoffset);
521 right = left + SHORT(p->width);
522 bottom = top + SHORT(p->height);
523 W_UnlockLumpNum(lump);
525 if (left >= 0
526 && right < 320
527 && top >= 0
528 && bottom < 200)
530 fits = true;
532 else
534 i++;
536 } while (!fits && i!=2);
538 if (fits && i<2)
540 // CPhipps - patch drawing updated
541 V_DrawNamePatch(lnodes[wbs->epsd][n].x, lnodes[wbs->epsd][n].y,
542 FB, c[i], CR_DEFAULT, VPT_STRETCH);
544 else
546 // DEBUG
547 //jff 8/3/98 use logical output routine
548 printf("Could not place patch on level %d", n+1);
553 // ====================================================================
554 // WI_initAnimatedBack
555 // Purpose: Initialize pointers and styles for background animation
556 // Args: none
557 // Returns: void
559 void WI_initAnimatedBack(void)
561 int i;
562 anim_t* a;
564 if (gamemode == commercial) // no animation for DOOM2
565 return;
567 if (wbs->epsd > 2)
568 return;
570 for (i=0;i<NUMANIMS[wbs->epsd];i++)
572 a = &anims[wbs->epsd][i];
574 // init variables
575 a->ctr = -1;
577 // specify the next time to draw it
578 if (a->type == ANIM_ALWAYS)
579 a->nexttic = bcnt + 1 + (M_Random()%a->period);
580 else
581 if (a->type == ANIM_RANDOM)
582 a->nexttic = bcnt + 1 + a->data2+(M_Random()%a->data1);
583 else
584 if (a->type == ANIM_LEVEL)
585 a->nexttic = bcnt + 1;
590 // ====================================================================
591 // WI_updateAnimatedBack
592 // Purpose: Figure out what animation we do on this iteration
593 // Args: none
594 // Returns: void
596 void WI_updateAnimatedBack(void)
598 int i;
599 anim_t* a;
601 if (gamemode == commercial)
602 return;
604 if (wbs->epsd > 2)
605 return;
607 for (i=0;i<NUMANIMS[wbs->epsd];i++)
609 a = &anims[wbs->epsd][i];
611 if (bcnt == a->nexttic)
613 switch (a->type)
615 case ANIM_ALWAYS:
616 if (++a->ctr >= a->nanims) a->ctr = 0;
617 a->nexttic = bcnt + a->period;
618 break;
620 case ANIM_RANDOM:
621 a->ctr++;
622 if (a->ctr == a->nanims)
624 a->ctr = -1;
625 a->nexttic = bcnt+a->data2+(M_Random()%a->data1);
627 else
628 a->nexttic = bcnt + a->period;
629 break;
631 case ANIM_LEVEL:
632 // gawd-awful hack for level anims
633 if (!(state == StatCount && i == 7)
634 && wbs->next == a->data1)
636 a->ctr++;
637 if (a->ctr == a->nanims) a->ctr--;
638 a->nexttic = bcnt + a->period;
640 break;
647 // ====================================================================
648 // WI_drawAnimatedBack
649 // Purpose: Actually do the animation (whew!)
650 // Args: none
651 // Returns: void
653 void WI_drawAnimatedBack(void)
655 int i;
656 anim_t* a;
658 if (gamemode==commercial) //jff 4/25/98 Someone forgot commercial an enum
659 return;
661 if (wbs->epsd > 2)
662 return;
664 for (i=0 ; i<NUMANIMS[wbs->epsd] ; i++)
666 a = &anims[wbs->epsd][i];
668 if (a->ctr >= 0)
669 // CPhipps - patch drawing updated
670 V_DrawMemPatch(a->loc.x, a->loc.y, FB, a->p[a->ctr], CR_DEFAULT, VPT_STRETCH);
675 // ====================================================================
676 // WI_drawNum
677 // Purpose: Draws a number. If digits > 0, then use that many digits
678 // minimum, otherwise only use as many as necessary
679 // Args: x, y -- location
680 // n -- the number to be drawn
681 // digits -- number of digits minimum or zero
682 // Returns: new x position after drawing (note we are going to the left)
683 // CPhipps - static
684 static int WI_drawNum (int x, int y, int n, int digits)
686 int fontwidth = SHORT(num[0]->width);
687 int neg;
688 int temp;
690 if (digits < 0)
692 if (!n)
694 // make variable-length zeros 1 digit long
695 digits = 1;
697 else
699 // figure out # of digits in #
700 digits = 0;
701 temp = n;
703 while (temp)
705 temp /= 10;
706 digits++;
711 neg = n < 0;
712 if (neg)
713 n = -n;
715 // if non-number, do not draw it
716 if (n == 1994)
717 return 0;
719 // draw the new number
720 while (digits--)
722 x -= fontwidth;
723 // CPhipps - patch drawing updated
724 V_DrawMemPatch(x, y, FB, num[ n % 10 ], CR_DEFAULT, VPT_STRETCH);
725 n /= 10;
728 // draw a minus sign if necessary
729 if (neg)
730 // CPhipps - patch drawing updated
731 V_DrawNamePatch(x-=8, y, FB, wiminus, CR_DEFAULT, VPT_STRETCH);
733 return x;
737 // ====================================================================
738 // WI_drawPercent
739 // Purpose: Draws a percentage, really just a call to WI_drawNum
740 // after putting a percent sign out there
741 // Args: x, y -- location
742 // p -- the percentage value to be drawn, no negatives
743 // Returns: void
744 // CPhipps - static
745 static void WI_drawPercent(int x, int y, int p)
747 if (p < 0)
748 return;
750 // CPhipps - patch drawing updated
751 V_DrawNamePatch(x, y, FB, percent, CR_DEFAULT, VPT_STRETCH);
752 WI_drawNum(x, y, p, -1);
756 // ====================================================================
757 // WI_drawTime
758 // Purpose: Draws the level completion time or par time, or "Sucks"
759 // if 1 hour or more
760 // Args: x, y -- location
761 // t -- the time value to be drawn
762 // Returns: void
764 // CPhipps - static
765 // - largely rewritten to display hours and use slightly better algorithm
767 static void WI_drawTime(int x, int y, int t)
769 int n;
771 if (t<0)
772 return;
774 if (t < 100*60*60)
775 for(;;) {
776 n = t % 60;
777 t /= 60;
778 x = WI_drawNum(x, y, n, (t || n>9) ? 2 : 1) - V_NamePatchWidth(colon);
780 // draw
781 if (t)
782 // CPhipps - patch drawing updated
783 V_DrawNamePatch(x, y, FB, colon, CR_DEFAULT, VPT_STRETCH);
784 else break;
786 else // "sucks" (maybe should be "addicted", even I've never had a 100 hour game ;)
787 V_DrawNamePatch(x - V_NamePatchWidth(sucks),
788 y, FB, sucks, CR_DEFAULT, VPT_STRETCH);
792 // ====================================================================
793 // WI_End
794 // Purpose: Unloads data structures (inverse of WI_Start)
795 // Args: none
796 // Returns: void
798 void WI_End(void)
800 WI_unloadData();
802 if (deathmatch)
803 WI_endDeathmatchStats();
804 else if (netgame)
805 WI_endNetgameStats();
806 else
807 WI_endStats();
811 // ====================================================================
812 // WI_initNoState
813 // Purpose: Clear state, ready for end of level activity
814 // Args: none
815 // Returns: void
817 void WI_initNoState(void)
819 state = NoState;
820 acceleratestage = 0;
821 cnt = 10;
825 // ====================================================================
826 // WI_drawTimeStats
827 // Purpose: Put the times on the screen
828 // Args: time, total time, par time, in seconds
829 // Returns: void
831 // cph - pulled from WI_drawStats below
833 static void WI_drawTimeStats(int cnt_time, int cnt_total_time, int cnt_par)
835 V_DrawNamePatch(SP_TIMEX, SP_TIMEY, FB, time1, CR_DEFAULT, VPT_STRETCH);
836 WI_drawTime(320/2 - SP_TIMEX, SP_TIMEY, cnt_time);
838 V_DrawNamePatch(SP_TIMEX, (SP_TIMEY+200)/2, FB, total, CR_DEFAULT, VPT_STRETCH);
839 WI_drawTime(320/2 - SP_TIMEX, (SP_TIMEY+200)/2, cnt_total_time);
841 // Ty 04/11/98: redid logic: should skip only if with pwad but
842 // without deh patch
843 // killough 2/22/98: skip drawing par times on pwads
844 // Ty 03/17/98: unless pars changed with deh patch
846 if (!(modifiedgame)) //&& !deh_pars))
848 if (wbs->epsd < 3)
850 V_DrawNamePatch(320/2 + SP_TIMEX, SP_TIMEY, FB, par, CR_DEFAULT, VPT_STRETCH);
851 WI_drawTime(320 - SP_TIMEX, SP_TIMEY, cnt_par);
856 // ====================================================================
857 // WI_updateNoState
858 // Purpose: Cycle until end of level activity is done
859 // Args: none
860 // Returns: void
862 void WI_updateNoState(void)
865 WI_updateAnimatedBack();
867 if (!--cnt)
868 G_WorldDone();
871 static boolean snl_pointeron = false;
875 // ====================================================================
876 // WI_initShowNextLoc
877 // Purpose: Prepare to show the next level's location
878 // Args: none
879 // Returns: void
881 void WI_initShowNextLoc(void)
883 if ((gamemode != commercial) && (gamemap == 8)) {
884 G_WorldDone();
885 return;
888 state = ShowNextLoc;
889 acceleratestage = 0;
890 cnt = SHOWNEXTLOCDELAY * TICRATE;
892 WI_initAnimatedBack();
895 // ====================================================================
896 // WI_updateShowNextLoc
897 // Purpose: Prepare to show the next level's location
898 // Args: none
899 // Returns: void
901 void WI_updateShowNextLoc(void)
903 WI_updateAnimatedBack();
905 if (!--cnt || acceleratestage)
906 WI_initNoState();
907 else
908 snl_pointeron = (cnt & 31) < 20;
912 // ====================================================================
913 // WI_drawShowNextLoc
914 // Purpose: Show the next level's location on animated backgrounds
915 // Args: none
916 // Returns: void
918 void WI_drawShowNextLoc(void)
920 int i;
921 int last;
923 WI_slamBackground();
925 // draw animated background
926 WI_drawAnimatedBack();
928 if ( gamemode != commercial)
930 if (wbs->epsd > 2)
932 WI_drawEL(); // "Entering..." if not E1 or E2
933 return;
936 last = (wbs->last == 8) ? wbs->next - 1 : wbs->last;
938 // draw a splat on taken cities.
939 for (i=0 ; i<=last ; i++)
940 WI_drawOnLnode(i, &splat);
942 // splat the secret level?
943 if (wbs->didsecret)
944 WI_drawOnLnode(8, &splat);
946 // draw flashing ptr
947 if (snl_pointeron)
948 WI_drawOnLnode(wbs->next, yah);
951 // draws which level you are entering..
952 if ( (gamemode != commercial)
953 || wbs->next != 30) // check for MAP30 end game
954 WI_drawEL();
957 // ====================================================================
958 // WI_drawNoState
959 // Purpose: Draw the pointer and next location
960 // Args: none
961 // Returns: void
963 void WI_drawNoState(void)
965 snl_pointeron = true;
966 WI_drawShowNextLoc();
970 // ====================================================================
971 // WI_fragSum
972 // Purpose: Calculate frags for this player based on the current totals
973 // of all the other players. Subtract self-frags.
974 // Args: playernum -- the player to be calculated
975 // Returns: the total frags for this player
977 int WI_fragSum(int playernum)
979 int i;
980 int frags = 0;
982 for (i=0 ; i<MAXPLAYERS ; i++)
984 if (playeringame[i] // is this player playing?
985 && i!=playernum) // and it's not the player we're calculating
987 frags += plrs[playernum].frags[i];
992 // JDC hack - negative frags.
993 frags -= plrs[playernum].frags[playernum];
995 return frags;
999 static int dm_state;
1000 // CPhipps - short, dynamically allocated
1001 static short int **dm_frags; // frags matrix
1002 static short int *dm_totals; // totals by player
1004 // ====================================================================
1005 // WI_initDeathmatchStats
1006 // Purpose: Set up to display DM stats at end of level. Calculate
1007 // frags for all players.
1008 // Args: none
1009 // Returns: void
1011 void WI_initDeathmatchStats(void)
1013 int i; // looping variables
1015 // CPhipps - allocate data structures needed
1016 dm_frags = calloc(MAXPLAYERS, sizeof(*dm_frags));
1017 dm_totals = calloc(MAXPLAYERS, sizeof(*dm_totals));
1019 state = StatCount; // We're doing stats
1020 acceleratestage = 0;
1021 dm_state = 1; // count how many times we've done a complete stat
1023 cnt_pause = TICRATE;
1025 for (i=0 ; i<MAXPLAYERS ; i++)
1027 if (playeringame[i])
1029 // CPhipps - allocate frags line
1030 dm_frags[i] = calloc(MAXPLAYERS, sizeof(**dm_frags)); // set all counts to zero
1032 dm_totals[i] = 0;
1035 WI_initAnimatedBack();
1039 // ====================================================================
1040 // CPhipps - WI_endDeathmatchStats
1041 // Purpose: Deallocate dynamically allocated DM stats data
1042 // Args: none
1043 // Returns: void
1046 void WI_endDeathmatchStats(void)
1048 int i;
1049 for (i=0; i<MAXPLAYERS; i++)
1050 free(dm_frags[i]);
1052 free(dm_frags); free(dm_totals);
1055 // ====================================================================
1056 // WI_updateDeathmatchStats
1057 // Purpose: Advance Deathmatch stats screen animation. Calculate
1058 // frags for all players. Lots of noise and drama around
1059 // the presentation.
1060 // Args: none
1061 // Returns: void
1063 void WI_updateDeathmatchStats(void)
1065 int i;
1066 int j;
1068 boolean stillticking;
1070 WI_updateAnimatedBack();
1072 if (acceleratestage && dm_state != 4) // still ticking
1074 acceleratestage = 0;
1076 for (i=0 ; i<MAXPLAYERS ; i++)
1078 if (playeringame[i])
1080 for (j=0 ; j<MAXPLAYERS ; j++)
1081 if (playeringame[j])
1082 dm_frags[i][j] = plrs[i].frags[j];
1084 dm_totals[i] = WI_fragSum(i);
1089 S_StartSound(0, sfx_barexp); // bang
1090 dm_state = 4; // we're done with all 4 (or all we have to do)
1094 if (dm_state == 2)
1096 if (!(bcnt&3))
1097 S_StartSound(0, sfx_pistol); // noise while counting
1099 stillticking = false;
1101 for (i=0 ; i<MAXPLAYERS ; i++)
1103 if (playeringame[i])
1105 for (j=0 ; j<MAXPLAYERS ; j++)
1107 if (playeringame[j]
1108 && dm_frags[i][j] != plrs[i].frags[j])
1110 if (plrs[i].frags[j] < 0)
1111 dm_frags[i][j]--;
1112 else
1113 dm_frags[i][j]++;
1115 if (dm_frags[i][j] > 999) // Ty 03/17/98 3-digit frag count
1116 dm_frags[i][j] = 999;
1118 if (dm_frags[i][j] < -999)
1119 dm_frags[i][j] = -999;
1121 stillticking = true;
1124 dm_totals[i] = WI_fragSum(i);
1126 if (dm_totals[i] > 999)
1127 dm_totals[i] = 999;
1129 if (dm_totals[i] < -999)
1130 dm_totals[i] = -999; // Ty 03/17/98 end 3-digit frag count
1134 if (!stillticking)
1136 S_StartSound(0, sfx_barexp);
1137 dm_state++;
1140 else if (dm_state == 4)
1142 if (acceleratestage)
1144 S_StartSound(0, sfx_slop);
1146 if ( gamemode == commercial)
1147 WI_initNoState();
1148 else
1149 WI_initShowNextLoc();
1152 else if (dm_state & 1)
1154 if (!--cnt_pause)
1156 dm_state++;
1157 cnt_pause = TICRATE;
1163 // ====================================================================
1164 // WI_drawDeathmatchStats
1165 // Purpose: Draw the stats on the screen in a matrix
1166 // Args: none
1167 // Returns: void
1169 // proff/nicolas 09/20/98 -- changed for hi-res
1170 // CPhipps - patch drawing updated
1171 void WI_drawDeathmatchStats(void)
1173 int i;
1174 int j;
1175 int x;
1176 int y;
1177 int w;
1179 int lh; // line height
1180 int halfface = V_NamePatchWidth(facebackp)/2;
1182 lh = WI_SPACINGY;
1184 WI_slamBackground();
1186 // draw animated background
1187 WI_drawAnimatedBack();
1188 WI_drawLF();
1190 // draw stat titles (top line)
1191 V_DrawNamePatch(DM_TOTALSX-V_NamePatchWidth(total)/2,
1192 DM_MATRIXY-WI_SPACINGY+10, FB, total, CR_DEFAULT, VPT_STRETCH);
1194 V_DrawNamePatch(DM_KILLERSX, DM_KILLERSY, FB, killers, CR_DEFAULT, VPT_STRETCH);
1195 V_DrawNamePatch(DM_VICTIMSX, DM_VICTIMSY, FB, victims, CR_DEFAULT, VPT_STRETCH);
1197 // draw P?
1198 x = DM_MATRIXX + DM_SPACINGX;
1199 y = DM_MATRIXY;
1201 for (i=0 ; i<MAXPLAYERS ; i++)
1203 if (playeringame[i]) {
1204 //int trans = playernumtotrans[i];
1205 V_DrawNamePatch(x-halfface, DM_MATRIXY - WI_SPACINGY,
1206 FB, facebackp, i ? CR_LIMIT+i : CR_DEFAULT,
1207 VPT_STRETCH | (i ? VPT_TRANS : 0));
1208 V_DrawNamePatch(DM_MATRIXX-halfface, y,
1209 FB, facebackp, i ? CR_LIMIT+i : CR_DEFAULT,
1210 VPT_STRETCH | (i ? VPT_TRANS : 0));
1212 if (i == me)
1214 V_DrawNamePatch(x-halfface, DM_MATRIXY - WI_SPACINGY,
1215 FB, bstar, CR_DEFAULT, VPT_STRETCH);
1216 V_DrawNamePatch(DM_MATRIXX-halfface, y,
1217 FB, star, CR_DEFAULT, VPT_STRETCH);
1220 x += DM_SPACINGX;
1221 y += WI_SPACINGY;
1224 // draw stats
1225 y = DM_MATRIXY+10;
1226 w = SHORT(num[0]->width);
1228 for (i=0 ; i<MAXPLAYERS ; i++)
1230 x = DM_MATRIXX + DM_SPACINGX;
1232 if (playeringame[i])
1234 for (j=0 ; j<MAXPLAYERS ; j++)
1236 if (playeringame[j])
1237 WI_drawNum(x+w, y, dm_frags[i][j], 2);
1239 x += DM_SPACINGX;
1241 WI_drawNum(DM_TOTALSX+w, y, dm_totals[i], 2);
1243 y += WI_SPACINGY;
1249 // Note: The term "Netgame" means a coop game
1251 static short *cnt_kills;
1252 static short *cnt_items;
1253 static short *cnt_secret;
1254 static short *cnt_frags;
1255 static int dofrags;
1256 static int ng_state;
1258 // ====================================================================
1259 // CPhipps - WI_endNetgameStats
1260 // Purpose: Clean up coop game stats
1261 // Args: none
1262 // Returns: void
1264 static void WI_endNetgameStats(void)
1266 free(cnt_frags);
1267 free(cnt_secret);
1268 free(cnt_items);
1269 free(cnt_kills);
1272 // ====================================================================
1273 // WI_initNetgameStats
1274 // Purpose: Prepare for coop game stats
1275 // Args: none
1276 // Returns: void
1278 void WI_initNetgameStats(void)
1280 int i;
1282 state = StatCount;
1283 acceleratestage = 0;
1284 ng_state = 1;
1286 cnt_pause = TICRATE;
1288 // CPhipps - allocate these dynamically, blank with calloc
1289 cnt_kills = calloc(MAXPLAYERS, sizeof(*cnt_kills));
1290 cnt_items = calloc(MAXPLAYERS, sizeof(*cnt_items));
1291 cnt_secret= calloc(MAXPLAYERS, sizeof(*cnt_secret));
1292 cnt_frags = calloc(MAXPLAYERS, sizeof(*cnt_frags));
1294 for (i=0 ; i<MAXPLAYERS ; i++)
1295 if (playeringame[i])
1296 dofrags += WI_fragSum(i);
1298 dofrags = !!dofrags; // set to true or false - did we have frags?
1300 WI_initAnimatedBack();
1304 // ====================================================================
1305 // WI_updateNetgameStats
1306 // Purpose: Calculate coop stats as we display them with noise and fury
1307 // Args: none
1308 // Returns: void
1309 // Comment: This stuff sure is complicated for what it does
1311 void WI_updateNetgameStats(void)
1313 int i;
1314 int fsum;
1316 boolean stillticking;
1318 WI_updateAnimatedBack();
1320 if (acceleratestage && ng_state != 10)
1322 acceleratestage = 0;
1324 for (i=0 ; i<MAXPLAYERS ; i++)
1326 if (!playeringame[i])
1327 continue;
1329 cnt_kills[i] = (plrs[i].skills * 100) / wbs->maxkills;
1330 cnt_items[i] = (plrs[i].sitems * 100) / wbs->maxitems;
1332 // killough 2/22/98: Make secrets = 100% if maxsecret = 0:
1333 cnt_secret[i] = wbs->maxsecret ?
1334 (plrs[i].ssecret * 100) / wbs->maxsecret : 100;
1335 if (dofrags)
1336 cnt_frags[i] = WI_fragSum(i); // we had frags
1338 S_StartSound(0, sfx_barexp); // bang
1339 ng_state = 10;
1342 if (ng_state == 2)
1344 if (!(bcnt&3))
1345 S_StartSound(0, sfx_pistol); // pop
1347 stillticking = false;
1349 for (i=0 ; i<MAXPLAYERS ; i++)
1351 if (!playeringame[i])
1352 continue;
1354 cnt_kills[i] += 2;
1356 if (cnt_kills[i] >= (plrs[i].skills * 100) / wbs->maxkills)
1357 cnt_kills[i] = (plrs[i].skills * 100) / wbs->maxkills;
1358 else
1359 stillticking = true; // still got stuff to tally
1362 if (!stillticking)
1364 S_StartSound(0, sfx_barexp);
1365 ng_state++;
1368 else if (ng_state == 4)
1370 if (!(bcnt&3))
1371 S_StartSound(0, sfx_pistol);
1373 stillticking = false;
1375 for (i=0 ; i<MAXPLAYERS ; i++)
1377 if (!playeringame[i])
1378 continue;
1380 cnt_items[i] += 2;
1381 if (cnt_items[i] >= (plrs[i].sitems * 100) / wbs->maxitems)
1382 cnt_items[i] = (plrs[i].sitems * 100) / wbs->maxitems;
1383 else
1384 stillticking = true;
1387 if (!stillticking)
1389 S_StartSound(0, sfx_barexp);
1390 ng_state++;
1393 else if (ng_state == 6)
1395 if (!(bcnt&3))
1396 S_StartSound(0, sfx_pistol);
1398 stillticking = false;
1400 for (i=0 ; i<MAXPLAYERS ; i++)
1402 if (!playeringame[i])
1403 continue;
1405 cnt_secret[i] += 2;
1407 // killough 2/22/98: Make secrets = 100% if maxsecret = 0:
1409 if (cnt_secret[i] >= (wbs->maxsecret ? (plrs[i].ssecret * 100) / wbs->maxsecret : compatibility_level < lxdoom_1_compatibility ? 0 : 100))
1410 cnt_secret[i] = wbs->maxsecret ? (plrs[i].ssecret * 100) / wbs->maxsecret : 100;
1411 else
1412 stillticking = true;
1415 if (!stillticking)
1417 S_StartSound(0, sfx_barexp);
1418 ng_state += 1 + 2*!dofrags;
1421 else if (ng_state == 8)
1423 if (!(bcnt&3))
1424 S_StartSound(0, sfx_pistol);
1426 stillticking = false;
1428 for (i=0 ; i<MAXPLAYERS ; i++)
1430 if (!playeringame[i])
1431 continue;
1433 cnt_frags[i] += 1;
1435 if (cnt_frags[i] >= (fsum = WI_fragSum(i)))
1436 cnt_frags[i] = fsum;
1437 else
1438 stillticking = true;
1441 if (!stillticking)
1443 S_StartSound(0, sfx_pldeth);
1444 ng_state++;
1447 else if (ng_state == 10)
1449 if (acceleratestage)
1451 S_StartSound(0, sfx_sgcock);
1452 if ( gamemode == commercial )
1453 WI_initNoState();
1454 else
1455 WI_initShowNextLoc();
1458 else if (ng_state & 1)
1460 if (!--cnt_pause)
1462 ng_state++;
1463 cnt_pause = TICRATE;
1469 // ====================================================================
1470 // WI_drawNetgameStats
1471 // Purpose: Put the coop stats on the screen
1472 // Args: none
1473 // Returns: void
1475 // proff/nicolas 09/20/98 -- changed for hi-res
1476 // CPhipps - patch drawing updated
1477 void WI_drawNetgameStats(void)
1479 int i;
1480 int x;
1481 int y;
1482 int pwidth = V_NamePatchWidth(percent);
1483 int fwidth = V_NamePatchWidth(facebackp);
1485 WI_slamBackground();
1487 // draw animated background
1488 WI_drawAnimatedBack();
1490 WI_drawLF();
1492 // draw stat titles (top line)
1493 V_DrawNamePatch(NG_STATSX+NG_SPACINGX-V_NamePatchWidth(kills),
1494 NG_STATSY, FB, kills, CR_DEFAULT, VPT_STRETCH);
1496 V_DrawNamePatch(NG_STATSX+2*NG_SPACINGX-V_NamePatchWidth(items),
1497 NG_STATSY, FB, items, CR_DEFAULT, VPT_STRETCH);
1499 V_DrawNamePatch(NG_STATSX+3*NG_SPACINGX-V_NamePatchWidth(secret),
1500 NG_STATSY, FB, secret, CR_DEFAULT, VPT_STRETCH);
1502 if (dofrags)
1503 V_DrawNamePatch(NG_STATSX+4*NG_SPACINGX-V_NamePatchWidth(frags),
1504 NG_STATSY, FB, frags, CR_DEFAULT, VPT_STRETCH);
1506 // draw stats
1507 y = NG_STATSY + V_NamePatchHeight(kills);
1509 for (i=0 ; i<MAXPLAYERS ; i++)
1511 //int trans = playernumtotrans[i];
1512 if (!playeringame[i])
1513 continue;
1515 x = NG_STATSX;
1516 V_DrawNamePatch(x-fwidth, y, FB, facebackp,
1517 i ? CR_LIMIT+i : CR_DEFAULT,
1518 VPT_STRETCH | (i ? VPT_TRANS : 0));
1520 if (i == me)
1521 V_DrawNamePatch(x-fwidth, y, FB, star, CR_DEFAULT, VPT_STRETCH);
1523 x += NG_SPACINGX;
1524 WI_drawPercent(x-pwidth, y+10, cnt_kills[i]); x += NG_SPACINGX;
1525 WI_drawPercent(x-pwidth, y+10, cnt_items[i]); x += NG_SPACINGX;
1526 WI_drawPercent(x-pwidth, y+10, cnt_secret[i]); x += NG_SPACINGX;
1528 if (dofrags)
1529 WI_drawNum(x, y+10, cnt_frags[i], -1);
1531 y += WI_SPACINGY;
1534 if (y <= SP_TIMEY)
1535 // cph - show times in coop on the entering screen
1536 WI_drawTimeStats(plrs[me].stime / TICRATE, wbs->totaltimes / TICRATE, wbs->partime / TICRATE);
1539 static int sp_state;
1541 // ====================================================================
1542 // WI_initStats
1543 // Purpose: Get ready for single player stats
1544 // Args: none
1545 // Returns: void
1546 // Comment: Seems like we could do all these stats in a more generic
1547 // set of routines that weren't duplicated for dm, coop, sp
1549 void WI_initStats(void)
1551 state = StatCount;
1552 acceleratestage = 0;
1553 sp_state = 1;
1555 // CPhipps - allocate (awful code, I know, but saves changing it all) and initialise
1556 *(cnt_kills = malloc(sizeof(*cnt_kills))) =
1557 *(cnt_items = malloc(sizeof(*cnt_items))) =
1558 *(cnt_secret= malloc(sizeof(*cnt_secret))) = -1;
1559 cnt_time = cnt_par = cnt_total_time = -1;
1560 cnt_pause = TICRATE;
1562 WI_initAnimatedBack();
1565 // ====================================================================
1566 // WI_updateStats
1567 // Purpose: Calculate solo stats
1568 // Args: none
1569 // Returns: void
1571 void WI_updateStats(void)
1573 WI_updateAnimatedBack();
1575 if (acceleratestage && sp_state != 10)
1577 acceleratestage = 0;
1578 cnt_kills[0] = (plrs[me].skills * 100) / wbs->maxkills;
1579 cnt_items[0] = (plrs[me].sitems * 100) / wbs->maxitems;
1581 // killough 2/22/98: Make secrets = 100% if maxsecret = 0:
1582 cnt_secret[0] = (wbs->maxsecret ?
1583 (plrs[me].ssecret * 100) / wbs->maxsecret : 100);
1585 cnt_total_time = wbs->totaltimes / TICRATE;
1586 cnt_time = plrs[me].stime / TICRATE;
1587 cnt_par = wbs->partime / TICRATE;
1588 S_StartSound(0, sfx_barexp);
1589 sp_state = 10;
1592 if (sp_state == 2)
1594 cnt_kills[0] += 2;
1596 if (!(bcnt&3))
1597 S_StartSound(0, sfx_pistol);
1599 if (cnt_kills[0] >= (plrs[me].skills * 100) / wbs->maxkills)
1601 cnt_kills[0] = (plrs[me].skills * 100) / wbs->maxkills;
1602 S_StartSound(0, sfx_barexp);
1603 sp_state++;
1606 else if (sp_state == 4)
1608 cnt_items[0] += 2;
1610 if (!(bcnt&3))
1611 S_StartSound(0, sfx_pistol);
1613 if (cnt_items[0] >= (plrs[me].sitems * 100) / wbs->maxitems)
1615 cnt_items[0] = (plrs[me].sitems * 100) / wbs->maxitems;
1616 S_StartSound(0, sfx_barexp);
1617 sp_state++;
1620 else if (sp_state == 6)
1622 cnt_secret[0] += 2;
1624 if (!(bcnt&3))
1625 S_StartSound(0, sfx_pistol);
1627 // killough 2/22/98: Make secrets = 100% if maxsecret = 0:
1628 if ((!wbs->maxsecret && compatibility_level < lxdoom_1_compatibility) ||
1629 cnt_secret[0] >= (wbs->maxsecret ?
1630 (plrs[me].ssecret * 100) / wbs->maxsecret : 100))
1632 cnt_secret[0] = (wbs->maxsecret ?
1633 (plrs[me].ssecret * 100) / wbs->maxsecret : 100);
1634 S_StartSound(0, sfx_barexp);
1635 sp_state++;
1638 else if (sp_state == 8)
1640 if (!(bcnt&3))
1641 S_StartSound(0, sfx_pistol);
1643 cnt_time += 3;
1645 if (cnt_time >= plrs[me].stime / TICRATE)
1646 cnt_time = plrs[me].stime / TICRATE;
1648 cnt_total_time += 3;
1650 if (cnt_total_time >= wbs->totaltimes / TICRATE)
1651 cnt_total_time = wbs->totaltimes / TICRATE;
1653 cnt_par += 3;
1655 if (cnt_par >= wbs->partime / TICRATE)
1657 cnt_par = wbs->partime / TICRATE;
1659 if ((cnt_time >= plrs[me].stime / TICRATE) && (compatibility_level < lxdoom_1_compatibility || cnt_total_time >= wbs->totaltimes / TICRATE))
1661 S_StartSound(0, sfx_barexp);
1662 sp_state++;
1666 else if (sp_state == 10)
1668 if (acceleratestage)
1670 S_StartSound(0, sfx_sgcock);
1672 if (gamemode == commercial)
1673 WI_initNoState();
1674 else
1675 WI_initShowNextLoc();
1678 else if (sp_state & 1)
1680 if (!--cnt_pause)
1682 sp_state++;
1683 cnt_pause = TICRATE;
1689 // ====================================================================
1690 // WI_drawStats
1691 // Purpose: Put the solo stats on the screen
1692 // Args: none
1693 // Returns: void
1695 // proff/nicolas 09/20/98 -- changed for hi-res
1696 // CPhipps - patch drawing updated
1697 void WI_drawStats(void)
1699 // line height
1700 int lh;
1702 lh = (3*SHORT(num[0]->height))/2;
1704 WI_slamBackground();
1706 // draw animated background
1707 WI_drawAnimatedBack();
1709 WI_drawLF();
1711 V_DrawNamePatch(SP_STATSX, SP_STATSY, FB, kills, CR_DEFAULT, VPT_STRETCH);
1712 WI_drawPercent(320 - SP_STATSX, SP_STATSY, cnt_kills[0]);
1714 V_DrawNamePatch(SP_STATSX, SP_STATSY+lh, FB, items, CR_DEFAULT, VPT_STRETCH);
1715 WI_drawPercent(320 - SP_STATSX, SP_STATSY+lh, cnt_items[0]);
1717 V_DrawNamePatch(SP_STATSX, SP_STATSY+2*lh, FB, sp_secret, CR_DEFAULT, VPT_STRETCH);
1718 WI_drawPercent(320 - SP_STATSX, SP_STATSY+2*lh, cnt_secret[0]);
1720 WI_drawTimeStats(cnt_time, cnt_total_time, cnt_par);
1723 // ====================================================================
1724 // WI_checkForAccelerate
1725 // Purpose: See if the player has hit either the attack or use key
1726 // or mouse button. If so we set acceleratestage to 1 and
1727 // all those display routines above jump right to the end.
1728 // Args: none
1729 // Returns: void
1731 void WI_checkForAccelerate(void)
1733 int i;
1734 player_t *player;
1736 // check for button presses to skip delays
1737 for (i=0, player = players ; i<MAXPLAYERS ; i++, player++)
1739 if (playeringame[i])
1741 if (player->cmd.buttons & BT_ATTACK)
1743 if (!player->attackdown)
1744 acceleratestage = 1;
1745 player->attackdown = true;
1747 else
1748 player->attackdown = false;
1750 if (player->cmd.buttons & BT_USE)
1752 if (!player->usedown)
1753 acceleratestage = 1;
1754 player->usedown = true;
1756 else
1757 player->usedown = false;
1762 // ====================================================================
1763 // WI_Ticker
1764 // Purpose: Do various updates every gametic, for stats, animation,
1765 // checking that intermission music is running, etc.
1766 // Args: none
1767 // Returns: void
1769 void WI_Ticker(void)
1771 // counter for general background animation
1772 bcnt++;
1774 if (bcnt == 1)
1776 // intermission music
1777 if ( gamemode == commercial )
1778 S_ChangeMusic(mus_dm2int, true);
1779 else
1780 S_ChangeMusic(mus_inter, true);
1783 WI_checkForAccelerate();
1785 switch (state)
1787 case StatCount:
1788 if (deathmatch) WI_updateDeathmatchStats();
1789 else if (netgame) WI_updateNetgameStats();
1790 else WI_updateStats();
1791 break;
1793 case ShowNextLoc:
1794 WI_updateShowNextLoc();
1795 break;
1797 case NoState:
1798 WI_updateNoState();
1799 break;
1803 /* ====================================================================
1804 * WI_loadData
1805 * Purpose: Initialize intermission data such as background graphics,
1806 * patches, map names, etc.
1807 * Args: none
1808 * Returns: void
1810 * CPhipps - modified for new wad lump handling.
1811 * - no longer preload most graphics, other funcs can use
1812 * them by name
1815 void WI_loadData(void)
1817 int i;
1818 int j;
1819 char name[9]; // limited to 8 characters
1820 anim_t* a;
1822 if (gamemode != commercial)
1824 if (wbs->epsd < 3)
1826 for (j=0;j<NUMANIMS[wbs->epsd];j++)
1828 a = &anims[wbs->epsd][j];
1829 for (i=0;i<a->nanims;i++)
1831 // MONDO HACK!
1832 if (wbs->epsd != 1 || j != 8)
1834 // animations
1835 snprintf(name, sizeof(name),"WIA%d%s%d%s%d", wbs->epsd, (j/10>0?"":"0"), j,(i/10>0?"":"0"), i); //ANOTHER ROCKHACK
1836 //snprintf(name, sizeof(name),"WIA%d%.2d%.2d", wbs->epsd, j, i);
1837 a->p[i] = W_CacheLumpName(name);
1839 else
1841 // HACK ALERT!
1842 a->p[i] = anims[1][4].p[i];
1849 for (i=0;i<10;i++)
1851 // numbers 0-9
1852 snprintf(name,sizeof(name),"WINUM%d", i);
1853 num[i] = W_CacheLumpName(name);
1857 // ====================================================================
1858 // WI_unloadData
1859 // Purpose: Free up the space allocated during WI_loadData
1860 // Args: none
1861 // Returns: void
1863 // CPhipps - reverse of WI_loadData, goes through the same lumps, but unlocking
1864 void WI_unloadData(void)
1866 int i,j;
1867 char name[9]; // limited to 8 characters
1869 // cph - unlock gamemode dependent stuff here
1870 if (gamemode != commercial) {
1871 if (wbs->epsd < 3) {
1872 for (j=0;j<NUMANIMS[wbs->epsd];j++) {
1873 anim_t* a = &anims[wbs->epsd][j];
1874 for (i=0; i<a->nanims; i++) {
1875 // MONDO HACK!
1876 if (wbs->epsd != 1 || j != 8) {
1877 // animations
1878 snprintf(name, sizeof(name),"WIA%d%s%d%s%d", wbs->epsd, (j/10>0?"":"0"), j,(i/10>0?"":"0"), i); //ANOTHER ROCKHACK
1879 //snprintf(name,sizeof(name), "WIA%d%.2d%.2d", wbs->epsd, j, i);
1880 W_UnlockLumpName(name);
1887 for (i=0;i<10;i++) {
1888 // numbers 0-9
1889 snprintf(name, sizeof(name),"WINUM%d", i);
1890 W_UnlockLumpName(name);
1895 // ====================================================================
1896 // WI_Drawer
1897 // Purpose: Call the appropriate stats drawing routine depending on
1898 // what kind of game is being played (DM, coop, solo)
1899 // Args: none
1900 // Returns: void
1902 void WI_Drawer (void)
1904 switch (state)
1906 case StatCount:
1907 if (deathmatch)
1908 WI_drawDeathmatchStats();
1909 else if (netgame)
1910 WI_drawNetgameStats();
1911 else
1912 WI_drawStats();
1913 break;
1915 case ShowNextLoc:
1916 WI_drawShowNextLoc();
1917 break;
1919 case NoState:
1920 WI_drawNoState();
1921 break;
1925 // ====================================================================
1926 // WI_initVariables
1927 // Purpose: Initialize the intermission information structure
1928 // Note: wbstartstruct_t is defined in d_player.h
1929 // Args: wbstartstruct -- pointer to the structure with the data
1930 // Returns: void
1932 void WI_initVariables(wbstartstruct_t* wbstartstruct)
1935 wbs = wbstartstruct;
1937 #ifdef RANGECHECKING
1938 if (gamemode != commercial)
1940 if ( gamemode == retail )
1941 RNGCHECK(wbs->epsd, 0, 3);
1942 else
1943 RNGCHECK(wbs->epsd, 0, 2);
1945 else
1947 RNGCHECK(wbs->last, 0, 8);
1948 RNGCHECK(wbs->next, 0, 8);
1950 RNGCHECK(wbs->pnum, 0, MAXPLAYERS);
1951 RNGCHECK(wbs->pnum, 0, MAXPLAYERS);
1952 #endif
1954 acceleratestage = 0;
1955 cnt = bcnt = 0;
1956 firstrefresh = 1;
1957 me = wbs->pnum;
1958 plrs = wbs->plyr;
1960 if (!wbs->maxkills)
1961 wbs->maxkills = 1; // probably only useful in MAP30
1963 if (!wbs->maxitems)
1964 wbs->maxitems = 1;
1966 if ( gamemode != retail )
1967 if (wbs->epsd > 2)
1968 wbs->epsd -= 3;
1971 // ====================================================================
1972 // WI_Start
1973 // Purpose: Call the various init routines
1974 // Note: wbstartstruct_t is defined in d_player.h
1975 // Args: wbstartstruct -- pointer to the structure with the
1976 // intermission data
1977 // Returns: void
1979 void WI_Start(wbstartstruct_t* wbstartstruct)
1981 WI_initVariables(wbstartstruct);
1982 WI_loadData();
1984 if (deathmatch)
1985 WI_initDeathmatchStats();
1986 else if (netgame)
1987 WI_initNetgameStats();
1988 else
1989 WI_initStats();