f_finale.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678
  1. /* Emacs style mode select -*- C++ -*-
  2. *-----------------------------------------------------------------------------
  3. *
  4. *
  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
  11. * Copyright 2005, 2006 by
  12. * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
  13. *
  14. * This program is free software; you can redistribute it and/or
  15. * modify it under the terms of the GNU General Public License
  16. * as published by the Free Software Foundation; either version 2
  17. * of the License, or (at your option) any later version.
  18. *
  19. * This program is distributed in the hope that it will be useful,
  20. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  21. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  22. * GNU General Public License for more details.
  23. *
  24. * You should have received a copy of the GNU General Public License
  25. * along with this program; if not, write to the Free Software
  26. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
  27. * 02111-1307, USA.
  28. *
  29. * DESCRIPTION:
  30. * Game completion, final screen animation.
  31. *
  32. *-----------------------------------------------------------------------------
  33. */
  34. #include "doomstat.h"
  35. #include "d_event.h"
  36. #include "g_game.h"
  37. #include "v_video.h"
  38. #include "w_wad.h"
  39. #include "s_sound.h"
  40. #include "sounds.h"
  41. #include "d_deh.h" // Ty 03/22/98 - externalizations
  42. #include "f_finale.h" // CPhipps - hmm...
  43. // Stage of animation:
  44. // 0 = text, 1 = art screen, 2 = character cast
  45. static int finalestage; // cph -
  46. static int finalecount; // made static
  47. static const char* finaletext; // cph -
  48. static const char* finaleflat; // made static const
  49. // defines for the end mission display text // phares
  50. #define TEXTSPEED 3 // original value // phares
  51. #define TEXTWAIT 250 // original value // phares
  52. #define NEWTEXTSPEED 0.01f // new value // phares
  53. #define NEWTEXTWAIT 1000 // new value // phares
  54. // CPhipps - removed the old finale screen text message strings;
  55. // they were commented out for ages already
  56. // Ty 03/22/98 - ... the new s_WHATEVER extern variables are used
  57. // in the code below instead.
  58. void F_StartCast (void);
  59. void F_CastTicker (void);
  60. dboolean F_CastResponder (event_t *ev);
  61. void F_CastDrawer (void);
  62. void WI_checkForAccelerate(void); // killough 3/28/98: used to
  63. extern int acceleratestage; // accelerate intermission screens
  64. static int midstage; // whether we're in "mid-stage"
  65. //
  66. // F_StartFinale
  67. //
  68. void F_StartFinale (void)
  69. {
  70. gameaction = ga_nothing;
  71. gamestate = GS_FINALE;
  72. automapmode &= ~am_active;
  73. // killough 3/28/98: clear accelerative text flags
  74. acceleratestage = midstage = 0;
  75. // Okay - IWAD dependend stuff.
  76. // This has been changed severly, and
  77. // some stuff might have changed in the process.
  78. switch ( gamemode )
  79. {
  80. // DOOM 1 - E1, E3 or E4, but each nine missions
  81. case shareware:
  82. case registered:
  83. case retail:
  84. {
  85. S_ChangeMusic(mus_victor, true);
  86. switch (gameepisode)
  87. {
  88. case 1:
  89. finaleflat = bgflatE1; // Ty 03/30/98 - new externalized bg flats
  90. finaletext = s_E1TEXT; // Ty 03/23/98 - Was e1text variable.
  91. break;
  92. case 2:
  93. finaleflat = bgflatE2;
  94. finaletext = s_E2TEXT; // Ty 03/23/98 - Same stuff for each
  95. break;
  96. case 3:
  97. finaleflat = bgflatE3;
  98. finaletext = s_E3TEXT;
  99. break;
  100. case 4:
  101. finaleflat = bgflatE4;
  102. finaletext = s_E4TEXT;
  103. break;
  104. default:
  105. // Ouch.
  106. break;
  107. }
  108. break;
  109. }
  110. // DOOM II and missions packs with E1, M34
  111. case commercial:
  112. {
  113. S_ChangeMusic(mus_read_m, true);
  114. // Ty 08/27/98 - added the gamemission logic
  115. switch (gamemap)
  116. {
  117. case 6:
  118. finaleflat = bgflat06;
  119. finaletext = (gamemission==pack_tnt) ? s_T1TEXT :
  120. (gamemission==pack_plut) ? s_P1TEXT : s_C1TEXT;
  121. break;
  122. case 11:
  123. finaleflat = bgflat11;
  124. finaletext = (gamemission==pack_tnt) ? s_T2TEXT :
  125. (gamemission==pack_plut) ? s_P2TEXT : s_C2TEXT;
  126. break;
  127. case 20:
  128. finaleflat = bgflat20;
  129. finaletext = (gamemission==pack_tnt) ? s_T3TEXT :
  130. (gamemission==pack_plut) ? s_P3TEXT : s_C3TEXT;
  131. break;
  132. case 30:
  133. finaleflat = bgflat30;
  134. finaletext = (gamemission==pack_tnt) ? s_T4TEXT :
  135. (gamemission==pack_plut) ? s_P4TEXT : s_C4TEXT;
  136. break;
  137. case 15:
  138. finaleflat = bgflat15;
  139. finaletext = (gamemission==pack_tnt) ? s_T5TEXT :
  140. (gamemission==pack_plut) ? s_P5TEXT : s_C5TEXT;
  141. break;
  142. case 31:
  143. finaleflat = bgflat31;
  144. finaletext = (gamemission==pack_tnt) ? s_T6TEXT :
  145. (gamemission==pack_plut) ? s_P6TEXT : s_C6TEXT;
  146. break;
  147. default:
  148. // Ouch.
  149. break;
  150. }
  151. if (gamemission == pack_nerve && gamemap == 8)
  152. {
  153. finaleflat = bgflat06;
  154. finaletext = s_C6TEXT;
  155. }
  156. break;
  157. // Ty 08/27/98 - end gamemission logic
  158. }
  159. // Indeterminate.
  160. default: // Ty 03/30/98 - not externalized
  161. S_ChangeMusic(mus_read_m, true);
  162. finaleflat = "F_SKY1"; // Not used anywhere else.
  163. finaletext = s_C1TEXT; // FIXME - other text, music?
  164. break;
  165. }
  166. finalestage = 0;
  167. finalecount = 0;
  168. }
  169. dboolean F_Responder (event_t *event)
  170. {
  171. if (finalestage == 2)
  172. return F_CastResponder (event);
  173. return false;
  174. }
  175. // Get_TextSpeed() returns the value of the text display speed // phares
  176. // Rewritten to allow user-directed acceleration -- killough 3/28/98
  177. static float Get_TextSpeed(void)
  178. {
  179. return midstage ? NEWTEXTSPEED : (midstage=acceleratestage) ?
  180. acceleratestage=0, NEWTEXTSPEED : TEXTSPEED;
  181. }
  182. //
  183. // F_Ticker
  184. //
  185. // killough 3/28/98: almost totally rewritten, to use
  186. // player-directed acceleration instead of constant delays.
  187. // Now the player can accelerate the text display by using
  188. // the fire/use keys while it is being printed. The delay
  189. // automatically responds to the user, and gives enough
  190. // time to read.
  191. //
  192. // killough 5/10/98: add back v1.9 demo compatibility
  193. //
  194. void F_Ticker(void)
  195. {
  196. int i;
  197. if (!demo_compatibility)
  198. WI_checkForAccelerate(); // killough 3/28/98: check for acceleration
  199. else
  200. if (gamemode == commercial && finalecount > 50) // check for skipping
  201. for (i=0; i<MAXPLAYERS; i++)
  202. if (players[i].cmd.buttons)
  203. goto next_level; // go on to the next level
  204. // advance animation
  205. finalecount++;
  206. if (finalestage == 2)
  207. F_CastTicker();
  208. if (!finalestage)
  209. {
  210. float speed = demo_compatibility ? TEXTSPEED : Get_TextSpeed();
  211. /* killough 2/28/98: changed to allow acceleration */
  212. if (finalecount > strlen(finaletext)*speed +
  213. (midstage ? NEWTEXTWAIT : TEXTWAIT) ||
  214. (midstage && acceleratestage)) {
  215. if (gamemode != commercial) // Doom 1 / Ultimate Doom episode end
  216. { // with enough time, it's automatic
  217. finalecount = 0;
  218. finalestage = 1;
  219. wipegamestate = -1; // force a wipe
  220. if (gameepisode == 3)
  221. S_StartMusic(mus_bunny);
  222. }
  223. else // you must press a button to continue in Doom 2
  224. if (!demo_compatibility && midstage)
  225. {
  226. next_level:
  227. if (gamemap == 30 || (gamemission == pack_nerve && singleplayer && gamemap == 8))
  228. F_StartCast(); // cast of Doom 2 characters
  229. else
  230. gameaction = ga_worlddone; // next level, e.g. MAP07
  231. }
  232. }
  233. }
  234. }
  235. //
  236. // F_TextWrite
  237. //
  238. // This program displays the background and text at end-mission // phares
  239. // text time. It draws both repeatedly so that other displays, // |
  240. // like the main menu, can be drawn over it dynamically and // V
  241. // erased dynamically. The TEXTSPEED constant is changed into
  242. // the Get_TextSpeed function so that the speed of writing the // ^
  243. // text can be increased, and there's still time to read what's // |
  244. // written. // phares
  245. // CPhipps - reformatted
  246. #include "hu_stuff.h"
  247. extern patchnum_t hu_font[HU_FONTSIZE];
  248. static void F_TextWrite (void)
  249. {
  250. V_DrawBackground(finaleflat, 0);
  251. { // draw some of the text onto the screen
  252. int cx = 10;
  253. int cy = 10;
  254. const char* ch = finaletext; // CPhipps - const
  255. int count = (int)((float)(finalecount - 10)/Get_TextSpeed()); // phares
  256. int w;
  257. if (count < 0)
  258. count = 0;
  259. for ( ; count ; count-- ) {
  260. int c = *ch++;
  261. if (!c)
  262. break;
  263. if (c == '\n') {
  264. cx = 10;
  265. cy += 11;
  266. continue;
  267. }
  268. c = toupper(c) - HU_FONTSTART;
  269. if (c < 0 || c> HU_FONTSIZE) {
  270. cx += 4;
  271. continue;
  272. }
  273. w = hu_font[c].width;
  274. if (cx+w > SCREENWIDTH)
  275. break;
  276. // CPhipps - patch drawing updated
  277. V_DrawNumPatch(cx, cy, 0, hu_font[c].lumpnum, CR_DEFAULT, VPT_STRETCH);
  278. cx+=w;
  279. }
  280. }
  281. }
  282. //
  283. // Final DOOM 2 animation
  284. // Casting by id Software.
  285. // in order of appearance
  286. //
  287. typedef struct
  288. {
  289. const char **name; // CPhipps - const**
  290. mobjtype_t type;
  291. } castinfo_t;
  292. static const castinfo_t castorder[] = { // CPhipps - static const, initialised here
  293. { &s_CC_ZOMBIE, MT_POSSESSED },
  294. { &s_CC_SHOTGUN, MT_SHOTGUY },
  295. { &s_CC_HEAVY, MT_CHAINGUY },
  296. { &s_CC_IMP, MT_TROOP },
  297. { &s_CC_DEMON, MT_SERGEANT },
  298. { &s_CC_LOST, MT_SKULL },
  299. { &s_CC_CACO, MT_HEAD },
  300. { &s_CC_HELL, MT_KNIGHT },
  301. { &s_CC_BARON, MT_BRUISER },
  302. { &s_CC_ARACH, MT_BABY },
  303. { &s_CC_PAIN, MT_PAIN },
  304. { &s_CC_REVEN, MT_UNDEAD },
  305. { &s_CC_MANCU, MT_FATSO },
  306. { &s_CC_ARCH, MT_VILE },
  307. { &s_CC_SPIDER, MT_SPIDER },
  308. { &s_CC_CYBER, MT_CYBORG },
  309. { &s_CC_HERO, MT_PLAYER },
  310. { NULL, 0}
  311. };
  312. int castnum;
  313. int casttics;
  314. state_t* caststate;
  315. dboolean castdeath;
  316. int castframes;
  317. int castonmelee;
  318. dboolean castattacking;
  319. //
  320. // F_StartCast
  321. //
  322. void F_StartCast (void)
  323. {
  324. wipegamestate = -1; // force a screen wipe
  325. castnum = 0;
  326. caststate = &states[mobjinfo[castorder[castnum].type].seestate];
  327. casttics = caststate->tics;
  328. castdeath = false;
  329. finalestage = 2;
  330. castframes = 0;
  331. castonmelee = 0;
  332. castattacking = false;
  333. S_ChangeMusic(mus_evil, true);
  334. }
  335. //
  336. // F_CastTicker
  337. //
  338. void F_CastTicker (void)
  339. {
  340. int st;
  341. int sfx;
  342. if (--casttics > 0)
  343. return; // not time to change state yet
  344. if (caststate->tics == -1 || caststate->nextstate == S_NULL)
  345. {
  346. // switch from deathstate to next monster
  347. castnum++;
  348. castdeath = false;
  349. if (castorder[castnum].name == NULL)
  350. castnum = 0;
  351. if (mobjinfo[castorder[castnum].type].seesound)
  352. S_StartSound (NULL, mobjinfo[castorder[castnum].type].seesound);
  353. caststate = &states[mobjinfo[castorder[castnum].type].seestate];
  354. castframes = 0;
  355. }
  356. else
  357. {
  358. // just advance to next state in animation
  359. if (caststate == &states[S_PLAY_ATK1])
  360. goto stopattack; // Oh, gross hack!
  361. st = caststate->nextstate;
  362. caststate = &states[st];
  363. castframes++;
  364. // sound hacks....
  365. switch (st)
  366. {
  367. case S_PLAY_ATK1: sfx = sfx_dshtgn; break;
  368. case S_POSS_ATK2: sfx = sfx_pistol; break;
  369. case S_SPOS_ATK2: sfx = sfx_shotgn; break;
  370. case S_VILE_ATK2: sfx = sfx_vilatk; break;
  371. case S_SKEL_FIST2: sfx = sfx_skeswg; break;
  372. case S_SKEL_FIST4: sfx = sfx_skepch; break;
  373. case S_SKEL_MISS2: sfx = sfx_skeatk; break;
  374. case S_FATT_ATK8:
  375. case S_FATT_ATK5:
  376. case S_FATT_ATK2: sfx = sfx_firsht; break;
  377. case S_CPOS_ATK2:
  378. case S_CPOS_ATK3:
  379. case S_CPOS_ATK4: sfx = sfx_shotgn; break;
  380. case S_TROO_ATK3: sfx = sfx_claw; break;
  381. case S_SARG_ATK2: sfx = sfx_sgtatk; break;
  382. case S_BOSS_ATK2:
  383. case S_BOS2_ATK2:
  384. case S_HEAD_ATK2: sfx = sfx_firsht; break;
  385. case S_SKULL_ATK2: sfx = sfx_sklatk; break;
  386. case S_SPID_ATK2:
  387. case S_SPID_ATK3: sfx = sfx_shotgn; break;
  388. case S_BSPI_ATK2: sfx = sfx_plasma; break;
  389. case S_CYBER_ATK2:
  390. case S_CYBER_ATK4:
  391. case S_CYBER_ATK6: sfx = sfx_rlaunc; break;
  392. case S_PAIN_ATK3: sfx = sfx_sklatk; break;
  393. default: sfx = 0; break;
  394. }
  395. if (sfx)
  396. S_StartSound (NULL, sfx);
  397. }
  398. if (castframes == 12)
  399. {
  400. // go into attack frame
  401. castattacking = true;
  402. if (castonmelee)
  403. caststate=&states[mobjinfo[castorder[castnum].type].meleestate];
  404. else
  405. caststate=&states[mobjinfo[castorder[castnum].type].missilestate];
  406. castonmelee ^= 1;
  407. if (caststate == &states[S_NULL])
  408. {
  409. if (castonmelee)
  410. caststate=
  411. &states[mobjinfo[castorder[castnum].type].meleestate];
  412. else
  413. caststate=
  414. &states[mobjinfo[castorder[castnum].type].missilestate];
  415. }
  416. }
  417. if (castattacking)
  418. {
  419. if (castframes == 24
  420. || caststate == &states[mobjinfo[castorder[castnum].type].seestate] )
  421. {
  422. stopattack:
  423. castattacking = false;
  424. castframes = 0;
  425. caststate = &states[mobjinfo[castorder[castnum].type].seestate];
  426. }
  427. }
  428. casttics = caststate->tics;
  429. if (casttics == -1)
  430. casttics = 15;
  431. }
  432. //
  433. // F_CastResponder
  434. //
  435. dboolean F_CastResponder (event_t* ev)
  436. {
  437. if (ev->type != ev_keydown)
  438. return false;
  439. if (castdeath)
  440. return true; // already in dying frames
  441. // go into death frame
  442. castdeath = true;
  443. caststate = &states[mobjinfo[castorder[castnum].type].deathstate];
  444. casttics = caststate->tics;
  445. castframes = 0;
  446. castattacking = false;
  447. if (mobjinfo[castorder[castnum].type].deathsound)
  448. S_StartSound (NULL, mobjinfo[castorder[castnum].type].deathsound);
  449. return true;
  450. }
  451. static void F_CastPrint (const char* text) // CPhipps - static, const char*
  452. {
  453. const char* ch; // CPhipps - const
  454. int c;
  455. int cx;
  456. int w;
  457. int width;
  458. // find width
  459. ch = text;
  460. width = 0;
  461. while (ch)
  462. {
  463. c = *ch++;
  464. if (!c)
  465. break;
  466. c = toupper(c) - HU_FONTSTART;
  467. if (c < 0 || c> HU_FONTSIZE)
  468. {
  469. width += 4;
  470. continue;
  471. }
  472. w = hu_font[c].width;
  473. width += w;
  474. }
  475. // draw it
  476. cx = 160-width/2;
  477. ch = text;
  478. while (ch)
  479. {
  480. c = *ch++;
  481. if (!c)
  482. break;
  483. c = toupper(c) - HU_FONTSTART;
  484. if (c < 0 || c> HU_FONTSIZE)
  485. {
  486. cx += 4;
  487. continue;
  488. }
  489. w = hu_font[c].width;
  490. // CPhipps - patch drawing updated
  491. V_DrawNumPatch(cx, 180, 0, hu_font[c].lumpnum, CR_DEFAULT, VPT_STRETCH);
  492. cx+=w;
  493. }
  494. }
  495. //
  496. // F_CastDrawer
  497. //
  498. void F_CastDrawer (void)
  499. {
  500. spritedef_t* sprdef;
  501. spriteframe_t* sprframe;
  502. int lump;
  503. dboolean flip;
  504. // erase the entire screen to a background
  505. // CPhipps - patch drawing updated
  506. V_DrawNamePatch(0,0,0, bgcastcall, CR_DEFAULT, VPT_STRETCH); // Ty 03/30/98 bg texture extern
  507. // e6y: wide-res
  508. V_FillBorder(-1, 0);
  509. F_CastPrint (*(castorder[castnum].name));
  510. // draw the current frame in the middle of the screen
  511. sprdef = &sprites[caststate->sprite];
  512. sprframe = &sprdef->spriteframes[ caststate->frame & FF_FRAMEMASK];
  513. lump = sprframe->lump[0];
  514. flip = (dboolean)(sprframe->flip & 1);
  515. // CPhipps - patch drawing updated
  516. V_DrawNumPatch(160, 170, 0, lump+firstspritelump, CR_DEFAULT,
  517. VPT_STRETCH | (flip ? VPT_FLIP : 0));
  518. }
  519. //
  520. // F_BunnyScroll
  521. //
  522. static const char pfub2[] = { "PFUB2" };
  523. static const char pfub1[] = { "PFUB1" };
  524. static void F_BunnyScroll (void)
  525. {
  526. char name[10];
  527. int stage;
  528. static int laststage;
  529. {
  530. int scrolled = 320 - (finalecount-230)/2;
  531. if (scrolled <= 0) {
  532. V_DrawNamePatch(0, 0, 0, pfub2, CR_DEFAULT, VPT_STRETCH);
  533. } else if (scrolled >= 320) {
  534. V_DrawNamePatch(0, 0, 0, pfub1, CR_DEFAULT, VPT_STRETCH);
  535. } else {
  536. V_DrawNamePatch(320-scrolled, 0, 0, pfub1, CR_DEFAULT, VPT_STRETCH);
  537. V_DrawNamePatch(-scrolled, 0, 0, pfub2, CR_DEFAULT, VPT_STRETCH);
  538. }
  539. }
  540. if (finalecount < 1130)
  541. return;
  542. if (finalecount < 1180)
  543. {
  544. // CPhipps - patch drawing updated
  545. V_DrawNamePatch((320-13*8)/2, (200-8*8)/2,0, "END0", CR_DEFAULT, VPT_STRETCH);
  546. laststage = 0;
  547. return;
  548. }
  549. stage = (finalecount-1180) / 5;
  550. if (stage > 6)
  551. stage = 6;
  552. if (stage > laststage)
  553. {
  554. S_StartSound (NULL, sfx_pistol);
  555. laststage = stage;
  556. }
  557. sprintf (name,"END%i",stage);
  558. // CPhipps - patch drawing updated
  559. V_DrawNamePatch((320-13*8)/2, (200-8*8)/2, 0, name, CR_DEFAULT, VPT_STRETCH);
  560. }
  561. //
  562. // F_Drawer
  563. //
  564. void F_Drawer (void)
  565. {
  566. if (finalestage == 2)
  567. {
  568. F_CastDrawer ();
  569. return;
  570. }
  571. if (!finalestage)
  572. F_TextWrite ();
  573. else
  574. {
  575. switch (gameepisode)
  576. {
  577. // CPhipps - patch drawing updated
  578. case 1:
  579. if ( gamemode == retail )
  580. V_DrawNamePatch(0, 0, 0, "CREDIT", CR_DEFAULT, VPT_STRETCH);
  581. else
  582. V_DrawNamePatch(0, 0, 0, "HELP2", CR_DEFAULT, VPT_STRETCH);
  583. break;
  584. case 2:
  585. V_DrawNamePatch(0, 0, 0, "VICTORY2", CR_DEFAULT, VPT_STRETCH);
  586. break;
  587. case 3:
  588. F_BunnyScroll ();
  589. break;
  590. case 4:
  591. V_DrawNamePatch(0, 0, 0, "ENDPIC", CR_DEFAULT, VPT_STRETCH);
  592. break;
  593. }
  594. // e6y: wide-res
  595. V_FillBorder(-1, 0);
  596. }
  597. }