]> git.lizzy.rs Git - plan9front.git/blob - sys/src/games/doom/f_finale.c
bring games/swar from 1ed sources.
[plan9front.git] / sys / src / games / doom / f_finale.c
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 //      Game completion, final screen animation.
21 //
22 //-----------------------------------------------------------------------------
23
24
25 static const char
26 rcsid[] = "$Id: f_finale.c,v 1.5 1997/02/03 21:26:34 b1 Exp $";
27
28 #include "doomdef.h"
29
30 // Functions.
31 #include "i_system.h"
32 #include "m_swap.h"
33 #include "z_zone.h"
34 #include "v_video.h"
35 #include "w_wad.h"
36 #include "s_sound.h"
37
38 // Data.
39 #include "dstrings.h"
40 #include "sounds.h"
41
42 #include "doomstat.h"
43 #include "r_state.h"
44
45 // ?
46 //#include "doomstat.h"
47 //#include "r_local.h"
48 //#include "f_finale.h"
49
50 // Stage of animation:
51 //  0 = text, 1 = art screen, 2 = character cast
52 int             finalestage;
53
54 int             finalecount;
55
56 #define TEXTSPEED       3
57 #define TEXTWAIT        250
58
59 char*   e1text = E1TEXT;
60 char*   e2text = E2TEXT;
61 char*   e3text = E3TEXT;
62 char*   e4text = E4TEXT;
63
64 char*   c1text = C1TEXT;
65 char*   c2text = C2TEXT;
66 char*   c3text = C3TEXT;
67 char*   c4text = C4TEXT;
68 char*   c5text = C5TEXT;
69 char*   c6text = C6TEXT;
70
71 char*   p1text = P1TEXT;
72 char*   p2text = P2TEXT;
73 char*   p3text = P3TEXT;
74 char*   p4text = P4TEXT;
75 char*   p5text = P5TEXT;
76 char*   p6text = P6TEXT;
77
78 char*   t1text = T1TEXT;
79 char*   t2text = T2TEXT;
80 char*   t3text = T3TEXT;
81 char*   t4text = T4TEXT;
82 char*   t5text = T5TEXT;
83 char*   t6text = T6TEXT;
84
85 char*   finaletext;
86 char*   finaleflat;
87
88 void    F_StartCast (void);
89 void    F_CastTicker (void);
90 boolean F_CastResponder (event_t *ev);
91 void    F_CastDrawer (void);
92
93 //
94 // F_StartFinale
95 //
96 void F_StartFinale (void)
97 {
98     gameaction = ga_nothing;
99     gamestate = GS_FINALE;
100     viewactive = false;
101     automapactive = false;
102
103     // Okay - IWAD dependend stuff.
104     // This has been changed severly, and
105     //  some stuff might have changed in the process.
106     switch ( gamemode )
107     {
108
109       // DOOM 1 - E1, E3 or E4, but each nine missions
110       case shareware:
111       case registered:
112       case retail:
113       {
114         S_ChangeMusic(mus_victor, true);
115         
116         switch (gameepisode)
117         {
118           case 1:
119             finaleflat = "FLOOR4_8";
120             finaletext = e1text;
121             break;
122           case 2:
123             finaleflat = "SFLR6_1";
124             finaletext = e2text;
125             break;
126           case 3:
127             finaleflat = "MFLR8_4";
128             finaletext = e3text;
129             break;
130           case 4:
131             finaleflat = "MFLR8_3";
132             finaletext = e4text;
133             break;
134           default:
135             // Ouch.
136             break;
137         }
138         break;
139       }
140       
141       // DOOM II and missions packs with E1, M34
142       case commercial:
143       {
144           S_ChangeMusic(mus_read_m, true);
145
146           switch (gamemap)
147           {
148             case 6:
149               finaleflat = "SLIME16";
150               finaletext = c1text;
151               break;
152             case 11:
153               finaleflat = "RROCK14";
154               finaletext = c2text;
155               break;
156             case 20:
157               finaleflat = "RROCK07";
158               finaletext = c3text;
159               break;
160             case 30:
161               finaleflat = "RROCK17";
162               finaletext = c4text;
163               break;
164             case 15:
165               finaleflat = "RROCK13";
166               finaletext = c5text;
167               break;
168             case 31:
169               finaleflat = "RROCK19";
170               finaletext = c6text;
171               break;
172             default:
173               // Ouch.
174               break;
175           }
176           break;
177       } 
178
179    
180       // Indeterminate.
181       default:
182         S_ChangeMusic(mus_read_m, true);
183         finaleflat = "F_SKY1"; // Not used anywhere else.
184         finaletext = c1text;  // FIXME - other text, music?
185         break;
186     }
187     
188     finalestage = 0;
189     finalecount = 0;
190         
191 }
192
193
194
195 boolean F_Responder (event_t *event)
196 {
197     if (finalestage == 2)
198         return F_CastResponder (event);
199         
200     return false;
201 }
202
203
204 //
205 // F_Ticker
206 //
207 void F_Ticker (void)
208 {
209     int         i;
210     
211     // check for skipping
212     if ( (gamemode == commercial)
213       && ( finalecount > 50) )
214     {
215       // go on to the next level
216       for (i=0 ; i<MAXPLAYERS ; i++)
217         if (players[i].cmd.buttons)
218           break;
219                                 
220       if (i < MAXPLAYERS)
221       { 
222         if (gamemap == 30)
223           F_StartCast ();
224         else
225           gameaction = ga_worlddone;
226       }
227     }
228     
229     // advance animation
230     finalecount++;
231         
232     if (finalestage == 2)
233     {
234         F_CastTicker ();
235         return;
236     }
237         
238     if ( gamemode == commercial)
239         return;
240                 
241     if (!finalestage && finalecount>strlen (finaletext)*TEXTSPEED + TEXTWAIT)
242     {
243         finalecount = 0;
244         finalestage = 1;
245         wipegamestate = -1;             // force a wipe
246         if (gameepisode == 3)
247             S_StartMusic (mus_bunny);
248     }
249 }
250
251
252
253 //
254 // F_TextWrite
255 //
256
257 #include "hu_stuff.h"
258 extern  patch_t *hu_font[HU_FONTSIZE];
259
260
261 void F_TextWrite (void)
262 {
263     byte*       src;
264     byte*       dest;
265     
266     int         x,y,w;
267     int         count;
268     char*       ch;
269     int         c;
270     int         cx;
271     int         cy;
272     
273     // erase the entire screen to a tiled background
274     src = W_CacheLumpName ( finaleflat , PU_CACHE);
275     dest = screens[0];
276         
277     for (y=0 ; y<SCREENHEIGHT ; y++)
278     {
279         for (x=0 ; x<SCREENWIDTH/64 ; x++)
280         {
281             memcpy (dest, src+((y&63)<<6), 64);
282             dest += 64;
283         }
284         if (SCREENWIDTH&63)
285         {
286             memcpy (dest, src+((y&63)<<6), SCREENWIDTH&63);
287             dest += (SCREENWIDTH&63);
288         }
289     }
290
291     V_MarkRect (0, 0, SCREENWIDTH, SCREENHEIGHT);
292     
293     // draw some of the text onto the screen
294     cx = 10;
295     cy = 10;
296     ch = finaletext;
297         
298     count = (finalecount - 10)/TEXTSPEED;
299     if (count < 0)
300         count = 0;
301     for ( ; count ; count-- )
302     {
303         c = *ch++;
304         if (!c)
305             break;
306         if (c == '\n')
307         {
308             cx = 10;
309             cy += 11;
310             continue;
311         }
312                 
313         c = toupper(c) - HU_FONTSTART;
314         if (c < 0 || c> HU_FONTSIZE)
315         {
316             cx += 4;
317             continue;
318         }
319                 
320         w = SHORT (hu_font[c]->width);
321         if (cx+w > SCREENWIDTH)
322             break;
323         V_DrawPatch(cx, cy, 0, hu_font[c]);
324         cx+=w;
325     }
326         
327 }
328
329 //
330 // Final DOOM 2 animation
331 // Casting by id Software.
332 //   in order of appearance
333 //
334 typedef struct
335 {
336     char                *name;
337     mobjtype_t  type;
338 } castinfo_t;
339
340 castinfo_t      castorder[] = {
341     {CC_ZOMBIE, MT_POSSESSED},
342     {CC_SHOTGUN, MT_SHOTGUY},
343     {CC_HEAVY, MT_CHAINGUY},
344     {CC_IMP, MT_TROOP},
345     {CC_DEMON, MT_SERGEANT},
346     {CC_LOST, MT_SKULL},
347     {CC_CACO, MT_HEAD},
348     {CC_HELL, MT_KNIGHT},
349     {CC_BARON, MT_BRUISER},
350     {CC_ARACH, MT_BABY},
351     {CC_PAIN, MT_PAIN},
352     {CC_REVEN, MT_UNDEAD},
353     {CC_MANCU, MT_FATSO},
354     {CC_ARCH, MT_VILE},
355     {CC_SPIDER, MT_SPIDER},
356     {CC_CYBER, MT_CYBORG},
357     {CC_HERO, MT_PLAYER},
358
359     {NULL,0}
360 };
361
362 int             castnum;
363 int             casttics;
364 state_t*        caststate;
365 boolean         castdeath;
366 int             castframes;
367 int             castonmelee;
368 boolean         castattacking;
369
370
371 //
372 // F_StartCast
373 //
374 extern  gamestate_t     wipegamestate;
375
376
377 void F_StartCast (void)
378 {
379     wipegamestate = -1;         // force a screen wipe
380     castnum = 0;
381     caststate = &states[mobjinfo[castorder[castnum].type].seestate];
382     casttics = caststate->tics;
383     castdeath = false;
384     finalestage = 2;    
385     castframes = 0;
386     castonmelee = 0;
387     castattacking = false;
388     S_ChangeMusic(mus_evil, true);
389 }
390
391
392 //
393 // F_CastTicker
394 //
395 void F_CastTicker (void)
396 {
397     int         st;
398     int         sfx;
399         
400     if (--casttics > 0)
401         return;                 // not time to change state yet
402                 
403     if (caststate->tics == -1 || caststate->nextstate == S_NULL)
404     {
405         // switch from deathstate to next monster
406         castnum++;
407         castdeath = false;
408         if (castorder[castnum].name == NULL)
409             castnum = 0;
410         if (mobjinfo[castorder[castnum].type].seesound)
411             S_StartSound (NULL, mobjinfo[castorder[castnum].type].seesound);
412         caststate = &states[mobjinfo[castorder[castnum].type].seestate];
413         castframes = 0;
414     }
415     else
416     {
417         // just advance to next state in animation
418         if (caststate == &states[S_PLAY_ATK1])
419             goto stopattack;    // Oh, gross hack!
420         st = caststate->nextstate;
421         caststate = &states[st];
422         castframes++;
423         
424         // sound hacks....
425         switch (st)
426         {
427           case S_PLAY_ATK1:     sfx = sfx_dshtgn; break;
428           case S_POSS_ATK2:     sfx = sfx_pistol; break;
429           case S_SPOS_ATK2:     sfx = sfx_shotgn; break;
430           case S_VILE_ATK2:     sfx = sfx_vilatk; break;
431           case S_SKEL_FIST2:    sfx = sfx_skeswg; break;
432           case S_SKEL_FIST4:    sfx = sfx_skepch; break;
433           case S_SKEL_MISS2:    sfx = sfx_skeatk; break;
434           case S_FATT_ATK8:
435           case S_FATT_ATK5:
436           case S_FATT_ATK2:     sfx = sfx_firsht; break;
437           case S_CPOS_ATK2:
438           case S_CPOS_ATK3:
439           case S_CPOS_ATK4:     sfx = sfx_shotgn; break;
440           case S_TROO_ATK3:     sfx = sfx_claw; break;
441           case S_SARG_ATK2:     sfx = sfx_sgtatk; break;
442           case S_BOSS_ATK2:
443           case S_BOS2_ATK2:
444           case S_HEAD_ATK2:     sfx = sfx_firsht; break;
445           case S_SKULL_ATK2:    sfx = sfx_sklatk; break;
446           case S_SPID_ATK2:
447           case S_SPID_ATK3:     sfx = sfx_shotgn; break;
448           case S_BSPI_ATK2:     sfx = sfx_plasma; break;
449           case S_CYBER_ATK2:
450           case S_CYBER_ATK4:
451           case S_CYBER_ATK6:    sfx = sfx_rlaunc; break;
452           case S_PAIN_ATK3:     sfx = sfx_sklatk; break;
453           default: sfx = 0; break;
454         }
455                 
456         if (sfx)
457             S_StartSound (NULL, sfx);
458     }
459         
460     if (castframes == 12)
461     {
462         // go into attack frame
463         castattacking = true;
464         if (castonmelee)
465             caststate=&states[mobjinfo[castorder[castnum].type].meleestate];
466         else
467             caststate=&states[mobjinfo[castorder[castnum].type].missilestate];
468         castonmelee ^= 1;
469         if (caststate == &states[S_NULL])
470         {
471             if (castonmelee)
472                 caststate=
473                     &states[mobjinfo[castorder[castnum].type].meleestate];
474             else
475                 caststate=
476                     &states[mobjinfo[castorder[castnum].type].missilestate];
477         }
478     }
479         
480     if (castattacking)
481     {
482         if (castframes == 24
483             ||  caststate == &states[mobjinfo[castorder[castnum].type].seestate] )
484         {
485           stopattack:
486             castattacking = false;
487             castframes = 0;
488             caststate = &states[mobjinfo[castorder[castnum].type].seestate];
489         }
490     }
491         
492     casttics = caststate->tics;
493     if (casttics == -1)
494         casttics = 15;
495 }
496
497
498 //
499 // F_CastResponder
500 //
501
502 boolean F_CastResponder (event_t* ev)
503 {
504     if (ev->type != ev_keydown)
505         return false;
506                 
507     if (castdeath)
508         return true;                    // already in dying frames
509                 
510     // go into death frame
511     castdeath = true;
512     caststate = &states[mobjinfo[castorder[castnum].type].deathstate];
513     casttics = caststate->tics;
514     castframes = 0;
515     castattacking = false;
516     if (mobjinfo[castorder[castnum].type].deathsound)
517         S_StartSound (NULL, mobjinfo[castorder[castnum].type].deathsound);
518         
519     return true;
520 }
521
522
523 void F_CastPrint (char* text)
524 {
525     char*       ch;
526     int         c;
527     int         cx;
528     int         w;
529     int         width;
530     
531     // find width
532     ch = text;
533     width = 0;
534         
535     while (ch)
536     {
537         c = *ch++;
538         if (!c)
539             break;
540         c = toupper(c) - HU_FONTSTART;
541         if (c < 0 || c> HU_FONTSIZE)
542         {
543             width += 4;
544             continue;
545         }
546                 
547         w = SHORT (hu_font[c]->width);
548         width += w;
549     }
550     
551     // draw it
552     cx = 160-width/2;
553     ch = text;
554     while (ch)
555     {
556         c = *ch++;
557         if (!c)
558             break;
559         c = toupper(c) - HU_FONTSTART;
560         if (c < 0 || c> HU_FONTSIZE)
561         {
562             cx += 4;
563             continue;
564         }
565                 
566         w = SHORT (hu_font[c]->width);
567         V_DrawPatch(cx, 180, 0, hu_font[c]);
568         cx+=w;
569     }
570         
571 }
572
573
574 //
575 // F_CastDrawer
576 //
577 void V_DrawPatchFlipped (int x, int y, int scrn, patch_t *patch);
578
579 void F_CastDrawer (void)
580 {
581     spritedef_t*        sprdef;
582     spriteframe_t*      sprframe;
583     int                 lump;
584     boolean             flip;
585     patch_t*            patch;
586     
587     // erase the entire screen to a background
588     V_DrawPatch (0,0,0, W_CacheLumpName ("BOSSBACK", PU_CACHE));
589
590     F_CastPrint (castorder[castnum].name);
591     
592     // draw the current frame in the middle of the screen
593     sprdef = &sprites[caststate->sprite];
594     sprframe = &sprdef->spriteframes[ caststate->frame & FF_FRAMEMASK];
595     lump = sprframe->lump[0];
596     flip = (boolean)sprframe->flip[0];
597                         
598     patch = W_CacheLumpNum (lump+firstspritelump, PU_CACHE);
599     if (flip)
600         V_DrawPatchFlipped (160,170,0,patch);
601     else
602         V_DrawPatch (160,170,0,patch);
603 }
604
605
606 //
607 // F_DrawPatchCol
608 //
609 void
610 F_DrawPatchCol
611 ( int           x,
612   patch_t*      patch,
613   int           col )
614 {
615     column_t*   column;
616     byte*       source;
617     byte*       dest;
618     byte*       desttop;
619     int         count;
620         
621     column = (column_t *)((byte *)patch + LONG(patch->columnofs[col]));
622     desttop = screens[0]+x;
623
624     // step through the posts in a column
625     while (column->topdelta != 0xff )
626     {
627         source = (byte *)column + 3;
628         dest = desttop + column->topdelta*SCREENWIDTH;
629         count = column->length;
630                 
631         while (count--)
632         {
633             *dest = *source++;
634             dest += SCREENWIDTH;
635         }
636         column = (column_t *)(  (byte *)column + column->length + 4 );
637     }
638 }
639
640
641 //
642 // F_BunnyScroll
643 //
644 void F_BunnyScroll (void)
645 {
646     int         scrolled;
647     int         x;
648     patch_t*    p1;
649     patch_t*    p2;
650     char        name[10];
651     int         stage;
652     static int  laststage;
653                 
654     p1 = W_CacheLumpName ("PFUB2", PU_LEVEL);
655     p2 = W_CacheLumpName ("PFUB1", PU_LEVEL);
656
657     V_MarkRect (0, 0, SCREENWIDTH, SCREENHEIGHT);
658         
659     scrolled = 320 - (finalecount-230)/2;
660     if (scrolled > 320)
661         scrolled = 320;
662     if (scrolled < 0)
663         scrolled = 0;
664                 
665     for ( x=0 ; x<SCREENWIDTH ; x++)
666     {
667         if (x+scrolled < 320)
668             F_DrawPatchCol (x, p1, x+scrolled);
669         else
670             F_DrawPatchCol (x, p2, x+scrolled - 320);           
671     }
672         
673     if (finalecount < 1130)
674         return;
675     if (finalecount < 1180)
676     {
677         V_DrawPatch ((SCREENWIDTH-13*8)/2,
678                      (SCREENHEIGHT-8*8)/2,0, W_CacheLumpName ("END0",PU_CACHE));
679         laststage = 0;
680         return;
681     }
682         
683     stage = (finalecount-1180) / 5;
684     if (stage > 6)
685         stage = 6;
686     if (stage > laststage)
687     {
688         S_StartSound (NULL, sfx_pistol);
689         laststage = stage;
690     }
691         
692     sprintf (name,"END%i",stage);
693     V_DrawPatch ((SCREENWIDTH-13*8)/2, (SCREENHEIGHT-8*8)/2,0, W_CacheLumpName (name,PU_CACHE));
694 }
695
696
697 //
698 // F_Drawer
699 //
700 void F_Drawer (void)
701 {
702     if (finalestage == 2)
703     {
704         F_CastDrawer ();
705         return;
706     }
707
708     if (!finalestage)
709         F_TextWrite ();
710     else
711     {
712         switch (gameepisode)
713         {
714           case 1:
715             if ( gamemode == retail )
716               V_DrawPatch (0,0,0,
717                          W_CacheLumpName("CREDIT",PU_CACHE));
718             else
719               V_DrawPatch (0,0,0,
720                          W_CacheLumpName("HELP2",PU_CACHE));
721             break;
722           case 2:
723             V_DrawPatch(0,0,0,
724                         W_CacheLumpName("VICTORY2",PU_CACHE));
725             break;
726           case 3:
727             F_BunnyScroll ();
728             break;
729           case 4:
730             V_DrawPatch (0,0,0,
731                          W_CacheLumpName("ENDPIC",PU_CACHE));
732             break;
733         }
734     }
735                         
736 }
737
738