1 //
2 // Copyright(C) 1993-1996 Id Software, Inc.
3 // Copyright(C) 1993-2008 Raven Software
4 // Copyright(C) 2005-2014 Simon Howard
5 //
6 // This program is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU General Public License
8 // as published by the Free Software Foundation; either version 2
9 // of the License, or (at your option) any later version.
10 //
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 // GNU General Public License for more details.
15 //
16 
17 
18 // HEADER FILES ------------------------------------------------------------
19 
20 #include "h2def.h"
21 #include "i_system.h"
22 #include "i_video.h"
23 #include "p_local.h"
24 #include "s_sound.h"
25 #include <ctype.h>
26 #include "v_video.h"
27 #include "i_swap.h"
28 
29 // MACROS ------------------------------------------------------------------
30 
31 #define	TEXTSPEED	3
32 #define	TEXTWAIT	250
33 
34 // TYPES -------------------------------------------------------------------
35 
36 // EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
37 
38 // PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
39 
40 // PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
41 
42 static void TextWrite(void);
43 static void DrawPic(void);
44 static void InitializeFade(boolean fadeIn);
45 static void DeInitializeFade(void);
46 static void FadePic(void);
47 static char *GetFinaleText(int sequence);
48 
49 // EXTERNAL DATA DECLARATIONS ----------------------------------------------
50 
51 extern boolean automapactive;
52 extern boolean viewactive;
53 
54 // PUBLIC DATA DECLARATIONS ------------------------------------------------
55 
56 // PRIVATE DATA DEFINITIONS ------------------------------------------------
57 
58 static int FinaleStage;
59 static int FinaleCount;
60 static int FinaleEndCount;
61 static int FinaleLumpNum;
62 static int FontABaseLump;
63 static char *FinaleText;
64 
65 static fixed_t *Palette;
66 static fixed_t *PaletteDelta;
67 static byte *RealPalette;
68 
69 // CODE --------------------------------------------------------------------
70 
71 //===========================================================================
72 //
73 // F_StartFinale
74 //
75 //===========================================================================
76 
F_StartFinale(void)77 void F_StartFinale(void)
78 {
79     gameaction = ga_nothing;
80     gamestate = GS_FINALE;
81     viewactive = false;
82     automapactive = false;
83     P_ClearMessage(&players[consoleplayer]);
84 
85     FinaleStage = 0;
86     FinaleCount = 0;
87     FinaleText = GetFinaleText(0);
88     FinaleEndCount = 70;
89     FinaleLumpNum = W_GetNumForName("FINALE1");
90     FontABaseLump = W_GetNumForName("FONTA_S") + 1;
91     InitializeFade(1);
92 
93 //      S_ChangeMusic(mus_victor, true);
94     S_StartSongName("hall", false);     // don't loop the song
95 }
96 
97 //===========================================================================
98 //
99 // F_Responder
100 //
101 //===========================================================================
102 
F_Responder(event_t * event)103 boolean F_Responder(event_t * event)
104 {
105     return false;
106 }
107 
108 //===========================================================================
109 //
110 // F_Ticker
111 //
112 //===========================================================================
113 
F_Ticker(void)114 void F_Ticker(void)
115 {
116     FinaleCount++;
117     if (FinaleStage < 5 && FinaleCount >= FinaleEndCount)
118     {
119         FinaleCount = 0;
120         FinaleStage++;
121         switch (FinaleStage)
122         {
123             case 1:            // Text 1
124                 FinaleEndCount = strlen(FinaleText) * TEXTSPEED + TEXTWAIT;
125                 break;
126             case 2:            // Pic 2, Text 2
127                 FinaleText = GetFinaleText(1);
128                 FinaleEndCount = strlen(FinaleText) * TEXTSPEED + TEXTWAIT;
129                 FinaleLumpNum = W_GetNumForName("FINALE2");
130                 S_StartSongName("orb", false);
131                 break;
132             case 3:            // Pic 2 -- Fade out
133                 FinaleEndCount = 70;
134                 DeInitializeFade();
135                 InitializeFade(0);
136                 break;
137             case 4:            // Pic 3 -- Fade in
138                 FinaleLumpNum = W_GetNumForName("FINALE3");
139                 FinaleEndCount = 71;
140                 DeInitializeFade();
141                 InitializeFade(1);
142                 S_StartSongName("chess", true);
143                 break;
144             case 5:            // Pic 3 , Text 3
145                 FinaleText = GetFinaleText(2);
146                 DeInitializeFade();
147                 break;
148             default:
149                 break;
150         }
151         return;
152     }
153     if (FinaleStage == 0 || FinaleStage == 3 || FinaleStage == 4)
154     {
155         FadePic();
156     }
157 }
158 
159 //===========================================================================
160 //
161 // TextWrite
162 //
163 //===========================================================================
164 
TextWrite(void)165 static void TextWrite(void)
166 {
167     int count;
168     char *ch;
169     int c;
170     int cx, cy;
171     patch_t *w;
172 
173     memcpy(I_VideoBuffer, W_CacheLumpNum(FinaleLumpNum, PU_CACHE),
174            SCREENWIDTH * SCREENHEIGHT);
175     if (FinaleStage == 5)
176     {                           // Chess pic, draw the correct character graphic
177         if (netgame)
178         {
179             V_DrawPatch(20, 0, W_CacheLumpName("chessall", PU_CACHE));
180         }
181         else if (PlayerClass[consoleplayer])
182         {
183             V_DrawPatch(60, 0, W_CacheLumpNum(W_GetNumForName("chessc")
184                                               + PlayerClass[consoleplayer] -
185                                               1, PU_CACHE));
186         }
187     }
188     // Draw the actual text
189     if (FinaleStage == 5)
190     {
191         cy = 135;
192     }
193     else
194     {
195         cy = 5;
196     }
197     cx = 20;
198     ch = FinaleText;
199     count = (FinaleCount - 10) / TEXTSPEED;
200     if (count < 0)
201     {
202         count = 0;
203     }
204     for (; count; count--)
205     {
206         c = *ch++;
207         if (!c)
208         {
209             break;
210         }
211         if (c == '\n')
212         {
213             cx = 20;
214             cy += 9;
215             continue;
216         }
217         if (c < 32)
218         {
219             continue;
220         }
221         c = toupper(c);
222         if (c == 32)
223         {
224             cx += 5;
225             continue;
226         }
227         w = W_CacheLumpNum(FontABaseLump + c - 33, PU_CACHE);
228         if (cx + SHORT(w->width) > SCREENWIDTH)
229         {
230             break;
231         }
232         V_DrawPatch(cx, cy, w);
233         cx += SHORT(w->width);
234     }
235 }
236 
237 //===========================================================================
238 //
239 // InitializeFade
240 //
241 //===========================================================================
242 
InitializeFade(boolean fadeIn)243 static void InitializeFade(boolean fadeIn)
244 {
245     unsigned i;
246 
247     Palette = Z_Malloc(768 * sizeof(fixed_t), PU_STATIC, 0);
248     PaletteDelta = Z_Malloc(768 * sizeof(fixed_t), PU_STATIC, 0);
249     RealPalette = Z_Malloc(768 * sizeof(byte), PU_STATIC, 0);
250 
251     if (fadeIn)
252     {
253         memset(RealPalette, 0, 768 * sizeof(byte));
254         for (i = 0; i < 768; i++)
255         {
256             Palette[i] = 0;
257             PaletteDelta[i] = FixedDiv((*((byte *) W_CacheLumpName("playpal",
258                                                                    PU_CACHE) +
259                                           i)) << FRACBITS, 70 * FRACUNIT);
260         }
261     }
262     else
263     {
264         for (i = 0; i < 768; i++)
265         {
266             RealPalette[i] =
267                 *((byte *) W_CacheLumpName("playpal", PU_CACHE) + i);
268             Palette[i] = RealPalette[i] << FRACBITS;
269             PaletteDelta[i] = FixedDiv(Palette[i], -70 * FRACUNIT);
270         }
271     }
272     I_SetPalette(RealPalette);
273 }
274 
275 //===========================================================================
276 //
277 // DeInitializeFade
278 //
279 //===========================================================================
280 
DeInitializeFade(void)281 static void DeInitializeFade(void)
282 {
283     Z_Free(Palette);
284     Z_Free(PaletteDelta);
285     Z_Free(RealPalette);
286 }
287 
288 //===========================================================================
289 //
290 // FadePic
291 //
292 //===========================================================================
293 
FadePic(void)294 static void FadePic(void)
295 {
296     unsigned i;
297 
298     for (i = 0; i < 768; i++)
299     {
300         Palette[i] += PaletteDelta[i];
301         RealPalette[i] = Palette[i] >> FRACBITS;
302     }
303     I_SetPalette(RealPalette);
304 }
305 
306 //===========================================================================
307 //
308 // DrawPic
309 //
310 //===========================================================================
311 
DrawPic(void)312 static void DrawPic(void)
313 {
314     memcpy(I_VideoBuffer, W_CacheLumpNum(FinaleLumpNum, PU_CACHE),
315            SCREENWIDTH * SCREENHEIGHT);
316     if (FinaleStage == 4 || FinaleStage == 5)
317     {                           // Chess pic, draw the correct character graphic
318         if (netgame)
319         {
320             V_DrawPatch(20, 0, W_CacheLumpName("chessall", PU_CACHE));
321         }
322         else if (PlayerClass[consoleplayer])
323         {
324             V_DrawPatch(60, 0, W_CacheLumpNum(W_GetNumForName("chessc")
325                                               + PlayerClass[consoleplayer] -
326                                               1, PU_CACHE));
327         }
328     }
329 }
330 
331 //===========================================================================
332 //
333 // F_Drawer
334 //
335 //===========================================================================
336 
F_Drawer(void)337 void F_Drawer(void)
338 {
339     switch (FinaleStage)
340     {
341         case 0:                // Fade in initial finale screen
342             DrawPic();
343             break;
344         case 1:
345         case 2:
346             TextWrite();
347             break;
348         case 3:                // Fade screen out
349             DrawPic();
350             break;
351         case 4:                // Fade in chess screen
352             DrawPic();
353             break;
354         case 5:
355             TextWrite();
356             break;
357     }
358     UpdateState |= I_FULLSCRN;
359 }
360 
361 //==========================================================================
362 //
363 // GetFinaleText
364 //
365 //==========================================================================
366 
GetFinaleText(int sequence)367 static char *GetFinaleText(int sequence)
368 {
369     char *msgLumpName;
370     int msgSize;
371     int msgLump;
372     static char *winMsgLumpNames[] = {
373         "win1msg",
374         "win2msg",
375         "win3msg"
376     };
377 
378     msgLumpName = winMsgLumpNames[sequence];
379     msgLump = W_GetNumForName(msgLumpName);
380     msgSize = W_LumpLength(msgLump);
381     if (msgSize >= MAX_INTRMSN_MESSAGE_SIZE)
382     {
383         I_Error("Finale message too long (%s)", msgLumpName);
384     }
385     W_ReadLump(msgLump, ClusterMessage);
386     ClusterMessage[msgSize] = 0;        // Append terminator
387     return ClusterMessage;
388 }
389