1 /* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
5 * PrBoom a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
28 * Game completion, final screen animation.
30 *-----------------------------------------------------------------------------
40 #include "d_deh.h" // Ty 03/22/98 - externalizations
41 #include "f_finale.h" // CPhipps - hmm...
42 #include "rockmacros.h"
44 // Stage of animation:
45 // 0 = text, 1 = art screen, 2 = character cast
46 static int finalestage
; // cph -
47 static int finalecount
; // made static
48 static const char* finaletext
; // cph -
49 static const char* finaleflat
; // made static const
51 // defines for the end mission display text // phares
53 #define TEXTSPEED 3 // original value // phares
54 #define TEXTWAIT 250 // original value // phares
55 #define NEWTEXTSPEED 0.01f // new value // phares
56 #define NEWTEXTWAIT 1000 // new value // phares
58 // CPhipps - removed the old finale screen text message strings;
59 // they were commented out for ages already
60 // Ty 03/22/98 - ... the new s_WHATEVER extern variables are used
61 // in the code below instead.
63 void F_StartCast (void);
64 void F_CastTicker (void);
65 boolean
F_CastResponder (event_t
*ev
);
66 void F_CastDrawer (void);
68 void WI_checkForAccelerate(void); // killough 3/28/98: used to
69 extern int acceleratestage
; // accelerate intermission screens
70 static int midstage
; // whether we're in "mid-stage"
75 void F_StartFinale (void)
77 gameaction
= ga_nothing
;
78 gamestate
= GS_FINALE
;
79 automapmode
&= ~am_active
;
81 // killough 3/28/98: clear accelerative text flags
82 acceleratestage
= midstage
= 0;
84 // Okay - IWAD dependend stuff.
85 // This has been changed severly, and
86 // some stuff might have changed in the process.
90 // DOOM 1 - E1, E3 or E4, but each nine missions
95 S_ChangeMusic(mus_victor
, true);
100 finaleflat
= bgflatE1
; // Ty 03/30/98 - new externalized bg flats
101 finaletext
= s_E1TEXT
; // Ty 03/23/98 - Was e1text variable.
104 finaleflat
= bgflatE2
;
105 finaletext
= s_E2TEXT
; // Ty 03/23/98 - Same stuff for each
108 finaleflat
= bgflatE3
;
109 finaletext
= s_E3TEXT
;
112 finaleflat
= bgflatE4
;
113 finaletext
= s_E4TEXT
;
122 // DOOM II and missions packs with E1, M34
125 S_ChangeMusic(mus_read_m
, true);
127 // Ty 08/27/98 - added the gamemission logic
131 finaleflat
= bgflat06
;
132 finaletext
= (gamemission
==pack_tnt
) ? s_T1TEXT
:
133 (gamemission
==pack_plut
) ? s_P1TEXT
: s_C1TEXT
;
136 finaleflat
= bgflat11
;
137 finaletext
= (gamemission
==pack_tnt
) ? s_T2TEXT
:
138 (gamemission
==pack_plut
) ? s_P2TEXT
: s_C2TEXT
;
141 finaleflat
= bgflat20
;
142 finaletext
= (gamemission
==pack_tnt
) ? s_T3TEXT
:
143 (gamemission
==pack_plut
) ? s_P3TEXT
: s_C3TEXT
;
146 finaleflat
= bgflat30
;
147 finaletext
= (gamemission
==pack_tnt
) ? s_T4TEXT
:
148 (gamemission
==pack_plut
) ? s_P4TEXT
: s_C4TEXT
;
151 finaleflat
= bgflat15
;
152 finaletext
= (gamemission
==pack_tnt
) ? s_T5TEXT
:
153 (gamemission
==pack_plut
) ? s_P5TEXT
: s_C5TEXT
;
156 finaleflat
= bgflat31
;
157 finaletext
= (gamemission
==pack_tnt
) ? s_T6TEXT
:
158 (gamemission
==pack_plut
) ? s_P6TEXT
: s_C6TEXT
;
165 // Ty 08/27/98 - end gamemission logic
169 default: // Ty 03/30/98 - not externalized
170 S_ChangeMusic(mus_read_m
, true);
171 finaleflat
= "F_SKY1"; // Not used anywhere else.
172 finaletext
= s_C1TEXT
; // FIXME - other text, music?
183 boolean
F_Responder (event_t
*event
)
185 if (finalestage
== 2)
186 return F_CastResponder (event
);
191 // Get_TextSpeed() returns the value of the text display speed // phares
192 // Rewritten to allow user-directed acceleration -- killough 3/28/98
194 static float Get_TextSpeed(void)
196 return midstage
? NEWTEXTSPEED
: (midstage
=acceleratestage
) ?
197 acceleratestage
=0, NEWTEXTSPEED
: TEXTSPEED
;
203 // killough 3/28/98: almost totally rewritten, to use
204 // player-directed acceleration instead of constant delays.
205 // Now the player can accelerate the text display by using
206 // the fire/use keys while it is being printed. The delay
207 // automatically responds to the user, and gives enough
210 // killough 5/10/98: add back v1.9 demo compatibility
216 if (!demo_compatibility
)
217 WI_checkForAccelerate(); // killough 3/28/98: check for acceleration
219 if (gamemode
== commercial
&& finalecount
> 50) // check for skipping
220 for (i
=0; i
<MAXPLAYERS
; i
++)
221 if (players
[i
].cmd
.buttons
)
222 goto next_level
; // go on to the next level
227 if (finalestage
== 2)
232 float speed
= demo_compatibility
? TEXTSPEED
: Get_TextSpeed();
233 /* killough 2/28/98: changed to allow acceleration */
234 if (finalecount
> strlen(finaletext
)*speed
+
235 (midstage
? NEWTEXTWAIT
: TEXTWAIT
) ||
236 (midstage
&& acceleratestage
)) {
237 if (gamemode
!= commercial
) // Doom 1 / Ultimate Doom episode end
238 { // with enough time, it's automatic
241 wipegamestate
= -1; // force a wipe
242 if (gameepisode
== 3)
243 S_StartMusic(mus_bunny
);
245 else // you must press a button to continue in Doom 2
246 if (!demo_compatibility
&& midstage
)
250 F_StartCast(); // cast of Doom 2 characters
252 gameaction
= ga_worlddone
; // next level, e.g. MAP07
262 // This program displays the background and text at end-mission // phares
263 // text time. It draws both repeatedly so that other displays, // |
264 // like the main menu, can be drawn over it dynamically and // V
265 // erased dynamically. The TEXTSPEED constant is changed into
266 // the Get_TextSpeed function so that the speed of writing the // ^
267 // text can be increased, and there's still time to read what's // |
268 // written. // phares
269 // CPhipps - reformatted
271 #include "hu_stuff.h"
272 extern patchnum_t hu_font
[HU_FONTSIZE
];
275 void F_TextWrite (void)
277 V_DrawBackground(finaleflat
, 0);
278 { // draw some of the text onto the screen
281 const char* ch
= finaletext
; // CPhipps - const
282 int count
= (int)((float)(finalecount
- 10)/Get_TextSpeed()); // phares
288 for ( ; count
; count
-- ) {
299 c
= toupper(c
) - HU_FONTSTART
;
300 if (c
< 0 || c
> HU_FONTSIZE
) {
305 w
= SHORT (hu_font
[c
].width
);
308 // CPhipps - patch drawing updated
309 V_DrawNumPatch(cx
, cy
, 0, hu_font
[c
].lumpnum
, CR_DEFAULT
, VPT_STRETCH
);
316 // Final DOOM 2 animation
317 // Casting by id Software.
318 // in order of appearance
322 const char **name
; // CPhipps - const**
326 #define MAX_CASTORDER 18 /* Ty - hard coded for now */
327 static const castinfo_t castorder
[] = { // CPhipps - static const, initialised here
328 { &s_CC_ZOMBIE
, MT_POSSESSED
},
329 { &s_CC_SHOTGUN
, MT_SHOTGUY
},
330 { &s_CC_HEAVY
, MT_CHAINGUY
},
331 { &s_CC_IMP
, MT_TROOP
},
332 { &s_CC_DEMON
, MT_SERGEANT
},
333 { &s_CC_LOST
, MT_SKULL
},
334 { &s_CC_CACO
, MT_HEAD
},
335 { &s_CC_HELL
, MT_KNIGHT
},
336 { &s_CC_BARON
, MT_BRUISER
},
337 { &s_CC_ARACH
, MT_BABY
},
338 { &s_CC_PAIN
, MT_PAIN
},
339 { &s_CC_REVEN
, MT_UNDEAD
},
340 { &s_CC_MANCU
, MT_FATSO
},
341 { &s_CC_ARCH
, MT_VILE
},
342 { &s_CC_SPIDER
, MT_SPIDER
},
343 { &s_CC_CYBER
, MT_CYBORG
},
344 { &s_CC_HERO
, MT_PLAYER
},
354 boolean castattacking
;
360 extern gamestate_t wipegamestate
;
362 void F_StartCast (void)
364 wipegamestate
= -1; // force a screen wipe
366 caststate
= &states
[mobjinfo
[castorder
[castnum
].type
].seestate
];
367 casttics
= caststate
->tics
;
372 castattacking
= false;
373 S_ChangeMusic(mus_evil
, true);
380 void F_CastTicker (void)
386 return; // not time to change state yet
388 if (caststate
->tics
== -1 || caststate
->nextstate
== S_NULL
)
390 // switch from deathstate to next monster
393 if (castorder
[castnum
].name
== NULL
)
395 if (mobjinfo
[castorder
[castnum
].type
].seesound
)
396 S_StartSound (NULL
, mobjinfo
[castorder
[castnum
].type
].seesound
);
397 caststate
= &states
[mobjinfo
[castorder
[castnum
].type
].seestate
];
402 // just advance to next state in animation
403 if (caststate
== &states
[S_PLAY_ATK1
])
404 goto stopattack
; // Oh, gross hack!
405 st
= caststate
->nextstate
;
406 caststate
= &states
[st
];
412 case S_PLAY_ATK1
: sfx
= sfx_dshtgn
; break;
413 case S_POSS_ATK2
: sfx
= sfx_pistol
; break;
414 case S_SPOS_ATK2
: sfx
= sfx_shotgn
; break;
415 case S_VILE_ATK2
: sfx
= sfx_vilatk
; break;
416 case S_SKEL_FIST2
: sfx
= sfx_skeswg
; break;
417 case S_SKEL_FIST4
: sfx
= sfx_skepch
; break;
418 case S_SKEL_MISS2
: sfx
= sfx_skeatk
; break;
421 case S_FATT_ATK2
: sfx
= sfx_firsht
; break;
424 case S_CPOS_ATK4
: sfx
= sfx_shotgn
; break;
425 case S_TROO_ATK3
: sfx
= sfx_claw
; break;
426 case S_SARG_ATK2
: sfx
= sfx_sgtatk
; break;
429 case S_HEAD_ATK2
: sfx
= sfx_firsht
; break;
430 case S_SKULL_ATK2
: sfx
= sfx_sklatk
; break;
432 case S_SPID_ATK3
: sfx
= sfx_shotgn
; break;
433 case S_BSPI_ATK2
: sfx
= sfx_plasma
; break;
436 case S_CYBER_ATK6
: sfx
= sfx_rlaunc
; break;
437 case S_PAIN_ATK3
: sfx
= sfx_sklatk
; break;
438 default: sfx
= 0; break;
442 S_StartSound (NULL
, sfx
);
445 if (castframes
== 12)
447 // go into attack frame
448 castattacking
= true;
450 caststate
=&states
[mobjinfo
[castorder
[castnum
].type
].meleestate
];
452 caststate
=&states
[mobjinfo
[castorder
[castnum
].type
].missilestate
];
454 if (caststate
== &states
[S_NULL
])
458 &states
[mobjinfo
[castorder
[castnum
].type
].meleestate
];
461 &states
[mobjinfo
[castorder
[castnum
].type
].missilestate
];
468 || caststate
== &states
[mobjinfo
[castorder
[castnum
].type
].seestate
] )
471 castattacking
= false;
473 caststate
= &states
[mobjinfo
[castorder
[castnum
].type
].seestate
];
477 casttics
= caststate
->tics
;
487 boolean
F_CastResponder (event_t
* ev
)
489 if (ev
->type
!= ev_keydown
)
493 return true; // already in dying frames
495 // go into death frame
497 caststate
= &states
[mobjinfo
[castorder
[castnum
].type
].deathstate
];
498 casttics
= caststate
->tics
;
500 castattacking
= false;
501 if (mobjinfo
[castorder
[castnum
].type
].deathsound
)
502 S_StartSound (NULL
, mobjinfo
[castorder
[castnum
].type
].deathsound
);
508 static void F_CastPrint (const char* text
) // CPhipps - static, const char*
510 const char* ch
; // CPhipps - const
525 c
= toupper(c
) - HU_FONTSTART
;
526 if (c
< 0 || c
> HU_FONTSIZE
)
532 w
= SHORT (hu_font
[c
].width
);
544 c
= toupper(c
) - HU_FONTSTART
;
545 if (c
< 0 || c
> HU_FONTSIZE
)
551 w
= SHORT (hu_font
[c
].width
);
552 // CPhipps - patch drawing updated
553 V_DrawNumPatch(cx
, 180, 0, hu_font
[c
].lumpnum
, CR_DEFAULT
, VPT_STRETCH
);
563 void F_CastDrawer (void)
566 spriteframe_t
* sprframe
;
570 // erase the entire screen to a background
571 // CPhipps - patch drawing updated
572 V_DrawNamePatch(0,0,0, bgcastcall
, CR_DEFAULT
, VPT_STRETCH
); // Ty 03/30/98 bg texture extern
574 F_CastPrint (*(castorder
[castnum
].name
));
576 // draw the current frame in the middle of the screen
577 sprdef
= &sprites
[caststate
->sprite
];
578 sprframe
= &sprdef
->spriteframes
[ caststate
->frame
& FF_FRAMEMASK
];
579 lump
= sprframe
->lump
[0];
580 flip
= (boolean
)sprframe
->flip
[0];
582 // CPhipps - patch drawing updated
583 V_DrawNumPatch(160, 170, 0, lump
+firstspritelump
, CR_DEFAULT
,
584 VPT_STRETCH
| (flip
? VPT_FLIP
: 0));
591 static const char pfub2
[] = { "PFUB2" };
592 static const char pfub1
[] = { "PFUB1" };
594 static void F_BunnyScroll (void)
598 static int laststage
;
600 V_MarkRect (0, 0, SCREENWIDTH
, SCREENHEIGHT
);
602 int scrolled
= 320 - (finalecount
-230)/2;
604 V_DrawNamePatch(0, 0, 0, pfub2
, CR_DEFAULT
, VPT_STRETCH
);
605 } else if (scrolled
>= 320) {
606 V_DrawNamePatch(0, 0, 0, pfub1
, CR_DEFAULT
, VPT_STRETCH
);
610 int realscrolled
= (SCREENWIDTH
* scrolled
) / 320;
613 V_DrawNamePatch(0, 0, SCRN
, pfub2
, CR_DEFAULT
, VPT_STRETCH
);
614 V_CopyRect(realscrolled
, 0, SCRN
, SCREENWIDTH
-realscrolled
, SCREENHEIGHT
, 0, 0, 0, VPT_NONE
);
615 V_DrawNamePatch(0, 0, SCRN
, pfub1
, CR_DEFAULT
, VPT_STRETCH
);
616 V_CopyRect(0, 0, SCRN
, realscrolled
, SCREENHEIGHT
, SCREENWIDTH
-realscrolled
, 0, 0, VPT_NONE
);
621 if (finalecount
< 1130)
623 if (finalecount
< 1180)
625 // CPhipps - patch drawing updated
626 V_DrawNamePatch((320-13*8)/2, (200-8*8)/2,0, "END0", CR_DEFAULT
, VPT_STRETCH
);
631 stage
= (finalecount
-1180) / 5;
634 if (stage
> laststage
)
636 S_StartSound (NULL
, sfx_pistol
);
640 snprintf (name
,sizeof(name
), "END%d",stage
);
641 // CPhipps - patch drawing updated
642 V_DrawNamePatch((320-13*8)/2, (200-8*8)/2, 0, name
, CR_DEFAULT
, VPT_STRETCH
);
651 if (finalestage
== 2)
663 // CPhipps - patch drawing updated
665 if ( gamemode
== retail
)
666 V_DrawNamePatch(0, 0, 0, "CREDIT", CR_DEFAULT
, VPT_STRETCH
);
668 V_DrawNamePatch(0, 0, 0, "HELP2", CR_DEFAULT
, VPT_STRETCH
);
671 V_DrawNamePatch(0, 0, 0, "VICTORY2", CR_DEFAULT
, VPT_STRETCH
);
677 V_DrawNamePatch(0, 0, 0, "ENDPIC", CR_DEFAULT
, VPT_STRETCH
);