scummvm/engines/toon/toon.cpp
eriktorbjorn 7ecab9a982 TOON: Disable quick save/load from the main menu screen.
Saving is pointless and loading doesn't work right. Unless it's
really easy, making quick load work from the main menu is hardly
worth it, since it has a perfectly usable load button already.
2011-02-14 20:44:18 +01:00

4735 lines
116 KiB
C++

/* 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 "common/savefile.h"
#include "common/memstream.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(DisposeAfterUse::YES);
_firstFrame = false;
const Common::FSNode gameDataDir(ConfMan.get("path"));
SearchMan.addSubDirectoryMatching(gameDataDir, "MISC");
SearchMan.addSubDirectoryMatching(gameDataDir, "ACT1");
SearchMan.addSubDirectoryMatching(gameDataDir, "ACT2");
syncSoundSettings();
_pathFinding = new PathFinding(this);
resources()->openPackage("LOCAL.PAK", true);
resources()->openPackage("ONETIME.PAK", true);
resources()->openPackage("DREW.PAK", true);
for (int32 i = 0; i < 32; i++)
_characters[i] = NULL;
_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", "GENERIC.SVL");
_audioManager->loadAudioPack(2, "GENERIC.SEI", "GENERIC.SEL");
_lastMouseButton = 0;
_mouseButton = 0;
_lastRenderTime = _system->getMillis();
}
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(1);
_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)) {
bool hasModifier = event.kbd.hasFlags(Common::KBD_ALT|Common::KBD_CTRL|Common::KBD_SHIFT);
switch (event.type) {
case Common::EVENT_KEYDOWN:
if ((event.kbd.ascii == 27 || event.kbd.ascii == 32) && !hasModifier) {
_audioManager->stopCurrentVoice();
}
if (event.kbd.keycode == Common::KEYCODE_F5 && !hasModifier) {
if(canSaveGameStateCurrently())
saveGame(-1, Common::String());
}
if (event.kbd.keycode == Common::KEYCODE_F6 && !hasModifier) {
if(canLoadGameStateCurrently())
loadGame(-1);
}
if (event.kbd.ascii == 't' && !hasModifier) {
_showConversationText = !_showConversationText;
}
if (event.kbd.ascii == 'm' && !hasModifier) {
_audioManager->muteMusic(!_audioManager->isMusicMuted());
}
if (event.kbd.ascii == 'd' && !hasModifier) {
_audioManager->muteVoice(!_audioManager->isVoiceMuted());
}
if (event.kbd.ascii == 's' && !hasModifier) {
_audioManager->muteSfx(!_audioManager->isSfxMuted());
}
if (event.kbd.flags & Common::KBD_ALT) {
int slotNum = event.kbd.ascii - '0';
if (slotNum >= 0 && slotNum <= 9 && canSaveGameStateCurrently()) {
if (saveGame(slotNum, Common::String())) {
// 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);
dialog2.runModal();
}
}
}
if (event.kbd.flags & Common::KBD_CTRL) {
int slotNum = event.kbd.ascii - '0';
if (slotNum >= 0 && slotNum <= 9 && canLoadGameStateCurrently()) {
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();
}
}
if (event.kbd.keycode == Common::KEYCODE_d) {
_console->attach();
_console->onFrame();
}
}
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);
_audioManager->updateAmbientSFX();
_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)", (int)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(); // used to debug the current palette
//_drew->plotPath(*_mainSurface); // used to debug path finding
#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 (_needPaletteFlush) {
flushPalette(false);
_needPaletteFlush = false;
}
if (_firstFrame) {
copyToVirtualScreen(false);
fadeIn(5);
_firstFrame = false;
} else {
copyToVirtualScreen(true);
}
// add a little sleep here
int32 newMillis = (int32)_system->getMillis();
int32 sleepMs = 1; // Minimum delay to allow thread scheduling
if ((newMillis - _lastRenderTime) < _tickLength)
sleepMs = _tickLength - (newMillis - _lastRenderTime);
assert(sleepMs >= 0);
_system->delayMillis(sleepMs);
_lastRenderTime = _system->getMillis();
}
void ToonEngine::doMagnifierEffect() {
int32 posX = _mouseX + state()->_currentScrollValue - _cursorOffsetX;
int32 posY = _mouseY - _cursorOffsetY - 2;
Graphics::Surface &surface = *_mainSurface;
// fast sqrt table lookup (values up to 144 only)
static const byte intSqrt[] = {
0, 1, 1, 1, 2, 2, 2, 2, 2, 3,
3, 3, 3, 3, 3, 3, 4, 4, 4, 4,
4, 4, 4, 4, 4, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 8, 8, 8, 8, 8, 8,
8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
8, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
10, 11, 11, 11, 11, 11, 11, 11, 11, 11,
11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
11, 11, 11, 11, 12
};
byte tempBuffer[25*25];
for (int32 y = -12; y <= 12; y++) {
for (int32 x = -12; x <= 12; x++) {
int32 destPitch = surface.pitch;
uint8 *curRow = (uint8 *)surface.pixels + (posY + y) * destPitch + (posX + x);
tempBuffer[(y+12) * 25 + x + 12] = *curRow;
}
}
for (int32 y = -12; y <= 12; y++) {
for (int32 x = -12; x <= 12; x++) {
int32 dist = y * y + x * x;
if (dist > 144)
continue;
int32 destPitch = surface.pitch;
uint8 *curRow = (uint8 *)surface.pixels + (posY + y) * destPitch + (posX + x);
int32 lerp = (512 + intSqrt[dist] * 256 / 12);
*curRow = tempBuffer[(y*lerp/1024+12) * 25 + x*lerp/1024 + 12];
}
}
}
void ToonEngine::copyToVirtualScreen(bool updateScreen) {
// render cursor last
if (!_gameState->_mouseHidden) {
if (_cursorAnimationInstance->getFrame() == 7 && _cursorAnimationInstance->getAnimation() == _cursorAnimation) // magnifier icon needs a special effect
doMagnifierEffect();
_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();
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();
flushPalette(false);
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;
Common::SeekableReadStream *mainmenuMusicFile = NULL;
AudioStreamInstance *mainmenuMusic = NULL;
bool musicPlaying = false;
_gameState->_inMenu = true;
while (!doExit) {
clickingOn = MAINMENUHOTSPOT_NONE;
clickRelease = false;
if (!musicPlaying) {
mainmenuMusicFile = resources()->openFile("BR091013.MUS");
if (mainmenuMusicFile) {
mainmenuMusic = new AudioStreamInstance(_audioManager, _mixer, mainmenuMusicFile, true);
mainmenuMusic->play(false);
musicPlaying = true;
}
else {
musicPlaying = false;
}
}
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);
delete mainmenuMusicFile;
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("209_1M.SMK", 0x10);
getMoviePlayer()->play("209_2M.SMK", 0x10);
getMoviePlayer()->play("209_3M.SMK", 0x10);
break;
case MAINMENUHOTSPOT_LOADGAME:
doExit = loadGame(-1);
loadedGame = doExit;
exitGame = false;
break;
case MAINMENUHOTSPOT_CREDITS:
// Play credits movie
getMoviePlayer()->play("CREDITS.SMK", 0x0);
break;
case MAINMENUHOTSPOT_QUIT:
exitGame = true;
doExit = true;
break;
}
}
_gameState->_inMenu = false;
//delete mainmenuMusic;
for (int entryNr = 0; entryNr < MAINMENU_ENTRYCOUNT; entryNr++)
delete entries[entryNr].animation;
delete mainmenuPicture;
return !exitGame;
}
Common::Error ToonEngine::run() {
if (!loadToonDat())
return Common::kUnknownError;
g_eventRec.registerRandomSource(_rnd, "toon");
initGraphics(640, 400, true);
init();
// do we need to load directly a game?
bool loadedGame = false;
int32 slot = ConfMan.getInt("save_slot");
if (slot > -1) {
loadedGame = loadGame(slot);
}
if (!loadedGame) {
// play producer intro
getMoviePlayer()->play("VIELOGOM.SMK", 0x10);
// show mainmenu
if (!showMainmenu(loadedGame)) {
return Common::kNoError;
}
}
//loadScene(17);
//loadScene(37);
if (!loadedGame) {
newGame();
}
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;
_currentPicture = NULL;
_inventoryPicture = NULL;
_currentMask = NULL;
_showConversationText = true;
_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");
_resources = NULL;
_animationManager = NULL;
_moviePlayer = NULL;
_mainSurface = NULL;
_finalPalette = NULL;
_backupPalette = NULL;
_additionalPalette1 = NULL;
_additionalPalette2 = NULL;
_cutawayPalette = NULL;
_universalPalette = NULL;
_fluxPalette = NULL;
_roomScaleData = NULL;
_shadowLUT = NULL;
_conversationData = NULL;
_fontRenderer = NULL;
_fontToon = NULL;
_fontEZ = NULL;
_hotspots = NULL;
_genericTexts = NULL;
_roomTexts = NULL;
_script_func = NULL;
_script = NULL;
_mouseX = 0;
_mouseY = 0;
_mouseButton = 0;
_lastMouseButton = 0;
_saveBufferStream = NULL;
_pathFinding = NULL;
_console = new ToonConsole(this);
_cursorAnimation = NULL;
_cursorAnimationInstance = NULL;
_dialogIcons = NULL;
_inventoryIcons = NULL;
_inventoryIconSlots = NULL;
_genericTexts = NULL;
_audioManager = NULL;
memset(&_scriptData, 0, sizeof(EMCData));
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 = 4;
break;
default:
// 0 - english
_gameVariant = 0;
break;
}
}
ToonEngine::~ToonEngine() {
delete _currentPicture;
delete _currentMask;
delete _inventoryPicture;
delete _resources;
delete _animationManager;
delete _moviePlayer;
if(_mainSurface) {
_mainSurface->free();
delete _mainSurface;
}
delete[] _finalPalette;
delete[] _backupPalette;
delete[] _additionalPalette1;
delete[] _additionalPalette2;
delete[] _cutawayPalette;
delete[] _universalPalette;
delete[] _fluxPalette;
delete[] _roomScaleData;
delete[] _shadowLUT;
delete[] _conversationData;
delete _fontRenderer;
delete _fontToon;
delete _fontEZ;
delete _hotspots;
delete _genericTexts;
delete _roomTexts;
delete _script_func;
_script->unload(&_scriptData);
delete _script;
delete _saveBufferStream;
delete _pathFinding;
for (int32 i = 0; i < 64; i++) {
if (_sceneAnimations[i]._active) {
// see if one character shares this instance
for (int32 c = 0; c < 32; c++) {
if (_characters[c] && _characters[c]->getAnimationInstance() == _sceneAnimations[i]._animInstance) {
_characters[c]->setAnimationInstance(0);
}
}
delete _sceneAnimations[i]._originalAnimInstance;
delete _sceneAnimations[i]._animation;
}
}
for (int32 i = 0; i < 32; i++)
delete _characters[i];
delete _cursorAnimation;
delete _cursorAnimationInstance;
delete _dialogIcons;
delete _inventoryIcons;
delete _inventoryIconSlots;
//delete _genericTexts;
delete _audioManager;
delete _gameState;
unloadToonDat();
DebugMan.clearAllDebugChannels();
delete _console;
}
void ToonEngine::flushPalette(bool deferFlushToNextRender) {
if (deferFlushToNextRender) {
_needPaletteFlush = true;
return;
}
_needPaletteFlush = false;
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->getPaletteManager()->setPalette(vmpalette, 0, 256);
}
void ToonEngine::setPaletteEntries(uint8 *palette, int32 offset, int32 num) {
memcpy(_finalPalette + offset * 3, palette, num * 3);
flushPalette();
}
void ToonEngine::simpleUpdate(bool waitCharacterToTalk) {
int32 elapsedTime = _system->getMillis() - _oldTimer2;
_oldTimer2 = _system->getMillis();
_oldTimer = _oldTimer2;
if (!_audioManager->voiceStillPlaying() && !waitCharacterToTalk) {
_currentTextLine = 0;
_currentTextLineId = -1;
}
updateCharacters(elapsedTime);
updateAnimationSceneScripts(elapsedTime);
updateTimer(elapsedTime);
_animationManager->update(elapsedTime);
_audioManager->updateAmbientSFX();
render();
}
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 && !_sceneAnimationScripts[_lastProcessedSceneScript]._frozenForConversation) {
_animationSceneScriptRunFlag = true;
while (_animationSceneScriptRunFlag && _sceneAnimationScripts[_lastProcessedSceneScript]._lastTimer <= _system->getMillis() && !_shouldQuit) {
if (!_script->run(&_sceneAnimationScripts[_lastProcessedSceneScript]._state))
_animationSceneScriptRunFlag = false;
//waitForScriptStep();
if (_sceneAnimationScripts[_lastProcessedSceneScript]._frozen || _sceneAnimationScripts[_lastProcessedSceneScript]._frozenForConversation)
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 = 0;
if (!forGameLoad) {
_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;
_mouseButton = 0;
_lastMouseButton = 0x3;
// load package
strcpy(temp, createRoomFilename(Common::String::format("%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");
delete _currentPicture;
_currentPicture = new Picture(this);
_currentPicture->loadPicture(temp);
_currentPicture->setupPalette();
strcpy(temp, state()->_locations[SceneId]._name);
strcat(temp, ".MSC");
delete _currentMask;
_currentMask = new Picture(this);
if (_currentMask->loadPicture(temp))
_pathFinding->init(_currentMask);
strcpy(temp, state()->_locations[SceneId]._name);
strcat(temp, ".TRE");
delete _roomTexts;
_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) {
delete[] _roomScaleData;
_roomScaleData = new uint8[fileSize];
memcpy(_roomScaleData, sceneData, fileSize);
}
strcpy(temp, state()->_locations[SceneId]._name);
strcat(temp, ".SVI");
strcpy(temp2, createRoomFilename(Common::String::format("%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->unload(&_scriptData);
_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;
_sceneAnimationScripts[i]._frozenForConversation = false;
}
}
playRoomMusic();
_lastProcessedSceneScript = 0;
_gameState->_locations[SceneId]._visited = true;
setupGeneralPalette();
createShadowLUT();
state()->_mouseHidden = false;
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->forcePosition(_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();
}
}
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));
delete _script;
_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();
_script->unload(&data);
setupGeneralPalette();
}
void ToonEngine::loadCursor() {
delete _cursorAnimation;
_cursorAnimation = new Animation(this);
_cursorAnimation->loadAnimation("MOUSE.CAF");
delete _cursorAnimationInstance;
_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, int 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) == 0 && (_mouseButton & 0x1) == 1)
leftButton = true;
if ((_lastMouseButton & 0x2) == 0 && (_mouseButton & 0x2) == 2)
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 = 0;
return;
} else {
showInventory();
}
return;
}
}
// with inventory
if (rightButton && _gameState->_mouseState >= 0) {
addItemToInventory(_gameState->_mouseState);
setCursor(0, false, 0, 0);
_currentHotspotItem = 0;
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);
// see if one character shares this instance
for (int32 c = 0; c < 32; c++) {
if (_characters[c] && _characters[c]->getAnimationInstance() == _sceneAnimations[i]._animInstance) {
_characters[c]->setAnimationInstance(NULL);
}
}
delete _sceneAnimations[i]._originalAnimInstance;
_sceneAnimations[i]._animInstance = NULL;
_sceneAnimations[i]._animation = NULL;
_sceneAnimations[i]._originalAnimInstance = NULL;
}
}
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;
}
_audioManager->killAllAmbientSFX();
_audioManager->stopAllSfxs();
_audioManager->stopCurrentVoice();
_currentTextLine = 0;
_currentTextLineId = -1;
_currentTextLineCharacterId = 0;
char temp[256];
strcpy(temp, createRoomFilename(Common::String::format("%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->getPaletteManager()->setPalette(vmpalette, 0, 256);
_system->updateScreen();
_system->delayMillis(_tickLength);
}
}
void ToonEngine::fadeOut(int32 numFrames) {
uint8 oldpalette[1024];
_system->getPaletteManager()->grabPalette(oldpalette, 0, 256);
for (int32 f = 0; f < numFrames; f++) {
uint8 vmpalette[1024];
for (int32 i = 0; i < 256; i++) {
vmpalette[i*4+0] = (numFrames - f - 1) * oldpalette[i*4+0] / (numFrames - 1);
vmpalette[i*4+1] = (numFrames - f - 1) * oldpalette[i*4+1] / (numFrames - 1);
vmpalette[i*4+2] = (numFrames - f - 1) * oldpalette[i*4+2] / (numFrames - 1);
vmpalette[i*4+3] = 255;
}
_system->getPaletteManager()->setPalette(vmpalette, 0, 256);
_system->updateScreen();
_system->delayMillis(_tickLength);
}
}
void ToonEngine::initFonts() {
_fontRenderer = new FontRenderer(this);
_fontToon = new Animation(this);
_fontToon->loadAnimation("TOONFONT.CAF");
_fontEZ = new Animation(this);
_fontEZ->loadAnimation("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);
}
}
}
Common::WriteStream *ToonEngine::getSaveBufferStream() {
return _saveBufferStream;
}
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;
// clamp values
x = MIN<int32>(1279, MAX<int32>(0, x));
y = MIN<int32>(399, MAX<int32>(0, y));
int32 maskData = _currentMask->getData(x, y) & 0x1f;
return _roomScaleData[maskData+2] * 1024 / 100;
}
int32 ToonEngine::getLayerAtPoint(int32 x, int32 y) {
if (!_currentMask)
return 0;
// clamp values
x = MIN<int32>(1279, MAX<int32>(0, x));
y = MIN<int32>(399, MAX<int32>(0, y));
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()) {
if (_currentTextLineCharacterId == 0 || _currentTextLineCharacterId == 1) {
// Drew or Flux 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) {
Character *character = getCharacterById(talkerId);
if (character)
character->setTalking(true);
playTalkAnimOnCharacter(talkerAnimId, talkerId, true);
// set once more the values, they may have been overwritten when the engine
// waits for the character to be ready.
_currentTextLine = myLine;
_currentTextLineCharacterId = talkerId;
_currentTextLineId = dialogid;
} else {
Character *character = getCharacterById(talkerId);
if (character)
character->stopSpecialAnim();
}
debugC(0, 0xfff, "Talker = %d (num participants : %d) will say '%s'", (int)talkerId , (int)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;
Character *character = getCharacterById(talkerId);
if (character)
character->setTalking(false);
}
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 (READ_LE_INT16(i) >= 0) {
if (READ_LE_INT16(i) < 100) {
if (_gameState->_exitConversation == false) {
characterTalk(READ_LE_INT16(i + 1));
}
} else {
runConversationCommand(&i);
}
i += 2;
}
int16 command = READ_LE_INT16(i);
int16 value = READ_LE_INT16(i + 1);
if (command == -1) {
v2->_data2 = 0;
} else if (command == -2) {
v2->_data4 = (char *)_conversationData + value;
v2->_data3 = READ_LE_INT16(v2->_data4);
} else if (command == -3) {
v2->_data2 = 2;
v2->_data4 = (char *)_conversationData + value;
v2->_data3 = READ_LE_INT16(v2->_data4);
}
int16 *v7 = i + 2;
int16 v8 = READ_LE_INT16(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 = READ_LE_INT16(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 = READ_LE_INT16(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[30] & 1))
return 0;
break;
case 0x3e9:
if (!(_gameState->_gameGlobalData[30] & 2))
return 0;
break;
case 0x3ea:
if (!(_gameState->_gameGlobalData[30] & 4))
return 0;
break;
case 0x3eb:
if (!(_gameState->_gameGlobalData[30] & 8))
return 0;
break;
case 0x3ec:
if (!(_gameState->_gameGlobalData[30] & 16))
return 0;
break;
case 0x3ed:
if (!(_gameState->_gameGlobalData[30] & 32))
return 0;
break;
case 0x3ee:
if (!(_gameState->_gameGlobalData[30] & 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;
}
int32 ToonEngine::runConversationCommand(int16 **command) {
int16 *v5 = *command;
int v2 = READ_LE_INT16(v5);
int v4 = READ_LE_INT16(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 - 4);
break;
//
case 105:
if (getConversationFlag(_gameState->_currentScene, v4)) {
result = READ_LE_INT16(*command + 2);
*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();
delete _inventoryPicture;
_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 = 0x3;
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;
_mouseButton = 0;
_lastMouseButton = 0x3;
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 && _showConversationText) {
_fontRenderer->setFontColorByCharacter(_currentTextLineCharacterId);
_fontRenderer->setFont(_fontToon);
_fontRenderer->renderMultiLineText(_currentTextLineX, _currentTextLineY, Common::String(_currentTextLine), 0);
}
}
void ToonEngine::pauseEngineIntern(bool pause) {
Engine::pauseEngineIntern(pause);
static int32 pauseStart = 0;
if (pause) {
pauseStart = _system->getMillis();
} else {
_oldTimer = _system->getMillis();
_oldTimer2 = _oldTimer;
int32 diff = _oldTimer - pauseStart;
// we have to add the difference between the start and the current time
// to all "timer based" values.
for (int32 i = 0; i < _gameState->_locations[_gameState->_currentScene]._numSceneAnimations; i++) {
_sceneAnimationScripts[i]._lastTimer += diff;
}
for (int32 i = 0; i < 8; i++) {
if (_characters[i]) {
_characters[i]->updateTimers(diff);
}
}
_gameState->_timerTimeout[0] += diff;
_gameState->_timerTimeout[1] += diff;
}
}
bool ToonEngine::canSaveGameStateCurrently() {
return !_gameState->_inMenu && !_gameState->_inInventory && !_gameState->_inConversation && !_gameState->_inCutaway && !_gameState->_mouseHidden && !_moviePlayer->isPlaying();
}
bool ToonEngine::canLoadGameStateCurrently() {
return !_gameState->_inMenu && !_gameState->_inInventory && !_gameState->_inConversation && !_gameState->_inCutaway && !_gameState->_mouseHidden && !_moviePlayer->isPlaying();
}
Common::String ToonEngine::getSavegameName(int nr) {
return _targetName + Common::String::format(".%03d", nr);
}
bool ToonEngine::saveGame(int32 slot, Common::String saveGameDesc) {
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->runModalWithPluginAndTarget(plugin, ConfMan.getActiveDomainName());
savegameDescription = dialog->getResultString();
delete dialog;
} else {
savegameId = slot;
if (!saveGameDesc.empty()) {
savegameDescription = saveGameDesc;
} else {
savegameDescription = Common::String::format("Quick save #%d", (int)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->runModalWithPluginAndTarget(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();
_sceneAnimationScripts[i]._frozenForConversation = false;
int32 oldTimer = loadFile->readSint32BE();
_sceneAnimationScripts[i]._lastTimer = MAX<int32>(0,oldTimer + timerDiff);
_script->loadState(&_sceneAnimationScripts[i]._state, loadFile);
}
// load scene animations
for (int32 i = 0; i < 64; i++) {
_sceneAnimations[i].load(this, loadFile);
}
// scene animations have to be added in reverse order in animation manager to preserve the z order
for (int32 i = 63; i >= 0; i--) {
if (_sceneAnimations[i]._active && _sceneAnimations[i]._animInstance) {
_animationManager->addInstance(_sceneAnimations[i]._animInstance);
}
}
_gameState->_timerTimeout[0] += timerDiff;
_gameState->_timerTimeout[1] += timerDiff;
_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[] buf;
}
delete loadFile;
// setup correct palette if we are in a closeup/cutaway or not.
if (_gameState->_inCloseUp) {
_gameState->_inCloseUp = false;
flipScreens();
} else if (_gameState->_inCutaway) {
_currentCutaway->setupPalette();
setupGeneralPalette();
} else {
_currentPicture->setupPalette();
setupGeneralPalette();
}
flushPalette();
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::format("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 = loadTextsVariants(in);
_locationDirVisited = loadTextsVariants(in);
_specialInfoLine = loadTextsVariants(in);
return true;
}
void ToonEngine::unloadToonDat() {
unloadTextsVariants(_locationDirNotVisited);
unloadTextsVariants(_locationDirVisited);
unloadTextsVariants(_specialInfoLine);
}
char **ToonEngine::loadTextsVariants(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);
free(pos);
continue;
}
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::unloadTextsVariants(char **texts) {
if (!texts)
return;
free(*texts - DATAALIGNMENT);
free(texts);
}
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);
// we add them at the end of loading in reverse order
//vm->getAnimationManager()->addInstance(_animInstance);
_originalAnimInstance = _animInstance;
} else {
_animInstance = NULL;
_originalAnimInstance = NULL;
}
// 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);
}
}
}
} // End of namespace Toon