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 // F_finale.c
17 
18 #include <ctype.h>
19 
20 #include "doomdef.h"
21 #include "deh_str.h"
22 #include "i_swap.h"
23 #include "i_video.h"
24 #include "s_sound.h"
25 #include "v_video.h"
26 
27 static int finalestage;                // 0 = text, 1 = art screen
28 static int finalecount;
29 
30 #define TEXTSPEED       3
31 #define TEXTWAIT        250
32 
33 static const char *finaletext;
34 static const char *finaleflat;
35 
36 static int FontABaseLump;
37 
38 extern boolean automapactive;
39 extern boolean viewactive;
40 
41 extern void D_StartTitle(void);
42 
43 /*
44 =======================
45 =
46 = F_StartFinale
47 =
48 =======================
49 */
50 
F_StartFinale(void)51 void F_StartFinale(void)
52 {
53     gameaction = ga_nothing;
54     gamestate = GS_FINALE;
55     viewactive = false;
56     automapactive = false;
57     players[consoleplayer].messageTics = 1;
58     players[consoleplayer].message = NULL;
59     players[consoleplayer].centerMessage = NULL;
60 
61     switch (gameepisode)
62     {
63         case 1:
64             finaleflat = DEH_String("FLOOR25");
65             finaletext = DEH_String(E1TEXT);
66             break;
67         case 2:
68             finaleflat = DEH_String("FLATHUH1");
69             finaletext = DEH_String(E2TEXT);
70             break;
71         case 3:
72             finaleflat = DEH_String("FLTWAWA2");
73             finaletext = DEH_String(E3TEXT);
74             break;
75         case 4:
76             finaleflat = DEH_String("FLOOR28");
77             finaletext = DEH_String(E4TEXT);
78             break;
79         case 5:
80             finaleflat = DEH_String("FLOOR08");
81             finaletext = DEH_String(E5TEXT);
82             break;
83     }
84 
85     finalestage = 0;
86     finalecount = 0;
87     FontABaseLump = W_GetNumForName(DEH_String("FONTA_S")) + 1;
88 
89 //      S_ChangeMusic(mus_victor, true);
90     S_StartSong(mus_cptd, true);
91 }
92 
93 
94 
F_Responder(event_t * event)95 boolean F_Responder(event_t * event)
96 {
97     if (event->type != ev_keydown)
98     {
99         return false;
100     }
101     if (finalestage == 1 && gameepisode == 2)
102     {                           // we're showing the water pic, make any key kick to demo mode
103         finalestage++;
104         /*
105         memset((byte *) 0xa0000, 0, SCREENWIDTH * SCREENHEIGHT);
106         memset(I_VideoBuffer, 0, SCREENWIDTH * SCREENHEIGHT);
107         I_SetPalette(W_CacheLumpName("PLAYPAL", PU_CACHE));
108         */
109         return true;
110     }
111     return false;
112 }
113 
114 
115 /*
116 =======================
117 =
118 = F_Ticker
119 =
120 =======================
121 */
122 
F_Ticker(void)123 void F_Ticker(void)
124 {
125     finalecount++;
126     if (!finalestage
127         && finalecount > strlen(finaletext) * TEXTSPEED + TEXTWAIT)
128     {
129         finalecount = 0;
130         if (!finalestage)
131         {
132             finalestage = 1;
133         }
134 
135 //              wipegamestate = -1;             // force a wipe
136 /*
137 		if (gameepisode == 3)
138 			S_StartMusic (mus_bunny);
139 */
140     }
141 }
142 
143 
144 /*
145 =======================
146 =
147 = F_TextWrite
148 =
149 =======================
150 */
151 
152 //#include "hu_stuff.h"
153 //extern        patch_t *hu_font[HU_FONTSIZE];
154 
F_TextWrite(void)155 void F_TextWrite(void)
156 {
157     byte *src, *dest;
158     int x, y;
159     int count;
160     const char *ch;
161     int c;
162     int cx, cy;
163     patch_t *w;
164 
165 //
166 // erase the entire screen to a tiled background
167 //
168     src = W_CacheLumpName(finaleflat, PU_CACHE);
169     dest = I_VideoBuffer;
170     for (y = 0; y < SCREENHEIGHT; y++)
171     {
172         for (x = 0; x < SCREENWIDTH / 64; x++)
173         {
174             memcpy(dest, src + ((y & 63) << 6), 64);
175             dest += 64;
176         }
177         if (SCREENWIDTH & 63)
178         {
179             memcpy(dest, src + ((y & 63) << 6), SCREENWIDTH & 63);
180             dest += (SCREENWIDTH & 63);
181         }
182     }
183 
184 //      V_MarkRect (0, 0, SCREENWIDTH, SCREENHEIGHT);
185 
186 //
187 // draw some of the text onto the screen
188 //
189     cx = 20;
190     cy = 5;
191     ch = finaletext;
192 
193     count = (finalecount - 10) / TEXTSPEED;
194     if (count < 0)
195         count = 0;
196     for (; count; count--)
197     {
198         c = *ch++;
199         if (!c)
200             break;
201         if (c == '\n')
202         {
203             cx = 20;
204             cy += 9;
205             continue;
206         }
207 
208         c = toupper(c);
209         if (c < 33)
210         {
211             cx += 5;
212             continue;
213         }
214 
215         w = W_CacheLumpNum(FontABaseLump + c - 33, PU_CACHE);
216         if (cx + SHORT(w->width) > SCREENWIDTH)
217             break;
218         V_DrawPatch(cx, cy, w);
219         cx += SHORT(w->width);
220     }
221 
222 }
223 
224 
F_DrawPatchCol(int x,patch_t * patch,int col)225 void F_DrawPatchCol(int x, patch_t * patch, int col)
226 {
227     column_t *column;
228     byte *source, *dest, *desttop;
229     int count;
230 
231     column = (column_t *) ((byte *) patch + LONG(patch->columnofs[col]));
232     desttop = I_VideoBuffer + x;
233 
234 // step through the posts in a column
235 
236     while (column->topdelta != 0xff)
237     {
238         source = (byte *) column + 3;
239         dest = desttop + column->topdelta * SCREENWIDTH;
240         count = column->length;
241 
242         while (count--)
243         {
244             *dest = *source++;
245             dest += SCREENWIDTH;
246         }
247         column = (column_t *) ((byte *) column + column->length + 4);
248     }
249 }
250 
251 /*
252 ==================
253 =
254 = F_DemonScroll
255 =
256 ==================
257 */
258 
F_DemonScroll(void)259 void F_DemonScroll(void)
260 {
261     byte *p1, *p2;
262     static int yval = 0;
263     static int nextscroll = 0;
264 
265     if (finalecount < nextscroll)
266     {
267         return;
268     }
269     p1 = W_CacheLumpName(DEH_String("FINAL1"), PU_LEVEL);
270     p2 = W_CacheLumpName(DEH_String("FINAL2"), PU_LEVEL);
271     if (finalecount < 70)
272     {
273         V_CopyScaledBuffer(I_VideoBuffer, p1, ORIGHEIGHT * ORIGWIDTH);
274         nextscroll = finalecount;
275         return;
276     }
277     if (yval < 64000)
278     {
279         V_CopyScaledBuffer(I_VideoBuffer, p2 + ORIGHEIGHT * ORIGWIDTH - yval, yval);
280         V_CopyScaledBuffer(I_VideoBuffer + (yval << (2 * crispy->hires)), p1, ORIGHEIGHT * ORIGWIDTH - yval);
281         yval += ORIGWIDTH;
282         nextscroll = finalecount + 3;
283     }
284     else
285     {                           //else, we'll just sit here and wait, for now
286         V_CopyScaledBuffer(I_VideoBuffer, p2, ORIGWIDTH * ORIGHEIGHT);
287     }
288 }
289 
290 /*
291 ==================
292 =
293 = F_DrawUnderwater
294 =
295 ==================
296 */
297 
F_DrawUnderwater(void)298 void F_DrawUnderwater(void)
299 {
300     static boolean underwawa = false;
301     extern boolean askforquit;
302     const char *lumpname;
303     byte *palette;
304 
305     // The underwater screen has its own palette, which is rather annoying.
306     // The palette doesn't correspond to the normal palette. Because of
307     // this, we must regenerate the lookup tables used in the video scaling
308     // code.
309 
310     switch (finalestage)
311     {
312         case 1:
313             if (!underwawa)
314             {
315                 underwawa = true;
316                 V_DrawFilledBox(0, 0, SCREENWIDTH, SCREENHEIGHT, 0);
317                 lumpname = DEH_String("E2PAL");
318                 palette = W_CacheLumpName(lumpname, PU_STATIC);
319                 I_SetPalette(palette);
320                 W_ReleaseLumpName(lumpname);
321                 V_DrawRawScreen(W_CacheLumpName(DEH_String("E2END"), PU_CACHE));
322             }
323             paused = false;
324             MenuActive = false;
325             askforquit = false;
326 
327             break;
328         case 2:
329             if (underwawa)
330             {
331                 lumpname = DEH_String("PLAYPAL");
332                 palette = W_CacheLumpName(lumpname, PU_STATIC);
333                 I_SetPalette(palette);
334                 W_ReleaseLumpName(lumpname);
335                 underwawa = false;
336             }
337             V_DrawRawScreen(W_CacheLumpName(DEH_String("TITLE"), PU_CACHE));
338             //D_StartTitle(); // go to intro/demo mode.
339     }
340 }
341 
342 
343 #if 0
344 /*
345 ==================
346 =
347 = F_BunnyScroll
348 =
349 ==================
350 */
351 
352 void F_BunnyScroll(void)
353 {
354     int scrolled, x;
355     patch_t *p1, *p2;
356     char name[10];
357     int stage;
358     static int laststage;
359 
360     p1 = W_CacheLumpName("PFUB2", PU_LEVEL);
361     p2 = W_CacheLumpName("PFUB1", PU_LEVEL);
362 
363     V_MarkRect(0, 0, SCREENWIDTH, SCREENHEIGHT);
364 
365     scrolled = 320 - (finalecount - 230) / 2;
366     if (scrolled > 320)
367         scrolled = 320;
368     if (scrolled < 0)
369         scrolled = 0;
370 
371     for (x = 0; x < SCREENWIDTH; x++)
372     {
373         if (x + scrolled < 320)
374             F_DrawPatchCol(x, p1, x + scrolled);
375         else
376             F_DrawPatchCol(x, p2, x + scrolled - 320);
377     }
378 
379     if (finalecount < 1130)
380         return;
381     if (finalecount < 1180)
382     {
383         V_DrawPatch((SCREENWIDTH - 13 * 8) / 2, (SCREENHEIGHT - 8 * 8) / 2, 0,
384                     W_CacheLumpName("END0", PU_CACHE));
385         laststage = 0;
386         return;
387     }
388 
389     stage = (finalecount - 1180) / 5;
390     if (stage > 6)
391         stage = 6;
392     if (stage > laststage)
393     {
394         S_StartSound(NULL, sfx_pistol);
395         laststage = stage;
396     }
397 
398     M_snprintf(name, sizeof(name), "END%i", stage);
399     V_DrawPatch((SCREENWIDTH - 13 * 8) / 2, (SCREENHEIGHT - 8 * 8) / 2,
400                 W_CacheLumpName(name, PU_CACHE));
401 }
402 #endif
403 
404 /*
405 =======================
406 =
407 = F_Drawer
408 =
409 =======================
410 */
411 
F_Drawer(void)412 void F_Drawer(void)
413 {
414     UpdateState |= I_FULLSCRN;
415     if (!finalestage)
416         F_TextWrite();
417     else
418     {
419         switch (gameepisode)
420         {
421             case 1:
422                 if (gamemode == shareware)
423                 {
424                     V_DrawRawScreen(W_CacheLumpName("ORDER", PU_CACHE));
425                 }
426                 else
427                 {
428                     V_DrawRawScreen(W_CacheLumpName("CREDIT", PU_CACHE));
429                 }
430                 break;
431             case 2:
432                 F_DrawUnderwater();
433                 break;
434             case 3:
435                 F_DemonScroll();
436                 break;
437             case 4:            // Just show credits screen for extended episodes
438             case 5:
439                 V_DrawRawScreen(W_CacheLumpName("CREDIT", PU_CACHE));
440                 break;
441         }
442     }
443 }
444