PageRenderTime 53ms CodeModel.GetById 12ms RepoModel.GetById 0ms app.codeStats 1ms

/engines/kyra/lol.cpp

http://github.com/scummvm/scummvm
C++ | 4513 lines | 3520 code | 925 blank | 68 comment | 918 complexity | f942aa9b567e49540d9a3439c93ff8fe 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. #ifdef ENABLE_LOL
  23. #include "kyra/lol.h"
  24. #include "kyra/screen_lol.h"
  25. #include "kyra/resource.h"
  26. #include "kyra/timer.h"
  27. #include "kyra/util.h"
  28. #include "kyra/debugger.h"
  29. #include "kyra/sound.h"
  30. #include "audio/audiostream.h"
  31. #include "common/config-manager.h"
  32. #include "common/system.h"
  33. #include "common/translation.h"
  34. #include "backends/keymapper/keymapper.h"
  35. namespace Kyra {
  36. const char *const LoLEngine::kKeymapName = "lol";
  37. LoLEngine::LoLEngine(OSystem *system, const GameFlags &flags) : KyraRpgEngine(system, flags) {
  38. _screen = 0;
  39. _gui = 0;
  40. _tim = 0;
  41. _lang = 0;
  42. Common::Language lang = Common::parseLanguage(ConfMan.get("language"));
  43. if (lang == _flags.fanLang && _flags.replacedLang != Common::UNK_LANG)
  44. lang = _flags.replacedLang;
  45. switch (lang) {
  46. case Common::EN_ANY:
  47. case Common::EN_USA:
  48. case Common::EN_GRB:
  49. _lang = 0;
  50. break;
  51. case Common::FR_FRA:
  52. _lang = 1;
  53. break;
  54. case Common::DE_DEU:
  55. _lang = 2;
  56. break;
  57. case Common::JA_JPN:
  58. _lang = 0;
  59. break;
  60. default:
  61. warning("unsupported language, switching back to English");
  62. _lang = 0;
  63. }
  64. _chargenFrameTable = _flags.isTalkie ? _chargenFrameTableTalkie : _chargenFrameTableFloppy;
  65. _chargenWSA = 0;
  66. _lastUsedStringBuffer = 0;
  67. _landsFile = 0;
  68. _levelLangFile = 0;
  69. _lastMusicTrack = -1;
  70. _lastSfxTrack = -1;
  71. _curTlkFile = -1;
  72. _lastSpeaker = _lastSpeechId = _nextSpeechId = _nextSpeaker = -1;
  73. memset(_moneyColumnHeight, 0, sizeof(_moneyColumnHeight));
  74. _credits = 0;
  75. _itemsInPlay = 0;
  76. _itemProperties = 0;
  77. _itemInHand = 0;
  78. memset(_inventory, 0, sizeof(_inventory));
  79. memset(_charStatusFlags, 0, sizeof(_charStatusFlags));
  80. _inventoryCurItem = 0;
  81. _lastCharInventory = -1;
  82. _emcLastItem = -1;
  83. _itemIconShapes = _itemShapes = _gameShapes = _thrownShapes = _effectShapes = _fireballShapes = _healShapes = _healiShapes = 0;
  84. _levelShpList = _levelDatList = 0;
  85. _gameShapeMap = 0;
  86. memset(_monsterAnimType, 0, 3);
  87. _healOverlay = 0;
  88. _swarmSpellStatus = 0;
  89. _ingameMT32SoundIndex = _ingameGMSoundIndex = _ingamePCSpeakerSoundIndex = 0;
  90. _charSelection = -1;
  91. _characters = 0;
  92. _spellProperties = 0;
  93. _selectedSpell = 0;
  94. _updateCharNum = _portraitSpeechAnimMode = _textColorFlag = 0;
  95. _palUpdateTimer = _updatePortraitNext = 0;
  96. _lampStatusTimer = 0xFFFFFFFF;
  97. _weaponsDisabled = false;
  98. _charInventoryUnk = 0;
  99. _lastButtonShape = 0;
  100. _buttonPressTimer = 0;
  101. _selectedCharacter = 0;
  102. _suspendScript = false;
  103. _scriptDirection = 0;
  104. _compassDirectionIndex = -1;
  105. _compassStep = 0;
  106. _smoothScrollModeNormal = 1;
  107. _wllAutomapData = 0;
  108. _sceneXoffset = 112;
  109. _sceneShpDim = 13;
  110. _monsters = 0;
  111. _monsterProperties = 0;
  112. _lvlShapeIndex = 0;
  113. _partyAwake = true;
  114. _transparencyTable2 = 0;
  115. _transparencyTable1 = 0;
  116. _specialGuiShape = 0;
  117. _specialGuiShapeX = _specialGuiShapeY = _specialGuiShapeMirrorFlag = 0;
  118. memset(_characterFaceShapes, 0, sizeof(_characterFaceShapes));
  119. _lampEffect = _brightness = _lampOilStatus = 0;
  120. _lampStatusSuspended = false;
  121. _tempBuffer5120 = 0;
  122. _flyingObjects = 0;
  123. _monsters = 0;
  124. _lastMouseRegion = 0;
  125. _objectLastDirection = 0;
  126. _monsterCurBlock = 0;
  127. _seqWindowX1 = _seqWindowY1 = _seqWindowX2 = _seqWindowY2 = _seqTrigger = 0;
  128. _spsWindowX = _spsWindowY = _spsWindowW = _spsWindowH = 0;
  129. _dscWalls = 0;
  130. _dscOvlMap = 0;
  131. _dscShapeScaleW = 0;
  132. _dscShapeScaleH = 0;
  133. _dscShapeY = 0;
  134. _dscShapeOvlIndex = 0;
  135. _dscDoorMonsterX = _dscDoorMonsterY = 0;
  136. _dscDoor4 = 0;
  137. _ingameSoundList = 0;
  138. _ingameSoundIndex = 0;
  139. _ingameSoundListSize = 0;
  140. _musicTrackMap = 0;
  141. _curMusicTheme = -1;
  142. _curMusicFileExt = 0;
  143. _curMusicFileIndex = -1;
  144. _envSfxUseQueue = false;
  145. _envSfxNumTracksInQueue = 0;
  146. memset(_envSfxQueuedTracks, 0, sizeof(_envSfxQueuedTracks));
  147. memset(_envSfxQueuedBlocks, 0, sizeof(_envSfxQueuedBlocks));
  148. _partyPosX = _partyPosY = 0;
  149. _shpDmX = _shpDmY = _dmScaleW = _dmScaleH = 0;
  150. _floatingCursorControl = _currentFloatingCursor = 0;
  151. memset(_activeTim, 0, sizeof(_activeTim));
  152. memset(&_activeSpell, 0, sizeof(_activeSpell));
  153. _pageBuffer1 = _pageBuffer2 = 0;
  154. memset(_charStatsTemp, 0, sizeof(_charStatsTemp));
  155. _compassBroken = _drainMagic = 0;
  156. _buttonData = 0;
  157. _preserveEvents = false;
  158. _buttonList1 = _buttonList2 = _buttonList3 = _buttonList4 = _buttonList5 = _buttonList6 = _buttonList7 = _buttonList8 = 0;
  159. _mapOverlay = 0;
  160. _automapShapes = 0;
  161. _defaultLegendData = 0;
  162. _mapCursorOverlay = 0;
  163. _lightningProps = 0;
  164. _lightningCurSfx = -1;
  165. _lightningDiv = 0;
  166. _lightningFirstSfx = 0;
  167. _lightningSfxFrame = 0;
  168. _compassTimer = 0;
  169. _scriptCharacterCycle = 0;
  170. _partyDamageFlags = -1;
  171. memset(&_itemScript, 0, sizeof(_itemScript));
  172. }
  173. LoLEngine::~LoLEngine() {
  174. setupPrologueData(false);
  175. releaseTempData();
  176. delete[] _landsFile;
  177. delete[] _levelLangFile;
  178. delete _screen;
  179. _screen = 0;
  180. delete _gui;
  181. _gui = 0;
  182. delete _tim;
  183. _tim = 0;
  184. delete _txt;
  185. _txt = 0;
  186. delete[] _itemsInPlay;
  187. delete[] _itemProperties;
  188. delete[] _characters;
  189. delete[] _pageBuffer1;
  190. delete[] _pageBuffer2;
  191. if (_itemIconShapes) {
  192. for (int i = 0; i < _numItemIconShapes; i++)
  193. delete[] _itemIconShapes[i];
  194. delete[] _itemIconShapes;
  195. }
  196. if (_itemShapes) {
  197. for (int i = 0; i < _numItemShapes; i++)
  198. delete[] _itemShapes[i];
  199. delete[] _itemShapes;
  200. }
  201. if (_gameShapes) {
  202. for (int i = 0; i < _numGameShapes; i++)
  203. delete[] _gameShapes[i];
  204. delete[] _gameShapes;
  205. }
  206. if (_thrownShapes) {
  207. for (int i = 0; i < _numThrownShapes; i++)
  208. delete[] _thrownShapes[i];
  209. delete[] _thrownShapes;
  210. }
  211. if (_effectShapes) {
  212. for (int i = 0; i < _numEffectShapes; i++)
  213. delete[] _effectShapes[i];
  214. delete[] _effectShapes;
  215. }
  216. if (_fireballShapes) {
  217. for (int i = 0; i < _numFireballShapes; i++)
  218. delete[] _fireballShapes[i];
  219. delete[] _fireballShapes;
  220. }
  221. if (_healShapes) {
  222. for (int i = 0; i < _numHealShapes; i++)
  223. delete[] _healShapes[i];
  224. delete[] _healShapes;
  225. }
  226. if (_healiShapes) {
  227. for (int i = 0; i < _numHealiShapes; i++)
  228. delete[] _healiShapes[i];
  229. delete[] _healiShapes;
  230. }
  231. if (_monsterDecorationShapes) {
  232. for (int i = 0; i < 3; i++)
  233. releaseMonsterShapes(i);
  234. delete[] _monsterShapes;
  235. _monsterShapes = 0;
  236. delete[] _monsterPalettes;
  237. _monsterPalettes = 0;
  238. delete[] _monsterDecorationShapes;
  239. _monsterDecorationShapes = 0;
  240. }
  241. for (int i = 0; i < 6; i++) {
  242. delete[] _doorShapes[i];
  243. _doorShapes[i] = 0;
  244. }
  245. releaseDecorations();
  246. delete[] _automapShapes;
  247. for (Common::Array<const TIMOpcode *>::iterator i = _timIntroOpcodes.begin(); i != _timIntroOpcodes.end(); ++i)
  248. delete *i;
  249. _timIntroOpcodes.clear();
  250. for (Common::Array<const TIMOpcode *>::iterator i = _timOutroOpcodes.begin(); i != _timOutroOpcodes.end(); ++i)
  251. delete *i;
  252. _timOutroOpcodes.clear();
  253. for (Common::Array<const TIMOpcode *>::iterator i = _timIngameOpcodes.begin(); i != _timIngameOpcodes.end(); ++i)
  254. delete *i;
  255. _timIngameOpcodes.clear();
  256. delete[] _wllAutomapData;
  257. delete[] _tempBuffer5120;
  258. delete[] _flyingObjects;
  259. delete[] _monsters;
  260. delete[] _monsterProperties;
  261. delete[] _transparencyTable2;
  262. delete[] _transparencyTable1;
  263. delete[] _lightningProps;
  264. delete _lvlShpFileHandle;
  265. if (_ingameSoundList) {
  266. for (int i = 0; i < _ingameSoundListSize; i++)
  267. delete[] _ingameSoundList[i];
  268. delete[] _ingameSoundList;
  269. }
  270. for (int i = 0; i < 3; i++) {
  271. for (int ii = 0; ii < 40; ii++)
  272. delete[] _characterFaceShapes[ii][i];
  273. }
  274. delete[] _healOverlay;
  275. delete[] _defaultLegendData;
  276. delete[] _mapCursorOverlay;
  277. delete[] _mapOverlay;
  278. for (Common::Array<const SpellProc *>::iterator i = _spellProcs.begin(); i != _spellProcs.end(); ++i)
  279. delete *i;
  280. _spellProcs.clear();
  281. for (SpeechList::iterator i = _speechList.begin(); i != _speechList.end(); ++i)
  282. delete *i;
  283. _speechList.clear();
  284. _emc->unload(&_itemScript);
  285. _emc->unload(&_scriptData);
  286. }
  287. Screen *LoLEngine::screen() {
  288. return _screen;
  289. }
  290. GUI *LoLEngine::gui() const {
  291. return _gui;
  292. }
  293. Common::Error LoLEngine::init() {
  294. _screen = new Screen_LoL(this, _system);
  295. assert(_screen);
  296. _screen->setResolution();
  297. _debugger = new Debugger_LoL(this);
  298. assert(_debugger);
  299. KyraEngine_v1::init();
  300. initStaticResource();
  301. _gui = new GUI_LoL(this);
  302. assert(_gui);
  303. _gui->initStaticData();
  304. _txt = new TextDisplayer_LoL(this, _screen);
  305. _screen->setAnimBlockPtr(10000);
  306. _screen->setScreenDim(0);
  307. _pageBuffer1 = new uint8[0xFA00];
  308. memset(_pageBuffer1, 0, 0xFA00);
  309. _pageBuffer2 = new uint8[0xFA00];
  310. memset(_pageBuffer2, 0, 0xFA00);
  311. _itemsInPlay = new LoLItem[400];
  312. memset(_itemsInPlay, 0, sizeof(LoLItem) * 400);
  313. _characters = new LoLCharacter[4];
  314. memset(_characters, 0, sizeof(LoLCharacter) * 4);
  315. if (!_sound->init())
  316. error("Couldn't init sound");
  317. KyraRpgEngine::init();
  318. _wllAutomapData = new uint8[80];
  319. memset(_wllAutomapData, 0, 80);
  320. _monsters = new LoLMonster[30];
  321. memset(_monsters, 0, 30 * sizeof(LoLMonster));
  322. _monsterProperties = new LoLMonsterProperty[5];
  323. memset(_monsterProperties, 0, 5 * sizeof(LoLMonsterProperty));
  324. _tempBuffer5120 = new uint8[5120];
  325. memset(_tempBuffer5120, 0, 5120);
  326. _flyingObjects = new FlyingObject[_numFlyingObjects];
  327. _flyingObjectsPtr = _flyingObjects;
  328. _flyingObjectStructSize = sizeof(FlyingObject);
  329. memset(_flyingObjects, 0, _numFlyingObjects * sizeof(FlyingObject));
  330. memset(_globalScriptVars, 0, sizeof(_globalScriptVars));
  331. _lvlShpFileHandle = 0;
  332. _sceneDrawPage1 = 2;
  333. _sceneDrawPage2 = 6;
  334. _clickedShapeXOffs = 136;
  335. _clickedShapeYOffs = 8;
  336. _clickedSpecialFlag = 0x40;
  337. _monsterShapes = new uint8*[48];
  338. memset(_monsterShapes, 0, 48 * sizeof(uint8 *));
  339. _monsterPalettes = new uint8*[48];
  340. memset(_monsterPalettes, 0, 48 * sizeof(uint8 *));
  341. _monsterDecorationShapes = new uint8*[576];
  342. memset(_monsterDecorationShapes, 0, 576 * sizeof(uint8 *));
  343. memset(&_scriptData, 0, sizeof(EMCData));
  344. _activeMagicMenu = -1;
  345. _automapShapes = new const uint8*[109];
  346. _mapOverlay = new uint8[256];
  347. memset(_availableSpells, -1, 8);
  348. _spellProcs.push_back(new SpellProc(this, &LoLEngine::castSpark));
  349. _spellProcs.push_back(new SpellProc(this, &LoLEngine::castHeal));
  350. _spellProcs.push_back(new SpellProc(this, &LoLEngine::castIce));
  351. _spellProcs.push_back(new SpellProc(this, &LoLEngine::castFireball));
  352. _spellProcs.push_back(new SpellProc(this, &LoLEngine::castHandOfFate));
  353. _spellProcs.push_back(new SpellProc(this, &LoLEngine::castMistOfDoom));
  354. _spellProcs.push_back(new SpellProc(this, &LoLEngine::castLightning));
  355. _spellProcs.push_back(new SpellProc(this, 0));
  356. _spellProcs.push_back(new SpellProc(this, &LoLEngine::castFog));
  357. _spellProcs.push_back(new SpellProc(this, &LoLEngine::castSwarm));
  358. _spellProcs.push_back(new SpellProc(this, 0));
  359. _spellProcs.push_back(new SpellProc(this, 0));
  360. _spellProcs.push_back(new SpellProc(this, &LoLEngine::castVaelansCube));
  361. _spellProcs.push_back(new SpellProc(this, 0));
  362. _spellProcs.push_back(new SpellProc(this, 0));
  363. _spellProcs.push_back(new SpellProc(this, 0));
  364. _spellProcs.push_back(new SpellProc(this, &LoLEngine::castGuardian));
  365. #ifdef ENABLE_KEYMAPPER
  366. _eventMan->getKeymapper()->pushKeymap(kKeymapName, true);
  367. #endif
  368. return Common::kNoError;
  369. }
  370. void LoLEngine::initKeymap() {
  371. #ifdef ENABLE_KEYMAPPER
  372. Common::Keymapper *const mapper = _eventMan->getKeymapper();
  373. // Do not try to recreate same keymap over again
  374. if (mapper->getKeymap(kKeymapName) != 0)
  375. return;
  376. Common::Keymap *const engineKeyMap = new Common::Keymap(kKeymapName);
  377. const Common::KeyActionEntry keyActionEntries[] = {
  378. {Common::KeyState(Common::KEYCODE_F1, Common::ASCII_F1), "AT1", _("Attack 1")},
  379. {Common::KeyState(Common::KEYCODE_F2, Common::ASCII_F2), "AT2", _("Attack 2")},
  380. {Common::KeyState(Common::KEYCODE_F3, Common::ASCII_F3), "AT3", _("Attack 3")},
  381. {Common::KeyState(Common::KEYCODE_UP), "MVF", _("Move Forward")},
  382. {Common::KeyState(Common::KEYCODE_DOWN), "MVB", _("Move Back")},
  383. {Common::KeyState(Common::KEYCODE_LEFT), "SLL", _("Slide Left")},
  384. {Common::KeyState(Common::KEYCODE_RIGHT), "SLR", _("Slide Right")},
  385. {Common::KeyState(Common::KEYCODE_HOME), "TL", _("Turn Left")},
  386. {Common::KeyState(Common::KEYCODE_PAGEUP), "TR", _("Turn Right")},
  387. {Common::KeyState(Common::KEYCODE_r), "RST", _("Rest")},
  388. {Common::KeyState(Common::KEYCODE_o), "OPT", _("Options")},
  389. {Common::KeyState(Common::KEYCODE_SLASH), "SPL", _("Choose Spell")},
  390. {Common::KeyState(), 0, 0}
  391. };
  392. for (const Common::KeyActionEntry *entry = keyActionEntries; entry->id; ++entry) {
  393. Common::Action *const act = new Common::Action(engineKeyMap, entry->id, entry->description);
  394. act->addKeyEvent(entry->ks);
  395. }
  396. mapper->addGameKeymap(engineKeyMap);
  397. #endif
  398. }
  399. void LoLEngine::pauseEngineIntern(bool pause) {
  400. KyraEngine_v1::pauseEngineIntern(pause);
  401. pauseDemoPlayer(pause);
  402. }
  403. Common::Error LoLEngine::go() {
  404. int action = -1;
  405. if (_gameToLoad == -1) {
  406. action = processPrologue();
  407. if (action == -1)
  408. return Common::kNoError;
  409. }
  410. if (_flags.isTalkie && !_flags.isDemo) {
  411. if (!_res->loadFileList("FILEDATA.FDT"))
  412. error("Couldn't load file list: 'FILEDATA.FDT'");
  413. } else if (_pakFileList) {
  414. _res->loadFileList(_pakFileList, _pakFileListSize);
  415. }
  416. // Usually fonts etc. would be setup by the prologue code, if we skip
  417. // the prologue code we need to setup them manually here.
  418. if (_gameToLoad != -1 && action != 3) {
  419. preInit();
  420. _screen->setFont((_flags.lang == Common::JA_JPN && _flags.use16ColorMode) ? Screen::FID_SJIS_FNT : Screen::FID_9_FNT);
  421. }
  422. // We have three sound.dat files, one for the intro, one for the
  423. // end sequence and one for ingame, each contained in a different
  424. // PAK file. Therefore a new call to loadSoundFile() is required
  425. // whenever the PAK file configuration changes.
  426. if (_flags.platform == Common::kPlatformPC98)
  427. _sound->loadSoundFile("sound.dat");
  428. _sound->selectAudioResourceSet(kMusicIngame);
  429. if (_flags.platform != Common::kPlatformDOS)
  430. _sound->loadSoundFile(0);
  431. _tim = new TIMInterpreter_LoL(this, _screen, _system);
  432. assert(_tim);
  433. if (shouldQuit())
  434. return Common::kNoError;
  435. startup();
  436. if (action == 0) {
  437. startupNew();
  438. } else if (_gameToLoad != -1) {
  439. // FIXME: Instead of throwing away the error returned by
  440. // loadGameState, we should use it / augment it.
  441. if (loadGameState(_gameToLoad).getCode() != Common::kNoError)
  442. error("Couldn't load game slot %d on startup", _gameToLoad);
  443. _gameToLoad = -1;
  444. }
  445. _screen->_fadeFlag = 3;
  446. _sceneUpdateRequired = true;
  447. enableSysTimer(1);
  448. runLoop();
  449. return Common::kNoError;
  450. }
  451. #pragma mark - Initialization
  452. void LoLEngine::preInit() {
  453. _res->loadPakFile("GENERAL.PAK");
  454. if (_flags.isTalkie)
  455. _res->loadPakFile("STARTUP.PAK");
  456. _screen->loadFont(Screen::FID_9_FNT, "FONT9P.FNT");
  457. _screen->loadFont(Screen::FID_6_FNT, "FONT6P.FNT");
  458. loadTalkFile(0);
  459. Common::String filename;
  460. filename = Common::String::format("LANDS.%s", _languageExt[_lang]);
  461. _res->exists(filename.c_str(), true);
  462. delete[] _landsFile;
  463. _landsFile = _res->fileData(filename.c_str(), 0);
  464. loadItemIconShapes();
  465. }
  466. void LoLEngine::loadItemIconShapes() {
  467. if (_itemIconShapes) {
  468. for (int i = 0; i < _numItemIconShapes; i++)
  469. delete[] _itemIconShapes[i];
  470. delete[] _itemIconShapes;
  471. }
  472. _screen->loadBitmap("ITEMICN.SHP", 3, 3, 0);
  473. const uint8 *shp = _screen->getCPagePtr(3);
  474. _numItemIconShapes = READ_LE_UINT16(shp);
  475. _itemIconShapes = new uint8*[_numItemIconShapes];
  476. for (int i = 0; i < _numItemIconShapes; i++)
  477. _itemIconShapes[i] = _screen->makeShapeCopy(shp, i);
  478. _screen->setMouseCursor(0, 0, _itemIconShapes[0]);
  479. if (!_gameShapes) {
  480. _screen->loadBitmap("GAMESHP.SHP", 3, 3, 0);
  481. shp = _screen->getCPagePtr(3);
  482. _numGameShapes = READ_LE_UINT16(shp);
  483. _gameShapes = new uint8*[_numGameShapes];
  484. for (int i = 0; i < _numGameShapes; i++)
  485. _gameShapes[i] = _screen->makeShapeCopy(shp, i);
  486. }
  487. }
  488. void LoLEngine::setMouseCursorToIcon(int icon) {
  489. _flagsTable[31] |= 0x02;
  490. int i = _itemProperties[_itemsInPlay[_itemInHand].itemPropertyIndex].shpIndex;
  491. if (i == icon)
  492. return;
  493. _screen->setMouseCursor(0, 0, _itemIconShapes[icon]);
  494. }
  495. void LoLEngine::setMouseCursorToItemInHand() {
  496. _flagsTable[31] &= 0xFD;
  497. int o = (_itemInHand == 0) ? 0 : 10;
  498. _screen->setMouseCursor(o, o, getItemIconShapePtr(_itemInHand));
  499. }
  500. void LoLEngine::checkFloatingPointerRegions() {
  501. if (!_floatingCursorsEnabled)
  502. return;
  503. int t = -1;
  504. Common::Point p = getMousePos();
  505. if (!(_updateFlags & 4) & !_floatingCursorControl) {
  506. if (posWithinRect(p.x, p.y, 96, 0, 303, 136)) {
  507. if (!posWithinRect(p.x, p.y, 128, 16, 271, 119)) {
  508. if (posWithinRect(p.x, p.y, 112, 0, 287, 15))
  509. t = 0;
  510. if (posWithinRect(p.x, p.y, 272, 88, 303, 319))
  511. t = 1;
  512. if (posWithinRect(p.x, p.y, 112, 110, 287, 135))
  513. t = 2;
  514. if (posWithinRect(p.x, p.y, 96, 88, 127, 119))
  515. t = 3;
  516. if (posWithinRect(p.x, p.y, 96, 16, 127, 87))
  517. t = 4;
  518. if (posWithinRect(p.x, p.y, 272, 16, 303, 87))
  519. t = 5;
  520. if (t < 4) {
  521. int d = (_currentDirection + t) & 3;
  522. if (!checkBlockPassability(calcNewBlockPosition(_currentBlock, d), d))
  523. t = 6;
  524. }
  525. }
  526. }
  527. }
  528. if (t == _currentFloatingCursor)
  529. return;
  530. if (t == -1) {
  531. setMouseCursorToItemInHand();
  532. } else {
  533. static const uint8 floatingPtrX[] = { 7, 13, 7, 0, 0, 15, 7 };
  534. static const uint8 floatingPtrY[] = { 0, 7, 12, 7, 6, 6, 7 };
  535. _screen->setMouseCursor(floatingPtrX[t], floatingPtrY[t], _gameShapes[10 + t]);
  536. }
  537. _currentFloatingCursor = t;
  538. }
  539. uint8 *LoLEngine::getItemIconShapePtr(int index) {
  540. int ix = _itemProperties[_itemsInPlay[index].itemPropertyIndex].shpIndex;
  541. if (_itemProperties[_itemsInPlay[index].itemPropertyIndex].flags & 0x200)
  542. ix += (_itemsInPlay[index].shpCurFrame_flg & 0x1FFF) - 1;
  543. return _itemIconShapes[ix];
  544. }
  545. int LoLEngine::mainMenu() {
  546. bool hasSave = saveFileLoadable(0);
  547. MainMenu::StaticData data[] = {
  548. // 256 color ASCII mode
  549. {
  550. { 0, 0, 0, 0, 0 },
  551. { 0x01, 0x04, 0x0C, 0x04, 0x00, 0x3D, 0x9F },
  552. { 0x2C, 0x19, 0x48, 0x2C },
  553. Screen::FID_9_FNT, 1
  554. },
  555. // 16 color SJIS mode
  556. {
  557. { 0, 0, 0, 0, 0 },
  558. { 0x01, 0x04, 0x0C, 0x04, 0x00, 0xC1, 0xE1 },
  559. { 0xCC, 0xDD, 0xDD, 0xDD },
  560. Screen::FID_SJIS_FNT, 1
  561. }
  562. };
  563. int dataIndex = _flags.use16ColorMode ? 1 : 0;
  564. if (!_flags.isTalkie)
  565. --data[dataIndex].menuTable[3];
  566. if (hasSave)
  567. ++data[dataIndex].menuTable[3];
  568. static const uint16 mainMenuStrings[4][5] = {
  569. { 0x4248, 0x4249, 0x42DD, 0x424A, 0x0000 },
  570. { 0x4248, 0x4249, 0x42DD, 0x4001, 0x424A },
  571. { 0x4248, 0x4249, 0x424A, 0x0000, 0x0000 },
  572. { 0x4248, 0x4249, 0x4001, 0x424A, 0x0000 }
  573. };
  574. int tableOffs = _flags.isTalkie ? 0 : 2;
  575. for (int i = 0; i < 5; ++i) {
  576. if (hasSave)
  577. data[dataIndex].strings[i] = getLangString(mainMenuStrings[1 + tableOffs][i]);
  578. else
  579. data[dataIndex].strings[i] = getLangString(mainMenuStrings[tableOffs][i]);
  580. }
  581. MainMenu *menu = new MainMenu(this);
  582. assert(menu);
  583. menu->init(data[dataIndex], MainMenu::Animation());
  584. int selection = menu->handle(_flags.isTalkie ? (hasSave ? 19 : 6) : (hasSave ? 6 : 20));
  585. delete menu;
  586. _screen->setScreenDim(0);
  587. if (!_flags.isTalkie && selection >= 2)
  588. selection++;
  589. if (!hasSave && selection == 3)
  590. selection = 4;
  591. return selection;
  592. }
  593. void LoLEngine::startup() {
  594. _screen->clearPage(0);
  595. Palette &pal = _screen->getPalette(0);
  596. _screen->loadBitmap("PLAYFLD.CPS", 3, 3, &pal);
  597. if (_flags.use16ColorMode) {
  598. memset(_screen->_paletteOverlay1, 0, 256);
  599. memset(_screen->_paletteOverlay2, 0, 256);
  600. static const uint8 colTable1[] = { 0x00, 0xEE, 0xCC, 0xFF, 0x44, 0x66, 0x44, 0x88, 0xEE, 0xAA, 0x11, 0xCC, 0xDD, 0xEE, 0x44, 0xCC };
  601. static const uint8 colTable2[] = { 0x00, 0xCC, 0xFF, 0xBB, 0xEE, 0xBB, 0x55, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xFF, 0xCC, 0xDD, 0xBB };
  602. static const uint8 colTable3[] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF };
  603. for (int i = 0; i < 16; i++) {
  604. _screen->_paletteOverlay1[colTable3[i]] = colTable1[i];
  605. _screen->_paletteOverlay2[colTable3[i]] = colTable2[i];
  606. }
  607. } else {
  608. _screen->copyPalette(1, 0);
  609. pal.fill(0, 1, 0x3F);
  610. pal.fill(2, 126, 0x3F);
  611. pal.fill(192, 4, 0x3F);
  612. _screen->generateOverlay(pal, _screen->_paletteOverlay1, 1, 96, 254);
  613. _screen->generateOverlay(pal, _screen->_paletteOverlay2, 144, 65, 254);
  614. _screen->copyPalette(0, 1);
  615. }
  616. _screen->getPalette(1).clear();
  617. _screen->getPalette(2).clear();
  618. loadItemIconShapes();
  619. _screen->setMouseCursor(0, 0, _itemIconShapes[0x85]);
  620. _screen->loadBitmap("ITEMSHP.SHP", 3, 3, 0);
  621. const uint8 *shp = _screen->getCPagePtr(3);
  622. _numItemShapes = READ_LE_UINT16(shp);
  623. _itemShapes = new uint8*[_numItemShapes];
  624. for (int i = 0; i < _numItemShapes; i++)
  625. _itemShapes[i] = _screen->makeShapeCopy(shp, i);
  626. _screen->loadBitmap("THROWN.SHP", 3, 3, 0);
  627. shp = _screen->getCPagePtr(3);
  628. _numThrownShapes = READ_LE_UINT16(shp);
  629. _thrownShapes = new uint8*[_numThrownShapes];
  630. for (int i = 0; i < _numThrownShapes; i++)
  631. _thrownShapes[i] = _screen->makeShapeCopy(shp, i);
  632. _screen->loadBitmap("ICE.SHP", 3, 3, 0);
  633. shp = _screen->getCPagePtr(3);
  634. _numEffectShapes = READ_LE_UINT16(shp);
  635. _effectShapes = new uint8*[_numEffectShapes];
  636. for (int i = 0; i < _numEffectShapes; i++)
  637. _effectShapes[i] = _screen->makeShapeCopy(shp, i);
  638. _screen->loadBitmap("FIREBALL.SHP", 3, 3, 0);
  639. shp = _screen->getCPagePtr(3);
  640. _numFireballShapes = READ_LE_UINT16(shp);
  641. _fireballShapes = new uint8*[_numFireballShapes];
  642. for (int i = 0; i < _numFireballShapes; i++)
  643. _fireballShapes[i] = _screen->makeShapeCopy(shp, i);
  644. _screen->loadBitmap("HEAL.SHP", 3, 3, 0);
  645. shp = _screen->getCPagePtr(3);
  646. _numHealShapes = READ_LE_UINT16(shp);
  647. _healShapes = new uint8*[_numHealShapes];
  648. for (int i = 0; i < _numHealShapes; i++)
  649. _healShapes[i] = _screen->makeShapeCopy(shp, i);
  650. _screen->loadBitmap("HEALI.SHP", 3, 3, 0);
  651. shp = _screen->getCPagePtr(3);
  652. _numHealiShapes = READ_LE_UINT16(shp);
  653. _healiShapes = new uint8*[_numHealiShapes];
  654. for (int i = 0; i < _numHealiShapes; i++)
  655. _healiShapes[i] = _screen->makeShapeCopy(shp, i);
  656. memset(_itemsInPlay, 0, 400 * sizeof(LoLItem));
  657. for (int i = 0; i < 400; i++)
  658. _itemsInPlay[i].shpCurFrame_flg |= 0x8000;
  659. runInitScript("ONETIME.INF", 0);
  660. _emc->load("ITEM.INF", &_itemScript, &_opcodes);
  661. _transparencyTable1 = new uint8[256];
  662. _transparencyTable2 = new uint8[5120];
  663. _loadSuppFilesFlag = 1;
  664. _sound->loadSfxFile("LORESFX");
  665. setMouseCursorToItemInHand();
  666. }
  667. void LoLEngine::startupNew() {
  668. _selectedSpell = 0;
  669. _compassStep = 0;
  670. _compassDirection = _compassDirectionIndex = -1;
  671. _lastMouseRegion = -1;
  672. _currentLevel = 1;
  673. giveCredits(41, 0);
  674. _inventory[0] = makeItem(216, 0, 0);
  675. _inventory[1] = makeItem(217, 0, 0);
  676. _inventory[2] = makeItem(218, 0, 0);
  677. _availableSpells[0] = 0;
  678. setupScreenDims();
  679. Common::fill(_globalScriptVars2, ARRAYEND(_globalScriptVars2), 0x100);
  680. static const int selectIds[] = { -9, -1, -8, -5 };
  681. assert(_charSelection >= 0);
  682. assert(_charSelection < ARRAYSIZE(selectIds));
  683. addCharacter(selectIds[_charSelection]);
  684. gui_enableDefaultPlayfieldButtons();
  685. loadLevel(_currentLevel);
  686. _screen->showMouse();
  687. }
  688. void LoLEngine::runLoop() {
  689. // Initialize debugger since how it should be fully usable
  690. _debugger->initialize();
  691. enableSysTimer(2);
  692. _flagsTable[73] |= 0x08;
  693. while (!shouldQuit()) {
  694. if (_gameToLoad != -1) {
  695. // FIXME: Instead of throwing away the error returned by
  696. // loadGameState, we should use it / augment it.
  697. if (loadGameState(_gameToLoad).getCode() != Common::kNoError)
  698. error("Couldn't load game slot %d", _gameToLoad);
  699. _gameToLoad = -1;
  700. }
  701. if (_nextScriptFunc) {
  702. runLevelScript(_nextScriptFunc, 2);
  703. _nextScriptFunc = 0;
  704. }
  705. _timer->update();
  706. checkFloatingPointerRegions();
  707. gui_updateInput();
  708. update();
  709. if (_sceneUpdateRequired)
  710. gui_drawScene(0);
  711. else
  712. updateEnvironmentalSfx(0);
  713. if (_partyDamageFlags != -1) {
  714. checkForPartyDeath();
  715. _partyDamageFlags = -1;
  716. }
  717. delay(_tickLength);
  718. }
  719. }
  720. void LoLEngine::registerDefaultSettings() {
  721. KyraEngine_v1::registerDefaultSettings();
  722. // Most settings already have sensible defaults. This one, however, is
  723. // specific to the LoL engine.
  724. ConfMan.registerDefault("floating_cursors", false);
  725. ConfMan.registerDefault("smooth_scrolling", true);
  726. ConfMan.registerDefault("monster_difficulty", 1);
  727. }
  728. void LoLEngine::writeSettings() {
  729. ConfMan.setInt("monster_difficulty", _monsterDifficulty);
  730. ConfMan.setBool("floating_cursors", _floatingCursorsEnabled);
  731. ConfMan.setBool("smooth_scrolling", _smoothScrollingEnabled);
  732. switch (_lang) {
  733. case 1:
  734. _flags.lang = Common::FR_FRA;
  735. break;
  736. case 2:
  737. _flags.lang = Common::DE_DEU;
  738. break;
  739. case 0:
  740. default:
  741. if (_flags.platform == Common::kPlatformPC98 || _flags.platform == Common::kPlatformFMTowns)
  742. _flags.lang = Common::JA_JPN;
  743. else
  744. _flags.lang = Common::EN_ANY;
  745. }
  746. if (_flags.lang == _flags.replacedLang && _flags.fanLang != Common::UNK_LANG)
  747. _flags.lang = _flags.fanLang;
  748. ConfMan.set("language", Common::getLanguageCode(_flags.lang));
  749. KyraEngine_v1::writeSettings();
  750. }
  751. void LoLEngine::readSettings() {
  752. _monsterDifficulty = ConfMan.getInt("monster_difficulty");
  753. if (_monsterDifficulty < 0 || _monsterDifficulty > 2) {
  754. _monsterDifficulty = CLIP(_monsterDifficulty, 0, 2);
  755. warning("LoLEngine: Config file contains invalid difficulty setting.");
  756. }
  757. _smoothScrollingEnabled = ConfMan.getBool("smooth_scrolling");
  758. _floatingCursorsEnabled = ConfMan.getBool("floating_cursors");
  759. KyraEngine_v1::readSettings();
  760. }
  761. void LoLEngine::update() {
  762. updateSequenceBackgroundAnimations();
  763. if (_updateCharNum != -1 && _system->getMillis() > _updatePortraitNext)
  764. updatePortraitSpeechAnim();
  765. if (_flagsTable[31] & 0x08 || !(_updateFlags & 4))
  766. updateLampStatus();
  767. if (_flagsTable[31] & 0x40 && !(_updateFlags & 4) && (_compassDirection == -1 || (_currentDirection << 6) != _compassDirection || _compassStep))
  768. updateCompass();
  769. snd_updateCharacterSpeech();
  770. fadeText();
  771. updateInput();
  772. _screen->updateScreen();
  773. }
  774. #pragma mark - Localization
  775. char *LoLEngine::getLangString(uint16 id) {
  776. if (id == 0xFFFF)
  777. return 0;
  778. uint16 realId = id & 0x3FFF;
  779. uint8 *buffer = 0;
  780. if (id & 0x4000)
  781. buffer = _landsFile;
  782. else
  783. buffer = _levelLangFile;
  784. if (!buffer)
  785. return 0;
  786. char *string = (char *)getTableEntry(buffer, realId);
  787. char *srcBuffer = _stringBuffer[_lastUsedStringBuffer];
  788. if (_flags.lang == Common::JA_JPN) {
  789. decodeSjis(string, srcBuffer);
  790. } else if (_flags.lang == Common::RU_RUS && !_flags.isTalkie) {
  791. decodeCyrillic(string, srcBuffer);
  792. Util::decodeString2(srcBuffer, srcBuffer);
  793. } else {
  794. Util::decodeString1(string, srcBuffer);
  795. Util::decodeString2(srcBuffer, srcBuffer);
  796. }
  797. ++_lastUsedStringBuffer;
  798. _lastUsedStringBuffer %= ARRAYSIZE(_stringBuffer);
  799. return srcBuffer;
  800. }
  801. uint8 *LoLEngine::getTableEntry(uint8 *buffer, uint16 id) {
  802. if (!buffer)
  803. return 0;
  804. return buffer + READ_LE_UINT16(buffer + (id << 1));
  805. }
  806. void LoLEngine::decodeSjis(const char *src, char *dst) {
  807. char s[2];
  808. char d[3];
  809. s[1] = 0;
  810. uint8 cmd = 0;
  811. while ((cmd = *src++) != 0) {
  812. if (cmd == 27) {
  813. cmd = *src++ & 0x7F;
  814. memcpy(dst, src, cmd * 2);
  815. dst += cmd * 2;
  816. src += cmd * 2;
  817. } else {
  818. s[0] = cmd;
  819. int size = Util::decodeString1(s, d);
  820. memcpy(dst, d, size);
  821. dst += size;
  822. }
  823. }
  824. *dst = 0;
  825. }
  826. int LoLEngine::decodeCyrillic(const char *src, char *dst) {
  827. static const uint8 decodeTable1[] = {
  828. 0x20, 0xAE, 0xA5, 0xA0, 0xE2, 0xAD, 0xA8, 0xE0, 0xE1, 0xAB, 0xA2,
  829. 0xA4, 0xAC, 0xAA, 0xE3, 0x2E
  830. };
  831. static const uint8 decodeTable2[] = {
  832. 0xAD, 0xAF, 0xA2, 0xE1, 0xAC, 0xAA, 0x20, 0xA4, 0xAB, 0x20,
  833. 0xE0, 0xE2, 0xA4, 0xA2, 0xA6, 0xAA, 0x20, 0xAD, 0xE2, 0xE0,
  834. 0xAB, 0xAC, 0xE1, 0xA1, 0x20, 0xAC, 0xE1, 0xAA, 0xAB, 0xE0,
  835. 0xE2, 0xAD, 0xAE, 0xEC, 0xA8, 0xA5, 0xA0, 0x20, 0xE0, 0xEB,
  836. 0xAE, 0xA0, 0xA8, 0xA5, 0xEB, 0xEF, 0x20, 0xE3, 0xE2, 0x20,
  837. 0xAD, 0xE7, 0xAB, 0xAC, 0xA5, 0xE0, 0xAE, 0xA0, 0xA5, 0xA8,
  838. 0xE3, 0xEB, 0xEF, 0xAA, 0xE2, 0xEF, 0xA5, 0xEC, 0xAB, 0xAE,
  839. 0xAA, 0xAF, 0xA8, 0xA0, 0xA5, 0xEF, 0xAE, 0xEE, 0xEC, 0xE3,
  840. 0xA0, 0xAE, 0xA5, 0xA8, 0xEB, 0x20, 0xE0, 0xE3, 0xA0, 0xA5,
  841. 0xAE, 0xA8, 0xE3, 0xE1, 0xAD, 0xAB, 0x20, 0xAE, 0xA5, 0xA0,
  842. 0xA8, 0xAD, 0x2E, 0xE3, 0xAE, 0xA0, 0xA8, 0x20, 0xE0, 0xE3,
  843. 0xAB, 0xE1, 0x20, 0xA4, 0xAD, 0xE2, 0xA1, 0xA6, 0xAC, 0xE1,
  844. 0x0D, 0x20, 0x2E, 0x09, 0xA0, 0xA1, 0x9D, 0xA5
  845. };
  846. int size = 0;
  847. uint cChar = 0;
  848. while ((cChar = *src++) != 0) {
  849. if (cChar & 0x80) {
  850. cChar &= 0x7F;
  851. int index = (cChar & 0x78) >> 3;
  852. *dst++ = decodeTable1[index];
  853. ++size;
  854. assert(cChar < sizeof(decodeTable2));
  855. cChar = decodeTable2[cChar];
  856. } else if (cChar >= 0x70) {
  857. cChar = *src++;
  858. } else if (cChar >= 0x30) {
  859. if (cChar < 0x60)
  860. cChar -= 0x30;
  861. cChar |= 0x80;
  862. }
  863. *dst++ = cChar;
  864. ++size;
  865. }
  866. *dst++ = 0;
  867. return size;
  868. }
  869. bool LoLEngine::addCharacter(int id) {
  870. const uint16 *cdf[] = {
  871. _charDefsMan, _charDefsMan, _charDefsMan, _charDefsWoman,
  872. _charDefsMan, _charDefsMan, _charDefsWoman, _charDefsKieran, _charDefsAkshel
  873. };
  874. int numChars = countActiveCharacters();
  875. if (numChars == 4)
  876. return false;
  877. int i = 0;
  878. for (; i < _charDefaultsSize; i++) {
  879. if (_charDefaults[i].id == id) {
  880. memcpy(&_characters[numChars], &_charDefaults[i], sizeof(LoLCharacter));
  881. _characters[numChars].defaultModifiers = cdf[i];
  882. break;
  883. }
  884. }
  885. if (i == _charDefaultsSize)
  886. return false;
  887. loadCharFaceShapes(numChars, id);
  888. _characters[numChars].nextAnimUpdateCountdown = rollDice(1, 12) + 6;
  889. for (i = 0; i < 11; i++) {
  890. if (_characters[numChars].items[i]) {
  891. _characters[numChars].items[i] = makeItem(_characters[numChars].items[i], 0, 0);
  892. runItemScript(numChars, _characters[numChars].items[i], 0x80, 0, 0);
  893. }
  894. }
  895. calcCharPortraitXpos();
  896. if (numChars > 0)
  897. setTemporaryFaceFrame(numChars, 2, 6, 0);
  898. return true;
  899. }
  900. void LoLEngine::setTemporaryFaceFrame(int charNum, int frame, int updateDelay, int redraw) {
  901. _characters[charNum].tempFaceFrame = frame;
  902. if (frame || updateDelay)
  903. setCharacterUpdateEvent(charNum, 6, updateDelay, 1);
  904. if (redraw)
  905. gui_drawCharPortraitWithStats(charNum);
  906. }
  907. void LoLEngine::setTemporaryFaceFrameForAllCharacters(int frame, int updateDelay, int redraw) {
  908. for (int i = 0; i < 4; i++)
  909. setTemporaryFaceFrame(i, frame, updateDelay, 0);
  910. if (redraw)
  911. gui_drawAllCharPortraitsWithStats();
  912. }
  913. void LoLEngine::setCharacterUpdateEvent(int charNum, int updateType, int updateDelay, int overwrite) {
  914. LoLCharacter *l = &_characters[charNum];
  915. for (int i = 0; i < 5; i++) {
  916. if (l->characterUpdateEvents[i] && (!overwrite || l->characterUpdateEvents[i] != updateType))
  917. continue;
  918. l->characterUpdateEvents[i] = updateType;
  919. l->characterUpdateDelay[i] = updateDelay;
  920. _timer->setNextRun(3, _system->getMillis());
  921. _timer->resetNextRun();
  922. _timer->enable(3);
  923. break;
  924. }
  925. }
  926. int LoLEngine::countActiveCharacters() {
  927. int i = 0;
  928. while (_characters[i].flags & 1)
  929. i++;
  930. return i;
  931. }
  932. void LoLEngine::loadCharFaceShapes(int charNum, int id) {
  933. if (id < 0)
  934. id = -id;
  935. Common::String file = Common::String::format("FACE%02d.SHP", id);
  936. _screen->loadBitmap(file.c_str(), 3, 3, 0);
  937. const uint8 *p = _screen->getCPagePtr(3);
  938. for (int i = 0; i < 40; i++) {
  939. delete[] _characterFaceShapes[i][charNum];
  940. _characterFaceShapes[i][charNum] = _screen->makeShapeCopy(p, i);
  941. }
  942. }
  943. void LoLEngine::updatePortraitSpeechAnim() {
  944. int x = 0;
  945. int y = 0;
  946. bool redraw = false;
  947. if (_portraitSpeechAnimMode == 0) {
  948. x = _activeCharsXpos[_updateCharNum];
  949. y = 144;
  950. redraw = true;
  951. } else if (_portraitSpeechAnimMode == 1) {
  952. if (textEnabled()) {
  953. x = 90;
  954. y = 130;
  955. } else {
  956. x = _activeCharsXpos[_updateCharNum];
  957. y = 144;
  958. }
  959. } else if (_portraitSpeechAnimMode == 2) {
  960. if (textEnabled()) {
  961. x = 16;
  962. y = 134;
  963. } else {
  964. x = _activeCharsXpos[_updateCharNum] + 10;
  965. y = 145;
  966. }
  967. }
  968. int f = rollDice(1, 6) - 1;
  969. if (f == _characters[_updateCharNum].curFaceFrame)
  970. f++;
  971. if (f > 5)
  972. f -= 5;
  973. f += 7;
  974. if (speechEnabled()) {
  975. if (snd_updateCharacterSpeech() == 2)
  976. // WORKAROUND for portrait speech animations which would "freeze" in some situations
  977. if (_resetPortraitAfterSpeechAnim == 2)
  978. _resetPortraitAfterSpeechAnim = 1;
  979. else
  980. _updatePortraitSpeechAnimDuration = 2;
  981. else
  982. _updatePortraitSpeechAnimDuration = 1;
  983. } else if (_resetPortraitAfterSpeechAnim == 2) {
  984. _resetPortraitAfterSpeechAnim = 1;
  985. }
  986. _updatePortraitSpeechAnimDuration--;
  987. if (_updatePortraitSpeechAnimDuration) {
  988. setCharFaceFrame(_updateCharNum, f);
  989. if (redraw)
  990. gui_drawCharPortraitWithStats(_updateCharNum);
  991. else
  992. gui_drawCharFaceShape(_updateCharNum, x, y, 0);
  993. _updatePortraitNext = _system->getMillis() + 10 * _tickLength;
  994. } else if (_resetPortraitAfterSpeechAnim != 0) {
  995. faceFrameRefresh(_updateCharNum);
  996. if (redraw) {
  997. gui_drawCharPortraitWithStats(_updateCharNum);
  998. initTextFading(0, 0);
  999. } else {
  1000. gui_drawCharFaceShape(_updateCharNum, x, y, 0);
  1001. }
  1002. _updateCharNum = -1;
  1003. }
  1004. }
  1005. void LoLEngine::stopPortraitSpeechAnim() {
  1006. if (_updateCharNum == -1)
  1007. return;
  1008. _updatePortraitSpeechAnimDuration = 1;
  1009. // WORKAROUND for portrait speech animations which would "freeze" in some situations
  1010. _resetPortraitAfterSpeechAnim = 2;
  1011. updatePortraitSpeechAnim();
  1012. _updatePortraitSpeechAnimDuration = 1;
  1013. _updateCharNum = -1;
  1014. if (!_portraitSpeechAnimMode)
  1015. initTextFading(0, 0);
  1016. }
  1017. void LoLEngine::initTextFading(int textType, int clearField) {
  1018. if (_textColorFlag == textType || !textType) {
  1019. _fadeText = true;
  1020. _palUpdateTimer = _system->getMillis();
  1021. }
  1022. if (!clearField)
  1023. return;
  1024. stopPortraitSpeechAnim();
  1025. if (_needSceneRestore)
  1026. _screen->setScreenDim(_txt->clearDim(3));
  1027. _fadeText = false;
  1028. _timer->disable(11);
  1029. }
  1030. void LoLEngine::setCharFaceFrame(int charNum, int frameNum) {
  1031. _characters[charNum].curFaceFrame = frameNum;
  1032. }
  1033. void LoLEngine::faceFrameRefresh(int charNum) {
  1034. if (_characters[charNum].curFaceFrame == 1)
  1035. setTemporaryFaceFrame(charNum, 0, 0, 0);
  1036. else if (_characters[charNum].curFaceFrame == 6)
  1037. if (_characters[charNum].tempFaceFrame != 5)
  1038. setTemporaryFaceFrame(charNum, 0, 0, 0);
  1039. else
  1040. _characters[charNum].curFaceFrame = 5;
  1041. else
  1042. _characters[charNum].curFaceFrame = 0;
  1043. }
  1044. void LoLEngine::recalcCharacterStats(int charNum) {
  1045. for (int i = 0; i < 5; i++)
  1046. _charStatsTemp[i] = calculateCharacterStats(charNum, i);
  1047. }
  1048. int LoLEngine::calculateCharacterStats(int charNum, int index) {
  1049. if (index == 0) {
  1050. // Might
  1051. int c = 0;
  1052. for (int i = 0; i < 8; i++)
  1053. c += _characters[charNum].itemsMight[i];
  1054. if (c)
  1055. c += _characters[charNum].might;
  1056. else
  1057. c = _characters[charNum].defaultModifiers[8];
  1058. c = (c * _characters[charNum].defaultModifiers[1]) >> 8;
  1059. c = (c * _characters[charNum].totalMightModifier) >> 8;
  1060. return c;
  1061. } else if (index == 1) {
  1062. // Protection
  1063. return calculateProtection(charNum);
  1064. } else if (index > 4) {
  1065. return -1;
  1066. } else {
  1067. // Fighter
  1068. // Rogue
  1069. // Mage
  1070. index -= 2;
  1071. return _characters[charNum].skillLevels[index] + _characters[charNum].skillModifiers[index];
  1072. }
  1073. //return 1;
  1074. }
  1075. int LoLEngine::calculateProtection(int index) {
  1076. int c = 0;
  1077. if (index & 0x8000) {
  1078. // Monster
  1079. index &= 0x7FFF;
  1080. c = (_monsters[index].properties->itemProtection * _monsters[index].properties->fightingStats[2]) >> 8;
  1081. } else {
  1082. // Character
  1083. c = _characters[index].itemProtection + _characters[index].protection;
  1084. c = (c * _characters[index].defaultModifiers[2]) >> 8;
  1085. c = (c * _characters[index].totalProtectionModifier) >> 8;
  1086. }
  1087. return c;
  1088. }
  1089. void LoLEngine::setCharacterMagicOrHitPoints(int charNum, int type, int points, int mode) {
  1090. static const uint16 barData[4][5] = {
  1091. // xPos, bar color, text color, flag, string id
  1092. { 0x27, 0x9A, 0x98, 0x01, 0x4254 },
  1093. { 0x21, 0xA2, 0xA0, 0x00, 0x4253 },
  1094. // 16 color mode
  1095. { 0x27, 0x66, 0x55, 0x01, 0x4254 },
  1096. { 0x21, 0xAA, 0x99, 0x00, 0x4253 }
  1097. };
  1098. if (charNum > 2)
  1099. return;
  1100. LoLCharacter *c = &_characters[charNum];
  1101. if (!(c->flags & 1))
  1102. return;
  1103. int pointsMax = type ? c->magicPointsMax : c->hitPointsMax;
  1104. int pointsCur = type ? c->magicPointsCur : c->hitPointsCur;
  1105. int newVal = (mode == 2) ? (pointsMax + points) : (mode ? (pointsCur + points) : points);
  1106. newVal = CLIP(newVal, 0, pointsMax);
  1107. if (type) {
  1108. c->magicPointsCur = newVal;
  1109. } else {
  1110. c->hitPointsCur = newVal;
  1111. if (c->hitPointsCur < 1)
  1112. c->flags |= 8;
  1113. }
  1114. if (_updateFlags & 2)
  1115. return;
  1116. Screen::FontId cf = _screen->setFont(Screen::FID_6_FNT);
  1117. int cp = _screen->setCurPage(0);
  1118. int s = 8192 / pointsMax;
  1119. pointsMax = (s * pointsMax) >> 8;
  1120. pointsCur = (s * pointsCur) >> 8;
  1121. newVal = (s * newVal) >> 8;
  1122. int newValScl = CLIP(newVal, 0, pointsMax);
  1123. int step = (newVal > pointsCur) ? 2 : -2;
  1124. newVal = CLIP(newVal + step, 0, pointsMax);
  1125. if (_flags.use16ColorMode)
  1126. type += 2;
  1127. if (newVal != pointsCur) {
  1128. step = (newVal >= pointsCur) ? 2 : -2;
  1129. for (int i = pointsCur; i != newVal || newVal != newValScl;) {
  1130. if (ABS(i - newVal) < ABS(step))
  1131. step >>= 1;
  1132. i += step;
  1133. uint32 delayTimer = _system->getMillis() + _tickLength;
  1134. gui_drawLiveMagicBar(barData[type][0] + _activeCharsXpos[charNum], 175, i, 0, pointsMax, 5, 32, barData[type][1], _flags.use16ColorMode ? 0x44 : 1, barData[type][3]);
  1135. _screen->printText(getLangString(barData[type][4]), barData[type][0] + _activeCharsXpos[charNum], 144, barData[type][2], 0);
  1136. _screen->updateScreen();
  1137. if (i == newVal) {
  1138. newVal = newValScl;
  1139. step = -step;
  1140. }
  1141. delayUntil(delayTimer);
  1142. }
  1143. }
  1144. _screen->setFont(cf);
  1145. _screen->setCurPage(cp);
  1146. }
  1147. void LoLEngine::increaseExperience(int charNum, int skill, uint32 points) {
  1148. if (charNum & 0x8000)
  1149. return;
  1150. if (_characters[charNum].flags & 8)
  1151. return;
  1152. _characters[charNum].experiencePts[skill] += points;
  1153. bool loop = true;
  1154. while (loop) {
  1155. if (_characters[charNum].experiencePts[skill] < _expRequirements[_characters[charNum].skillLevels[skill]])
  1156. break;
  1157. _characters[charNum].skillLevels[skill]++;
  1158. _characters[charNum].flags |= (0x200 << skill);
  1159. int inc = 0;
  1160. switch (skill) {
  1161. case 0:
  1162. _txt->printMessage(0x8003, getLangString(0x4023), _characters[charNum].name);
  1163. inc = rollDice(4, 6);
  1164. _characters[charNum].hitPointsCur += inc;
  1165. _characters[charNum].hitPointsMax += inc;
  1166. break;
  1167. case 1:
  1168. _txt->printMessage(0x8003, getLangString(0x4025), _characters[charNum].name);
  1169. inc = rollDice(2, 6);
  1170. _characters[charNum].hitPointsCur += inc;
  1171. _characters[charNum].hitPointsMax += inc;
  1172. break;
  1173. case 2:
  1174. _txt->printMessage(0x8003, getLangString(0x4024), _characters[charNum].name);
  1175. inc = (_characters[charNum].defaultModifiers[6] * (rollDice(1, 8) + 17)) >> 8;
  1176. _characters[charNum].magicPointsCur += inc;
  1177. _characters[charNum].magicPointsMax += inc;
  1178. inc = rollDice(1, 6);
  1179. _characters[charNum].hitPointsCur += inc;
  1180. _characters[charNum].hitPointsMax += inc;
  1181. break;
  1182. default:
  1183. break;
  1184. }
  1185. snd_playSoundEffect(118, -1);
  1186. gui_drawCharPortraitWithStats(charNum);
  1187. }
  1188. }
  1189. void LoLEngine::increaseCharacterHitpoints(int charNum, int points, bool ignoreDeath) {
  1190. if (_characters[charNum].hitPointsCur <= 0 && !ignoreDeath)
  1191. return;
  1192. if (points <= 1)
  1193. points = 1;
  1194. _characters[charNum].hitPointsCur = CLIP<int16>(_characters[charNum].hitPointsCur + points, 1, _characters[charNum].hitPointsMax);
  1195. _characters[charNum].flags &= 0xFFF7;
  1196. }
  1197. void LoLEngine::setupScreenDims() {
  1198. if (textEnabled()) {
  1199. _screen->modifyScreenDim(4, 11, 124, 28, 45);
  1200. _screen->modifyScreenDim(5, 85, 123, 233, 54);
  1201. } else {
  1202. _screen->modifyScreenDim(4, 11, 124, 28, 9);
  1203. _screen->modifyScreenDim(5, 85, 123, 233, 18);
  1204. }
  1205. }
  1206. void LoLEngine::initSceneWindowDialogue(int controlMode) {
  1207. resetPortraitsAndDisableSysTimer();
  1208. gui_prepareForSequence(112, 0, 176, 120, controlMode);
  1209. _updateFlags |= 3;
  1210. _txt->setupField(true);
  1211. _txt->expandField();
  1212. setupScreenDims();
  1213. gui_disableControls(controlMode);
  1214. }
  1215. void LoLEngine::toggleSelectedCharacterFrame(bool mode) {
  1216. if (countActiveCharacters() == 1)
  1217. return;
  1218. int col = mode ? 212 : 1;
  1219. int cp = _screen->setCurPage(0);
  1220. int x = _activeCharsXpos[_selectedCharacter];
  1221. _screen->drawBox(x, 143, x + 65, 176, col);
  1222. _screen->setCurPage(cp);
  1223. }
  1224. void LoLEngine::gui_prepareForSequence(int x, int y, int w, int h, int buttonFlags) {
  1225. setSequenceButtons(x, y, w, h, buttonFlags);
  1226. _seqWindowX1 = x;
  1227. _seqWindowY1 = y;
  1228. _seqWindowX2 = x + w;
  1229. _seqWindowY2 = y + h;
  1230. int mouseOffs = _itemInHand ? 10 : 0;
  1231. _screen->setMouseCursor(mouseOffs, mouseOffs, getItemIconShapePtr(_itemInHand));
  1232. _lastMouseRegion = -1;
  1233. if (w == 320) {
  1234. setLampMode(false);
  1235. _lampStatusSuspended = true;
  1236. }
  1237. }
  1238. void LoLEngine::gui_specialSceneSuspendControls(int controlMode) {
  1239. if (controlMode) {
  1240. _updateFlags |= 4;
  1241. setLampMode(false);
  1242. }
  1243. _updateFlags |= 1;
  1244. _specialSceneFlag = 1;
  1245. _currentControlMode = controlMode;
  1246. calcCharPortraitXpos();
  1247. checkFloatingPointerRegions();
  1248. }
  1249. void LoLEngine::gui_specialSceneRestoreControls(int restoreLamp) {
  1250. if (restoreLamp) {
  1251. _updateFlags &= 0xFFFA;
  1252. resetLampStatus();
  1253. }
  1254. _updateFlags &= 0xFFFE;
  1255. _specialSceneFlag = 0;
  1256. checkFloatingPointerRegions();
  1257. }
  1258. void LoLEngine::restoreAfterSceneWindowDialogue(int redraw) {
  1259. gui_enableControls();
  1260. _txt->setupField(false);
  1261. _updateFlags &= 0xFFDF;
  1262. setDefaultButtonState();
  1263. for (int i = 0; i < 6; i++)
  1264. _tim->freeAnimStruct(i);
  1265. _updateFlags = 0;
  1266. if (redraw) {
  1267. if (_screen->_fadeFlag != 2)
  1268. _screen->fadeClearSceneWindow(10);
  1269. gui_drawPlayField();
  1270. setPaletteBrightness(_screen->getPalette(0), _brightness, _lampEffect);
  1271. _screen->_fadeFlag = 0;
  1272. }
  1273. _needSceneRestore = 0;
  1274. enableSysTimer(2);
  1275. }
  1276. void LoLEngine::initDialogueSequence(int controlMode, int pageNum) {
  1277. if (controlMode) {
  1278. _timer->disable(11);
  1279. _fadeText = false;
  1280. int cp = _screen->setCurPage(pageNum);
  1281. if (_flags.use16ColorMode) {
  1282. _screen->fillRect(0, 128, 319, 199, 0x44);
  1283. gui_drawBox(0, 129, 320, 71, 0xEE, 0xCC, -1);
  1284. gui_drawBox(1, 130, 318, 69, 0xEE, 0xCC, 0x11);
  1285. } else {
  1286. _screen->fillRect(0, 128, 319, 199, 1);
  1287. gui_drawBox(0, 129, 320, 71, 136, 251, -1);
  1288. gui_drawBox(1, 130, 318, 69, 136, 251, 252);
  1289. }
  1290. _screen->modifyScreenDim(5, 8, 131, 306, 66);
  1291. _screen->modifyScreenDim(4, 1, 133, 38, 60);
  1292. _txt->clearDim(4);
  1293. _updateFlags |= 2;
  1294. _currentControlMode = controlMode;
  1295. calcCharPortraitXpos();
  1296. if (!textEnabled() && (!(controlMode & 2))) {
  1297. int nc = countActiveCharacters();
  1298. for (int i = 0; i < nc; i++) {
  1299. _portraitSpeechAnimMode = 2;
  1300. _updateCharNum = i;
  1301. _screen->drawShape(0, _gameShapes[88], _activeCharsXpos[_updateCharNum] + 8, 142, 0, 0);
  1302. stopPortraitSpeechAnim();
  1303. }
  1304. }
  1305. _screen->setCurPage(cp);
  1306. } else {
  1307. _txt->setupField(true);
  1308. _txt->expandField();
  1309. setupScreenDims();
  1310. _txt->clearDim(4);
  1311. }
  1312. _currentControlMode = controlMode;
  1313. _dialogueField = true;
  1314. }
  1315. void LoLEngine::restoreAfterDialogueSequence(int controlMode) {
  1316. if (!_dialogueField)
  1317. return;
  1318. stopPortraitSpeechAnim();
  1319. _currentControlMode = controlMode;
  1320. calcCharPortraitXpos();
  1321. if (_currentControlMode) {
  1322. _screen->modifyScreenDim(4, 11, 124, 28, 45);
  1323. _screen->modifyScreenDim(5, 85, 123, 233, 54);
  1324. _updateFlags &= 0xFFFD;
  1325. } else {
  1326. const ScreenDim *d = _screen->getScreenDim(5);
  1327. _screen->fillRect(d->sx, d->sy, d->sx + d->w - (_flags.use16ColorMode ? 3 : 2), d->sy + d->h - 2, d->unkA);
  1328. _txt->clearDim(4);
  1329. _txt->setupField(false);
  1330. }
  1331. _dialogueField = false;
  1332. }
  1333. void LoLEngine::resetPortraitsAndDisableSysTimer() {
  1334. _needSceneRestore = 1;
  1335. if (!textEnabled() || (!(_currentControlMode & 2)))
  1336. timerUpdatePortraitAnimations(1);
  1337. disableSysTimer(2);
  1338. }
  1339. void LoLEngine::fadeText() {
  1340. if (!_fadeText)
  1341. return;
  1342. if (_screen->fadeColor(192, 252, (_system->getMillis() - _palUpdateTimer) / _tickLength, 60))
  1343. return;
  1344. if (_needSceneRestore)
  1345. return;
  1346. _screen->setScreenDim(_txt->clearDim(3));
  1347. _timer->disable(11);
  1348. _fadeText = false;
  1349. }
  1350. void LoLEngine::setPaletteBrightness(const Palette &srcPal, int brightness, int modifier) {
  1351. generateBrightnessPalette(srcPal, _screen->getPalette(1), brightness, modifier);
  1352. _screen->fadePalette(_screen->getPalette(1), 5, 0);
  1353. _screen->_fadeFlag = 0;
  1354. }
  1355. void LoLEngine::generateBrightnessPalette(const Palette &src, Palette &dst, int brightness, int16 modifier) {
  1356. dst.copy(src);
  1357. if (_flags.use16ColorMode) {
  1358. if (!brightness)
  1359. modifier = 0;
  1360. else if (modifier < 0 || modifier > 7 || !(_flagsTable[31] & 0x08))
  1361. modifier = 8;
  1362. modifier >>= 1;
  1363. if (modifier)
  1364. modifier--;
  1365. if (modifier > 3)
  1366. modifier = 3;
  1367. _blockBrightness = modifier << 4;
  1368. _sceneUpdateRequired = true;
  1369. } else {
  1370. _screen->loadSpecialColors(dst);
  1371. brightness = (8 - brightness) << 5;
  1372. if (modifier >= 0 && modifier < 8 && (_flagsTable[31] & 0x08)) {
  1373. brightness = 256 - ((((modifier & 0xFFFE) << 5) * (256 - brightness)) >> 8);
  1374. if (brightness < 0)
  1375. brightness = 0;
  1376. }
  1377. for (int i = 0; i < 384; i++) {
  1378. uint16 c = (dst[i] * brightness) >> 8;
  1379. dst[i] = c & 0xFF;
  1380. }
  1381. }
  1382. }
  1383. void LoLEngine::generateFlashPalette(const Palette &src, Palette &dst, int colorFlags) {
  1384. dst.copy(src, 0, 2);
  1385. for (int i = 2; i < 128; i++) {
  1386. for (int ii = 0; ii < 3; ii++) {
  1387. uint8 t = src[i * 3 + ii] & 0x3F;
  1388. if (colorFlags & (1 << ii))
  1389. t += ((0x3F - t) >> 1);
  1390. else
  1391. t -= (t >> 1);
  1392. dst[i * 3 + ii] = t;
  1393. }
  1394. }
  1395. dst.copy(src, 128);
  1396. }
  1397. void LoLEngine::createTransparencyTables() {
  1398. if (_flags.isTalkie || _loadSuppFilesFlag)
  1399. return;
  1400. uint8 *tpal = new uint8[768];
  1401. if (_flags.use16ColorMode) {
  1402. static const uint8 colTbl[] = {
  1403. 0x00, 0x00, 0x11, 0x00, 0x22, 0x00, 0x33, 0x00, 0x44, 0x00, 0x55, 0x00, 0x66, 0x00, 0x77, 0x00,
  1404. 0x88, 0x00, 0x99, 0x00, 0xAA, 0x00, 0xBB, 0x00, 0xCC, 0x00, 0xDD, 0x00, 0xEE, 0x00, 0xFF, 0x00
  1405. };
  1406. memset(tpal, 0xFF, 768);
  1407. _res->loadFileToBuf("LOL.NOL", tpal, 48);
  1408. for (int i = 15; i > -1; i--) {
  1409. int s = colTbl[i << 1] * 3;
  1410. tpal[s] = tpal[i * 3];
  1411. tpal[s + 1] = tpal[i * 3 + 1];
  1412. tpal[s + 2] = tpal[i * 3 + 2];
  1413. tpal[i * 3 + 2] = tpal[i * 3 + 1] = tpal[i * 3] = 0xFF;
  1414. }
  1415. _screen->createTransparencyTablesIntern(colTbl, 16, tpal, tpal, _transparencyTable1, _transparencyTable2, 80);
  1416. } else {
  1417. _res->loadFileToBuf("fxpal.col", tpal, 768);
  1418. _screen->loadBitmap("fxpal.shp", 3, 3, 0);
  1419. const uint8 *shpPal = _screen->getPtrToShape(_screen->getCPagePtr(2), 0) + 11;
  1420. _screen->createTransparencyTablesIntern(shpPal, 20, tpal, _screen->getPalette(1).getData(), _transparencyTable1, _transparencyTable2, 70);
  1421. }
  1422. delete[] tpal;
  1423. _loadSuppFilesFlag = 1;
  1424. }
  1425. void LoLEngine::updateSequenceBackgroundAnimations() {
  1426. if (_updateFlags & 8 || !_tim)
  1427. return;
  1428. if (!_tim->animator())
  1429. return;
  1430. for (int i = 0; i < 6; i++)
  1431. _tim->animator()->update(i);
  1432. }
  1433. void LoLEngine::loadTalkFile(int index) {
  1434. if (index == _curTlkFile)
  1435. return;
  1436. if (_curTlkFile > 0 && index > 0)
  1437. _res->unloadPakFile(Common::String::format("%02d.TLK", _curTlkFile));
  1438. if (index > 0)
  1439. _curTlkFile = index;
  1440. _res->loadPakFile(Common::String::format("%02d.TLK", index));
  1441. }
  1442. int LoLEngine::characterSays(int track, int charId, bool redraw) {
  1443. if (charId == 1) {
  1444. charId = _selectedCharacter;
  1445. } if (charId <= 0) {
  1446. charId = 0;
  1447. } else {
  1448. int i = 0;
  1449. for (; i < 4; i++) {
  1450. if (charId != _characters[i].id || !(_characters[i].flags & 1))
  1451. continue;
  1452. charId = i;
  1453. break;
  1454. }
  1455. if (i == 4)
  1456. return 0;
  1457. }
  1458. bool r = snd_playCharacterSpeech(track, charId, 0);
  1459. if (r && redraw) {
  1460. stopPortraitSpeechAnim();
  1461. _updateCharNum = charId;
  1462. _portraitSpeechAnimMode = 0;
  1463. _resetPortraitAfterSpeechAnim = 1;
  1464. _fadeText = false;
  1465. updatePortraitSpeechAnim();
  1466. }
  1467. return r ? (textEnabled() ? 1 : 0) : 1;
  1468. }
  1469. int LoLEngine::playCharacterScriptChat(int charId, int mode, int restorePortrait, char *str, EMCState *script, const uint16 *paramList, int16 paramIndex) {
  1470. int ch = 0;
  1471. bool skipAnim = false;
  1472. if ((charId == -1) || (!(charId & 0x70)))
  1473. charId = ch = (charId == 1) ? (_selectedCharacter ? _characters[_selectedCharacter].id : 0) : charId;
  1474. else
  1475. charId ^= 0x70;
  1476. stopPortraitSpeechAnim();
  1477. if (charId < 0) {
  1478. charId = ch = _rnd.getRandomNumber(countActiveCharacters() - 1);
  1479. } else if (charId > 0) {
  1480. int i = 0;
  1481. for (; i < 3; i++) {
  1482. if (_characters[i].id != charId || !(_characters[i].flags & 1))
  1483. continue;
  1484. if (charId == ch)
  1485. ch = i;
  1486. charId = i;
  1487. break;
  1488. }
  1489. if (i == 4) {
  1490. if (charId == 8)
  1491. skipAnim = true;
  1492. else
  1493. return 0;
  1494. }
  1495. }
  1496. if (!skipAnim) {
  1497. _updateCharNum = charId;
  1498. _portraitSpeechAnimMode = mode;
  1499. _updatePortraitSpeechAnimDuration = strlen(str) >> 1;
  1500. _resetPortraitAfterSpeechAnim = restorePortrait;
  1501. }
  1502. if (script)
  1503. snd_playCharacterSpeech(script->stack[script->sp + 2], ch, 0);
  1504. else if (paramList)
  1505. snd_playCharacterSpeech(paramList[2], ch, 0);
  1506. if (textEnabled()) {
  1507. if (mode == 0) {
  1508. _txt->printDialogueText(3, str, script, paramList, paramIndex);
  1509. } else if (mode == 1) {
  1510. _txt->clearDim(4);
  1511. _screen->modifyScreenDim(4, 16, 123, 23, 47);
  1512. _txt->printDialogueText(4, str, script, paramList, paramIndex);
  1513. _screen->modifyScreenDim(4, 11, 123, 28, 47);
  1514. } else if (mode == 2) {
  1515. _txt->clearDim(4);
  1516. _screen->modifyScreenDim(4, 9, 133, 30, 60);
  1517. _txt->printDialogueText(4, str, script, paramList, 3

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