f_finale.c 18 KB

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