1 // Emacs style mode select -*- C++ -*-
2 //-----------------------------------------------------------------------------
3 //
4 // $Id:$
5 //
6 // Copyright (C) 1993-1996 by id Software, Inc.
7 //
8 // This source is available for distribution and/or modification
9 // only under the terms of the DOOM Source Code License as
10 // published by id Software. All rights reserved.
11 //
12 // The source is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
15 // for more details.
16 //
17 // $Log:$
18 //
19 // DESCRIPTION:
20 // Intermission screens.
21 //
22 //-----------------------------------------------------------------------------
23
24 // Enhancements by Graf Zahl
25
26 #include <ctype.h>
27 #include <stdio.h>
28
29 #include "m_random.h"
30 #include "m_swap.h"
31 #include "i_system.h"
32 #include "w_wad.h"
33 #include "g_game.h"
34 #include "g_level.h"
35 #include "s_sound.h"
36 #include "doomstat.h"
37 #include "v_video.h"
38 #include "i_video.h"
39 #include "wi_stuff.h"
40 #include "c_console.h"
41 #include "hu_stuff.h"
42 #include "v_palette.h"
43 #include "s_sndseq.h"
44 #include "sc_man.h"
45 #include "v_text.h"
46 #include "gi.h"
47 #include "d_player.h"
48 #include "d_netinf.h"
49 #include "b_bot.h"
50 #include "textures/textures.h"
51 #include "r_data/r_translate.h"
52 #include "templates.h"
53 #include "gstrings.h"
54
55 // States for the intermission
56 typedef enum
57 {
58 NoState = -1,
59 StatCount,
60 ShowNextLoc,
61 LeavingIntermission
62 } stateenum_t;
63
64 CVAR (Bool, wi_percents, true, CVAR_ARCHIVE)
65 CVAR (Bool, wi_showtotaltime, true, CVAR_ARCHIVE)
66 CVAR (Bool, wi_noautostartmap, false, CVAR_USERINFO|CVAR_ARCHIVE)
67 CVAR (Int, wi_autoadvance, 0, CVAR_SERVERINFO)
68
69
70 void WI_loadData ();
71 void WI_unloadData ();
72
73 // GLOBAL LOCATIONS
74 #define WI_TITLEY 2
75 #define WI_SPACINGY 33
76
77 // SINGPLE-PLAYER STUFF
78 #define SP_STATSX 50
79 #define SP_STATSY 50
80
81 #define SP_TIMEX 8
82 #define SP_TIMEY (200-32)
83
84
85 // NET GAME STUFF
86 #define NG_STATSY 50
87 #define NG_STATSX (32 + star->GetScaledWidth()/2 + 32*!dofrags)
88
89 #define NG_SPACINGX 64
90
91
92 // DEATHMATCH STUFF
93 #define DM_MATRIXX 42
94 #define DM_MATRIXY 68
95
96 #define DM_SPACINGX 40
97
98 #define DM_TOTALSX 269
99
100 #define DM_KILLERSX 10
101 #define DM_KILLERSY 100
102 #define DM_VICTIMSX 5
103 #define DM_VICTIMSY 50
104
105 // These animation variables, structures, etc. are used for the
106 // DOOM/Ultimate DOOM intermission screen animations. This is
107 // totally different from any sprite or texture/flat animations
108 typedef enum
109 {
110 ANIM_ALWAYS, // determined by patch entry
111 ANIM_PIC, // continuous
112
113 // condition bitflags
114 ANIM_IFVISITED=8,
115 ANIM_IFNOTVISITED=16,
116 ANIM_IFENTERING=32,
117 ANIM_IFNOTENTERING=64,
118 ANIM_IFLEAVING=128,
119 ANIM_IFNOTLEAVING=256,
120 ANIM_IFTRAVELLING=512,
121 ANIM_IFNOTTRAVELLING=1024,
122
123 ANIM_TYPE=7,
124 ANIM_CONDITION=~7,
125
126 } animenum_t;
127
128 struct yahpt_t
129 {
130 int x, y;
131 };
132
133 struct lnode_t
134 {
135 int x; // x/y coordinate pair structure
136 int y;
137 char level[9];
138 } ;
139
140
141 #define FACEBACKOFS 4
142
143
144 //
145 // Animation.
146 // There is another anim_t used in p_spec.
147 // (which is why I have renamed this one!)
148 //
149
150 #define MAX_ANIMATION_FRAMES 20
151 struct in_anim_t
152 {
153 int type; // Made an int so I can use '|'
154 int period; // period in tics between animations
155 int nanims; // number of animation frames
156 yahpt_t loc; // location of animation
157 int data; // ALWAYS: n/a, RANDOM: period deviation (<256)
158 FTexture * p[MAX_ANIMATION_FRAMES]; // actual graphics for frames of animations
159
160 // following must be initialized to zero before use!
161 int nexttic; // next value of bcnt (used in conjunction with period)
162 int ctr; // next frame number to animate
163 int state; // used by RANDOM and LEVEL when animating
164
165 char levelname[9];
166 char levelname2[9];
167 };
168
169 static TArray<lnode_t> lnodes;
170 static TArray<in_anim_t> anims;
171
172
173 //
174 // GENERAL DATA
175 //
176
177 //
178 // Locally used stuff.
179 //
180
181
182 // States for single-player
183 #define SP_KILLS 0
184 #define SP_ITEMS 2
185 #define SP_SECRET 4
186 #define SP_FRAGS 6
187 #define SP_TIME 8
188 #define SP_PAR ST_TIME
189
190 #define SP_PAUSE 1
191
192 #define SHOWNEXTLOCDELAY 4 // in seconds
193
194 static int acceleratestage; // used to accelerate or skip a stage
195 static bool playerready[MAXPLAYERS];
196 static int me; // wbs->pnum
197 static stateenum_t state; // specifies current state
198 static wbstartstruct_t *wbs; // contains information passed into intermission
199 static wbplayerstruct_t*plrs; // wbs->plyr[]
200 static int cnt; // used for general timing
201 static int bcnt; // used for timing of background animation
202 static int cnt_kills[MAXPLAYERS];
203 static int cnt_items[MAXPLAYERS];
204 static int cnt_secret[MAXPLAYERS];
205 static int cnt_frags[MAXPLAYERS];
206 static int cnt_deaths[MAXPLAYERS];
207 static int cnt_time;
208 static int cnt_total_time;
209 static int cnt_par;
210 static int cnt_pause;
211 static int total_frags;
212 static int total_deaths;
213 static bool noautostartmap;
214 static int dofrags;
215 static int ng_state;
216
217 //
218 // GRAPHICS
219 //
220
221 struct FPatchInfo
222 {
223 FFont *mFont;
224 FTexture *mPatch;
225 EColorRange mColor;
226
InitFPatchInfo227 void Init(FGIFont &gifont)
228 {
229 if (gifont.color == NAME_Null)
230 {
231 mPatch = TexMan[gifont.fontname]; // "entering"
232 mColor = mPatch == NULL? CR_UNTRANSLATED : CR_UNDEFINED;
233 mFont = NULL;
234 }
235 else
236 {
237 mFont = V_GetFont(gifont.fontname);
238 mColor = V_FindFontColor(gifont.color);
239 mPatch = NULL;
240 }
241 if (mFont == NULL)
242 {
243 mFont = BigFont;
244 }
245 }
246 };
247
248 static FPatchInfo mapname;
249 static FPatchInfo finished;
250 static FPatchInfo entering;
251
252 static TArray<FTexture *> yah; // You Are Here graphic
253 static FTexture* splat; // splat
254 static FTexture* sp_secret; // "secret"
255 static FTexture* kills; // "Kills", "Scrt", "Items", "Frags"
256 static FTexture* secret;
257 static FTexture* items;
258 static FTexture* frags;
259 static FTexture* timepic; // Time sucks.
260 static FTexture* par;
261 static FTexture* sucks;
262 static FTexture* killers; // "killers", "victims"
263 static FTexture* victims;
264 static FTexture* total; // "Total", your face, your dead face
265 //static FTexture* star;
266 //static FTexture* bstar;
267 static FTexture* p; // Player graphic
268 static FTexture* lnames[2]; // Name graphics of each level (centered)
269
270 // [RH] Info to dynamically generate the level name graphics
271 static FString lnametexts[2];
272
273 static FTexture *background;
274
275 //
276 // CODE
277 //
278
279 // ====================================================================
280 //
281 // Background script commands
282 //
283 // ====================================================================
284
285 static const char *WI_Cmd[]={
286 "Background",
287 "Splat",
288 "Pointer",
289 "Spots",
290
291 "IfEntering",
292 "IfNotEntering",
293 "IfVisited",
294 "IfNotVisited",
295 "IfLeaving",
296 "IfNotLeaving",
297 "IfTravelling",
298 "IfNotTravelling",
299
300 "Animation",
301 "Pic",
302
303 "NoAutostartMap",
304
305 NULL
306 };
307
308 //====================================================================
309 //
310 // Loads the background - either from a single texture
311 // or an intermission lump.
312 // Unfortunately the texture manager is incapable of recognizing text
313 // files so if you use a script you have to prefix its name by '$' in
314 // MAPINFO.
315 //
316 //====================================================================
IsExMy(const char * name)317 static bool IsExMy(const char * name)
318 {
319 // Only check for the first 3 episodes. They are the only ones with default intermission scripts.
320 // Level names can be upper- and lower case so use tolower to check!
321 return (tolower(name[0])=='e' && name[1]>='1' && name[1]<='3' && tolower(name[2])=='m');
322 }
323
WI_LoadBackground(bool isenterpic)324 void WI_LoadBackground(bool isenterpic)
325 {
326 const char *lumpname = NULL;
327 char buffer[10];
328 in_anim_t an;
329 lnode_t pt;
330 FTextureID texture;
331
332 bcnt=0;
333
334 texture.SetInvalid();
335 if (isenterpic)
336 {
337 level_info_t * li = FindLevelInfo(wbs->next);
338 if (li != NULL) lumpname = li->EnterPic;
339 }
340 else
341 {
342 lumpname = level.info->ExitPic;
343 }
344
345 // Try to get a default if nothing specified
346 if (lumpname == NULL || lumpname[0]==0)
347 {
348 lumpname = NULL;
349 switch(gameinfo.gametype)
350 {
351 case GAME_Chex:
352 case GAME_Doom:
353 if (!(gameinfo.flags & GI_MAPxx))
354 {
355 const char *level = isenterpic ? wbs->next : wbs->current;
356 if (IsExMy(level))
357 {
358 mysnprintf(buffer, countof(buffer), "$IN_EPI%c", level[1]);
359 lumpname = buffer;
360 }
361 }
362 if (!lumpname)
363 {
364 if (isenterpic)
365 {
366 // One special case needs to be handled here!
367 // If going from E1-E3 to E4 the default should be used, not the exit pic.
368
369 // Not if the exit pic is user defined!
370 if (level.info->ExitPic.IsNotEmpty()) return;
371
372 // E1-E3 need special treatment when playing Doom 1.
373 if (!(gameinfo.flags & GI_MAPxx))
374 {
375 // not if the last level is not from the first 3 episodes
376 if (!IsExMy(wbs->current)) return;
377
378 // not if the next level is one of the first 3 episodes
379 if (IsExMy(wbs->next)) return;
380 }
381 }
382 lumpname = "INTERPIC";
383 }
384 break;
385
386 case GAME_Heretic:
387 if (isenterpic)
388 {
389 if (IsExMy(wbs->next))
390 {
391 mysnprintf(buffer, countof(buffer), "$IN_HTC%c", wbs->next[1]);
392 lumpname = buffer;
393 }
394 }
395 if (!lumpname)
396 {
397 if (isenterpic) return;
398 lumpname = "FLOOR16";
399 }
400 break;
401
402 case GAME_Hexen:
403 if (isenterpic) return;
404 lumpname = "INTERPIC";
405 break;
406
407 case GAME_Strife:
408 default:
409 // Strife doesn't have an intermission pic so choose something neutral.
410 if (isenterpic) return;
411 lumpname = gameinfo.BorderFlat;
412 break;
413 }
414 }
415 if (lumpname == NULL)
416 {
417 // shouldn't happen!
418 background = NULL;
419 return;
420 }
421
422 lnodes.Clear();
423 anims.Clear();
424 yah.Clear();
425 splat = NULL;
426
427 // a name with a starting '$' indicates an intermission script
428 if (*lumpname!='$')
429 {
430 texture = TexMan.CheckForTexture(lumpname, FTexture::TEX_MiscPatch, FTextureManager::TEXMAN_TryAny);
431 }
432 else
433 {
434 int lumpnum=Wads.CheckNumForFullName(lumpname+1, true);
435 if (lumpnum>=0)
436 {
437 FScanner sc(lumpnum);
438 while (sc.GetString())
439 {
440 memset(&an,0,sizeof(an));
441 int caseval = sc.MustMatchString(WI_Cmd);
442 switch(caseval)
443 {
444 case 0: // Background
445 sc.MustGetString();
446 texture = TexMan.CheckForTexture(sc.String, FTexture::TEX_MiscPatch, FTextureManager::TEXMAN_TryAny);
447 break;
448
449 case 1: // Splat
450 sc.MustGetString();
451 splat = TexMan[sc.String];
452 break;
453
454 case 2: // Pointers
455 while (sc.GetString() && !sc.Crossed)
456 {
457 yah.Push(TexMan[sc.String]);
458 }
459 if (sc.Crossed)
460 sc.UnGet();
461 break;
462
463 case 3: // Spots
464 sc.MustGetStringName("{");
465 while (!sc.CheckString("}"))
466 {
467 sc.MustGetString();
468 strncpy(pt.level, sc.String,8);
469 pt.level[8] = 0;
470 sc.MustGetNumber();
471 pt.x = sc.Number;
472 sc.MustGetNumber();
473 pt.y = sc.Number;
474 lnodes.Push(pt);
475 }
476 break;
477
478 case 4: // IfEntering
479 an.type = ANIM_IFENTERING;
480 goto readanimation;
481
482 case 5: // IfEntering
483 an.type = ANIM_IFNOTENTERING;
484 goto readanimation;
485
486 case 6: // IfVisited
487 an.type = ANIM_IFVISITED;
488 goto readanimation;
489
490 case 7: // IfNotVisited
491 an.type = ANIM_IFNOTVISITED;
492 goto readanimation;
493
494 case 8: // IfLeaving
495 an.type = ANIM_IFLEAVING;
496 goto readanimation;
497
498 case 9: // IfNotLeaving
499 an.type = ANIM_IFNOTLEAVING;
500 goto readanimation;
501
502 case 10: // IfTravelling
503 an.type = ANIM_IFTRAVELLING;
504 sc.MustGetString();
505 strncpy(an.levelname2, sc.String, 8);
506 an.levelname2[8] = 0;
507 goto readanimation;
508
509 case 11: // IfNotTravelling
510 an.type = ANIM_IFTRAVELLING;
511 sc.MustGetString();
512 strncpy(an.levelname2, sc.String, 8);
513 an.levelname2[8] = 0;
514 goto readanimation;
515
516 case 14: // NoAutostartMap
517 noautostartmap = true;
518 break;
519
520 readanimation:
521 sc.MustGetString();
522 strncpy(an.levelname, sc.String, 8);
523 an.levelname[8] = 0;
524 sc.MustGetString();
525 caseval=sc.MustMatchString(WI_Cmd);
526
527 default:
528 switch (caseval)
529 {
530 case 12: // Animation
531 an.type |= ANIM_ALWAYS;
532 sc.MustGetNumber();
533 an.loc.x = sc.Number;
534 sc.MustGetNumber();
535 an.loc.y = sc.Number;
536 sc.MustGetNumber();
537 an.period = sc.Number;
538 an.nexttic = 1 + (M_Random() % an.period);
539 if (sc.GetString())
540 {
541 if (sc.Compare("ONCE"))
542 {
543 an.data = 1;
544 }
545 else
546 {
547 sc.UnGet();
548 }
549 }
550 if (!sc.CheckString("{"))
551 {
552 sc.MustGetString();
553 an.p[an.nanims++] = TexMan[sc.String];
554 }
555 else
556 {
557 while (!sc.CheckString("}"))
558 {
559 sc.MustGetString();
560 if (an.nanims<MAX_ANIMATION_FRAMES)
561 an.p[an.nanims++] = TexMan[sc.String];
562 }
563 }
564 an.ctr = -1;
565 anims.Push(an);
566 break;
567
568 case 13: // Pic
569 an.type |= ANIM_PIC;
570 sc.MustGetNumber();
571 an.loc.x = sc.Number;
572 sc.MustGetNumber();
573 an.loc.y = sc.Number;
574 sc.MustGetString();
575 an.p[0] = TexMan[sc.String];
576 anims.Push(an);
577 break;
578
579 default:
580 sc.ScriptError("Unknown token %s in intermission script", sc.String);
581 }
582 }
583 }
584 }
585 else
586 {
587 Printf("Intermission script %s not found!\n", lumpname+1);
588 texture = TexMan.GetTexture("INTERPIC", FTexture::TEX_MiscPatch);
589 }
590 }
591 background=TexMan[texture];
592 }
593
594 //====================================================================
595 //
596 // made this more generic and configurable through a script
597 // Removed all the ugly special case handling for different game modes
598 //
599 //====================================================================
600
WI_updateAnimatedBack()601 void WI_updateAnimatedBack()
602 {
603 unsigned int i;
604
605 for(i=0;i<anims.Size();i++)
606 {
607 in_anim_t * a = &anims[i];
608 switch (a->type & ANIM_TYPE)
609 {
610 case ANIM_ALWAYS:
611 if (bcnt >= a->nexttic)
612 {
613 if (++a->ctr >= a->nanims)
614 {
615 if (a->data==0) a->ctr = 0;
616 else a->ctr--;
617 }
618 a->nexttic = bcnt + a->period;
619 }
620 break;
621
622 case ANIM_PIC:
623 a->ctr = 0;
624 break;
625
626 }
627 }
628 }
629
630 //====================================================================
631 //
632 // Draws the background including all animations
633 //
634 //====================================================================
635
WI_drawBackground()636 void WI_drawBackground()
637 {
638 unsigned int i;
639 double animwidth=320; // For a flat fill or clear background scale animations to 320x200
640 double animheight=200;
641
642 if (background)
643 {
644 // background
645 if (background->UseType == FTexture::TEX_MiscPatch)
646 {
647 // scale all animations below to fit the size of the base pic
648 // The base pic is always scaled to fit the screen so this allows
649 // placing the animations precisely where they belong on the base pic
650 animwidth = background->GetScaledWidthDouble();
651 animheight = background->GetScaledHeightDouble();
652 screen->FillBorder (NULL);
653 screen->DrawTexture(background, 0, 0, DTA_Fullscreen, true, TAG_DONE);
654 }
655 else
656 {
657 screen->FlatFill(0, 0, SCREENWIDTH, SCREENHEIGHT, background);
658 }
659 }
660 else
661 {
662 screen->Clear(0,0, SCREENWIDTH, SCREENHEIGHT, 0, 0);
663 }
664
665 for(i=0;i<anims.Size();i++)
666 {
667 in_anim_t * a = &anims[i];
668 level_info_t * li;
669
670 switch (a->type & ANIM_CONDITION)
671 {
672 case ANIM_IFVISITED:
673 li = FindLevelInfo(a->levelname);
674 if (li == NULL || !(li->flags & LEVEL_VISITED)) continue;
675 break;
676
677 case ANIM_IFNOTVISITED:
678 li = FindLevelInfo(a->levelname);
679 if (li == NULL || (li->flags & LEVEL_VISITED)) continue;
680 break;
681
682 // StatCount means 'leaving' - everything else means 'entering'!
683 case ANIM_IFENTERING:
684 if (state == StatCount || strnicmp(a->levelname, wbs->next, 8)) continue;
685 break;
686
687 case ANIM_IFNOTENTERING:
688 if (state != StatCount && !strnicmp(a->levelname, wbs->next, 8)) continue;
689 break;
690
691 case ANIM_IFLEAVING:
692 if (state != StatCount || strnicmp(a->levelname, wbs->current, 8)) continue;
693 break;
694
695 case ANIM_IFNOTLEAVING:
696 if (state == StatCount && !strnicmp(a->levelname, wbs->current, 8)) continue;
697 break;
698
699 case ANIM_IFTRAVELLING:
700 if (strnicmp(a->levelname2, wbs->current, 8) || strnicmp(a->levelname, wbs->next, 8)) continue;
701 break;
702
703 case ANIM_IFNOTTRAVELLING:
704 if (!strnicmp(a->levelname2, wbs->current, 8) && !strnicmp(a->levelname, wbs->next, 8)) continue;
705 break;
706 }
707 if (a->ctr >= 0)
708 screen->DrawTexture(a->p[a->ctr], a->loc.x, a->loc.y,
709 DTA_VirtualWidthF, animwidth, DTA_VirtualHeightF, animheight, TAG_DONE);
710 }
711 }
712
713
714 //====================================================================
715 //
716 // Draws a single character with a shadow
717 //
718 //====================================================================
719
WI_DrawCharPatch(FFont * font,int charcode,int x,int y,EColorRange translation=CR_UNTRANSLATED,bool nomove=false)720 static int WI_DrawCharPatch (FFont *font, int charcode, int x, int y, EColorRange translation=CR_UNTRANSLATED, bool nomove=false)
721 {
722 int width;
723 screen->DrawTexture(font->GetChar(charcode, &width), x, y,
724 nomove ? DTA_CleanNoMove : DTA_Clean, true,
725 DTA_ShadowAlpha, (gameinfo.gametype & GAME_DoomChex) ? 0 : FRACUNIT/2,
726 DTA_Translation, font->GetColorTranslation(translation),
727 TAG_DONE);
728 return x - width;
729 }
730
731 //====================================================================
732 //
733 // CheckRealHeight
734 //
735 // Checks the posts in a texture and returns the lowest row (plus one)
736 // of the texture that is actually used.
737 //
738 //====================================================================
739
CheckRealHeight(FTexture * tex)740 int CheckRealHeight(FTexture *tex)
741 {
742 const FTexture::Span *span;
743 int maxy = 0, miny = tex->GetHeight();
744
745 for (int i = 0; i < tex->GetWidth(); ++i)
746 {
747 tex->GetColumn(i, &span);
748 while (span->Length != 0)
749 {
750 if (span->TopOffset < miny)
751 {
752 miny = span->TopOffset;
753 }
754 if (span->TopOffset + span->Length > maxy)
755 {
756 maxy = span->TopOffset + span->Length;
757 }
758 span++;
759 }
760 }
761 // Scale maxy before returning it
762 maxy = (maxy << 17) / tex->yScale;
763 maxy = (maxy >> 1) + (maxy & 1);
764 return maxy;
765 }
766
767 //====================================================================
768 //
769 // Draws a level name with the big font
770 //
771 // x is no longer passed as a parameter because the text is now broken into several lines
772 // if it is too long
773 //
774 //====================================================================
775
WI_DrawName(int y,FTexture * tex,const char * levelname)776 int WI_DrawName(int y, FTexture *tex, const char *levelname)
777 {
778 // draw <LevelName>
779 if (tex)
780 {
781 screen->DrawTexture(tex, (screen->GetWidth() - tex->GetScaledWidth()*CleanXfac) /2, y, DTA_CleanNoMove, true, TAG_DONE);
782 int h = tex->GetScaledHeight();
783 if (h > 50)
784 { // Fix for Deus Vult II and similar wads that decide to make these hugely tall
785 // patches with vast amounts of empty space at the bottom.
786 h = CheckRealHeight(tex);
787 }
788 return y + (h + BigFont->GetHeight()/4) * CleanYfac;
789 }
790 else
791 {
792 int i;
793 size_t l;
794 const char *p;
795 int h = 0;
796 int lumph;
797
798 lumph = mapname.mFont->GetHeight() * CleanYfac;
799
800 p = levelname;
801 if (!p) return 0;
802 l = strlen(p);
803 if (!l) return 0;
804
805 FBrokenLines *lines = V_BreakLines(mapname.mFont, screen->GetWidth() / CleanXfac, p);
806
807 if (lines)
808 {
809 for (i = 0; lines[i].Width >= 0; i++)
810 {
811 screen->DrawText(mapname.mFont, mapname.mColor, (SCREENWIDTH - lines[i].Width * CleanXfac) / 2, y + h,
812 lines[i].Text, DTA_CleanNoMove, true, TAG_DONE);
813 h += lumph;
814 }
815 V_FreeBrokenLines(lines);
816 }
817 return y + h + lumph/4;
818 }
819 }
820
821 //====================================================================
822 //
823 // Draws a text, either as patch or as string from the string table
824 //
825 //====================================================================
826
WI_DrawPatchText(int y,FPatchInfo * pinfo,const char * stringname)827 int WI_DrawPatchText(int y, FPatchInfo *pinfo, const char *stringname)
828 {
829 const char *string = GStrings(stringname);
830 int midx = screen->GetWidth() / 2;
831
832 if (pinfo->mPatch != NULL)
833 {
834 screen->DrawTexture(pinfo->mPatch, midx - pinfo->mPatch->GetScaledWidth()*CleanXfac/2, y, DTA_CleanNoMove, true, TAG_DONE);
835 return y + (pinfo->mPatch->GetScaledHeight() * CleanYfac);
836 }
837 else
838 {
839 screen->DrawText(pinfo->mFont, pinfo->mColor, midx - pinfo->mFont->StringWidth(string)*CleanXfac/2,
840 y, string, DTA_CleanNoMove, true, TAG_DONE);
841 return y + pinfo->mFont->GetHeight() * CleanYfac;
842 }
843 }
844
845
846 //====================================================================
847 //
848 // Draws "<Levelname> Finished!"
849 //
850 // Either uses the specified patch or the big font
851 // A level name patch can be specified for all games now, not just Doom.
852 //
853 //====================================================================
854
WI_drawLF()855 int WI_drawLF ()
856 {
857 int y = WI_TITLEY * CleanYfac;
858
859 y = WI_DrawName(y, wbs->LName0, lnametexts[0]);
860
861 // Adjustment for different font sizes for map name and 'finished'.
862 y -= ((mapname.mFont->GetHeight() - finished.mFont->GetHeight()) * CleanYfac) / 4;
863
864 // draw "Finished!"
865 if (y < (NG_STATSY - finished.mFont->GetHeight()*3/4) * CleanYfac)
866 {
867 // don't draw 'finished' if the level name is too tall
868 y = WI_DrawPatchText(y, &finished, "WI_FINISHED");
869 }
870 return y;
871 }
872
873
874 //====================================================================
875 //
876 // Draws "Entering <LevelName>"
877 //
878 // Either uses the specified patch or the big font
879 // A level name patch can be specified for all games now, not just Doom.
880 //
881 //====================================================================
882
WI_drawEL()883 void WI_drawEL ()
884 {
885 int y = WI_TITLEY * CleanYfac;
886
887 y = WI_DrawPatchText(y, &entering, "WI_ENTERING");
888 y += entering.mFont->GetHeight() * CleanYfac / 4;
889 WI_DrawName(y, wbs->LName1, lnametexts[1]);
890 }
891
892
893 //====================================================================
894 //
895 // Draws the splats and the 'You are here' arrows
896 //
897 //====================================================================
898
WI_MapToIndex(const char * map)899 int WI_MapToIndex (const char *map)
900 {
901 unsigned int i;
902
903 for (i = 0; i < lnodes.Size(); i++)
904 {
905 if (!strnicmp (lnodes[i].level, map, 8))
906 break;
907 }
908 return i;
909 }
910
911
912 //====================================================================
913 //
914 // Draws the splats and the 'You are here' arrows
915 //
916 //====================================================================
917
WI_drawOnLnode(int n,FTexture * c[],int numc)918 void WI_drawOnLnode( int n, FTexture * c[] ,int numc)
919 {
920 int i;
921 for(i=0;i<numc;i++)
922 {
923 int left;
924 int top;
925 int right;
926 int bottom;
927
928
929 right = c[i]->GetScaledWidth();
930 bottom = c[i]->GetScaledHeight();
931 left = lnodes[n].x - c[i]->GetScaledLeftOffset();
932 top = lnodes[n].y - c[i]->GetScaledTopOffset();
933 right += left;
934 bottom += top;
935
936 if (left >= 0 && right < 320 && top >= 0 && bottom < 200)
937 {
938 screen->DrawTexture (c[i], lnodes[n].x, lnodes[n].y, DTA_320x200, true, TAG_DONE);
939 break;
940 }
941 }
942 }
943
944 //====================================================================
945 //
946 // Draws a number.
947 // If digits > 0, then use that many digits minimum,
948 // otherwise only use as many as necessary.
949 // x is the right edge of the number.
950 // Returns new x position, that is, the left edge of the number.
951 //
952 //====================================================================
WI_drawNum(FFont * font,int x,int y,int n,int digits,bool leadingzeros=true,EColorRange translation=CR_UNTRANSLATED)953 int WI_drawNum (FFont *font, int x, int y, int n, int digits, bool leadingzeros=true, EColorRange translation=CR_UNTRANSLATED)
954 {
955 int fontwidth = font->GetCharWidth('3');
956 char text[8];
957 int len;
958 char *text_p;
959 bool nomove = font != IntermissionFont;
960
961 if (nomove)
962 {
963 fontwidth *= CleanXfac;
964 }
965 if (leadingzeros)
966 {
967 len = mysnprintf (text, countof(text), "%0*d", digits, n);
968 }
969 else
970 {
971 len = mysnprintf (text, countof(text), "%d", n);
972 }
973 text_p = text + MIN<int>(len, countof(text)-1);
974
975 while (--text_p >= text)
976 {
977 // Digits are centered in a box the width of the '3' character.
978 // Other characters (specifically, '-') are right-aligned in their cell.
979 if (*text_p >= '0' && *text_p <= '9')
980 {
981 x -= fontwidth;
982 WI_DrawCharPatch(font, *text_p, x + (fontwidth - font->GetCharWidth(*text_p)) / 2, y, translation, nomove);
983 }
984 else
985 {
986 WI_DrawCharPatch(font, *text_p, x - font->GetCharWidth(*text_p), y, translation, nomove);
987 x -= fontwidth;
988 }
989 }
990 if (len < digits)
991 {
992 x -= fontwidth * (digits - len);
993 }
994 return x;
995 }
996
997 //====================================================================
998 //
999 //
1000 //
1001 //====================================================================
1002
WI_drawPercent(FFont * font,int x,int y,int p,int b,bool show_total=true,EColorRange color=CR_UNTRANSLATED)1003 void WI_drawPercent (FFont *font, int x, int y, int p, int b, bool show_total=true, EColorRange color=CR_UNTRANSLATED)
1004 {
1005 if (p < 0)
1006 return;
1007
1008 if (wi_percents)
1009 {
1010 if (font != IntermissionFont)
1011 {
1012 x -= font->GetCharWidth('%') * CleanXfac;
1013 }
1014 else
1015 {
1016 x -= font->GetCharWidth('%');
1017 }
1018 screen->DrawText(font, color, x, y, "%", font != IntermissionFont ? DTA_CleanNoMove : DTA_Clean, true, TAG_DONE);
1019 if (font != IntermissionFont)
1020 {
1021 x -= 2*CleanXfac;
1022 }
1023 WI_drawNum(font, x, y, b == 0 ? 100 : p * 100 / b, -1, false, color);
1024 }
1025 else
1026 {
1027 if (show_total)
1028 {
1029 x = WI_drawNum(font, x, y, b, 2, false);
1030 x -= font->GetCharWidth('/');
1031 screen->DrawText (IntermissionFont, color, x, y, "/",
1032 DTA_Clean, true, TAG_DONE);
1033 }
1034 WI_drawNum (font, x, y, p, -1, false, color);
1035 }
1036 }
1037
1038 //====================================================================
1039 //
1040 // Display level completion time and par, or "sucks" message if overflow.
1041 //
1042 //====================================================================
WI_drawTime(int x,int y,int t,bool no_sucks=false)1043 void WI_drawTime (int x, int y, int t, bool no_sucks=false)
1044 {
1045 bool sucky;
1046
1047 if (t<0)
1048 return;
1049
1050 sucky = !no_sucks && t >= wbs->sucktime * 60 * 60 && wbs->sucktime > 0;
1051
1052 if (sucky)
1053 { // "sucks"
1054 if (sucks != NULL)
1055 {
1056 screen->DrawTexture (sucks, x - sucks->GetScaledWidth(), y - IntermissionFont->GetHeight() - 2,
1057 DTA_Clean, true, TAG_DONE);
1058 }
1059 else
1060 {
1061 screen->DrawText (BigFont, CR_UNTRANSLATED, x - BigFont->StringWidth("SUCKS"), y - IntermissionFont->GetHeight() - 2,
1062 "SUCKS", DTA_Clean, true, TAG_DONE);
1063 }
1064 }
1065
1066 int hours = t / 3600;
1067 t -= hours * 3600;
1068 int minutes = t / 60;
1069 t -= minutes * 60;
1070 int seconds = t;
1071
1072 // Why were these offsets hard coded? Half the WADs with custom patches
1073 // I tested screwed up miserably in this function!
1074 int num_spacing = IntermissionFont->GetCharWidth('3');
1075 int colon_spacing = IntermissionFont->GetCharWidth(':');
1076
1077 x = WI_drawNum (IntermissionFont, x, y, seconds, 2) - 1;
1078 WI_DrawCharPatch (IntermissionFont, ':', x -= colon_spacing, y);
1079 x = WI_drawNum (IntermissionFont, x, y, minutes, 2, hours!=0);
1080 if (hours)
1081 {
1082 WI_DrawCharPatch (IntermissionFont, ':', x -= colon_spacing, y);
1083 WI_drawNum (IntermissionFont, x, y, hours, 2);
1084 }
1085 }
1086
WI_End()1087 void WI_End ()
1088 {
1089 state = LeavingIntermission;
1090 WI_unloadData ();
1091
1092 //Added by mc
1093 if (deathmatch)
1094 {
1095 bglobal.RemoveAllBots (consoleplayer != Net_Arbitrator);
1096 }
1097 }
1098
WI_autoSkip()1099 bool WI_autoSkip()
1100 {
1101 return wi_autoadvance > 0 && bcnt > (wi_autoadvance * TICRATE);
1102 }
1103
WI_initNoState()1104 void WI_initNoState ()
1105 {
1106 state = NoState;
1107 acceleratestage = 0;
1108 cnt = 10;
1109 }
1110
WI_updateNoState()1111 void WI_updateNoState ()
1112 {
1113 WI_updateAnimatedBack();
1114
1115 if (acceleratestage)
1116 {
1117 cnt = 0;
1118 }
1119 else
1120 {
1121 bool noauto = noautostartmap;
1122 bool autoskip = WI_autoSkip();
1123
1124 for (int i = 0; !noauto && i < MAXPLAYERS; ++i)
1125 {
1126 if (playeringame[i])
1127 {
1128 noauto |= players[i].userinfo.GetNoAutostartMap();
1129 }
1130 }
1131 if (!noauto || autoskip)
1132 {
1133 cnt--;
1134 }
1135 }
1136
1137 if (cnt == 0)
1138 {
1139 WI_End();
1140 G_WorldDone();
1141 }
1142 }
1143
1144 static bool snl_pointeron = false;
1145
WI_initShowNextLoc()1146 void WI_initShowNextLoc ()
1147 {
1148 if (wbs->next_ep == -1)
1149 {
1150 // Last map in episode - there is no next location!
1151 WI_End();
1152 G_WorldDone();
1153 return;
1154 }
1155
1156 state = ShowNextLoc;
1157 acceleratestage = 0;
1158 cnt = SHOWNEXTLOCDELAY * TICRATE;
1159 WI_LoadBackground(true);
1160 }
1161
WI_updateShowNextLoc()1162 void WI_updateShowNextLoc ()
1163 {
1164 WI_updateAnimatedBack();
1165
1166 if (!--cnt || acceleratestage)
1167 WI_initNoState();
1168 else
1169 snl_pointeron = (cnt & 31) < 20;
1170 }
1171
WI_drawShowNextLoc(void)1172 void WI_drawShowNextLoc(void)
1173 {
1174 unsigned int i;
1175
1176 WI_drawBackground();
1177
1178 if (splat)
1179 {
1180 for (i=0 ; i<lnodes.Size() ; i++)
1181 {
1182 level_info_t * li = FindLevelInfo (lnodes[i].level);
1183 if (li && li->flags & LEVEL_VISITED) WI_drawOnLnode(i, &splat,1); // draw a splat on taken cities.
1184 }
1185 }
1186
1187 // draw flashing ptr
1188 if (snl_pointeron && yah.Size())
1189 {
1190 unsigned int v = WI_MapToIndex (wbs->next);
1191 // Draw only if it points to a valid level on the current screen!
1192 if (v<lnodes.Size()) WI_drawOnLnode (v, &yah[0], yah.Size());
1193 }
1194
1195 // draws which level you are entering..
1196 WI_drawEL ();
1197
1198 }
1199
WI_drawNoState()1200 void WI_drawNoState ()
1201 {
1202 snl_pointeron = true;
1203 WI_drawShowNextLoc();
1204 }
1205
WI_fragSum(int playernum)1206 int WI_fragSum (int playernum)
1207 {
1208 int i;
1209 int frags = 0;
1210
1211 for (i = 0; i < MAXPLAYERS; i++)
1212 {
1213 if (playeringame[i]
1214 && i!=playernum)
1215 {
1216 frags += plrs[playernum].frags[i];
1217 }
1218 }
1219
1220 // JDC hack - negative frags.
1221 frags -= plrs[playernum].frags[playernum];
1222
1223 return frags;
1224 }
1225
1226 static int player_deaths[MAXPLAYERS];
1227
WI_initDeathmatchStats(void)1228 void WI_initDeathmatchStats (void)
1229 {
1230 int i, j;
1231
1232 state = StatCount;
1233 acceleratestage = 0;
1234 memset(playerready, 0, sizeof(playerready));
1235 memset(cnt_frags, 0, sizeof(cnt_frags));
1236 memset(cnt_deaths, 0, sizeof(cnt_deaths));
1237 memset(player_deaths, 0, sizeof(player_deaths));
1238 total_frags = 0;
1239 total_deaths = 0;
1240
1241 ng_state = 1;
1242 cnt_pause = TICRATE;
1243
1244 for (i=0 ; i<MAXPLAYERS ; i++)
1245 {
1246 if (playeringame[i])
1247 {
1248 for (j = 0; j < MAXPLAYERS; j++)
1249 if (playeringame[j])
1250 player_deaths[i] += plrs[j].frags[i];
1251 total_deaths += player_deaths[i];
1252 total_frags += plrs[i].fragcount;
1253 }
1254 }
1255 }
1256
WI_updateDeathmatchStats()1257 void WI_updateDeathmatchStats ()
1258 {
1259
1260 int i;
1261 bool stillticking;
1262 bool autoskip = WI_autoSkip();
1263
1264 WI_updateAnimatedBack();
1265
1266 if ((acceleratestage || autoskip) && ng_state != 6)
1267 {
1268 acceleratestage = 0;
1269
1270 for (i = 0; i<MAXPLAYERS; i++)
1271 {
1272 if (!playeringame[i])
1273 continue;
1274
1275 cnt_frags[i] = plrs[i].fragcount;
1276 cnt_deaths[i] = player_deaths[i];
1277 }
1278 S_Sound(CHAN_VOICE | CHAN_UI, "intermission/nextstage", 1, ATTN_NONE);
1279 ng_state = 6;
1280 }
1281
1282 if (ng_state == 2)
1283 {
1284 if (!(bcnt & 3))
1285 S_Sound(CHAN_VOICE | CHAN_UI, "intermission/tick", 1, ATTN_NONE);
1286
1287 stillticking = false;
1288
1289 for (i = 0; i<MAXPLAYERS; i++)
1290 {
1291 if (!playeringame[i])
1292 continue;
1293
1294 cnt_frags[i] += 2;
1295
1296 if (cnt_frags[i] > plrs[i].fragcount)
1297 cnt_frags[i] = plrs[i].fragcount;
1298 else
1299 stillticking = true;
1300 }
1301
1302 if (!stillticking)
1303 {
1304 S_Sound(CHAN_VOICE | CHAN_UI, "intermission/nextstage", 1, ATTN_NONE);
1305 ng_state++;
1306 }
1307 }
1308 else if (ng_state == 4)
1309 {
1310 if (!(bcnt & 3))
1311 S_Sound(CHAN_VOICE | CHAN_UI, "intermission/tick", 1, ATTN_NONE);
1312
1313 stillticking = false;
1314
1315 for (i = 0; i<MAXPLAYERS; i++)
1316 {
1317 if (!playeringame[i])
1318 continue;
1319
1320 cnt_deaths[i] += 2;
1321 if (cnt_deaths[i] > player_deaths[i])
1322 cnt_deaths[i] = player_deaths[i];
1323 else
1324 stillticking = true;
1325 }
1326 if (!stillticking)
1327 {
1328 S_Sound(CHAN_VOICE | CHAN_UI, "intermission/nextstage", 1, ATTN_NONE);
1329 ng_state++;
1330 }
1331 }
1332 else if (ng_state == 6)
1333 {
1334 int i;
1335 for (i = 0; i < MAXPLAYERS; i++)
1336 {
1337 // If the player is in the game and not ready, stop checking
1338 if (playeringame[i] && players[i].Bot == NULL && !playerready[i])
1339 break;
1340 }
1341
1342 // All players are ready; proceed.
1343 if ((i == MAXPLAYERS && acceleratestage) || autoskip)
1344 {
1345 S_Sound(CHAN_VOICE | CHAN_UI, "intermission/pastdmstats", 1, ATTN_NONE);
1346 WI_initShowNextLoc();
1347 }
1348 }
1349 else if (ng_state & 1)
1350 {
1351 if (!--cnt_pause)
1352 {
1353 ng_state++;
1354 cnt_pause = TICRATE;
1355 }
1356 }
1357 }
1358
1359
1360
WI_drawDeathmatchStats()1361 void WI_drawDeathmatchStats ()
1362 {
1363 int i, pnum, x, y, ypadding, height, lineheight;
1364 int maxnamewidth, maxscorewidth, maxiconheight;
1365 int pwidth = IntermissionFont->GetCharWidth('%');
1366 int icon_x, name_x, frags_x, deaths_x;
1367 int deaths_len;
1368 float h, s, v, r, g, b;
1369 EColorRange color;
1370 const char *text_deaths, *text_frags;
1371 FTexture *readyico = TexMan.FindTexture("READYICO");
1372 player_t *sortedplayers[MAXPLAYERS];
1373
1374 // draw animated background
1375 WI_drawBackground();
1376
1377 y = WI_drawLF();
1378
1379 HU_GetPlayerWidths(maxnamewidth, maxscorewidth, maxiconheight);
1380 // Use the readyico height if it's bigger.
1381 height = readyico->GetScaledHeight() - readyico->GetScaledTopOffset();
1382 maxiconheight = MAX(height, maxiconheight);
1383 height = SmallFont->GetHeight() * CleanYfac;
1384 lineheight = MAX(height, maxiconheight * CleanYfac);
1385 ypadding = (lineheight - height + 1) / 2;
1386 y += CleanYfac;
1387
1388 text_deaths = GStrings("SCORE_DEATHS");
1389 //text_color = GStrings("SCORE_COLOR");
1390 text_frags = GStrings("SCORE_FRAGS");
1391
1392 icon_x = 8 * CleanXfac;
1393 name_x = icon_x + maxscorewidth * CleanXfac;
1394 frags_x = name_x + (maxnamewidth + MAX(SmallFont->StringWidth("XXXXX"), SmallFont->StringWidth(text_frags)) + 8) * CleanXfac;
1395 deaths_x = frags_x + ((deaths_len = SmallFont->StringWidth(text_deaths)) + 8) * CleanXfac;
1396
1397 x = (SCREENWIDTH - deaths_x) >> 1;
1398 icon_x += x;
1399 name_x += x;
1400 frags_x += x;
1401 deaths_x += x;
1402
1403 color = (gameinfo.gametype & GAME_Raven) ? CR_GREEN : CR_UNTRANSLATED;
1404
1405 screen->DrawText(SmallFont, color, name_x, y, GStrings("SCORE_NAME"), DTA_CleanNoMove, true, TAG_DONE);
1406 screen->DrawText(SmallFont, color, frags_x - SmallFont->StringWidth(text_frags)*CleanXfac, y, text_frags, DTA_CleanNoMove, true, TAG_DONE);
1407 screen->DrawText(SmallFont, color, deaths_x - deaths_len*CleanXfac, y, text_deaths, DTA_CleanNoMove, true, TAG_DONE);
1408 y += height + 6 * CleanYfac;
1409
1410 // Sort all players
1411 for (i = 0; i < MAXPLAYERS; i++)
1412 {
1413 sortedplayers[i] = &players[i];
1414 }
1415
1416 if (teamplay)
1417 qsort(sortedplayers, MAXPLAYERS, sizeof(player_t *), compareteams);
1418 else
1419 qsort(sortedplayers, MAXPLAYERS, sizeof(player_t *), comparepoints);
1420
1421 // Draw lines for each player
1422 for (i = 0; i < MAXPLAYERS; i++)
1423 {
1424 player_t *player = sortedplayers[i];
1425 pnum = int(player - players);
1426
1427 if (!playeringame[pnum])
1428 continue;
1429
1430 D_GetPlayerColor(pnum, &h, &s, &v, NULL);
1431 HSVtoRGB(&r, &g, &b, h, s, v);
1432
1433 screen->Dim(MAKERGB(clamp(int(r*255.f), 0, 255),
1434 clamp(int(g*255.f), 0, 255),
1435 clamp(int(b*255.f), 0, 255)), 0.8f, x, y - ypadding, (deaths_x - x) + (8 * CleanXfac), lineheight);
1436
1437 if (playerready[pnum] || player->Bot != NULL) // Bots are automatically assumed ready, to prevent confusion
1438 screen->DrawTexture(readyico, x - (readyico->GetWidth() * CleanXfac), y, DTA_CleanNoMove, true, TAG_DONE);
1439
1440 color = (EColorRange)HU_GetRowColor(player, pnum == consoleplayer);
1441 if (player->mo->ScoreIcon.isValid())
1442 {
1443 FTexture *pic = TexMan[player->mo->ScoreIcon];
1444 screen->DrawTexture(pic, icon_x, y, DTA_CleanNoMove, true, TAG_DONE);
1445 }
1446 screen->DrawText(SmallFont, color, name_x, y + ypadding, player->userinfo.GetName(), DTA_CleanNoMove, true, TAG_DONE);
1447 WI_drawNum(SmallFont, frags_x, y + ypadding, cnt_frags[pnum], 0, false, color);
1448 if (ng_state >= 2)
1449 {
1450 WI_drawNum(SmallFont, deaths_x, y + ypadding, cnt_deaths[pnum], 0, false, color);
1451 }
1452 y += lineheight + CleanYfac;
1453 }
1454
1455 // Draw "TOTAL" line
1456 y += height + 3 * CleanYfac;
1457 color = (gameinfo.gametype & GAME_Raven) ? CR_GREEN : CR_UNTRANSLATED;
1458 screen->DrawText(SmallFont, color, name_x, y, GStrings("SCORE_TOTAL"), DTA_CleanNoMove, true, TAG_DONE);
1459 WI_drawNum(SmallFont, frags_x, y, total_frags, 0, false, color);
1460 if (ng_state >= 4)
1461 {
1462 WI_drawNum(SmallFont, deaths_x, y, total_deaths, 0, false, color);
1463 }
1464
1465 // Draw game time
1466 y += height + CleanYfac;
1467
1468 int seconds = Tics2Seconds(plrs[me].stime);
1469 int hours = seconds / 3600;
1470 int minutes = (seconds % 3600) / 60;
1471 seconds = seconds % 60;
1472
1473 FString leveltime = GStrings("SCORE_LVLTIME");
1474 leveltime += ": ";
1475
1476 char timer[sizeof "HH:MM:SS"];
1477 mysnprintf(timer, sizeof(timer), "%02i:%02i:%02i", hours, minutes, seconds);
1478 leveltime += timer;
1479
1480 screen->DrawText(SmallFont, color, x, y, leveltime, DTA_CleanNoMove, true, TAG_DONE);
1481 }
1482
WI_initNetgameStats()1483 void WI_initNetgameStats ()
1484 {
1485
1486 int i;
1487
1488 state = StatCount;
1489 acceleratestage = 0;
1490 memset(playerready, 0, sizeof(playerready));
1491 ng_state = 1;
1492
1493 cnt_pause = TICRATE;
1494
1495 for (i = 0; i < MAXPLAYERS; i++)
1496 {
1497 if (!playeringame[i])
1498 continue;
1499
1500 cnt_kills[i] = cnt_items[i] = cnt_secret[i] = cnt_frags[i] = 0;
1501
1502 dofrags += WI_fragSum (i);
1503 }
1504
1505 dofrags = !!dofrags;
1506 }
1507
WI_updateNetgameStats()1508 void WI_updateNetgameStats ()
1509 {
1510
1511 int i;
1512 int fsum;
1513 bool stillticking;
1514 bool autoskip = WI_autoSkip();
1515
1516 WI_updateAnimatedBack ();
1517
1518 if ((acceleratestage || autoskip) && ng_state != 10)
1519 {
1520 acceleratestage = 0;
1521
1522 for (i=0 ; i<MAXPLAYERS ; i++)
1523 {
1524 if (!playeringame[i])
1525 continue;
1526
1527 cnt_kills[i] = plrs[i].skills;
1528 cnt_items[i] = plrs[i].sitems;
1529 cnt_secret[i] = plrs[i].ssecret;
1530
1531 if (dofrags)
1532 cnt_frags[i] = WI_fragSum (i);
1533 }
1534 S_Sound (CHAN_VOICE | CHAN_UI, "intermission/nextstage", 1, ATTN_NONE);
1535 ng_state = 10;
1536 }
1537
1538 if (ng_state == 2)
1539 {
1540 if (!(bcnt&3))
1541 S_Sound (CHAN_VOICE | CHAN_UI, "intermission/tick", 1, ATTN_NONE);
1542
1543 stillticking = false;
1544
1545 for (i=0 ; i<MAXPLAYERS ; i++)
1546 {
1547 if (!playeringame[i])
1548 continue;
1549
1550 cnt_kills[i] += 2;
1551
1552 if (cnt_kills[i] > plrs[i].skills)
1553 cnt_kills[i] = plrs[i].skills;
1554 else
1555 stillticking = true;
1556 }
1557
1558 if (!stillticking)
1559 {
1560 S_Sound (CHAN_VOICE | CHAN_UI, "intermission/nextstage", 1, ATTN_NONE);
1561 ng_state++;
1562 }
1563 }
1564 else if (ng_state == 4)
1565 {
1566 if (!(bcnt&3))
1567 S_Sound (CHAN_VOICE | CHAN_UI, "intermission/tick", 1, ATTN_NONE);
1568
1569 stillticking = false;
1570
1571 for (i=0 ; i<MAXPLAYERS ; i++)
1572 {
1573 if (!playeringame[i])
1574 continue;
1575
1576 cnt_items[i] += 2;
1577 if (cnt_items[i] > plrs[i].sitems)
1578 cnt_items[i] = plrs[i].sitems;
1579 else
1580 stillticking = true;
1581 }
1582 if (!stillticking)
1583 {
1584 S_Sound (CHAN_VOICE | CHAN_UI, "intermission/nextstage", 1, ATTN_NONE);
1585 ng_state++;
1586 }
1587 }
1588 else if (ng_state == 6)
1589 {
1590 if (!(bcnt&3))
1591 S_Sound (CHAN_VOICE | CHAN_UI, "intermission/tick", 1, ATTN_NONE);
1592
1593 stillticking = false;
1594
1595 for (i=0 ; i<MAXPLAYERS ; i++)
1596 {
1597 if (!playeringame[i])
1598 continue;
1599
1600 cnt_secret[i] += 2;
1601
1602 if (cnt_secret[i] > plrs[i].ssecret)
1603 cnt_secret[i] = plrs[i].ssecret;
1604 else
1605 stillticking = true;
1606 }
1607
1608 if (!stillticking)
1609 {
1610 S_Sound (CHAN_VOICE | CHAN_UI, "intermission/nextstage", 1, ATTN_NONE);
1611 ng_state += 1 + 2*!dofrags;
1612 }
1613 }
1614 else if (ng_state == 8)
1615 {
1616 if (!(bcnt&3))
1617 S_Sound (CHAN_VOICE | CHAN_UI, "intermission/tick", 1, ATTN_NONE);
1618
1619 stillticking = false;
1620
1621 for (i=0 ; i<MAXPLAYERS ; i++)
1622 {
1623 if (!playeringame[i])
1624 continue;
1625
1626 cnt_frags[i] += 1;
1627
1628 if (cnt_frags[i] >= (fsum = WI_fragSum(i)))
1629 cnt_frags[i] = fsum;
1630 else
1631 stillticking = true;
1632 }
1633
1634 if (!stillticking)
1635 {
1636 S_Sound (CHAN_VOICE | CHAN_UI, "intermission/cooptotal", 1, ATTN_NONE);
1637 ng_state++;
1638 }
1639 }
1640 else if (ng_state == 10)
1641 {
1642 int i;
1643 for (i = 0; i < MAXPLAYERS; i++)
1644 {
1645 // If the player is in the game and not ready, stop checking
1646 if (playeringame[i] && players[i].Bot == NULL && !playerready[i])
1647 break;
1648 }
1649
1650 // All players are ready; proceed.
1651 if ((i == MAXPLAYERS && acceleratestage) || autoskip)
1652 {
1653 S_Sound (CHAN_VOICE | CHAN_UI, "intermission/pastcoopstats", 1, ATTN_NONE);
1654 WI_initShowNextLoc();
1655 }
1656 }
1657 else if (ng_state & 1)
1658 {
1659 if (!--cnt_pause)
1660 {
1661 ng_state++;
1662 cnt_pause = TICRATE;
1663 }
1664 }
1665 }
1666
WI_drawNetgameStats()1667 void WI_drawNetgameStats ()
1668 {
1669 int i, x, y, ypadding, height, lineheight;
1670 int maxnamewidth, maxscorewidth, maxiconheight;
1671 int pwidth = IntermissionFont->GetCharWidth('%');
1672 int icon_x, name_x, kills_x, bonus_x, secret_x;
1673 int bonus_len, secret_len;
1674 int missed_kills, missed_items, missed_secrets;
1675 float h, s, v, r, g, b;
1676 EColorRange color;
1677 const char *text_bonus, *text_secret, *text_kills;
1678 FTexture *readyico = TexMan.FindTexture("READYICO");
1679
1680 // draw animated background
1681 WI_drawBackground();
1682
1683 y = WI_drawLF();
1684
1685 HU_GetPlayerWidths(maxnamewidth, maxscorewidth, maxiconheight);
1686 // Use the readyico height if it's bigger.
1687 height = readyico->GetScaledHeight() - readyico->GetScaledTopOffset();
1688 if (height > maxiconheight)
1689 {
1690 maxiconheight = height;
1691 }
1692 height = SmallFont->GetHeight() * CleanYfac;
1693 lineheight = MAX(height, maxiconheight * CleanYfac);
1694 ypadding = (lineheight - height + 1) / 2;
1695 y += CleanYfac;
1696
1697 text_bonus = GStrings((gameinfo.gametype & GAME_Raven) ? "SCORE_BONUS" : "SCORE_ITEMS");
1698 text_secret = GStrings("SCORE_SECRET");
1699 text_kills = GStrings("SCORE_KILLS");
1700
1701 icon_x = 8 * CleanXfac;
1702 name_x = icon_x + maxscorewidth * CleanXfac;
1703 kills_x = name_x + (maxnamewidth + MAX(SmallFont->StringWidth("XXXXX"), SmallFont->StringWidth(text_kills)) + 8) * CleanXfac;
1704 bonus_x = kills_x + ((bonus_len = SmallFont->StringWidth(text_bonus)) + 8) * CleanXfac;
1705 secret_x = bonus_x + ((secret_len = SmallFont->StringWidth(text_secret)) + 8) * CleanXfac;
1706
1707 x = (SCREENWIDTH - secret_x) >> 1;
1708 icon_x += x;
1709 name_x += x;
1710 kills_x += x;
1711 bonus_x += x;
1712 secret_x += x;
1713
1714 color = (gameinfo.gametype & GAME_Raven) ? CR_GREEN : CR_UNTRANSLATED;
1715
1716 screen->DrawText(SmallFont, color, name_x, y, GStrings("SCORE_NAME"), DTA_CleanNoMove, true, TAG_DONE);
1717 screen->DrawText(SmallFont, color, kills_x - SmallFont->StringWidth(text_kills)*CleanXfac, y, text_kills, DTA_CleanNoMove, true, TAG_DONE);
1718 screen->DrawText(SmallFont, color, bonus_x - bonus_len*CleanXfac, y, text_bonus, DTA_CleanNoMove, true, TAG_DONE);
1719 screen->DrawText(SmallFont, color, secret_x - secret_len*CleanXfac, y, text_secret, DTA_CleanNoMove, true, TAG_DONE);
1720 y += height + 6 * CleanYfac;
1721
1722 missed_kills = wbs->maxkills;
1723 missed_items = wbs->maxitems;
1724 missed_secrets = wbs->maxsecret;
1725
1726 // Draw lines for each player
1727 for (i = 0; i < MAXPLAYERS; ++i)
1728 {
1729 player_t *player;
1730
1731 if (!playeringame[i])
1732 continue;
1733
1734 player = &players[i];
1735
1736 D_GetPlayerColor(i, &h, &s, &v, NULL);
1737 HSVtoRGB(&r, &g, &b, h, s, v);
1738
1739 screen->Dim(MAKERGB(clamp(int(r*255.f), 0, 255),
1740 clamp(int(g*255.f), 0, 255),
1741 clamp(int(b*255.f), 0, 255)), 0.8f, x, y - ypadding, (secret_x - x) + (8 * CleanXfac), lineheight);
1742
1743 if (playerready[i] || player->Bot != NULL) // Bots are automatically assumed ready, to prevent confusion
1744 screen->DrawTexture(readyico, x - (readyico->GetWidth() * CleanXfac), y, DTA_CleanNoMove, true, TAG_DONE);
1745
1746 color = (EColorRange)HU_GetRowColor(player, i == consoleplayer);
1747 if (player->mo->ScoreIcon.isValid())
1748 {
1749 FTexture *pic = TexMan[player->mo->ScoreIcon];
1750 screen->DrawTexture(pic, icon_x, y, DTA_CleanNoMove, true, TAG_DONE);
1751 }
1752 screen->DrawText(SmallFont, color, name_x, y + ypadding, player->userinfo.GetName(), DTA_CleanNoMove, true, TAG_DONE);
1753 WI_drawPercent(SmallFont, kills_x, y + ypadding, cnt_kills[i], wbs->maxkills, false, color);
1754 missed_kills -= cnt_kills[i];
1755 if (ng_state >= 4)
1756 {
1757 WI_drawPercent(SmallFont, bonus_x, y + ypadding, cnt_items[i], wbs->maxitems, false, color);
1758 missed_items -= cnt_items[i];
1759 if (ng_state >= 6)
1760 {
1761 WI_drawPercent(SmallFont, secret_x, y + ypadding, cnt_secret[i], wbs->maxsecret, false, color);
1762 missed_secrets -= cnt_secret[i];
1763 }
1764 }
1765 y += lineheight + CleanYfac;
1766 }
1767
1768 // Draw "MISSED" line
1769 y += 3 * CleanYfac;
1770 screen->DrawText(SmallFont, CR_DARKGRAY, name_x, y, GStrings("SCORE_MISSED"), DTA_CleanNoMove, true, TAG_DONE);
1771 WI_drawPercent(SmallFont, kills_x, y, missed_kills, wbs->maxkills, false, CR_DARKGRAY);
1772 if (ng_state >= 4)
1773 {
1774 WI_drawPercent(SmallFont, bonus_x, y, missed_items, wbs->maxitems, false, CR_DARKGRAY);
1775 if (ng_state >= 6)
1776 {
1777 WI_drawPercent(SmallFont, secret_x, y, missed_secrets, wbs->maxsecret, false, CR_DARKGRAY);
1778 }
1779 }
1780
1781 // Draw "TOTAL" line
1782 y += height + 3 * CleanYfac;
1783 color = (gameinfo.gametype & GAME_Raven) ? CR_GREEN : CR_UNTRANSLATED;
1784 screen->DrawText(SmallFont, color, name_x, y, GStrings("SCORE_TOTAL"), DTA_CleanNoMove, true, TAG_DONE);
1785 WI_drawNum(SmallFont, kills_x, y, wbs->maxkills, 0, false, color);
1786 if (ng_state >= 4)
1787 {
1788 WI_drawNum(SmallFont, bonus_x, y, wbs->maxitems, 0, false, color);
1789 if (ng_state >= 6)
1790 {
1791 WI_drawNum(SmallFont, secret_x, y, wbs->maxsecret, 0, false, color);
1792 }
1793 }
1794 }
1795
1796 static int sp_state;
1797
WI_initStats()1798 void WI_initStats ()
1799 {
1800 state = StatCount;
1801 acceleratestage = 0;
1802 sp_state = 1;
1803 cnt_kills[0] = cnt_items[0] = cnt_secret[0] = -1;
1804 cnt_time = cnt_par = -1;
1805 cnt_pause = TICRATE;
1806
1807 cnt_total_time = -1;
1808 }
1809
WI_updateStats()1810 void WI_updateStats ()
1811 {
1812 WI_updateAnimatedBack ();
1813
1814 if (acceleratestage && sp_state != 10)
1815 {
1816 acceleratestage = 0;
1817 sp_state = 10;
1818 S_Sound (CHAN_VOICE | CHAN_UI, "intermission/nextstage", 1, ATTN_NONE);
1819
1820 cnt_kills[0] = plrs[me].skills;
1821 cnt_items[0] = plrs[me].sitems;
1822 cnt_secret[0] = plrs[me].ssecret;
1823 cnt_time = Tics2Seconds(plrs[me].stime);
1824 cnt_par = wbs->partime / TICRATE;
1825 cnt_total_time = Tics2Seconds(wbs->totaltime);
1826 }
1827
1828 if (sp_state == 2)
1829 {
1830 if (gameinfo.intermissioncounter)
1831 {
1832 cnt_kills[0] += 2;
1833
1834 if (!(bcnt&3))
1835 S_Sound (CHAN_VOICE | CHAN_UI, "intermission/tick", 1, ATTN_NONE);
1836 }
1837 if (!gameinfo.intermissioncounter || cnt_kills[0] >= plrs[me].skills)
1838 {
1839 cnt_kills[0] = plrs[me].skills;
1840 S_Sound (CHAN_VOICE | CHAN_UI, "intermission/nextstage", 1, ATTN_NONE);
1841 sp_state++;
1842 }
1843 }
1844 else if (sp_state == 4)
1845 {
1846 if (gameinfo.intermissioncounter)
1847 {
1848 cnt_items[0] += 2;
1849
1850 if (!(bcnt&3))
1851 S_Sound (CHAN_VOICE | CHAN_UI, "intermission/tick", 1, ATTN_NONE);
1852 }
1853 if (!gameinfo.intermissioncounter || cnt_items[0] >= plrs[me].sitems)
1854 {
1855 cnt_items[0] = plrs[me].sitems;
1856 S_Sound (CHAN_VOICE | CHAN_UI, "intermission/nextstage", 1, ATTN_NONE);
1857 sp_state++;
1858 }
1859 }
1860 else if (sp_state == 6)
1861 {
1862 if (gameinfo.intermissioncounter)
1863 {
1864 cnt_secret[0] += 2;
1865
1866 if (!(bcnt&3))
1867 S_Sound (CHAN_VOICE | CHAN_UI, "intermission/tick", 1, ATTN_NONE);
1868 }
1869 if (!gameinfo.intermissioncounter || cnt_secret[0] >= plrs[me].ssecret)
1870 {
1871 cnt_secret[0] = plrs[me].ssecret;
1872 S_Sound (CHAN_VOICE | CHAN_UI, "intermission/nextstage", 1, ATTN_NONE);
1873 sp_state++;
1874 }
1875 }
1876 else if (sp_state == 8)
1877 {
1878 if (gameinfo.intermissioncounter)
1879 {
1880 if (!(bcnt&3))
1881 S_Sound (CHAN_VOICE | CHAN_UI, "intermission/tick", 1, ATTN_NONE);
1882
1883 cnt_time += 3;
1884 cnt_par += 3;
1885 cnt_total_time += 3;
1886 }
1887
1888 int sec = Tics2Seconds(plrs[me].stime);
1889 if (!gameinfo.intermissioncounter || cnt_time >= sec)
1890 cnt_time = sec;
1891
1892 int tsec = Tics2Seconds(wbs->totaltime);
1893 if (!gameinfo.intermissioncounter || cnt_total_time >= tsec)
1894 cnt_total_time = tsec;
1895
1896 if (!gameinfo.intermissioncounter || cnt_par >= wbs->partime / TICRATE)
1897 {
1898 cnt_par = wbs->partime / TICRATE;
1899
1900 if (cnt_time >= sec)
1901 {
1902 cnt_total_time = tsec;
1903 S_Sound (CHAN_VOICE | CHAN_UI, "intermission/nextstage", 1, ATTN_NONE);
1904 sp_state++;
1905 }
1906 }
1907 }
1908 else if (sp_state == 10)
1909 {
1910 if (acceleratestage)
1911 {
1912 S_Sound (CHAN_VOICE | CHAN_UI, "intermission/paststats", 1, ATTN_NONE);
1913 WI_initShowNextLoc();
1914 }
1915 }
1916 else if (sp_state & 1)
1917 {
1918 if (!--cnt_pause)
1919 {
1920 sp_state++;
1921 cnt_pause = TICRATE;
1922 }
1923 }
1924 }
1925
WI_drawStats(void)1926 void WI_drawStats (void)
1927 {
1928 // line height
1929 int lh;
1930
1931 lh = IntermissionFont->GetHeight() * 3 / 2;
1932
1933 // draw animated background
1934 WI_drawBackground();
1935
1936 WI_drawLF();
1937
1938 if (gameinfo.gametype & GAME_DoomChex)
1939 {
1940 screen->DrawTexture (kills, SP_STATSX, SP_STATSY, DTA_Clean, true, TAG_DONE);
1941 WI_drawPercent (IntermissionFont, 320 - SP_STATSX, SP_STATSY, cnt_kills[0], wbs->maxkills);
1942
1943 screen->DrawTexture (items, SP_STATSX, SP_STATSY+lh, DTA_Clean, true, TAG_DONE);
1944 WI_drawPercent (IntermissionFont, 320 - SP_STATSX, SP_STATSY+lh, cnt_items[0], wbs->maxitems);
1945
1946 screen->DrawTexture (sp_secret, SP_STATSX, SP_STATSY+2*lh, DTA_Clean, true, TAG_DONE);
1947 WI_drawPercent (IntermissionFont, 320 - SP_STATSX, SP_STATSY+2*lh, cnt_secret[0], wbs->maxsecret);
1948
1949 screen->DrawTexture (timepic, SP_TIMEX, SP_TIMEY, DTA_Clean, true, TAG_DONE);
1950 WI_drawTime (160 - SP_TIMEX, SP_TIMEY, cnt_time);
1951 if (wi_showtotaltime)
1952 {
1953 WI_drawTime (160 - SP_TIMEX, SP_TIMEY + lh, cnt_total_time, true); // no 'sucks' for total time ever!
1954 }
1955
1956 if (wbs->partime)
1957 {
1958 screen->DrawTexture (par, 160 + SP_TIMEX, SP_TIMEY, DTA_Clean, true, TAG_DONE);
1959 WI_drawTime (320 - SP_TIMEX, SP_TIMEY, cnt_par);
1960 }
1961
1962 }
1963 else
1964 {
1965 screen->DrawText (BigFont, CR_UNTRANSLATED, 50, 65, GStrings("TXT_IMKILLS"), DTA_Clean, true, DTA_Shadow, true, TAG_DONE);
1966 screen->DrawText (BigFont, CR_UNTRANSLATED, 50, 90, GStrings("TXT_IMITEMS"), DTA_Clean, true, DTA_Shadow, true, TAG_DONE);
1967 screen->DrawText (BigFont, CR_UNTRANSLATED, 50, 115, GStrings("TXT_IMSECRETS"), DTA_Clean, true, DTA_Shadow, true, TAG_DONE);
1968
1969 int countpos = gameinfo.gametype==GAME_Strife? 285:270;
1970 if (sp_state >= 2)
1971 {
1972 WI_drawPercent (IntermissionFont, countpos, 65, cnt_kills[0], wbs->maxkills);
1973 }
1974 if (sp_state >= 4)
1975 {
1976 WI_drawPercent (IntermissionFont, countpos, 90, cnt_items[0], wbs->maxitems);
1977 }
1978 if (sp_state >= 6)
1979 {
1980 WI_drawPercent (IntermissionFont, countpos, 115, cnt_secret[0], wbs->maxsecret);
1981 }
1982 if (sp_state >= 8)
1983 {
1984 screen->DrawText (BigFont, CR_UNTRANSLATED, 85, 160, GStrings("TXT_IMTIME"),
1985 DTA_Clean, true, DTA_Shadow, true, TAG_DONE);
1986 WI_drawTime (249, 160, cnt_time);
1987 if (wi_showtotaltime)
1988 {
1989 WI_drawTime (249, 180, cnt_total_time);
1990 }
1991 }
1992 }
1993 }
1994
1995 // ====================================================================
1996 // WI_checkForAccelerate
1997 // Purpose: See if the player has hit either the attack or use key
1998 // or mouse button. If so we set acceleratestage to 1 and
1999 // all those display routines above jump right to the end.
2000 // Args: none
2001 // Returns: void
2002 //
2003 // ====================================================================
WI_checkForAccelerate(void)2004 void WI_checkForAccelerate(void)
2005 {
2006 int i;
2007 player_t *player;
2008
2009 // check for button presses to skip delays
2010 for (i = 0, player = players; i < MAXPLAYERS; i++, player++)
2011 {
2012 if (playeringame[i])
2013 {
2014 if ((player->cmd.ucmd.buttons ^ player->oldbuttons) &&
2015 ((players[i].cmd.ucmd.buttons & players[i].oldbuttons)
2016 == players[i].oldbuttons) && player->Bot == NULL)
2017 {
2018 acceleratestage = 1;
2019 playerready[i] = true;
2020 }
2021 player->oldbuttons = player->cmd.ucmd.buttons;
2022 }
2023 }
2024 }
2025
2026 // ====================================================================
2027 // WI_Ticker
2028 // Purpose: Do various updates every gametic, for stats, animation,
2029 // checking that intermission music is running, etc.
2030 // Args: none
2031 // Returns: void
2032 //
2033 // ====================================================================
WI_Ticker(void)2034 void WI_Ticker(void)
2035 {
2036 // counter for general background animation
2037 bcnt++;
2038
2039 if (bcnt == 1)
2040 {
2041 // intermission music - use the defaults if none specified
2042 if (level.info->InterMusic.IsNotEmpty())
2043 S_ChangeMusic(level.info->InterMusic, level.info->intermusicorder);
2044 else
2045 S_ChangeMusic (gameinfo.intermissionMusic.GetChars(), gameinfo.intermissionOrder);
2046
2047 }
2048
2049 WI_checkForAccelerate();
2050
2051 switch (state)
2052 {
2053 case StatCount:
2054 if (deathmatch) WI_updateDeathmatchStats();
2055 else if (multiplayer) WI_updateNetgameStats();
2056 else WI_updateStats();
2057 break;
2058
2059 case ShowNextLoc:
2060 WI_updateShowNextLoc();
2061 break;
2062
2063 case NoState:
2064 WI_updateNoState();
2065 break;
2066
2067 case LeavingIntermission:
2068 // Hush, GCC.
2069 break;
2070 }
2071 }
2072
2073
WI_loadData(void)2074 void WI_loadData(void)
2075 {
2076 entering.Init(gameinfo.mStatscreenEnteringFont);
2077 finished.Init(gameinfo.mStatscreenFinishedFont);
2078 mapname.Init(gameinfo.mStatscreenMapNameFont);
2079
2080 if (gameinfo.gametype & GAME_DoomChex)
2081 {
2082 kills = TexMan["WIOSTK"]; // "kills"
2083 secret = TexMan["WIOSTS"]; // "scrt"
2084 sp_secret = TexMan["WISCRT2"]; // "secret"
2085 items = TexMan["WIOSTI"]; // "items"
2086 frags = TexMan["WIFRGS"]; // "frgs"
2087 timepic = TexMan["WITIME"]; // "time"
2088 sucks = TexMan["WISUCKS"]; // "sucks"
2089 par = TexMan["WIPAR"]; // "par"
2090 killers = TexMan["WIKILRS"]; // "killers" (vertical]
2091 victims = TexMan["WIVCTMS"]; // "victims" (horiz]
2092 total = TexMan["WIMSTT"]; // "total"
2093 // star = TexMan["STFST01"]; // your face
2094 // bstar = TexMan["STFDEAD0"]; // dead face
2095 p = TexMan["STPBANY"];
2096 }
2097 #if 0
2098 else if (gameinfo.gametype & GAME_Raven)
2099 {
2100 if (gameinfo.gametype == GAME_Heretic)
2101 {
2102 star = TexMan["FACEA0"];
2103 bstar = TexMan["FACEB0"];
2104 }
2105 else
2106 {
2107 star = BigFont->GetChar('*', NULL);
2108 bstar = star;
2109 }
2110 }
2111 else // Strife needs some handling, too!
2112 {
2113 star = BigFont->GetChar('*', NULL);
2114 bstar = star;
2115 }
2116 #endif
2117
2118 // Use the local level structure which can be overridden by hubs
2119 lnametexts[0] = level.LevelName;
2120
2121 level_info_t *li = FindLevelInfo(wbs->next);
2122 if (li) lnametexts[1] = li->LookupLevelName();
2123 else lnametexts[1] = "";
2124
2125 WI_LoadBackground(false);
2126 }
2127
WI_unloadData()2128 void WI_unloadData ()
2129 {
2130 // [RH] The texture data gets unloaded at pre-map time, so there's nothing to do here
2131 return;
2132 }
2133
WI_Drawer(void)2134 void WI_Drawer (void)
2135 {
2136 switch (state)
2137 {
2138 case StatCount:
2139 if (deathmatch)
2140 WI_drawDeathmatchStats();
2141 else if (multiplayer)
2142 WI_drawNetgameStats();
2143 else
2144 WI_drawStats();
2145 break;
2146
2147 case ShowNextLoc:
2148 WI_drawShowNextLoc();
2149 break;
2150
2151 case LeavingIntermission:
2152 break;
2153
2154 default:
2155 WI_drawNoState();
2156 break;
2157 }
2158 }
2159
2160
WI_initVariables(wbstartstruct_t * wbstartstruct)2161 void WI_initVariables (wbstartstruct_t *wbstartstruct)
2162 {
2163 wbs = wbstartstruct;
2164 acceleratestage = 0;
2165 cnt = bcnt = 0;
2166 me = wbs->pnum;
2167 plrs = wbs->plyr;
2168 }
2169
WI_Start(wbstartstruct_t * wbstartstruct)2170 void WI_Start (wbstartstruct_t *wbstartstruct)
2171 {
2172 noautostartmap = false;
2173 V_SetBlend (0,0,0,0);
2174 WI_initVariables (wbstartstruct);
2175 WI_loadData ();
2176 if (deathmatch)
2177 WI_initDeathmatchStats();
2178 else if (multiplayer)
2179 WI_initNetgameStats();
2180 else
2181 WI_initStats();
2182 S_StopAllChannels ();
2183 SN_StopAllSequences ();
2184 }
2185