scummvm/engines/tony/gfxengine.cpp

844 lines
20 KiB
C++
Raw Normal View History

/* 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.
*
*/
2012-05-14 05:43:50 +00:00
/*
* This code is based on original Tony Tough source code
*
* Copyright (c) 1997-2003 Nayma Software
*/
2012-05-01 13:00:03 +00:00
#include "common/savefile.h"
#include "tony/mpal/lzo.h"
#include "tony/mpal/mpalutils.h"
#include "tony/custom.h"
2012-05-04 12:09:24 +00:00
#include "tony/gfxengine.h"
2012-05-01 13:00:03 +00:00
#include "tony/tony.h"
namespace Tony {
2012-05-01 13:00:03 +00:00
/****************************************************************************\
* RMGfxEngine Methods
2012-05-01 13:00:03 +00:00
\****************************************************************************/
2012-09-07 06:11:33 +00:00
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
2012-06-08 22:52:38 +00:00
GLOBALS._bSkipSfxNoLoop = true;
CORO_INVOKE_2(mpalEndIdlePoll, nCurLoc, NULL);
2012-06-08 22:52:38 +00:00
GLOBALS._bIdleExited = true;
GLOBALS._bSkipSfxNoLoop = false;
CORO_END_CODE;
}
2012-05-01 13:00:03 +00:00
RMGfxEngine::RMGfxEngine() {
// Create big buffer where the frame will be rendered
2012-06-05 06:39:55 +00:00
_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;
2012-05-01 13:00:03 +00:00
}
RMGfxEngine::~RMGfxEngine() {
// Close the buffer
2012-06-05 06:39:55 +00:00
_bigBuf.destroy();
2012-05-01 13:00:03 +00:00
}
void RMGfxEngine::openOptionScreen(CORO_PARAM, int type) {
CORO_BEGIN_CONTEXT;
2012-05-14 19:29:27 +00:00
bool bRes;
CORO_END_CONTEXT(_ctx);
2012-05-01 13:00:03 +00:00
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) {
2012-08-22 12:00:46 +00:00
g_vm->pauseSound(true);
2012-05-01 13:00:03 +00:00
disableInput();
_inv.endCombine();
_curActionObj = 0;
_curAction = TA_GOTO;
_point.setAction(_curAction);
_point.setSpecialPointer(RMPointer::PTR_NONE);
_point.setCustomPointer(NULL);
enableMouse();
2012-08-22 12:00:46 +00:00
g_vm->grabThumbnail();
2012-05-14 19:29:27 +00:00
// Exists the IDLE to avoid premature death in loading
_bMustEnterMenu = true;
2012-05-01 13:00:03 +00:00
if (type == 1 || type == 2) {
2012-06-08 22:52:38 +00:00
GLOBALS._bIdleExited = true;
2012-05-01 13:00:03 +00:00
} else {
CORO_INVOKE_0(_tony.stopNoAction);
2012-05-01 13:00:03 +00:00
2012-06-08 22:52:38 +00:00
GLOBALS._bIdleExited = false;
2012-09-07 06:11:33 +00:00
CoroScheduler.createProcess(exitAllIdles, &_nCurLoc, sizeof(int));
2012-05-01 13:00:03 +00:00
}
}
CORO_END_CODE;
2012-05-01 13:00:03 +00:00
}
void RMGfxEngine::doFrame(CORO_PARAM, bool bDrawLocation) {
CORO_BEGIN_CONTEXT;
CORO_END_CONTEXT(_ctx);
CORO_BEGIN_CODE(_ctx);
// Poll of input devices
_input.poll();
2012-05-01 13:00:03 +00:00
2012-06-08 22:52:38 +00:00
if (_bMustEnterMenu && GLOBALS._bIdleExited) {
_bOption = true;
_bMustEnterMenu = false;
2012-06-08 22:52:38 +00:00
GLOBALS._bIdleExited = false;
2012-05-01 13:00:03 +00:00
}
2012-05-14 19:29:27 +00:00
if (_bOption) {
CORO_INVOKE_1(_opt.doFrame, &_input);
_bOption = !_opt.isClosing();
if (!_bOption) {
disableMouse();
enableInput();
mpalStartIdlePoll(_nCurLoc);
2012-08-22 12:00:46 +00:00
g_vm->pauseSound(false);
2012-05-01 13:00:03 +00:00
}
}
if (bDrawLocation && _bLocationLoaded) {
// Location and objects
_loc.doFrame(&_bigBuf);
2012-05-01 13:00:03 +00:00
// 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);
2012-05-01 13:00:03 +00:00
}
2012-05-14 19:29:27 +00:00
} else
2012-05-01 13:00:03 +00:00
// Right Click
// ***********
if (_input.mouseRightClicked()) {
2012-06-06 06:04:33 +00:00
if (_itemName.isItemSelected()) {
_curActionObj = 0;
_inv.rightClick(_input.mousePos());
2012-05-14 19:29:27 +00:00
} else
_inv.rightClick(_input.mousePos());
2012-05-01 13:00:03 +00:00
} else
// Right Release
// *************
if (_input.mouseRightReleased()) {
if (_inv.rightRelease(_input.mousePos(), _curAction)) {
CORO_INVOKE_3(_tony.moveAndDoAction, _itemName.getHotspot(), _itemName.getSelectedItem(), _curAction);
2012-05-01 13:00:03 +00:00
_curAction = TA_GOTO;
_point.setAction(_curAction);
2012-05-14 19:29:27 +00:00
}
}
2012-05-01 13:00:03 +00:00
} else {
// Options Menu
2012-05-01 13:00:03 +00:00
// ************
if (_bGUIOption) {
if (!_tony.inAction() && _bInput) {
2012-06-11 18:24:25 +00:00
if ((_input.mouseLeftClicked() && _input.mousePos()._x < 3 && _input.mousePos()._y < 3)) {
CORO_INVOKE_1(openOptionScreen, 0);
2012-05-01 13:00:03 +00:00
goto SKIPCLICKSINISTRO;
} else if (_input.getAsyncKeyState(Common::KEYCODE_ESCAPE))
CORO_INVOKE_1(openOptionScreen, 0);
2012-08-22 12:00:46 +00:00
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);
2012-05-01 13:00:03 +00:00
}
}
}
// Left Click
2012-05-01 13:00:03 +00:00
// **************
if (_input.mouseLeftClicked() && !_inter.active()) {
if (_curAction != TA_COMBINE)
CORO_INVOKE_3(_tony.moveAndDoAction, _itemName.getHotspot(), _itemName.getSelectedItem(), _point.curAction());
2012-06-06 06:04:33 +00:00
else if (_itemName.getSelectedItem() != NULL)
CORO_INVOKE_4(_tony.moveAndDoAction, _itemName.getHotspot(), _itemName.getSelectedItem(), TA_COMBINE, _curActionObj);
2012-05-14 19:29:27 +00:00
if (_curAction == TA_COMBINE) {
_inv.endCombine();
_point.setSpecialPointer(RMPointer::PTR_NONE);
2012-05-01 13:00:03 +00:00
}
_curAction = TA_GOTO;
_point.setAction(_curAction);
2012-05-01 13:00:03 +00:00
}
SKIPCLICKSINISTRO:
// Right Click
2012-05-01 13:00:03 +00:00
// ************
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);
2012-05-01 13:00:03 +00:00
}
2012-06-06 06:04:33 +00:00
} 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());
2012-05-01 13:00:03 +00:00
}
}
2012-05-14 19:29:27 +00:00
2012-05-01 13:00:03 +00:00
// 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);
2012-05-01 13:00:03 +00:00
}
}
}
}
// Update the name under the mouse pointer
2012-06-06 06:04:33 +00:00
_itemName.setMouseCoord(_input.mousePos());
if (!_inter.active() && !_inv.miniActive())
2012-06-06 06:04:33 +00:00
CORO_INVOKE_4(_itemName.doFrame, _bigBuf, _loc, _point, _inv);
2012-05-01 13:00:03 +00:00
}
// Interface & Inventory
_inter.doFrame(_bigBuf, _input.mousePos());
_inv.doFrame(_bigBuf, _point, _input.mousePos(), (!_tony.inAction() && !_inter.active() && _bGUIInventory));
2012-05-01 13:00:03 +00:00
}
// Animate Tony
CORO_INVOKE_2(_tony.doFrame, &_bigBuf, _nCurLoc);
2012-05-14 19:29:27 +00:00
// Update screen scrolling to keep Tony in focus
if (_tony.mustUpdateScrolling() && _bLocationLoaded) {
RMPoint showThis = _tony.position();
2012-06-11 18:24:25 +00:00
showThis._y -= 60;
_loc.updateScrolling(showThis);
2012-05-01 13:00:03 +00:00
}
if (_bLocationLoaded)
_tony.setScrollPosition(_loc.scrollPosition());
2012-05-01 13:00:03 +00:00
if ((!_tony.inAction() && _bInput) || _bAlwaysDrawMouse) {
_point.showCursor();
} else {
_point.hideCursor();
2012-05-01 13:00:03 +00:00
}
_point.doFrame();
2012-05-01 13:00:03 +00:00
// **********************
// Draw the list in the OT
2012-05-01 13:00:03 +00:00
// **********************
2012-06-05 06:39:55 +00:00
CORO_INVOKE_0(_bigBuf.drawOT);
2012-05-01 13:00:03 +00:00
#define FSTEP (480/32)
// Wipe
if (_bWiping) {
switch (_nWipeType) {
2012-05-14 19:29:27 +00:00
case 1:
if (!(_rcWipeEllipse.bottom - _rcWipeEllipse.top >= FSTEP * 2)) {
CoroScheduler.setEvent(_hWipeEvent);
_nWipeType = 3;
2012-05-01 13:00:03 +00:00
break;
2012-05-14 19:29:27 +00:00
}
2012-05-01 13:00:03 +00:00
_rcWipeEllipse.top += FSTEP;
_rcWipeEllipse.left += FSTEP;
_rcWipeEllipse.right -= FSTEP;
_rcWipeEllipse.bottom -= FSTEP;
2012-05-14 19:29:27 +00:00
break;
2012-05-01 13:00:03 +00:00
2012-05-14 19:29:27 +00:00
case 2:
if (!(_rcWipeEllipse.bottom - _rcWipeEllipse.top < 480 - FSTEP)) {
CoroScheduler.setEvent(_hWipeEvent);
_nWipeType = 3;
2012-05-01 13:00:03 +00:00
break;
2012-05-14 19:29:27 +00:00
}
_rcWipeEllipse.top -= FSTEP;
_rcWipeEllipse.left -= FSTEP;
_rcWipeEllipse.right += FSTEP;
_rcWipeEllipse.bottom += FSTEP;
2012-05-14 19:29:27 +00:00
break;
2012-05-01 13:00:03 +00:00
}
}
CORO_END_CODE;
2012-05-01 13:00:03 +00:00
}
void RMGfxEngine::initCustomDll() {
2012-08-22 12:00:46 +00:00
setupGlobalVars(&_tony, &_point, &g_vm->_theBoxes, &_loc, &_inv, &_input);
2012-05-01 13:00:03 +00:00
}
void RMGfxEngine::itemIrq(uint32 dwItem, int nPattern, int nStatus) {
2012-05-01 13:00:03 +00:00
RMItem *item;
2012-06-10 20:02:31 +00:00
assert(GLOBALS._gfxEngine);
2012-05-01 13:00:03 +00:00
2012-06-10 20:02:31 +00:00
if (GLOBALS._gfxEngine->_bLocationLoaded) {
item = GLOBALS._gfxEngine->_loc.getItemFromCode(dwItem);
2012-05-01 13:00:03 +00:00
if (item != NULL) {
if (nPattern != -1) {
item->setPattern(nPattern, true);
2012-05-01 13:00:03 +00:00
}
if (nStatus != -1)
item->setStatus(nStatus);
2012-05-01 13:00:03 +00:00
}
}
}
void RMGfxEngine::initForNewLocation(int nLoc, RMPoint ptTonyStart, RMPoint start) {
2012-06-11 18:24:25 +00:00
if (start._x == -1 || start._y == -1) {
start._x = ptTonyStart._x - RM_SX / 2;
start._y = ptTonyStart._y - RM_SY / 2;
2012-05-01 13:00:03 +00:00
}
_loc.setScrollPosition(start);
2012-05-14 19:29:27 +00:00
2012-06-11 18:24:25 +00:00
if (ptTonyStart._x == 0 && ptTonyStart._y == 0) {
2012-05-01 13:00:03 +00:00
} else {
_tony.setPosition(ptTonyStart, nLoc);
_tony.setScrollPosition(start);
2012-05-01 13:00:03 +00:00
}
_curAction = TA_GOTO;
_point.setCustomPointer(NULL);
_point.setSpecialPointer(RMPointer::PTR_NONE);
_point.setAction(_curAction);
_inter.reset();
2012-06-06 06:04:33 +00:00
_inv.reset();
2012-05-01 13:00:03 +00:00
mpalStartIdlePoll(_nCurLoc);
2012-05-01 13:00:03 +00:00
}
uint32 RMGfxEngine::loadLocation(int nLoc, RMPoint ptTonyStart, RMPoint start) {
_nCurLoc = nLoc;
2012-05-01 13:00:03 +00:00
bool bLoaded = false;
for (int i = 0; i < 5; i++) {
// Try the loading of the location
RMRes res(_nCurLoc);
if (!res.isValid())
2012-05-01 13:00:03 +00:00
continue;
2012-08-28 12:26:00 +00:00
Common::SeekableReadStream *ds = res.getReadStream();
_loc.load(*ds);
delete ds;
initForNewLocation(nLoc, ptTonyStart, start);
2012-05-01 13:00:03 +00:00
bLoaded = true;
break;
}
2012-05-14 19:29:27 +00:00
2012-05-01 13:00:03 +00:00
if (!bLoaded)
error("Location was not loaded");
2012-05-01 13:00:03 +00:00
if (_bOption)
_opt.reInit(_bigBuf);
2012-05-01 13:00:03 +00:00
_bLocationLoaded = true;
2012-05-01 13:00:03 +00:00
// On entering the location
2012-08-31 22:25:35 +00:00
return CORO_INVALID_PID_VALUE; //mpalQueryDoAction(0, m_nCurLoc, 0);
2012-05-01 13:00:03 +00:00
}
void RMGfxEngine::unloadLocation(CORO_PARAM, bool bDoOnExit, uint32 *result) {
CORO_BEGIN_CONTEXT;
2012-05-14 19:29:27 +00:00
uint32 h;
CORO_END_CONTEXT(_ctx);
CORO_BEGIN_CODE(_ctx);
2012-05-14 19:29:27 +00:00
// Release the location
CORO_INVOKE_2(mpalEndIdlePoll, _nCurLoc, NULL);
2012-05-01 13:00:03 +00:00
// On Exit?
2012-05-03 13:08:19 +00:00
if (bDoOnExit) {
_ctx->h = mpalQueryDoAction(1, _nCurLoc, 0);
if (_ctx->h != CORO_INVALID_PID_VALUE)
CORO_INVOKE_2(CoroScheduler.waitForSingleObject, _ctx->h, CORO_INFINITE);
2012-05-01 13:00:03 +00:00
}
_bLocationLoaded = false;
2012-05-14 19:29:27 +00:00
2012-06-05 06:39:55 +00:00
_bigBuf.clearOT();
_loc.unload();
2012-05-01 13:00:03 +00:00
if (result != NULL)
*result = CORO_INVALID_PID_VALUE;
CORO_END_CODE;
2012-05-01 13:00:03 +00:00
}
void RMGfxEngine::init() {
// Screen loading
2012-05-14 19:29:27 +00:00
RMResRaw *raw;
2012-05-01 13:00:03 +00:00
RMGfxSourceBuffer16 *load = NULL;
INIT_GFX16_FROMRAW(20038, load);
2012-06-05 06:39:55 +00:00
_bigBuf.addPrim(new RMGfxPrimitive(load));
_bigBuf.drawOT(Common::nullContext);
_bigBuf.clearOT();
2012-05-01 13:00:03 +00:00
delete load;
// Display 'Loading' screen
_bigBuf.addDirtyRect(Common::Rect(0, 0, RM_SX, RM_SY));
2012-08-22 12:00:46 +00:00
g_vm->_window.getNewFrame(*this, NULL);
g_vm->_window.repaint();
2012-05-01 13:00:03 +00:00
// Activate GUI
_bGUIOption = true;
_bGUIInterface = true;
_bGUIInventory = true;
2012-05-01 13:00:03 +00:00
2012-06-08 22:52:38 +00:00
GLOBALS._bSkipSfxNoLoop = false;
_bMustEnterMenu = false;
2012-06-08 22:52:38 +00:00
GLOBALS._bIdleExited = false;
_bOption = false;
_bWiping = false;
_hWipeEvent = CoroScheduler.createEvent(false, false);
2012-05-01 13:00:03 +00:00
// Initialize the IRQ function for items for MPAL
2012-06-10 20:02:31 +00:00
GLOBALS._gfxEngine = this;
mpalInstallItemIrq(itemIrq);
2012-05-14 19:29:27 +00:00
// Initialize the mouse pointer
_point.init();
2012-05-01 13:00:03 +00:00
// Initialize Tony
2012-06-05 06:39:55 +00:00
_tony.init();
2012-08-22 12:00:46 +00:00
_tony.linkToBoxes(&g_vm->_theBoxes);
2012-05-01 13:00:03 +00:00
// Initialize the inventory and the interface
2012-06-06 06:04:33 +00:00
_inv.init();
_inter.init();
2012-05-01 13:00:03 +00:00
// Download the location and set priorities @@@@@
_bLocationLoaded = false;
enableInput();
2012-05-01 13:00:03 +00:00
// Starting the game
_tony.executeAction(20, 1, 0);
2012-05-01 13:00:03 +00:00
}
void RMGfxEngine::close() {
2012-06-05 06:39:55 +00:00
_bigBuf.clearOT();
2012-05-01 13:00:03 +00:00
_inter.close();
2012-06-06 06:04:33 +00:00
_inv.close();
_tony.close();
_point.close();
2012-05-01 13:00:03 +00:00
}
void RMGfxEngine::enableInput() {
_bInput = true;
2012-05-01 13:00:03 +00:00
}
void RMGfxEngine::disableInput() {
_bInput = false;
_inter.reset();
2012-05-01 13:00:03 +00:00
}
void RMGfxEngine::enableMouse() {
_bAlwaysDrawMouse = true;
2012-05-01 13:00:03 +00:00
}
void RMGfxEngine::disableMouse() {
_bAlwaysDrawMouse = false;
2012-05-01 13:00:03 +00:00
}
#define TONY_SAVEGAME_VERSION 8
2012-05-01 13:00:03 +00:00
void RMGfxEngine::saveState(const Common::String &fn, byte *curThumb, const Common::String &name) {
2012-05-01 13:00:03 +00:00
Common::OutSaveFile *f;
byte *state;
2012-05-01 13:00:03 +00:00
char buf[4];
RMPoint tp = _tony.position();
2012-05-01 13:00:03 +00:00
// Saving: MPAL variables, current location, and Tony inventory position
2012-05-01 13:00:03 +00:00
// For now, we only save the MPAL state
uint size = mpalGetSaveStateSize();
2012-05-01 13:00:03 +00:00
state = new byte[size];
mpalSaveState(state);
uint thumbsize = 160 * 120 * 2;
2012-05-14 19:29:27 +00:00
2012-05-01 13:00:03 +00:00
buf[0] = 'R';
buf[1] = 'M';
buf[2] = 'S';
buf[3] = TONY_SAVEGAME_VERSION;
2012-05-01 13:00:03 +00:00
f = g_system->getSavefileManager()->openForSaving(fn);
2012-05-14 19:29:27 +00:00
if (f == NULL)
return;
2012-05-01 13:00:03 +00:00
f->write(buf, 4);
f->writeUint32LE(thumbsize);
f->write(curThumb, thumbsize);
2012-05-01 13:00:03 +00:00
// Difficulty level
int i = mpalQueryGlobalVar("VERSIONEFACILE");
2012-05-01 13:00:03 +00:00
f->writeByte(i);
i = strlen(name.c_str());
2012-05-01 13:00:03 +00:00
f->writeByte(i);
f->write(name.c_str(), i);
f->writeUint32LE(_nCurLoc);
2012-06-11 18:24:25 +00:00
f->writeUint32LE(tp._x);
f->writeUint32LE(tp._y);
2012-05-01 13:00:03 +00:00
f->writeUint32LE(size);
f->write(state, size);
2012-05-01 13:00:03 +00:00
delete[] state;
// Inventory
size = _inv.getSaveStateSize();
2012-05-01 13:00:03 +00:00
state = new byte[size];
_inv.saveState(state);
2012-05-01 13:00:03 +00:00
f->writeUint32LE(size);
f->write(state, size);
delete[] state;
// boxes
2012-08-22 12:00:46 +00:00
size = g_vm->_theBoxes.getSaveStateSize();
2012-05-01 13:00:03 +00:00
state = new byte[size];
2012-08-22 12:00:46 +00:00
g_vm->_theBoxes.saveState(state);
2012-05-01 13:00:03 +00:00
f->writeUint32LE(size);
f->write(state, size);
delete[] state;
// New Ver5
// Saves the state of the shepherdess and show yourself
bool bStat = _tony.getShepherdess();
2012-05-01 13:00:03 +00:00
f->writeByte(bStat);
2012-06-11 22:07:50 +00:00
bStat = _inter.getPerorate();
2012-05-01 13:00:03 +00:00
f->writeByte(bStat);
2012-05-14 19:29:27 +00:00
// Save the chars
2012-09-07 06:11:33 +00:00
charsSaveAll(f);
2012-05-01 13:00:03 +00:00
// Save the options
2012-06-08 22:52:38 +00:00
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);
2012-06-08 22:52:38 +00:00
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);
2012-05-01 13:00:03 +00:00
// Save the hotspots
2012-09-07 06:11:33 +00:00
saveChangedHotspot(f);
2012-05-01 13:00:03 +00:00
// Save the music
2012-09-07 06:11:33 +00:00
saveMusic(f);
2012-05-01 13:00:03 +00:00
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;
2012-05-14 19:29:27 +00:00
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);
2012-05-01 13:00:03 +00:00
_ctx->f = g_system->getSavefileManager()->openForLoading(fn);
2012-05-14 19:29:27 +00:00
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;
2012-05-01 13:00:03 +00:00
return;
}
2012-05-14 19:29:27 +00:00
_ctx->ver = _ctx->buf[3];
2012-05-14 19:29:27 +00:00
if (_ctx->ver == 0 || _ctx->ver > TONY_SAVEGAME_VERSION) {
delete _ctx->f;
2012-05-01 13:00:03 +00:00
return;
}
2012-05-14 19:29:27 +00:00
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);
}
2012-05-01 13:00:03 +00:00
}
if (_ctx->ver >= 0x5) {
// Skip the difficulty level
_ctx->f->seek(1, SEEK_CUR);
2012-05-01 13:00:03 +00:00
}
2012-05-14 19:29:27 +00:00
if (_ctx->ver >= 0x4) { // Skip the savegame name, which serves no purpose
_ctx->i = _ctx->f->readByte();
_ctx->f->seek(_ctx->i, SEEK_CUR);
2012-05-01 13:00:03 +00:00
}
_ctx->loc = _ctx->f->readUint32LE();
2012-06-11 18:24:25 +00:00
_ctx->tp._x = _ctx->f->readUint32LE();
_ctx->tp._y = _ctx->f->readUint32LE();
_ctx->size = _ctx->f->readUint32LE();
2012-05-01 13:00:03 +00:00
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);
2012-05-14 19:29:27 +00:00
lzo1x_decompress(_ctx->statecmp, _ctx->sizecmp, _ctx->state, &_ctx->size);
delete[] _ctx->statecmp;
2012-05-01 13:00:03 +00:00
} else {
// Read uncompressed MPAL data
_ctx->state = new byte[_ctx->size];
_ctx->f->read(_ctx->state, _ctx->size);
2012-05-01 13:00:03 +00:00
}
mpalLoadState(_ctx->state);
delete[] _ctx->state;
2012-05-01 13:00:03 +00:00
// 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) { // Version 2: box please
_ctx->size = _ctx->f->readUint32LE();
_ctx->state = new byte[_ctx->size];
_ctx->f->read(_ctx->state, _ctx->size);
2012-08-22 12:00:46 +00:00
g_vm->_theBoxes.loadState(_ctx->state);
delete[] _ctx->state;
2012-05-01 13:00:03 +00:00
}
if (_ctx->ver >= 5) {
// Version 5
2012-05-01 13:00:03 +00:00
bool bStat = false;
2012-05-14 19:29:27 +00:00
bStat = _ctx->f->readByte();
2012-06-13 06:00:37 +00:00
_tony.setShepherdess(bStat);
bStat = _ctx->f->readByte();
2012-06-11 22:07:50 +00:00
_inter.setPerorate(bStat);
2012-05-01 13:00:03 +00:00
2012-09-07 06:11:33 +00:00
charsLoadAll(_ctx->f);
2012-05-01 13:00:03 +00:00
}
if (_ctx->ver >= 6) {
// Load options
2012-06-08 22:52:38 +00:00
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();
2012-06-08 22:52:38 +00:00
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();
2012-05-01 13:00:03 +00:00
// Load hotspots
2012-09-07 06:11:33 +00:00
loadChangedHotspot(_ctx->f);
2012-05-01 13:00:03 +00:00
}
if (_ctx->ver >= 7) {
2012-09-07 06:11:33 +00:00
loadMusic(_ctx->f);
2012-05-01 13:00:03 +00:00
}
delete _ctx->f;
2012-05-01 13:00:03 +00:00
CORO_INVOKE_2(unloadLocation, false, NULL);
loadLocation(_ctx->loc, _ctx->tp, RMPoint(-1, -1));
_tony.setPattern(RMTony::PAT_STANDRIGHT);
2012-05-14 19:29:27 +00:00
// On older versions, need to an enter action
if (_ctx->ver < 5)
mpalQueryDoAction(0, _ctx->loc, 0);
2012-05-01 13:00:03 +00:00
else {
// In the new ones, we just reset the mcode
2012-09-07 06:11:33 +00:00
mCharResetCodes();
2012-05-01 13:00:03 +00:00
}
if (_ctx->ver >= 6)
2012-09-07 06:11:33 +00:00
reapplyChangedHotspot();
2012-05-01 13:00:03 +00:00
2012-09-07 06:11:33 +00:00
CORO_INVOKE_0(restoreMusic);
2012-05-01 13:00:03 +00:00
_bGUIInterface = true;
_bGUIInventory = true;
_bGUIOption = true;
CORO_END_CODE;
2012-05-01 13:00:03 +00:00
}
void RMGfxEngine::pauseSound(bool bPause) {
if (_bLocationLoaded)
_loc.pauseSound(bPause);
2012-05-01 13:00:03 +00:00
}
void RMGfxEngine::initWipe(int type) {
_bWiping = true;
_nWipeType = type;
_nWipeStep = 0;
2012-05-01 13:00:03 +00:00
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);
2012-05-01 13:00:03 +00:00
}
void RMGfxEngine::closeWipe() {
_bWiping = false;
2012-05-01 13:00:03 +00:00
}
void RMGfxEngine::waitWipeEnd(CORO_PARAM) {
CoroScheduler.waitForSingleObject(coroParam, _hWipeEvent, CORO_INFINITE);
2012-05-01 13:00:03 +00:00
}
bool RMGfxEngine::canLoadSave() {
2012-08-22 12:00:46 +00:00
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