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