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