title.cpp 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839
  1. ////////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright 2016 RWS Inc, All Rights Reserved
  4. //
  5. // This program is free software; you can redistribute it and/or modify
  6. // it under the terms of version 2 of the GNU General Public License as published by
  7. // the Free Software Foundation
  8. //
  9. // This program is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. // GNU General Public License for more details.
  13. //
  14. // You should have received a copy of the GNU General Public License along
  15. // with this program; if not, write to the Free Software Foundation, Inc.,
  16. // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  17. //
  18. // title.cpp
  19. // Project: Postal
  20. //
  21. // This module deals with displaying the title sequence and the loading of
  22. // assets during that time.
  23. //
  24. // History:
  25. // 12/04/96 MJR Started.
  26. //
  27. // 01/28/97 JMI Took out feet and title.bmp and replaced them with a simple
  28. // progress bar and Pile640K.bmp.
  29. //
  30. // 01/31/97 JMI Now uses FullPath() to get full path for filespecs.
  31. //
  32. // 02/02/97 JMI Now, once EndTitle() is called, the progress bar is
  33. // guaranteed to be completely filled. Also, changed
  34. // static sLastFillPos local to DoTitle() to module static
  35. // so it can be initialized in StartTitle() and, therefore,
  36. // the title screen can be restarted.
  37. //
  38. // 02/03/97 JMI Updated paths to reflect SAK dir.
  39. //
  40. // 02/24/97 MJR Put in new title screen and modified progress bar.
  41. //
  42. // 04/14/97 JMI Now shows one BMP for a portion of the title progress and
  43. // then a different one for the rest.
  44. // You can select the starting bitmap on the call to
  45. // StartTitle().
  46. // Eventually, I imagine this will be generalized further with
  47. // an array of res names and durations (one for RWS, one for
  48. // the publisher, and one for Postal).
  49. //
  50. // 04/14/97 JMI Temporarily disabled progress meter for ABC News demo.
  51. //
  52. // 06/03/97 JMI Now displays the pre-release excuse after the RWS logo.
  53. //
  54. // 06/04/97 JMI Now you can select a title page relative to the last one
  55. // by specifying a number < 1.
  56. //
  57. // 06/04/97 JMI Rearranged title screens and added RC logo.
  58. //
  59. // 06/11/97 JMI Added check against g_GameSettings.m_szDontShowTitles.
  60. // Also, DisplayImage() now does a ReleaseAndPurge() instead
  61. // of an rspReleaseResource() to save what would currently
  62. // amount to about 1.2M of RAM.
  63. //
  64. // 06/11/97 JMI Changed RResMgr::ReleaseAndPurge() call to
  65. // rspReleaseAndPurge().
  66. //
  67. // 06/12/97 JMI Now IsInList() uses rspStricmp().
  68. //
  69. // 06/12/97 JMI Now only updates the palette of the new image if it is
  70. // different from the current.
  71. //
  72. // 06/16/97 JMI Now centers title screens and erases entire screen even
  73. // no palette change.
  74. //
  75. // 07/09/97 JMI Now uses its own g_smidTitle for the title noise instead of
  76. // relying on the menu one.
  77. //
  78. // 07/18/97 JMI Got rid of bogus immitation PlaySample functions.
  79. // Now there is one PlaySample() function. Also, you now
  80. // MUST specify a category and you don't have to specify a
  81. // SoundInstance ptr to specify a volume.
  82. //
  83. // 07/23/97 JMI Added rating.bmp as first title card.
  84. //
  85. // 08/08/97 JMI Added parameter specifying whether to play musak to
  86. // StartTitle().
  87. //
  88. // 08/18/97 BRH Took out beta screen.
  89. //
  90. // 08/18/97 BRH Added game ending sequence wiht backgrounds and audio.
  91. //
  92. // 08/18/97 JMI Changed TitleRFileCallback to call Update() instead of
  93. // RMix::Do() (Update() calls RMix::Do() ) b/c Update()
  94. // makes the Mac load faster.
  95. //
  96. // 08/21/97 JMI Changed call to Update() to UpdateSystem() and occurrences
  97. // of rspUpdateDisplay() to UpdateDisplay().
  98. //
  99. // 08/22/97 JMI Changed calls to UpdateDisplay() back to rspUpdateDisplay()
  100. // since we no longer need UpdateDisplay() now that we are
  101. // using rspLock/Unlock* functions properly.
  102. // Also, put locks around accesses (Blits, Rects, etc.) to the
  103. // composite buffer.
  104. // Also, now loops the entire intro and does not abort it when
  105. // EndTitle() is called (it still stops the loopage, though).
  106. //
  107. // 08/23/97 JMI Now you can get the sound instance of the title musak from
  108. // StartTitle().
  109. //
  110. // 08/30/97 BRH Took out beta test screen.
  111. //
  112. // 09/01/97 BRH Adjusted the final ending sequence so that the music starts
  113. // on a black screen, then the door is shown while you hear
  114. // the door slam sound, then it goes to the first sequence
  115. // picture of the tortured guy.
  116. //
  117. // 09/03/97 JMI Many loops in Title_EndingSequence() wer calling RMix::Do()
  118. // instead of UpdateSystem(). While RMix::Do() will keep the
  119. // music running it does not give Blue a chance to realize
  120. // things like focus loss and video mode changes -- we should
  121. // always call UpdateSystem() in these loops.
  122. //
  123. // 09/04/97 JMI Now calls UpdateSystem() every iteration instead of every
  124. // 1/20th of a second.
  125. //
  126. // 09/07/97 BRH You can now quit with Alt-F4 when the final end of
  127. // game sequence is playing.
  128. //
  129. // 09/07/97 JMI Removed RipCord logo since the animated version is played
  130. // elsewhere (main.cpp).
  131. //
  132. // 09/08/97 JMI Move Rip Cord static logo to front.
  133. //
  134. // 09/17/97 JMI Removed unused heart beat interval timer, progress
  135. // meter calculations, and progress image loadage.
  136. //
  137. // 09/24/97 BRH Added conditional compile based on LOCALE for the title
  138. // sequence. The foreign versions have an additional
  139. // distributer screen after the ripcord logo, and the UK
  140. // warning screen is different.
  141. //
  142. // 09/25/97 JMI Added #include of "comileOptions.h" so US, UK, etc. would
  143. // be defined.
  144. //
  145. // 09/30/97 JMI Now sets and unsets RFile::ms_criticall in DisplayImage()
  146. // to guarantee it is being set during any title sequence.
  147. //
  148. // 10/21/97 JMI A call to Title_DisableRipcordStaticLogo() will now disable
  149. // the RipCord static logo.
  150. //
  151. // 11/17/97 JMI DoTitle() could theoretically blow m_adTitlePercent's
  152. // bounds.
  153. //
  154. // 06/01/98 BRH Removed the references to RIPCORD_LOGO_INDEX and the
  155. // code that disables the static logo to when the movie
  156. // logo is played etc. Take2/AIM has requested that
  157. // the only logo on the game should be Running With Scissors
  158. // so we don't want Ripcord or Take2 logos at all.
  159. //
  160. // 09/27/99 JMI Changed to allow deluxe violence disclaimer only in any
  161. // locale satisfying the CompilerOptions macro VIOLENT_LOCALE.
  162. //
  163. // 01/20/00 MJR Added screen for distributor logo.
  164. //
  165. // 03/30/00 MJR Now uses TITLE_SHOW_DISTRIBUTOR to control whether the
  166. // distributor screen is shown.
  167. //
  168. ////////////////////////////////////////////////////////////////////////////////
  169. #define TITLE_CPP
  170. #include "RSPiX.h"
  171. #include "title.h"
  172. #include "game.h"
  173. #include "update.h"
  174. #include "SampleMaster.h"
  175. #include "CompileOptions.h"
  176. ////////////////////////////////////////////////////////////////////////////////
  177. // Macros/types/etc.
  178. ////////////////////////////////////////////////////////////////////////////////
  179. #define TITLE_BG_W 640
  180. #define TITLE_BG_H 400
  181. #define TITLE_BG_X (g_pimScreenBuf->m_sWidth / 2 - TITLE_BG_W / 2)
  182. #define TITLE_BG_Y (g_pimScreenBuf->m_sHeight / 2 - TITLE_BG_H / 2)
  183. #define PROGRESS_W (600-8)
  184. #define TITLE_SOUND_UPDATE_INTERVAL 50
  185. // Determines the number of elements in the passed array at compile time.
  186. #define NUM_ELEMENTS(a) (sizeof(a) / sizeof(a[0]) )
  187. // Percentage of progress at which time we switch to the next image.
  188. #define TOGGLE_BG_PERCENT (100 / NUM_ELEMENTS(ms_apszFiles) + 1)
  189. // Token delimiters.
  190. #define TOKEN_DELIMITERS "\t ,"
  191. #define MAX_TITLES 10
  192. #define NUM_IMAGES NUM_ELEMENTS(ms_apszFiles)
  193. #define MUSAK_START_TIME 0 // 11260
  194. #define MUSAK_END_TIME 0
  195. ////////////////////////////////////////////////////////////////////////////////
  196. // Variables/data
  197. ////////////////////////////////////////////////////////////////////////////////
  198. long m_lTotalUnits;
  199. long m_lCummUnits; // I will brace myself for an onslaught of jokes.
  200. double m_adTitlePercent[MAX_TITLES+1];
  201. static short m_sValid = FALSE;
  202. static long ms_lTitleRFileCallbackTime = 0;
  203. // Indicates the currently displayed image.
  204. static short ms_sImageNum = 0;
  205. // The instance of the title musak sample.
  206. static SampleMaster::SoundInstance ms_siMusak;
  207. static SampleMaster::SoundInstance ms_siEndingAudio;
  208. static bool ms_bDisableRipcordStaticLogo = false;
  209. // These are the images (in the order) to display.
  210. static char* ms_apszFiles[] =
  211. {
  212. // Even the rating disclaimer is too violent for some countries.
  213. #if VIOLENT_LOCALE
  214. "Title/rating.bmp",
  215. #else
  216. "Title/ratingUK.bmp",
  217. #endif
  218. #ifdef TITLE_SHOW_DISTRIBUTOR
  219. "Title/distrib.bmp",
  220. #endif
  221. "Title/Logo2.bmp",
  222. "Title/Postal.bmp"
  223. };
  224. ////////////////////////////////////////////////////////////////////////////////
  225. // Function prototypes
  226. ////////////////////////////////////////////////////////////////////////////////
  227. ////////////////////////////////////////////////////////////////////////////////
  228. // TitleRFileCallback
  229. //
  230. // Callback that will call the Update() while the next background is being
  231. // loaded.
  232. //
  233. ////////////////////////////////////////////////////////////////////////////////
  234. static void TitleRFileCallback(long lBytes)
  235. {
  236. long lCurrentTime = rspGetMilliseconds();
  237. if ((lCurrentTime - ms_lTitleRFileCallbackTime) > TITLE_SOUND_UPDATE_INTERVAL)
  238. {
  239. UpdateSystem();
  240. ms_lTitleRFileCallbackTime = rspGetMilliseconds();
  241. }
  242. }
  243. ////////////////////////////////////////////////////////////////////////////////
  244. // Returns true if the specified string is in the comma separated list.
  245. ////////////////////////////////////////////////////////////////////////////////
  246. static bool IsInList( // Returns true if in list. false otherwise.
  247. char* pszSearchFor, // In: String to search for in pszSearchIn.
  248. char* pszSearchIn) // In: Comma delimited list of strings to search in for
  249. // pszSearchFor.
  250. {
  251. bool bFound = false; // Assume not found.
  252. // Copy to temp so strtok can tokenize leaving full of NULLs.
  253. char szTokenize[512];
  254. strncpy(szTokenize, pszSearchIn, sizeof(szTokenize) - 1);
  255. szTokenize[sizeof(szTokenize) - 1] = '\0';
  256. // Tokenize.
  257. char* pszToken = strtok(szTokenize, TOKEN_DELIMITERS);
  258. while (pszToken != NULL)
  259. {
  260. if (rspStricmp(pszToken, pszSearchFor) == 0)
  261. {
  262. // Found it.
  263. bFound = true;
  264. break;
  265. }
  266. pszToken = strtok(NULL, TOKEN_DELIMITERS);
  267. }
  268. return bFound;
  269. }
  270. ////////////////////////////////////////////////////////////////////////////////
  271. // Loads, displays, and disgards image from specified file.
  272. ////////////////////////////////////////////////////////////////////////////////
  273. static short DisplayImage( // Returns nothing.
  274. char* pszImageFile) // Filename of image (relative path).
  275. {
  276. // Store the original callback.
  277. RFile::CritiCall criticallRestore = RFile::ms_criticall;
  278. // Set the callback
  279. RFile::ms_criticall = TitleRFileCallback;
  280. ms_lTitleRFileCallbackTime = rspGetMilliseconds();
  281. RImage* pimTitle;
  282. short sResult = rspGetResource(&g_resmgrShell, pszImageFile, &pimTitle);
  283. if (sResult == 0)
  284. {
  285. // Determine position for new image.
  286. short sX = g_pimScreenBuf->m_sWidth / 2 - pimTitle->m_sWidth / 2;
  287. short sY = g_pimScreenBuf->m_sHeight / 2 - pimTitle->m_sHeight / 2;
  288. // Set palette
  289. ASSERT(pimTitle->m_pPalette != NULL);
  290. ASSERT(pimTitle->m_pPalette->m_type == RPal::PDIB);
  291. // Get the new palette.
  292. U8* pu8NewRed = pimTitle->m_pPalette->Red(0);
  293. U8* pu8NewGreen = pimTitle->m_pPalette->Green(0);
  294. U8* pu8NewBlue = pimTitle->m_pPalette->Blue(0);
  295. short sStartIndex = pimTitle->m_pPalette->m_sStartIndex;
  296. short sNumEntries = pimTitle->m_pPalette->m_sNumEntries;
  297. short sEntrySize = pimTitle->m_pPalette->m_sPalEntrySize;
  298. // Get the current palette.
  299. U8 au8CurRed[256];
  300. U8 au8CurGreen[256];
  301. U8 au8CurBlue[256];
  302. rspGetPaletteEntries(
  303. sStartIndex,
  304. sNumEntries,
  305. au8CurRed,
  306. au8CurGreen,
  307. au8CurBlue,
  308. 1);
  309. // Compare.
  310. bool bSetPalette = false; // true to set new palette.
  311. short i;
  312. U8* pu8NewRedEntry = pu8NewRed;
  313. U8* pu8NewGreenEntry = pu8NewGreen;
  314. U8* pu8NewBlueEntry = pu8NewBlue;
  315. U8* pu8CurRedEntry = au8CurRed;
  316. U8* pu8CurGreenEntry = au8CurGreen;
  317. U8* pu8CurBlueEntry = au8CurBlue;
  318. for (i = 0; i < sNumEntries; i++)
  319. {
  320. if ( *pu8CurRedEntry++ != *pu8NewRedEntry
  321. || *pu8CurGreenEntry++ != *pu8NewGreenEntry
  322. || *pu8CurBlueEntry++ != *pu8NewBlueEntry)
  323. {
  324. bSetPalette = true;
  325. break;
  326. }
  327. pu8NewRedEntry += sEntrySize;
  328. pu8NewGreenEntry += sEntrySize;
  329. pu8NewBlueEntry += sEntrySize;
  330. }
  331. // Lock the RSPiX composite buffer so we can access it.
  332. rspLockBuffer();
  333. // Blank screen before updating palette.
  334. rspRect(
  335. RSP_BLACK_INDEX,
  336. g_pimScreenBuf,
  337. 0,
  338. 0,
  339. g_pimScreenBuf->m_sWidth,
  340. g_pimScreenBuf->m_sHeight);
  341. // If we need to set the palette . . .
  342. if (bSetPalette == true)
  343. {
  344. rspSetPaletteEntries(
  345. sStartIndex,
  346. sNumEntries,
  347. pu8NewRed,
  348. pu8NewGreen,
  349. pu8NewBlue,
  350. sEntrySize);
  351. // Unlock to update the display.
  352. rspUnlockBuffer();
  353. // Make sure screen is black during palette change.
  354. rspUpdateDisplay();
  355. // Lock the RSPiX composite buffer so we can access it again.
  356. rspLockBuffer();
  357. // Update hardware palette.
  358. rspUpdatePalette();
  359. }
  360. // Show title image.
  361. rspBlit(
  362. pimTitle,
  363. g_pimScreenBuf,
  364. 0, 0,
  365. sX,
  366. sY,
  367. pimTitle->m_sWidth,
  368. pimTitle->m_sHeight);
  369. // Unlock now that we're done with the composite buffer.
  370. rspUnlockBuffer();
  371. // Update display.
  372. rspUpdateDisplay();
  373. rspReleaseAndPurgeResource(&g_resmgrShell, &pimTitle);
  374. }
  375. else
  376. {
  377. TRACE("DisplayImage(): Error loading %s!\n", pszImageFile);
  378. }
  379. // Restore the callback.
  380. RFile::ms_criticall = criticallRestore;
  381. return sResult;
  382. }
  383. ////////////////////////////////////////////////////////////////////////////////
  384. // Loads, displays, and disgards image from file specified via image num.
  385. ////////////////////////////////////////////////////////////////////////////////
  386. static short DisplayImageNum( // Returns nothing.
  387. short sImageNum) // In: Image Num to show [1..n].
  388. {
  389. short sRes = 0; // Assume success.
  390. // Switch to array indexing mode.
  391. sImageNum--;
  392. // If not in list of no shows . . .
  393. while (sImageNum < NUM_ELEMENTS(ms_apszFiles) )
  394. {
  395. if (IsInList(ms_apszFiles[sImageNum], g_GameSettings.m_szDontShowTitles) == false)
  396. {
  397. break;
  398. }
  399. sImageNum++;
  400. }
  401. if (sImageNum < NUM_ELEMENTS(ms_apszFiles) )
  402. {
  403. sRes = DisplayImage(ms_apszFiles[sImageNum]);
  404. }
  405. return sRes;
  406. }
  407. ////////////////////////////////////////////////////////////////////////////////
  408. //
  409. // Start the title sequence, which includes some type of progress meter, which
  410. // may or may not (hopefully not) look like a standard progress meter. The
  411. // total range of the progress bar is determined by lTotalUnits. As far as
  412. // this module is concerned, these units are completely abstract.
  413. //
  414. ////////////////////////////////////////////////////////////////////////////////
  415. extern short StartTitle( // Returns 0 if successfull, non-zero otherwise
  416. short sStartImage /*= 1*/, // In: Image to start with. Values less
  417. // than 1 indicate a page relative to the
  418. // end.
  419. bool bPlayMusak /*= false*/, // In: true to play title musak.
  420. SampleMaster::SoundInstance* psi /*= 0*/) // Out: Sound instance of musak.
  421. {
  422. short sResult = 0;
  423. // Save total units and reset other stuff
  424. short i;
  425. m_lTotalUnits = 0;
  426. for (i = 0; i < NUM_ELEMENTS(ms_apszFiles); i++)
  427. m_lTotalUnits += g_GameSettings.m_alTitleDurations[i];
  428. // Avoid divide by zero and other possible screw-ups.
  429. if (m_lTotalUnits <= 0)
  430. {
  431. m_lTotalUnits = 1;
  432. }
  433. m_adTitlePercent[0] = 0;
  434. for (i = 0; i < NUM_ELEMENTS(ms_apszFiles); i++)
  435. m_adTitlePercent[i+1] = ((double) g_GameSettings.m_alTitleDurations[i] / (double) m_lTotalUnits) + m_adTitlePercent[i];
  436. m_lCummUnits = 0;
  437. m_sValid = 0;
  438. // If value less than 1 . . .
  439. if (sStartImage < 1)
  440. {
  441. // It specifies a value relative to the end.
  442. sStartImage += NUM_ELEMENTS(ms_apszFiles);
  443. }
  444. // Force this sample to load now
  445. // CacheSample(g_smidTitle);
  446. // Display title screen
  447. sResult = DisplayImageNum(sStartImage);
  448. if (sResult == 0)
  449. {
  450. // If told to play sample . . .
  451. if (bPlayMusak)
  452. {
  453. // If not already playing . . .
  454. if (IsSamplePlaying(ms_siMusak) == false)
  455. {
  456. PlaySample( // Returns nothing.
  457. // Does not fail.
  458. g_smidTitleMusak, // In: Identifier of sample you want played.
  459. SampleMaster::BackgroundMusic, // In: Sound Volume Category for user adjustment
  460. 255, // In: Initial Sound Volume (0 - 255)
  461. &ms_siMusak, // Out: Handle for adjusting sound volume
  462. NULL, // Out: Sample duration in ms, if not NULL.
  463. MUSAK_START_TIME, // In: Where to loop back to in milliseconds.
  464. // -1 indicates no looping (unless m_sLoop is
  465. // explicitly set).
  466. MUSAK_END_TIME, // In: Where to loop back from in milliseconds.
  467. // In: If less than 1, the end + lLoopEndTime is used.
  468. true); // In: Call ReleaseAndPurge rather than Release after playing
  469. // Copy sound instance for user if given a destination for it.
  470. if (psi)
  471. {
  472. *psi = ms_siMusak;
  473. }
  474. }
  475. }
  476. m_sValid = TRUE;
  477. ms_sImageNum = sStartImage;
  478. }
  479. else
  480. {
  481. TRACE("StartTitle(): Error loading %s!\n", ms_apszFiles[sStartImage - 1]);
  482. }
  483. return sResult;
  484. }
  485. ////////////////////////////////////////////////////////////////////////////////
  486. // TitleGetNumTitles - give the number of title screens in use
  487. ////////////////////////////////////////////////////////////////////////////////
  488. extern short TitleGetNumTitles(void)
  489. {
  490. return NUM_ELEMENTS(ms_apszFiles);
  491. }
  492. ////////////////////////////////////////////////////////////////////////////////
  493. //
  494. // Update the title sequence. The specified number of units are added to a
  495. // running total. The ration between the running total and the value passed to
  496. // StartTitle() determines the new position of the progress meter.
  497. //
  498. ////////////////////////////////////////////////////////////////////////////////
  499. extern short DoTitle( // Returns 0 if successfull, non-zero otherwise
  500. long lUnits) // In: Additional progess units
  501. {
  502. short sResult = 0;
  503. // Can't call this if StartTitle() didn't work
  504. if (m_sValid)
  505. {
  506. // Add to cummulative total
  507. m_lCummUnits += lUnits;
  508. // Calculate ratio and use it to determine how much progress bar juice
  509. // we should display.
  510. double dRatio = (double)m_lCummUnits / (double)m_lTotalUnits;
  511. // While we've passed the duration before displaying the next image.
  512. // This loop is intended to skip title cards that have 0 for their
  513. // duration.
  514. // NOTE that m_adTitlePercent is valid up to and including Num Images + 1.
  515. while (dRatio > m_adTitlePercent[ms_sImageNum])
  516. {
  517. // Advance image.
  518. if (ms_sImageNum++ < TitleGetNumTitles() )
  519. {
  520. // If there's at least a smidgen of time allocated for this image . . .
  521. if (g_GameSettings.m_alTitleDurations[ms_sImageNum] )
  522. {
  523. // Display new image.
  524. DisplayImageNum(ms_sImageNum);
  525. }
  526. }
  527. else
  528. {
  529. break;
  530. }
  531. }
  532. }
  533. else
  534. {
  535. sResult = -1;
  536. TRACE("DoTitle(): It appears that StartTitle() wasn't called or didn't complete successfully!\n");
  537. }
  538. return sResult;
  539. }
  540. ////////////////////////////////////////////////////////////////////////////////
  541. //
  542. // When you are completely done, call EndTitle(). This gives the title sequence
  543. // a chance to fully complete the progess meter (in case it never reached 100%
  544. // due to an overestimated lTotalUnits) and allows all resources to be freed.
  545. //
  546. ////////////////////////////////////////////////////////////////////////////////
  547. extern short EndTitle(void) // Returns 0 if successfull, non-zero otherwise
  548. {
  549. short sResult = 0;
  550. // It's okay to call this even if StartTitle() didn't work
  551. if (m_sValid)
  552. {
  553. // Display this stuff so we can easily tune the total units based on the
  554. // actual units that were passed to this module.
  555. TRACE("EndTitle(): lTotalUnits = %ld, lCummUnits = %ld\n", m_lTotalUnits, m_lCummUnits);
  556. // Always pretend we made it, even if we didn't.
  557. DoTitle(ABS(m_lTotalUnits - m_lCummUnits) );
  558. // Lock the RSPiX composite buffer so we can access it.
  559. rspLockBuffer();
  560. // Erase progress meter
  561. RRect rcClip(0, 440, 640, 40);
  562. rspRect(
  563. RSP_BLACK_INDEX,
  564. g_pimScreenBuf,
  565. 0,
  566. 440,
  567. 640,
  568. 40,
  569. &rcClip);
  570. // Unlock now that we're done with the composite buffer.
  571. rspUnlockBuffer();
  572. rspUpdateDisplay();
  573. // Make sure last sample finishes
  574. // while (IsSamplePlaying(g_smidTitle))
  575. // Update();
  576. // Reset.
  577. m_sValid = FALSE;
  578. }
  579. return sResult;
  580. }
  581. ////////////////////////////////////////////////////////////////////////////////
  582. // Title_GameEndSequence
  583. //
  584. // Show the end of game sequence when the player wins. This will include 4
  585. // screens and audio clips.
  586. //
  587. ////////////////////////////////////////////////////////////////////////////////
  588. void Title_GameEndSequence(void)
  589. {
  590. long lDisplayTime = 0;
  591. long lTotalTime = 0;
  592. long lSectionTime = 0;
  593. long lCurrentTime;
  594. long lUpdateTime;
  595. TRACE("So this is the big end of game sequence eh?\n");
  596. // Play the sound
  597. PlaySample( // Returns nothing.
  598. // Does not fail.
  599. g_smidEndingAudio, // In: Identifier of sample you want played.
  600. SampleMaster::Unspecified, // In: Sound Volume Category for user adjustment
  601. 255, // In: Initial Sound Volume (0 - 255)
  602. &ms_siEndingAudio, // Out: Handle for adjusting sound volume
  603. &lTotalTime, // Out: Sample duration in ms, if not NULL.
  604. -1, // In: Where to loop back to in milliseconds.
  605. // -1 indicates no looping (unless m_sLoop is
  606. // explicitly set).
  607. 0, // In: Where to loop back from in milliseconds.
  608. // In: If less than 1, the end + lLoopEndTime is used.
  609. true); // In: Call ReleaseAndPurge rather than Release after playing
  610. // Set the callback
  611. RFile::ms_criticall = TitleRFileCallback;
  612. ms_lTitleRFileCallbackTime = rspGetMilliseconds();
  613. // Show black while the audio starts and then put up the door when the door slam
  614. // sound is heard.
  615. lCurrentTime = rspGetMilliseconds();
  616. lDisplayTime = lCurrentTime + 2500;
  617. lTotalTime -= 2500;
  618. lUpdateTime = lCurrentTime + TITLE_SOUND_UPDATE_INTERVAL;
  619. while (lCurrentTime < lDisplayTime)
  620. {
  621. if (lCurrentTime > lUpdateTime)
  622. {
  623. lUpdateTime = lCurrentTime + TITLE_SOUND_UPDATE_INTERVAL;
  624. }
  625. UpdateSystem();
  626. // If they hit Alt-F4 then quit the loop
  627. if (rspGetQuitStatus())
  628. lCurrentTime = lDisplayTime;
  629. else
  630. lCurrentTime = rspGetMilliseconds();
  631. }
  632. // Show the door for a short time
  633. DisplayImage("Title/fdoor.bmp");
  634. lCurrentTime = rspGetMilliseconds();
  635. lDisplayTime = lCurrentTime + 3000;
  636. lTotalTime -= 3000;
  637. lUpdateTime = lCurrentTime + TITLE_SOUND_UPDATE_INTERVAL;
  638. while (lCurrentTime < lDisplayTime)
  639. {
  640. if (lCurrentTime > lUpdateTime)
  641. {
  642. lUpdateTime = lCurrentTime + TITLE_SOUND_UPDATE_INTERVAL;
  643. }
  644. UpdateSystem();
  645. // If they hit Alt-F4, then quit the loop
  646. if (rspGetQuitStatus())
  647. lCurrentTime = lDisplayTime;
  648. else
  649. lCurrentTime = rspGetMilliseconds();
  650. }
  651. // Divide up the rest of the time.
  652. lSectionTime = lTotalTime / 4;
  653. // Display the ending backgrounds.
  654. DisplayImage("Title/corridor.bmp");
  655. lDisplayTime = rspGetMilliseconds() + lSectionTime;
  656. lCurrentTime = rspGetMilliseconds();
  657. lUpdateTime = lCurrentTime + TITLE_SOUND_UPDATE_INTERVAL;
  658. while (lCurrentTime < lDisplayTime)
  659. {
  660. if (lCurrentTime > lUpdateTime)
  661. {
  662. lUpdateTime = lCurrentTime + TITLE_SOUND_UPDATE_INTERVAL;
  663. }
  664. UpdateSystem();
  665. // If they hit Alt-F4, then quit the loop
  666. if (rspGetQuitStatus())
  667. lCurrentTime = lDisplayTime;
  668. else
  669. lCurrentTime = rspGetMilliseconds();
  670. }
  671. DisplayImage("Title/jacketbg.bmp");
  672. lDisplayTime = rspGetMilliseconds() + lSectionTime;
  673. lCurrentTime = rspGetMilliseconds();
  674. lUpdateTime = lCurrentTime + TITLE_SOUND_UPDATE_INTERVAL;
  675. while (lCurrentTime < lDisplayTime)
  676. {
  677. if (lCurrentTime > lUpdateTime)
  678. {
  679. lUpdateTime = lCurrentTime + TITLE_SOUND_UPDATE_INTERVAL;
  680. }
  681. UpdateSystem();
  682. // If they hit Alt-F4, then quit the loop
  683. if (rspGetQuitStatus())
  684. lCurrentTime = lDisplayTime;
  685. else
  686. lCurrentTime = rspGetMilliseconds();
  687. }
  688. DisplayImage("Title/torture2.bmp");
  689. lDisplayTime = rspGetMilliseconds() + lSectionTime;
  690. lCurrentTime = rspGetMilliseconds();
  691. lUpdateTime = lCurrentTime + TITLE_SOUND_UPDATE_INTERVAL;
  692. while (lCurrentTime < lDisplayTime)
  693. {
  694. if (lCurrentTime > lUpdateTime)
  695. {
  696. lUpdateTime = lCurrentTime + TITLE_SOUND_UPDATE_INTERVAL;
  697. }
  698. UpdateSystem();
  699. // If they hit Alt-F4, then quit the loop
  700. if (rspGetQuitStatus())
  701. lCurrentTime = lDisplayTime;
  702. else
  703. lCurrentTime = rspGetMilliseconds();
  704. }
  705. DisplayImage("Title/fdoor.bmp");
  706. lDisplayTime = rspGetMilliseconds() + lSectionTime;
  707. lCurrentTime = rspGetMilliseconds();
  708. lUpdateTime = lCurrentTime + TITLE_SOUND_UPDATE_INTERVAL;
  709. while (lCurrentTime < lDisplayTime)
  710. {
  711. if (lCurrentTime > lUpdateTime)
  712. {
  713. lUpdateTime = lCurrentTime + TITLE_SOUND_UPDATE_INTERVAL;
  714. }
  715. UpdateSystem();
  716. // If they hit Alt-F4, then quit the loop
  717. if (rspGetQuitStatus())
  718. lCurrentTime = lDisplayTime;
  719. else
  720. lCurrentTime = rspGetMilliseconds();
  721. }
  722. // Unset the callback
  723. RFile::ms_criticall = 0;
  724. }
  725. ////////////////////////////////////////////////////////////////////////////////
  726. // Disable RipCord static logo.
  727. ////////////////////////////////////////////////////////////////////////////////
  728. extern void Title_DisableRipcordStaticLogo(void)
  729. {
  730. ms_bDisableRipcordStaticLogo = true;
  731. }
  732. ////////////////////////////////////////////////////////////////////////////////
  733. // EOF
  734. ////////////////////////////////////////////////////////////////////////////////