PageRenderTime 64ms CodeModel.GetById 24ms RepoModel.GetById 1ms app.codeStats 0ms

/engines/kyra/sequence/sequences_hof.cpp

http://github.com/scummvm/scummvm
C++ | 3524 lines | 2846 code | 633 blank | 45 comment | 658 complexity | 2cef18f99ad1cc7ddc8c44f8682322b4 MD5 | raw file
Possible License(s): GPL-3.0, LGPL-2.1, GPL-2.0

Large files files are truncated, but you can click here to view the full file

  1. /* ScummVM - Graphic Adventure Engine
  2. *
  3. * ScummVM is the legal property of its developers, whose names
  4. * are too numerous to list here. Please refer to the COPYRIGHT
  5. * file distributed with this source distribution.
  6. *
  7. * This program is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU General Public License
  9. * as published by the Free Software Foundation; either version 2
  10. * of the License, or (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with this program; if not, write to the Free Software
  19. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  20. *
  21. */
  22. #include "kyra/engine/kyra_hof.h"
  23. #include "kyra/graphics/screen_hof.h"
  24. #include "kyra/graphics/screen_lol.h"
  25. #include "kyra/resource/resource.h"
  26. #include "kyra/sound/sound.h"
  27. #include "kyra/sequence/sequences_hof.h"
  28. #include "kyra/engine/timer.h"
  29. #include "common/system.h"
  30. namespace Kyra {
  31. enum SequenceID {
  32. kSequenceNoLooping = -1,
  33. kSequenceVirgin = 0,
  34. kSequenceWestwood,
  35. kSequenceTitle,
  36. kSequenceOverview,
  37. kSequenceLibrary,
  38. kSequenceHand,
  39. kSequencePoint,
  40. kSequenceZanfaun,
  41. kSequenceFunters,
  42. kSequenceFerb,
  43. kSequenceFish,
  44. kSequenceFheep,
  45. kSequenceFarmer,
  46. kSequenceFuards,
  47. kSequenceFirates,
  48. kSequenceFrash,
  49. kSequenceHoFDemoVirgin,
  50. kSequenceHoFDemoWestwood,
  51. kSequenceHoFDemoTitle,
  52. kSequenceHoFDemoHill,
  53. kSequenceHoFDemoOuthome,
  54. kSequenceHoFDemoWharf,
  55. kSequenceHoFDemoDinob,
  56. kSequenceHoFDemoFisher,
  57. // The following enums remain active even if LoL is disabled
  58. kSequenceLoLDemoScene1,
  59. kSequenceLoLDemoText1,
  60. kSequenceLoLDemoScene2,
  61. kSequenceLoLDemoText2,
  62. kSequenceLoLDemoScene3,
  63. kSequenceLoLDemoText3,
  64. kSequenceLoLDemoScene4,
  65. kSequenceLoLDemoText4,
  66. kSequenceLoLDemoScene5,
  67. kSequenceLoLDemoText5,
  68. kSequenceLoLDemoScene6,
  69. kSequenceArraySize
  70. };
  71. enum NestedSequenceID {
  72. kNestedSequenceFiggle = 0,
  73. kNestedSequenceOver1,
  74. kNestedSequenceOver2,
  75. kNestedSequenceForest,
  76. kNestedSequenceDragon,
  77. kNestedSequenceDarm,
  78. kNestedSequenceLibrary2,
  79. kNestedSequenceLibrary3,
  80. kNestedSequenceMarco,
  81. kNestedSequenceHand1a,
  82. kNestedSequenceHand1b,
  83. kNestedSequenceHand1c,
  84. kNestedSequenceHand2,
  85. kNestedSequenceHand3,
  86. kNestedSequenceHand4,
  87. kNestedSequenceHoFDemoWharf2,
  88. kNestedSequenceHoFDemoDinob2,
  89. kNestedSequenceHoFDemoWater,
  90. kNestedSequenceHoFDemoBail,
  91. kNestedSequenceHoFDemoDig,
  92. kNestedSequenceArraySize
  93. };
  94. typedef int (SeqPlayer_HOF::*SeqProc)(WSAMovie_v2 *, int, int, int);
  95. struct SeqPlayerConfig {
  96. SeqPlayerConfig(const HoFSeqData *data, const SeqProc *callbacks, const SeqProc *nestedCallbacks) : seq(data->seq), seqProc(callbacks), numSeq(data->numSeq), nestedSeq(data->nestedSeq), nestedSeqProc(nestedCallbacks), numNestedSeq(data->numNestedSeq) {}
  97. const HoFSequence *seq;
  98. const SeqProc *seqProc;
  99. int numSeq;
  100. const HoFNestedSequence *nestedSeq;
  101. const SeqProc *nestedSeqProc;
  102. int numNestedSeq;
  103. };
  104. class SeqPlayer_HOF {
  105. public:
  106. SeqPlayer_HOF(KyraEngine_v1 *vm, Screen_v2 *screen, OSystem *system, bool startupSaveLoadable = false);
  107. ~SeqPlayer_HOF();
  108. int play(SequenceID firstScene, SequenceID loopStartScene);
  109. void pause(bool toggle);
  110. static SeqPlayer_HOF *instance() { return _instance; }
  111. private:
  112. // Init
  113. void setupCallbacks();
  114. // Playback loop
  115. void runLoop();
  116. void playScenes();
  117. bool checkAbortPlayback();
  118. bool checkPlaybackStatus();
  119. bool _abortRequested;
  120. uint32 _pauseStart;
  121. // Sequence transitions
  122. void doTransition(int type);
  123. void nestedFrameAnimTransition(int srcPage, int dstPage, int delaytime, int steps, int x, int y, int w, int h, int openClose, int directionFlags);
  124. void nestedFrameFadeTransition(const char *cmpFile);
  125. // Animations
  126. void playAnimation(WSAMovie_v2 *wsaObj, int startFrame, int numFrames, int frameRate, int x, int y, const SeqProc callback, Palette *fadePal1, Palette *fadePal2, int fadeRate, bool restoreScreen);
  127. void playDialogueAnimation(uint16 strID, uint16 soundID, int textColor, int textPosX, int textPosY, int textWidth, WSAMovie_v2 *wsaObj, int animStartFrame, int animLastFrame, int animPosX, int animPosY);
  128. void startNestedAnimation(int animSlot, int sequenceID);
  129. void closeNestedAnimation(int animSlot);
  130. void unloadNestedAnimation(int animSlot);
  131. void doNestedFrameTransition(int transitionType, int animSlot);
  132. void updateAllNestedAnimations();
  133. bool updateNestedAnimation(int animSlot);
  134. struct AnimSlot {
  135. SeqProc callback;
  136. WSAMovie_v2 *movie;
  137. const FrameControl *control;
  138. int16 flags;
  139. uint16 startFrame;
  140. uint16 endFrame;
  141. uint16 frameDelay;
  142. uint32 nextFrame;
  143. uint16 currentFrame;
  144. uint16 lastFrame;
  145. uint16 x;
  146. uint16 y;
  147. uint16 fadeInTransitionType;
  148. uint16 fadeOutTransitionType;
  149. };
  150. AnimSlot _animSlots[8];
  151. bool _updateAnimations;
  152. uint32 _animDuration;
  153. int _animCurrentFrame;
  154. int _callbackCurrentFrame;
  155. // The only reason to declare these here (instead of just locally) is being able to increase them after pausing the Engine
  156. uint32 _specialAnimTimeOutTotal;
  157. uint32 _specialAnimFrameTimeOut;
  158. // Subtitles/Dialogue/Sound
  159. void playSoundEffect(uint16 id, int16 vol);
  160. void playSoundAndDisplaySubTitle(uint16 id);
  161. void printFadingText(uint16 strID, int x, int y, const uint8 *colorMap, uint8 textcolor);
  162. int displaySubTitle(uint16 strID, uint16 posX, uint16 posY, int duration, uint16 width);
  163. void updateSubTitles();
  164. char *preprocessString(const char *str, int width);
  165. void waitForSubTitlesTimeout();
  166. uint32 ticksTillSubTitlesTimeout();
  167. void resetAllTextSlots();
  168. void fadeOutMusic();
  169. struct TextSlot {
  170. uint16 strIndex;
  171. uint16 x;
  172. uint16 y;
  173. uint16 width;
  174. int32 duration;
  175. uint32 startTime;
  176. int16 textcolor;
  177. };
  178. TextSlot _textSlots[10];
  179. char *_tempString;
  180. uint8 _textColor[2];
  181. uint8 _textColorMap[16];
  182. int _textDuration[33];
  183. const char *const *_sequenceStrings;
  184. const char *const *_sequenceSoundList;
  185. int _sequenceSoundListSize;
  186. static const uint8 _textColorPresets[];
  187. // HOF credits
  188. void playHoFTalkieCredits();
  189. void displayHoFTalkieScrollText(uint8 *data, const ScreenDim *d, int tempPage1, int tempPage2, int speed, int step, Screen::FontId fid1, Screen::FontId fid2, const uint8 *shapeData = 0, const char *const *specialData = 0);
  190. bool _talkieFinaleExtraFlag;
  191. // HOF+LOL demo specific
  192. void updateDemoAdText(int bottom, int top);
  193. ActiveItemAnim _hofDemoActiveItemAnim[5];
  194. const HoFSeqItemAnimData *_hofDemoAnimData;
  195. uint32 _fisherAnimCurTime;
  196. int _scrollProgressCounter;
  197. uint8 *_hofDemoShapeData;
  198. uint8 *_hofDemoItemShapes[20];
  199. // Misc
  200. void delayTicks(uint32 ticks);
  201. void delayUntil(uint32 dest);
  202. void setCountDown(uint32 ticks);
  203. bool countDownRunning();
  204. uint32 _countDownRemainder;
  205. uint32 _countDownLastUpdate;
  206. enum SeqPlayerTargetInfo {
  207. kHoF = 0,
  208. kHoFDemo,
  209. kLoLDemo
  210. };
  211. SeqPlayerTargetInfo _target;
  212. int _firstScene, _loopStartScene, _curScene, _preventSkipBeforeScene, _lastScene;
  213. bool _startupSaveLoadable, _isFinale, _preventLooping;
  214. SeqPlayerConfig *_config;
  215. MainMenu *_menu;
  216. int _result;
  217. bool _abortPlayback;
  218. KyraEngine_v1 *_vm;
  219. Screen_v2 *_screen;
  220. // We might consider getting rid of Screen_HoF, since there are only 2 methods left in that class anyway
  221. Screen_HoF *_screenHoF;
  222. OSystem *_system;
  223. static SeqPlayer_HOF *_instance;
  224. private:
  225. // Sequence specific callback functions
  226. int cbHOF_westwood(WSAMovie_v2 *wsaObj, int x, int y, int frm);
  227. int cbHOF_title(WSAMovie_v2 *wsaObj, int x, int y, int frm);
  228. int cbHOF_overview(WSAMovie_v2 *wsaObj, int x, int y, int frm);
  229. int cbHOF_library(WSAMovie_v2 *wsaObj, int x, int y, int frm);
  230. int cbHOF_hand(WSAMovie_v2 *wsaObj, int x, int y, int frm);
  231. int cbHOF_point(WSAMovie_v2 *wsaObj, int x, int y, int frm);
  232. int cbHOF_zanfaun(WSAMovie_v2 *wsaObj, int x, int y, int frm);
  233. int cbHOF_over1(WSAMovie_v2 *wsaObj, int x, int y, int frm);
  234. int cbHOF_over2(WSAMovie_v2 *wsaObj, int x, int y, int frm);
  235. int cbHOF_forest(WSAMovie_v2 *wsaObj, int x, int y, int frm);
  236. int cbHOF_dragon(WSAMovie_v2 *wsaObj, int x, int y, int frm);
  237. int cbHOF_darm(WSAMovie_v2 *wsaObj, int x, int y, int frm);
  238. int cbHOF_library2(WSAMovie_v2 *wsaObj, int x, int y, int frm);
  239. int cbHOF_marco(WSAMovie_v2 *wsaObj, int x, int y, int frm);
  240. int cbHOF_hand1a(WSAMovie_v2 *wsaObj, int x, int y, int frm);
  241. int cbHOF_hand1b(WSAMovie_v2 *wsaObj, int x, int y, int frm);
  242. int cbHOF_hand1c(WSAMovie_v2 *wsaObj, int x, int y, int frm);
  243. int cbHOF_hand2(WSAMovie_v2 *wsaObj, int x, int y, int frm);
  244. int cbHOF_hand3(WSAMovie_v2 *wsaObj, int x, int y, int frm);
  245. int cbHOF_funters(WSAMovie_v2 *wsaObj, int x, int y, int frm);
  246. int cbHOF_ferb(WSAMovie_v2 *wsaObj, int x, int y, int frm);
  247. int cbHOF_fish(WSAMovie_v2 *wsaObj, int x, int y, int frm);
  248. int cbHOF_fheep(WSAMovie_v2 *wsaObj, int x, int y, int frm);
  249. int cbHOF_farmer(WSAMovie_v2 *wsaObj, int x, int y, int frm);
  250. int cbHOF_fuards(WSAMovie_v2 *wsaObj, int x, int y, int frm);
  251. int cbHOF_firates(WSAMovie_v2 *wsaObj, int x, int y, int frm);
  252. int cbHOF_frash(WSAMovie_v2 *wsaObj, int x, int y, int frm);
  253. int cbHOF_figgle(WSAMovie_v2 *wsaObj, int x, int y, int frm);
  254. int cbHOFDEMO_virgin(WSAMovie_v2 *wsaObj, int x, int y, int frm);
  255. int cbHOFDEMO_westwood(WSAMovie_v2 *wsaObj, int x, int y, int frm);
  256. int cbHOFDEMO_title(WSAMovie_v2 *wsaObj, int x, int y, int frm);
  257. int cbHOFDEMO_hill(WSAMovie_v2 *wsaObj, int x, int y, int frm);
  258. int cbHOFDEMO_outhome(WSAMovie_v2 *wsaObj, int x, int y, int frm);
  259. int cbHOFDEMO_wharf(WSAMovie_v2 *wsaObj, int x, int y, int frm);
  260. int cbHOFDEMO_dinob(WSAMovie_v2 *wsaObj, int x, int y, int frm);
  261. int cbHOFDEMO_fisher(WSAMovie_v2 *wsaObj, int x, int y, int frm);
  262. int cbHOFDEMO_wharf2(WSAMovie_v2 *wsaObj, int x, int y, int frm);
  263. int cbHOFDEMO_dinob2(WSAMovie_v2 *wsaObj, int x, int y, int frm);
  264. int cbHOFDEMO_water(WSAMovie_v2 *wsaObj, int x, int y, int frm);
  265. int cbHOFDEMO_bail(WSAMovie_v2 *wsaObj, int x, int y, int frm);
  266. int cbHOFDEMO_dig(WSAMovie_v2 *wsaObj, int x, int y, int frm);
  267. #ifdef ENABLE_LOL
  268. int cbLOLDEMO_scene1(WSAMovie_v2 *wsaObj, int x, int y, int frm);
  269. int cbLOLDEMO_scene2(WSAMovie_v2 *wsaObj, int x, int y, int frm);
  270. int cbLOLDEMO_scene3(WSAMovie_v2 *wsaObj, int x, int y, int frm);
  271. int cbLOLDEMO_scene4(WSAMovie_v2 *wsaObj, int x, int y, int frm);
  272. int cbLOLDEMO_scene5(WSAMovie_v2 *wsaObj, int x, int y, int frm);
  273. int cbLOLDEMO_text5(WSAMovie_v2 *wsaObj, int x, int y, int frm);
  274. int cbLOLDEMO_scene6(WSAMovie_v2 *wsaObj, int x, int y, int frm);
  275. #endif // ENABLE_LOL
  276. };
  277. SeqPlayer_HOF *SeqPlayer_HOF::_instance = 0;
  278. SeqPlayer_HOF::SeqPlayer_HOF(KyraEngine_v1 *vm, Screen_v2 *screen, OSystem *system, bool startupSaveLoadable) : _vm(vm), _screen(screen), _system(system), _startupSaveLoadable(startupSaveLoadable) {
  279. // We use a static pointer for pauseEngine functionality. Since we don't
  280. // ever need more than one SeqPlayer_HOF object at the same time we keep
  281. // this simple and just add an assert to detect typos, regressions, etc.
  282. assert(_instance == 0);
  283. memset(_animSlots, 0, sizeof(_animSlots));
  284. memset(_textSlots, 0, sizeof(_textSlots));
  285. memset(_hofDemoActiveItemAnim, 0, sizeof(_hofDemoActiveItemAnim));
  286. _screenHoF = _vm->game() == GI_KYRA2 ? (Screen_HoF*)screen : 0;
  287. _config = 0;
  288. _result = 0;
  289. _sequenceSoundList = 0;
  290. _hofDemoAnimData = 0;
  291. _hofDemoShapeData = 0;
  292. _isFinale = false;
  293. _preventLooping = false;
  294. _menu = 0;
  295. _abortRequested = false;
  296. _pauseStart = 0;
  297. _updateAnimations = false;
  298. _animDuration = 0;
  299. _animCurrentFrame = 0;
  300. _callbackCurrentFrame = 0;
  301. _abortPlayback = false;
  302. _curScene = 0;
  303. _preventSkipBeforeScene = -1;
  304. _lastScene = 0;
  305. _scrollProgressCounter = 0;
  306. _fisherAnimCurTime = 0;
  307. _tempString = new char[200];
  308. _countDownRemainder = 0;
  309. _countDownLastUpdate = 0;
  310. int tempSize = 0;
  311. _vm->resource()->unloadAllPakFiles();
  312. _vm->resource()->loadPakFile(StaticResource::staticDataFilename());
  313. const char *const *files = _vm->staticres()->loadStrings(k2SeqplayPakFiles, tempSize);
  314. _vm->resource()->loadFileList(files, tempSize);
  315. _sequenceStrings = _vm->staticres()->loadStrings(k2SeqplayStrings, tempSize);
  316. uint8 multiplier = (_vm->gameFlags().platform == Common::kPlatformFMTowns || _vm->gameFlags().platform == Common::kPlatformPC98) ? 12 : 8;
  317. for (int i = 0; i < MIN(33, tempSize); i++)
  318. _textDuration[i] = (int)strlen(_sequenceStrings[i]) * multiplier;
  319. if (_sequenceSoundList) {
  320. for (int i = 0; i < _sequenceSoundListSize; i++) {
  321. if (_sequenceSoundList[i])
  322. delete[] _sequenceSoundList[i];
  323. }
  324. delete[] _sequenceSoundList;
  325. _sequenceSoundList = 0;
  326. }
  327. const char *const *seqSoundList = _vm->staticres()->loadStrings(k2SeqplaySfxFiles, _sequenceSoundListSize);
  328. // replace sequence talkie files with localized versions
  329. const char *const *tlkfiles = _vm->staticres()->loadStrings(k2SeqplayTlkFiles, tempSize);
  330. char **tmpSndLst = new char *[_sequenceSoundListSize];
  331. for (int i = 0; i < _sequenceSoundListSize; i++) {
  332. const int len = strlen(seqSoundList[i]);
  333. tmpSndLst[i] = new char[len + 1];
  334. tmpSndLst[i][0] = 0;
  335. if (tlkfiles && len > 1) {
  336. for (int ii = 0; ii < tempSize; ii++) {
  337. if (strlen(tlkfiles[ii]) > 1 && !scumm_stricmp(&seqSoundList[i][1], &tlkfiles[ii][1]))
  338. strcpy(tmpSndLst[i], tlkfiles[ii]);
  339. }
  340. }
  341. if (tmpSndLst[i][0] == 0)
  342. strcpy(tmpSndLst[i], seqSoundList[i]);
  343. }
  344. tlkfiles = seqSoundList = 0;
  345. _vm->staticres()->unloadId(k2SeqplayTlkFiles);
  346. _vm->staticres()->unloadId(k2SeqplaySfxFiles);
  347. _sequenceSoundList = tmpSndLst;
  348. if (_vm->gameFlags().platform == Common::kPlatformPC98)
  349. _vm->sound()->loadSoundFile("SOUND.DAT");
  350. _screen->loadFont(_screen->FID_GOLDFONT_FNT, "GOLDFONT.FNT");
  351. _screen->setFont(_vm->gameFlags().lang == Common::JA_JPN ? Screen::FID_SJIS_FNT : Screen::FID_GOLDFONT_FNT);
  352. if (_vm->gameFlags().isDemo && !_vm->gameFlags().isTalkie) {
  353. if (_vm->game() == GI_KYRA2) {
  354. _hofDemoAnimData = _vm->staticres()->loadHoFSeqItemAnimData(k2SeqplayShapeAnimData, tempSize);
  355. uint8 *shp = _vm->resource()->fileData("ICONS.SHP", 0);
  356. uint32 outsize = READ_LE_UINT16(shp + 4);
  357. _hofDemoShapeData = new uint8[outsize];
  358. Screen::decodeFrame4(shp + 10, _hofDemoShapeData, outsize);
  359. for (int i = 0; i < 20; i++)
  360. _hofDemoItemShapes[i] = _screen->getPtrToShape(_hofDemoShapeData, i);
  361. delete[] shp;
  362. }
  363. } else {
  364. const MainMenu::StaticData data = {
  365. { _sequenceStrings[97], _sequenceStrings[96], _sequenceStrings[95], _sequenceStrings[98], 0 },
  366. { 0x01, 0x04, 0x0C, 0x04, 0x00, 0xD7, 0xD6 },
  367. { 0xD8, 0xDA, 0xD9, 0xD8 },
  368. (_vm->gameFlags().lang == Common::JA_JPN) ? Screen::FID_SJIS_FNT : Screen::FID_8_FNT, 240
  369. };
  370. _menu = new MainMenu(_vm);
  371. _menu->init(data, MainMenu::Animation());
  372. }
  373. _instance = this;
  374. }
  375. SeqPlayer_HOF::~SeqPlayer_HOF() {
  376. _instance = 0;
  377. if (_sequenceSoundList) {
  378. for (int i = 0; i < _sequenceSoundListSize; i++) {
  379. if (_sequenceSoundList[i])
  380. delete[] _sequenceSoundList[i];
  381. }
  382. delete[] _sequenceSoundList;
  383. _sequenceSoundList = NULL;
  384. }
  385. delete[] _tempString;
  386. delete[] _hofDemoShapeData;
  387. delete _menu;
  388. if (_vm->game() != GI_LOL)
  389. _screen->setFont(_vm->gameFlags().lang == Common::JA_JPN ? Screen::FID_SJIS_FNT : Screen::FID_8_FNT);
  390. }
  391. int SeqPlayer_HOF::play(SequenceID firstScene, SequenceID loopStartScene) {
  392. bool incompatibleData = false;
  393. AudioResourceSet soundSet = kMusicIntro;
  394. _firstScene = firstScene;
  395. _loopStartScene = loopStartScene;
  396. _preventLooping = false;
  397. _result = 0;
  398. if (firstScene >= kSequenceArraySize || firstScene < kSequenceVirgin || loopStartScene >= kSequenceArraySize || loopStartScene < kSequenceNoLooping) {
  399. return 0;
  400. } else if (firstScene >= kSequenceLoLDemoScene1) {
  401. #ifndef ENABLE_LOL
  402. error("SeqPlayer_HOF::play(): The Lands of Lore sub engine (including this non-interactive demo) has been disabled in this build");
  403. #endif
  404. incompatibleData = (_vm->game() != GI_LOL);
  405. _firstScene -= kSequenceLoLDemoScene1;
  406. if (loopStartScene != kSequenceNoLooping)
  407. _loopStartScene -= kSequenceLoLDemoScene1;
  408. _lastScene = kSequenceLoLDemoScene6 - kSequenceLoLDemoScene1;
  409. _target = kLoLDemo;
  410. _screen->_charWidth = 0;
  411. } else if (firstScene >= kSequenceHoFDemoVirgin) {
  412. incompatibleData = (_vm->game() != GI_KYRA2 || !_vm->gameFlags().isDemo || _vm->gameFlags().isTalkie);
  413. _firstScene -= kSequenceHoFDemoVirgin;
  414. if (loopStartScene != kSequenceNoLooping)
  415. _loopStartScene -= kSequenceHoFDemoVirgin;
  416. _lastScene = kSequenceHoFDemoFisher - kSequenceHoFDemoVirgin;
  417. _target = kHoFDemo;
  418. _screen->_charWidth = -2;
  419. } else {
  420. _isFinale = _preventLooping = firstScene > kSequenceZanfaun;
  421. incompatibleData = (_vm->game() != GI_KYRA2 || (_vm->gameFlags().isDemo && (!_vm->gameFlags().isTalkie || _isFinale)));
  422. _target = kHoF;
  423. _screen->_charWidth = -2;
  424. if (_isFinale) {
  425. soundSet = kMusicFinale;
  426. _lastScene = kSequenceFrash;
  427. } else {
  428. _lastScene = kSequenceZanfaun;
  429. }
  430. }
  431. if (incompatibleData)
  432. error("SeqPlayer_HOF::play(): Specified sequences do not match the available sequence data for this target");
  433. _vm->sound()->selectAudioResourceSet(soundSet);
  434. _vm->sound()->loadSoundFile(0);
  435. setupCallbacks();
  436. runLoop();
  437. return _result;
  438. }
  439. void SeqPlayer_HOF::pause(bool toggle) {
  440. if (toggle) {
  441. _pauseStart = _system->getMillis();
  442. } else {
  443. uint32 pausedTime = _system->getMillis() - _pauseStart;
  444. _pauseStart = 0;
  445. _countDownLastUpdate += pausedTime;
  446. _fisherAnimCurTime += pausedTime;
  447. _specialAnimTimeOutTotal += pausedTime;
  448. _specialAnimFrameTimeOut += pausedTime;
  449. for (int i = 0; i < 10; i++) {
  450. if (_textSlots[i].duration != -1)
  451. _textSlots[i].startTime += pausedTime;
  452. }
  453. for (int i = 0; i < 8; i++) {
  454. if (_animSlots[i].flags != -1)
  455. _animSlots[i].nextFrame += pausedTime;
  456. }
  457. }
  458. }
  459. void SeqPlayer_HOF::setupCallbacks() {
  460. #define SCB(x) &SeqPlayer_HOF::cbHOF_##x
  461. static const SeqProc seqCallbacksHoF[] = { 0, SCB(westwood), SCB(title), SCB(overview), SCB(library), SCB(hand), SCB(point), SCB(zanfaun), SCB(funters), SCB(ferb), SCB(fish), SCB(fheep), SCB(farmer), SCB(fuards), SCB(firates), SCB(frash) };
  462. static const SeqProc nestedSeqCallbacksHoF[] = { SCB(figgle), SCB(over1), SCB(over2), SCB(forest), SCB(dragon), SCB(darm), SCB(library2), SCB(library2), SCB(marco), SCB(hand1a), SCB(hand1b), SCB(hand1c), SCB(hand2), SCB(hand3), 0 };
  463. #undef SCB
  464. #define SCB(x) &SeqPlayer_HOF::cbHOFDEMO_##x
  465. static const SeqProc seqCallbacksHoFDemo[] = { SCB(virgin), SCB(westwood), SCB(title), SCB(hill), SCB(outhome), SCB(wharf), SCB(dinob), SCB(fisher) };
  466. static const SeqProc nestedSeqCallbacksHoFDemo[] = { SCB(wharf2), SCB(dinob2), SCB(water), SCB(bail), SCB(dig), 0 };
  467. #undef SCB
  468. #ifdef ENABLE_LOL
  469. #define SCB(x) &SeqPlayer_HOF::cbLOLDEMO_##x
  470. static const SeqProc seqCallbacksLoLDemo[] = { SCB(scene1), 0, SCB(scene2), 0, SCB(scene3), 0, SCB(scene4), 0, SCB(scene5), SCB(text5), SCB(scene6), 0 };
  471. #undef SCB
  472. #else
  473. static const SeqProc seqCallbacksLoLDemo[] = { 0 };
  474. #endif
  475. static const SeqProc nestedSeqCallbacksLoLDemo[] = { 0 };
  476. static const SeqProc *const seqCallbacks[] = { seqCallbacksHoF, seqCallbacksHoFDemo, seqCallbacksLoLDemo};
  477. static const SeqProc *const nestedSeqCallbacks[] = { nestedSeqCallbacksHoF, nestedSeqCallbacksHoFDemo, nestedSeqCallbacksLoLDemo};
  478. int tmpSize = 0;
  479. delete _config;
  480. _config = new SeqPlayerConfig(_vm->staticres()->loadHoFSequenceData(k2SeqplaySeqData, tmpSize), seqCallbacks[_target], nestedSeqCallbacks[_target]);
  481. }
  482. void SeqPlayer_HOF::runLoop() {
  483. memset(_animSlots, 0, sizeof(_animSlots));
  484. memset(_textSlots, 0, sizeof(_textSlots));
  485. memset(_hofDemoActiveItemAnim, 0, sizeof(_hofDemoActiveItemAnim));
  486. for (int i = 0; i < 8; ++i)
  487. _animSlots[i].flags = -1;
  488. _screen->clearPage(10);
  489. _screen->clearPage(12);
  490. _screen->hideMouse();
  491. int oldPage = _screen->setCurPage(2);
  492. for (int i = 0; i < 4; ++i)
  493. _screen->getPalette(i).clear();
  494. _updateAnimations = false;
  495. _animCurrentFrame = 0;
  496. _textColor[0] = _textColor[1] = 0;
  497. _curScene = _firstScene;
  498. do {
  499. playScenes();
  500. doTransition(0);
  501. resetAllTextSlots();
  502. fadeOutMusic();
  503. _firstScene = ((!_startupSaveLoadable || _preventLooping) && _curScene >= _loopStartScene) ? kSequenceNoLooping : _loopStartScene;
  504. } while (!_vm->shouldQuit() && _firstScene != kSequenceNoLooping);
  505. checkPlaybackStatus();
  506. for (int i = 0; i < 8; i++)
  507. unloadNestedAnimation(i);
  508. if (_vm->gameFlags().isDemo && !_vm->gameFlags().isTalkie)
  509. _screen->fadeToBlack();
  510. else if (!_isFinale && !_startupSaveLoadable)
  511. _result = 1;
  512. if (!_result)
  513. delayTicks(75);
  514. _screen->setCurPage(oldPage);
  515. _screen->_charWidth = 0;
  516. _screen->showMouse();
  517. }
  518. void SeqPlayer_HOF::playScenes() {
  519. _vm->sound()->stopAllSoundEffects();
  520. _curScene = _firstScene;
  521. _screen->copyPalette(1, 0);
  522. WSAMovie_v2 anim(_vm);
  523. _abortRequested = false;
  524. _scrollProgressCounter = 0;
  525. while (!_vm->shouldQuit()) {
  526. if (checkAbortPlayback())
  527. if (checkPlaybackStatus())
  528. break;
  529. _callbackCurrentFrame = 0;
  530. if (_curScene > _lastScene)
  531. break;
  532. const Kyra::HoFSequence &sq = _config->seq[_curScene];
  533. if (sq.flags & 2) {
  534. _screen->loadBitmap(sq.cpsFile, 2, 2, &_screen->getPalette(0));
  535. _screen->setScreenPalette(_screen->getPalette(0));
  536. } else {
  537. _screen->setCurPage(2);
  538. _screen->clearPage(2);
  539. _screen->loadPalette("GOLDFONT.COL", _screen->getPalette(0));
  540. }
  541. if (_config->seqProc[_curScene] && !(_vm->gameFlags().isDemo && !_vm->gameFlags().isTalkie))
  542. (this->*_config->seqProc[_curScene])(0, 0, 0, -1);
  543. if (sq.flags & 1) {
  544. anim.open(sq.wsaFile, 0, &_screen->getPalette(0));
  545. if (!(sq.flags & 2))
  546. anim.displayFrame(0, 2, sq.xPos, sq.yPos, 0x4000, 0, 0);
  547. }
  548. if (sq.flags & 4) {
  549. int cp = _screen->setCurPage(2);
  550. Screen::FontId cf = _screen->setFont(_vm->gameFlags().lang == Common::JA_JPN ? Screen::FID_SJIS_FNT : Screen::FID_GOLDFONT_FNT);
  551. if (sq.stringIndex1 != -1)
  552. _screen->printText(_sequenceStrings[sq.stringIndex1], (320 - _screen->getTextWidth(_sequenceStrings[sq.stringIndex1])) / 2, 100 - _screen->getFontHeight(), 1, 0);
  553. if (sq.stringIndex2 != -1)
  554. _screen->printText(_sequenceStrings[sq.stringIndex2], (320 - _screen->getTextWidth(_sequenceStrings[sq.stringIndex2])) / 2, 100, 1, 0);
  555. _screen->setFont(cf);
  556. _screen->setCurPage(cp);
  557. }
  558. _screen->copyPage(2, 12);
  559. _screen->copyPage(0, 2);
  560. _screen->copyPage(2, 10);
  561. _screen->copyPage(12, 2);
  562. doTransition(sq.fadeInTransitionType);
  563. if (!(checkAbortPlayback() || _vm->shouldQuit() || _result)) {
  564. _screen->copyPage(2, 0);
  565. _screen->updateScreen();
  566. }
  567. if (sq.flags & 1) {
  568. playAnimation(&anim, sq.startFrame, sq.numFrames, sq.duration, sq.xPos, sq.yPos, _config->seqProc[_curScene], &_screen->getPalette(1), &_screen->getPalette(0), 30, 0);
  569. anim.close();
  570. } else {
  571. _animDuration = sq.duration;
  572. setCountDown(_animDuration);
  573. while (!checkAbortPlayback() && !_vm->shouldQuit() && (countDownRunning() || _updateAnimations)) {
  574. uint32 endFrame = (_system->getMillis() + _vm->tickLength()) & ~(_vm->tickLength() - 1);
  575. updateAllNestedAnimations();
  576. if (_config->seqProc[_curScene])
  577. (this->*_config->seqProc[_curScene])(0, 0, 0, 0);
  578. updateSubTitles();
  579. _screen->copyPage(2, 0);
  580. _screen->updateScreen();
  581. _screen->copyPage(12, 2);
  582. do {
  583. if (checkAbortPlayback())
  584. if (checkPlaybackStatus())
  585. break;
  586. } while (_system->getMillis() < endFrame);
  587. }
  588. }
  589. if (_config->seqProc[_curScene] && !(_vm->gameFlags().isDemo && !_vm->gameFlags().isTalkie))
  590. (this->*_config->seqProc[_curScene])(0, 0, 0, -2);
  591. uint32 textTimeOut = ticksTillSubTitlesTimeout();
  592. setCountDown(sq.timeout < textTimeOut ? textTimeOut : sq.timeout);
  593. while (!checkAbortPlayback() && !_vm->shouldQuit() && (countDownRunning() || _updateAnimations)) {
  594. updateAllNestedAnimations();
  595. _screen->copyPage(2, 0);
  596. _screen->updateScreen();
  597. _screen->copyPage(12, 2);
  598. }
  599. doTransition(sq.fadeOutTransitionType);
  600. _curScene++;
  601. }
  602. resetAllTextSlots();
  603. _vm->sound()->haltTrack();
  604. _vm->sound()->voiceStop();
  605. if ((!checkAbortPlayback() || _vm->shouldQuit()) && _vm->gameFlags().isDemo)
  606. _curScene = -1;
  607. }
  608. bool SeqPlayer_HOF::checkAbortPlayback() {
  609. Common::Event event;
  610. if (_vm->skipFlag()) {
  611. _abortRequested = true;
  612. _vm->resetSkipFlag();
  613. }
  614. if (_abortRequested)
  615. return true;
  616. while (_system->getEventManager()->pollEvent(event)) {
  617. switch (event.type) {
  618. case Common::EVENT_KEYDOWN:
  619. if (event.kbd.keycode == Common::KEYCODE_q && event.kbd.hasFlags(Common::KBD_CTRL)) {
  620. _abortRequested = true;
  621. _vm->quitGame();
  622. return true;
  623. } else if (event.kbd.keycode != Common::KEYCODE_ESCAPE && event.kbd.keycode != Common::KEYCODE_RETURN && event.kbd.keycode != Common::KEYCODE_SPACE) {
  624. continue;
  625. }
  626. // fall through
  627. case Common::EVENT_LBUTTONDOWN:
  628. case Common::EVENT_RBUTTONDOWN:
  629. case Common::EVENT_LBUTTONUP:
  630. case Common::EVENT_RBUTTONUP:
  631. _abortRequested = true;
  632. return true;
  633. default:
  634. break;
  635. }
  636. }
  637. return false;
  638. }
  639. bool SeqPlayer_HOF::checkPlaybackStatus() {
  640. _updateAnimations = false;
  641. if (_curScene <= _preventSkipBeforeScene || (_curScene == _loopStartScene && !_isFinale)) {
  642. _abortRequested = false;
  643. return false;
  644. }
  645. if (_loopStartScene == kSequenceNoLooping) {
  646. doTransition(0);
  647. fadeOutMusic();
  648. _abortPlayback = true;
  649. }
  650. return true;
  651. }
  652. void SeqPlayer_HOF::doTransition(int type) {
  653. for (int i = 0; i < 8; i++)
  654. closeNestedAnimation(i);
  655. switch (type) {
  656. case 0:
  657. _screen->fadeToBlack(36);
  658. _screen->getPalette(0).clear();
  659. _screen->getPalette(1).clear();
  660. break;
  661. case 1:
  662. playSoundAndDisplaySubTitle(_vm->_rnd.getRandomBit());
  663. _screen->getPalette(0).fill(0, 256, 0x3F);
  664. _screen->fadePalette(_screen->getPalette(0), 16);
  665. _screen->copyPalette(1, 0);
  666. break;
  667. case 3:
  668. _screen->copyPage(2, 0);
  669. _screen->fadePalette(_screen->getPalette(0), 16);
  670. _screen->copyPalette(1, 0);
  671. break;
  672. case 4:
  673. _screen->copyPage(2, 0);
  674. _screen->fadePalette(_screen->getPalette(0), 36);
  675. _screen->copyPalette(1, 0);
  676. break;
  677. case 5:
  678. _screen->copyPage(2, 0);
  679. break;
  680. case 6:
  681. // UNUSED
  682. // seq_loadBLD("library.bld");
  683. break;
  684. case 7:
  685. // UNUSED
  686. // seq_loadBLD("marco.bld");
  687. break;
  688. case 8:
  689. _screen->fadeToBlack(16);
  690. _screen->getPalette(0).clear();
  691. _screen->getPalette(1).clear();
  692. delayTicks(120);
  693. break;
  694. case 9: {
  695. Palette &pal = _screen->getPalette(0);
  696. for (int i = 0; i < 255; i++)
  697. pal.fill(i, 1, (pal[3 * i] + pal[3 * i + 1] + pal[3 * i + 2]) / 3);
  698. pal.fill(255, 1, 0x3F);
  699. _screen->fadePalette(pal, 64);
  700. _screen->copyPalette(1, 0);
  701. } break;
  702. default:
  703. break;
  704. }
  705. }
  706. void SeqPlayer_HOF::nestedFrameAnimTransition(int srcPage, int dstPage, int delaytime, int steps, int x, int y, int w, int h, int openClose, int directionFlags) {
  707. if (openClose) {
  708. for (int i = 1; i < steps; i++) {
  709. uint32 endtime = _system->getMillis() + delaytime * _vm->tickLength();
  710. int w2 = (((w * 256) / steps) * i) / 256;
  711. int h2 = (((h * 256) / steps) * i) / 256;
  712. int ym = (directionFlags & 2) ? (h - h2) : 0;
  713. int xm = (directionFlags & 1) ? (w - w2) : 0;
  714. _screen->wsaFrameAnimationStep(0, 0, x + xm, y + ym, w, h, w2, h2, srcPage, dstPage, 0);
  715. _screen->copyPage(dstPage, 6);
  716. _screen->copyPage(dstPage, 0);
  717. _screen->updateScreen();
  718. _screen->copyPage(12, dstPage);
  719. delayUntil(endtime);
  720. }
  721. _screen->wsaFrameAnimationStep(0, 0, x, y, w, h, w, h, srcPage, dstPage, 0);
  722. _screen->copyPage(dstPage, 6);
  723. _screen->copyPage(dstPage, 0);
  724. _screen->updateScreen();
  725. } else {
  726. _screen->copyPage(12, dstPage);
  727. for (int i = steps; i; i--) {
  728. uint32 endtime = _system->getMillis() + delaytime * _vm->tickLength();
  729. int w2 = (((w * 256) / steps) * i) / 256;
  730. int h2 = (((h * 256) / steps) * i) / 256;
  731. int ym = (directionFlags & 2) ? (h - h2) : 0;
  732. int xm = (directionFlags & 1) ? (w - w2) : 0;
  733. _screen->wsaFrameAnimationStep(0, 0, x + xm, y + ym, w, h, w2, h2, srcPage, dstPage, 0);
  734. _screen->copyPage(dstPage, 6);
  735. _screen->copyPage(dstPage, 0);
  736. _screen->updateScreen();
  737. _screen->copyPage(12, dstPage);
  738. delayUntil(endtime);
  739. }
  740. }
  741. }
  742. void SeqPlayer_HOF::nestedFrameFadeTransition(const char *cmpFile) {
  743. _screen->copyPage(10, 2);
  744. _screen->copyPage(4, 10);
  745. _screen->clearPage(6);
  746. _screen->loadBitmap(cmpFile, 6, 6, 0);
  747. _screen->copyPage(12, 4);
  748. for (int i = 0; i < 3; i++) {
  749. uint32 endtime = _system->getMillis() + 4 * _vm->tickLength();
  750. assert(_screenHoF);
  751. _screenHoF->cmpFadeFrameStep(4, 320, 200, 0, 0, 2, 320, 200, 0, 0, 320, 200, 6);
  752. _screen->copyRegion(0, 0, 0, 0, 320, 200, 2, 0);
  753. _screen->updateScreen();
  754. delayUntil(endtime);
  755. }
  756. _screen->copyPage(4, 0);
  757. _screen->updateScreen();
  758. _screen->copyPage(4, 2);
  759. _screen->copyPage(4, 6);
  760. _screen->copyPage(10, 4);
  761. }
  762. void SeqPlayer_HOF::playAnimation(WSAMovie_v2 *wsaObj, int startFrame, int lastFrame, int frameRate, int x, int y, const SeqProc callback, Palette *fadePal1, Palette *fadePal2, int fadeRate, bool restoreScreen) {
  763. bool finished = false;
  764. uint32 startTime = _system->getMillis();
  765. int origW = wsaObj ? wsaObj->width() : 0;
  766. int origH = wsaObj ? wsaObj->height() : 0;
  767. int drwX = x;
  768. int drwY = y;
  769. int drwW = origW;
  770. int drwH = origH;
  771. _animDuration = frameRate;
  772. if (wsaObj) {
  773. if (x < 0) {
  774. drwW += x;
  775. drwX = 0;
  776. }
  777. if (y < 0) {
  778. drwH += y;
  779. drwY = 0;
  780. }
  781. if (x + origW > 319)
  782. origW = 320 - x;
  783. if (y + origH > 199)
  784. origW = 200 - y;
  785. }
  786. int8 frameStep = (startFrame > lastFrame) ? -1 : 1;
  787. _animCurrentFrame = startFrame;
  788. while (!_vm->shouldQuit() && !finished) {
  789. if (checkAbortPlayback())
  790. if (checkPlaybackStatus())
  791. break;
  792. setCountDown(_animDuration);
  793. if (wsaObj || callback)
  794. _screen->copyPage(12, 2);
  795. int frameIndex = _animCurrentFrame;
  796. if (wsaObj)
  797. frameIndex %= wsaObj->frames();
  798. if (callback)
  799. (this->*callback)(wsaObj, x, y, frameIndex);
  800. if (wsaObj)
  801. wsaObj->displayFrame(frameIndex, 2, x, y, 0, 0, 0);
  802. _screen->copyPage(2, 12);
  803. updateAllNestedAnimations();
  804. updateSubTitles();
  805. if ((wsaObj || callback) && (!(checkAbortPlayback() || _vm->shouldQuit() || _result))) {
  806. _screen->copyPage(2, 0);
  807. _screen->updateScreen();
  808. }
  809. while (!_vm->shouldQuit()) {
  810. if (checkAbortPlayback())
  811. if (checkPlaybackStatus())
  812. break;
  813. if (fadePal1 && fadePal2) {
  814. if (!_screen->timedPaletteFadeStep(fadePal1->getData(), fadePal2->getData(), _system->getMillis() - startTime, fadeRate * _vm->tickLength()) && !wsaObj)
  815. break;
  816. }
  817. if ((wsaObj || callback) && (!(checkAbortPlayback() || _vm->shouldQuit() || _result))) {
  818. _screen->copyPage(2, 0);
  819. _screen->updateScreen();
  820. }
  821. updateSubTitles();
  822. if (!countDownRunning())
  823. break;
  824. }
  825. if (wsaObj) {
  826. _animCurrentFrame += frameStep;
  827. if ((frameStep > 0 && _animCurrentFrame >= lastFrame) || (frameStep < 0 && _animCurrentFrame < lastFrame))
  828. finished = true;
  829. }
  830. if (restoreScreen && (wsaObj || callback)) {
  831. _screen->copyPage(12, 2);
  832. _screen->copyRegion(drwX, drwY, drwX, drwY, drwW, drwH, 2, 0, Screen::CR_NO_P_CHECK);
  833. _screen->updateScreen();
  834. }
  835. }
  836. }
  837. void SeqPlayer_HOF::playDialogueAnimation(uint16 strID, uint16 soundID, int textColor, int textPosX, int textPosY, int textWidth, WSAMovie_v2 *wsaObj, int animStartFrame, int animLastFrame, int animPosX, int animPosY) {
  838. int dur = int(strlen(_sequenceStrings[strID])) * (_vm->gameFlags().isTalkie ? 7 : 15);
  839. if (_vm->textEnabled()) {
  840. int slot = displaySubTitle(strID, textPosX, textPosY, dur, textWidth);
  841. if (slot >= 0)
  842. _textSlots[slot].textcolor = textColor;
  843. }
  844. _specialAnimTimeOutTotal = _system->getMillis() + dur * _vm->tickLength();
  845. int curframe = animStartFrame;
  846. if (soundID && _vm->speechEnabled()) {
  847. while (_vm->sound()->voiceIsPlaying() && !_abortPlayback)
  848. delayTicks(1);
  849. playSoundAndDisplaySubTitle(soundID);
  850. }
  851. while (_system->getMillis() < _specialAnimTimeOutTotal && !_abortPlayback) {
  852. if (animLastFrame < 0) {
  853. int t = ABS(animLastFrame);
  854. if (t < curframe)
  855. curframe = t;
  856. }
  857. if (ABS(animLastFrame) < curframe)
  858. curframe = animStartFrame;
  859. _specialAnimFrameTimeOut = _system->getMillis() + _animDuration * _vm->tickLength();
  860. setCountDown(_animDuration);
  861. if (wsaObj)
  862. wsaObj->displayFrame(curframe % wsaObj->frames(), 2, animPosX, animPosY, 0, 0, 0);
  863. _screen->copyPage(2, 12);
  864. updateSubTitles();
  865. delayUntil(MIN(_specialAnimFrameTimeOut, _specialAnimTimeOutTotal));
  866. if (_vm->speechEnabled() && !_vm->textEnabled() && !_vm->snd_voiceIsPlaying())
  867. break;
  868. if (checkAbortPlayback())
  869. if (checkPlaybackStatus())
  870. break;
  871. _screen->copyPage(2, 0);
  872. _screen->updateScreen();
  873. curframe++;
  874. }
  875. if (_abortPlayback)
  876. _vm->sound()->voiceStop();
  877. if (ABS(animLastFrame) < curframe)
  878. curframe = ABS(animLastFrame);
  879. if (curframe == animStartFrame)
  880. curframe++;
  881. _animCurrentFrame = curframe;
  882. }
  883. void SeqPlayer_HOF::startNestedAnimation(int animSlot, int sequenceID) {
  884. if (_animSlots[animSlot].flags != -1)
  885. return;
  886. if (_target == kLoLDemo) {
  887. return;
  888. } else if (_target == kHoFDemo) {
  889. assert(sequenceID >= kNestedSequenceHoFDemoWharf2);
  890. sequenceID -= kNestedSequenceHoFDemoWharf2;
  891. }
  892. HoFNestedSequence s = _config->nestedSeq[sequenceID];
  893. if (!_animSlots[animSlot].movie) {
  894. _animSlots[animSlot].movie = new WSAMovie_v2(_vm);
  895. assert(_animSlots[animSlot].movie);
  896. }
  897. _animSlots[animSlot].movie->close();
  898. _animSlots[animSlot].movie->open(s.wsaFile, 0, 0);
  899. if (!_animSlots[animSlot].movie->opened()) {
  900. delete _animSlots[animSlot].movie;
  901. _animSlots[animSlot].movie = 0;
  902. return;
  903. }
  904. _animSlots[animSlot].endFrame = s.endFrame;
  905. _animSlots[animSlot].startFrame = _animSlots[animSlot].currentFrame = s.startframe;
  906. _animSlots[animSlot].frameDelay = s.frameDelay;
  907. _animSlots[animSlot].callback = _config->nestedSeqProc[sequenceID];
  908. _animSlots[animSlot].control = s.wsaControl;
  909. _animSlots[animSlot].flags = s.flags | 1;
  910. _animSlots[animSlot].x = s.x;
  911. _animSlots[animSlot].y = s.y;
  912. _animSlots[animSlot].fadeInTransitionType = s.fadeInTransitionType;
  913. _animSlots[animSlot].fadeOutTransitionType = s.fadeOutTransitionType;
  914. _animSlots[animSlot].lastFrame = 0xFFFF;
  915. doNestedFrameTransition(s.fadeInTransitionType, animSlot);
  916. if (!s.fadeInTransitionType)
  917. updateNestedAnimation(animSlot);
  918. _animSlots[animSlot].nextFrame = _system->getMillis() & ~(_vm->tickLength() - 1);
  919. }
  920. void SeqPlayer_HOF::closeNestedAnimation(int animSlot) {
  921. if (_animSlots[animSlot].flags == -1)
  922. return;
  923. _animSlots[animSlot].flags = -1;
  924. doNestedFrameTransition(_animSlots[animSlot].fadeOutTransitionType, animSlot);
  925. _animSlots[animSlot].movie->close();
  926. }
  927. void SeqPlayer_HOF::unloadNestedAnimation(int animSlot) {
  928. if (_animSlots[animSlot].movie) {
  929. _animSlots[animSlot].movie->close();
  930. delete _animSlots[animSlot].movie;
  931. _animSlots[animSlot].movie = 0;
  932. }
  933. }
  934. void SeqPlayer_HOF::doNestedFrameTransition(int transitionType, int animSlot) {
  935. int xa = 0, ya = 0;
  936. transitionType--;
  937. if (!_animSlots[animSlot].movie || _abortPlayback || _vm->shouldQuit())
  938. return;
  939. switch (transitionType) {
  940. case 0:
  941. xa = -_animSlots[animSlot].movie->xAdd();
  942. ya = -_animSlots[animSlot].movie->yAdd();
  943. _animSlots[animSlot].movie->displayFrame(0, 8, xa, ya, 0, 0, 0);
  944. nestedFrameAnimTransition(8, 2, 7, 8, _animSlots[animSlot].movie->xAdd(), _animSlots[animSlot].movie->yAdd(),
  945. _animSlots[animSlot].movie->width(), _animSlots[animSlot].movie->height(), 1, 2);
  946. break;
  947. case 1:
  948. xa = -_animSlots[animSlot].movie->xAdd();
  949. ya = -_animSlots[animSlot].movie->yAdd();
  950. _animSlots[animSlot].movie->displayFrame(0, 8, xa, ya, 0, 0, 0);
  951. nestedFrameAnimTransition(8, 2, 7, 8, _animSlots[animSlot].movie->xAdd(), _animSlots[animSlot].movie->yAdd(),
  952. _animSlots[animSlot].movie->width(), _animSlots[animSlot].movie->height(), 1, 1);
  953. break;
  954. case 2:
  955. waitForSubTitlesTimeout();
  956. xa = -_animSlots[animSlot].movie->xAdd();
  957. ya = -_animSlots[animSlot].movie->yAdd();
  958. _animSlots[animSlot].movie->displayFrame(21, 8, xa, ya, 0, 0, 0);
  959. nestedFrameAnimTransition(8, 2, 7, 8, _animSlots[animSlot].movie->xAdd(), _animSlots[animSlot].movie->yAdd(),
  960. _animSlots[animSlot].movie->width(), _animSlots[animSlot].movie->height(), 0, 2);
  961. break;
  962. case 3:
  963. _screen->copyPage(2, 10);
  964. _animSlots[animSlot].movie->displayFrame(0, 2, 0, 0, 0, 0, 0);
  965. _screen->copyPage(2, 12);
  966. nestedFrameFadeTransition("scene2.cmp");
  967. break;
  968. case 4:
  969. _screen->copyPage(2, 10);
  970. _animSlots[animSlot].movie->displayFrame(0, 2, 0, 0, 0, 0, 0);
  971. _screen->copyPage(2, 12);
  972. nestedFrameFadeTransition("scene3.cmp");
  973. break;
  974. default:
  975. break;
  976. }
  977. }
  978. void SeqPlayer_HOF::updateAllNestedAnimations() {
  979. for (int i = 0; i < 8; i++) {
  980. if (_animSlots[i].flags != -1) {
  981. if (updateNestedAnimation(i))
  982. closeNestedAnimation(i);
  983. }
  984. }
  985. }
  986. bool SeqPlayer_HOF::updateNestedAnimation(int animSlot) {
  987. uint16 currentFrame = _animSlots[animSlot].currentFrame;
  988. uint32 curTick = _system->getMillis() & ~(_vm->tickLength() - 1);
  989. if (_animSlots[animSlot].callback && currentFrame != _animSlots[animSlot].lastFrame) {
  990. _animSlots[animSlot].lastFrame = currentFrame;
  991. currentFrame = (this->*_animSlots[animSlot].callback)(_animSlots[animSlot].movie, _animSlots[animSlot].x, _animSlots[animSlot].y, currentFrame);
  992. }
  993. if (_animSlots[animSlot].movie) {
  994. if (_animSlots[animSlot].flags & 0x20) {
  995. _animSlots[animSlot].movie->displayFrame(_animSlots[animSlot].control[currentFrame].index, 2, _animSlots[animSlot].x, _animSlots[animSlot].y, 0x4000, 0, 0);
  996. _animSlots[animSlot].frameDelay = _animSlots[animSlot].control[currentFrame].delay;
  997. } else {
  998. _animSlots[animSlot].movie->displayFrame(currentFrame % _animSlots[animSlot].movie->frames(), 2, _animSlots[animSlot].x, _animSlots[animSlot].y, 0x4000, 0, 0);
  999. }
  1000. }
  1001. if (_animSlots[animSlot].flags & 0x10) {
  1002. currentFrame = (curTick - _animSlots[animSlot].nextFrame) / (_animSlots[animSlot].frameDelay * _vm->tickLength());
  1003. } else {
  1004. int diff = (curTick - _animSlots[animSlot].nextFrame) / (_animSlots[animSlot].frameDelay * _vm->tickLength());
  1005. if (diff > 0) {
  1006. currentFrame++;
  1007. if (_vm->gameFlags().platform == Common::kPlatformFMTowns || _vm->gameFlags().platform == Common::kPlatformPC98)
  1008. _animSlots[animSlot].nextFrame += ((curTick - _animSlots[animSlot].nextFrame) * 2 / 3);
  1009. else
  1010. _animSlots[animSlot].nextFrame = curTick;
  1011. }
  1012. }
  1013. bool res = false;
  1014. if (currentFrame >= _animSlots[animSlot].endFrame) {
  1015. int sw = ((_animSlots[animSlot].flags & 0x1E) - 2);
  1016. switch (sw) {
  1017. case 0:
  1018. res = true;
  1019. currentFrame = _animSlots[animSlot].endFrame;
  1020. _screen->copyPage(2, 12);
  1021. break;
  1022. case 6:
  1023. case 8:
  1024. currentFrame = _animSlots[animSlot].endFrame - 1;
  1025. break;
  1026. case 2:
  1027. case 10:
  1028. currentFrame = _animSlots[animSlot].startFrame;
  1029. break;
  1030. default:
  1031. currentFrame = _animSlots[animSlot].endFrame - 1;
  1032. res = true;
  1033. }
  1034. }
  1035. _animSlots[animSlot].currentFrame = currentFrame;
  1036. return res;
  1037. }
  1038. void SeqPlayer_HOF::playSoundEffect(uint16 id, int16 vol) {
  1039. assert(id < _sequenceSoundListSize);
  1040. _vm->sound()->voicePlay(_sequenceSoundList[id], 0, vol);
  1041. }
  1042. void SeqPlayer_HOF::playSoundAndDisplaySubTitle(uint16 id) {
  1043. assert(id < _sequenceSoundListSize);
  1044. if (id < 12 && !_vm->gameFlags().isDemo && _vm->textEnabled())
  1045. displaySubTitle(id, 160, 168, _textDuration[id], 160);
  1046. _vm->sound()->voicePlay(_sequenceSoundList[id], 0);
  1047. }
  1048. void SeqPlayer_HOF::printFadingText(uint16 strID, int x, int y, const uint8 *colorMap, uint8 textcolor) {
  1049. uint8 cmap[16];
  1050. if (checkAbortPlayback())
  1051. checkPlaybackStatus();
  1052. if (_abortPlayback || _abortRequested || _vm->shouldQuit() || _result)
  1053. return;
  1054. Screen::FontId of = _screen->setFont(Screen::FID_8_FNT);
  1055. _screen->getPalette(0).fill(254, 2, 63);
  1056. _screen->setPaletteIndex(252, 63, 32, 48);
  1057. cmap[0] = colorMap[0];
  1058. cmap[1] = 253;
  1059. memcpy(&cmap[2], &colorMap[2], 14);
  1060. uint8 col0 = _textColor[0];
  1061. _textColor[0] = 253;
  1062. _screen->setTextColorMap(cmap);
  1063. resetAllTextSlots();
  1064. displaySubTitle(strID, x, y, 128, 120);
  1065. updateSubTitles();
  1066. _screen->copyPage(2, 0);
  1067. _screen->updateScreen();
  1068. _screen->getPalette(0).copy(_screen->getPalette(0), textcolor, 1, 253);
  1069. _screen->fadePalette(_screen->getPalette(0), 24);
  1070. _textColor[0] = textcolor;
  1071. _screen->setTextColorMap(colorMap);
  1072. resetAllTextSlots();
  1073. displaySubTitle(strID, x, y, 128, 120);
  1074. updateSubTitles();
  1075. _screen->copyPage(2, 0);
  1076. _screen->updateScreen();
  1077. _screen->getPalette(0).fill(253, 1, 0);
  1078. _screen->fadePalette(_screen->getPalette(0), 1);
  1079. _screen->copyPage(2, 12);
  1080. resetAllTextSlots();
  1081. _textColor[0] = col0;
  1082. _screen->setFont(of);
  1083. }
  1084. int SeqPlayer_HOF::displaySubTitle(uint16 strIndex, uint16 posX, uint16 posY, int duration, uint16 width) {
  1085. for (int i = 0; i < 10; i++) {
  1086. if (_textSlots[i].duration != -1) {
  1087. if (i < 9)
  1088. continue;
  1089. else
  1090. return -1;
  1091. }
  1092. _textSlots[i].strIndex = strIndex;
  1093. _textSlots[i].x = posX;
  1094. _textSlots[i].y = posY;
  1095. _textSlots[i].duration = duration * _vm->tickLength();
  1096. _textSlots[i].width = width;
  1097. _textSlots[i].startTime = _system->getMillis();
  1098. _textSlots[i].textcolor = -1;
  1099. return i;
  1100. }
  1101. return -1;
  1102. }
  1103. void SeqPlayer_HOF::updateSubTitles() {
  1104. int curPage = _screen->setCurPage(2);
  1105. char outputStr[70];
  1106. for (int i = 0; i < 10; i++) {
  1107. if (_textSlots[i].startTime + _textSlots[i].duration > _system->getMillis() && _textSlots[i].duration != -1) {
  1108. char *srcStr = preprocessString(_sequenceStrings[_textSlots[i].strIndex], _textSlots[i].width);
  1109. int yPos = _textSlots[i].y;
  1110. while (*srcStr) {
  1111. uint32 linePos = 0;
  1112. for (; *srcStr; linePos++) {
  1113. if (*srcStr == '\r')
  1114. break;
  1115. outputStr[linePos] = *srcStr;
  1116. srcStr++;
  1117. }
  1118. outputStr[linePos] = 0;
  1119. if (*srcStr == '\r')
  1120. srcStr++;
  1121. uint8 textColor = (_textSlots[i].textcolor >= 0) ? _textSlots[i].textcolor : _textColor[0];
  1122. _screen->printText(outputStr, _textSlots[i].x - (_screen->getTextWidth(outputStr) / 2), yPos, textColor, 0);
  1123. yPos += 10;
  1124. }
  1125. } else {
  1126. _textSlots[i].duration = -1;
  1127. }
  1128. }
  1129. _screen->setCurPage(curPage);
  1130. }
  1131. char *SeqPlayer_HOF::preprocessString(const char *srcStr, int width) {
  1132. char *dstStr = _tempString;
  1133. int lineStart = 0;
  1134. int linePos = 0;
  1135. while (*srcStr) {
  1136. while (*srcStr && *srcStr != ' ')
  1137. dstStr[lineStart + linePos++] = *srcStr++;
  1138. dstStr[lineStart + linePos] = 0;
  1139. int len = _screen->getTextWidth(&dstStr[lineStart]);
  1140. if (width >= len && *srcStr) {
  1141. dstStr[lineStart + linePos++] = *srcStr++;
  1142. } else {
  1143. dstStr[lineStart + linePos] = '\r';
  1144. lineStart += linePos + 1;
  1145. linePos = 0;
  1146. if (*srcStr)
  1147. srcStr++;
  1148. }
  1149. }
  1150. dstStr[lineStart + linePos] = 0;
  1151. return strlen(_tempString) ? dstStr : 0;
  1152. }
  1153. void SeqPlayer_HOF::waitForSubTitlesTimeout() {
  1154. uint32 timeOut = _system->getMillis() + ticksTillSubTitlesTimeout() * _vm->tickLength();
  1155. if (_vm->textEnabled()) {
  1156. delayUntil(timeOut);
  1157. } else if (_vm->speechEnabled()) {
  1158. while (_vm->snd_voiceIsPlaying())
  1159. delayTicks(1);
  1160. }
  1161. resetAllTextSlots();
  1162. }
  1163. uint32 SeqPlayer_HOF::ticksTillSubTitlesTimeout() {
  1164. uint32 longest = 0;
  1165. for (int i = 0; i < 10; i++) {
  1166. uint32 timeOut = (_textSlots[i].duration + _textSlots[i].startTime);
  1167. uint32 curtime = _system->getMillis();
  1168. if (_textSlots[i].duration != -1 && timeOut > curtime) {
  1169. timeOut -= curtime;
  1170. if (longest < timeOut)
  1171. longest = timeOut;
  1172. }
  1173. }
  1174. uint32 tl = _vm->tickLength();
  1175. return (longest + (tl - 1)) / tl;
  1176. }
  1177. void SeqPlayer_HOF::resetAllTextSlots() {
  1178. for (int i = 0; i < 10; i++)
  1179. _textSlots[i].duration = -1;
  1180. }
  1181. void SeqPlayer_HOF::fadeOutMusic() {
  1182. _vm->sound()->beginFadeOut();
  1183. delayTicks(80);
  1184. }
  1185. void SeqPlayer_HOF::playHoFTalkieCredits() {
  1186. static const uint8 colormap[] = {0, 0, 102, 102, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
  1187. static const ScreenDim d = { 0x00, 0x0C, 0x28, 0xB4, 0xFF, 0x00, 0x00, 0x00 };
  1188. _screen->loadBitmap("finale.cps", 3, 3, &_screen->getPalette(0));
  1189. _screen->setFont(Screen::FID_GOLDFONT_FNT);
  1190. int talkieCreditsSize, talkieCreditsSpecialSize;
  1191. const uint8 *talkieCredits = _vm->staticres()->loadRawData(k2SeqplayCredits, talkieCreditsSize);
  1192. const char *const *talkieCreditsSpecial = _vm->staticres()->loadStrings(k2SeqplayCreditsSpecial, talkieCreditsSpecialSize);
  1193. _vm->sound()->selectAudioResourceSet(kMusicIngame);
  1194. _vm->sound()->loadSoundFile(3);
  1195. _vm->sound()->playTrack(3);
  1196. _screen->setTextColorMap(colormap);
  1197. _screen->copyRegion(0, 0, 0, 0, 320, 200, 2, 0);
  1198. _screen->updateScreen();
  1199. _screen->fadeFromBlack();
  1200. _screen->_charWidth = -2;
  1201. uint8 *dataPtr = new uint8[0xAFD];
  1202. memcpy(dataPtr, talkieCredits, talkieCreditsSize);
  1203. _vm->staticres()->unloadId(k2SeqplayCredits);
  1204. displayHoFTalkieScrollText(dataPtr, &d, 2, 6, 5, 1, Screen::FID_GOLDFONT_FNT, Screen::FID_GOLDFONT_FNT, 0, talkieCreditsSpecial);
  1205. delayTicks(8);
  1206. delete[] dataPtr;
  1207. _vm->staticres()->unloadId(k2SeqplayCreditsSpecial);
  1208. _vm->sound()->selectAudioResourceSet(kMusicFinale);
  1209. _vm->sound()->loadSoundFile(0);
  1210. }
  1211. void SeqPlayer_HOF::displayHoFTalkieScrollText(uint8 *data, const ScreenDim *d, int tempPage1, int tempPage2, int speed,
  1212. int step, Screen::FontId fid1, Screen::FontId fid2, const uint8 *shapeData, const char *const *specialData) {
  1213. if (!data)
  1214. return;
  1215. static const char mark[] = { 5, 13, 0 };
  1216. _screen->clearPage(tempPage1);
  1217. _screen->clearPage(tempPage2);
  1218. _screen->copyRegion(d->sx << 3, d->sy, d->sx << 3, d->sy, d->w << 3, d->h, 0, tempPage1);
  1219. struct ScrollTextData {
  1220. int16 x;
  1221. int16 y;
  1222. uint8 *text;
  1223. byte unk1;
  1224. byte height;
  1225. byte adjust;
  1226. ScrollTextData() {
  1227. x = 0; // 0 11
  1228. y = 0; // 2 13
  1229. text = 0; // 4 15
  1230. unk1 = 0; // 8 19
  1231. height = 0; // 9 20
  1232. adjust = 0; // 10 21
  1233. }
  1234. };
  1235. ScrollTextData *textData = new ScrollTextData[36];
  1236. uint8 *ptr = data;
  1237. bool loop = true;
  1238. int cnt = 0;
  1239. while (loop) {
  1240. uint32 loopEnd = _system->getMillis() + speed * _vm->tickLength();
  1241. while (cnt < 35 && *ptr) {
  1242. uint16 cH;
  1243. if (cnt)
  1244. cH = textData[cnt].y + textData[cnt].height + (textData[cnt].height >> 3);
  1245. else
  1246. cH = d->h;
  1247. char *str = (char *)ptr;
  1248. ptr = (uint8 *)strpbrk(str, mark);
  1249. if (!ptr)
  1250. ptr = (uint8 *)strchr(str, 0);
  1251. textData[cnt + 1].unk1 = *ptr;
  1252. *ptr = 0;
  1253. if (textData[cnt + 1].unk1)
  1254. ptr++;
  1255. if (*str == 3 || *str == 4)
  1256. textData[cnt + 1].adjust = *str++;
  1257. else
  1258. textData[cnt + 1].adjust = 0;
  1259. _screen->setFont(fid1);
  1260. if (*str == 1) {
  1261. _screen->setFont(fid2);
  1262. str++;
  1263. } else if (*str == 2) {
  1264. str++;
  1265. }
  1266. textData[cnt + 1].height = _screen->getFontHeight();
  1267. switch (textData[cnt + 1].adjust) {
  1268. case 3:
  1269. textData[cnt + 1].x = 157 - _screen->getTextWidth(str);
  1270. break;
  1271. case 4:
  1272. textData[cnt + 1].x = 161;
  1273. break;
  1274. default:
  1275. textData[cnt + 1].x = (((d->w << 3) - _screen->getTextWidth(str)) >> 1) + 1;
  1276. }
  1277. if (textData[cnt].unk1 == 5)
  1278. cH -= (textData[cnt].height + (textData[cnt].height >> 3));
  1279. textData[cnt + 1].y = cH;
  1280. textData[cnt + 1].text = (uint8 *)str;
  1281. cnt++;
  1282. }
  1283. _screen->copyRegion(d->sx << 3, d->sy, d->sx << 3, d->sy, d->w << 3, d->h, tempPage1, tempPage2);
  1284. int cnt2 = 0;
  1285. bool palCycle = 0;
  1286. while (cnt2 < cnt) {
  1287. const char *str = (const char *)textData[cnt2 + 1].text;
  1288. const char *str2 = str;
  1289. int16 cW = textData[cnt2 + 1].x - 10;
  1290. int16 cH = textData[cnt2 + 1].y;
  1291. int x = (d->sx << 3) + cW;
  1292. int y = d->sy + cH;
  1293. int col1 = 255;
  1294. if (cH < d->h) {
  1295. _screen->setCurPage(tempPage2);
  1296. _screen->setFont(fid1);
  1297. if (textData[cnt2 + 1].height != _screen->getFontHeight())
  1298. _screen->setFont(fid2);
  1299. if (specialData) {
  1300. if (!strcmp(str, specialData[0])) {
  1301. col1 = 112;
  1302. char cChar[2] = " ";
  1303. while (*str2) {
  1304. cChar[0] = *str2;
  1305. _screen->printText(cChar, x, y, col1++, 0);
  1306. x += _screen->getCharWidth((uint8)*str2++);
  1307. }
  1308. palCycle = true;
  1309. } else if (!strcmp(str, specialData[1])) {
  1310. col1 = 133;
  1311. char cChar[2] = " ";
  1312. while (*str2) {
  1313. cChar[0] = *str2;
  1314. _screen->printText(cChar, x, y, col1--, 0);
  1315. x += _screen->getCharWidth((uint8)*str2++);
  1316. }
  1317. palCycle = true;
  1318. } else {
  1319. _screen->printText(str, x, y, col1, 0);
  1320. }
  1321. } else {
  1322. _screen->printText(str, x, y, col1, 0);
  1323. }
  1324. _screen->setCurPage(0);
  1325. }
  1326. textData[cnt2 + 1].y -= step;
  1327. cnt2++;
  1328. }
  1329. _screen->copyRegion(d->sx << 3, d->sy, d->sx << 3, d->sy, d->w << 3, d->h, tempPage2, 0);
  1330. _screen->updateScreen();
  1331. if (textData[1].y < -10) {
  1332. textData[1].text += strlen((char *)textData[1].text);
  1333. textData[1].text[0] = textData[1].unk1;
  1334. cnt--;
  1335. memmove(&textData[1], &textData[2], cnt * sizeof(ScrollTextData));
  1336. }
  1337. if (palCycle) {
  1338. for (int col = 133; col > 112; col--)
  1339. _screen->getPalette(0).copy(_screen->getPalette(0), col - 1, 1, col);
  1340. _screen->getPalette(0).copy(_screen->getPalette(0), 133, 1, 112);
  1341. _screen->setScreenPalette(_screen->getPalette(0));
  1342. }
  1343. delayUntil(loopEnd);
  1344. if ((cnt < 36) && ((d->sy + d->h) > (textData[cnt].y + textData[cnt].height)) && !_abortPlayback) {
  1345. delayTicks(500);
  1346. cnt = 0;
  1347. }
  1348. if (checkAbortPlayback())
  1349. if (checkPlaybackStatus())
  1350. loop = false;
  1351. if (!cnt || _abortPlayback)
  1352. loop = false;
  1353. }
  1354. _vm->sound()->beginFadeOut();
  1355. _screen->fadeToBlack();
  1356. _abortPlayback = _abortRequested = false;
  1357. delete[] textData;
  1358. }
  1359. void SeqPlayer_HOF::updateDemoAdText(int bottom, int top) {
  1360. int dstY, dstH, srcH;
  1361. static const ScreenDim d = { 0x00, 0x00, 0x28, 0x320, 0xFF, 0xFE, 0x00, 0x00 };
  1362. if (_scrollProgressCounter - (top - 1) < 0) {
  1363. dstY = top - _scrollProgressCounter;
  1364. dstH = _scrollProgressCounter;
  1365. srcH = 0;
  1366. } else {
  1367. dstY = 0;
  1368. srcH = _scrollProgressCounter - top;
  1369. dstH = (400 - srcH <= top) ? 400 - srcH : top;
  1370. }
  1371. if (dstH > 0)

Large files files are truncated, but you can click here to view the full file