aboutsummaryrefslogtreecommitdiff
path: root/engines/tony/gfxengine.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'engines/tony/gfxengine.cpp')
-rw-r--r--engines/tony/gfxengine.cpp862
1 files changed, 862 insertions, 0 deletions
diff --git a/engines/tony/gfxengine.cpp b/engines/tony/gfxengine.cpp
new file mode 100644
index 0000000000..5c038e154d
--- /dev/null
+++ b/engines/tony/gfxengine.cpp
@@ -0,0 +1,862 @@
+/* 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.
+ *
+ */
+
+/*
+ * This code is based on original Tony Tough source code
+ *
+ * Copyright (c) 1997-2003 Nayma Software
+ */
+
+#include "common/savefile.h"
+#include "tony/mpal/lzo.h"
+#include "tony/mpal/mpalutils.h"
+#include "tony/custom.h"
+#include "tony/gfxengine.h"
+#include "tony/tony.h"
+
+namespace Tony {
+
+
+/****************************************************************************\
+* RMGfxEngine Methods
+\****************************************************************************/
+
+void ExitAllIdles(CORO_PARAM, const void *param) {
+ CORO_BEGIN_CONTEXT;
+ CORO_END_CONTEXT(_ctx);
+
+ int nCurLoc = *(const int *)param;
+
+ CORO_BEGIN_CODE(_ctx);
+
+ // Closes idle
+ GLOBALS._bSkipSfxNoLoop = true;
+
+ CORO_INVOKE_2(mpalEndIdlePoll, nCurLoc, NULL);
+
+ GLOBALS._bIdleExited = true;
+ GLOBALS._bSkipSfxNoLoop = false;
+
+ CORO_END_CODE;
+}
+
+RMGfxEngine::RMGfxEngine() {
+ // Create big buffer where the frame will be rendered
+ _bigBuf.create(RM_BBX, RM_BBY, 16);
+ _bigBuf.offsetY(RM_SKIPY);
+ _bigBuf.setTrackDirtyRects(true);
+
+ _nCurLoc = 0;
+ _curAction = TA_GOTO;
+ _curActionObj = 0;
+ _nWipeType = 0;
+ _hWipeEvent = 0;
+ _nWipeStep = 0;
+ _bMustEnterMenu = false;
+ _bWiping = false;
+ _bGUIOption = false;
+ _bGUIInterface = false;
+ _bGUIInventory = false;
+ _bAlwaysDrawMouse = false;
+ _bOption = false;
+ _bLocationLoaded = false;
+ _bInput = false;
+}
+
+RMGfxEngine::~RMGfxEngine() {
+ // Close the buffer
+ _bigBuf.destroy();
+}
+
+void RMGfxEngine::openOptionScreen(CORO_PARAM, int type) {
+ CORO_BEGIN_CONTEXT;
+ bool bRes;
+ CORO_END_CONTEXT(_ctx);
+
+ CORO_BEGIN_CODE(_ctx);
+
+ _ctx->bRes = false;
+
+ if (type == 0)
+ CORO_INVOKE_2(_opt.init, _bigBuf, _ctx->bRes);
+ else if (type == 1)
+ CORO_INVOKE_3(_opt.initLoadMenuOnly, _bigBuf, true, _ctx->bRes);
+ else if (type == 2)
+ CORO_INVOKE_2(_opt.initNoLoadSave, _bigBuf, _ctx->bRes);
+ else if (type == 3)
+ CORO_INVOKE_3(_opt.initLoadMenuOnly, _bigBuf, false, _ctx->bRes);
+ else if (type == 4)
+ CORO_INVOKE_3(_opt.initSaveMenuOnly, _bigBuf, false, _ctx->bRes);
+
+ if (_ctx->bRes) {
+ g_vm->pauseSound(true);
+
+ disableInput();
+ _inv.endCombine();
+ _curActionObj = 0;
+ _curAction = TA_GOTO;
+ _point.setAction(_curAction);
+ _point.setSpecialPointer(RMPointer::PTR_NONE);
+ _point.setCustomPointer(NULL);
+ enableMouse();
+ g_vm->grabThumbnail();
+
+ // Exists the IDLE to avoid premature death in loading
+ _bMustEnterMenu = true;
+ if (type == 1 || type == 2) {
+ GLOBALS._bIdleExited = true;
+ } else {
+ CORO_INVOKE_0(_tony.stopNoAction);
+
+ GLOBALS._bIdleExited = false;
+
+ CoroScheduler.createProcess(ExitAllIdles, &_nCurLoc, sizeof(int));
+ }
+ }
+
+ CORO_END_CODE;
+}
+
+void RMGfxEngine::doFrame(CORO_PARAM, bool bDrawLocation) {
+ CORO_BEGIN_CONTEXT;
+ CORO_END_CONTEXT(_ctx);
+
+ CORO_BEGIN_CODE(_ctx);
+
+ // Poll of input devices
+ _input.poll();
+
+ if (_bMustEnterMenu && GLOBALS._bIdleExited) {
+ _bOption = true;
+ _bMustEnterMenu = false;
+ GLOBALS._bIdleExited = false;
+ }
+
+ if (_bOption) {
+ CORO_INVOKE_1(_opt.doFrame, &_input);
+ _bOption = !_opt.isClosing();
+ if (!_bOption) {
+ disableMouse();
+ enableInput();
+ mpalStartIdlePoll(_nCurLoc);
+ g_vm->pauseSound(false);
+ }
+ }
+
+ if (bDrawLocation && _bLocationLoaded) {
+ // Location and objects
+ _loc.doFrame(&_bigBuf);
+
+ // Check the mouse input
+ if (_bInput && !_tony.inAction()) {
+ // If we are on the inventory, it is it who controls all input
+ if (_inv.haveFocus(_input.mousePos()) && !_inter.active()) {
+ // Left Click
+ // **********
+ if (_input.mouseLeftClicked()/* && m_itemName.IsItemSelected()*/) {
+ // Left click activates the combine, if we are on an object
+ if (_inv.leftClick(_input.mousePos(), _curActionObj)) {
+ _curAction = TA_COMBINE;
+ _point.setAction(_curAction);
+ }
+ } else
+
+ // Right Click
+ // ***********
+ if (_input.mouseRightClicked()) {
+ if (_itemName.isItemSelected()) {
+ _curActionObj = 0;
+ _inv.rightClick(_input.mousePos());
+ } else
+ _inv.rightClick(_input.mousePos());
+ } else
+
+ // Right Release
+ // *************
+ if (_input.mouseRightReleased()) {
+ if (_inv.rightRelease(_input.mousePos(), _curAction)) {
+ CORO_INVOKE_3(_tony.moveAndDoAction, _itemName.getHotspot(), _itemName.getSelectedItem(), _curAction);
+
+ _curAction = TA_GOTO;
+ _point.setAction(_curAction);
+ }
+ }
+ } else {
+ // Options Menu
+ // ************
+ if (_bGUIOption) {
+ if (!_tony.inAction() && _bInput) {
+ if ((_input.mouseLeftClicked() && _input.mousePos()._x < 3 && _input.mousePos()._y < 3)) {
+ CORO_INVOKE_1(openOptionScreen, 0);
+ goto SKIPCLICKSINISTRO;
+ } else if (_input.getAsyncKeyState(Common::KEYCODE_ESCAPE))
+ CORO_INVOKE_1(openOptionScreen, 0);
+ else if (!g_vm->getIsDemo()) {
+ if (_input.getAsyncKeyState(Common::KEYCODE_F3) || _input.getAsyncKeyState(Common::KEYCODE_F5))
+ // Save game screen
+ CORO_INVOKE_1(openOptionScreen, 4);
+ else if (_input.getAsyncKeyState(Common::KEYCODE_F2) || _input.getAsyncKeyState(Common::KEYCODE_F7))
+ // Load game screen
+ CORO_INVOKE_1(openOptionScreen, 3);
+ }
+ }
+ }
+
+ // Left Click
+ // **************
+ if (_input.mouseLeftClicked() && !_inter.active()) {
+
+ if (_curAction != TA_COMBINE)
+ CORO_INVOKE_3(_tony.moveAndDoAction, _itemName.getHotspot(), _itemName.getSelectedItem(), _point.curAction());
+ else if (_itemName.getSelectedItem() != NULL)
+ CORO_INVOKE_4(_tony.moveAndDoAction, _itemName.getHotspot(), _itemName.getSelectedItem(), TA_COMBINE, _curActionObj);
+
+ if (_curAction == TA_COMBINE) {
+ _inv.endCombine();
+ _point.setSpecialPointer(RMPointer::PTR_NONE);
+ }
+
+ _curAction = TA_GOTO;
+ _point.setAction(_curAction);
+ }
+
+SKIPCLICKSINISTRO:
+ // Right Click
+ // ************
+ if (_curAction == TA_COMBINE) {
+ // During a combine, it cancels it
+ if (_input.mouseRightClicked()) {
+ _inv.endCombine();
+ _curActionObj = 0;
+ _curAction = TA_GOTO;
+ _point.setAction(_curAction);
+ _point.setSpecialPointer(RMPointer::PTR_NONE);
+ }
+ } else if (_input.mouseRightClicked() && _itemName.isItemSelected() && _point.getSpecialPointer() == RMPointer::PTR_NONE) {
+ if (_bGUIInterface) {
+ // Before opening the interface, replaces GOTO
+ _curAction = TA_GOTO;
+ _curActionObj = 0;
+ _point.setAction(_curAction);
+ _inter.clicked(_input.mousePos());
+ }
+ }
+
+
+ // Right Release
+ // *************
+ if (_input.mouseRightReleased()) {
+ if (_bGUIInterface) {
+ if (_inter.released(_input.mousePos(), _curAction)) {
+ _point.setAction(_curAction);
+ CORO_INVOKE_3(_tony.moveAndDoAction, _itemName.getHotspot(), _itemName.getSelectedItem(), _curAction);
+
+ _curAction = TA_GOTO;
+ _point.setAction(_curAction);
+ }
+ }
+ }
+ }
+
+ // Update the name under the mouse pointer
+ _itemName.setMouseCoord(_input.mousePos());
+ if (!_inter.active() && !_inv.miniActive())
+ CORO_INVOKE_4(_itemName.doFrame, _bigBuf, _loc, _point, _inv);
+ }
+
+ // Interface & Inventory
+ _inter.doFrame(_bigBuf, _input.mousePos());
+ _inv.doFrame(_bigBuf, _point, _input.mousePos(), (!_tony.inAction() && !_inter.active() && _bGUIInventory));
+ }
+
+ // Animate Tony
+ CORO_INVOKE_2(_tony.doFrame, &_bigBuf, _nCurLoc);
+
+ // Update screen scrolling to keep Tony in focus
+ if (_tony.mustUpdateScrolling() && _bLocationLoaded) {
+ RMPoint showThis = _tony.position();
+ showThis._y -= 60;
+ _loc.updateScrolling(showThis);
+ }
+
+ if (_bLocationLoaded)
+ _tony.setScrollPosition(_loc.scrollPosition());
+
+ if ((!_tony.inAction() && _bInput) || _bAlwaysDrawMouse) {
+ _point.showCursor();
+ } else {
+ _point.hideCursor();
+ }
+ _point.doFrame();
+
+ // **********************
+ // Draw the list in the OT
+ // **********************
+ CORO_INVOKE_0(_bigBuf.drawOT);
+
+#define FSTEP (480/32)
+
+ // Wipe
+ if (_bWiping) {
+ switch (_nWipeType) {
+ case 1:
+ if (!(_rcWipeEllipse.bottom - _rcWipeEllipse.top >= FSTEP * 2)) {
+ CoroScheduler.setEvent(_hWipeEvent);
+ _nWipeType = 3;
+ break;
+ }
+
+ _rcWipeEllipse.top += FSTEP;
+ _rcWipeEllipse.left += FSTEP;
+ _rcWipeEllipse.right -= FSTEP;
+ _rcWipeEllipse.bottom -= FSTEP;
+ break;
+
+ case 2:
+ if (!(_rcWipeEllipse.bottom - _rcWipeEllipse.top < 480 - FSTEP)) {
+ CoroScheduler.setEvent(_hWipeEvent);
+ _nWipeType = 3;
+ break;
+ }
+
+ _rcWipeEllipse.top -= FSTEP;
+ _rcWipeEllipse.left -= FSTEP;
+ _rcWipeEllipse.right += FSTEP;
+ _rcWipeEllipse.bottom += FSTEP;
+ break;
+ }
+ }
+
+ CORO_END_CODE;
+}
+
+void RMGfxEngine::initCustomDll() {
+ setupGlobalVars(&_tony, &_point, &g_vm->_theBoxes, &_loc, &_inv, &_input);
+}
+
+void RMGfxEngine::itemIrq(uint32 dwItem, int nPattern, int nStatus) {
+ RMItem *item;
+ assert(GLOBALS._gfxEngine);
+
+ if (GLOBALS._gfxEngine->_bLocationLoaded) {
+ item = GLOBALS._gfxEngine->_loc.getItemFromCode(dwItem);
+ if (item != NULL) {
+ if (nPattern != -1) {
+ item->setPattern(nPattern, true);
+ }
+ if (nStatus != -1)
+ item->setStatus(nStatus);
+ }
+ }
+}
+
+void RMGfxEngine::initForNewLocation(int nLoc, RMPoint ptTonyStart, RMPoint start) {
+ if (start._x == -1 || start._y == -1) {
+ start._x = ptTonyStart._x - RM_SX / 2;
+ start._y = ptTonyStart._y - RM_SY / 2;
+ }
+
+ _loc.setScrollPosition(start);
+
+ if (ptTonyStart._x == 0 && ptTonyStart._y == 0) {
+ } else {
+ _tony.setPosition(ptTonyStart, nLoc);
+ _tony.setScrollPosition(start);
+ }
+
+ _curAction = TA_GOTO;
+ _point.setCustomPointer(NULL);
+ _point.setSpecialPointer(RMPointer::PTR_NONE);
+ _point.setAction(_curAction);
+ _inter.reset();
+ _inv.reset();
+
+ mpalStartIdlePoll(_nCurLoc);
+}
+
+uint32 RMGfxEngine::loadLocation(int nLoc, RMPoint ptTonyStart, RMPoint start) {
+ bool bLoaded;
+ int i;
+
+ _nCurLoc = nLoc;
+
+ bLoaded = false;
+ for (i = 0; i < 5; i++) {
+ // Try the loading of the location
+ RMRes res(_nCurLoc);
+ if (!res.isValid())
+ continue;
+
+ Common::SeekableReadStream *ds = res.getReadStream();
+ _loc.load(*ds);
+ delete ds;
+
+ initForNewLocation(nLoc, ptTonyStart, start);
+ bLoaded = true;
+ break;
+ }
+
+ if (!bLoaded)
+ error("Location was not loaded");
+
+ if (_bOption)
+ _opt.reInit(_bigBuf);
+
+ _bLocationLoaded = true;
+
+ // On entering the location
+ return CORO_INVALID_PID_VALUE; //mpalQueryDoAction(0, m_nCurLoc, 0);
+}
+
+void RMGfxEngine::unloadLocation(CORO_PARAM, bool bDoOnExit, uint32 *result) {
+ CORO_BEGIN_CONTEXT;
+ uint32 h;
+ CORO_END_CONTEXT(_ctx);
+
+ CORO_BEGIN_CODE(_ctx);
+
+ // Release the location
+ CORO_INVOKE_2(mpalEndIdlePoll, _nCurLoc, NULL);
+
+ // On Exit?
+ if (bDoOnExit) {
+ _ctx->h = mpalQueryDoAction(1, _nCurLoc, 0);
+ if (_ctx->h != CORO_INVALID_PID_VALUE)
+ CORO_INVOKE_2(CoroScheduler.waitForSingleObject, _ctx->h, CORO_INFINITE);
+ }
+
+ _bLocationLoaded = false;
+
+ _bigBuf.clearOT();
+ _loc.unload();
+
+ if (result != NULL)
+ *result = CORO_INVALID_PID_VALUE;
+
+ CORO_END_CODE;
+}
+
+void RMGfxEngine::init() {
+ // Screen loading
+ RMResRaw *raw;
+ RMGfxSourceBuffer16 *load = NULL;
+ INIT_GFX16_FROMRAW(20038, load);
+ _bigBuf.addPrim(new RMGfxPrimitive(load));
+ _bigBuf.drawOT(Common::nullContext);
+ _bigBuf.clearOT();
+ delete load;
+
+ // Display 'Loading' screen
+ _bigBuf.addDirtyRect(Common::Rect(0, 0, RM_SX, RM_SY));
+ g_vm->_window.getNewFrame(*this, NULL);
+ g_vm->_window.repaint();
+
+ // Activate GUI
+ _bGUIOption = true;
+ _bGUIInterface = true;
+ _bGUIInventory = true;
+
+ GLOBALS._bSkipSfxNoLoop = false;
+ _bMustEnterMenu = false;
+ GLOBALS._bIdleExited = false;
+ _bOption = false;
+ _bWiping = false;
+ _hWipeEvent = CoroScheduler.createEvent(false, false);
+
+ // Initialize the IRQ function for items for MPAL
+ GLOBALS._gfxEngine = this;
+ mpalInstallItemIrq(itemIrq);
+
+ // Initialize the mouse pointer
+ _point.init();
+
+ // Initialize Tony
+ _tony.init();
+ _tony.linkToBoxes(&g_vm->_theBoxes);
+
+ // Initialize the inventory and the interface
+ _inv.init();
+ _inter.init();
+
+ // Download the location and set priorities @@@@@
+ _bLocationLoaded = false;
+
+ enableInput();
+
+ // Starting the game
+ _tony.executeAction(20, 1, 0);
+}
+
+void RMGfxEngine::close() {
+ _bigBuf.clearOT();
+
+ _inter.close();
+ _inv.close();
+ _tony.close();
+ _point.close();
+}
+
+void RMGfxEngine::enableInput() {
+ _bInput = true;
+}
+
+void RMGfxEngine::disableInput() {
+ _bInput = false;
+ _inter.reset();
+}
+
+void RMGfxEngine::enableMouse() {
+ _bAlwaysDrawMouse = true;
+}
+
+void RMGfxEngine::disableMouse() {
+ _bAlwaysDrawMouse = false;
+}
+
+void CharsSaveAll(Common::OutSaveFile *f);
+void CharsLoadAll(Common::InSaveFile *f);
+void MCharResetCodes();
+void SaveChangedHotspot(Common::OutSaveFile *f);
+void LoadChangedHotspot(Common::InSaveFile *f);
+void ReapplyChangedHotspot();
+
+void RestoreMusic(CORO_PARAM);
+void SaveMusic(Common::OutSaveFile *f);
+void LoadMusic(Common::InSaveFile *f);
+
+#define TONY_SAVEGAME_VERSION 8
+
+void RMGfxEngine::saveState(const Common::String &fn, byte *curThumb, const Common::String &name) {
+ Common::OutSaveFile *f;
+ byte *state;
+ uint thumbsize;
+ uint size;
+ int i;
+ char buf[4];
+ RMPoint tp = _tony.position();
+
+ // Saving: MPAL variables, current location, and Tony inventory position
+
+ // For now, we only save the MPAL state
+ size = mpalGetSaveStateSize();
+ state = new byte[size];
+ mpalSaveState(state);
+
+ thumbsize = 160 * 120 * 2;
+
+ buf[0] = 'R';
+ buf[1] = 'M';
+ buf[2] = 'S';
+ buf[3] = TONY_SAVEGAME_VERSION;
+
+ f = g_system->getSavefileManager()->openForSaving(fn);
+ if (f == NULL)
+ return;
+
+ f->write(buf, 4);
+ f->writeUint32LE(thumbsize);
+ f->write(curThumb, thumbsize);
+
+ // Difficulty level
+ i = mpalQueryGlobalVar("VERSIONEFACILE");
+ f->writeByte(i);
+
+ i = strlen(name.c_str());
+ f->writeByte(i);
+ f->write(name.c_str(), i);
+ f->writeUint32LE(_nCurLoc);
+ f->writeUint32LE(tp._x);
+ f->writeUint32LE(tp._y);
+
+ f->writeUint32LE(size);
+ f->write(state, size);
+ delete[] state;
+
+ // Inventory
+ size = _inv.getSaveStateSize();
+ state = new byte[size];
+ _inv.saveState(state);
+ f->writeUint32LE(size);
+ f->write(state, size);
+ delete[] state;
+
+ // boxes
+ size = g_vm->_theBoxes.getSaveStateSize();
+ state = new byte[size];
+ g_vm->_theBoxes.saveState(state);
+ f->writeUint32LE(size);
+ f->write(state, size);
+ delete[] state;
+
+ // New Ver5
+ bool bStat;
+
+ // Saves the state of the shepherdess and show yourself
+ bStat = _tony.getShepherdess();
+ f->writeByte(bStat);
+ bStat = _inter.getPerorate();
+ f->writeByte(bStat);
+
+ // Save the chars
+ CharsSaveAll(f);
+
+ // Save the options
+ f->writeByte(GLOBALS._bCfgInvLocked);
+ f->writeByte(GLOBALS._bCfgInvNoScroll);
+ f->writeByte(GLOBALS._bCfgTimerizedText);
+ f->writeByte(GLOBALS._bCfgInvUp);
+ f->writeByte(GLOBALS._bCfgAnni30);
+ f->writeByte(GLOBALS._bCfgAntiAlias);
+ f->writeByte(GLOBALS._bShowSubtitles);
+ f->writeByte(GLOBALS._bCfgTransparence);
+ f->writeByte(GLOBALS._bCfgInterTips);
+ f->writeByte(GLOBALS._bCfgDubbing);
+ f->writeByte(GLOBALS._bCfgMusic);
+ f->writeByte(GLOBALS._bCfgSFX);
+ f->writeByte(GLOBALS._nCfgTonySpeed);
+ f->writeByte(GLOBALS._nCfgTextSpeed);
+ f->writeByte(GLOBALS._nCfgDubbingVolume);
+ f->writeByte(GLOBALS._nCfgMusicVolume);
+ f->writeByte(GLOBALS._nCfgSFXVolume);
+
+ // Save the hotspots
+ SaveChangedHotspot(f);
+
+ // Save the music
+ SaveMusic(f);
+
+ f->finalize();
+ delete f;
+}
+
+void RMGfxEngine::loadState(CORO_PARAM, const Common::String &fn) {
+ // PROBLEM: You should change the location in a separate process to do the OnEnter
+ CORO_BEGIN_CONTEXT;
+ Common::InSaveFile *f;
+ byte *state, *statecmp;
+ uint size, sizecmp;
+ char buf[4];
+ RMPoint tp;
+ int loc;
+ int ver;
+ int i;
+ CORO_END_CONTEXT(_ctx);
+
+ CORO_BEGIN_CODE(_ctx);
+
+ _ctx->f = g_system->getSavefileManager()->openForLoading(fn);
+ if (_ctx->f == NULL)
+ return;
+ _ctx->f->read(_ctx->buf, 4);
+
+ if (_ctx->buf[0] != 'R' || _ctx->buf[1] != 'M' || _ctx->buf[2] != 'S') {
+ delete _ctx->f;
+ return;
+ }
+
+ _ctx->ver = _ctx->buf[3];
+
+ if (_ctx->ver == 0 || _ctx->ver > TONY_SAVEGAME_VERSION) {
+ delete _ctx->f;
+ return;
+ }
+
+ if (_ctx->ver >= 0x3) {
+ // There is a thumbnail. If the version is between 5 and 7, it's compressed
+ if ((_ctx->ver >= 0x5) && (_ctx->ver <= 0x7)) {
+ _ctx->i = 0;
+ _ctx->i = _ctx->f->readUint32LE();
+ _ctx->f->seek(_ctx->i);
+ } else {
+ if (_ctx->ver >= 8)
+ // Skip thumbnail size
+ _ctx->f->skip(4);
+
+ _ctx->f->seek(160 * 120 * 2, SEEK_CUR);
+ }
+ }
+
+ if (_ctx->ver >= 0x5) {
+ // Skip the difficulty level
+ _ctx->f->seek(1, SEEK_CUR);
+ }
+
+ if (_ctx->ver >= 0x4) { // Skip the savegame name, which serves no purpose
+ _ctx->i = _ctx->f->readByte();
+ _ctx->f->seek(_ctx->i, SEEK_CUR);
+ }
+
+ _ctx->loc = _ctx->f->readUint32LE();
+ _ctx->tp._x = _ctx->f->readUint32LE();
+ _ctx->tp._y = _ctx->f->readUint32LE();
+ _ctx->size = _ctx->f->readUint32LE();
+
+ if ((_ctx->ver >= 0x5) && (_ctx->ver <= 7)) {
+ // MPAL was packed!
+ _ctx->sizecmp = _ctx->f->readUint32LE();
+ _ctx->state = new byte[_ctx->size];
+ _ctx->statecmp = new byte[_ctx->sizecmp];
+ _ctx->f->read(_ctx->statecmp, _ctx->sizecmp);
+ lzo1x_decompress(_ctx->statecmp, _ctx->sizecmp, _ctx->state, &_ctx->size);
+ delete[] _ctx->statecmp;
+ } else {
+ // Read uncompressed MPAL data
+ _ctx->state = new byte[_ctx->size];
+ _ctx->f->read(_ctx->state, _ctx->size);
+ }
+
+ mpalLoadState(_ctx->state);
+ delete[] _ctx->state;
+
+ // Inventory
+ _ctx->size = _ctx->f->readUint32LE();
+ _ctx->state = new byte[_ctx->size];
+ _ctx->f->read(_ctx->state, _ctx->size);
+ _inv.loadState(_ctx->state);
+ delete[] _ctx->state;
+
+ if (_ctx->ver >= 0x2) { // Versione 2: box please
+ _ctx->size = _ctx->f->readUint32LE();
+ _ctx->state = new byte[_ctx->size];
+ _ctx->f->read(_ctx->state, _ctx->size);
+ g_vm->_theBoxes.loadState(_ctx->state);
+ delete[] _ctx->state;
+ }
+
+ if (_ctx->ver >= 5) {
+ // Versione 5
+ bool bStat = false;
+
+ bStat = _ctx->f->readByte();
+ _tony.setShepherdess(bStat);
+ bStat = _ctx->f->readByte();
+ _inter.setPerorate(bStat);
+
+ CharsLoadAll(_ctx->f);
+ }
+
+ if (_ctx->ver >= 6) {
+ // Load options
+ GLOBALS._bCfgInvLocked = _ctx->f->readByte();
+ GLOBALS._bCfgInvNoScroll = _ctx->f->readByte();
+ GLOBALS._bCfgTimerizedText = _ctx->f->readByte();
+ GLOBALS._bCfgInvUp = _ctx->f->readByte();
+ GLOBALS._bCfgAnni30 = _ctx->f->readByte();
+ GLOBALS._bCfgAntiAlias = _ctx->f->readByte();
+ GLOBALS._bShowSubtitles = _ctx->f->readByte();
+ GLOBALS._bCfgTransparence = _ctx->f->readByte();
+ GLOBALS._bCfgInterTips = _ctx->f->readByte();
+ GLOBALS._bCfgDubbing = _ctx->f->readByte();
+ GLOBALS._bCfgMusic = _ctx->f->readByte();
+ GLOBALS._bCfgSFX = _ctx->f->readByte();
+ GLOBALS._nCfgTonySpeed = _ctx->f->readByte();
+ GLOBALS._nCfgTextSpeed = _ctx->f->readByte();
+ GLOBALS._nCfgDubbingVolume = _ctx->f->readByte();
+ GLOBALS._nCfgMusicVolume = _ctx->f->readByte();
+ GLOBALS._nCfgSFXVolume = _ctx->f->readByte();
+
+ // Load hotspots
+ LoadChangedHotspot(_ctx->f);
+ }
+
+ if (_ctx->ver >= 7) {
+ LoadMusic(_ctx->f);
+ }
+
+ delete _ctx->f;
+
+ CORO_INVOKE_2(unloadLocation, false, NULL);
+ loadLocation(_ctx->loc, _ctx->tp, RMPoint(-1, -1));
+ _tony.setPattern(RMTony::PAT_STANDRIGHT);
+
+ // On older versions, need to an enter action
+ if (_ctx->ver < 5)
+ mpalQueryDoAction(0, _ctx->loc, 0);
+ else {
+ // In the new ones, we just reset the mcode
+ MCharResetCodes();
+ }
+
+ if (_ctx->ver >= 6)
+ ReapplyChangedHotspot();
+
+ CORO_INVOKE_0(RestoreMusic);
+
+ _bGUIInterface = true;
+ _bGUIInventory = true;
+ _bGUIOption = true;
+
+ CORO_END_CODE;
+}
+
+void RMGfxEngine::pauseSound(bool bPause) {
+ if (_bLocationLoaded)
+ _loc.pauseSound(bPause);
+}
+
+void RMGfxEngine::initWipe(int type) {
+ _bWiping = true;
+ _nWipeType = type;
+ _nWipeStep = 0;
+
+ if (_nWipeType == 1)
+ _rcWipeEllipse = Common::Rect(80, 0, 640 - 80, 480);
+ else if (_nWipeType == 2)
+ _rcWipeEllipse = Common::Rect(320 - FSTEP, 240 - FSTEP, 320 + FSTEP, 240 + FSTEP);
+}
+
+void RMGfxEngine::closeWipe() {
+ _bWiping = false;
+}
+
+void RMGfxEngine::waitWipeEnd(CORO_PARAM) {
+ CoroScheduler.waitForSingleObject(coroParam, _hWipeEvent, CORO_INFINITE);
+}
+
+bool RMGfxEngine::canLoadSave() {
+ return _bInput && !_tony.inAction() && !g_vm->getIsDemo();
+}
+
+RMGfxEngine::operator RMGfxTargetBuffer &() {
+ return _bigBuf;
+}
+
+RMInput &RMGfxEngine::getInput() {
+ return _input;
+}
+
+RMPointer &RMGfxEngine::getPointer() {
+ return _point;
+}
+
+/**
+ * Link to graphic task
+ */
+void RMGfxEngine::linkGraphicTask(RMGfxTask *task) {
+ _bigBuf.addPrim(new RMGfxPrimitive(task));
+}
+
+void RMGfxEngine::setPerorate(bool bpal) {
+ _inter.setPerorate(bpal);
+}
+
+} // End of namespace Tony