Update the discussion of themeing in the manual, and put a note in the wps tags appen...
[kugel-rb.git] / apps / plugins / doom / wi_stuff.c
blob3d14d088d548bc45378577fbe2d1dac61a942c38
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 typedef enum
112 ANIM_ALWAYS, // determined by patch entry
113 ANIM_RANDOM, // occasional
114 ANIM_LEVEL // continuous
115 } animenum_t;
117 typedef struct
119 int x; // x/y coordinate pair structure
120 int y;
121 } point_t;
125 // Animation.
126 // There is another anim_t used in p_spec.
128 typedef struct
130 animenum_t type;
132 // period in tics between animations
133 int period;
135 // number of animation frames
136 int nanims;
138 // location of animation
139 point_t loc;
141 // ALWAYS: n/a,
142 // RANDOM: period deviation (<256),
143 // LEVEL: level
144 int data1;
146 // ALWAYS: n/a,
147 // RANDOM: random base period,
148 // LEVEL: n/a
149 int data2;
151 /* actual graphics for frames of animations
152 * cphipps - const
154 const patch_t* p[3];
156 // following must be initialized to zero before use!
158 // next value of bcnt (used in conjunction with period)
159 int nexttic;
161 // last drawn animation frame
162 int lastdrawn;
164 // next frame number to animate
165 int ctr;
167 // used by RANDOM and LEVEL when animating
168 int state;
169 } anim_t;
172 static point_t lnodes[NUMEPISODES][NUMMAPS] =
174 // Episode 0 World Map
176 { 185, 164 }, // location of level 0 (CJ)
177 { 148, 143 }, // location of level 1 (CJ)
178 { 69, 122 }, // location of level 2 (CJ)
179 { 209, 102 }, // location of level 3 (CJ)
180 { 116, 89 }, // location of level 4 (CJ)
181 { 166, 55 }, // location of level 5 (CJ)
182 { 71, 56 }, // location of level 6 (CJ)
183 { 135, 29 }, // location of level 7 (CJ)
184 { 71, 24 } // location of level 8 (CJ)
187 // Episode 1 World Map should go here
189 { 254, 25 }, // location of level 0 (CJ)
190 { 97, 50 }, // location of level 1 (CJ)
191 { 188, 64 }, // location of level 2 (CJ)
192 { 128, 78 }, // location of level 3 (CJ)
193 { 214, 92 }, // location of level 4 (CJ)
194 { 133, 130 }, // location of level 5 (CJ)
195 { 208, 136 }, // location of level 6 (CJ)
196 { 148, 140 }, // location of level 7 (CJ)
197 { 235, 158 } // location of level 8 (CJ)
200 // Episode 2 World Map should go here
202 { 156, 168 }, // location of level 0 (CJ)
203 { 48, 154 }, // location of level 1 (CJ)
204 { 174, 95 }, // location of level 2 (CJ)
205 { 265, 75 }, // location of level 3 (CJ)
206 { 130, 48 }, // location of level 4 (CJ)
207 { 279, 23 }, // location of level 5 (CJ)
208 { 198, 48 }, // location of level 6 (CJ)
209 { 140, 25 }, // location of level 7 (CJ)
210 { 281, 136 } // location of level 8 (CJ)
217 // Animation locations for episode 0 (1).
218 // Using patches saves a lot of space,
219 // as they replace 320x200 full screen frames.
221 static anim_t epsd0animinfo[] =
223 { ANIM_ALWAYS, TICRATE/3, 3, { 224, 104 }, 0, 0, { 0, 0, 0 }, 0, 0, 0, 0 },
224 { ANIM_ALWAYS, TICRATE/3, 3, { 184, 160 }, 0, 0, { 0, 0, 0 }, 0, 0, 0, 0 },
225 { ANIM_ALWAYS, TICRATE/3, 3, { 112, 136 }, 0, 0, { 0, 0, 0 }, 0, 0, 0, 0 },
226 { ANIM_ALWAYS, TICRATE/3, 3, { 72, 112 }, 0, 0, { 0, 0, 0 }, 0, 0, 0, 0 },
227 { ANIM_ALWAYS, TICRATE/3, 3, { 88, 96 }, 0, 0, { 0, 0, 0 }, 0, 0, 0, 0 },
228 { ANIM_ALWAYS, TICRATE/3, 3, { 64, 48 }, 0, 0, { 0, 0, 0 }, 0, 0, 0, 0 },
229 { ANIM_ALWAYS, TICRATE/3, 3, { 192, 40 }, 0, 0, { 0, 0, 0 }, 0, 0, 0, 0 },
230 { ANIM_ALWAYS, TICRATE/3, 3, { 136, 16 }, 0, 0, { 0, 0, 0 }, 0, 0, 0, 0 },
231 { ANIM_ALWAYS, TICRATE/3, 3, { 80, 16 }, 0, 0, { 0, 0, 0 }, 0, 0, 0, 0 },
232 { ANIM_ALWAYS, TICRATE/3, 3, { 64, 24 }, 0, 0, { 0, 0, 0 }, 0, 0, 0, 0 }
235 static anim_t epsd1animinfo[] =
237 { ANIM_LEVEL, TICRATE/3, 1, { 128, 136 }, 1, 0, { 0, 0, 0 }, 0, 0, 0, 0 },
238 { ANIM_LEVEL, TICRATE/3, 1, { 128, 136 }, 2, 0, { 0, 0, 0 }, 0, 0, 0, 0 },
239 { ANIM_LEVEL, TICRATE/3, 1, { 128, 136 }, 3, 0, { 0, 0, 0 }, 0, 0, 0, 0 },
240 { ANIM_LEVEL, TICRATE/3, 1, { 128, 136 }, 4, 0, { 0, 0, 0 }, 0, 0, 0, 0 },
241 { ANIM_LEVEL, TICRATE/3, 1, { 128, 136 }, 5, 0, { 0, 0, 0 }, 0, 0, 0, 0 },
242 { ANIM_LEVEL, TICRATE/3, 1, { 128, 136 }, 6, 0, { 0, 0, 0 }, 0, 0, 0, 0 },
243 { ANIM_LEVEL, TICRATE/3, 1, { 128, 136 }, 7, 0, { 0, 0, 0 }, 0, 0, 0, 0 },
244 { ANIM_LEVEL, TICRATE/3, 3, { 192, 144 }, 8, 0, { 0, 0, 0 }, 0, 0, 0, 0 },
245 { ANIM_LEVEL, TICRATE/3, 1, { 128, 136 }, 8, 0, { 0, 0, 0 }, 0, 0, 0, 0 }
248 static anim_t epsd2animinfo[] =
250 { ANIM_ALWAYS, TICRATE/3, 3, { 104, 168 }, 0, 0, { 0, 0, 0 }, 0, 0, 0, 0 },
251 { ANIM_ALWAYS, TICRATE/3, 3, { 40, 136 }, 0, 0, { 0, 0, 0 }, 0, 0, 0, 0 },
252 { ANIM_ALWAYS, TICRATE/3, 3, { 160, 96 }, 0, 0, { 0, 0, 0 }, 0, 0, 0, 0 },
253 { ANIM_ALWAYS, TICRATE/3, 3, { 104, 80 }, 0, 0, { 0, 0, 0 }, 0, 0, 0, 0 },
254 { ANIM_ALWAYS, TICRATE/3, 3, { 120, 32 }, 0, 0, { 0, 0, 0 }, 0, 0, 0, 0 },
255 { ANIM_ALWAYS, TICRATE/4, 3, { 40, 0 }, 0, 0, { 0, 0, 0 }, 0, 0, 0, 0 }
258 static int NUMANIMS[NUMEPISODES] =
260 sizeof(epsd0animinfo)/sizeof(anim_t),
261 sizeof(epsd1animinfo)/sizeof(anim_t),
262 sizeof(epsd2animinfo)/sizeof(anim_t)
265 static anim_t *anims[NUMEPISODES] =
267 epsd0animinfo,
268 epsd1animinfo,
269 epsd2animinfo
274 // GENERAL DATA
278 // Locally used stuff.
280 #define FB 0
283 // States for single-player
284 #define SP_KILLS 0
285 #define SP_ITEMS 2
286 #define SP_SECRET 4
287 #define SP_FRAGS 6
288 #define SP_TIME 8
289 #define SP_PAR ST_TIME
291 #define SP_PAUSE 1
293 // in seconds
294 #define SHOWNEXTLOCDELAY 4
295 //#define SHOWLASTLOCDELAY SHOWNEXTLOCDELAY
298 // used to accelerate or skip a stage
299 int acceleratestage; // killough 3/28/98: made global
301 // wbs->pnum
302 static int me;
304 // specifies current state
305 static stateenum_t state;
307 // contains information passed into intermission
308 static wbstartstruct_t* wbs;
310 static wbplayerstruct_t* plrs; // wbs->plyr[]
312 // used for general timing
313 static int cnt;
315 // used for timing of background animation
316 static int bcnt;
318 // signals to refresh everything for one frame
319 static int firstrefresh;
321 static int cnt_time;
322 static int cnt_total_time;
323 static int cnt_par;
324 static int cnt_pause;
328 // GRAPHICS
331 // You Are Here graphic
332 static const char* yah[2] = { "WIURH0", "WIURH1" };
334 // splat
335 static const char* splat = "WISPLAT";
337 // %, : graphics
338 static const char percent[] = {"WIPCNT"};
339 static const char colon[] = {"WICOLON"};
341 // 0-9 graphic
342 static const patch_t * num[10];
344 // minus sign
345 static const char wiminus[] = {"WIMINUS"};
347 // "Finished!" graphics
348 static const char finished[] = {"WIF"};
350 // "Entering" graphic
351 static const char entering[] = {"WIENTER"};
353 // "secret"
354 static const char sp_secret[] = {"WISCRT2"};
356 // "Kills", "Scrt", "Items", "Frags"
357 static const char kills[] = {"WIOSTK"};
358 static const char secret[] = {"WIOSTS"};
359 static const char items[] = {"WIOSTI"};
360 static const char frags[] = {"WIFRGS"};
362 // Time sucks.
363 static const char time1[] = {"WITIME"};
364 static const char par[] = {"WIPAR"};
365 static const char sucks[] = {"WISUCKS"};
367 // "killers", "victims"
368 static const char killers[] = {"WIKILRS"};
369 static const char victims[] = {"WIVCTMS"};
371 // "Total", your face, your dead face
372 static const char total[] = {"WIMSTT"};
373 static const char star[] = {"STFST01"};
374 static const char bstar[] = {"STFDEAD0"};
376 // "red P[1..MAXPLAYERS]"
377 static const char facebackp[] = {"STPB0"};
381 // CODE
384 static void WI_endDeathmatchStats(void);
385 static void WI_endNetgameStats(void);
386 void WI_unloadData(void);
387 #define WI_endStats WI_endNetgameStats
389 /* ====================================================================
390 * WI_levelNameLump
391 * Purpore: Returns the name of the graphic lump containing the name of
392 * the given level.
393 * Args: Episode and level, and buffer (must by 9 chars) to write to
394 * Returns: void
396 void WI_levelNameLump(int epis, int map, char* buf, int bsize)
398 if (gamemode == commercial) {
399 snprintf(buf, bsize,"CWILV%s%d",(map/10>0?"":"0"), map); //ANOTHER ROCKHACK "CWILV%2.2d"
400 //snprintf(buf,bsize, "CWILV%2.2d", map);
401 } else {
402 snprintf(buf,bsize, "WILV%d%d", epis, map);
406 // ====================================================================
407 // WI_slamBackground
408 // Purpose: Put the full-screen background up prior to patches
409 // Args: none
410 // Returns: void
412 static void WI_slamBackground(void)
414 char name[9]; // limited to 8 characters
416 if (gamemode == commercial || (gamemode == retail && wbs->epsd == 3))
417 strcpy(name, "INTERPIC");
418 else
419 snprintf(name, sizeof(name), "WIMAP%d", wbs->epsd);
421 // background
422 V_DrawNamePatch(0, 0, FB, name, CR_DEFAULT, VPT_STRETCH);
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
431 // The ticker is used to detect keys
432 // because of timing issues in netgames.
433 boolean WI_Responder(event_t* ev)
435 (void)ev;
436 return false;
439 // ====================================================================
440 // WI_drawLF
441 // Purpose: Draw the "Finished" level name before showing stats
442 // Args: none
443 // Returns: void
445 void WI_drawLF(void)
447 int y = WI_TITLEY;
448 char lname[9];
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);
457 // draw "Finished!"
458 y += (5*V_NamePatchHeight(lname))/4;
460 // CPhipps - patch drawing updated
461 V_DrawNamePatch((320 - V_NamePatchWidth(finished))/2, y,
462 FB, finished, CR_DEFAULT, VPT_STRETCH);
465 // ====================================================================
466 // WI_drawEL
467 // Purpose: Draw introductory "Entering" and level name
468 // Args: none
469 // Returns: void
471 void WI_drawEL(void)
473 int y = WI_TITLEY;
474 char lname[9];
476 /* cph - get the graphic lump name */
477 WI_levelNameLump(wbs->epsd, wbs->next, lname, sizeof(lname));
479 // draw "Entering"
480 // CPhipps - patch drawing updated
481 V_DrawNamePatch((320 - V_NamePatchWidth(entering))/2,
482 y, FB, entering, CR_DEFAULT, VPT_STRETCH);
484 // draw level
485 y += (5*V_NamePatchHeight(lname))/4;
487 // CPhipps - patch drawing updated
488 V_DrawNamePatch((320 - V_NamePatchWidth(lname))/2, y, FB,
489 lname, CR_DEFAULT, VPT_STRETCH);
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
500 void
501 WI_drawOnLnode // draw stuff at a location by episode/map#
502 ( int n,
503 const char* const c[] )
505 int i;
506 boolean fits = false;
508 i = 0;
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);
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);
524 if (left >= 0
525 && right < 320
526 && top >= 0
527 && bottom < 200)
529 fits = true;
531 else
533 i++;
535 } while (!fits && i!=2);
537 if (fits && i<2)
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);
543 else
545 // DEBUG
546 //jff 8/3/98 use logical output routine
547 printf("Could not place patch on level %d", n+1);
552 // ====================================================================
553 // WI_initAnimatedBack
554 // Purpose: Initialize pointers and styles for background animation
555 // Args: none
556 // Returns: void
558 void WI_initAnimatedBack(void)
560 int i;
561 anim_t* a;
563 if (gamemode == commercial) // no animation for DOOM2
564 return;
566 if (wbs->epsd > 2)
567 return;
569 for (i=0;i<NUMANIMS[wbs->epsd];i++)
571 a = &anims[wbs->epsd][i];
573 // init variables
574 a->ctr = -1;
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;
589 // ====================================================================
590 // WI_updateAnimatedBack
591 // Purpose: Figure out what animation we do on this iteration
592 // Args: none
593 // Returns: void
595 void WI_updateAnimatedBack(void)
597 int i;
598 anim_t* a;
600 if (gamemode == commercial)
601 return;
603 if (wbs->epsd > 2)
604 return;
606 for (i=0;i<NUMANIMS[wbs->epsd];i++)
608 a = &anims[wbs->epsd][i];
610 if (bcnt == a->nexttic)
612 switch (a->type)
614 case ANIM_ALWAYS:
615 if (++a->ctr >= a->nanims) a->ctr = 0;
616 a->nexttic = bcnt + a->period;
617 break;
619 case ANIM_RANDOM:
620 a->ctr++;
621 if (a->ctr == a->nanims)
623 a->ctr = -1;
624 a->nexttic = bcnt+a->data2+(M_Random()%a->data1);
626 else
627 a->nexttic = bcnt + a->period;
628 break;
630 case ANIM_LEVEL:
631 // gawd-awful hack for level anims
632 if (!(state == StatCount && i == 7)
633 && wbs->next == a->data1)
635 a->ctr++;
636 if (a->ctr == a->nanims) a->ctr--;
637 a->nexttic = bcnt + a->period;
639 break;
646 // ====================================================================
647 // WI_drawAnimatedBack
648 // Purpose: Actually do the animation (whew!)
649 // Args: none
650 // Returns: void
652 void WI_drawAnimatedBack(void)
654 int i;
655 anim_t* a;
657 if (gamemode==commercial) //jff 4/25/98 Someone forgot commercial an enum
658 return;
660 if (wbs->epsd > 2)
661 return;
663 for (i=0 ; i<NUMANIMS[wbs->epsd] ; i++)
665 a = &anims[wbs->epsd][i];
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);
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
683 static int WI_drawNum (int x, int y, int n, int digits)
685 int fontwidth = SHORT(num[0]->width);
686 int neg;
687 int temp;
689 if (digits < 0)
691 if (!n)
693 // make variable-length zeros 1 digit long
694 digits = 1;
696 else
698 // figure out # of digits in #
699 digits = 0;
700 temp = n;
702 while (temp)
704 temp /= 10;
705 digits++;
710 neg = n < 0;
711 if (neg)
712 n = -n;
714 // if non-number, do not draw it
715 if (n == 1994)
716 return 0;
718 // draw the new number
719 while (digits--)
721 x -= fontwidth;
722 // CPhipps - patch drawing updated
723 V_DrawMemPatch(x, y, FB, num[ n % 10 ], CR_DEFAULT, VPT_STRETCH);
724 n /= 10;
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);
732 return x;
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
744 static void WI_drawPercent(int x, int y, int p)
746 if (p < 0)
747 return;
749 // CPhipps - patch drawing updated
750 V_DrawNamePatch(x, y, FB, percent, CR_DEFAULT, VPT_STRETCH);
751 WI_drawNum(x, y, p, -1);
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
763 // CPhipps - static
764 // - largely rewritten to display hours and use slightly better algorithm
766 static void WI_drawTime(int x, int y, int t)
768 int n;
770 if (t<0)
771 return;
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);
779 // draw
780 if (t)
781 // CPhipps - patch drawing updated
782 V_DrawNamePatch(x, y, FB, colon, CR_DEFAULT, VPT_STRETCH);
783 else break;
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);
791 // ====================================================================
792 // WI_End
793 // Purpose: Unloads data structures (inverse of WI_Start)
794 // Args: none
795 // Returns: void
797 void WI_End(void)
799 WI_unloadData();
801 if (deathmatch)
802 WI_endDeathmatchStats();
803 else if (netgame)
804 WI_endNetgameStats();
805 else
806 WI_endStats();
810 // ====================================================================
811 // WI_initNoState
812 // Purpose: Clear state, ready for end of level activity
813 // Args: none
814 // Returns: void
816 void WI_initNoState(void)
818 state = NoState;
819 acceleratestage = 0;
820 cnt = 10;
824 // ====================================================================
825 // WI_drawTimeStats
826 // Purpose: Put the times on the screen
827 // Args: time, total time, par time, in seconds
828 // Returns: void
830 // cph - pulled from WI_drawStats below
832 static void WI_drawTimeStats(int cnt_time, int cnt_total_time, int cnt_par)
834 V_DrawNamePatch(SP_TIMEX, SP_TIMEY, FB, time1, CR_DEFAULT, VPT_STRETCH);
835 WI_drawTime(320/2 - SP_TIMEX, SP_TIMEY, cnt_time);
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);
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
845 if (!(modifiedgame)) //&& !deh_pars))
847 if (wbs->epsd < 3)
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);
855 // ====================================================================
856 // WI_updateNoState
857 // Purpose: Cycle until end of level activity is done
858 // Args: none
859 // Returns: void
861 void WI_updateNoState(void)
864 WI_updateAnimatedBack();
866 if (!--cnt)
867 G_WorldDone();
870 static boolean snl_pointeron = false;
874 // ====================================================================
875 // WI_initShowNextLoc
876 // Purpose: Prepare to show the next level's location
877 // Args: none
878 // Returns: void
880 void WI_initShowNextLoc(void)
882 if ((gamemode != commercial) && (gamemap == 8)) {
883 G_WorldDone();
884 return;
887 state = ShowNextLoc;
888 acceleratestage = 0;
889 cnt = SHOWNEXTLOCDELAY * TICRATE;
891 WI_initAnimatedBack();
894 // ====================================================================
895 // WI_updateShowNextLoc
896 // Purpose: Prepare to show the next level's location
897 // Args: none
898 // Returns: void
900 void WI_updateShowNextLoc(void)
902 WI_updateAnimatedBack();
904 if (!--cnt || acceleratestage)
905 WI_initNoState();
906 else
907 snl_pointeron = (cnt & 31) < 20;
911 // ====================================================================
912 // WI_drawShowNextLoc
913 // Purpose: Show the next level's location on animated backgrounds
914 // Args: none
915 // Returns: void
917 void WI_drawShowNextLoc(void)
919 int i;
920 int last;
922 WI_slamBackground();
924 // draw animated background
925 WI_drawAnimatedBack();
927 if ( gamemode != commercial)
929 if (wbs->epsd > 2)
931 WI_drawEL(); // "Entering..." if not E1 or E2
932 return;
935 last = (wbs->last == 8) ? wbs->next - 1 : wbs->last;
937 // draw a splat on taken cities.
938 for (i=0 ; i<=last ; i++)
939 WI_drawOnLnode(i, &splat);
941 // splat the secret level?
942 if (wbs->didsecret)
943 WI_drawOnLnode(8, &splat);
945 // draw flashing ptr
946 if (snl_pointeron)
947 WI_drawOnLnode(wbs->next, yah);
950 // draws which level you are entering..
951 if ( (gamemode != commercial)
952 || wbs->next != 30) // check for MAP30 end game
953 WI_drawEL();
956 // ====================================================================
957 // WI_drawNoState
958 // Purpose: Draw the pointer and next location
959 // Args: none
960 // Returns: void
962 void WI_drawNoState(void)
964 snl_pointeron = true;
965 WI_drawShowNextLoc();
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
976 int WI_fragSum(int playernum)
978 int i;
979 int frags = 0;
981 for (i=0 ; i<MAXPLAYERS ; i++)
983 if (playeringame[i] // is this player playing?
984 && i!=playernum) // and it's not the player we're calculating
986 frags += plrs[playernum].frags[i];
991 // JDC hack - negative frags.
992 frags -= plrs[playernum].frags[playernum];
994 return frags;
998 static int dm_state;
999 // CPhipps - short, dynamically allocated
1000 static short int **dm_frags; // frags matrix
1001 static short int *dm_totals; // totals by player
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
1010 void WI_initDeathmatchStats(void)
1012 int i; // looping variables
1014 // CPhipps - allocate data structures needed
1015 dm_frags = calloc(MAXPLAYERS, sizeof(*dm_frags));
1016 dm_totals = calloc(MAXPLAYERS, sizeof(*dm_totals));
1018 state = StatCount; // We're doing stats
1019 acceleratestage = 0;
1020 dm_state = 1; // count how many times we've done a complete stat
1022 cnt_pause = TICRATE;
1024 for (i=0 ; i<MAXPLAYERS ; i++)
1026 if (playeringame[i])
1028 // CPhipps - allocate frags line
1029 dm_frags[i] = calloc(MAXPLAYERS, sizeof(**dm_frags)); // set all counts to zero
1031 dm_totals[i] = 0;
1034 WI_initAnimatedBack();
1038 // ====================================================================
1039 // CPhipps - WI_endDeathmatchStats
1040 // Purpose: Deallocate dynamically allocated DM stats data
1041 // Args: none
1042 // Returns: void
1045 void WI_endDeathmatchStats(void)
1047 int i;
1048 for (i=0; i<MAXPLAYERS; i++)
1049 free(dm_frags[i]);
1051 free(dm_frags); free(dm_totals);
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
1062 void WI_updateDeathmatchStats(void)
1064 int i;
1065 int j;
1067 boolean stillticking;
1069 WI_updateAnimatedBack();
1071 if (acceleratestage && dm_state != 4) // still ticking
1073 acceleratestage = 0;
1075 for (i=0 ; i<MAXPLAYERS ; i++)
1077 if (playeringame[i])
1079 for (j=0 ; j<MAXPLAYERS ; j++)
1080 if (playeringame[j])
1081 dm_frags[i][j] = plrs[i].frags[j];
1083 dm_totals[i] = WI_fragSum(i);
1088 S_StartSound(0, sfx_barexp); // bang
1089 dm_state = 4; // we're done with all 4 (or all we have to do)
1093 if (dm_state == 2)
1095 if (!(bcnt&3))
1096 S_StartSound(0, sfx_pistol); // noise while counting
1098 stillticking = false;
1100 for (i=0 ; i<MAXPLAYERS ; i++)
1102 if (playeringame[i])
1104 for (j=0 ; j<MAXPLAYERS ; j++)
1106 if (playeringame[j]
1107 && dm_frags[i][j] != plrs[i].frags[j])
1109 if (plrs[i].frags[j] < 0)
1110 dm_frags[i][j]--;
1111 else
1112 dm_frags[i][j]++;
1114 if (dm_frags[i][j] > 999) // Ty 03/17/98 3-digit frag count
1115 dm_frags[i][j] = 999;
1117 if (dm_frags[i][j] < -999)
1118 dm_frags[i][j] = -999;
1120 stillticking = true;
1123 dm_totals[i] = WI_fragSum(i);
1125 if (dm_totals[i] > 999)
1126 dm_totals[i] = 999;
1128 if (dm_totals[i] < -999)
1129 dm_totals[i] = -999; // Ty 03/17/98 end 3-digit frag count
1133 if (!stillticking)
1135 S_StartSound(0, sfx_barexp);
1136 dm_state++;
1139 else if (dm_state == 4)
1141 if (acceleratestage)
1143 S_StartSound(0, sfx_slop);
1145 if ( gamemode == commercial)
1146 WI_initNoState();
1147 else
1148 WI_initShowNextLoc();
1151 else if (dm_state & 1)
1153 if (!--cnt_pause)
1155 dm_state++;
1156 cnt_pause = TICRATE;
1162 // ====================================================================
1163 // WI_drawDeathmatchStats
1164 // Purpose: Draw the stats on the screen in a matrix
1165 // Args: none
1166 // Returns: void
1168 // proff/nicolas 09/20/98 -- changed for hi-res
1169 // CPhipps - patch drawing updated
1170 void WI_drawDeathmatchStats(void)
1172 int i;
1173 int j;
1174 int x;
1175 int y;
1176 int w;
1178 int lh; // line height
1179 int halfface = V_NamePatchWidth(facebackp)/2;
1181 lh = WI_SPACINGY;
1183 WI_slamBackground();
1185 // draw animated background
1186 WI_drawAnimatedBack();
1187 WI_drawLF();
1189 // draw stat titles (top line)
1190 V_DrawNamePatch(DM_TOTALSX-V_NamePatchWidth(total)/2,
1191 DM_MATRIXY-WI_SPACINGY+10, FB, total, CR_DEFAULT, VPT_STRETCH);
1193 V_DrawNamePatch(DM_KILLERSX, DM_KILLERSY, FB, killers, CR_DEFAULT, VPT_STRETCH);
1194 V_DrawNamePatch(DM_VICTIMSX, DM_VICTIMSY, FB, victims, CR_DEFAULT, VPT_STRETCH);
1196 // draw P?
1197 x = DM_MATRIXX + DM_SPACINGX;
1198 y = DM_MATRIXY;
1200 for (i=0 ; i<MAXPLAYERS ; i++)
1202 if (playeringame[i]) {
1203 //int trans = playernumtotrans[i];
1204 V_DrawNamePatch(x-halfface, DM_MATRIXY - WI_SPACINGY,
1205 FB, facebackp, i ? CR_LIMIT+i : CR_DEFAULT,
1206 VPT_STRETCH | (i ? VPT_TRANS : 0));
1207 V_DrawNamePatch(DM_MATRIXX-halfface, y,
1208 FB, facebackp, i ? CR_LIMIT+i : CR_DEFAULT,
1209 VPT_STRETCH | (i ? VPT_TRANS : 0));
1211 if (i == me)
1213 V_DrawNamePatch(x-halfface, DM_MATRIXY - WI_SPACINGY,
1214 FB, bstar, CR_DEFAULT, VPT_STRETCH);
1215 V_DrawNamePatch(DM_MATRIXX-halfface, y,
1216 FB, star, CR_DEFAULT, VPT_STRETCH);
1219 x += DM_SPACINGX;
1220 y += WI_SPACINGY;
1223 // draw stats
1224 y = DM_MATRIXY+10;
1225 w = SHORT(num[0]->width);
1227 for (i=0 ; i<MAXPLAYERS ; i++)
1229 x = DM_MATRIXX + DM_SPACINGX;
1231 if (playeringame[i])
1233 for (j=0 ; j<MAXPLAYERS ; j++)
1235 if (playeringame[j])
1236 WI_drawNum(x+w, y, dm_frags[i][j], 2);
1238 x += DM_SPACINGX;
1240 WI_drawNum(DM_TOTALSX+w, y, dm_totals[i], 2);
1242 y += WI_SPACINGY;
1248 // Note: The term "Netgame" means a coop game
1250 static short *cnt_kills;
1251 static short *cnt_items;
1252 static short *cnt_secret;
1253 static short *cnt_frags;
1254 static int dofrags;
1255 static int ng_state;
1257 // ====================================================================
1258 // CPhipps - WI_endNetgameStats
1259 // Purpose: Clean up coop game stats
1260 // Args: none
1261 // Returns: void
1263 static void WI_endNetgameStats(void)
1265 free(cnt_frags);
1266 free(cnt_secret);
1267 free(cnt_items);
1268 free(cnt_kills);
1271 // ====================================================================
1272 // WI_initNetgameStats
1273 // Purpose: Prepare for coop game stats
1274 // Args: none
1275 // Returns: void
1277 void WI_initNetgameStats(void)
1279 int i;
1281 state = StatCount;
1282 acceleratestage = 0;
1283 ng_state = 1;
1285 cnt_pause = TICRATE;
1287 // CPhipps - allocate these dynamically, blank with calloc
1288 cnt_kills = calloc(MAXPLAYERS, sizeof(*cnt_kills));
1289 cnt_items = calloc(MAXPLAYERS, sizeof(*cnt_items));
1290 cnt_secret= calloc(MAXPLAYERS, sizeof(*cnt_secret));
1291 cnt_frags = calloc(MAXPLAYERS, sizeof(*cnt_frags));
1293 for (i=0 ; i<MAXPLAYERS ; i++)
1294 if (playeringame[i])
1295 dofrags += WI_fragSum(i);
1297 dofrags = !!dofrags; // set to true or false - did we have frags?
1299 WI_initAnimatedBack();
1303 // ====================================================================
1304 // WI_updateNetgameStats
1305 // Purpose: Calculate coop stats as we display them with noise and fury
1306 // Args: none
1307 // Returns: void
1308 // Comment: This stuff sure is complicated for what it does
1310 void WI_updateNetgameStats(void)
1312 int i;
1313 int fsum;
1315 boolean stillticking;
1317 WI_updateAnimatedBack();
1319 if (acceleratestage && ng_state != 10)
1321 acceleratestage = 0;
1323 for (i=0 ; i<MAXPLAYERS ; i++)
1325 if (!playeringame[i])
1326 continue;
1328 cnt_kills[i] = (plrs[i].skills * 100) / wbs->maxkills;
1329 cnt_items[i] = (plrs[i].sitems * 100) / wbs->maxitems;
1331 // killough 2/22/98: Make secrets = 100% if maxsecret = 0:
1332 cnt_secret[i] = wbs->maxsecret ?
1333 (plrs[i].ssecret * 100) / wbs->maxsecret : 100;
1334 if (dofrags)
1335 cnt_frags[i] = WI_fragSum(i); // we had frags
1337 S_StartSound(0, sfx_barexp); // bang
1338 ng_state = 10;
1341 if (ng_state == 2)
1343 if (!(bcnt&3))
1344 S_StartSound(0, sfx_pistol); // pop
1346 stillticking = false;
1348 for (i=0 ; i<MAXPLAYERS ; i++)
1350 if (!playeringame[i])
1351 continue;
1353 cnt_kills[i] += 2;
1355 if (cnt_kills[i] >= (plrs[i].skills * 100) / wbs->maxkills)
1356 cnt_kills[i] = (plrs[i].skills * 100) / wbs->maxkills;
1357 else
1358 stillticking = true; // still got stuff to tally
1361 if (!stillticking)
1363 S_StartSound(0, sfx_barexp);
1364 ng_state++;
1367 else if (ng_state == 4)
1369 if (!(bcnt&3))
1370 S_StartSound(0, sfx_pistol);
1372 stillticking = false;
1374 for (i=0 ; i<MAXPLAYERS ; i++)
1376 if (!playeringame[i])
1377 continue;
1379 cnt_items[i] += 2;
1380 if (cnt_items[i] >= (plrs[i].sitems * 100) / wbs->maxitems)
1381 cnt_items[i] = (plrs[i].sitems * 100) / wbs->maxitems;
1382 else
1383 stillticking = true;
1386 if (!stillticking)
1388 S_StartSound(0, sfx_barexp);
1389 ng_state++;
1392 else if (ng_state == 6)
1394 if (!(bcnt&3))
1395 S_StartSound(0, sfx_pistol);
1397 stillticking = false;
1399 for (i=0 ; i<MAXPLAYERS ; i++)
1401 if (!playeringame[i])
1402 continue;
1404 cnt_secret[i] += 2;
1406 // killough 2/22/98: Make secrets = 100% if maxsecret = 0:
1408 if (cnt_secret[i] >= (wbs->maxsecret ? (plrs[i].ssecret * 100) / wbs->maxsecret : compatibility_level < lxdoom_1_compatibility ? 0 : 100))
1409 cnt_secret[i] = wbs->maxsecret ? (plrs[i].ssecret * 100) / wbs->maxsecret : 100;
1410 else
1411 stillticking = true;
1414 if (!stillticking)
1416 S_StartSound(0, sfx_barexp);
1417 ng_state += 1 + 2*!dofrags;
1420 else if (ng_state == 8)
1422 if (!(bcnt&3))
1423 S_StartSound(0, sfx_pistol);
1425 stillticking = false;
1427 for (i=0 ; i<MAXPLAYERS ; i++)
1429 if (!playeringame[i])
1430 continue;
1432 cnt_frags[i] += 1;
1434 if (cnt_frags[i] >= (fsum = WI_fragSum(i)))
1435 cnt_frags[i] = fsum;
1436 else
1437 stillticking = true;
1440 if (!stillticking)
1442 S_StartSound(0, sfx_pldeth);
1443 ng_state++;
1446 else if (ng_state == 10)
1448 if (acceleratestage)
1450 S_StartSound(0, sfx_sgcock);
1451 if ( gamemode == commercial )
1452 WI_initNoState();
1453 else
1454 WI_initShowNextLoc();
1457 else if (ng_state & 1)
1459 if (!--cnt_pause)
1461 ng_state++;
1462 cnt_pause = TICRATE;
1468 // ====================================================================
1469 // WI_drawNetgameStats
1470 // Purpose: Put the coop stats on the screen
1471 // Args: none
1472 // Returns: void
1474 // proff/nicolas 09/20/98 -- changed for hi-res
1475 // CPhipps - patch drawing updated
1476 void WI_drawNetgameStats(void)
1478 int i;
1479 int x;
1480 int y;
1481 int pwidth = V_NamePatchWidth(percent);
1482 int fwidth = V_NamePatchWidth(facebackp);
1484 WI_slamBackground();
1486 // draw animated background
1487 WI_drawAnimatedBack();
1489 WI_drawLF();
1491 // draw stat titles (top line)
1492 V_DrawNamePatch(NG_STATSX+NG_SPACINGX-V_NamePatchWidth(kills),
1493 NG_STATSY, FB, kills, CR_DEFAULT, VPT_STRETCH);
1495 V_DrawNamePatch(NG_STATSX+2*NG_SPACINGX-V_NamePatchWidth(items),
1496 NG_STATSY, FB, items, CR_DEFAULT, VPT_STRETCH);
1498 V_DrawNamePatch(NG_STATSX+3*NG_SPACINGX-V_NamePatchWidth(secret),
1499 NG_STATSY, FB, secret, CR_DEFAULT, VPT_STRETCH);
1501 if (dofrags)
1502 V_DrawNamePatch(NG_STATSX+4*NG_SPACINGX-V_NamePatchWidth(frags),
1503 NG_STATSY, FB, frags, CR_DEFAULT, VPT_STRETCH);
1505 // draw stats
1506 y = NG_STATSY + V_NamePatchHeight(kills);
1508 for (i=0 ; i<MAXPLAYERS ; i++)
1510 //int trans = playernumtotrans[i];
1511 if (!playeringame[i])
1512 continue;
1514 x = NG_STATSX;
1515 V_DrawNamePatch(x-fwidth, y, FB, facebackp,
1516 i ? CR_LIMIT+i : CR_DEFAULT,
1517 VPT_STRETCH | (i ? VPT_TRANS : 0));
1519 if (i == me)
1520 V_DrawNamePatch(x-fwidth, y, FB, star, CR_DEFAULT, VPT_STRETCH);
1522 x += NG_SPACINGX;
1523 WI_drawPercent(x-pwidth, y+10, cnt_kills[i]); x += NG_SPACINGX;
1524 WI_drawPercent(x-pwidth, y+10, cnt_items[i]); x += NG_SPACINGX;
1525 WI_drawPercent(x-pwidth, y+10, cnt_secret[i]); x += NG_SPACINGX;
1527 if (dofrags)
1528 WI_drawNum(x, y+10, cnt_frags[i], -1);
1530 y += WI_SPACINGY;
1533 if (y <= SP_TIMEY)
1534 // cph - show times in coop on the entering screen
1535 WI_drawTimeStats(plrs[me].stime / TICRATE, wbs->totaltimes / TICRATE, wbs->partime / TICRATE);
1538 static int sp_state;
1540 // ====================================================================
1541 // WI_initStats
1542 // Purpose: Get ready for single player stats
1543 // Args: none
1544 // Returns: void
1545 // Comment: Seems like we could do all these stats in a more generic
1546 // set of routines that weren't duplicated for dm, coop, sp
1548 void WI_initStats(void)
1550 state = StatCount;
1551 acceleratestage = 0;
1552 sp_state = 1;
1554 // CPhipps - allocate (awful code, I know, but saves changing it all) and initialise
1555 *(cnt_kills = malloc(sizeof(*cnt_kills))) =
1556 *(cnt_items = malloc(sizeof(*cnt_items))) =
1557 *(cnt_secret= malloc(sizeof(*cnt_secret))) = -1;
1558 cnt_time = cnt_par = cnt_total_time = -1;
1559 cnt_pause = TICRATE;
1561 WI_initAnimatedBack();
1564 // ====================================================================
1565 // WI_updateStats
1566 // Purpose: Calculate solo stats
1567 // Args: none
1568 // Returns: void
1570 void WI_updateStats(void)
1572 WI_updateAnimatedBack();
1574 if (acceleratestage && sp_state != 10)
1576 acceleratestage = 0;
1577 cnt_kills[0] = (plrs[me].skills * 100) / wbs->maxkills;
1578 cnt_items[0] = (plrs[me].sitems * 100) / wbs->maxitems;
1580 // killough 2/22/98: Make secrets = 100% if maxsecret = 0:
1581 cnt_secret[0] = (wbs->maxsecret ?
1582 (plrs[me].ssecret * 100) / wbs->maxsecret : 100);
1584 cnt_total_time = wbs->totaltimes / TICRATE;
1585 cnt_time = plrs[me].stime / TICRATE;
1586 cnt_par = wbs->partime / TICRATE;
1587 S_StartSound(0, sfx_barexp);
1588 sp_state = 10;
1591 if (sp_state == 2)
1593 cnt_kills[0] += 2;
1595 if (!(bcnt&3))
1596 S_StartSound(0, sfx_pistol);
1598 if (cnt_kills[0] >= (plrs[me].skills * 100) / wbs->maxkills)
1600 cnt_kills[0] = (plrs[me].skills * 100) / wbs->maxkills;
1601 S_StartSound(0, sfx_barexp);
1602 sp_state++;
1605 else if (sp_state == 4)
1607 cnt_items[0] += 2;
1609 if (!(bcnt&3))
1610 S_StartSound(0, sfx_pistol);
1612 if (cnt_items[0] >= (plrs[me].sitems * 100) / wbs->maxitems)
1614 cnt_items[0] = (plrs[me].sitems * 100) / wbs->maxitems;
1615 S_StartSound(0, sfx_barexp);
1616 sp_state++;
1619 else if (sp_state == 6)
1621 cnt_secret[0] += 2;
1623 if (!(bcnt&3))
1624 S_StartSound(0, sfx_pistol);
1626 // killough 2/22/98: Make secrets = 100% if maxsecret = 0:
1627 if ((!wbs->maxsecret && compatibility_level < lxdoom_1_compatibility) ||
1628 cnt_secret[0] >= (wbs->maxsecret ?
1629 (plrs[me].ssecret * 100) / wbs->maxsecret : 100))
1631 cnt_secret[0] = (wbs->maxsecret ?
1632 (plrs[me].ssecret * 100) / wbs->maxsecret : 100);
1633 S_StartSound(0, sfx_barexp);
1634 sp_state++;
1637 else if (sp_state == 8)
1639 if (!(bcnt&3))
1640 S_StartSound(0, sfx_pistol);
1642 cnt_time += 3;
1644 if (cnt_time >= plrs[me].stime / TICRATE)
1645 cnt_time = plrs[me].stime / TICRATE;
1647 cnt_total_time += 3;
1649 if (cnt_total_time >= wbs->totaltimes / TICRATE)
1650 cnt_total_time = wbs->totaltimes / TICRATE;
1652 cnt_par += 3;
1654 if (cnt_par >= wbs->partime / TICRATE)
1656 cnt_par = wbs->partime / TICRATE;
1658 if ((cnt_time >= plrs[me].stime / TICRATE) && (compatibility_level < lxdoom_1_compatibility || cnt_total_time >= wbs->totaltimes / TICRATE))
1660 S_StartSound(0, sfx_barexp);
1661 sp_state++;
1665 else if (sp_state == 10)
1667 if (acceleratestage)
1669 S_StartSound(0, sfx_sgcock);
1671 if (gamemode == commercial)
1672 WI_initNoState();
1673 else
1674 WI_initShowNextLoc();
1677 else if (sp_state & 1)
1679 if (!--cnt_pause)
1681 sp_state++;
1682 cnt_pause = TICRATE;
1688 // ====================================================================
1689 // WI_drawStats
1690 // Purpose: Put the solo stats on the screen
1691 // Args: none
1692 // Returns: void
1694 // proff/nicolas 09/20/98 -- changed for hi-res
1695 // CPhipps - patch drawing updated
1696 void WI_drawStats(void)
1698 // line height
1699 int lh;
1701 lh = (3*SHORT(num[0]->height))/2;
1703 WI_slamBackground();
1705 // draw animated background
1706 WI_drawAnimatedBack();
1708 WI_drawLF();
1710 V_DrawNamePatch(SP_STATSX, SP_STATSY, FB, kills, CR_DEFAULT, VPT_STRETCH);
1711 WI_drawPercent(320 - SP_STATSX, SP_STATSY, cnt_kills[0]);
1713 V_DrawNamePatch(SP_STATSX, SP_STATSY+lh, FB, items, CR_DEFAULT, VPT_STRETCH);
1714 WI_drawPercent(320 - SP_STATSX, SP_STATSY+lh, cnt_items[0]);
1716 V_DrawNamePatch(SP_STATSX, SP_STATSY+2*lh, FB, sp_secret, CR_DEFAULT, VPT_STRETCH);
1717 WI_drawPercent(320 - SP_STATSX, SP_STATSY+2*lh, cnt_secret[0]);
1719 WI_drawTimeStats(cnt_time, cnt_total_time, cnt_par);
1722 // ====================================================================
1723 // WI_checkForAccelerate
1724 // Purpose: See if the player has hit either the attack or use key
1725 // or mouse button. If so we set acceleratestage to 1 and
1726 // all those display routines above jump right to the end.
1727 // Args: none
1728 // Returns: void
1730 void WI_checkForAccelerate(void)
1732 int i;
1733 player_t *player;
1735 // check for button presses to skip delays
1736 for (i=0, player = players ; i<MAXPLAYERS ; i++, player++)
1738 if (playeringame[i])
1740 if (player->cmd.buttons & BT_ATTACK)
1742 if (!player->attackdown)
1743 acceleratestage = 1;
1744 player->attackdown = true;
1746 else
1747 player->attackdown = false;
1749 if (player->cmd.buttons & BT_USE)
1751 if (!player->usedown)
1752 acceleratestage = 1;
1753 player->usedown = true;
1755 else
1756 player->usedown = false;
1761 // ====================================================================
1762 // WI_Ticker
1763 // Purpose: Do various updates every gametic, for stats, animation,
1764 // checking that intermission music is running, etc.
1765 // Args: none
1766 // Returns: void
1768 void WI_Ticker(void)
1770 // counter for general background animation
1771 bcnt++;
1773 if (bcnt == 1)
1775 // intermission music
1776 if ( gamemode == commercial )
1777 S_ChangeMusic(mus_dm2int, true);
1778 else
1779 S_ChangeMusic(mus_inter, true);
1782 WI_checkForAccelerate();
1784 switch (state)
1786 case StatCount:
1787 if (deathmatch) WI_updateDeathmatchStats();
1788 else if (netgame) WI_updateNetgameStats();
1789 else WI_updateStats();
1790 break;
1792 case ShowNextLoc:
1793 WI_updateShowNextLoc();
1794 break;
1796 case NoState:
1797 WI_updateNoState();
1798 break;
1802 /* ====================================================================
1803 * WI_loadData
1804 * Purpose: Initialize intermission data such as background graphics,
1805 * patches, map names, etc.
1806 * Args: none
1807 * Returns: void
1809 * CPhipps - modified for new wad lump handling.
1810 * - no longer preload most graphics, other funcs can use
1811 * them by name
1814 void WI_loadData(void)
1816 int i;
1817 int j;
1818 char name[9]; // limited to 8 characters
1819 anim_t* a;
1821 if (gamemode != commercial)
1823 if (wbs->epsd < 3)
1825 for (j=0;j<NUMANIMS[wbs->epsd];j++)
1827 a = &anims[wbs->epsd][j];
1828 for (i=0;i<a->nanims;i++)
1830 // MONDO HACK!
1831 if (wbs->epsd != 1 || j != 8)
1833 // animations
1834 snprintf(name, sizeof(name),"WIA%d%s%d%s%d", wbs->epsd, (j/10>0?"":"0"), j,(i/10>0?"":"0"), i); //ANOTHER ROCKHACK
1835 //snprintf(name, sizeof(name),"WIA%d%.2d%.2d", wbs->epsd, j, i);
1836 a->p[i] = W_CacheLumpName(name);
1838 else
1840 // HACK ALERT!
1841 a->p[i] = anims[1][4].p[i];
1848 for (i=0;i<10;i++)
1850 // numbers 0-9
1851 snprintf(name,sizeof(name),"WINUM%d", i);
1852 num[i] = W_CacheLumpName(name);
1856 // ====================================================================
1857 // WI_unloadData
1858 // Purpose: Free up the space allocated during WI_loadData
1859 // Args: none
1860 // Returns: void
1862 // CPhipps - reverse of WI_loadData, goes through the same lumps, but unlocking
1863 void WI_unloadData(void)
1865 int i,j;
1866 char name[9]; // limited to 8 characters
1868 // cph - unlock gamemode dependent stuff here
1869 if (gamemode != commercial) {
1870 if (wbs->epsd < 3) {
1871 for (j=0;j<NUMANIMS[wbs->epsd];j++) {
1872 anim_t* a = &anims[wbs->epsd][j];
1873 for (i=0; i<a->nanims; i++) {
1874 // MONDO HACK!
1875 if (wbs->epsd != 1 || j != 8) {
1876 // animations
1877 snprintf(name, sizeof(name),"WIA%d%s%d%s%d", wbs->epsd, (j/10>0?"":"0"), j,(i/10>0?"":"0"), i); //ANOTHER ROCKHACK
1878 //snprintf(name,sizeof(name), "WIA%d%.2d%.2d", wbs->epsd, j, i);
1879 W_UnlockLumpName(name);
1886 for (i=0;i<10;i++) {
1887 // numbers 0-9
1888 snprintf(name, sizeof(name),"WINUM%d", i);
1889 W_UnlockLumpName(name);
1894 // ====================================================================
1895 // WI_Drawer
1896 // Purpose: Call the appropriate stats drawing routine depending on
1897 // what kind of game is being played (DM, coop, solo)
1898 // Args: none
1899 // Returns: void
1901 void WI_Drawer (void)
1903 switch (state)
1905 case StatCount:
1906 if (deathmatch)
1907 WI_drawDeathmatchStats();
1908 else if (netgame)
1909 WI_drawNetgameStats();
1910 else
1911 WI_drawStats();
1912 break;
1914 case ShowNextLoc:
1915 WI_drawShowNextLoc();
1916 break;
1918 case NoState:
1919 WI_drawNoState();
1920 break;
1924 // ====================================================================
1925 // WI_initVariables
1926 // Purpose: Initialize the intermission information structure
1927 // Note: wbstartstruct_t is defined in d_player.h
1928 // Args: wbstartstruct -- pointer to the structure with the data
1929 // Returns: void
1931 void WI_initVariables(wbstartstruct_t* wbstartstruct)
1934 wbs = wbstartstruct;
1936 #ifdef RANGECHECKING
1937 if (gamemode != commercial)
1939 if ( gamemode == retail )
1940 RNGCHECK(wbs->epsd, 0, 3);
1941 else
1942 RNGCHECK(wbs->epsd, 0, 2);
1944 else
1946 RNGCHECK(wbs->last, 0, 8);
1947 RNGCHECK(wbs->next, 0, 8);
1949 RNGCHECK(wbs->pnum, 0, MAXPLAYERS);
1950 RNGCHECK(wbs->pnum, 0, MAXPLAYERS);
1951 #endif
1953 acceleratestage = 0;
1954 cnt = bcnt = 0;
1955 firstrefresh = 1;
1956 me = wbs->pnum;
1957 plrs = wbs->plyr;
1959 if (!wbs->maxkills)
1960 wbs->maxkills = 1; // probably only useful in MAP30
1962 if (!wbs->maxitems)
1963 wbs->maxitems = 1;
1965 if ( gamemode != retail )
1966 if (wbs->epsd > 2)
1967 wbs->epsd -= 3;
1970 // ====================================================================
1971 // WI_Start
1972 // Purpose: Call the various init routines
1973 // Note: wbstartstruct_t is defined in d_player.h
1974 // Args: wbstartstruct -- pointer to the structure with the
1975 // intermission data
1976 // Returns: void
1978 void WI_Start(wbstartstruct_t* wbstartstruct)
1980 WI_initVariables(wbstartstruct);
1981 WI_loadData();
1983 if (deathmatch)
1984 WI_initDeathmatchStats();
1985 else if (netgame)
1986 WI_initNetgameStats();
1987 else
1988 WI_initStats();