diff options
author | Johannes Schickel | 2010-10-13 03:57:44 +0000 |
---|---|---|
committer | Johannes Schickel | 2010-10-13 03:57:44 +0000 |
commit | 75e8452b6e6a2bf4fb2f588aa00b428a60d873b5 (patch) | |
tree | f29541d55309487a94bd1d38e8b53bb3dde9aec6 /engines/toon/toon.cpp | |
parent | 48ee83b88957dab86bc763e9ef21a70179fa8679 (diff) | |
parent | e9f50882ea5b6beeefa994040be9d3bab6a1f107 (diff) | |
download | scummvm-rg350-75e8452b6e6a2bf4fb2f588aa00b428a60d873b5.tar.gz scummvm-rg350-75e8452b6e6a2bf4fb2f588aa00b428a60d873b5.tar.bz2 scummvm-rg350-75e8452b6e6a2bf4fb2f588aa00b428a60d873b5.zip |
OPENGL: Merged from trunk, from rev 52105 to 53396.
This includes an rather hacky attempt to merge all the recent gp2x backend
changes into the branch. I suppose the gp2x backend and probably all new
backends, i.e. gph, dingux etc., might not compile anymore.
Since I have no way of testing those it would be nice if porters could look
into getting those up to speed in this branch.
svn-id: r53399
Diffstat (limited to 'engines/toon/toon.cpp')
-rw-r--r-- | engines/toon/toon.cpp | 4401 |
1 files changed, 4401 insertions, 0 deletions
diff --git a/engines/toon/toon.cpp b/engines/toon/toon.cpp new file mode 100644 index 0000000000..7489f5c5d9 --- /dev/null +++ b/engines/toon/toon.cpp @@ -0,0 +1,4401 @@ +/* ScummVM - Graphic Adventure Engine +* +* ScummVM is the legal property of its developers, whose names +* are too numerous to list here. Please refer to the COPYRIGHT +* file distributed with this source distribution. +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version 2 +* of the License, or (at your option) any later version. + +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. + +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +* +* $URL$ +* $Id$ +* +*/ + +#include "common/system.h" +#include "common/events.h" +#include "common/debug-channels.h" +#include "common/archive.h" +#include "common/config-manager.h" +#include "common/EventRecorder.h" +#include "engines/util.h" +#include "graphics/surface.h" +#include "graphics/thumbnail.h" +#include "gui/saveload.h" +#include "gui/about.h" +#include "gui/message.h" +#include "toon/resource.h" +#include "toon/toon.h" +#include "toon/anim.h" +#include "toon/picture.h" +#include "toon/hotspot.h" +#include "toon/flux.h" +#include "toon/drew.h" +#include "toon/path.h" + +namespace Toon { + + +void ToonEngine::init() { + _currentScriptRegion = 0; + _resources = new Resources(this); + _animationManager = new AnimationManager(this); + _moviePlayer = new Movie(this, new ToonstruckSmackerDecoder(_mixer)); + _hotspots = new Hotspots(this); + + _mainSurface = new Graphics::Surface(); + _mainSurface->create(1280, 400, 1); + + _finalPalette = new uint8[768]; + _backupPalette = new uint8[768]; + _additionalPalette1 = new uint8[69]; + _additionalPalette2 = new uint8[69]; + _cutawayPalette = new uint8[768]; + _universalPalette = new uint8[96]; + _fluxPalette = new uint8[24]; + + memset(_finalPalette, 0, 768); + memset(_backupPalette, 0, 768); + memset(_additionalPalette1, 0, 69); + memset(_additionalPalette2, 0, 69); + memset(_cutawayPalette, 0, 768); + memset(_universalPalette, 0, 96); + memset(_fluxPalette, 0, 24); + + _conversationData = new int16[4096]; + memset(_conversationData, 0, 4096 * sizeof(int16)); + + _shouldQuit = false; + _scriptStep = 0; + + _cursorOffsetX = 0; + _cursorOffsetY = 0; + _currentHotspotItem = 0; + + _currentTextLine = 0; + _currentTextLineId = -1; + _currentTextLineX = 0; + _currentTextLineY = 0; + _currentTextLineCharacterId = 0; + + _saveBufferStream = new Common::MemoryWriteStreamDynamic(); + + _firstFrame = false; + + const Common::FSNode gameDataDir(ConfMan.get("path")); + SearchMan.addSubDirectoryMatching(gameDataDir, "misc"); + + syncSoundSettings(); + + _pathFinding = new PathFinding(this); + + resources()->openPackage("misc/local.pak", true); + resources()->openPackage("misc/onetime.pak", true); + resources()->openPackage("misc/drew.pak", true); + + for (int32 i = 0; i < 32; i++) + _characters[i] = 0; + + _characters[0] = new CharacterDrew(this); + _characters[1] = new CharacterFlux(this); + _drew = _characters[0]; + _flux = _characters[1]; + + // preload walk anim for flux and drew + _drew->loadWalkAnimation("stndwalk.caf"); + _drew->setupPalette(); + _drew->loadShadowAnimation("shadow.caf"); + + _flux->loadWalkAnimation("fxstwalk.caf"); + _flux->loadShadowAnimation("shadow.caf"); + + loadAdditionalPalette("universe.pal", 3); + loadAdditionalPalette("flux.pal", 4); + setupGeneralPalette(); + + _script_func = new ScriptFunc(this); + _gameState = new State(); + _gameState->_conversationData = _conversationData; + + memset(_sceneAnimations, 0, sizeof(_sceneAnimations)); + memset(_sceneAnimationScripts, 0, sizeof(_sceneAnimationScripts)); + + + _gameState->_currentChapter = 1; + initChapter(); + loadCursor(); + initFonts(); + + _dialogIcons = new Animation(this); + _dialogIcons->loadAnimation("dialogue.caf"); + + _inventoryIcons = new Animation(this); + _inventoryIcons->loadAnimation("inventry.caf"); + + _inventoryIconSlots = new Animation(this); + _inventoryIconSlots->loadAnimation("iconslot.caf"); + + _genericTexts = new TextResource(this); + _genericTexts->loadTextResource("generic.tre"); + + _audioManager = new AudioManager(this, _mixer); + _audioManager->loadAudioPack(0, "generic.svi", "misc/generic.svl"); + _audioManager->loadAudioPack(2, "generic.sei", "generic.sel"); + + _lastMouseButton = 0; + _mouseButton = 0; +} + +void ToonEngine::waitForScriptStep() { + // Wait after a specified number of script steps when executing a script + // to lower CPU usage + if (++_scriptStep >= 40) { + g_system->delayMillis(10); + _scriptStep = 0; + } +} + +void ToonEngine::parseInput() { + + Common::EventManager *_event = _system->getEventManager(); + + _mouseX = _event->getMousePos().x; + _mouseY = _event->getMousePos().y; + _mouseButton = _event->getButtonState(); + + Common::Event event; + while (_event->pollEvent(event)) { + switch (event.type) { + case Common::EVENT_KEYUP: + if (event.kbd.ascii == 27 || event.kbd.ascii == 32) { + _audioManager->stopCurrentVoice(); + } + if (event.kbd.keycode == Common::KEYCODE_F5) { + saveGame(-1); + } + if (event.kbd.keycode == Common::KEYCODE_F6) { + loadGame(-1); + } + + if (event.kbd.flags & Common::KBD_ALT) { + int32 slotNum = event.kbd.ascii - '0'; + if (slotNum >= 0 && slotNum <= 9) { + if (saveGame(slotNum)) { + // ok + char buf[256]; + snprintf(buf, 256, "Saved game in slot #%d ", slotNum); + GUI::TimedMessageDialog dialog(buf, 1000); + dialog.runModal(); + } else { + char buf[256]; + snprintf(buf, 256, "Could not quick save into slot #%d", slotNum); + GUI::MessageDialog dialog2(buf, "OK", 0); + //warning("%s", buf); + dialog2.runModal(); + + } + } + } + + if (event.kbd.flags & Common::KBD_CTRL) { + int32 slotNum = event.kbd.ascii - '0'; + if (slotNum >= 0 && slotNum <= 9) { + if (loadGame(slotNum)) { + // ok + char buf[256]; + snprintf(buf, 256, "Savegame #%d quick loaded", slotNum); + GUI::TimedMessageDialog dialog(buf, 1000); + dialog.runModal(); + } else { + char buf[256]; + snprintf(buf, 256, "Could not quick load the savegame #%d", slotNum); + GUI::MessageDialog dialog(buf, "OK", 0); + warning("%s", buf); + dialog.runModal(); + } + } + } + break; +// Strangerke - Commented (not used) +// case Common::EVENT_LBUTTONDOWN: +// break; +// case Common::EVENT_RBUTTONDOWN: +// break; +// case Common::EVENT_LBUTTONUP: +// break; +// case Common::EVENT_RBUTTONUP: +// break; +// case Common::EVENT_WHEELUP: +// break; +// case Common::EVENT_WHEELDOWN: +// break; + default: + break; + } + } + + if (!_gameState->_inConversation && !_gameState->_mouseHidden && !_gameState->_inInventory) { + selectHotspot(); + clickEvent(); + } + +} + +void ToonEngine::enableTimer(int32 timerId) { + _gameState->_timerEnabled[timerId] = true; +} +void ToonEngine::setTimer(int32 timerId, int32 timerWait) { + _gameState->_timerTimeout[timerId] = getOldMilli() + timerWait * getTickLength(); + _gameState->_timerDelay[timerId] = timerWait; +} +void ToonEngine::disableTimer(int32 timerId) { + _gameState->_timerEnabled[timerId] = false; +} +void ToonEngine::updateTimers() { + for (int32 i = 0; i < 2; i++) { + if (_gameState->_timerEnabled[i]) { + if (_gameState->_timerDelay[i] > -1 && getOldMilli() > _gameState->_timerTimeout[i]) { + if (i == 0) { + + EMCState *status = &_scriptState[_currentScriptRegion]; + _script->init(status, &_scriptData); + + // setup registers + status->regs[0] = _mouseX; + status->regs[1] = _mouseY; + status->regs[2] = 0; + + _currentScriptRegion++; + + _script->start(status, 7); + while (_script->run(status)) + waitForScriptStep(); + + _currentScriptRegion--; + + _gameState->_timerTimeout[i] = getOldMilli() + _gameState->_timerDelay[i] * getTickLength(); + + return; + + } + } + } + } +} + +void ToonEngine::updateScrolling(bool force, int32 timeIncrement) { + static int32 lastScrollOffset = 320; + if (!_audioManager->voiceStillPlaying() && !_gameState->_currentScrollLock && (_drew->getFlag() & 1) == 0) { + if (_drew->getFacing() & 3) { + if (_drew->getFacing() <= 4) + lastScrollOffset = 200; + else + lastScrollOffset = 440; + } + + if (_gameState->_inCutaway || _gameState->_inInventory || _gameState->_inCloseUp) + return; + + int32 desiredScrollValue = _drew->getX() - lastScrollOffset; + + if ((_gameState->_locations[_gameState->_currentScene]._flags & 0x80) == 0) { + if (desiredScrollValue < 0) + desiredScrollValue = 0; + if (desiredScrollValue >= _currentPicture->getWidth() - 640) + desiredScrollValue = _currentPicture->getWidth() - 640; + + if (force) { + _gameState->_currentScrollValue = desiredScrollValue; + return; + } else { + if (_gameState->_currentScrollValue < desiredScrollValue) { + _gameState->_currentScrollValue += timeIncrement / 2; + + if (_gameState->_currentScrollValue > desiredScrollValue) + _gameState->_currentScrollValue = desiredScrollValue; + } else if (_gameState->_currentScrollValue > desiredScrollValue) { + _gameState->_currentScrollValue -= timeIncrement / 2; + + if (_gameState->_currentScrollValue < desiredScrollValue) + _gameState->_currentScrollValue = desiredScrollValue; + } + } + } + } +} + +void ToonEngine::update(int32 timeIncrement) { + // to make sure we're updating the game at 5fps at least + if (timeIncrement > 200) + timeIncrement = 200; + + updateAnimationSceneScripts(timeIncrement); + updateCharacters(timeIncrement); + updateTimer(timeIncrement); + updateTimers(); + updateScrolling(false, timeIncrement); + _animationManager->update(timeIncrement); + _cursorAnimationInstance->update(timeIncrement); + + if (!_audioManager->voiceStillPlaying()) { + _currentTextLine = 0; + _currentTextLineId = -1; + } +} + +void ToonEngine::updateTimer(int32 timeIncrement) { + if (_gameState->_gameTimer > 0) { + debugC(0, 0xfff, "updateTimer(%d)", timeIncrement); + _gameState->_gameTimer -= timeIncrement; + if (_gameState->_gameTimer < 0) + _gameState->_gameTimer = 0; + } +} + +void ToonEngine::render() { + if (_gameState->_inCutaway) + _currentCutaway->draw(*_mainSurface, 0, 0, 0, 0); + else + _currentPicture->draw(*_mainSurface, 0, 0, 0, 0); + + //_currentMask->drawMask(*_mainSurface,0,0,0,0); + _animationManager->render(); + + drawInfoLine(); + drawConversationLine(); + drawConversationIcons(); + drawSack(); + //drawPalette(); + +#if 0 + char test[256]; + if (_mouseX > 0 && _mouseX < 640 && _mouseY > 0 && _mouseY < 400) { + sprintf(test, "%d %d / mask %d layer %d z %d", _mouseX, _mouseY, getMask()->getData(_mouseX, _mouseY), getLayerAtPoint(_mouseX, _mouseY), getZAtPoint(_mouseX, _mouseY)); + + int32 c = *(uint8 *)_mainSurface->getBasePtr(_mouseX, _mouseY); + sprintf(test, "%d %d / color id %d %d,%d,%d", _mouseX, _mouseY, c, _finalPalette[c*3+0], _finalPalette[c*3+1], _finalPalette[c*3+2]); + + _fontRenderer->setFont(_fontToon); + _fontRenderer->renderText(40, 150, Common::String(test), 0); + } +#endif + + if (_firstFrame) { + copyToVirtualScreen(false); + fadeIn(5); + _firstFrame = false; + } else { + copyToVirtualScreen(true); + } +} + +void ToonEngine::copyToVirtualScreen(bool updateScreen) { + // render cursor last + if (!_gameState->_mouseHidden) { + _cursorAnimationInstance->setPosition(_mouseX - 40 + state()->_currentScrollValue - _cursorOffsetX, _mouseY - 40 - _cursorOffsetY, 0, false); + _cursorAnimationInstance->render(); + } + _system->copyRectToScreen((byte *)_mainSurface->pixels + state()->_currentScrollValue, 1280, 0, 0, 640, 400); + if (updateScreen) { + _system->updateScreen(); + _shouldQuit = shouldQuit(); // update game quit flag - this shouldn't be called all the time, as it's a virtual function + } +} + +void ToonEngine::doFrame() { + + if (_gameState->_inInventory) { + renderInventory(); + } else { + render(); + + int32 currentTimer = _system->getMillis(); +// Strangerke - Commented (not used) +// int32 elapsedTime = currentTimer - _oldTimer; + + update(currentTimer - _oldTimer); + _oldTimer = currentTimer; + _oldTimer2 = currentTimer; + } + parseInput(); +} + +enum MainMenuSelections { + MAINMENUHOTSPOT_NONE = 0, + MAINMENUHOTSPOT_START = 1, + MAINMENUHOTSPOT_INTRO = 2, + MAINMENUHOTSPOT_LOADGAME = 3, + MAINMENUHOTSPOT_HOTKEYS = 4, + MAINMENUHOTSPOT_CREDITS = 5, + MAINMENUHOTSPOT_QUIT = 6, + MAINMENUHOTSPOT_HOTKEYSCLOSE = 7 +}; + +enum MainMenuMasks { + MAINMENUMASK_BASE = 1, + MAINMENUMASK_HOTKEYS = 2, + MAINMENUMASK_EVERYWHERE = 3 +}; + +struct MainMenuFile { + int menuMask; + int id; + const char *animationFile; + int animateOnFrame; +}; + +#define MAINMENU_ENTRYCOUNT 12 +static const MainMenuFile mainMenuFiles[] = { + { MAINMENUMASK_BASE, MAINMENUHOTSPOT_START, "STARTBUT.CAF", 0 }, // "Start" button + { MAINMENUMASK_BASE, MAINMENUHOTSPOT_INTRO, "INTROBUT.CAF", 0 }, // "Intro" button + { MAINMENUMASK_BASE, MAINMENUHOTSPOT_LOADGAME, "LOADBUT.CAF", 0 }, // "Load Game" button + { MAINMENUMASK_BASE, MAINMENUHOTSPOT_HOTKEYS, "HOTBUT.CAF", 0 }, // "Hot Keys" button + { MAINMENUMASK_BASE, MAINMENUHOTSPOT_CREDITS, "CREDBUT.CAF", 0 }, // "Credits" button + { MAINMENUMASK_BASE, MAINMENUHOTSPOT_QUIT, "QUITBUT.CAF", 0 }, // "Quit" button + { MAINMENUMASK_BASE, MAINMENUHOTSPOT_NONE, "LEGALTXT.CAF", 0 }, // Legal Text + + { MAINMENUMASK_EVERYWHERE, MAINMENUHOTSPOT_NONE, "TOONGLOW.CAF", 6 }, // Clown glow + { MAINMENUMASK_EVERYWHERE, MAINMENUHOTSPOT_NONE, "TOONSTRK.CAF", 6 }, // Toonstruck title + { MAINMENUMASK_EVERYWHERE, MAINMENUHOTSPOT_NONE, "EYEGLOW.CAF", 4 }, // Clown eye glow + { MAINMENUMASK_EVERYWHERE, MAINMENUHOTSPOT_NONE, "PROPHEAD.CAF", 4 }, // Clown propellor head + { MAINMENUMASK_HOTKEYS, MAINMENUHOTSPOT_HOTKEYSCLOSE, "HOTKEYS.CAF", 0 } // Hotkeys display - clicking on it will close hotkeys +}; + +struct MainMenuEntry { + int menuMask; + int id; + Animation *animation; + Common::Rect rect; + int animateOnFrame; + int animateCurFrame; + int activeFrame; +}; + +bool ToonEngine::showMainmenu(bool &loadedGame) { + Picture *mainmenuPicture = new Picture(this); + mainmenuPicture->loadPicture("TITLESCR.CPS", true); + mainmenuPicture->setupPalette(); + + MainMenuEntry entries[MAINMENU_ENTRYCOUNT]; + + for (int entryNr = 0; entryNr < MAINMENU_ENTRYCOUNT; entryNr++) { + entries[entryNr].menuMask = mainMenuFiles[entryNr].menuMask; + entries[entryNr].id = mainMenuFiles[entryNr].id; + entries[entryNr].animation = new Animation(this); + entries[entryNr].animation->loadAnimation(mainMenuFiles[entryNr].animationFile); + if (entries[entryNr].id != MAINMENUHOTSPOT_NONE) + entries[entryNr].rect = entries[entryNr].animation->getRect(); + entries[entryNr].animateOnFrame = mainMenuFiles[entryNr].animateOnFrame; + entries[entryNr].animateCurFrame = 0; + entries[entryNr].activeFrame = 0; + } + + setCursor(1); + + bool doExit = false; + bool exitGame = false; + int clickingOn, clickRelease; + int menuMask = MAINMENUMASK_BASE; + AudioStreamInstance *mainmenuMusic = NULL; + bool musicPlaying = false; + + while (!doExit) { + clickingOn = MAINMENUHOTSPOT_NONE; + clickRelease = false; + + if (!musicPlaying) { + Common::SeekableReadStream *mainmenuMusicFile = resources()->openFile("misc/BR091013.MUS"); + mainmenuMusic = new AudioStreamInstance(_audioManager, _mixer, mainmenuMusicFile, true); + mainmenuMusic->play(false); + musicPlaying = true; + } + + while (!clickRelease) { + mainmenuPicture->draw(*_mainSurface, 0, 0, 0, 0); + + for (int entryNr = 0; entryNr < MAINMENU_ENTRYCOUNT; entryNr++) { + if (entries[entryNr].menuMask & menuMask) { + if (entries[entryNr].animateOnFrame) { + entries[entryNr].animateCurFrame++; + if (entries[entryNr].animateOnFrame <= entries[entryNr].animateCurFrame) { + entries[entryNr].activeFrame++; + if (entries[entryNr].activeFrame >= entries[entryNr].animation->_numFrames) + entries[entryNr].activeFrame = 0; + entries[entryNr].animateCurFrame = 0; + } + } + int32 frameNr = entries[entryNr].activeFrame; + if ((entries[entryNr].id == clickingOn) && (clickingOn != MAINMENUHOTSPOT_NONE)) + frameNr = 1; + entries[entryNr].animation->drawFrame(*_mainSurface, frameNr, 0, 0); + } + } + + parseInput(); + copyToVirtualScreen(true); + _system->delayMillis(17); + + if (_mouseButton & 1) { + // left mouse button pushed down + clickingOn = MAINMENUHOTSPOT_NONE; + for (int entryNr = 0; entryNr < MAINMENU_ENTRYCOUNT; entryNr++) { + if (entries[entryNr].menuMask & menuMask) { + if (entries[entryNr].id != MAINMENUHOTSPOT_NONE) { + if (entries[entryNr].rect.contains(_mouseX, _mouseY)) + clickingOn = entries[entryNr].id; + } + } + } + } else { + // left mouse button released/not pushed down + if (clickingOn != MAINMENUHOTSPOT_NONE) + clickRelease = true; + } + if (_shouldQuit) { + clickingOn = MAINMENUHOTSPOT_NONE; + clickRelease = true; + doExit = true; + } + } + + if (clickingOn != MAINMENUHOTSPOT_NONE) { + _audioManager->playSFX(10, 128, true); + } + + switch (clickingOn) { + case MAINMENUHOTSPOT_HOTKEYS: + menuMask = MAINMENUMASK_HOTKEYS; + continue; + case MAINMENUHOTSPOT_HOTKEYSCLOSE: + menuMask = MAINMENUMASK_BASE; + continue; + } + + if (musicPlaying) { + //stop music + mainmenuMusic->stop(false); + musicPlaying = false; + } + + + + switch (clickingOn) { + case MAINMENUHOTSPOT_START: + // Start game (actually exit main menu) + loadedGame = false; + doExit = true; + break; + case MAINMENUHOTSPOT_INTRO: + // Play intro movies + getMoviePlayer()->play("MISC/209_1M.SMK", 0x10); + getMoviePlayer()->play("MISC/209_2M.SMK", 0x10); + getMoviePlayer()->play("MISC/209_3M.SMK", 0x10); + break; + case MAINMENUHOTSPOT_LOADGAME: + doExit = loadGame(-1); + loadedGame = doExit; + exitGame = false; + break; + case MAINMENUHOTSPOT_CREDITS: + // Play credits movie + getMoviePlayer()->play("MISC/CREDITS.SMK", 0x0); + break; + case MAINMENUHOTSPOT_QUIT: + exitGame = true; + doExit = true; + break; + } + } + + return !exitGame; +} + +Common::Error ToonEngine::run() { + + if (!loadToonDat()) + return Common::kUnknownError; + + g_eventRec.registerRandomSource(_rnd, "toon"); + + initGraphics(640, 400, true); + init(); + + // play producer intro + getMoviePlayer()->play("MISC/VIELOGOM.SMK", 0x10); + + // show mainmenu + bool loadedGame = false; + if (!showMainmenu(loadedGame)) { + return Common::kNoError; + } + + //loadScene(17); + //loadScene(37); + if (!loadedGame) { + newGame(); + } + +// Strangerke - Commented (not used) +// int32 oldTimer = _system->getMillis(); + while (!_shouldQuit && _gameState->_currentScene != -1) + doFrame(); + return Common::kNoError; +} + +ToonEngine::ToonEngine(OSystem *syst, const ADGameDescription *gameDescription) + : Engine(syst), _gameDescription(gameDescription), _language(gameDescription->language) { + _system = syst; + _tickLength = 16; + _currentMask = 0; + _currentPicture = 0; + _roomScaleData = 0; + _shadowLUT = 0; + _isDemo = _gameDescription->flags & ADGF_DEMO; + + DebugMan.addDebugChannel(kDebugAnim, "Anim", "Animation debug level"); + DebugMan.addDebugChannel(kDebugCharacter, "Character", "Character debug level"); + DebugMan.addDebugChannel(kDebugAudio, "Audio", "Audio debug level"); + DebugMan.addDebugChannel(kDebugHotspot, "Hotspot", "Hotspot debug level"); + DebugMan.addDebugChannel(kDebugFont, "Font", "Font debug level"); + DebugMan.addDebugChannel(kDebugPath, "Path", "Path debug level"); + DebugMan.addDebugChannel(kDebugMovie, "Movie", "Movie debug level"); + DebugMan.addDebugChannel(kDebugPicture, "Picture", "Picture debug level"); + DebugMan.addDebugChannel(kDebugResource, "Resource", "Resource debug level"); + DebugMan.addDebugChannel(kDebugState, "State", "State debug level"); + DebugMan.addDebugChannel(kDebugTools, "Tools", "Tools debug level"); + DebugMan.addDebugChannel(kDebugText, "Text", "Text debug level"); + + switch (_language) { + case Common::EN_GRB: + case Common::EN_USA: + case Common::EN_ANY: + _gameVariant = 0; + break; + case Common::FR_FRA: + _gameVariant = 1; + break; + case Common::DE_DEU: + _gameVariant = 2; + break; + case Common::RU_RUS: + _gameVariant = 3; + break; + case Common::ES_ESP: + _gameVariant = 3; + break; + default: + // 0 - english + _gameVariant = 0; + break; + } +} + +ToonEngine::~ToonEngine() { + +} + +void ToonEngine::flushPalette() { + + uint8 vmpalette[1024]; + for (int32 i = 0; i < 256; i++) { + vmpalette[i*4+0] = _finalPalette[i*3+0]; + vmpalette[i*4+1] = _finalPalette[i*3+1]; + vmpalette[i*4+2] = _finalPalette[i*3+2]; + vmpalette[i*4+3] = 0; + } + _system->setPalette(vmpalette, 0, 256); +} +void ToonEngine::setPaletteEntries(uint8 *palette, int32 offset, int32 num) { + memcpy(_finalPalette + offset * 3, palette, num * 3); + uint8 vmpalette[1024]; + for (int32 i = 0; i < num; i++) { + vmpalette[i*4+0] = palette[i*3+0]; + vmpalette[i*4+1] = palette[i*3+1]; + vmpalette[i*4+2] = palette[i*3+2]; + vmpalette[i*4+3] = 0; + } + _system->setPalette(vmpalette, offset, num); +} + +void ToonEngine::simpleUpdate() { + int32 elapsedTime = _system->getMillis() - _oldTimer2; + _oldTimer2 = _system->getMillis(); + _oldTimer = _oldTimer2; + + updateCharacters(elapsedTime); + updateAnimationSceneScripts(elapsedTime); + updateTimer(elapsedTime); + _animationManager->update(elapsedTime); + render(); + + if (!_audioManager->voiceStillPlaying()) { + _currentTextLine = 0; + _currentTextLineId = -1; + } +} + +void ToonEngine::fixPaletteEntries(uint8 *palette, int num) { + // some color values are coded on 6bits ( for old 6bits DAC ) + for (int32 i = 0; i < num * 3; i++) { + int32 a = palette[i]; + a = a * 4; + if (a > 255) + a = 255; + palette[i] = a; + } +} + +// adapted from KyraEngine +void ToonEngine::updateAnimationSceneScripts(int32 timeElapsed) { + + + static int32 numReentrant = 0; + numReentrant++; + +// Strangerke - Commented (not used) +// uint32 nextTime = _system->getMillis() + _tickLength; + const int startScript = _lastProcessedSceneScript; + + _updatingSceneScriptRunFlag = true; + + do { + if (_sceneAnimationScripts[_lastProcessedSceneScript]._lastTimer <= _system->getMillis() && + !_sceneAnimationScripts[_lastProcessedSceneScript]._frozen) { + _animationSceneScriptRunFlag = true; + + while (_animationSceneScriptRunFlag && _sceneAnimationScripts[_lastProcessedSceneScript]._lastTimer <= _system->getMillis() && !_shouldQuit) { + if (!_script->run(&_sceneAnimationScripts[_lastProcessedSceneScript]._state)) + _animationSceneScriptRunFlag = false; + + //waitForScriptStep(); + + if (_sceneAnimationScripts[_lastProcessedSceneScript]._frozen) + break; + } + + } + + if (!_script->isValid(&_sceneAnimationScripts[_lastProcessedSceneScript]._state)) { + _script->start(&_sceneAnimationScripts[_lastProcessedSceneScript]._state, 9 + _lastProcessedSceneScript); + _animationSceneScriptRunFlag = false; + } + + ++_lastProcessedSceneScript; + if (_lastProcessedSceneScript >= state()->_locations[state()->_currentScene]._numSceneAnimations) + _lastProcessedSceneScript = 0; + + } while (_lastProcessedSceneScript != startScript && !_shouldQuit); + + + _updatingSceneScriptRunFlag = false; + numReentrant--; + +} + +void ToonEngine::loadScene(int32 SceneId, bool forGameLoad) { + char temp[256]; + char temp2[256]; + + + _firstFrame = true; + + _gameState->_lastVisitedScene = _gameState->_currentScene; + _gameState->_currentScene = SceneId; + + _saveBufferStream->seek(0); + + if (SceneId == -1) { + // this scene -1 is loaded at the very end of the game + getAudioManager()->stopMusic(); + getMoviePlayer()->play("CREDITS.SMK"); + return; + } + + // find out in what chapter we are (the script function ProcessToNextChapter is actually not called ) + // the location flag has the chapter info in it + int32 flag = _gameState->_locations[SceneId]._flags; + if (flag) { + _gameState->_currentChapter = 0; + do { + _gameState->_currentChapter++; + flag >>= 1; + } while ((flag & 1) == 0); + } + + for (int32 i = 0; i < 8; i++) { + if (_characters[i]) _characters[i]->setFlag(0); + } + _drew->playStandingAnim(); + _drew->setVisible(true); + + // hide flux in chapter 2 + if (_gameState->_currentChapter == 1) { + _flux->playStandingAnim(); + _flux->setVisible(true); + } else { + _flux->setVisible(false); + } + + _lastMouseButton = 0; + _mouseButton = 0; + _currentHotspotItem = -1; + _gameState->_sackVisible = true; + _gameState->_inCloseUp = false; + _gameState->_inConversation = false; + _gameState->_inInventory = false; + _gameState->_inCutaway = false; + _gameState->_currentScrollValue = 0; + _gameState->_currentScrollLock = false; + _gameState->_inCloseUp = false; + + + if (_gameState->_mouseState >= 0) + addItemToInventory(_gameState->_mouseState); + + _gameState->_mouseState = -1; + + + // load package + strcpy(temp, createRoomFilename(Common::String::printf("%s.pak", _gameState->_locations[_gameState->_currentScene]._name).c_str()).c_str()); + resources()->openPackage(temp, true); + + strcpy(temp, state()->_locations[SceneId]._name); + strcat(temp, ".npp"); + loadAdditionalPalette(temp, 0); + + strcpy(temp, state()->_locations[SceneId]._name); + strcat(temp, ".np2"); + loadAdditionalPalette(temp, 1); + + strcpy(temp, state()->_locations[SceneId]._name); + strcat(temp, ".cup"); + loadAdditionalPalette(temp, 2); + + // load artwork + strcpy(temp, state()->_locations[SceneId]._name); + strcat(temp, ".cps"); + _currentPicture = new Picture(this); + _currentPicture->loadPicture(temp); + _currentPicture->setupPalette(); + + strcpy(temp, state()->_locations[SceneId]._name); + strcat(temp, ".msc"); + _currentMask = new Picture(this); + if (_currentMask->loadPicture(temp)) + _pathFinding->init(_currentMask); + + strcpy(temp, state()->_locations[SceneId]._name); + strcat(temp, ".tre"); + _roomTexts = new TextResource(this); + _roomTexts->loadTextResource(temp); + + + strcpy(temp, state()->_locations[SceneId]._name); + strcat(temp, ".dat"); + uint32 fileSize; + uint8 *sceneData = resources()->getFileData(temp, &fileSize); + if (sceneData) { + _roomScaleData = new uint8[fileSize]; + memcpy(_roomScaleData, sceneData, fileSize); + } + + strcpy(temp, state()->_locations[SceneId]._name); + strcat(temp, ".svi"); + strcpy(temp2, createRoomFilename(Common::String::printf("%s.svl", _gameState->_locations[_gameState->_currentScene]._name).c_str()).c_str()); + _audioManager->loadAudioPack(1, temp, temp2); + strcpy(temp, state()->_locations[SceneId]._name); + strcpy(temp2, state()->_locations[SceneId]._name); + strcat(temp, ".sei"); + strcat(temp2, ".sel"); + _audioManager->loadAudioPack(3, temp, temp2); + + strcpy(temp, state()->_locations[SceneId]._name); + strcat(temp, ".ric"); + if (state()->_locations[SceneId]._flags & 0x40) { + strcpy(temp2, state()->_locations[SceneId]._cutaway); + strcat(temp2, ".ric"); + } else { + strcpy(temp2, ""); + } + _hotspots->LoadRif(temp, temp2); + restoreRifFlags(_gameState->_currentScene); + + + strcpy(temp, state()->_locations[SceneId]._name); + strcat(temp, ".cnv"); + uint32 convfileSize; + uint8 *convData = resources()->getFileData(temp, &convfileSize); + if (convData) { + assert(convfileSize < 4096 * sizeof(int16)); + memcpy(_conversationData , convData, convfileSize); + prepareConversations(); + } + + // load script + strcpy(temp, state()->_locations[SceneId]._name); + strcat(temp, ".emc"); + + _oldTimer = _system->getMillis(); + _oldTimer2 = _oldTimer; + + // fix the weird scaling issue during one frame when entering new scene + _drew->update(0); + _flux->update(0); + + + _script->load(temp, &_scriptData, &_script_func->_opcodes); + _script->init(&_scriptState[0], &_scriptData); + _script->init(&_scriptState[1], &_scriptData); + _script->init(&_scriptState[2], &_scriptData); + _script->init(&_scriptState[3], &_scriptData); + + //_script->RoomScript->Decompile("decomp.txt"); + //RoomScript->Decompile2("decomp2.txt"); + + for (int i = 0; i < state()->_locations[SceneId]._numSceneAnimations; i++) { + _sceneAnimationScripts[i]._data = &_scriptData; + _script->init(&_sceneAnimationScripts[i]._state, _sceneAnimationScripts[i]._data); + if (!forGameLoad) { + _script->start(&_sceneAnimationScripts[i]._state, 9 + i); + _sceneAnimationScripts[i]._lastTimer = getSystem()->getMillis(); + _sceneAnimationScripts[i]._frozen = false; + } + } + + // launch mus +#if 0 + SoundManager.StopMusic(); + SoundManager.UnloadMusic(); + SoundManager.LoadMusic(GameLocations[Scene].name, GameLocations[Scene].mus); + SoundManager.PlayMusic(); +#endif + + playRoomMusic(); + + _lastProcessedSceneScript = 0; + _gameState->_locations[SceneId]._visited = true; + + + setupGeneralPalette(); + createShadowLUT(); + + + + if (!forGameLoad) { + + _script->start(&_scriptState[0], 0); + + while (_script->run(&_scriptState[0])) + waitForScriptStep(); + + _script->start(&_scriptState[0], 8); + + while (_script->run(&_scriptState[0])) + waitForScriptStep(); + + if (_gameState->_nextSpecialEnterX != -1 && _gameState->_nextSpecialEnterY != -1) { + _drew->setPosition(_gameState->_nextSpecialEnterX, _gameState->_nextSpecialEnterY); + _gameState->_nextSpecialEnterX = -1; + _gameState->_nextSpecialEnterY = -1; + } + + _script->start(&_scriptState[0], 3); + + while (_script->run(&_scriptState[0])) + waitForScriptStep(); + + _script->start(&_scriptState[0], 4); + + while (_script->run(&_scriptState[0])) + waitForScriptStep(); + + } + + state()->_mouseHidden = false; +} + +void ToonEngine::setupGeneralPalette() { + setPaletteEntries(_additionalPalette1, 232, 23); + setPaletteEntries(_universalPalette, 200, 32); + setPaletteEntries(_fluxPalette, 192, 8); + + if (_drew) + _drew->setupPalette(); +} + +void ToonEngine::loadAdditionalPalette(Common::String fileName, int32 mode) { + + uint32 size = 0; + uint8 *palette = resources()->getFileData(fileName, &size); + if (!palette) + return; + + switch (mode) { + case 0: + memcpy(_additionalPalette1, palette, 69); + fixPaletteEntries(_additionalPalette1, 23); + break; + case 1: + memcpy(_additionalPalette2, palette, 69); + fixPaletteEntries(_additionalPalette2, 23); + break; + case 2: + memcpy(_cutawayPalette, palette, 768); + fixPaletteEntries(_cutawayPalette, 256); + break; + case 3: + memcpy(_universalPalette, palette, 96); + fixPaletteEntries(_universalPalette, 32); + break; + case 4: + memcpy(_fluxPalette, palette, 24); + fixPaletteEntries(_fluxPalette , 8); + break; + default: + warning("loadAdditionalPalette() - Unknown mode"); + } +} + +void ToonEngine::initChapter() { + + EMCData data; + EMCState status; + memset(&data, 0, sizeof(data)); + memset(&status, 0, sizeof(status)); + + _script = new EMCInterpreter(this); + + _script->load("_START01.EMC", &data, &_script_func->_opcodes); + _script->init(&status, &data); + _script->start(&status, 0); + while (_script->run(&status)) + waitForScriptStep(); + + setupGeneralPalette(); + +} + +void ToonEngine::loadCursor() { + _cursorAnimation = new Animation(this); + _cursorAnimation->loadAnimation("MOUSE.CAF"); + _cursorAnimationInstance = _animationManager->createNewInstance(kAnimationCursor); + _cursorAnimationInstance->setAnimation(_cursorAnimation); + _cursorAnimationInstance->setVisible(true); + _cursorAnimationInstance->setFrame(0); + _cursorAnimationInstance->setAnimationRange(0, 0); + _cursorAnimationInstance->setFps(8); + + setCursor(5); +} + +void ToonEngine::setCursor(int32 type, bool inventory, int32 offsetX, int32 offsetY) { + + static const int32 offsets[] = { + 0, 1, 1, 6, 7, 1, 8, 10, 18, 10, + 28, 8, 36, 10, 46, 10, 56, 10, 66, 10, + 76, 10, 86, 10, 96, 10, 106, 10, 116, 10, + 126, 10 + }; + + if (!inventory) { + _cursorAnimationInstance->setAnimation(_cursorAnimation); + _cursorAnimationInstance->setAnimationRange(offsets[type * 2 + 0], offsets[type * 2 + 0] + offsets[type * 2 + 1] - 1); + _cursorAnimationInstance->playAnimation(); + } else { + _cursorAnimationInstance->setAnimation(_inventoryIcons); + _cursorAnimationInstance->setAnimationRange(type, type); + _cursorAnimationInstance->playAnimation(); + } + + _cursorOffsetX = offsetX; + _cursorOffsetY = offsetY; +} + +void ToonEngine::setSceneAnimationScriptUpdate(bool enable) { + _animationSceneScriptRunFlag = enable; +} + +bool ToonEngine::isUpdatingSceneAnimation() { + return _updatingSceneScriptRunFlag; +} + +int32 ToonEngine::getCurrentUpdatingSceneAnimation() { + return _lastProcessedSceneScript; +} + +int32 ToonEngine::randRange(int32 minStart, int32 maxStart) { + return _rnd.getRandomNumberRng(minStart, maxStart); +} + +int32 ToonEngine::runEventScript(int32 x, int32 y, int32 mode, int32 id, int32 scriptId) { + + if (_currentScriptRegion >= 4) + return 0; + + EMCState *status = &_scriptState[_currentScriptRegion]; + _script->init(status, &_scriptData); + + // setup registers + status->regs[0] = x; + status->regs[1] = y; + status->regs[2] = 0; + status->regs[3] = 0; + status->regs[4] = _gameState->_mouseState; // + status->regs[5] = 0; + status->regs[6] = scriptId; + status->regs[7] = mode; + status->regs[8] = id; + + _currentScriptRegion++; + + _script->start(status, 1); + while (_script->run(status)) + waitForScriptStep(); + + _currentScriptRegion--; + + return status->regs[2]; +} + +void ToonEngine::clickEvent() { + bool leftButton = false; + bool rightButton = false; + + if ((_lastMouseButton & 0x1) == 1 && (_mouseButton & 0x1) == 0) + leftButton = true; + if ((_lastMouseButton & 0x2) == 2 && (_mouseButton & 0x2) == 0) + rightButton = true; + + _lastMouseButton = _mouseButton; + if (!leftButton && !rightButton) + return; + + if (_gameState->_sackVisible) { + if (_mouseX > 0 && _mouseX < 40 && _mouseY > 356 && _mouseY < 396) { + if (_gameState->_mouseState >= 0 && !rightButton) { + addItemToInventory(_gameState->_mouseState); + setCursor(0, false, 0, 0); + _currentHotspotItem = -1; + return; + } else { + showInventory(); + } + return; + } + } + + // with inventory + if (rightButton && _gameState->_mouseState >= 0) { + addItemToInventory(_gameState->_mouseState); + setCursor(0, false, 0, 0); + _currentHotspotItem = -1; + return; + } + + + int32 mouseX = _mouseX; + if (_gameState->_inCutaway) { + mouseX += 1280; + } + + // find hotspot + int32 hot = _hotspots->Find(mouseX + state()->_currentScrollValue , _mouseY); + HotspotData *currentHot = 0; + if (hot > -1) { + currentHot = _hotspots->Get(hot); + } + + if (_currentHotspotItem == -3) { + if (_gameState->_mouseState <= 0) { + if (leftButton) + createMouseItem(104); + else + characterTalk(518); + } + } + if (_currentHotspotItem == -4) { + if (_gameState->_mouseState >= 0) { + if (leftButton) + if (!handleInventoryOnInventory(0, _gameState->_mouseState)) { + playSoundWrong(); + } + return; + } + } + + + if (!currentHot) { + int32 xx, yy; + + if (_gameState->_inCutaway || _gameState->_inInventory || _gameState->_inCloseUp) + return; + + if (_pathFinding->findClosestWalkingPoint(_mouseX + _gameState->_currentScrollValue , _mouseY, &xx, &yy)) + _drew->walkTo(xx, yy); + return; + } + + int commandId = 0; + if (_gameState->_mouseState < 0) { + // left or right click + if (rightButton) + commandId = 2 + 8; + else + commandId = 0 + 8; + } else { + commandId = 2 * (_gameState->_mouseState - 1) + 16; + } + + _drew->stopWalk(); + + int16 command = currentHot->getData(commandId); + int16 argument = currentHot->getData(commandId + 1); + int16 priority = currentHot->getPriority(); +// Strangerke - Commented (not used) +// int16 ref = currentHot->getRef(); +// int16 pad1 = currentHot->getData(6); + + if (!_gameState->_inCutaway && !_gameState->_inCloseUp) { + if (leftButton && (currentHot->getData(4) != 2 || _gameState->_mouseState >= 0) && currentHot->getData(5) != -1) { + if (currentHot->getData(5)) { + if (!_drew->walkTo(currentHot->getData(5), currentHot->getData(6))) { + // walk was canceled ? + return; + } + } else { + if (!_drew->walkTo(_mouseX, _mouseY)) { + // walk was canceled ? + return; + } + } + } + } + + int32 result = 0; + + switch (command) { + case 1: + sayLines(1, argument); + break; + case 2: + result = runEventScript(_mouseX, _mouseY, command, argument, priority); + break; + case 3: + runEventScript(_mouseX, _mouseY, command, argument, priority); + result = 0; + break; + case 4: + playSFX(argument, 128); + break; + case 5: + break; + case 6: + createMouseItem(argument); + currentHot->setData(7, -1); + break; + case 7: + // switch to CloseUp +// Strangerke - Commented (not used) +// int closeup = 1; + break; + case 8: + // face flux + sayLines(1, argument); + break; + case 9: + case 10: +// Strangerke - Commented (not used) +// if (rand() % 1 == 1) { +// } else { +// } + // setFluxFacingPoint(x,y) + sayLines(2, argument); + break; + case 11: + sayLines(3, argument); + break; + default: + playSoundWrong(); + return; + } + + if (result == 3) { + int32 val = _scriptState[_currentScriptRegion].regs[4]; + currentHot->setData(4, currentHot->getData(4) & val); + } + if (result == 2 || result == 3) { + int32 val = _scriptState[_currentScriptRegion].regs[6]; + currentHot->setData(7, val); + } + + if (result == 1) { + int32 val = _scriptState[_currentScriptRegion].regs[4]; + currentHot->setData(4, currentHot->getData(4) & val); + } + +} + +void ToonEngine::selectHotspot() { + int32 x1 = 0; + int32 x2 = 0; + int32 y1 = 0; + int32 y2 = 0; + + int32 mouseX = _mouseX; + + if (_gameState->_inCutaway) + mouseX += 1280; + + if (_gameState->_sackVisible) { + if (_mouseX > 0 && _mouseX < 40 && _mouseY > 356 && _mouseY < 396) { + _currentHotspotItem = -2; + + if (_gameState->_mouseState < 0) { + int mode = 3; + setCursor(mode); + } else { + setCursor(_gameState->_mouseState, true, -18, -14); + } + + return; + } + } + + if (_gameState->_mouseState > 0) { + // picked drew? + getDrew()->getAnimationInstance()->getRect(&x1, &y1, &x2, &y2); + if (_mouseX + _gameState->_currentScrollValue >= x1 && _mouseX + _gameState->_currentScrollValue <= x2 && _mouseY >= y1 && _mouseY <= y2) { + _currentHotspotItem = -4; + return; + } + } + + if (getFlux()->getVisible()) { + getFlux()->getAnimationInstance()->getRect(&x1, &y1, &x2, &y2); + if (_mouseX + _gameState->_currentScrollValue >= x1 && _mouseX + _gameState->_currentScrollValue <= x2 && _mouseY >= y1 && _mouseY <= y2) { + _currentHotspotItem = -3; + + if (_gameState->_mouseState < 0) { + int mode = 3; + setCursor(mode); + } else { + setCursor(_gameState->_mouseState, true, -18, -14); + } + + return; + } + } + + int32 hot = _hotspots->Find(mouseX + state()->_currentScrollValue, _mouseY); + if (hot != -1) { + HotspotData *hotspot = _hotspots->Get(hot); + int32 item = hotspot->getData(14); + if (hotspot->getType() == 3) + item += 2000; + + // update palette based on ticks if we're in "use from inventory mode" + if (_gameState->_mouseState >= 0) { + + int32 tick = _system->getMillis() / _tickLength; + int32 animReverse = tick & 0x10; + int32 animStep = tick & 0xf; + + byte color[3]; + if (animReverse == 0) { + color[0] = 16 * animStep; + color[1] = 0; + color[2] = 0; + } else { + color[0] = 16 * (15 - animStep); + color[1] = 0; + color[2] = 0; + } + setPaletteEntries(color, 255, 1); + } + +#if 0 + if (item == _currentHotspotItem) + return; +#endif + _currentHotspotItem = item; + if (_gameState->_mouseState < 0) { + int mode = hotspot->getMode(); + setCursor(mode); + } else { + setCursor(_gameState->_mouseState, true, -18, -14); + } + } else { + _currentHotspotItem = 0; + + if (_gameState->_mouseState < 0) { + setCursor(0); + } else { + byte color[3]; + color[0] = 0; + color[1] = 0; + color[2] = 0; + setCursor(_gameState->_mouseState, true, -18, -14); + setPaletteEntries(color, 255, 1); + } + } +} + +void ToonEngine::exitScene() { + + fadeOut(5); + + // disable all scene animation + for (int32 i = 0; i < 64; i++) { + if (_sceneAnimations[i]._active) { + delete _sceneAnimations[i]._animation; + _sceneAnimations[i]._active = false; + _animationManager->removeInstance(_sceneAnimations[i]._animInstance); + _sceneAnimations[i]._animInstance = 0; + _sceneAnimations[i]._animation = 0; + } + } + for (int32 i = 0; i < 64; i++) { + _sceneAnimationScripts[i]._frozen = true; + _sceneAnimationScripts[i]._active = false; + } + + // remove all characters except drew and flux + for (int32 i = 0; i < 8; i++) { + if (_characters[i] != _drew && _characters[i] != _flux) { + if (_characters[i]) { + delete _characters[i]; + _characters[i] = 0; + } + } else { + _characters[i]->stopSpecialAnim(); + } + } + + for (int32 i = 0; i < 2; i++) { + _gameState->_timerEnabled[i] = false; + } + + // put back our item if inventory if needed + if (_gameState->_mouseState >= 0) { + addItemToInventory(_gameState->_mouseState); + _gameState->_mouseState = -1; + } + + char temp[256]; + strcpy(temp, createRoomFilename(Common::String::printf("%s.pak", _gameState->_locations[_gameState->_currentScene]._name).c_str()).c_str()); + resources()->closePackage(temp); + + _drew->stopWalk(); + _flux->stopWalk(); + + storeRifFlags(_gameState->_currentScene); +} + +// flip between the cutaway scene and the normal scene +void ToonEngine::flipScreens() { + _gameState->_inCloseUp = !_gameState->_inCloseUp; + + if (_gameState->_inCloseUp) { + _gameState->_currentScrollValue = 640; + setPaletteEntries(_cutawayPalette, 1, 128); + setPaletteEntries(_additionalPalette2, 232, 23); + } else { + _gameState->_currentScrollValue = 0; + _currentPicture->setupPalette(); + setupGeneralPalette(); + } + flushPalette(); +} + +void ToonEngine::fadeIn(int32 numFrames) { + for (int32 f = 0; f < numFrames; f++) { + + uint8 vmpalette[1024]; + for (int32 i = 0; i < 256; i++) { + vmpalette[i*4+0] = f * _finalPalette[i*3+0] / (numFrames - 1); + vmpalette[i*4+1] = f * _finalPalette[i*3+1] / (numFrames - 1); + vmpalette[i*4+2] = f * _finalPalette[i*3+2] / (numFrames - 1); + vmpalette[i*4+3] = 0; + } + _system->setPalette(vmpalette, 0, 256); + _system->updateScreen(); + _system->delayMillis(_tickLength); + } +} + +void ToonEngine::fadeOut(int32 numFrames) { + for (int32 f = 0; f < numFrames; f++) { + + uint8 vmpalette[1024]; + for (int32 i = 0; i < 256; i++) { + vmpalette[i*4+0] = (numFrames - f - 1) * _finalPalette[i*3+0] / (numFrames - 1); + vmpalette[i*4+1] = (numFrames - f - 1) * _finalPalette[i*3+1] / (numFrames - 1); + vmpalette[i*4+2] = (numFrames - f - 1) * _finalPalette[i*3+2] / (numFrames - 1); + vmpalette[i*4+3] = (numFrames - f - 1); + } + _system->setPalette(vmpalette, 0, 256); + _system->updateScreen(); + _system->delayMillis(_tickLength); + } +} + +void ToonEngine::initFonts() { + _fontRenderer = new FontRenderer(this); + _fontToon = new Animation(this); + _fontToon->loadAnimation("misc/toonfont.caf"); + + _fontEZ = new Animation(this); + _fontEZ->loadAnimation("misc/ezfont.caf"); +} + +void ToonEngine::drawInfoLine() { + if (_currentHotspotItem != 0 && !_gameState->_mouseHidden && !_gameState->_inConversation) { + const char *infoTool = NULL; + if (_currentHotspotItem >= 0 && _currentHotspotItem < 2000) { + infoTool = _roomTexts->getText(_currentHotspotItem); + } else if (_currentHotspotItem <= -1) { +// static const char * const specialInfoLine[] = { "Exit non defined", "Bottomless Bag", "Flux", "Drew Blanc" }; + infoTool = _specialInfoLine[-1 - _currentHotspotItem]; + } else { + int32 loc = _currentHotspotItem - 2000; + // location names are hardcoded ... + infoTool = getLocationString(loc, _gameState->_locations[loc]._visited); + } + if (infoTool) { + _fontRenderer->setFontColor(0xc8, 0xdd, 0xe3); + _fontRenderer->setFont(_fontToon); + _fontRenderer->renderText(320 + _gameState->_currentScrollValue, 398, infoTool, 5); + } + } +} + +const char *ToonEngine::getLocationString(int32 locationId, bool alreadyVisited) { + if (alreadyVisited) + return _locationDirVisited[locationId]; + else + return _locationDirNotVisited[locationId]; +} + +int32 ToonEngine::getScaleAtPoint(int32 x, int32 y) { + if (!_currentMask) + return 1024; + + int32 maskData = _currentMask->getData(x, y) & 0x1f; + return _roomScaleData[maskData+2] * 1024 / 100; +} + +int32 ToonEngine::getLayerAtPoint(int32 x, int32 y) { + if (!_currentMask) + return 0; + + int32 maskData = _currentMask->getData(x, y) & 0x1f; + return _roomScaleData[maskData+130] << 5; +} + +int32 ToonEngine::getZAtPoint(int32 x, int32 y) { + if (!_currentMask) + return 0; + return _currentMask->getData(x, y) & 0x1f; +} + +void ToonEngine::storeRifFlags(int32 location) { + + if (_gameState->_locations[location]._numRifBoxes != _hotspots->getCount()) { + _gameState->_locations[location]._numRifBoxes = _hotspots->getCount(); + } + + for (int32 i = 0; i < _hotspots->getCount(); i++) { + _gameState->_locations[location]._rifBoxesFlags[i * 2 + 0] = _hotspots->Get(i)->getData(4); + _gameState->_locations[location]._rifBoxesFlags[i * 2 + 1] = _hotspots->Get(i)->getData(7); + } +} + +void ToonEngine::restoreRifFlags(int32 location) { + if (_hotspots) { + if (!_gameState->_locations[location]._visited) { + for (int32 i = 0; i < _hotspots->getCount(); i++) { + _gameState->_locations[location]._rifBoxesFlags[i * 2 + 0] = _hotspots->Get(i)->getData(4); + _gameState->_locations[location]._rifBoxesFlags[i * 2 + 1] = _hotspots->Get(i)->getData(7); + } + _gameState->_locations[location]._numRifBoxes = _hotspots->getCount(); + } else { + if (_gameState->_locations[location]._numRifBoxes != _hotspots->getCount()) + return; + + for (int32 i = 0; i < _hotspots->getCount(); i++) { + _hotspots->Get(i)->setData(4, _gameState->_locations[location]._rifBoxesFlags[i * 2 + 0]); + _hotspots->Get(i)->setData(7, _gameState->_locations[location]._rifBoxesFlags[i * 2 + 1]); + } + } + } +} + +void ToonEngine::sayLines(int numLines, int dialogId) { + // exit conversation state + + // if (inInventory) + // character_talks(dialogid, -1, 0, 0); + // else + +#if 0 + int oldShowMouse = 0; + + if (Game.MouseHiddenCount <= 0) { + Game.MouseHiddenCount = 1; + oldShowMouse = 1; + } +#endif + + int32 currentLine = dialogId; + + for (int32 i = 0; i < numLines; i++) { + if (!characterTalk(currentLine)) + break; + + while (_audioManager->voiceStillPlaying() && !_shouldQuit) + doFrame(); + + // find next line + if (currentLine < 1000) + currentLine = _roomTexts->getNext(currentLine); + else + currentLine = _genericTexts->getNext(currentLine - 1000) + 1000; + } + +#if 0 + if (oldShowMouse) + Game.MouseHiddenCount = 0; +#endif + +} + +int32 ToonEngine::simpleCharacterTalk(int32 dialogid) { + int32 myId = 0; + +// Strangerke - Commented (not used) +#if 0 + char *myLine; + if (dialogid < 1000) { + myLine = _roomTexts->getText(dialogid); + myId = dialogid; + } else { + myLine = _genericTexts->getText(dialogid - 1000); + myId = dialogid - 1000; + } + debugC(0, 0xfff, "Talker = %d will say '%s' \n", READ_LE_UINT16(c - 2), myLine); +#endif + + if (_audioManager->voiceStillPlaying()) + _audioManager->stopCurrentVoice(); + + if (dialogid < 1000) { + myId = _roomTexts->getId(dialogid); + _audioManager->playVoice(myId, false); + } else { + myId = _genericTexts->getId(dialogid - 1000); + _audioManager->playVoice(myId, true); + } + + return 1; +} + +void ToonEngine::playTalkAnimOnCharacter(int32 animID, int32 characterId, bool talker) { + if (animID || talker) { +// Strangerke - Commented (not used) +#if 0 + if (_gameState->_inCutaway || _gameState->_inInventory) { + if (talker) { + // character talks + } + } else +#endif + if (characterId == 0) { + _drew->playAnim(animID, 0, (talker ? 8 : 0) + 2); + } else if (characterId == 1) { + // stop flux if he is walking + if (_flux->getFlag() & 1) { + _flux->stopWalk(); + } + _flux->playAnim(animID, 0, (talker ? 8 : 0) + 2); + _flux->setFlag(_flux->getFlag() | 1); + } else { + Character *character = getCharacterById(characterId); + if (character) { + character->playAnim(animID, 0, (talker ? 8 : 0) + 2); + } + } + } else { + Character *character = getCharacterById(characterId); + if (character) + character->setAnimFlag(character->getAnimFlag() | 1); + } +} + +int32 ToonEngine::characterTalk(int32 dialogid, bool blocking) { + if (blocking == false && _audioManager->voiceStillPlaying()) { + // someone is already talking, and this voice is not important + // skip it + return 0; + } + + int32 myId = 0; + char *myLine; + if (dialogid < 1000) { + myLine = _roomTexts->getText(dialogid); + myId = dialogid; + } else { + myLine = _genericTexts->getText(dialogid - 1000); + myId = dialogid - 1000; + } + + if (!myLine) + return 0; + + bool oldMouseHidden = _gameState->_mouseHidden; + if (blocking) { + _gameState->_mouseHidden = true; + } + + + // get what is before the string + int a = READ_LE_UINT16(myLine - 2); + char *b = myLine - 2 - 4 * a; + + char *c = b - 2; // v6 + int numParticipants = READ_LE_UINT16(c); // num dialogue participants + + char *e = c - 2 - 4 * numParticipants; + READ_LE_UINT16(e); + +// Strangerke - Commented (not used) +// char *g = e - 2 * f; + + // flag as talking +// Strangerke - Commented (not used) +// char *h = c; + + + // if one voice is still playing, wait ! + if (blocking) { + while (_audioManager->voiceStillPlaying() && !_shouldQuit) + doFrame(); + + char *cc = c; + Character *waitChar; + for (int32 i = 0; i < numParticipants - 1; i++) { + // listener + int32 listenerId = READ_LE_UINT16(cc - 2); + cc -= 4; + waitChar = getCharacterById(listenerId); + if (waitChar) { + while ((waitChar->getAnimFlag() & 0x10) == 0x10 && !_shouldQuit) + doFrame(); + } + + } + int32 talkerId = READ_LE_UINT16(cc - 2); + + waitChar = getCharacterById(talkerId); + if (waitChar && !_gameState->_inInventory) { + while ((waitChar->getAnimFlag() & 0x10) == 0x10 && !_shouldQuit) + doFrame(); + } + } else { + if (_audioManager->voiceStillPlaying()) + _audioManager->stopCurrentVoice(); + } + + for (int32 i = 0; i < numParticipants - 1; i++) { + // listener + int32 listenerId = READ_LE_UINT16(c - 2); + int32 listenerAnimId = READ_LE_UINT16(c - 4); + if (blocking) playTalkAnimOnCharacter(listenerAnimId, listenerId, false); + c -= 4; + } + + int32 talkerId = READ_LE_UINT16(c - 2); + int32 talkerAnimId = READ_LE_UINT16(c - 4); + + _currentTextLine = myLine; + _currentTextLineCharacterId = talkerId; + _currentTextLineId = dialogid; + + if (blocking) { + playTalkAnimOnCharacter(talkerAnimId, talkerId, true); + } else { + Character *character = getCharacterById(talkerId); + if (character) + character->stopSpecialAnim(); + } + + debugC(0, 0xfff, "Talker = %d (num participants : %d) will say '%s'", talkerId , numParticipants, myLine); + + + getTextPosition(talkerId, &_currentTextLineX, &_currentTextLineY); + + if (dialogid < 1000) { + myId = _roomTexts->getId(dialogid); + _audioManager->playVoice(myId, false); + } else { + myId = _genericTexts->getId(dialogid - 1000); + _audioManager->playVoice(myId, true); + } + + if (blocking) { + while (_audioManager->voiceStillPlaying() && !_shouldQuit) + doFrame(); + _gameState->_mouseHidden = oldMouseHidden && _gameState->_mouseHidden; + } + + + return 1; +} + +void ToonEngine::haveAConversation(int32 convId) { + setCursor(0); + + _gameState->_inConversation = true; + _gameState->_showConversationIcons = false; + _gameState->_exitConversation = false; + _gameState->_sackVisible = false; + Conversation *conv = &state()->_conversationState[convId]; + _gameState->_currentConversationId = convId; + + // change the music to the "conversation" music if needed. + playRoomMusic(); + + if (conv->_enable) { + // fix dialog script based on new flags + for (int32 i = 0; i < 10; i++) { + if (conv->state[i]._data2 == 1 || conv->state[i]._data2 == 3) { + if (getConversationFlag(_gameState->_currentScene, conv->state[i]._data3)) + conv->state[i]._data2 = 1; + else + conv->state[i]._data2 = 3; + } + } + + // if current voice stream sub 15130 + processConversationClick(conv , 2); + doFrame(); + } + + + _mouseButton = 0; + _gameState->_firstConverstationLine = true; + + while (!_gameState->_exitConversation && !_shouldQuit) { + _gameState->_mouseHidden = false; + _gameState->_showConversationIcons = true; + int32 oldMouseButton = _mouseButton; + while (!_shouldQuit) { + doFrame(); + + if (_mouseButton != 0) { + if (!oldMouseButton) + break; + } else { + oldMouseButton = 0; + } + } + int selected = -1; + int a = 0; + for (int i = 0; i < 10; i++) { + if (conv->state[i]._data2 == 1) { + if (_mouseX > 50 + a * 60 && _mouseX < 100 + a * 60 && _mouseY >= 336 && _mouseY <= 386) { + selected = i; + break; + } + a++; + } + } + if (_shouldQuit) return; + _gameState->_showConversationIcons = false; + _gameState->_mouseHidden = 1; + + + if (selected < 0 || selected == 1 || selected == 3) { + if (_gameState->_firstConverstationLine) + processConversationClick(conv, 3); + else + processConversationClick(conv, 1); + break; + } else { + processConversationClick(conv, selected); + } + } + +// Strangerke - Commented (not used) +// int cur = 0; + + for (int i = 0; i < 10; i++) { + if (conv->state[i]._data2 == 2) { + if (i != 3) + conv->state[i]._data2 = 1; + } + } + + _gameState->_exitConversation = false; + _gameState->_inConversation = false; + _gameState->_currentConversationId = -1; + _gameState->_mouseHidden = false; + _gameState->_sackVisible = true; + + // switch back to original music + playRoomMusic(); + +} + +void ToonEngine::drawConversationIcons() { + if (!_gameState->_inConversation || !_gameState->_showConversationIcons) + return; + int32 aa = 50 + _gameState->_currentScrollValue; + for (int32 i = 0; i < 10; i++) { + if (_gameState->_conversationState[_gameState->_currentConversationId].state[i]._data2 == 1) { + _dialogIcons->drawFrame(*_mainSurface, (i + _gameState->_currentScene) & 7, aa, 336); + _dialogIcons->drawFrame(*_mainSurface, 7 + _gameState->_conversationState[_gameState->_currentConversationId].state[i]._data3, aa, 339); + aa += 60; + } + } +} + +void ToonEngine::prepareConversations() { + Conversation *allConvs = _gameState->_conversationState; + for (int32 i = 0; i < 60; i++) { + + allConvs[i].state[0]._data2 = 1; + if (!allConvs[i].state[0]._data3) { + allConvs[i].state[0]._data3 = 1; + } + allConvs[i].state[1]._data2 = 1; + allConvs[i].state[1]._data3 = 6; + allConvs[i].state[3]._data2 = 2; + + } + int numConversations = READ_LE_UINT16(_conversationData + 1); + int16 *curConversation = _conversationData + 3; + for (int i = 0; i < numConversations; i++) { + Conversation *conv = &allConvs[ READ_LE_UINT16(curConversation)]; + if (!conv->_enable) { + + conv->_enable = 1; + + int16 offset1 = READ_LE_UINT16(curConversation + 1); + void *convData1 = (char *)_conversationData + offset1; + conv->state[0]._data4 = convData1; + + int16 offset2 = READ_LE_UINT16(curConversation + 2); + void *convData2 = (char *)_conversationData + offset2; + conv->state[1]._data4 = convData2; + + int16 offset3 = READ_LE_UINT16(curConversation + 3); + void *convData3 = (char *)_conversationData + offset3; + conv->state[2]._data4 = convData3; + + int16 offset4 = READ_LE_UINT16(curConversation + 4); + void *convData4 = (char *)_conversationData + offset4; + conv->state[3]._data4 = convData4; + } + curConversation += 5; + } +} + +void ToonEngine::processConversationClick(Conversation *conv, int32 status) { + Conversation::ConvState *v2 = (Conversation::ConvState *)&conv->state[status]; + + int16 *i = (int16 *)((char *)v2->_data4 + 2); + + _gameState->_firstConverstationLine = false; + while (*i >= 0) { + if (*i < 100) { + if (_gameState->_exitConversation == false) { + characterTalk(i[1]); + } + } else { + runConversationCommand(&i); + } + i += 2; + } + + int16 command = i[0]; + int16 value = i[1]; + + if (command == -1) { + v2->_data2 = 0; + } else if (command == -2) { + v2->_data4 = (char *)_conversationData + value; + v2->_data3 = *(int16 *)v2->_data4; + } else if (command == -3) { + v2->_data2 = 2; + v2->_data4 = (char *)_conversationData + value; + v2->_data3 = *(int16 *)v2->_data4; + } + + int16 *v7 = i + 2; +// Strangerke - Commented (not used) +// int16 v6 = conv->state[0].data2; + int16 v8 = *v7; + if (v8 == -1) { + _gameState->_mouseHidden = false; + } else { +retry: + while (1) { + v7 += 1; + int16 *v14 = (int16 *)((char *)_conversationData + v8); + + // find free dialogue slot + for (int j = 0; j < 10; j++) { + if (!conv->state[j]._data2) { + conv->state[j]._data3 = *v14; + conv->state[j]._data4 = v14; + if (getConversationFlag(_gameState->_currentScene, conv->state[j]._data3)) + conv->state[j]._data2 = 1; + else + conv->state[j]._data2 = 3; + + v8 = *v7; + if (v8 == -1) + return; + + goto retry; + } + } + + if (v8 != -1) + continue; + + break; + } + } + +} + +// hardcoded conversation flag to know if one dialogue icon must be displayed or not +// based on game events... +int32 ToonEngine::getConversationFlag(int32 locationId, int32 param) { + if (locationId == 1) { + if (param == 0x34) + return _gameState->getGameFlag(93); + + if (param != 55) + return 1; + + if (!_gameState->getGameFlag(262)) + return 1; + + return 0; + } else if (locationId == 2) { + if (param == 36 && _gameState->getGameFlag(149)) + return 0; + return 1; + } else if (locationId == 7) { + if (param == 30) + return _gameState->getGameFlag(132); + else + return 1; + } else if (locationId == 8) { + if (param == 0x20) { + if (!_gameState->getGameFlag(73) && !_gameState->getGameFlag(151) && !_gameState->getGameFlag(152) && !_gameState->getGameFlag(153)) + return 1; + return 0; + } + if (param == 33) { + if (!_gameState->getGameFlag(73) && !_gameState->getGameFlag(151) && !_gameState->getGameFlag(152) && !_gameState->getGameFlag(153)) + return 0; + return 1; + } + } else if (locationId == 0xb) { + if (param == 0x12) { + if (!_gameState->hasItemInInventory(71)) + return 1; + else + return 0; + } + if (param == 74) { + if (_gameState->hasItemInInventory(71)) + return 1; + else + return 0; + } + return 1; + } else if (locationId == 0xc) { + if (param == 0x3d && _gameState->getGameFlag(154)) { + return 0; + } + if (param == 76 && !_gameState->getGameFlag(79)) { + return 0; + } + if (param == 0x4e && !_gameState->hasItemInInventory(32)) { + return 0; + } + if (param == 0x4f && !_gameState->hasItemInInventory(92)) { + return 0; + } + if (param == 80 && !_gameState->hasItemInInventory(91)) { + return 0; + } + if (param == 0x4d && _gameState->getGameFlag(79)) { + return 0; + } + } else if (locationId == 0xd) { + if (param == 0x2f && _gameState->getGameFlag(81)) { + return 0; + } + if (param == 48 && _gameState->getGameFlag(81)) { + return 0; + } + } else if (locationId == 0x10) { + switch (param) { + case 0x3e8: + if (!(_gameState->_gameGlobalData[83] & 1)) + return 0; + break; + case 0x3e9: + if (!(_gameState->_gameGlobalData[83] & 2)) + return 0; + break; + case 0x3ea: + if (!(_gameState->_gameGlobalData[83] & 4)) + return 0; + break; + case 0x3eb: + if (!(_gameState->_gameGlobalData[83] & 8)) + return 0; + break; + case 0x3ec: + if (!(_gameState->_gameGlobalData[83] & 16)) + return 0; + break; + case 0x3ed: + if (!(_gameState->_gameGlobalData[83] & 32)) + return 0; + break; + case 0x3ee: + if (!(_gameState->_gameGlobalData[83] & 64)) + return 0; + break; + default: + break; + }; + return 1; + } else if (locationId == 0x12) { + if (param == 0x28 && _gameState->getGameFlag(91)) { + return 0; + } + if (param == 41 && (!_gameState->getGameFlag(96) || _gameState->getGameFlag(91))) { + return 0; + } + } else if (locationId == 0x13) { + if (param == 0x32 && _gameState->getGameFlag(107)) { + return 0; + } + if (param == 68 && !_gameState->getGameFlag(107)) { + return 0; + } + } else if (locationId == 0x14) { + if (param == 1000 && !_gameState->getGameFlag(82)) { + return 0; + } + } else if (locationId == 0x25) { + if (param == 7 && _gameState->_gameGlobalData[28] != 1) { + return 0; + } + if (param == 8 && _gameState->_gameGlobalData[28] != 1) { + return 0; + } + if (param == 9 && _gameState->_gameGlobalData[28] != 1) { + return 0; + } + if (param == 75 && _gameState->_gameGlobalData[28] != 2) { + return 0; + } + } else if (locationId == 72) { + if (param == 63 && _gameState->getGameFlag(105)) { + return 0; + } + if (param == 67 && !_gameState->getGameFlag(105)) { + return 0; + } + if (param == 0x40 && !_gameState->getGameFlag(105)) { + return 0; + } + } + return 1; +} + +int ToonEngine::runConversationCommand(int16 **command) { + +// Strangerke - Commented (not used) +// int16 com = **command; + int16 *v5 = *command; + + int v2 = v5[0]; + int v4 = v5[1]; + int result = v2 - 100; + switch (v2) { + case 100: + result = runEventScript(_mouseX, _mouseY, 2, v4, 0); + break; + case 101: + _gameState->_exitConversation = true; + break; + case 102: + playSoundWrong(); + break; + case 104: + *command = (int16 *)((char *)_conversationData + v4); + *command = (int16 *)((char *)_conversationData + v4 - 4); + break; + // + case 105: + if (getConversationFlag(_gameState->_currentScene, v4)) { + result = *(int16 *)(*command + 4); + *command = (int16 *)((char *)_conversationData + result); + *command = (int16 *)((char *)_conversationData + result - 4); + } else { + int16 *newPtr = *command + 1; + *command = newPtr; + } + break; + case 103: + return result; + break; + } + return result; +} + +int32 ToonEngine::waitTicks(int32 numTicks, bool breakOnMouseClick) { +// Strangerke - Commented (not used) +// Common::EventManager *_event = _system->getEventManager(); + + uint32 nextTime = _system->getMillis() + numTicks * _tickLength; + while (_system->getMillis() < nextTime || numTicks == -1) { + //if (!_animationSceneScriptRunFlag) + // break; + updateAnimationSceneScripts(0); + getMouseEvent(); + simpleUpdate(); + + if (breakOnMouseClick && (_mouseButton & 0x2)) + break; + } + return 0; +} + +void ToonEngine::renderInventory() { + if (!_gameState->_inInventory) + return; + + _inventoryPicture->draw(*_mainSurface, 0, 0, 0, 0); + + // draw items on screen + for (int32 i = 0; i < _gameState->_numInventoryItems; i++) { + int32 x = 57 * (i % 7) + 114; + int32 y = ((9 * (i % 7)) & 0xf) + 56 * (i / 7) + 80; + _inventoryIconSlots->drawFrame(*_mainSurface, i % 12, x + _gameState->_currentScrollValue, y); + if (_gameState->_inventory[i]) + _inventoryIcons->drawFrame(*_mainSurface, _gameState->_inventory[i], x + _gameState->_currentScrollValue + 2, y + 2); + } + + drawConversationLine(); + if (!_audioManager->voiceStillPlaying()) { + _currentTextLineCharacterId = -1; + _currentTextLine = 0; + _currentTextLineId = -1; + } + + if (_firstFrame) { + copyToVirtualScreen(false); + _firstFrame = false; + fadeIn(5); + } + copyToVirtualScreen(); +} + +int32 ToonEngine::showInventory() { + int32 oldScrollValue = _gameState->_currentScrollValue; +// Strangerke - Commented (not used) +// Common::EventManager *_event = _system->getEventManager(); + _inventoryPicture = new Picture(this); + fadeOut(5); + _inventoryPicture->loadPicture("SACK128.CPS", true); + _inventoryPicture->setupPalette(); + + if (_gameState->_mouseState >= 0) { + setCursor(_gameState->_mouseState, true, -18, -14); + + // make sure we have a free spot + if (!_gameState->hasItemInInventory(0)) { + _gameState->_inventory[_gameState->_numInventoryItems] = 0; + _gameState->_numInventoryItems++; + } + } else { + setCursor(0); + } + + _gameState->_inInventory = true; + _gameState->_currentScrollValue = 0; + + int32 oldMouseButton = 0; + int32 justPressedButton = 0; + _firstFrame = true; + + while (!_shouldQuit) { + getMouseEvent(); + + justPressedButton = _mouseButton & ~oldMouseButton; + oldMouseButton = _mouseButton; + + if (justPressedButton & 0x3) { + // find out what object we're on + int32 foundObj = -1; + for (int32 i = 0; i < _gameState->_numInventoryItems; i++) { + int32 x = 57 * (i % 7) + 114; + int32 y = ((9 * (i % 7)) & 0xf) + 56 * (i / 7) + 80; + if (_mouseX >= (_gameState->_currentScrollValue + x - 6) && + _mouseX <= (_gameState->_currentScrollValue + x + 44 + 7) && + _mouseY >= y - 6 && _mouseY <= y + 50) { + foundObj = i; + break; + } + } + + if (justPressedButton & 0x1) { + if (_gameState->_mouseState < 0) { + if (foundObj >= 0) { + // take an object + int32 item = _gameState->_inventory[foundObj]; + + int32 modItem = getSpecialInventoryItem(item); + if (modItem) { + + if (modItem == -1) { + _gameState->_mouseState = item; + _gameState->_inventory[foundObj] = 0; + } else { + _gameState->_mouseState = modItem; + if (!_gameState->hasItemInInventory(0)) { + _gameState->_inventory[_gameState->_numInventoryItems] = 0; + _gameState->_numInventoryItems++; + } + } + + setCursor(_gameState->_mouseState, true, -18, -14); + } + + } else { + break; + } + } else { + if (foundObj >= 0 && _gameState->_inventory[foundObj] == 0) { // empty place + _gameState->_inventory[foundObj] = _gameState->_mouseState; + setCursor(0, false); + _gameState->_mouseState = -1; + } else if (foundObj >= 0 && _gameState->_inventory[foundObj] > 0) { + if (!handleInventoryOnInventory(_gameState->_mouseState, _gameState->_inventory[foundObj])) + playSoundWrong(); + } else { + // quit the inventory mode with the icon + break; + } + } + + } else if (justPressedButton & 0x2) { // right button + if (foundObj >= 0) { + // talk about the object + if (!handleInventoryOnInventory(_gameState->_inventory[foundObj], -1)) + characterTalk(1000 + _gameState->_inventory[foundObj]); + } else { + // go out + break; + } + } + } + + renderInventory(); + + } + + _gameState->_currentScrollValue = oldScrollValue; + _gameState->_inInventory = false; + + fadeOut(5); + if (_gameState->_inCloseUp) { + _gameState->_inCloseUp = false; + flipScreens(); + } else if (_gameState->_inCutaway) { + _currentCutaway->setupPalette(); + setupGeneralPalette(); + } else { + _currentPicture->setupPalette(); + setupGeneralPalette(); + } + flushPalette(); + _firstFrame = true; + + return 0; +} + +void ToonEngine::getMouseEvent() { + Common::EventManager *_event = _system->getEventManager(); + + Common::Event event; + while (_event->pollEvent(event) && !_shouldQuit) + ; + + _mouseX = _event->getMousePos().x; + _mouseY = _event->getMousePos().y; + _mouseButton = _event->getButtonState(); +} + +void ToonEngine::drawSack() { + if (_gameState->_sackVisible) { + _inventoryIcons->drawFrame(*_mainSurface, 0, _gameState->_currentScrollValue, 356); + } +} + +void ToonEngine::addItemToInventory(int32 item) { + + if (item == 103 || item == 104 || item == 89 || item == 82) { + // can't add that to inventory + _gameState->_mouseState = -1; + return; + } + + if (item == 41) { + // confiscated inventory + for (int32 i = 0; i < _gameState->_numConfiscatedInventoryItems; i++) + addItemToInventory(_gameState->_confiscatedInventory[i]); + + _gameState->_numConfiscatedInventoryItems = 0; + _gameState->_mouseState = -1; + return; + } + + for (int32 i = 0; i < _gameState->_numInventoryItems; i++) { + if (_gameState->_inventory[i] == 0) { + _gameState->_inventory[i] = item; + _gameState->_mouseState = -1; + return; + } + } + _gameState->_inventory[_gameState->_numInventoryItems] = item; + _gameState->_numInventoryItems++; + _gameState->_mouseState = -1; +} + +void ToonEngine::createMouseItem(int32 item) { + _gameState->_mouseState = item; + setCursor(_gameState->_mouseState, true, -18, -14); +} + +void ToonEngine::deleteMouseItem() { + _gameState->_mouseState = -1; + rearrangeInventory(); + setCursor(0); +} + +void ToonEngine::showCutaway(Common::String cutawayPicture) { + _gameState->_inCutaway = true; + _currentCutaway = new Picture(this); + if (cutawayPicture == "") { + cutawayPicture = Common::String(_gameState->_locations[_gameState->_currentScene]._cutaway) + ".CPS"; + } + _currentCutaway->loadPicture(cutawayPicture, false); + _currentCutaway->setupPalette(); + _oldScrollValue = _gameState->_currentScrollValue; + _gameState->_currentScrollValue = 0; + flushPalette(); +} + +void ToonEngine::hideCutaway() { + _gameState->_inCutaway = false; + _gameState->_sackVisible = true; + delete _currentCutaway; + _gameState->_currentScrollValue = _oldScrollValue; + _currentCutaway = 0; + _currentPicture->setupPalette(); + flushPalette(); +} + +void ToonEngine::updateCharacters(int32 timeElapsed) { + for (int32 i = 0; i < 8; i++) { + if (_characters[i]) { + _characters[i]->update(timeElapsed); + } + } +} + +void ToonEngine::drawPalette() { + for (int32 i = 0; i < 256; i++) { + int32 x = i % 32; + int32 y = i / 32; + _mainSurface->fillRect(Common::Rect(x * 16, y * 16, x * 16 + 16, y * 16 + 16), i); + } +} + +void ToonEngine::rearrangeInventory() { + for (int32 i = 0; i < _gameState->_numInventoryItems; i++) { + if (_gameState->_inventory[i] == 0) { + // move all the following items from one + for (int32 j = i + 1; j < _gameState->_numInventoryItems; j++) { + _gameState->_inventory[j-1] = _gameState->_inventory[j]; + } + _gameState->_numInventoryItems--; + } + } +} + +void ToonEngine::newGame() { + + if (_isDemo) { + addItemToInventory(59); + addItemToInventory(67); + addItemToInventory(11); + addItemToInventory(19); + loadScene(_gameState->_currentScene); + } else { + //loadScene(4); + loadScene(_gameState->_currentScene); + } +} + +void ToonEngine::playSFX(int32 id, int32 volume) { + if (id < 0) + _audioManager->playSFX(-id + 1, volume, true); + else + _audioManager->playSFX(id , volume, false); +} + +void ToonEngine::playSoundWrong() { + _audioManager->playSFX(rand() & 7, 128, true); +} + +void ToonEngine::getTextPosition(int32 characterId, int32 *retX, int32 *retY) { + + if (characterId < 0) + characterId = 0; + + // default position is the center of current screen + *retX = _gameState->_currentScrollValue + 320; + *retY = 70; + + // hardcoded special cases... + if (characterId == 0) { + // drew + int32 x = _drew->getX(); + int32 y = _drew->getY(); + if (x >= _gameState->_currentScrollValue && x <= _gameState->_currentScrollValue + 640) { + if (!_gameState->_inCutaway && !_gameState->_inInventory) { + *retX = x; + *retY = y - ((_drew->getScale() * 256 / 1024) >> 1) - 45; + } + } + } else if (characterId == 1) { + // flux + int32 x = _flux->getX(); + int32 y = _flux->getY(); + if (x >= _gameState->_currentScrollValue && x <= _gameState->_currentScrollValue + 640) { + if (!_gameState->_inCutaway) { + *retX = x; + *retY = y - ((_drew->getScale() * 100 / 1024) >> 1) - 30; + } + } + } else if (characterId == 5 || characterId == 39) { + *retX = 80; + *retY = 120; + } else if (characterId == 14) { + *retX = 257; + *retY = 132; + } else if (characterId == 18) { + *retX = 80; + *retY = 180; + } else if (characterId == 21) { + *retX = 363; + *retY = 193; + } else if (characterId == 23) { + *retX = 532; + *retY = 178; + } else if (characterId == 33) { + *retX = 167; + *retY = 172; + } else { + + // more "standard" code by character + Character *character = getCharacterById(characterId); + if (character && !_gameState->_inCutaway) { + if (character->getAnimationInstance()) { + if (character->getX() >= _gameState->_currentScrollValue && character->getX() <= _gameState->_currentScrollValue + 640) { + int32 x1, y1, x2, y2; + character->getAnimationInstance()->getRect(&x1, &y1, &x2, &y2); + *retX = (x1 + x2) / 2; + *retY = y1; + } + } + } + } +} + +Character *ToonEngine::getCharacterById(int32 charId) { + + for (int32 i = 0; i < 8; i++) { + if (_characters[i] && _characters[i]->getId() == charId) + return _characters[i]; + } + return 0; +} + +void ToonEngine::drawConversationLine() { + if (_currentTextLine) { + _fontRenderer->setFontColorByCharacter(_currentTextLineCharacterId); + _fontRenderer->setFont(_fontToon); + _fontRenderer->renderMultiLineText(_currentTextLineX, _currentTextLineY, Common::String(_currentTextLine), 0); + } +} + +Common::String ToonEngine::getSavegameName(int nr) { + return _targetName + Common::String::printf(".%03d", nr); +} + +bool ToonEngine::saveGame(int32 slot) { + const EnginePlugin *plugin = NULL; + int16 savegameId; + Common::String savegameDescription; + EngineMan.findGame(_gameDescription->gameid, &plugin); + + if (slot == -1) { + GUI::SaveLoadChooser *dialog = new GUI::SaveLoadChooser("Save game:", "Save"); + dialog->setSaveMode(true); + savegameId = dialog->runModal(plugin, ConfMan.getActiveDomainName()); + savegameDescription = dialog->getResultString(); + delete dialog; + } else { + savegameId = slot; + savegameDescription = Common::String::printf("Quick save #%d", slot); + } + + if (savegameId < 0) + return false; // dialog aborted + + Common::String savegameFile = getSavegameName(savegameId); + Common::SaveFileManager *saveMan = g_system->getSavefileManager(); + Common::OutSaveFile *saveFile = saveMan->openForSaving(savegameFile); + if (!saveFile) + return false; + + // save savegame header + saveFile->writeSint32BE(TOON_SAVEGAME_VERSION); + + if (savegameDescription == "") { + savegameDescription = "Untitled savegame"; + } + + saveFile->writeSint16BE(savegameDescription.size() + 1); + saveFile->write(savegameDescription.c_str(), savegameDescription.size() + 1); + + Graphics::saveThumbnail(*saveFile); + + TimeDate curTime; + _system->getTimeAndDate(curTime); + + uint32 saveDate = (curTime.tm_mday & 0xFF) << 24 | ((curTime.tm_mon + 1) & 0xFF) << 16 | ((curTime.tm_year + 1900) & 0xFFFF); + uint16 saveTime = (curTime.tm_hour & 0xFF) << 8 | ((curTime.tm_min) & 0xFF); + + saveFile->writeUint32BE(saveDate); + saveFile->writeUint16BE(saveTime); + + + // save global state + _gameState->save(saveFile); + _gameState->saveConversations(saveFile); + _hotspots->save(saveFile); + + // save current time to be able to patch the time when loading + saveFile->writeSint32BE(getOldMilli()); + + // save script states + for (int32 i = 0; i < 4; i++) { + _script->saveState(&_scriptState[i], saveFile); + } + + // save animation script states + for (int32 i = 0; i < state()->_locations[_gameState->_currentScene]._numSceneAnimations; i++) { + saveFile->writeByte(_sceneAnimationScripts[i]._active); + saveFile->writeByte(_sceneAnimationScripts[i]._frozen); + saveFile->writeSint32BE(_sceneAnimationScripts[i]._lastTimer); + _script->saveState(&_sceneAnimationScripts[i]._state, saveFile); + } + + // save scene animations + for (int32 i = 0; i < 64; i++) { + _sceneAnimations[i].save(this, saveFile); + } + + + for (int32 i = 0; i < 8; i++) { + if (_characters[i]) { + saveFile->writeSByte(i); + _characters[i]->save(saveFile); + } + } + saveFile->writeSByte(-1); + + // save "command buffer" + saveFile->writeSint16BE(_saveBufferStream->pos()); + if (_saveBufferStream->pos() > 0) { + saveFile->write(_saveBufferStream->getData(), _saveBufferStream->pos()); + saveFile->writeSint16BE(0); + } + + delete saveFile; + + return true; +} + +bool ToonEngine::loadGame(int32 slot) { + const EnginePlugin *plugin = NULL; + int16 savegameId; + EngineMan.findGame(_gameDescription->gameid, &plugin); + + if (slot == -1) { + GUI::SaveLoadChooser *dialog = new GUI::SaveLoadChooser("Restore game:", "Restore"); + dialog->setSaveMode(false); + savegameId = dialog->runModal(plugin, ConfMan.getActiveDomainName()); + delete dialog; + } else { + savegameId = slot; + } + if (savegameId < 0) + return false; // dialog aborted + + Common::String savegameFile = getSavegameName(savegameId); + Common::SaveFileManager *saveMan = g_system->getSavefileManager(); + Common::InSaveFile *loadFile = saveMan->openForLoading(savegameFile); + if (!loadFile) + return false; + + int32 saveGameVersion = loadFile->readSint32BE(); + if (saveGameVersion != TOON_SAVEGAME_VERSION) { + delete loadFile; + return false; + } + int32 saveGameNameSize = loadFile->readSint16BE(); + loadFile->skip(saveGameNameSize); + + // We don't need the thumbnail here, so just read it and discard it + Graphics::skipThumbnail(*loadFile); + + loadFile->skip(6); // date & time skip + + if (_gameState->_currentScene != -1) { + exitScene(); + } + + + _gameState->load(loadFile); + loadScene(_gameState->_currentScene, true); + _gameState->loadConversations(loadFile); + _hotspots->load(loadFile); + + // read the old time + int32 savedTime = loadFile->readSint32BE(); + int32 timerDiff = _system->getMillis() - savedTime; + + // load script states + for (int32 i = 0; i < 4; i++) { + _script->loadState(&_scriptState[i], loadFile); + } + + // load animation script states + for (int32 i = 0; i < state()->_locations[_gameState->_currentScene]._numSceneAnimations; i++) { + _sceneAnimationScripts[i]._active = loadFile->readByte(); + _sceneAnimationScripts[i]._frozen = loadFile->readByte(); + int32 oldTimer = loadFile->readSint32BE(); + _sceneAnimationScripts[i]._lastTimer = MAX(0,oldTimer + timerDiff); + _script->loadState(&_sceneAnimationScripts[i]._state, loadFile); + } + + // load scene animations + for (int32 i = 0; i < 64; i++) { + _sceneAnimations[i].load(this, loadFile); + } + + _gameState->_timerTimeout[0] += timerDiff; + _gameState->_timerTimeout[1] += timerDiff; + + /* + int32 diff = _conversationData - _gameState->_conversationData; + + for (int32 i = 0; i < 60; i++) { + if (_gameState->_conversationState[i]._enable) { + // we have to fix up our pointers... + for (int32 a = 0; a < 10; a++) { + if (_gameState->_conversationState[i].state[a]._data4) + _gameState->_conversationState[i].state[a]._data4 = (int16 *)_gameState->_conversationState[i].state[a]._data4 + diff; + } + } + } + */ + + _gameState->_conversationData = _conversationData; + _firstFrame = true; + + // read characters info + while (1) { + int8 c = loadFile->readSByte(); + if (c < 0) + break; + + if (!_characters[c]) { + _characters[c] = new Character(this); + } + _characters[c]->load(loadFile); + //_characters[c]->setVisible(true); + _characters[c]->update(0); + } + + // load "command buffer" + int32 size = loadFile->readSint16BE(); + if (size) { + uint8 *buf = new uint8[size+2]; + loadFile->read(buf, size + 2); + + Common::MemoryReadStream rStr(buf, size + 2); + while (1) { + int16 command = rStr.readSint16BE(); + if (!command) break; + switch (command) { + case 1: { + int16 frame = rStr.readSint16BE(); + int16 animLen = rStr.readSint16BE(); + char animName[32]; + rStr.read(animName, animLen); + int16 x = rStr.readSint16BE(); + int16 y = rStr.readSint16BE(); +// int16 z = rStr.readSint16BE(); +// int16 layerZ = rStr.readSint16BE(); + rStr.readSint16BE(); + rStr.readSint16BE(); + + Animation *anim = new Animation(this); + anim->loadAnimation(animName); + anim->drawFrameOnPicture(frame, x, y); + delete anim; + break; + } + case 2: { + int16 x = rStr.readSint16BE(); + int16 y = rStr.readSint16BE(); + int16 x1 = rStr.readSint16BE(); + int16 y1 = rStr.readSint16BE(); + makeLineNonWalkable(x, y, x1, y1); + break; + } + case 3: { + int16 x = rStr.readSint16BE(); + int16 y = rStr.readSint16BE(); + int16 x1 = rStr.readSint16BE(); + int16 y1 = rStr.readSint16BE(); + makeLineWalkable(x, y, x1, y1); + break; + } + case 4: { + int16 x = rStr.readSint16BE(); + int16 y = rStr.readSint16BE(); + getMask()->floodFillNotWalkableOnMask(x, y); + break; + } + default: + break; + } + } + + _saveBufferStream->write(buf, size); + delete loadFile; + } + return true; +} + +// another special case for inventory +int32 ToonEngine::getSpecialInventoryItem(int32 item) { + + // butter + if (item == 12) { + for (int32 i = 0; i < _gameState->_numInventoryItems; i++) { + if (_gameState->_inventory[i] == 12) + _gameState->_inventory[i] = 11; + } + return 11; + + } else if (item == 84) { + if (_gameState->getGameFlag(26)) { + characterTalk(1726); + return 0; + } else { + if (!_gameState->hasItemInInventory(102) && !_gameState->hasItemInInventory(90) && !_gameState->hasItemInInventory(89)) { + characterTalk(1416); + return 102; + } else { + return 0; + } + } + } + + return -1; +} + +void ToonEngine::initCharacter(int32 characterId, int32 animScriptId, int32 sceneAnimationId, int32 animToPlayId) { + // find a new index + int32 characterIndex = -1; + for (int32 i = 0; i < 8; i++) { + if (_characters[i] && _characters[i]->getId() == characterId) { + characterIndex = i; + break; + } + + if (!_characters[i]) { + characterIndex = i; + break; + } + } + + if (characterIndex == -1) { + return; + } + +// Strangerke - Commented (not used) +// if (_characters[characterIndex]) +// delete current char + + _characters[characterIndex] = new Character(this); + _characters[characterIndex]->setId(characterId); + _characters[characterIndex]->setAnimScript(animScriptId); + _characters[characterIndex]->setDefaultSpecialAnimationId(animToPlayId); + _characters[characterIndex]->setSceneAnimationId(sceneAnimationId); + _characters[characterIndex]->setFlag(0); + _characters[characterIndex]->setVisible(true); + if (sceneAnimationId != -1) + _characters[characterIndex]->setAnimationInstance(_sceneAnimations[sceneAnimationId]._animInstance); +} + +int32 ToonEngine::handleInventoryOnFlux(int32 itemId) { + + switch (itemId) { + case 8: + sayLines(1, 1332); + break; + case 0x14: + case 0x15: + case 0x45: + sayLines(1, 1304); + break; + case 0x68: + _gameState->_mouseState = 0; + setCursor(0, false, 0, 0); + break; + case 116: + sayLines(1, 1306); + break; + default: + return false; + } + return true; +} + +void ToonEngine::storePalette() { + memcpy(_backupPalette, _finalPalette, 768); +} + +void ToonEngine::restorePalette() { + memcpy(_finalPalette, _backupPalette, 768); + flushPalette(); +} + +const char *ToonEngine::getSpecialConversationMusic(int32 conversationId) { + static const char * const specialMusic[] = { + 0, 0, + "BR091013", "BR091013", + "NET1214", "NET1214", + 0, 0, + "CAR1365B", "CAR1365B", + 0, 0, + 0, 0, + "CAR14431", "CAR14431", + 0, 0, + 0, 0, + "SCD16520", "SCD16520", + "SCD16520", "SCD16520", + "SCD16522", "SCD16522", + 0, 0, + "KPM8719", "KPM8719", + 0, 0, + "CAR1368B", "CAR1368B", + 0, 0, + 0, 0, + "KPM6337", "KPM6337", + "CAR20471", "CAR20471", + "CAR136_1", "KPM87_57", + 0, 0, + "CAR13648", "CAR13648", + 0, 0, + 0, 0, + 0, 0, + 0, 0, + "SCD16526", "SCD16526", + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0 + }; + + return specialMusic[randRange(0, 1) + conversationId * 2]; +} + +void ToonEngine::viewInventoryItem(Common::String str, int32 lineId, int32 itemDest) { + storePalette(); + fadeOut(5); + + Picture *pic = new Picture(this); + pic->loadPicture(str, false); + pic->setupPalette(); + flushPalette(); + + if (lineId) { + characterTalk(lineId, false); + } + + uint32 oldMouseButton = _mouseButton; + uint32 justPressedButton = 0; + _firstFrame = true; + + int32 oldScrollValue = _gameState->_currentScrollValue; + _gameState->_currentScrollValue = 0; + + while (!_shouldQuit) { + getMouseEvent(); + + justPressedButton = _mouseButton & ~oldMouseButton; + oldMouseButton = _mouseButton; + + if (justPressedButton) { + break; + } + + pic->draw(*_mainSurface, 0, 0, 0, 0); + + drawConversationLine(); + if (!_audioManager->voiceStillPlaying()) { + _currentTextLineCharacterId = -1; + _currentTextLine = 0; + _currentTextLineId = -1; + } + + if (_firstFrame) { + copyToVirtualScreen(false); + _firstFrame = false; + fadeIn(5); + } + + copyToVirtualScreen(); + } + + fadeOut(5); + restorePalette(); + _firstFrame = true; + _gameState->_currentScrollValue = oldScrollValue; + delete pic; + +} + +int32 ToonEngine::handleInventoryOnInventory(int32 itemDest, int32 itemSrc) { + switch (itemDest) { + case 0: + return handleInventoryOnDrew(itemSrc); + case 1: + if (itemSrc == 71) { + sayLines(2, 1212); + return 1; + } + break; + case 5: + if (itemSrc == 15) { + characterTalk(1492); + } else if (itemSrc == 0x2f) { + characterTalk(1488); + } else if (itemSrc == 88) { + sayLines(2, 1478); + } else { + return 0; + } + break; + case 6: + if (itemSrc == -1) { + viewInventoryItem("BLUEPRNT.CPS", 1006, itemDest); + return 1; + } else + return 0; + break; + case 8: + if (itemSrc == -1) { + viewInventoryItem("BOOK.CPS", 0, itemDest); + return 1; + } else { + return 0; + } + break; + case 11: + if (itemSrc == 0xb) { + _gameState->_mouseState = -1; + replaceItemFromInventory(11,12); + setCursor(0, false, 0, 0); + rearrangeInventory(); + return 1; + // + } else if (itemSrc == 24) { + characterTalk(1244); + return 1; + } else if (itemSrc == 0x1a || itemSrc == 0x40 || itemSrc == 71) { + sayLines(2, 1212); + return 1; + } + break; + case 12: + if (itemSrc == 24) { + characterTalk(1244); + return 1; + } else if (itemSrc == 0x1a || itemSrc == 0x40 || itemSrc == 71) { + sayLines(2, 1212); + return 1; + } + break; + case 13: + if (itemSrc == 0x35 || itemSrc == 0x36) { + characterTalk(1204); + return 1; + } else if (itemSrc >= 0x6b && itemSrc <= 0x72) { + characterTalk(1312); + return 1; + } + break; + case 14: + if (itemSrc == -1) { + deleteItemFromInventory(14); + addItemToInventory(15); + addItemToInventory(42); + rearrangeInventory(); + return 1; + } else if (itemSrc == 43) { + characterTalk(1410); + return 1; + } else if (itemSrc == 49) { + characterTalk(1409); + return 1; + } + break; + case 16: + if (itemSrc == 55) { + characterTalk(1400); + replaceItemFromInventory(55, 98); + return 1; + } + break; + case 19: + if (itemSrc == 0x34) { + characterTalk(1322); + return 1; + } else if (itemSrc == 107) { + sayLines(2 , 1300); + replaceItemFromInventory(107, 111); + _gameState->_mouseState = -1; + setCursor(0, false, 0, 0); + rearrangeInventory(); + return 1; + } else if (itemSrc == 0x6c) { + sayLines(2, 1300); + replaceItemFromInventory(108, 112); + _gameState->_mouseState = -1; + setCursor(0, false, 0, 0); + rearrangeInventory(); + return 1; + } else if (itemSrc == 0x6d) { + sayLines(2, 1300); + replaceItemFromInventory(109, 113); + _gameState->_mouseState = -1; + setCursor(0, false, 0, 0); + rearrangeInventory(); + return 1; + } else if (itemSrc == 110) { + sayLines(2, 1300); + replaceItemFromInventory(110, 114); + _gameState->_mouseState = -1; + setCursor(0, false, 0, 0); + rearrangeInventory(); + return 1; + } + break; + case 20: + if (itemSrc == 35) { + createMouseItem(21); + replaceItemFromInventory(35, 36); + return 1; + } else if (itemSrc == 0x24) { + createMouseItem(21); + replaceItemFromInventory(36, 37); + return 1; + } else if (itemSrc == 37) { + deleteItemFromInventory(37); + createMouseItem(21); + rearrangeInventory(); + return 1; + } else if (itemSrc == 0x6b || itemSrc == 0x6c || itemSrc == 0x6f || itemSrc == 108 || itemSrc == 112) { + sayLines(2, 1292); + return 1; + } + break; + case 21: + switch (itemSrc) { + + case 107: + characterTalk(1296); + replaceItemFromInventory(107, 109); + _gameState->_mouseState = -1; + setCursor(0, false, 0, 0); + rearrangeInventory(); + return 1; + case 108: + characterTalk(1298); + replaceItemFromInventory(108, 110); + _gameState->_mouseState = -1; + setCursor(0, false, 0, 0); + rearrangeInventory(); + return 1; + case 111: + characterTalk(1296); + replaceItemFromInventory(111, 113); + _gameState->_mouseState = -1; + setCursor(0, false, 0, 0); + rearrangeInventory(); + return 1; + case 112: + characterTalk(1298); + replaceItemFromInventory(112, 114); + _gameState->_mouseState = -1; + setCursor(0, false, 0, 0); + rearrangeInventory(); + return 1; + } + break; + case 22: + if (itemSrc == 32) { + characterTalk(1252); + return 1; + } + break; + case 24: + if (itemSrc == 0xc) { + characterTalk(1244); + return 1; + } else if (itemSrc == 79) { + characterTalk(1280); + return 1; + } + break; + case 26: + if (itemSrc == 0x5e) { + characterTalk(1316); + return 1; + } else if (itemSrc == 95) { + characterTalk(1320); + return 1; + } + break; + case 31: + if (itemSrc == 61) { + characterTalk(1412); + deleteItemFromInventory(61); + createMouseItem(62); + rearrangeInventory(); + return 1; + } + break; + case 32: + if (itemSrc == 22) { + characterTalk(1252); + return 1; + } + break; + case 33: + if (itemSrc == 117) { + characterTalk(1490); + return 1; + } + break; + case 34: + if (itemSrc == 61) { + characterTalk(1414); + return 1; + } + break; + case 35: + if (itemSrc == -1) { + characterTalk(1035); + return 1; + } else if (itemSrc == 20) { + replaceItemFromInventory(20, 21); + createMouseItem(36); + return 1; + } else if (itemSrc == 68) { + replaceItemFromInventory(68, 69); + createMouseItem(36); + return 1; + } else if (itemSrc >= 107 && itemSrc <= 114) { + characterTalk(1314); + return 1; + } else { + characterTalk(1208); + return 1; + } + break; + case 36: + if (itemSrc == -1) { + characterTalk(1035); + return 1; + } else if (itemSrc == 20) { + replaceItemFromInventory(20, 21); + createMouseItem(37); + return 1; + } else if (itemSrc == 68) { + replaceItemFromInventory(68, 69); + createMouseItem(37); + return 1; + } else if (itemSrc >= 107 && itemSrc <= 114) { + characterTalk(1314); + return 1; + } else { + characterTalk(1208); + return 1; + } + break; + case 37: + if (itemSrc == -1) { + characterTalk(1035); + return 1; + } else if (itemSrc == 20) { + replaceItemFromInventory(20, 21); + _gameState->_mouseState = -1; + setCursor(0, false, 0, 0); + rearrangeInventory(); + return 1; + } else if (itemSrc == 68) { + replaceItemFromInventory(68, 69); + _gameState->_mouseState = -1; + setCursor(0, false, 0, 0); + rearrangeInventory(); + return 1; + } else if (itemSrc >= 107 && itemSrc <= 114) { + characterTalk(1314); + return 1; + } else { + characterTalk(1208); + return 1; + } + break; + case 38: + if (itemSrc == 15) { + characterTalk(1492); + return 1; + } else if (itemSrc == 0x2f) { + characterTalk(1488); + return 1; + } else if (itemSrc == 88) { + sayLines(2, 1478); + return 1; + } + break; + case 40: + if (itemSrc == 53) { + replaceItemFromInventory(53, 54); + characterTalk(1222); + return 1; + } else if (itemSrc == 0x36) { + characterTalk(1228); + return 1; + } else if (itemSrc == 0x5b) { + characterTalk(1230); + return 1; + } else if (itemSrc == 92) { + characterTalk(1220); + return 1; + } + break; + case 43: + if (itemSrc == 14) { + characterTalk(1410); + return 1; + } + break; + case 47: + if (itemSrc == -1) + characterTalk(1047); + else + characterTalk(1488); + + return 1; + case 49: + if (itemSrc == 0xe) { + characterTalk(1409); + return 1; + } else if (itemSrc == 38 || itemSrc == 5 || itemSrc == 0x42) { + characterTalk(1476); + return 1; + } else if (itemSrc == 0x34) { + characterTalk(1260); + return 1; + } else if (itemSrc == 0x47) { + characterTalk(1246); + return 1; + } else if (itemSrc == 0x36) { + sayLines(2, 1324); + return 1; + } + break; + case 52: + if (itemSrc == 0x13) { + characterTalk(1322); + return 1; + } else if (itemSrc == 94) { + characterTalk(1282); + return 1; + } + break; + case 53: + if (itemSrc == 40) { + createMouseItem(54); + characterTalk(1222); + return 1; + } else if (itemSrc == 0x31) { + sayLines(2, 1324); + return 1; + } else if (itemSrc == 0x34) { + characterTalk(1310); + return 1; + } else if (itemSrc == 91) { + characterTalk(1218); + return 1; + } + + break; + case 54: + if (itemSrc == 40) { + characterTalk(1228); + return 1; + } else if (itemSrc == 0x34) { + characterTalk(1310); + return 1; + } else if (itemSrc == 0x5b) { + characterTalk(1226); + replaceItemFromInventory(91, 92); + return 1; + } else if (itemSrc == 92) { + characterTalk(1220); + return 1; + } + + break; + case 55: + if (itemSrc == 16) { + createMouseItem(98); + characterTalk(1400); + return 1; + } + break; + case 61: + if (itemSrc == 0x1f) { + characterTalk(1412); + deleteItemFromInventory(31); + createMouseItem(62); + rearrangeInventory(); + return 1; + } else if (itemSrc == 0x21 || itemSrc == 0x22) { + characterTalk(1414); + return 1; + } + break; + case 64: + if (itemSrc == 0xb) { + sayLines(2, 1212); + return 1; + } else if (itemSrc == 0x5e || itemSrc == 0x5f) { + characterTalk(1318); + return 1; + } + break; + case 66: + if (itemSrc == 15) { + characterTalk(1492); + return 1; + } else if (itemSrc == 0x2f) { + characterTalk(1488); + return 1; + } else if (itemSrc == 88) { + sayLines(2, 1478); + characterTalk(1478); + return 1; + } + break; + case 67: + if (itemSrc == 79) { + sayLines(2, 1212); + return 1; + } + break; + case 68: + if (itemSrc == 35) { + createMouseItem(69); + replaceItemFromInventory(35, 36); + return 1; + } else if (itemSrc == 0x24) { + createMouseItem(69); + replaceItemFromInventory(36, 37); + return 1; + } else if (itemSrc == 37) { + deleteItemFromInventory(37); + createMouseItem(69); + rearrangeInventory(); + return 1; + } else if (itemSrc == 0x6b || itemSrc == 113 || itemSrc == 0x6f || itemSrc == 109) { + sayLines(2, 1288); + return 1; + } + break; + case 69: + switch (itemSrc) { + case 107: + characterTalk(1296); + replaceItemFromInventory(107, 108); + _gameState->_mouseState = -1; + setCursor(0, false, 0, 0); + rearrangeInventory(); + return 1; + case 109: + characterTalk(1298); + replaceItemFromInventory(109, 110); + _gameState->_mouseState = -1; + setCursor(0, false, 0, 0); + rearrangeInventory(); + return 1; + case 111: + characterTalk(1296); + replaceItemFromInventory(111, 112); + _gameState->_mouseState = -1; + setCursor(0, false, 0, 0); + rearrangeInventory(); + return 1; + case 113: + characterTalk(1298); + replaceItemFromInventory(113, 114); + _gameState->_mouseState = -1; + setCursor(0, false, 0, 0); + rearrangeInventory(); + return 1; + } + break; + case 71: + if (itemSrc == 0xc || itemSrc == 1 || itemSrc == 0x41 || itemSrc == 67 || itemSrc == 0x4c || itemSrc == 57) { + sayLines(2, 1212); + return 1; + } else if (itemSrc == 79) { + characterTalk(1238); + return 1; + } + break; + case 79: + if (itemSrc == 1 || itemSrc == 67 || itemSrc == 76 || itemSrc == 57 || itemSrc == 0x41) { + sayLines(2, 1212); + return 1; + } else if (itemSrc == 0x18) { + characterTalk(1280); + return 1; + } else if (itemSrc == 0x47) { + characterTalk(1238); + return 1; + } + break; + case 82: + if (itemSrc == 84) { + sayLines(2, 1424); + return 1; + } else if (itemSrc == 0x58) { + deleteItemFromInventory(88); + createMouseItem(89); + rearrangeInventory(); + characterTalk(1428); + return 1; + } else if (itemSrc == 117) { + sayLines(2, 1496); + return 1; + } + break; + case 84: + if (itemSrc == 0x58) { + replaceItemFromInventory(88, 90); + characterTalk(1090); + return 1; + } else if (itemSrc == 117) { + characterTalk(1494); + return 1; + } + break; + case 88: + if (itemSrc == 82) { + deleteItemFromInventory(82); + createMouseItem(89); + rearrangeInventory(); + characterTalk(1428); + return 1; + } else if (itemSrc == 0x54) { + createMouseItem(90); + characterTalk(1090); + return 1; + } else if (itemSrc == 102) { + deleteItemFromInventory(102); + createMouseItem(90); + rearrangeInventory(); + characterTalk(1090); + return 1; + } + break; + case 89: + if (itemSrc == 117) { + sayLines(2, 1496); + return 1; + } + break; + case 90: + if (itemSrc == 117) { + sayLines(2, 1494); + return 1; + } + break; + case 91: + if (itemSrc == 0x28) { + characterTalk(1230); + return 1; + } else if (itemSrc == 54) { + createMouseItem(92); + return 1; + } + break; + case 92: + if (itemSrc == 0x28 || itemSrc == 54) { + characterTalk(1220); + return 1; + } + break; + case 94: + if (itemSrc == 26) { + characterTalk(1316); + return 1; + } else if (itemSrc == 0x34) { + characterTalk(1282); + return 1; + } else if (itemSrc == 64) { + characterTalk(1318); + return 1; + } + break; + case 95: + if (itemSrc == 26) { + characterTalk(1320); + return 1; + } else if (itemSrc == 0x40) { + characterTalk(1318); + return 1; + } else if (itemSrc == 115) { + characterTalk(1284); + replaceItemFromInventory(115, 116); + createMouseItem(93); + return 1; + } + break; + case 96: + if (itemSrc == 0x34) { + characterTalk(1234); + return 1; + } else if (itemSrc == 71) { + sayLines(2, 1212); + return 1; + } + break; + case 97: + if (itemSrc == 15) { + characterTalk(1492); + return 1; + } else if (itemSrc == 0x2f) { + characterTalk(1488); + return 1; + } else if (itemSrc == 88) { + sayLines(2, 1478); + return 1; + } + break; + case 100: + if (itemSrc == 117) { + characterTalk(1490); + return 1; + } + break; + case 102: + if (itemSrc == -1) { + characterTalk(1102); + return 1; + } else if (itemSrc == 84) { + _gameState->_mouseState = -1; + setCursor(0, false, 0, 0); + rearrangeInventory(); + characterTalk(1418); + return 1; + } else if (itemSrc == 88) { + deleteItemFromInventory(88); + createMouseItem(90); + rearrangeInventory(); + characterTalk(1090); + return 1; + } else if (itemSrc == 117) { + characterTalk(1494); + return 1; + } else { + characterTalk(1426); + return 1; + } + break; + case 106: + if (itemSrc == 13) { + characterTalk(1308); + return 1; + } + break; + case 107: + if (itemSrc == 19) { + sayLines(2, 1300); + deleteItemFromInventory(19); + createMouseItem(111); + rearrangeInventory(); + return 1; + } else if (itemSrc == 0x15) { + characterTalk(1296); + deleteItemFromInventory(21); + createMouseItem(109); + rearrangeInventory(); + return 1; + } else if (itemSrc == 0x23) { + characterTalk(1314); + return 1; + } else if (itemSrc == 69) { + characterTalk(1296); + deleteItemFromInventory(69); + createMouseItem(108); + rearrangeInventory(); + return 1; + } + break; + case 108: + if (itemSrc == 19) { + sayLines(2, 1300); + deleteItemFromInventory(19); + createMouseItem(112); + rearrangeInventory(); + return 1; + } else if (itemSrc == 0x15) { + characterTalk(1298); + deleteItemFromInventory(21); + createMouseItem(110); + rearrangeInventory(); + return 1; + } else if (itemSrc == 35) { + characterTalk(1314); + return 1; + } + break; + case 109: + if (itemSrc == 19) { + sayLines(2, 1300); + deleteItemFromInventory(19); + createMouseItem(113); + rearrangeInventory(); + return 1; + } else if (itemSrc == 0x23) { + characterTalk(1314); + return 1; + } else if (itemSrc == 69) { + characterTalk(1298); + deleteItemFromInventory(69); + createMouseItem(110); + rearrangeInventory(); + return 1; + } + break; + case 110: + if (itemSrc == 0x13) { + sayLines(2, 1300); + deleteItemFromInventory(19); + createMouseItem(114); + rearrangeInventory(); + return 1; + } else if (itemSrc == 35) { + characterTalk(1314); + return 1; + } + break; + case 111: + if (itemSrc == 21) { + characterTalk(1296); + deleteItemFromInventory(21); + createMouseItem(113); + rearrangeInventory(); + return 1; + } else if (itemSrc == 0x23) { + characterTalk(1314); + return 1; + } else if (itemSrc == 69) { + characterTalk(1296); + deleteItemFromInventory(69); + createMouseItem(112); + rearrangeInventory(); + return 1; + } + break; + case 112: + if (itemSrc == 0x15) { + characterTalk(1298); + deleteItemFromInventory(21); + createMouseItem(114); + rearrangeInventory(); + return 1; + } else if (itemSrc == 35) { + characterTalk(1314); + return 1; + } + break; + case 113: + if (itemSrc == 0x23) { + characterTalk(1314); + return 1; + } else if (itemSrc == 69) { + characterTalk(1298); + deleteItemFromInventory(69); + createMouseItem(114); + rearrangeInventory(); + return 1; + } + break; + case 114: + if (itemSrc == 35) { + characterTalk(1314); + return 1; + } + break; + case 115: + if (itemSrc == 95) { + replaceItemFromInventory(95, 93); + createMouseItem(116); + return 1; + } + break; + case 117: + if (itemSrc == 90 || itemSrc == 33) { + characterTalk(1490); + } else if (itemSrc == 102 || itemSrc == 84) { + characterTalk(1494); + } else if (itemSrc == 0x59 || itemSrc == 0x52) { + characterTalk(1496); + } + } + return 0; +} +int32 ToonEngine::handleInventoryOnDrew(int32 itemId) { + switch (itemId) { + case 1: + sayLines(1, 1232); + return 1; + case 2: + sayLines(2, 1202); + return 1; + case 7: + if (_gameState->_currentScene == 32) { + runEventScript(_mouseX, _mouseY, 2, 107, 0); + } else if (_gameState->_currentScene < 37) { + sayLines(2, 1258); + } else { + sayLines(2, 1462); + } + return 1; + case 8: + sayLines(2, 1328); + return 1; + case 0xc: + sayLines(1, 1266); + return 1; + case 0xd: + sayLines(1, 1206); + return 1; + case 16: + sayLines(1, 1438); + return 1; + case 0x12: + if (_gameState->_currentScene == 30) { + runEventScript(_mouseX, _mouseY, 2, 106, 0); + _gameState->_mouseState = -1; + } else { + sayLines(2, 1200); + } + return 1; + case 0x14: + sayLines(1, 1216); + return 1; + case 22: + if (_gameState->_currentScene != 39 && _gameState->_currentScene != 50 && _gameState->_currentScene != 49) { + if (_gameState->_currentScene < 37) { + sayLines(1, 1256); + } else { + sayLines(1, 1456); + } + } else { + runEventScript(_mouseX, _mouseY, 2, 100 , 0); + } + return 1; + case 0x18: + sayLines(1, 1216); + return 1; + case 0x23: + sayLines(1, 1210); + return 1; + case 0x31: + sayLines(1, 1262); + return 1; + case 50: + if (_gameState->_currentScene == 37) { + runEventScript(_mouseX, _mouseY, 2, 103, 0); + return 1; + }; + break; + case 0x36: + if (_gameState->_currentScene == 46) { + runEventScript(_mouseX, _mouseY, 2, 102, 0); + } else { + sayLines(1, 1224); + } + return 1; + case 0x37: + sayLines(1, 1408); + return 1; + case 0x20: + sayLines(1, 1254); + return 1; + case 0x21: + sayLines(1, 1268); + return 1; + case 0x22: + if (_gameState->_currentScene == 52) { + runEventScript(_mouseX, _mouseY, 2, 104, 0); + return 1; + } else { + _gameState->_mouseHidden = true; + _drew->setFacing(4); + sayLines(1, 1465); + sayLines(1, randRange(0, 1) + 1468); + createMouseItem(33); + _gameState->_mouseHidden = false; + return 1; + } + break; + case 31: + sayLines(1, 1436); + return 1; + case 0x1a: + sayLines(1, 1216); + return 1; + case 0x39: + sayLines(1, 1270); + return 1; + case 0x3a: + sayLines(1, 1444); + return 1; + case 0x3b: + sayLines(1, 1272); + return 1; + case 0x3f: + if (_gameState->_currentScene != 10 && _gameState->_currentScene != 30 && _gameState->_currentScene != 22) { + sayLines(1, 1274); + } else { + runEventScript(_mouseX, _mouseY, 2, 109, 0); + } + return 1; + case 0x41: + sayLines(1, 1232); + return 1; + + case 0x4b: + if (_gameState->_currentScene != 53) { + _gameState->_mouseHidden = true; + _drew->setFacing(4); + sayLines(1, 1437); + sayLines(2, 1440); + _gameState->_mouseHidden = false; + } else { + runEventScript(_mouseX, _mouseY, 2 , 101, 0); + } + return 1; + case 79: + sayLines(1, 1242); + return 1; + case 0x4c: + sayLines(1, 1232); + return 1; + case 71: + sayLines(1, 1250); + return 1; + case 0x43: + sayLines(1, 1216); + return 1; + case 0x60: + sayLines(2, 1236); + return 1; + case 99: + if (_gameState->_currentScene == 43) { + runEventScript(_mouseX, _mouseY, 2, 105, 0); + } + _gameState->_mouseState = -1; + setCursor(0, false, 0, 0); + sayLines(1, 1555); + return 1; + case 0x5a: + sayLines(1, 1432); + return 1; + case 0x58: + sayLines(1, 1432); + return 1; + case 0x65: + if (_gameState->_currentScene == 52) { + runEventScript(_mouseX, _mouseY, 2, 104, 0); + } else { + _gameState->_mouseHidden = true; + _drew->setFacing(4); + sayLines(1, 1464); + sayLines(1, 1468 + randRange(0, 1)); + createMouseItem(100); + _gameState->_mouseHidden = false; + } + return 1; + case 0x74: + sayLines(1, 1286); + return 1; + case 0x75: + sayLines(1, 1482); + return 1; + case 118: + sayLines(2, 1500); + return 1; + case 115: + sayLines(1, 1216); + return 1; + case 0x67: + if (_gameState->_currentScene == 52 || _gameState->_currentScene == 53) { + runEventScript(_mouseX, _mouseY, 2, 108, 0); + } + return 1; + } + return 0; +} + +void ToonEngine::deleteItemFromInventory(int32 item) { + for (int32 i = 0; i < _gameState->_numInventoryItems; i++) { + if (_gameState->_inventory[i] == item) { + _gameState->_inventory[i] = 0; + rearrangeInventory(); + return; + } + } +} + +void ToonEngine::replaceItemFromInventory(int32 item, int32 newitem) { + for (int32 i = 0; i < _gameState->_numInventoryItems; i++) { + if (_gameState->_inventory[i] == item) { + _gameState->_inventory[i] = newitem; + return; + } + } +} + +int32 ToonEngine::pauseSceneAnimationScript(int32 animScriptId, int32 tickToWait) { + int32 nextTicks = getTickLength() * tickToWait + getSceneAnimationScript(animScriptId)->_lastTimer; + if (nextTicks < getOldMilli()) { + getSceneAnimationScript(animScriptId)->_lastTimer = getOldMilli() + getTickLength() * tickToWait; + } else { + getSceneAnimationScript(animScriptId)->_lastTimer = nextTicks; + } + return nextTicks; +} + +Common::String ToonEngine::createRoomFilename(Common::String name) { + Common::String file = Common::String::printf("ACT%d/%s/%s", _gameState->_currentChapter, _gameState->_locations[_gameState->_currentScene]._name, name.c_str()); + return file; +} + +void ToonEngine::createShadowLUT() { + // here we create the redirection table that will be used to draw shadows + // for each color of the palette we find the closest color in the palette that could be used for shadowed color. + + // In the original program, the scale factor is 0.77f + // we will use 77 / 100 here. + + if (!_shadowLUT) { + _shadowLUT = new uint8[256]; + } + + uint32 scaleNum = 77; + uint32 scaleDenom = 100; + + for (int32 i = 0; i < 255; i++) { + + // goal color + uint32 destR = _finalPalette[i*3+0] * scaleNum / scaleDenom; + uint32 destG = _finalPalette[i*3+1] * scaleNum / scaleDenom; + uint32 destB = _finalPalette[i*3+2] * scaleNum / scaleDenom; + + // search only in the "picture palette" which is in colors 1-128 and 200-255 + int32 colorDist = 0xffffff; + int32 foundColor = 0; + + for (int32 c = 1; c < 129; c++) { + + int32 diffR = _finalPalette[c*3+0] - destR; + int32 diffG = _finalPalette[c*3+1] - destG; + int32 diffB = _finalPalette[c*3+2] - destB; + + if (colorDist > diffR * diffR + diffG * diffG + diffB * diffB) { + colorDist = diffR * diffR + diffG * diffG + diffB * diffB; + foundColor = c; + } + } + + for (int32 c = 200; c < 256; c++) { + + int32 diffR = _finalPalette[c*3+0] - destR; + int32 diffG = _finalPalette[c*3+1] - destG; + int32 diffB = _finalPalette[c*3+2] - destB; + + if (colorDist > diffR * diffR + diffG * diffG + diffB * diffB) { + colorDist = diffR * diffR + diffG * diffG + diffB * diffB; + foundColor = c; + } + } + + _shadowLUT[i] = foundColor; + + } +} + +bool ToonEngine::loadToonDat() { + Common::File in; + char buf[256]; + int majVer, minVer; + + in.open("toon.dat"); + + if (!in.isOpen()) { + Common::String errorMessage = "You're missing the 'toon.dat' file. Get it from the ScummVM website"; + GUIErrorMessage(errorMessage); + warning("%s", errorMessage.c_str()); + return false; + } + + // Read header + in.read(buf, 4); + buf[4] = '\0'; + + if (strcmp(buf, "TOON")) { + Common::String errorMessage = "File 'toon.dat' is corrupt. Get it from the ScummVM website"; + GUIErrorMessage(errorMessage); + warning("%s", errorMessage.c_str()); + return false; + } + + majVer = in.readByte(); + minVer = in.readByte(); + + if ((majVer != TOON_DAT_VER_MAJ) || (minVer != TOON_DAT_VER_MIN)) { + snprintf(buf, 256, "File 'toon.dat' is wrong version. Expected %d.%d but got %d.%d. Get it from the ScummVM website", TOON_DAT_VER_MAJ, TOON_DAT_VER_MIN, majVer, minVer); + GUIErrorMessage(buf); + warning("%s", buf); + + return false; + } + + _numVariant = in.readUint16BE(); + + _locationDirNotVisited = loadTextsVariante(in); + _locationDirVisited = loadTextsVariante(in); + _specialInfoLine = loadTextsVariante(in); + + return true; +} + +char **ToonEngine::loadTextsVariante(Common::File &in) { + int numTexts; + int entryLen; + int len; + char **res = 0; + char *pos = 0; + + for (int varnt = 0; varnt < _numVariant; varnt++) { + numTexts = in.readUint16BE(); + entryLen = in.readUint16BE(); + pos = (char *)malloc(entryLen); + if (varnt == _gameVariant) { + res = (char **)malloc(sizeof(char *) * numTexts); + res[0] = pos; + in.read(res[0], entryLen); + res[0] += DATAALIGNMENT; + } else { + in.read(pos, entryLen); + } + + pos += DATAALIGNMENT; + + for (int i = 1; i < numTexts; i++) { + pos -= 2; + + len = READ_BE_UINT16(pos); + pos += 2 + len; + + if (varnt == _gameVariant) + res[i] = pos; + } + } + + return res; +} + +void ToonEngine::makeLineNonWalkable(int32 x, int32 y, int32 x2, int32 y2) { + _currentMask->drawLineOnMask(x, y, x2, y2, false); +} + +void ToonEngine::makeLineWalkable(int32 x, int32 y, int32 x2, int32 y2) { + _currentMask->drawLineOnMask(x, y, x2, y2, true); +} + +void ToonEngine::playRoomMusic() { + if(_gameState->_inConversation) { + const char* music = getSpecialConversationMusic(_gameState->_currentConversationId); + if (music) { + _audioManager->playMusic(_gameState->_locations[_gameState->_currentScene]._name, music); + return; + } + } + + _audioManager->playMusic(_gameState->_locations[_gameState->_currentScene]._name, _gameState->_locations[_gameState->_currentScene]._music); +} + +void SceneAnimation::save(ToonEngine *vm, Common::WriteStream *stream) { + stream->writeByte(_active); + stream->writeSint32BE(_id); + + if (!_active) + return; + + if (_animInstance) { + stream->writeByte(1); + _animInstance->save(stream); + } else { + stream->writeByte(0); + } + + if (!_animation) { + stream->writeByte(0); + } else { + stream->writeByte(strlen(_animation->_name) + 1); + stream->write(_animation->_name, strlen(_animation->_name) + 1); + } +} +void SceneAnimation::load(ToonEngine *vm, Common::ReadStream *stream) { + + _active = stream->readByte(); + _id = stream->readSint32BE(); + + + if (!_active) + return; + + if (stream->readByte() == 1) { + _animInstance = vm->getAnimationManager()->createNewInstance(kAnimationScene); + _animInstance->load(stream); + vm->getAnimationManager()->addInstance(_animInstance); + } + + // load animation if any + char animationName[256]; + *animationName = 0; + int8 strSize = stream->readByte(); + if (!strSize) { + _animation = 0; + if (_animInstance) + _animInstance->setAnimation(0); + } else { + stream->read(animationName, strSize); + animationName[strSize] = 0; + + _animation = new Animation(vm); + _animation->loadAnimation(animationName); + + if (_animInstance) + _animInstance->setAnimation(_animation, false); + + printf("load animation instance %d / %s / visible %d \n", _id, _animation->_name, _animInstance->getVisible()); + } +} + +} // End of namespace Toon |