]> icculus.org git repositories - theoddone33/hhexen.git/blob - base/in_lude.c
Initial revision
[theoddone33/hhexen.git] / base / in_lude.c
1
2 //**************************************************************************
3 //**
4 //** in_lude.c : Heretic 2 : Raven Software, Corp.
5 //**
6 //** $RCSfile$
7 //** $Revision$
8 //** $Date$
9 //** $Author$
10 //**
11 //**************************************************************************
12
13 #include "h2def.h"
14 #include <ctype.h>
15
16 // MACROS ------------------------------------------------------------------
17
18 #define TEXTSPEED 3
19 #define TEXTWAIT 140
20
21 // TYPES -------------------------------------------------------------------
22
23 typedef enum
24 {
25         SINGLE,
26         COOPERATIVE,
27         DEATHMATCH
28 } gametype_t;
29
30 // EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
31
32 // PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
33
34 void IN_Start(void);
35 void IN_Ticker(void);
36 void IN_Drawer(void);
37
38 // PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
39
40 static void WaitStop(void);
41 static void Stop(void);
42 static void LoadPics(void);
43 static void UnloadPics(void);
44 static void CheckForSkip(void);
45 static void InitStats(void);
46 static void DrDeathTally(void);
47 static void DrNumber(int val, int x, int y, int wrapThresh);
48 static void DrNumberBold(int val, int x, int y, int wrapThresh);
49 static void DrawHubText(void);
50
51 // EXTERNAL DATA DECLARATIONS ----------------------------------------------
52
53 // PUBLIC DATA DECLARATIONS ------------------------------------------------
54
55 boolean intermission;
56 char ClusterMessage[MAX_INTRMSN_MESSAGE_SIZE];
57
58 // PRIVATE DATA DEFINITIONS ------------------------------------------------
59
60 static boolean skipintermission;
61 static int interstate = 0;
62 static int intertime = -1;
63 static gametype_t gametype;
64 static int cnt;
65 static int slaughterboy; // in DM, the player with the most kills
66 static patch_t *patchINTERPIC;
67 static patch_t *FontBNumbers[10];
68 static patch_t *FontBNegative;
69 static patch_t *FontBSlash;
70 static patch_t *FontBPercent;
71 static int FontABaseLump;
72 static int FontBLump;
73 static int FontBLumpBase;
74
75 static signed int totalFrags[MAXPLAYERS];
76
77 static int HubCount;
78 static char *HubText;
79
80 // CODE --------------------------------------------------------------------
81
82 //========================================================================
83 //
84 // IN_Start
85 //
86 //========================================================================
87
88 extern void AM_Stop (void);
89
90 void IN_Start(void)
91 {
92         int i;
93         I_SetPalette(W_CacheLumpName("PLAYPAL", PU_CACHE));
94         InitStats();
95         LoadPics();
96         intermission = true;
97         interstate = 0;
98         skipintermission = false;
99         intertime = 0;
100         AM_Stop();
101         for(i = 0; i < MAXPLAYERS; i++)
102         {
103                 players[i].messageTics = 0;
104                 players[i].message[0] = 0;
105         }
106         SN_StopAllSequences();  
107 }
108
109 //========================================================================
110 //
111 // WaitStop
112 //
113 //========================================================================
114
115 void WaitStop(void)
116 {
117         if(!--cnt)
118         {
119                 Stop();
120 //              gamestate = GS_LEVEL;
121 //              G_DoLoadLevel();
122                 gameaction = ga_leavemap;
123 //              G_WorldDone();
124         }
125 }
126
127 //========================================================================
128 //
129 // Stop
130 //
131 //========================================================================
132
133 static void Stop(void)
134 {
135         intermission = false;
136         UnloadPics();
137         SB_state = -1;
138         BorderNeedRefresh = true;
139 }
140
141 //========================================================================
142 //
143 // InitStats
144 //
145 //      Initializes the stats for single player mode
146 //========================================================================
147
148 static char *ClusMsgLumpNames[] =
149 {
150 #ifdef VERSION10_WAD
151         CLUS1MSG,
152         CLUS2MSG,
153         CLUS3MSG,
154         CLUS4MSG,
155         CLUS5MSG
156 #else
157         "clus1msg",
158         "clus2msg", 
159         "clus3msg",
160         "clus4msg", 
161         "clus5msg"
162 #endif
163 };
164
165 static void InitStats(void)
166 {
167         int i;
168         int j;
169         int oldCluster;
170         signed int slaughterfrags;
171         int posnum;
172         int slaughtercount;
173         int playercount;
174         char *msgLumpName;
175         int msgSize;
176         int msgLump;
177
178         extern int LeaveMap;
179
180         if(!deathmatch)
181         {
182                 gametype = SINGLE;
183                 HubCount = 0;
184                 oldCluster = P_GetMapCluster(gamemap);
185                 if(oldCluster != P_GetMapCluster(LeaveMap))
186                 {
187                         if(oldCluster >= 1 && oldCluster <= 5)
188                         {
189 #ifdef VERSION10_WAD
190                                 HubText = ClusMsgLumpNames[oldCluster-1];
191 #else
192                                 msgLumpName = ClusMsgLumpNames[oldCluster-1];
193                                 msgLump = W_GetNumForName(msgLumpName);
194                                 msgSize = W_LumpLength(msgLump);
195                                 if(msgSize >= MAX_INTRMSN_MESSAGE_SIZE)
196                                 {
197                                         I_Error("Cluster message too long (%s)", msgLumpName);
198                                 }
199                                 W_ReadLump(msgLump, ClusterMessage);
200                                 ClusterMessage[msgSize] = 0; // Append terminator
201                                 HubText = ClusterMessage;
202 #endif
203                                 HubCount = strlen(HubText)*TEXTSPEED+TEXTWAIT;
204                                 S_StartSongName("hub", true);
205                         }
206                 }
207         }
208         else
209         {
210                 gametype = DEATHMATCH;
211                 slaughterboy = 0;
212                 slaughterfrags = -9999;
213                 posnum = 0;
214                 playercount = 0;
215                 slaughtercount = 0;
216                 for(i=0; i<MAXPLAYERS; i++)
217                 {
218                         totalFrags[i] = 0;
219                         if(playeringame[i])
220                         {
221                                 playercount++;
222                                 for(j=0; j<MAXPLAYERS; j++)
223                                 {
224                                         if(playeringame[j])
225                                         {
226                                                 totalFrags[i] += players[i].frags[j];
227                                         }
228                                 }
229                                 posnum++;
230                         }
231                         if(totalFrags[i] > slaughterfrags)
232                         {
233                                 slaughterboy = 1<<i;
234                                 slaughterfrags = totalFrags[i];
235                                 slaughtercount = 1;
236                         }
237                         else if(totalFrags[i] == slaughterfrags)
238                         {
239                                 slaughterboy |= 1<<i;
240                                 slaughtercount++;
241                         }
242                 }
243                 if(playercount == slaughtercount)
244                 { // don't do the slaughter stuff if everyone is equal
245                         slaughterboy = 0;
246                 }
247                 S_StartSongName("hub", true);
248         }
249 }
250
251 //========================================================================
252 //
253 // LoadPics
254 //
255 //========================================================================
256
257 static void LoadPics(void)
258 {
259         int i;
260
261         if(HubCount || gametype == DEATHMATCH)
262         {
263                 patchINTERPIC = W_CacheLumpName("INTERPIC", PU_STATIC);
264                 FontBLumpBase = W_GetNumForName("FONTB16");
265                 for(i=0; i<10; i++)
266                 {
267                         FontBNumbers[i] = W_CacheLumpNum(FontBLumpBase+i, PU_STATIC);
268                 }
269                 FontBLump = W_GetNumForName("FONTB_S")+1;
270                 FontBNegative = W_CacheLumpName("FONTB13", PU_STATIC);
271                 FontABaseLump = W_GetNumForName("FONTA_S")+1;
272         
273                 FontBSlash = W_CacheLumpName("FONTB15", PU_STATIC);
274                 FontBPercent = W_CacheLumpName("FONTB05", PU_STATIC);
275         }
276 }
277
278 //========================================================================
279 //
280 // UnloadPics
281 //
282 //========================================================================
283
284 static void UnloadPics(void)
285 {
286         int i;
287
288         if(HubCount || gametype == DEATHMATCH)
289         {
290                 Z_ChangeTag(patchINTERPIC, PU_CACHE);
291                 for(i=0; i<10; i++)
292                 {
293                         Z_ChangeTag(FontBNumbers[i], PU_CACHE);
294                 }
295                 Z_ChangeTag(FontBNegative, PU_CACHE);
296                 Z_ChangeTag(FontBSlash, PU_CACHE);
297                 Z_ChangeTag(FontBPercent, PU_CACHE);
298         }
299 }
300
301 //========================================================================
302 //
303 // IN_Ticker
304 //
305 //========================================================================
306
307 void IN_Ticker(void)
308 {
309         if(!intermission)
310         {
311                 return;
312         }
313         if(interstate)
314         {
315                 WaitStop();
316                 return;
317         }
318         skipintermission = false;
319         CheckForSkip();
320         intertime++;
321         if(skipintermission || (gametype == SINGLE && !HubCount))
322         {
323                 interstate = 1;
324                 cnt = 10;
325                 skipintermission = false;
326                 //S_StartSound(NULL, sfx_dorcls);
327         }
328 }
329
330 //========================================================================
331 //
332 // CheckForSkip
333 //
334 //      Check to see if any player hit a key
335 //========================================================================
336
337 static void CheckForSkip(void)
338 {
339         int i;
340         player_t *player;
341         static boolean triedToSkip;
342
343         for(i = 0, player = players; i < MAXPLAYERS; i++, player++)
344         {
345         if(playeringame[i])
346         {
347                         if(player->cmd.buttons&BT_ATTACK)
348                         {
349                                 if(!player->attackdown)
350                                 {
351                                         skipintermission = 1;
352                                 }
353                                 player->attackdown = true;
354                         }
355                         else
356                         {
357                                 player->attackdown = false;
358                         }
359                         if(player->cmd.buttons&BT_USE)
360                         {
361                                 if(!player->usedown)
362                                 {
363                                         skipintermission = 1;
364                                 }
365                                 player->usedown = true;
366                         }
367                         else
368                         {
369                                 player->usedown = false;
370                         }
371                 }
372         }
373         if(deathmatch && intertime < 140)
374         { // wait for 4 seconds before allowing a skip
375                 if(skipintermission == 1)
376                 {
377                         triedToSkip = true;
378                         skipintermission = 0;
379                 }
380         }
381         else
382         {
383                 if(triedToSkip)
384                 {
385                         skipintermission = 1;
386                         triedToSkip = false;
387                 }
388         }
389 }
390
391 //========================================================================
392 //
393 // IN_Drawer
394 //
395 //========================================================================
396
397 void IN_Drawer(void)
398 {
399         if(!intermission)
400         {
401                 return;
402         }
403         if(interstate)
404         {
405                 return;
406         }
407         UpdateState |= I_FULLSCRN;
408         memcpy(screen, (byte *)patchINTERPIC, SCREENWIDTH*SCREENHEIGHT);
409
410         if(gametype == SINGLE)
411         {
412                 if(HubCount)
413                 {
414                         DrawHubText();
415                 }
416         }
417         else
418         {
419                 DrDeathTally();
420         }
421 }
422
423 //========================================================================
424 //
425 // DrDeathTally
426 //
427 //========================================================================
428
429 #define TALLY_EFFECT_TICKS 20
430 #define TALLY_FINAL_X_DELTA (23*FRACUNIT)
431 #define TALLY_FINAL_Y_DELTA (13*FRACUNIT)
432 #define TALLY_START_XPOS (178*FRACUNIT)
433 #define TALLY_STOP_XPOS (90*FRACUNIT)
434 #define TALLY_START_YPOS (132*FRACUNIT)
435 #define TALLY_STOP_YPOS (83*FRACUNIT)
436 #define TALLY_TOP_X 85
437 #define TALLY_TOP_Y 9
438 #define TALLY_LEFT_X 7
439 #define TALLY_LEFT_Y 71
440 #define TALLY_TOTALS_X 291
441
442 static void DrDeathTally(void)
443 {
444         int i, j;
445         fixed_t xPos, yPos;
446         fixed_t xDelta, yDelta;
447         fixed_t xStart, scale;
448         int x, y;
449         boolean bold;
450         static boolean showTotals;
451         int temp;
452
453         V_DrawPatch(TALLY_TOP_X, TALLY_TOP_Y,
454                 W_CacheLumpName("tallytop", PU_CACHE));
455         V_DrawPatch(TALLY_LEFT_X, TALLY_LEFT_Y,
456                 W_CacheLumpName("tallylft", PU_CACHE));
457         if(intertime < TALLY_EFFECT_TICKS)
458         {
459                 showTotals = false;
460                 scale = (intertime*FRACUNIT)/TALLY_EFFECT_TICKS;
461                 xDelta = FixedMul(scale, TALLY_FINAL_X_DELTA);
462                 yDelta = FixedMul(scale, TALLY_FINAL_Y_DELTA);
463                 xStart = TALLY_START_XPOS-FixedMul(scale,
464                         TALLY_START_XPOS-TALLY_STOP_XPOS);
465                 yPos = TALLY_START_YPOS-FixedMul(scale,
466                         TALLY_START_YPOS-TALLY_STOP_YPOS);
467         }
468         else
469         {
470                 xDelta = TALLY_FINAL_X_DELTA;
471                 yDelta = TALLY_FINAL_Y_DELTA;
472                 xStart = TALLY_STOP_XPOS;
473                 yPos = TALLY_STOP_YPOS;
474         }
475         if(intertime >= TALLY_EFFECT_TICKS && showTotals == false)
476         {
477                 showTotals = true;
478                 S_StartSound(NULL, SFX_PLATFORM_STOP);
479         }
480         y = yPos>>FRACBITS;
481         for(i = 0; i < MAXPLAYERS; i++)
482         {
483                 xPos = xStart;
484                 for(j = 0; j < MAXPLAYERS; j++, xPos += xDelta)
485                 {
486                         x = xPos>>FRACBITS;
487                         bold = (i == consoleplayer || j == consoleplayer);
488                         if(playeringame[i] && playeringame[j])
489                         {
490                                 if(bold)
491                                 {
492                                         DrNumberBold(players[i].frags[j], x, y, 100);
493                                 }
494                                 else
495                                 {
496                                         DrNumber(players[i].frags[j], x, y, 100);
497                                 }
498                         }
499                         else
500                         {
501                                 temp = MN_TextAWidth("--")/2;
502                                 if(bold)
503                                 {
504                                         MN_DrTextAYellow("--", x-temp, y);
505                                 }
506                                 else
507                                 {
508                                         MN_DrTextA("--", x-temp, y);
509                                 }
510                         }
511                 }
512                 if(showTotals && playeringame[i]
513                         && !((slaughterboy&(1<<i)) && !(intertime&16)))
514                 {
515                         DrNumber(totalFrags[i], TALLY_TOTALS_X, y, 1000);
516                 }
517                 yPos += yDelta;
518                 y = yPos>>FRACBITS;
519         }
520 }
521
522 //==========================================================================
523 //
524 // DrNumber
525 //
526 //==========================================================================
527
528 static void DrNumber(int val, int x, int y, int wrapThresh)
529 {
530         char buff[8] = "XX";
531
532         if(!(val < -9 && wrapThresh < 1000))
533         {
534                 sprintf(buff, "%d", val >= wrapThresh ? val%wrapThresh : val);
535         }
536         MN_DrTextA(buff, x-MN_TextAWidth(buff)/2, y);
537 }
538
539 //==========================================================================
540 //
541 // DrNumberBold
542 //
543 //==========================================================================
544
545 static void DrNumberBold(int val, int x, int y, int wrapThresh)
546 {
547         char buff[8] = "XX";
548
549         if(!(val < -9 && wrapThresh < 1000))
550         {
551                 sprintf(buff, "%d", val >= wrapThresh ? val%wrapThresh : val);
552         }
553         MN_DrTextAYellow(buff, x-MN_TextAWidth(buff)/2, y);
554 }
555
556 //===========================================================================
557 //
558 // DrawHubText
559 //
560 //===========================================================================
561
562 static void DrawHubText(void)
563 {
564         int             count;
565         char    *ch;
566         int             c;
567         int             cx, cy;
568         patch_t *w;
569
570         cy = 5;
571         cx = 10;
572         ch = HubText;
573         count = (intertime-10)/TEXTSPEED;
574         if (count < 0)
575         {
576                 count = 0;
577         }
578         for(; count; count--)
579         {
580                 c = *ch++;
581                 if(!c)
582                 {
583                         break;
584                 }
585                 if(c == '\n')
586                 {
587                         cx = 10;
588                         cy += 9;
589                         continue;
590                 }
591                 if(c < 32)
592                 {
593                         continue;
594                 }
595                 c = toupper(c);
596                 if(c == 32)
597                 {
598                         cx += 5;
599                         continue;
600                 }
601                 w = W_CacheLumpNum(FontABaseLump+c-33, PU_CACHE);
602                 if(cx+w->width > SCREENWIDTH)
603                 {
604                         break;
605                 }
606                 V_DrawPatch(cx, cy, w);
607                 cx += w->width;
608         }
609 }