1 //
2 // Copyright(C) 1993-1996 Id Software, Inc.
3 // Copyright(C) 2005-2014 Simon Howard
4 //
5 // This program is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU General Public License
7 // as published by the Free Software Foundation; either version 2
8 // of the License, or (at your option) any later version.
9 //
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 // GNU General Public License for more details.
14 //
15 // DESCRIPTION:
16 //	Intermission screens.
17 //
18 
19 
20 #include <stdio.h>
21 
22 #include "z_zone.h"
23 
24 #include "m_misc.h"
25 #include "m_random.h"
26 
27 #include "deh_main.h"
28 #include "i_swap.h"
29 #include "i_system.h"
30 
31 #include "w_wad.h"
32 
33 #include "g_game.h"
34 
35 #include "r_local.h"
36 #include "s_sound.h"
37 
38 #include "doomstat.h"
39 
40 // Data.
41 #include "sounds.h"
42 
43 // Needs access to LFB.
44 #include "v_video.h"
45 
46 #include "wi_stuff.h"
47 
48 //
49 // Data needed to add patches to full screen intermission pics.
50 // Patches are statistics messages, and animations.
51 // Loads of by-pixel layout and placement, offsets etc.
52 //
53 
54 
55 //
56 // Different vetween registered DOOM (1994) and
57 //  Ultimate DOOM - Final edition (retail, 1995?).
58 // This is supposedly ignored for commercial
59 //  release (aka DOOM II), which had 34 maps
60 //  in one episode. So there.
61 #define NUMEPISODES	4
62 #define NUMMAPS		9
63 
64 
65 // in tics
66 //U #define PAUSELEN		(TICRATE*2)
67 //U #define SCORESTEP		100
68 //U #define ANIMPERIOD		32
69 // pixel distance from "(YOU)" to "PLAYER N"
70 //U #define STARDIST		10
71 //U #define WK 1
72 
73 
74 // GLOBAL LOCATIONS
75 #define WI_TITLEY		2
76 #define WI_SPACINGY    		33
77 
78 // SINGPLE-PLAYER STUFF
79 #define SP_STATSX		50
80 #define SP_STATSY		50
81 
82 #define SP_TIMEX		16
83 #define SP_TIMEY		(SCREENHEIGHT-32)
84 
85 
86 // NET GAME STUFF
87 #define NG_STATSY		50
88 #define NG_STATSX		(32 + SHORT(star->width)/2 + 32*!dofrags)
89 
90 #define NG_SPACINGX    		64
91 
92 
93 // DEATHMATCH STUFF
94 #define DM_MATRIXX		42
95 #define DM_MATRIXY		68
96 
97 #define DM_SPACINGX		40
98 
99 #define DM_TOTALSX		269
100 
101 #define DM_KILLERSX		10
102 #define DM_KILLERSY		100
103 #define DM_VICTIMSX    		5
104 #define DM_VICTIMSY		50
105 
106 
107 
108 
109 typedef enum
110 {
111     ANIM_ALWAYS,
112     ANIM_RANDOM,
113     ANIM_LEVEL
114 
115 } animenum_t;
116 
117 typedef struct
118 {
119     int		x;
120     int		y;
121 
122 } point_t;
123 
124 
125 //
126 // Animation.
127 // There is another anim_t used in p_spec.
128 //
129 typedef struct
130 {
131     animenum_t	type;
132 
133     // period in tics between animations
134     int		period;
135 
136     // number of animation frames
137     int		nanims;
138 
139     // location of animation
140     point_t	loc;
141 
142     // ALWAYS: n/a,
143     // RANDOM: period deviation (<256),
144     // LEVEL: level
145     int		data1;
146 
147     // ALWAYS: n/a,
148     // RANDOM: random base period,
149     // LEVEL: n/a
150     int		data2;
151 
152     // actual graphics for frames of animations
153     patch_t*	p[3];
154 
155     // following must be initialized to zero before use!
156 
157     // next value of bcnt (used in conjunction with period)
158     int		nexttic;
159 
160     // last drawn animation frame
161     int		lastdrawn;
162 
163     // next frame number to animate
164     int		ctr;
165 
166     // used by RANDOM and LEVEL when animating
167     int		state;
168 
169 } anim_t;
170 
171 
172 static point_t lnodes[NUMEPISODES][NUMMAPS] =
173 {
174     // Episode 0 World Map
175     {
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)
185     },
186 
187     // Episode 1 World Map should go here
188     {
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)
198     },
199 
200     // Episode 2 World Map should go here
201     {
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)
211     }
212 
213 };
214 
215 
216 //
217 // Animation locations for episode 0 (1).
218 // Using patches saves a lot of space,
219 //  as they replace 320x200 full screen frames.
220 //
221 
222 #define ANIM(type, period, nanims, x, y, nexttic)            \
223    { (type), (period), (nanims), { (x), (y) }, (nexttic),    \
224      0, { NULL, NULL, NULL }, 0, 0, 0, 0 }
225 
226 
227 static anim_t epsd0animinfo[] =
228 {
229     ANIM(ANIM_ALWAYS, TICRATE/3, 3, 224, 104, 0),
230     ANIM(ANIM_ALWAYS, TICRATE/3, 3, 184, 160, 0),
231     ANIM(ANIM_ALWAYS, TICRATE/3, 3, 112, 136, 0),
232     ANIM(ANIM_ALWAYS, TICRATE/3, 3, 72, 112, 0),
233     ANIM(ANIM_ALWAYS, TICRATE/3, 3, 88, 96, 0),
234     ANIM(ANIM_ALWAYS, TICRATE/3, 3, 64, 48, 0),
235     ANIM(ANIM_ALWAYS, TICRATE/3, 3, 192, 40, 0),
236     ANIM(ANIM_ALWAYS, TICRATE/3, 3, 136, 16, 0),
237     ANIM(ANIM_ALWAYS, TICRATE/3, 3, 80, 16, 0),
238     ANIM(ANIM_ALWAYS, TICRATE/3, 3, 64, 24, 0),
239 };
240 
241 static anim_t epsd1animinfo[] =
242 {
243     ANIM(ANIM_LEVEL, TICRATE/3, 1, 128, 136, 1),
244     ANIM(ANIM_LEVEL, TICRATE/3, 1, 128, 136, 2),
245     ANIM(ANIM_LEVEL, TICRATE/3, 1, 128, 136, 3),
246     ANIM(ANIM_LEVEL, TICRATE/3, 1, 128, 136, 4),
247     ANIM(ANIM_LEVEL, TICRATE/3, 1, 128, 136, 5),
248     ANIM(ANIM_LEVEL, TICRATE/3, 1, 128, 136, 6),
249     ANIM(ANIM_LEVEL, TICRATE/3, 1, 128, 136, 7),
250     ANIM(ANIM_LEVEL, TICRATE/3, 3, 192, 144, 8),
251     ANIM(ANIM_LEVEL, TICRATE/3, 1, 128, 136, 8),
252 };
253 
254 static anim_t epsd2animinfo[] =
255 {
256     ANIM(ANIM_ALWAYS, TICRATE/3, 3, 104, 168, 0),
257     ANIM(ANIM_ALWAYS, TICRATE/3, 3, 40, 136, 0),
258     ANIM(ANIM_ALWAYS, TICRATE/3, 3, 160, 96, 0),
259     ANIM(ANIM_ALWAYS, TICRATE/3, 3, 104, 80, 0),
260     ANIM(ANIM_ALWAYS, TICRATE/3, 3, 120, 32, 0),
261     ANIM(ANIM_ALWAYS, TICRATE/4, 3, 40, 0, 0),
262 };
263 
264 static int NUMANIMS[NUMEPISODES] =
265 {
266     arrlen(epsd0animinfo),
267     arrlen(epsd1animinfo),
268     arrlen(epsd2animinfo),
269 };
270 
271 static anim_t *anims[NUMEPISODES] =
272 {
273     epsd0animinfo,
274     epsd1animinfo,
275     epsd2animinfo
276 };
277 
278 
279 //
280 // GENERAL DATA
281 //
282 
283 //
284 // Locally used stuff.
285 //
286 
287 // States for single-player
288 #define SP_KILLS		0
289 #define SP_ITEMS		2
290 #define SP_SECRET		4
291 #define SP_FRAGS		6
292 #define SP_TIME			8
293 #define SP_PAR			ST_TIME
294 
295 #define SP_PAUSE		1
296 
297 // in seconds
298 #define SHOWNEXTLOCDELAY	4
299 //#define SHOWLASTLOCDELAY	SHOWNEXTLOCDELAY
300 
301 
302 // used to accelerate or skip a stage
303 static int		acceleratestage;
304 
305 // wbs->pnum
306 static int		me;
307 
308  // specifies current state
309 static stateenum_t	state;
310 
311 // contains information passed into intermission
312 static wbstartstruct_t*	wbs;
313 
314 static wbplayerstruct_t* plrs;  // wbs->plyr[]
315 
316 // used for general timing
317 static int 		cnt;
318 
319 // used for timing of background animation
320 static int 		bcnt;
321 
322 // signals to refresh everything for one frame
323 static int 		firstrefresh;
324 
325 static int		cnt_kills[MAXPLAYERS];
326 static int		cnt_items[MAXPLAYERS];
327 static int		cnt_secret[MAXPLAYERS];
328 static int		cnt_time;
329 static int		cnt_par;
330 static int		cnt_pause;
331 
332 // # of commercial levels
333 static int		NUMCMAPS;
334 
335 
336 //
337 //	GRAPHICS
338 //
339 
340 // You Are Here graphic
341 static patch_t*		yah[3] = { NULL, NULL, NULL };
342 
343 // splat
344 static patch_t*		splat[2] = { NULL, NULL };
345 
346 // %, : graphics
347 static patch_t*		percent;
348 static patch_t*		colon;
349 
350 // 0-9 graphic
351 static patch_t*		num[10];
352 
353 // minus sign
354 static patch_t*		wiminus;
355 
356 // "Finished!" graphics
357 static patch_t*		finished;
358 
359 // "Entering" graphic
360 static patch_t*		entering;
361 
362 // "secret"
363 static patch_t*		sp_secret;
364 
365  // "Kills", "Scrt", "Items", "Frags"
366 static patch_t*		kills;
367 static patch_t*		secret;
368 static patch_t*		items;
369 static patch_t*		frags;
370 
371 // Time sucks.
372 static patch_t*		timepatch;
373 static patch_t*		par;
374 static patch_t*		sucks;
375 
376 // "killers", "victims"
377 static patch_t*		killers;
378 static patch_t*		victims;
379 
380 // "Total", your face, your dead face
381 static patch_t*		total;
382 static patch_t*		star;
383 static patch_t*		bstar;
384 
385 // "red P[1..MAXPLAYERS]"
386 static patch_t*		p[MAXPLAYERS];
387 
388 // "gray P[1..MAXPLAYERS]"
389 static patch_t*		bp[MAXPLAYERS];
390 
391  // Name graphics of each level (centered)
392 static patch_t**	lnames;
393 
394 // Buffer storing the backdrop
395 static patch_t *background;
396 
397 //
398 // CODE
399 //
400 
401 // slam background
WI_slamBackground(void)402 void WI_slamBackground(void)
403 {
404     V_DrawPatch(0, 0, background);
405 }
406 
407 // The ticker is used to detect keys
408 //  because of timing issues in netgames.
WI_Responder(event_t * ev)409 boolean WI_Responder(event_t* ev)
410 {
411     return false;
412 }
413 
414 
415 // Draws "<Levelname> Finished!"
WI_drawLF(void)416 void WI_drawLF(void)
417 {
418     int y = WI_TITLEY;
419 
420     if (gamemode != commercial || wbs->last < NUMCMAPS)
421     {
422         // draw <LevelName>
423         V_DrawPatch((SCREENWIDTH - SHORT(lnames[wbs->last]->width))/2,
424                     y, lnames[wbs->last]);
425 
426         // draw "Finished!"
427         y += (5*SHORT(lnames[wbs->last]->height))/4;
428 
429         V_DrawPatch((SCREENWIDTH - SHORT(finished->width)) / 2, y, finished);
430     }
431     else if (wbs->last == NUMCMAPS)
432     {
433         // MAP33 - nothing is displayed!
434     }
435     else if (wbs->last > NUMCMAPS)
436     {
437         // > MAP33.  Doom bombs out here with a Bad V_DrawPatch error.
438         // I'm pretty sure that doom2.exe is just reading into random
439         // bits of memory at this point, but let's try to be accurate
440         // anyway.  This deliberately triggers a V_DrawPatch error.
441 
442         patch_t tmp = { SCREENWIDTH, SCREENHEIGHT, 1, 1,
443                         { 0, 0, 0, 0, 0, 0, 0, 0 } };
444 
445         V_DrawPatch(0, y, &tmp);
446     }
447 }
448 
449 
450 
451 // Draws "Entering <LevelName>"
WI_drawEL(void)452 void WI_drawEL(void)
453 {
454     int y = WI_TITLEY;
455 
456     // draw "Entering"
457     V_DrawPatch((SCREENWIDTH - SHORT(entering->width))/2,
458 		y,
459                 entering);
460 
461     // draw level
462     y += (5*SHORT(lnames[wbs->next]->height))/4;
463 
464     V_DrawPatch((SCREENWIDTH - SHORT(lnames[wbs->next]->width))/2,
465 		y,
466                 lnames[wbs->next]);
467 
468 }
469 
470 void
WI_drawOnLnode(int n,patch_t * c[])471 WI_drawOnLnode
472 ( int		n,
473   patch_t*	c[] )
474 {
475 
476     int		i;
477     int		left;
478     int		top;
479     int		right;
480     int		bottom;
481     boolean	fits = false;
482 
483     i = 0;
484     do
485     {
486 	left = lnodes[wbs->epsd][n].x - SHORT(c[i]->leftoffset);
487 	top = lnodes[wbs->epsd][n].y - SHORT(c[i]->topoffset);
488 	right = left + SHORT(c[i]->width);
489 	bottom = top + SHORT(c[i]->height);
490 
491 	if (left >= 0
492 	    && right < SCREENWIDTH
493 	    && top >= 0
494 	    && bottom < SCREENHEIGHT)
495 	{
496 	    fits = true;
497 	}
498 	else
499 	{
500 	    i++;
501 	}
502     } while (!fits && i!=2 && c[i] != NULL);
503 
504     if (fits && i<2)
505     {
506 	V_DrawPatch(lnodes[wbs->epsd][n].x,
507                     lnodes[wbs->epsd][n].y,
508 		    c[i]);
509     }
510     else
511     {
512 	// DEBUG
513 	printf("Could not place patch on level %d", n+1);
514     }
515 }
516 
517 
518 
WI_initAnimatedBack(void)519 void WI_initAnimatedBack(void)
520 {
521     int		i;
522     anim_t*	a;
523 
524     if (gamemode == commercial)
525 	return;
526 
527     if (wbs->epsd > 2)
528 	return;
529 
530     for (i=0;i<NUMANIMS[wbs->epsd];i++)
531     {
532 	a = &anims[wbs->epsd][i];
533 
534 	// init variables
535 	a->ctr = -1;
536 
537 	// specify the next time to draw it
538 	if (a->type == ANIM_ALWAYS)
539 	    a->nexttic = bcnt + 1 + (M_Random()%a->period);
540 	else if (a->type == ANIM_RANDOM)
541 	    a->nexttic = bcnt + 1 + a->data2+(M_Random()%a->data1);
542 	else if (a->type == ANIM_LEVEL)
543 	    a->nexttic = bcnt + 1;
544     }
545 
546 }
547 
WI_updateAnimatedBack(void)548 void WI_updateAnimatedBack(void)
549 {
550     int		i;
551     anim_t*	a;
552 
553     if (gamemode == commercial)
554 	return;
555 
556     if (wbs->epsd > 2)
557 	return;
558 
559     for (i=0;i<NUMANIMS[wbs->epsd];i++)
560     {
561 	a = &anims[wbs->epsd][i];
562 
563 	if (bcnt == a->nexttic)
564 	{
565 	    switch (a->type)
566 	    {
567 	      case ANIM_ALWAYS:
568 		if (++a->ctr >= a->nanims) a->ctr = 0;
569 		a->nexttic = bcnt + a->period;
570 		break;
571 
572 	      case ANIM_RANDOM:
573 		a->ctr++;
574 		if (a->ctr == a->nanims)
575 		{
576 		    a->ctr = -1;
577 		    a->nexttic = bcnt+a->data2+(M_Random()%a->data1);
578 		}
579 		else a->nexttic = bcnt + a->period;
580 		break;
581 
582 	      case ANIM_LEVEL:
583 		// gawd-awful hack for level anims
584 		if (!(state == StatCount && i == 7)
585 		    && wbs->next == a->data1)
586 		{
587 		    a->ctr++;
588 		    if (a->ctr == a->nanims) a->ctr--;
589 		    a->nexttic = bcnt + a->period;
590 		}
591 		break;
592 	    }
593 	}
594 
595     }
596 
597 }
598 
WI_drawAnimatedBack(void)599 void WI_drawAnimatedBack(void)
600 {
601     int			i;
602     anim_t*		a;
603 
604     if (gamemode == commercial)
605 	return;
606 
607     if (wbs->epsd > 2)
608 	return;
609 
610     for (i=0 ; i<NUMANIMS[wbs->epsd] ; i++)
611     {
612 	a = &anims[wbs->epsd][i];
613 
614 	if (a->ctr >= 0)
615 	    V_DrawPatch(a->loc.x, a->loc.y, a->p[a->ctr]);
616     }
617 
618 }
619 
620 //
621 // Draws a number.
622 // If digits > 0, then use that many digits minimum,
623 //  otherwise only use as many as necessary.
624 // Returns new x position.
625 //
626 
627 int
WI_drawNum(int x,int y,int n,int digits)628 WI_drawNum
629 ( int		x,
630   int		y,
631   int		n,
632   int		digits )
633 {
634 
635     int		fontwidth = SHORT(num[0]->width);
636     int		neg;
637     int		temp;
638 
639     if (digits < 0)
640     {
641 	if (!n)
642 	{
643 	    // make variable-length zeros 1 digit long
644 	    digits = 1;
645 	}
646 	else
647 	{
648 	    // figure out # of digits in #
649 	    digits = 0;
650 	    temp = n;
651 
652 	    while (temp)
653 	    {
654 		temp /= 10;
655 		digits++;
656 	    }
657 	}
658     }
659 
660     neg = n < 0;
661     if (neg)
662 	n = -n;
663 
664     // if non-number, do not draw it
665     if (n == 1994)
666 	return 0;
667 
668     // draw the new number
669     while (digits--)
670     {
671 	x -= fontwidth;
672 	V_DrawPatch(x, y, num[ n % 10 ]);
673 	n /= 10;
674     }
675 
676     // draw a minus sign if necessary
677     if (neg)
678 	V_DrawPatch(x-=8, y, wiminus);
679 
680     return x;
681 
682 }
683 
684 void
WI_drawPercent(int x,int y,int p)685 WI_drawPercent
686 ( int		x,
687   int		y,
688   int		p )
689 {
690     if (p < 0)
691 	return;
692 
693     V_DrawPatch(x, y, percent);
694     WI_drawNum(x, y, p, -1);
695 }
696 
697 
698 
699 //
700 // Display level completion time and par,
701 //  or "sucks" message if overflow.
702 //
703 void
WI_drawTime(int x,int y,int t)704 WI_drawTime
705 ( int		x,
706   int		y,
707   int		t )
708 {
709 
710     int		div;
711     int		n;
712 
713     if (t<0)
714 	return;
715 
716     if (t <= 61*59)
717     {
718 	div = 1;
719 
720 	do
721 	{
722 	    n = (t / div) % 60;
723 	    x = WI_drawNum(x, y, n, 2) - SHORT(colon->width);
724 	    div *= 60;
725 
726 	    // draw
727 	    if (div==60 || t / div)
728 		V_DrawPatch(x, y, colon);
729 
730 	} while (t / div);
731     }
732     else
733     {
734 	// "sucks"
735 	V_DrawPatch(x - SHORT(sucks->width), y, sucks);
736     }
737 }
738 
739 
WI_End(void)740 void WI_End(void)
741 {
742     void WI_unloadData(void);
743     WI_unloadData();
744 }
745 
WI_initNoState(void)746 void WI_initNoState(void)
747 {
748     state = NoState;
749     acceleratestage = 0;
750     cnt = 10;
751 }
752 
WI_updateNoState(void)753 void WI_updateNoState(void) {
754 
755     WI_updateAnimatedBack();
756 
757     if (!--cnt)
758     {
759         // Don't call WI_End yet.  G_WorldDone doesnt immediately
760         // change gamestate, so WI_Drawer is still going to get
761         // run until that happens.  If we do that after WI_End
762         // (which unloads all the graphics), we're in trouble.
763 	//WI_End();
764 	G_WorldDone();
765     }
766 
767 }
768 
769 static boolean		snl_pointeron = false;
770 
771 
WI_initShowNextLoc(void)772 void WI_initShowNextLoc(void)
773 {
774     state = ShowNextLoc;
775     acceleratestage = 0;
776     cnt = SHOWNEXTLOCDELAY * TICRATE;
777 
778     WI_initAnimatedBack();
779 }
780 
WI_updateShowNextLoc(void)781 void WI_updateShowNextLoc(void)
782 {
783     WI_updateAnimatedBack();
784 
785     if (!--cnt || acceleratestage)
786 	WI_initNoState();
787     else
788 	snl_pointeron = (cnt & 31) < 20;
789 }
790 
WI_drawShowNextLoc(void)791 void WI_drawShowNextLoc(void)
792 {
793 
794     int		i;
795     int		last;
796 
797     WI_slamBackground();
798 
799     // draw animated background
800     WI_drawAnimatedBack();
801 
802     if ( gamemode != commercial)
803     {
804   	if (wbs->epsd > 2)
805 	{
806 	    WI_drawEL();
807 	    return;
808 	}
809 
810 	last = (wbs->last == 8) ? wbs->next - 1 : wbs->last;
811 
812 	// draw a splat on taken cities.
813 	for (i=0 ; i<=last ; i++)
814 	    WI_drawOnLnode(i, splat);
815 
816 	// splat the secret level?
817 	if (wbs->didsecret)
818 	    WI_drawOnLnode(8, splat);
819 
820 	// draw flashing ptr
821 	if (snl_pointeron)
822 	    WI_drawOnLnode(wbs->next, yah);
823     }
824 
825     // draws which level you are entering..
826     if ( (gamemode != commercial)
827 	 || wbs->next != 30)
828 	WI_drawEL();
829 
830 }
831 
WI_drawNoState(void)832 void WI_drawNoState(void)
833 {
834     snl_pointeron = true;
835     WI_drawShowNextLoc();
836 }
837 
WI_fragSum(int playernum)838 int WI_fragSum(int playernum)
839 {
840     int		i;
841     int		frags = 0;
842 
843     for (i=0 ; i<MAXPLAYERS ; i++)
844     {
845 	if (playeringame[i]
846 	    && i!=playernum)
847 	{
848 	    frags += plrs[playernum].frags[i];
849 	}
850     }
851 
852 
853     // JDC hack - negative frags.
854     frags -= plrs[playernum].frags[playernum];
855     // UNUSED if (frags < 0)
856     // 	frags = 0;
857 
858     return frags;
859 }
860 
861 
862 
863 static int		dm_state;
864 static int		dm_frags[MAXPLAYERS][MAXPLAYERS];
865 static int		dm_totals[MAXPLAYERS];
866 
867 
868 
WI_initDeathmatchStats(void)869 void WI_initDeathmatchStats(void)
870 {
871 
872     int		i;
873     int		j;
874 
875     state = StatCount;
876     acceleratestage = 0;
877     dm_state = 1;
878 
879     cnt_pause = TICRATE;
880 
881     for (i=0 ; i<MAXPLAYERS ; i++)
882     {
883 	if (playeringame[i])
884 	{
885 	    for (j=0 ; j<MAXPLAYERS ; j++)
886 		if (playeringame[j])
887 		    dm_frags[i][j] = 0;
888 
889 	    dm_totals[i] = 0;
890 	}
891     }
892 
893     WI_initAnimatedBack();
894 }
895 
896 
897 
WI_updateDeathmatchStats(void)898 void WI_updateDeathmatchStats(void)
899 {
900 
901     int		i;
902     int		j;
903 
904     boolean	stillticking;
905 
906     WI_updateAnimatedBack();
907 
908     if (acceleratestage && dm_state != 4)
909     {
910 	acceleratestage = 0;
911 
912 	for (i=0 ; i<MAXPLAYERS ; i++)
913 	{
914 	    if (playeringame[i])
915 	    {
916 		for (j=0 ; j<MAXPLAYERS ; j++)
917 		    if (playeringame[j])
918 			dm_frags[i][j] = plrs[i].frags[j];
919 
920 		dm_totals[i] = WI_fragSum(i);
921 	    }
922 	}
923 
924 
925 	S_StartSound(0, sfx_barexp);
926 	dm_state = 4;
927     }
928 
929 
930     if (dm_state == 2)
931     {
932 	if (!(bcnt&3))
933 	    S_StartSound(0, sfx_pistol);
934 
935 	stillticking = false;
936 
937 	for (i=0 ; i<MAXPLAYERS ; i++)
938 	{
939 	    if (playeringame[i])
940 	    {
941 		for (j=0 ; j<MAXPLAYERS ; j++)
942 		{
943 		    if (playeringame[j]
944 			&& dm_frags[i][j] != plrs[i].frags[j])
945 		    {
946 			if (plrs[i].frags[j] < 0)
947 			    dm_frags[i][j]--;
948 			else
949 			    dm_frags[i][j]++;
950 
951 			if (dm_frags[i][j] > 99)
952 			    dm_frags[i][j] = 99;
953 
954 			if (dm_frags[i][j] < -99)
955 			    dm_frags[i][j] = -99;
956 
957 			stillticking = true;
958 		    }
959 		}
960 		dm_totals[i] = WI_fragSum(i);
961 
962 		if (dm_totals[i] > 99)
963 		    dm_totals[i] = 99;
964 
965 		if (dm_totals[i] < -99)
966 		    dm_totals[i] = -99;
967 	    }
968 
969 	}
970 	if (!stillticking)
971 	{
972 	    S_StartSound(0, sfx_barexp);
973 	    dm_state++;
974 	}
975 
976     }
977     else if (dm_state == 4)
978     {
979 	if (acceleratestage)
980 	{
981 	    S_StartSound(0, sfx_slop);
982 
983 	    if ( gamemode == commercial)
984 		WI_initNoState();
985 	    else
986 		WI_initShowNextLoc();
987 	}
988     }
989     else if (dm_state & 1)
990     {
991 	if (!--cnt_pause)
992 	{
993 	    dm_state++;
994 	    cnt_pause = TICRATE;
995 	}
996     }
997 }
998 
999 
1000 
WI_drawDeathmatchStats(void)1001 void WI_drawDeathmatchStats(void)
1002 {
1003 
1004     int		i;
1005     int		j;
1006     int		x;
1007     int		y;
1008     int		w;
1009 
1010     WI_slamBackground();
1011 
1012     // draw animated background
1013     WI_drawAnimatedBack();
1014     WI_drawLF();
1015 
1016     // draw stat titles (top line)
1017     V_DrawPatch(DM_TOTALSX-SHORT(total->width)/2,
1018 		DM_MATRIXY-WI_SPACINGY+10,
1019 		total);
1020 
1021     V_DrawPatch(DM_KILLERSX, DM_KILLERSY, killers);
1022     V_DrawPatch(DM_VICTIMSX, DM_VICTIMSY, victims);
1023 
1024     // draw P?
1025     x = DM_MATRIXX + DM_SPACINGX;
1026     y = DM_MATRIXY;
1027 
1028     for (i=0 ; i<MAXPLAYERS ; i++)
1029     {
1030 	if (playeringame[i])
1031 	{
1032 	    V_DrawPatch(x-SHORT(p[i]->width)/2,
1033 			DM_MATRIXY - WI_SPACINGY,
1034 			p[i]);
1035 
1036 	    V_DrawPatch(DM_MATRIXX-SHORT(p[i]->width)/2,
1037 			y,
1038 			p[i]);
1039 
1040 	    if (i == me)
1041 	    {
1042 		V_DrawPatch(x-SHORT(p[i]->width)/2,
1043 			    DM_MATRIXY - WI_SPACINGY,
1044 			    bstar);
1045 
1046 		V_DrawPatch(DM_MATRIXX-SHORT(p[i]->width)/2,
1047 			    y,
1048 			    star);
1049 	    }
1050 	}
1051 	else
1052 	{
1053 	    // V_DrawPatch(x-SHORT(bp[i]->width)/2,
1054 	    //   DM_MATRIXY - WI_SPACINGY, bp[i]);
1055 	    // V_DrawPatch(DM_MATRIXX-SHORT(bp[i]->width)/2,
1056 	    //   y, bp[i]);
1057 	}
1058 	x += DM_SPACINGX;
1059 	y += WI_SPACINGY;
1060     }
1061 
1062     // draw stats
1063     y = DM_MATRIXY+10;
1064     w = SHORT(num[0]->width);
1065 
1066     for (i=0 ; i<MAXPLAYERS ; i++)
1067     {
1068 	x = DM_MATRIXX + DM_SPACINGX;
1069 
1070 	if (playeringame[i])
1071 	{
1072 	    for (j=0 ; j<MAXPLAYERS ; j++)
1073 	    {
1074 		if (playeringame[j])
1075 		    WI_drawNum(x+w, y, dm_frags[i][j], 2);
1076 
1077 		x += DM_SPACINGX;
1078 	    }
1079 	    WI_drawNum(DM_TOTALSX+w, y, dm_totals[i], 2);
1080 	}
1081 	y += WI_SPACINGY;
1082     }
1083 }
1084 
1085 static int	cnt_frags[MAXPLAYERS];
1086 static int	dofrags;
1087 static int	ng_state;
1088 
WI_initNetgameStats(void)1089 void WI_initNetgameStats(void)
1090 {
1091 
1092     int i;
1093 
1094     state = StatCount;
1095     acceleratestage = 0;
1096     ng_state = 1;
1097 
1098     cnt_pause = TICRATE;
1099 
1100     for (i=0 ; i<MAXPLAYERS ; i++)
1101     {
1102 	if (!playeringame[i])
1103 	    continue;
1104 
1105 	cnt_kills[i] = cnt_items[i] = cnt_secret[i] = cnt_frags[i] = 0;
1106 
1107 	dofrags += WI_fragSum(i);
1108     }
1109 
1110     dofrags = !!dofrags;
1111 
1112     WI_initAnimatedBack();
1113 }
1114 
1115 
1116 
WI_updateNetgameStats(void)1117 void WI_updateNetgameStats(void)
1118 {
1119 
1120     int		i;
1121     int		fsum;
1122 
1123     boolean	stillticking;
1124 
1125     WI_updateAnimatedBack();
1126 
1127     if (acceleratestage && ng_state != 10)
1128     {
1129 	acceleratestage = 0;
1130 
1131 	for (i=0 ; i<MAXPLAYERS ; i++)
1132 	{
1133 	    if (!playeringame[i])
1134 		continue;
1135 
1136 	    cnt_kills[i] = (plrs[i].skills * 100) / wbs->maxkills;
1137 	    cnt_items[i] = (plrs[i].sitems * 100) / wbs->maxitems;
1138 	    cnt_secret[i] = (plrs[i].ssecret * 100) / wbs->maxsecret;
1139 
1140 	    if (dofrags)
1141 		cnt_frags[i] = WI_fragSum(i);
1142 	}
1143 	S_StartSound(0, sfx_barexp);
1144 	ng_state = 10;
1145     }
1146 
1147     if (ng_state == 2)
1148     {
1149 	if (!(bcnt&3))
1150 	    S_StartSound(0, sfx_pistol);
1151 
1152 	stillticking = false;
1153 
1154 	for (i=0 ; i<MAXPLAYERS ; i++)
1155 	{
1156 	    if (!playeringame[i])
1157 		continue;
1158 
1159 	    cnt_kills[i] += 2;
1160 
1161 	    if (cnt_kills[i] >= (plrs[i].skills * 100) / wbs->maxkills)
1162 		cnt_kills[i] = (plrs[i].skills * 100) / wbs->maxkills;
1163 	    else
1164 		stillticking = true;
1165 	}
1166 
1167 	if (!stillticking)
1168 	{
1169 	    S_StartSound(0, sfx_barexp);
1170 	    ng_state++;
1171 	}
1172     }
1173     else if (ng_state == 4)
1174     {
1175 	if (!(bcnt&3))
1176 	    S_StartSound(0, sfx_pistol);
1177 
1178 	stillticking = false;
1179 
1180 	for (i=0 ; i<MAXPLAYERS ; i++)
1181 	{
1182 	    if (!playeringame[i])
1183 		continue;
1184 
1185 	    cnt_items[i] += 2;
1186 	    if (cnt_items[i] >= (plrs[i].sitems * 100) / wbs->maxitems)
1187 		cnt_items[i] = (plrs[i].sitems * 100) / wbs->maxitems;
1188 	    else
1189 		stillticking = true;
1190 	}
1191 	if (!stillticking)
1192 	{
1193 	    S_StartSound(0, sfx_barexp);
1194 	    ng_state++;
1195 	}
1196     }
1197     else if (ng_state == 6)
1198     {
1199 	if (!(bcnt&3))
1200 	    S_StartSound(0, sfx_pistol);
1201 
1202 	stillticking = false;
1203 
1204 	for (i=0 ; i<MAXPLAYERS ; i++)
1205 	{
1206 	    if (!playeringame[i])
1207 		continue;
1208 
1209 	    cnt_secret[i] += 2;
1210 
1211 	    if (cnt_secret[i] >= (plrs[i].ssecret * 100) / wbs->maxsecret)
1212 		cnt_secret[i] = (plrs[i].ssecret * 100) / wbs->maxsecret;
1213 	    else
1214 		stillticking = true;
1215 	}
1216 
1217 	if (!stillticking)
1218 	{
1219 	    S_StartSound(0, sfx_barexp);
1220 	    ng_state += 1 + 2*!dofrags;
1221 	}
1222     }
1223     else if (ng_state == 8)
1224     {
1225 	if (!(bcnt&3))
1226 	    S_StartSound(0, sfx_pistol);
1227 
1228 	stillticking = false;
1229 
1230 	for (i=0 ; i<MAXPLAYERS ; i++)
1231 	{
1232 	    if (!playeringame[i])
1233 		continue;
1234 
1235 	    cnt_frags[i] += 1;
1236 
1237 	    if (cnt_frags[i] >= (fsum = WI_fragSum(i)))
1238 		cnt_frags[i] = fsum;
1239 	    else
1240 		stillticking = true;
1241 	}
1242 
1243 	if (!stillticking)
1244 	{
1245 	    S_StartSound(0, sfx_pldeth);
1246 	    ng_state++;
1247 	}
1248     }
1249     else if (ng_state == 10)
1250     {
1251 	if (acceleratestage)
1252 	{
1253 	    S_StartSound(0, sfx_sgcock);
1254 	    if ( gamemode == commercial )
1255 		WI_initNoState();
1256 	    else
1257 		WI_initShowNextLoc();
1258 	}
1259     }
1260     else if (ng_state & 1)
1261     {
1262 	if (!--cnt_pause)
1263 	{
1264 	    ng_state++;
1265 	    cnt_pause = TICRATE;
1266 	}
1267     }
1268 }
1269 
1270 
1271 
WI_drawNetgameStats(void)1272 void WI_drawNetgameStats(void)
1273 {
1274     int		i;
1275     int		x;
1276     int		y;
1277     int		pwidth = SHORT(percent->width);
1278 
1279     WI_slamBackground();
1280 
1281     // draw animated background
1282     WI_drawAnimatedBack();
1283 
1284     WI_drawLF();
1285 
1286     // draw stat titles (top line)
1287     V_DrawPatch(NG_STATSX+NG_SPACINGX-SHORT(kills->width),
1288 		NG_STATSY, kills);
1289 
1290     V_DrawPatch(NG_STATSX+2*NG_SPACINGX-SHORT(items->width),
1291 		NG_STATSY, items);
1292 
1293     V_DrawPatch(NG_STATSX+3*NG_SPACINGX-SHORT(secret->width),
1294 		NG_STATSY, secret);
1295 
1296     if (dofrags)
1297 	V_DrawPatch(NG_STATSX+4*NG_SPACINGX-SHORT(frags->width),
1298 		    NG_STATSY, frags);
1299 
1300     // draw stats
1301     y = NG_STATSY + SHORT(kills->height);
1302 
1303     for (i=0 ; i<MAXPLAYERS ; i++)
1304     {
1305 	if (!playeringame[i])
1306 	    continue;
1307 
1308 	x = NG_STATSX;
1309 	V_DrawPatch(x-SHORT(p[i]->width), y, p[i]);
1310 
1311 	if (i == me)
1312 	    V_DrawPatch(x-SHORT(p[i]->width), y, star);
1313 
1314 	x += NG_SPACINGX;
1315 	WI_drawPercent(x-pwidth, y+10, cnt_kills[i]);	x += NG_SPACINGX;
1316 	WI_drawPercent(x-pwidth, y+10, cnt_items[i]);	x += NG_SPACINGX;
1317 	WI_drawPercent(x-pwidth, y+10, cnt_secret[i]);	x += NG_SPACINGX;
1318 
1319 	if (dofrags)
1320 	    WI_drawNum(x, y+10, cnt_frags[i], -1);
1321 
1322 	y += WI_SPACINGY;
1323     }
1324 
1325 }
1326 
1327 static int	sp_state;
1328 
WI_initStats(void)1329 void WI_initStats(void)
1330 {
1331     state = StatCount;
1332     acceleratestage = 0;
1333     sp_state = 1;
1334     cnt_kills[0] = cnt_items[0] = cnt_secret[0] = -1;
1335     cnt_time = cnt_par = -1;
1336     cnt_pause = TICRATE;
1337 
1338     WI_initAnimatedBack();
1339 }
1340 
WI_updateStats(void)1341 void WI_updateStats(void)
1342 {
1343 
1344     WI_updateAnimatedBack();
1345 
1346     if (acceleratestage && sp_state != 10)
1347     {
1348 	acceleratestage = 0;
1349 	cnt_kills[0] = (plrs[me].skills * 100) / wbs->maxkills;
1350 	cnt_items[0] = (plrs[me].sitems * 100) / wbs->maxitems;
1351 	cnt_secret[0] = (plrs[me].ssecret * 100) / wbs->maxsecret;
1352 	cnt_time = plrs[me].stime / TICRATE;
1353 	cnt_par = wbs->partime / TICRATE;
1354 	S_StartSound(0, sfx_barexp);
1355 	sp_state = 10;
1356     }
1357 
1358     if (sp_state == 2)
1359     {
1360 	cnt_kills[0] += 2;
1361 
1362 	if (!(bcnt&3))
1363 	    S_StartSound(0, sfx_pistol);
1364 
1365 	if (cnt_kills[0] >= (plrs[me].skills * 100) / wbs->maxkills)
1366 	{
1367 	    cnt_kills[0] = (plrs[me].skills * 100) / wbs->maxkills;
1368 	    S_StartSound(0, sfx_barexp);
1369 	    sp_state++;
1370 	}
1371     }
1372     else if (sp_state == 4)
1373     {
1374 	cnt_items[0] += 2;
1375 
1376 	if (!(bcnt&3))
1377 	    S_StartSound(0, sfx_pistol);
1378 
1379 	if (cnt_items[0] >= (plrs[me].sitems * 100) / wbs->maxitems)
1380 	{
1381 	    cnt_items[0] = (plrs[me].sitems * 100) / wbs->maxitems;
1382 	    S_StartSound(0, sfx_barexp);
1383 	    sp_state++;
1384 	}
1385     }
1386     else if (sp_state == 6)
1387     {
1388 	cnt_secret[0] += 2;
1389 
1390 	if (!(bcnt&3))
1391 	    S_StartSound(0, sfx_pistol);
1392 
1393 	if (cnt_secret[0] >= (plrs[me].ssecret * 100) / wbs->maxsecret)
1394 	{
1395 	    cnt_secret[0] = (plrs[me].ssecret * 100) / wbs->maxsecret;
1396 	    S_StartSound(0, sfx_barexp);
1397 	    sp_state++;
1398 	}
1399     }
1400 
1401     else if (sp_state == 8)
1402     {
1403 	if (!(bcnt&3))
1404 	    S_StartSound(0, sfx_pistol);
1405 
1406 	cnt_time += 3;
1407 
1408 	if (cnt_time >= plrs[me].stime / TICRATE)
1409 	    cnt_time = plrs[me].stime / TICRATE;
1410 
1411 	cnt_par += 3;
1412 
1413 	if (cnt_par >= wbs->partime / TICRATE)
1414 	{
1415 	    cnt_par = wbs->partime / TICRATE;
1416 
1417 	    if (cnt_time >= plrs[me].stime / TICRATE)
1418 	    {
1419 		S_StartSound(0, sfx_barexp);
1420 		sp_state++;
1421 	    }
1422 	}
1423     }
1424     else if (sp_state == 10)
1425     {
1426 	if (acceleratestage)
1427 	{
1428 	    S_StartSound(0, sfx_sgcock);
1429 
1430 	    if (gamemode == commercial)
1431 		WI_initNoState();
1432 	    else
1433 		WI_initShowNextLoc();
1434 	}
1435     }
1436     else if (sp_state & 1)
1437     {
1438 	if (!--cnt_pause)
1439 	{
1440 	    sp_state++;
1441 	    cnt_pause = TICRATE;
1442 	}
1443     }
1444 
1445 }
1446 
WI_drawStats(void)1447 void WI_drawStats(void)
1448 {
1449     // line height
1450     int lh;
1451 
1452     lh = (3*SHORT(num[0]->height))/2;
1453 
1454     WI_slamBackground();
1455 
1456     // draw animated background
1457     WI_drawAnimatedBack();
1458 
1459     WI_drawLF();
1460 
1461     V_DrawPatch(SP_STATSX, SP_STATSY, kills);
1462     WI_drawPercent(SCREENWIDTH - SP_STATSX, SP_STATSY, cnt_kills[0]);
1463 
1464     V_DrawPatch(SP_STATSX, SP_STATSY+lh, items);
1465     WI_drawPercent(SCREENWIDTH - SP_STATSX, SP_STATSY+lh, cnt_items[0]);
1466 
1467     V_DrawPatch(SP_STATSX, SP_STATSY+2*lh, sp_secret);
1468     WI_drawPercent(SCREENWIDTH - SP_STATSX, SP_STATSY+2*lh, cnt_secret[0]);
1469 
1470     V_DrawPatch(SP_TIMEX, SP_TIMEY, timepatch);
1471     WI_drawTime(SCREENWIDTH/2 - SP_TIMEX, SP_TIMEY, cnt_time);
1472 
1473     if (wbs->epsd < 3)
1474     {
1475 	V_DrawPatch(SCREENWIDTH/2 + SP_TIMEX, SP_TIMEY, par);
1476 	WI_drawTime(SCREENWIDTH - SP_TIMEX, SP_TIMEY, cnt_par);
1477     }
1478 
1479 }
1480 
WI_checkForAccelerate(void)1481 void WI_checkForAccelerate(void)
1482 {
1483     int   i;
1484     player_t  *player;
1485 
1486     // check for button presses to skip delays
1487     for (i=0, player = players ; i<MAXPLAYERS ; i++, player++)
1488     {
1489 	if (playeringame[i])
1490 	{
1491 	    if (player->cmd.buttons & BT_ATTACK)
1492 	    {
1493 		if (!player->attackdown)
1494 		    acceleratestage = 1;
1495 		player->attackdown = true;
1496 	    }
1497 	    else
1498 		player->attackdown = false;
1499 	    if (player->cmd.buttons & BT_USE)
1500 	    {
1501 		if (!player->usedown)
1502 		    acceleratestage = 1;
1503 		player->usedown = true;
1504 	    }
1505 	    else
1506 		player->usedown = false;
1507 	}
1508     }
1509 }
1510 
1511 
1512 
1513 // Updates stuff each tick
WI_Ticker(void)1514 void WI_Ticker(void)
1515 {
1516     // counter for general background animation
1517     bcnt++;
1518 
1519     if (bcnt == 1)
1520     {
1521 	// intermission music
1522   	if ( gamemode == commercial )
1523 	  S_ChangeMusic(mus_dm2int, true);
1524 	else
1525 	  S_ChangeMusic(mus_inter, true);
1526     }
1527 
1528     WI_checkForAccelerate();
1529 
1530     switch (state)
1531     {
1532       case StatCount:
1533 	if (deathmatch) WI_updateDeathmatchStats();
1534 	else if (netgame) WI_updateNetgameStats();
1535 	else WI_updateStats();
1536 	break;
1537 
1538       case ShowNextLoc:
1539 	WI_updateShowNextLoc();
1540 	break;
1541 
1542       case NoState:
1543 	WI_updateNoState();
1544 	break;
1545     }
1546 
1547 }
1548 
1549 typedef void (*load_callback_t)(char *lumpname, patch_t **variable);
1550 
1551 // Common load/unload function.  Iterates over all the graphics
1552 // lumps to be loaded/unloaded into memory.
1553 
WI_loadUnloadData(load_callback_t callback)1554 static void WI_loadUnloadData(load_callback_t callback)
1555 {
1556     int i, j;
1557     char name[9];
1558     anim_t *a;
1559 
1560     if (gamemode == commercial)
1561     {
1562 	for (i=0 ; i<NUMCMAPS ; i++)
1563 	{
1564 	    DEH_snprintf(name, 9, "CWILV%2.2d", i);
1565             callback(name, &lnames[i]);
1566 	}
1567     }
1568     else
1569     {
1570 	for (i=0 ; i<NUMMAPS ; i++)
1571 	{
1572 	    DEH_snprintf(name, 9, "WILV%d%d", wbs->epsd, i);
1573             callback(name, &lnames[i]);
1574 	}
1575 
1576 	// you are here
1577         callback(DEH_String("WIURH0"), &yah[0]);
1578 
1579 	// you are here (alt.)
1580         callback(DEH_String("WIURH1"), &yah[1]);
1581 
1582 	// splat
1583         callback(DEH_String("WISPLAT"), &splat[0]);
1584 
1585 	if (wbs->epsd < 3)
1586 	{
1587 	    for (j=0;j<NUMANIMS[wbs->epsd];j++)
1588 	    {
1589 		a = &anims[wbs->epsd][j];
1590 		for (i=0;i<a->nanims;i++)
1591 		{
1592 		    // MONDO HACK!
1593 		    if (wbs->epsd != 1 || j != 8)
1594 		    {
1595 			// animations
1596 			DEH_snprintf(name, 9, "WIA%d%.2d%.2d", wbs->epsd, j, i);
1597                         callback(name, &a->p[i]);
1598 		    }
1599 		    else
1600 		    {
1601 			// HACK ALERT!
1602 			a->p[i] = anims[1][4].p[i];
1603 		    }
1604 		}
1605 	    }
1606 	}
1607     }
1608 
1609     // More hacks on minus sign.
1610     callback(DEH_String("WIMINUS"), &wiminus);
1611 
1612     for (i=0;i<10;i++)
1613     {
1614 	 // numbers 0-9
1615 	DEH_snprintf(name, 9, "WINUM%d", i);
1616         callback(name, &num[i]);
1617     }
1618 
1619     // percent sign
1620     callback(DEH_String("WIPCNT"), &percent);
1621 
1622     // "finished"
1623     callback(DEH_String("WIF"), &finished);
1624 
1625     // "entering"
1626     callback(DEH_String("WIENTER"), &entering);
1627 
1628     // "kills"
1629     callback(DEH_String("WIOSTK"), &kills);
1630 
1631     // "scrt"
1632     callback(DEH_String("WIOSTS"), &secret);
1633 
1634      // "secret"
1635     callback(DEH_String("WISCRT2"), &sp_secret);
1636 
1637     // french wad uses WIOBJ (?)
1638     if (W_CheckNumForName(DEH_String("WIOBJ")) >= 0)
1639     {
1640     	// "items"
1641     	if (netgame && !deathmatch)
1642             callback(DEH_String("WIOBJ"), &items);
1643     	else
1644             callback(DEH_String("WIOSTI"), &items);
1645     } else {
1646         callback(DEH_String("WIOSTI"), &items);
1647     }
1648 
1649     // "frgs"
1650     callback(DEH_String("WIFRGS"), &frags);
1651 
1652     // ":"
1653     callback(DEH_String("WICOLON"), &colon);
1654 
1655     // "time"
1656     callback(DEH_String("WITIME"), &timepatch);
1657 
1658     // "sucks"
1659     callback(DEH_String("WISUCKS"), &sucks);
1660 
1661     // "par"
1662     callback(DEH_String("WIPAR"), &par);
1663 
1664     // "killers" (vertical)
1665     callback(DEH_String("WIKILRS"), &killers);
1666 
1667     // "victims" (horiz)
1668     callback(DEH_String("WIVCTMS"), &victims);
1669 
1670     // "total"
1671     callback(DEH_String("WIMSTT"), &total);
1672 
1673     for (i=0 ; i<MAXPLAYERS ; i++)
1674     {
1675 	// "1,2,3,4"
1676 	DEH_snprintf(name, 9, "STPB%d", i);
1677         callback(name, &p[i]);
1678 
1679 	// "1,2,3,4"
1680 	DEH_snprintf(name, 9, "WIBP%d", i+1);
1681         callback(name, &bp[i]);
1682     }
1683 
1684     // Background image
1685 
1686     if (gamemode == commercial)
1687     {
1688         M_StringCopy(name, DEH_String("INTERPIC"), sizeof(name));
1689     }
1690     else if (gameversion >= exe_ultimate && wbs->epsd == 3)
1691     {
1692         M_StringCopy(name, DEH_String("INTERPIC"), sizeof(name));
1693     }
1694     else
1695     {
1696 	DEH_snprintf(name, sizeof(name), "WIMAP%d", wbs->epsd);
1697     }
1698 
1699     // Draw backdrop and save to a temporary buffer
1700 
1701     callback(name, &background);
1702 }
1703 
WI_loadCallback(char * name,patch_t ** variable)1704 static void WI_loadCallback(char *name, patch_t **variable)
1705 {
1706     *variable = W_CacheLumpName(name, PU_STATIC);
1707 }
1708 
WI_loadData(void)1709 void WI_loadData(void)
1710 {
1711     if (gamemode == commercial)
1712     {
1713 	NUMCMAPS = 32;
1714 	lnames = (patch_t **) Z_Malloc(sizeof(patch_t*) * NUMCMAPS,
1715 				       PU_STATIC, NULL);
1716     }
1717     else
1718     {
1719 	lnames = (patch_t **) Z_Malloc(sizeof(patch_t*) * NUMMAPS,
1720 				       PU_STATIC, NULL);
1721     }
1722 
1723     WI_loadUnloadData(WI_loadCallback);
1724 
1725     // These two graphics are special cased because we're sharing
1726     // them with the status bar code
1727 
1728     // your face
1729     star = W_CacheLumpName(DEH_String("STFST01"), PU_STATIC);
1730 
1731     // dead face
1732     bstar = W_CacheLumpName(DEH_String("STFDEAD0"), PU_STATIC);
1733 }
1734 
WI_unloadCallback(char * name,patch_t ** variable)1735 static void WI_unloadCallback(char *name, patch_t **variable)
1736 {
1737     W_ReleaseLumpName(name);
1738     *variable = NULL;
1739 }
1740 
WI_unloadData(void)1741 void WI_unloadData(void)
1742 {
1743     WI_loadUnloadData(WI_unloadCallback);
1744 
1745     // We do not free these lumps as they are shared with the status
1746     // bar code.
1747 
1748     // W_ReleaseLumpName("STFST01");
1749     // W_ReleaseLumpName("STFDEAD0");
1750 }
1751 
WI_Drawer(void)1752 void WI_Drawer (void)
1753 {
1754     switch (state)
1755     {
1756       case StatCount:
1757 	if (deathmatch)
1758 	    WI_drawDeathmatchStats();
1759 	else if (netgame)
1760 	    WI_drawNetgameStats();
1761 	else
1762 	    WI_drawStats();
1763 	break;
1764 
1765       case ShowNextLoc:
1766 	WI_drawShowNextLoc();
1767 	break;
1768 
1769       case NoState:
1770 	WI_drawNoState();
1771 	break;
1772     }
1773 }
1774 
1775 
WI_initVariables(wbstartstruct_t * wbstartstruct)1776 void WI_initVariables(wbstartstruct_t* wbstartstruct)
1777 {
1778 
1779     wbs = wbstartstruct;
1780 
1781 #ifdef RANGECHECKING
1782     if (gamemode != commercial)
1783     {
1784       if (gameversion >= exe_ultimate)
1785 	RNGCHECK(wbs->epsd, 0, 3);
1786       else
1787 	RNGCHECK(wbs->epsd, 0, 2);
1788     }
1789     else
1790     {
1791 	RNGCHECK(wbs->last, 0, 8);
1792 	RNGCHECK(wbs->next, 0, 8);
1793     }
1794     RNGCHECK(wbs->pnum, 0, MAXPLAYERS);
1795     RNGCHECK(wbs->pnum, 0, MAXPLAYERS);
1796 #endif
1797 
1798     acceleratestage = 0;
1799     cnt = bcnt = 0;
1800     firstrefresh = 1;
1801     me = wbs->pnum;
1802     plrs = wbs->plyr;
1803 
1804     if (!wbs->maxkills)
1805 	wbs->maxkills = 1;
1806 
1807     if (!wbs->maxitems)
1808 	wbs->maxitems = 1;
1809 
1810     if (!wbs->maxsecret)
1811 	wbs->maxsecret = 1;
1812 
1813     if ( gameversion < exe_ultimate )
1814       if (wbs->epsd > 2)
1815 	wbs->epsd -= 3;
1816 }
1817 
WI_Start(wbstartstruct_t * wbstartstruct)1818 void WI_Start(wbstartstruct_t* wbstartstruct)
1819 {
1820     WI_initVariables(wbstartstruct);
1821     WI_loadData();
1822 
1823     if (deathmatch)
1824 	WI_initDeathmatchStats();
1825     else if (netgame)
1826 	WI_initNetgameStats();
1827     else
1828 	WI_initStats();
1829 }
1830