scummvm/engines/zvision/scripting/script_manager.cpp
Filippos Karapetis 21e9007d80 Revert "ZVISION: Remove ActionRestoreGame and loading of r.svr (restart slot)"
This reverts commit 9f642074ba8e17aa23b01bcee82b2293fe84f8f1, as it
broke the credits screen in ZGI.

This has been rewritten to use the common save code
2015-01-10 22:03:15 +02:00

845 lines
25 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.
*
*/
#include "common/scummsys.h"
#include "zvision/scripting/script_manager.h"
#include "zvision/zvision.h"
#include "zvision/graphics/render_manager.h"
#include "zvision/graphics/cursors/cursor_manager.h"
#include "zvision/file/save_manager.h"
#include "zvision/scripting/actions.h"
#include "zvision/scripting/menu.h"
#include "zvision/scripting/effects/timer_effect.h"
#include "common/algorithm.h"
#include "common/hashmap.h"
#include "common/debug.h"
#include "common/stream.h"
#include "common/config-manager.h"
namespace ZVision {
ScriptManager::ScriptManager(ZVision *engine)
: _engine(engine),
_currentlyFocusedControl(0),
_activeControls(NULL) {
}
ScriptManager::~ScriptManager() {
cleanScriptScope(universe);
cleanScriptScope(world);
cleanScriptScope(room);
cleanScriptScope(nodeview);
_controlEvents.clear();
}
void ScriptManager::initialize() {
cleanScriptScope(universe);
cleanScriptScope(world);
cleanScriptScope(room);
cleanScriptScope(nodeview);
_currentLocation.node = 0;
_currentLocation.world = 0;
_currentLocation.room = 0;
_currentLocation.view = 0;
parseScrFile("universe.scr", universe);
changeLocation('g', 'a', 'r', 'y', 0);
_controlEvents.clear();
}
void ScriptManager::update(uint deltaTimeMillis) {
if (_currentLocation.node != _nextLocation.node ||
_currentLocation.room != _nextLocation.room ||
_currentLocation.view != _nextLocation.view ||
_currentLocation.world != _nextLocation.world)
ChangeLocationReal();
updateNodes(deltaTimeMillis);
if (! execScope(nodeview))
return;
if (! execScope(room))
return;
if (! execScope(world))
return;
if (! execScope(universe))
return;
updateControls(deltaTimeMillis);
}
bool ScriptManager::execScope(ScriptScope &scope) {
// Swap queues
PuzzleList *tmp = scope.execQueue;
scope.execQueue = scope.scopeQueue;
scope.scopeQueue = tmp;
scope.scopeQueue->clear();
for (PuzzleList::iterator PuzzleIter = scope.puzzles.begin(); PuzzleIter != scope.puzzles.end(); ++PuzzleIter)
(*PuzzleIter)->addedBySetState = false;
if (scope.procCount < 2 || getStateValue(StateKey_ExecScopeStyle)) {
for (PuzzleList::iterator PuzzleIter = scope.puzzles.begin(); PuzzleIter != scope.puzzles.end(); ++PuzzleIter)
if (!checkPuzzleCriteria(*PuzzleIter, scope.procCount))
return false;
} else {
for (PuzzleList::iterator PuzzleIter = scope.execQueue->begin(); PuzzleIter != scope.execQueue->end(); ++PuzzleIter)
if (!checkPuzzleCriteria(*PuzzleIter, scope.procCount))
return false;
}
if (scope.procCount < 2) {
scope.procCount++;
}
return true;
}
void ScriptManager::referenceTableAddPuzzle(uint32 key, PuzzleRef ref) {
if (_referenceTable.contains(key)) {
Common::Array<PuzzleRef> *arr = &_referenceTable[key];
for (uint32 i = 0; i < arr->size(); i++)
if ((*arr)[i].puz == ref.puz)
return;
}
_referenceTable[key].push_back(ref);
}
void ScriptManager::addPuzzlesToReferenceTable(ScriptScope &scope) {
// Iterate through each local Puzzle
for (PuzzleList::iterator PuzzleIter = scope.puzzles.begin(); PuzzleIter != scope.puzzles.end(); ++PuzzleIter) {
Puzzle *puzzlePtr = (*PuzzleIter);
PuzzleRef ref;
ref.scope = &scope;
ref.puz = puzzlePtr;
referenceTableAddPuzzle(puzzlePtr->key, ref);
// Iterate through each CriteriaEntry and add a reference from the criteria key to the Puzzle
for (Common::List<Common::List<Puzzle::CriteriaEntry> >::iterator criteriaIter = (*PuzzleIter)->criteriaList.begin(); criteriaIter != (*PuzzleIter)->criteriaList.end(); ++criteriaIter)
for (Common::List<Puzzle::CriteriaEntry>::iterator entryIter = criteriaIter->begin(); entryIter != criteriaIter->end(); ++entryIter)
referenceTableAddPuzzle(entryIter->key, ref);
}
}
void ScriptManager::updateNodes(uint deltaTimeMillis) {
// If process() returns true, it means the node can be deleted
for (SideFXList::iterator iter = _activeSideFx.begin(); iter != _activeSideFx.end();) {
if ((*iter)->process(deltaTimeMillis)) {
delete(*iter);
// Remove the node
iter = _activeSideFx.erase(iter);
} else {
++iter;
}
}
}
void ScriptManager::updateControls(uint deltaTimeMillis) {
if (!_activeControls)
return;
// Process only one event
if (!_controlEvents.empty()) {
Common::Event _event = _controlEvents.front();
Common::Point imageCoord;
switch (_event.type) {
case Common::EVENT_LBUTTONDOWN:
imageCoord = _engine->getRenderManager()->screenSpaceToImageSpace(_event.mouse);
onMouseDown(_event.mouse, imageCoord);
break;
case Common::EVENT_LBUTTONUP:
imageCoord = _engine->getRenderManager()->screenSpaceToImageSpace(_event.mouse);
onMouseUp(_event.mouse, imageCoord);
break;
case Common::EVENT_KEYDOWN:
onKeyDown(_event.kbd);
break;
case Common::EVENT_KEYUP:
onKeyUp(_event.kbd);
break;
default:
break;
}
_controlEvents.pop_front();
}
for (ControlList::iterator iter = _activeControls->begin(); iter != _activeControls->end(); iter++)
if ((*iter)->process(deltaTimeMillis))
break;
}
bool ScriptManager::checkPuzzleCriteria(Puzzle *puzzle, uint counter) {
// Check if the puzzle is already finished
// Also check that the puzzle isn't disabled
if (getStateValue(puzzle->key) == 1 || (getStateFlag(puzzle->key) & Puzzle::DISABLED) == Puzzle::DISABLED) {
return true;
}
// Check each Criteria
if (counter == 0 && (getStateFlag(puzzle->key) & Puzzle::DO_ME_NOW) == 0)
return true;
bool criteriaMet = false;
for (Common::List<Common::List<Puzzle::CriteriaEntry> >::iterator criteriaIter = puzzle->criteriaList.begin(); criteriaIter != puzzle->criteriaList.end(); ++criteriaIter) {
criteriaMet = false;
for (Common::List<Puzzle::CriteriaEntry>::iterator entryIter = criteriaIter->begin(); entryIter != criteriaIter->end(); ++entryIter) {
// Get the value to compare against
int argumentValue;
if (entryIter->argumentIsAKey)
argumentValue = getStateValue(entryIter->argument);
else
argumentValue = entryIter->argument;
// Do the comparison
switch (entryIter->criteriaOperator) {
case Puzzle::EQUAL_TO:
criteriaMet = getStateValue(entryIter->key) == argumentValue;
break;
case Puzzle::NOT_EQUAL_TO:
criteriaMet = getStateValue(entryIter->key) != argumentValue;
break;
case Puzzle::GREATER_THAN:
criteriaMet = getStateValue(entryIter->key) > argumentValue;
break;
case Puzzle::LESS_THAN:
criteriaMet = getStateValue(entryIter->key) < argumentValue;
break;
}
// If one check returns false, don't keep checking
if (!criteriaMet) {
break;
}
}
// If any of the Criteria are *fully* met, then execute the results
if (criteriaMet) {
break;
}
}
// criteriaList can be empty. Aka, the puzzle should be executed immediately
if (puzzle->criteriaList.empty() || criteriaMet) {
debug(1, "Puzzle %u criteria passed. Executing its ResultActions", puzzle->key);
// Set the puzzle as completed
setStateValue(puzzle->key, 1);
for (Common::List<ResultAction *>::iterator resultIter = puzzle->resultActions.begin(); resultIter != puzzle->resultActions.end(); ++resultIter) {
if (!(*resultIter)->execute())
return false;
}
}
return true;
}
void ScriptManager::cleanStateTable() {
for (StateMap::iterator iter = _globalState.begin(); iter != _globalState.end(); ++iter) {
// If the value is equal to zero, we can purge it since getStateValue()
// will return zero if _globalState doesn't contain a key
if (iter->_value == 0) {
// Remove the node
_globalState.erase(iter);
}
}
}
void ScriptManager::cleanScriptScope(ScriptScope &scope) {
scope.privQueueOne.clear();
scope.privQueueTwo.clear();
scope.scopeQueue = &scope.privQueueOne;
scope.execQueue = &scope.privQueueTwo;
for (PuzzleList::iterator iter = scope.puzzles.begin(); iter != scope.puzzles.end(); ++iter)
delete(*iter);
scope.puzzles.clear();
for (ControlList::iterator iter = scope.controls.begin(); iter != scope.controls.end(); ++iter)
delete(*iter);
scope.controls.clear();
scope.procCount = 0;
}
int ScriptManager::getStateValue(uint32 key) {
if (_globalState.contains(key))
return _globalState[key];
else
return 0;
}
void ScriptManager::queuePuzzles(uint32 key) {
if (_referenceTable.contains(key)) {
Common::Array<PuzzleRef> *arr = &_referenceTable[key];
for (int32 i = arr->size() - 1; i >= 0; i--)
if (!(*arr)[i].puz->addedBySetState) {
(*arr)[i].scope->scopeQueue->push_back((*arr)[i].puz);
(*arr)[i].puz->addedBySetState = true;
}
}
}
void ScriptManager::setStateValue(uint32 key, int value) {
if (value == 0)
_globalState.erase(key);
else
_globalState[key] = value;
queuePuzzles(key);
}
void ScriptManager::setStateValueSilent(uint32 key, int value) {
if (value == 0)
_globalState.erase(key);
else
_globalState[key] = value;
}
uint ScriptManager::getStateFlag(uint32 key) {
if (_globalStateFlags.contains(key))
return _globalStateFlags[key];
else
return 0;
}
void ScriptManager::setStateFlag(uint32 key, uint value) {
queuePuzzles(key);
_globalStateFlags[key] |= value;
}
void ScriptManager::setStateFlagSilent(uint32 key, uint value) {
if (value == 0)
_globalStateFlags.erase(key);
else
_globalStateFlags[key] = value;
}
void ScriptManager::unsetStateFlag(uint32 key, uint value) {
queuePuzzles(key);
if (_globalStateFlags.contains(key)) {
_globalStateFlags[key] &= ~value;
if (_globalStateFlags[key] == 0)
_globalStateFlags.erase(key);
}
}
Control *ScriptManager::getControl(uint32 key) {
for (ControlList::iterator iter = _activeControls->begin(); iter != _activeControls->end(); ++iter)
if ((*iter)->getKey() == key)
return *iter;
return nullptr;
}
void ScriptManager::focusControl(uint32 key) {
if (!_activeControls)
return;
if (_currentlyFocusedControl == key)
return;
for (ControlList::iterator iter = _activeControls->begin(); iter != _activeControls->end(); ++iter) {
uint32 controlKey = (*iter)->getKey();
if (controlKey == key) {
(*iter)->focus();
} else if (controlKey == _currentlyFocusedControl) {
(*iter)->unfocus();
}
}
_currentlyFocusedControl = key;
}
void ScriptManager::setFocusControlKey(uint32 key) {
_currentlyFocusedControl = key;
}
void ScriptManager::addSideFX(ScriptingEffect *fx) {
_activeSideFx.push_back(fx);
}
ScriptingEffect *ScriptManager::getSideFX(uint32 key) {
for (SideFXList::iterator iter = _activeSideFx.begin(); iter != _activeSideFx.end(); ++iter) {
if ((*iter)->getKey() == key) {
return (*iter);
}
}
return nullptr;
}
void ScriptManager::deleteSideFx(uint32 key) {
for (SideFXList::iterator iter = _activeSideFx.begin(); iter != _activeSideFx.end(); ++iter) {
if ((*iter)->getKey() == key) {
delete(*iter);
_activeSideFx.erase(iter);
break;
}
}
}
void ScriptManager::stopSideFx(uint32 key) {
for (SideFXList::iterator iter = _activeSideFx.begin(); iter != _activeSideFx.end(); ++iter) {
if ((*iter)->getKey() == key) {
bool ret = (*iter)->stop();
if (ret) {
delete(*iter);
_activeSideFx.erase(iter);
}
break;
}
}
}
void ScriptManager::killSideFx(uint32 key) {
for (SideFXList::iterator iter = _activeSideFx.begin(); iter != _activeSideFx.end(); ++iter) {
if ((*iter)->getKey() == key) {
(*iter)->kill();
delete(*iter);
_activeSideFx.erase(iter);
break;
}
}
}
void ScriptManager::killSideFxType(ScriptingEffect::ScriptingEffectType type) {
for (SideFXList::iterator iter = _activeSideFx.begin(); iter != _activeSideFx.end();) {
if ((*iter)->getType() & type) {
(*iter)->kill();
delete(*iter);
iter = _activeSideFx.erase(iter);
} else {
++iter;
}
}
}
void ScriptManager::onMouseDown(const Common::Point &screenSpacePos, const Common::Point &backgroundImageSpacePos) {
if (!_activeControls)
return;
for (ControlList::iterator iter = _activeControls->reverse_begin(); iter != _activeControls->end(); iter--) {
if ((*iter)->onMouseDown(screenSpacePos, backgroundImageSpacePos))
return;
}
}
void ScriptManager::onMouseUp(const Common::Point &screenSpacePos, const Common::Point &backgroundImageSpacePos) {
if (!_activeControls)
return;
for (ControlList::iterator iter = _activeControls->reverse_begin(); iter != _activeControls->end(); iter--) {
if ((*iter)->onMouseUp(screenSpacePos, backgroundImageSpacePos))
return;
}
}
bool ScriptManager::onMouseMove(const Common::Point &screenSpacePos, const Common::Point &backgroundImageSpacePos) {
if (!_activeControls)
return false;
for (ControlList::iterator iter = _activeControls->reverse_begin(); iter != _activeControls->end(); iter--) {
if ((*iter)->onMouseMove(screenSpacePos, backgroundImageSpacePos))
return true;
}
return false;
}
void ScriptManager::onKeyDown(Common::KeyState keyState) {
if (!_activeControls)
return;
for (ControlList::iterator iter = _activeControls->begin(); iter != _activeControls->end(); ++iter) {
if ((*iter)->onKeyDown(keyState))
return;
}
}
void ScriptManager::onKeyUp(Common::KeyState keyState) {
if (!_activeControls)
return;
for (ControlList::iterator iter = _activeControls->begin(); iter != _activeControls->end(); ++iter) {
if ((*iter)->onKeyUp(keyState))
return;
}
}
void ScriptManager::changeLocation(const Location &_newLocation) {
changeLocation(_newLocation.world, _newLocation.room, _newLocation.node, _newLocation.view, _newLocation.offset);
}
void ScriptManager::changeLocation(char _world, char _room, char _node, char _view, uint32 offset) {
_nextLocation.world = _world;
_nextLocation.room = _room;
_nextLocation.node = _node;
_nextLocation.view = _view;
_nextLocation.offset = offset;
// If next location is 0000, return to the previous location.
if (_nextLocation.world == '0' && _nextLocation.room == '0' && _nextLocation.node == '0' && _nextLocation.view == '0') {
if (getStateValue(StateKey_World) != 'g' || getStateValue(StateKey_Room) != 'j') {
_nextLocation.world = getStateValue(StateKey_LastWorld);
_nextLocation.room = getStateValue(StateKey_LastRoom);
_nextLocation.node = getStateValue(StateKey_LastNode);
_nextLocation.view = getStateValue(StateKey_LastView);
_nextLocation.offset = getStateValue(StateKey_LastViewPos);
} else {
_nextLocation.world = getStateValue(StateKey_Menu_LastWorld);
_nextLocation.room = getStateValue(StateKey_Menu_LastRoom);
_nextLocation.node = getStateValue(StateKey_Menu_LastNode);
_nextLocation.view = getStateValue(StateKey_Menu_LastView);
_nextLocation.offset = getStateValue(StateKey_Menu_LastViewPos);
}
}
}
void ScriptManager::ChangeLocationReal() {
assert(_nextLocation.world != 0);
debug(1, "Changing location to: %c %c %c %c %u", _nextLocation.world, _nextLocation.room, _nextLocation.node, _nextLocation.view, _nextLocation.offset);
if (_nextLocation.world == 'g' && _nextLocation.room == 'j' && !ConfMan.getBool("originalsaveload")) {
if ((_nextLocation.node == 's' || _nextLocation.node == 'r') && _nextLocation.view == 'e') {
// Hook up the ScummVM save/restore dialog
bool isSave = (_nextLocation.node == 's');
bool gameSavedOrLoaded = _engine->getSaveManager()->scummVMSaveLoadDialog(isSave);
if (!gameSavedOrLoaded || isSave) {
// Reload the current room
_nextLocation.world = _currentLocation.world;
_nextLocation.room = _currentLocation.room;
_nextLocation.node = _currentLocation.node;
_nextLocation.view = _currentLocation.view;
_nextLocation.offset = _currentLocation.offset;
_currentLocation.world = '0';
_currentLocation.room = '0';
_currentLocation.node = '0';
_currentLocation.view = '0';
_currentLocation.offset = 0;
} else
return;
}
}
_engine->setRenderDelay(2);
if (getStateValue(StateKey_World) != 'g' || getStateValue(StateKey_Room) != 'j') {
if (_nextLocation.world != 'g' || _nextLocation.room != 'j') {
setStateValue(StateKey_LastWorld, getStateValue(StateKey_World));
setStateValue(StateKey_LastRoom, getStateValue(StateKey_Room));
setStateValue(StateKey_LastNode, getStateValue(StateKey_Node));
setStateValue(StateKey_LastView, getStateValue(StateKey_View));
setStateValue(StateKey_LastViewPos, getStateValue(StateKey_ViewPos));
} else {
setStateValue(StateKey_Menu_LastWorld, getStateValue(StateKey_World));
setStateValue(StateKey_Menu_LastRoom, getStateValue(StateKey_Room));
setStateValue(StateKey_Menu_LastNode, getStateValue(StateKey_Node));
setStateValue(StateKey_Menu_LastView, getStateValue(StateKey_View));
setStateValue(StateKey_Menu_LastViewPos, getStateValue(StateKey_ViewPos));
}
}
if (_nextLocation.world == 'g' && _nextLocation.room == 'j') {
if (_nextLocation.node == 's' && _nextLocation.view == 'e' &&
_currentLocation.world != 'g' && _currentLocation.room != 'j')
_engine->getSaveManager()->prepareSaveBuffer();
} else {
if (_currentLocation.world == 'g' && _currentLocation.room == 'j')
_engine->getSaveManager()->flushSaveBuffer();
}
setStateValue(StateKey_World, _nextLocation.world);
setStateValue(StateKey_Room, _nextLocation.room);
setStateValue(StateKey_Node, _nextLocation.node);
setStateValue(StateKey_View, _nextLocation.view);
setStateValue(StateKey_ViewPos, _nextLocation.offset);
_referenceTable.clear();
addPuzzlesToReferenceTable(universe);
_engine->getMenuHandler()->setEnable(0xFFFF);
if (_nextLocation.world != _currentLocation.world) {
cleanScriptScope(nodeview);
cleanScriptScope(room);
cleanScriptScope(world);
Common::String fileName = Common::String::format("%c%c%c%c.scr", _nextLocation.world, _nextLocation.room, _nextLocation.node, _nextLocation.view);
parseScrFile(fileName, nodeview);
addPuzzlesToReferenceTable(nodeview);
fileName = Common::String::format("%c%c.scr", _nextLocation.world, _nextLocation.room);
parseScrFile(fileName, room);
addPuzzlesToReferenceTable(room);
fileName = Common::String::format("%c.scr", _nextLocation.world);
parseScrFile(fileName, world);
addPuzzlesToReferenceTable(world);
} else if (_nextLocation.room != _currentLocation.room) {
cleanScriptScope(nodeview);
cleanScriptScope(room);
addPuzzlesToReferenceTable(world);
Common::String fileName = Common::String::format("%c%c%c%c.scr", _nextLocation.world, _nextLocation.room, _nextLocation.node, _nextLocation.view);
parseScrFile(fileName, nodeview);
addPuzzlesToReferenceTable(nodeview);
fileName = Common::String::format("%c%c.scr", _nextLocation.world, _nextLocation.room);
parseScrFile(fileName, room);
addPuzzlesToReferenceTable(room);
} else if (_nextLocation.node != _currentLocation.node || _nextLocation.view != _currentLocation.view) {
cleanScriptScope(nodeview);
addPuzzlesToReferenceTable(room);
addPuzzlesToReferenceTable(world);
Common::String fileName = Common::String::format("%c%c%c%c.scr", _nextLocation.world, _nextLocation.room, _nextLocation.node, _nextLocation.view);
parseScrFile(fileName, nodeview);
addPuzzlesToReferenceTable(nodeview);
}
_activeControls = &nodeview.controls;
// Revert to the idle cursor
_engine->getCursorManager()->changeCursor(CursorIndex_Idle);
// Change the background position
_engine->getRenderManager()->setBackgroundPosition(_nextLocation.offset);
if (_currentLocation.world == 0 && _currentLocation.room == 0 && _currentLocation.node == 0 && _currentLocation.view == 0) {
_currentLocation = _nextLocation;
execScope(world);
execScope(room);
execScope(nodeview);
} else if (_nextLocation.world != _currentLocation.world) {
_currentLocation = _nextLocation;
execScope(room);
execScope(nodeview);
} else if (_nextLocation.room != _currentLocation.room) {
_currentLocation = _nextLocation;
execScope(room);
execScope(nodeview);
} else if (_nextLocation.node != _currentLocation.node || _nextLocation.view != _currentLocation.view) {
_currentLocation = _nextLocation;
execScope(nodeview);
}
_engine->getRenderManager()->checkBorders();
}
void ScriptManager::serialize(Common::WriteStream *stream) {
stream->writeUint32BE(MKTAG('Z', 'N', 'S', 'G'));
stream->writeUint32LE(4);
stream->writeUint32LE(0);
stream->writeUint32BE(MKTAG('L', 'O', 'C', ' '));
stream->writeUint32LE(8);
stream->writeByte(getStateValue(StateKey_World));
stream->writeByte(getStateValue(StateKey_Room));
stream->writeByte(getStateValue(StateKey_Node));
stream->writeByte(getStateValue(StateKey_View));
stream->writeUint32LE(getStateValue(StateKey_ViewPos));
for (SideFXList::iterator iter = _activeSideFx.begin(); iter != _activeSideFx.end(); ++iter)
(*iter)->serialize(stream);
stream->writeUint32BE(MKTAG('F', 'L', 'A', 'G'));
int32 slots = 20000;
if (_engine->getGameId() == GID_NEMESIS)
slots = 30000;
stream->writeUint32LE(slots * 2);
for (int32 i = 0; i < slots; i++)
stream->writeUint16LE(getStateFlag(i));
stream->writeUint32BE(MKTAG('P', 'U', 'Z', 'Z'));
stream->writeUint32LE(slots * 2);
for (int32 i = 0; i < slots; i++)
stream->writeSint16LE(getStateValue(i));
}
void ScriptManager::deserialize(Common::SeekableReadStream *stream) {
// Clear out the current table values
_globalState.clear();
_globalStateFlags.clear();
cleanScriptScope(nodeview);
cleanScriptScope(room);
cleanScriptScope(world);
_currentLocation.node = 0;
_currentLocation.world = 0;
_currentLocation.room = 0;
_currentLocation.view = 0;
for (SideFXList::iterator iter = _activeSideFx.begin(); iter != _activeSideFx.end(); iter++)
delete(*iter);
_activeSideFx.clear();
_referenceTable.clear();
if (stream->readUint32BE() != MKTAG('Z', 'N', 'S', 'G') || stream->readUint32LE() != 4) {
changeLocation('g', 'a', 'r', 'y', 0);
return;
}
stream->seek(4, SEEK_CUR);
if (stream->readUint32BE() != MKTAG('L', 'O', 'C', ' ') || stream->readUint32LE() != 8) {
changeLocation('g', 'a', 'r', 'y', 0);
return;
}
Location nextLocation;
nextLocation.world = stream->readByte();
nextLocation.room = stream->readByte();
nextLocation.node = stream->readByte();
nextLocation.view = stream->readByte();
nextLocation.offset = stream->readUint32LE() & 0x0000FFFF;
while (stream->pos() < stream->size()) {
uint32 tag = stream->readUint32BE();
uint32 tagSize = stream->readUint32LE();
switch (tag) {
case MKTAG('T', 'I', 'M', 'R'): {
uint32 key = stream->readUint32LE();
uint32 time = stream->readUint32LE();
if (_engine->getGameId() == GID_GRANDINQUISITOR)
time /= 100;
else if (_engine->getGameId() == GID_NEMESIS)
time /= 1000;
addSideFX(new TimerNode(_engine, key, time));
}
break;
case MKTAG('F', 'L', 'A', 'G'):
for (uint32 i = 0; i < tagSize / 2; i++)
setStateFlagSilent(i, stream->readUint16LE());
break;
case MKTAG('P', 'U', 'Z', 'Z'):
for (uint32 i = 0; i < tagSize / 2; i++)
setStateValueSilent(i, stream->readUint16LE());
break;
default:
stream->seek(tagSize, SEEK_CUR);
}
}
_nextLocation = nextLocation;
ChangeLocationReal();
_engine->setRenderDelay(10);
setStateValue(StateKey_RestoreFlag, 1);
_engine->loadSettings();
}
Location ScriptManager::getCurrentLocation() const {
Location location = _currentLocation;
location.offset = _engine->getRenderManager()->getCurrentBackgroundOffset();
return location;
}
Location ScriptManager::getLastLocation() {
Location location;
location.world = getStateValue(StateKey_LastWorld);
location.room = getStateValue(StateKey_LastRoom);
location.node = getStateValue(StateKey_LastNode);
location.view = getStateValue(StateKey_LastView);
location.offset = getStateValue(StateKey_LastViewPos);
return location;
}
Location ScriptManager::getLastMenuLocation() {
Location location;
location.world = getStateValue(StateKey_Menu_LastWorld);
location.room = getStateValue(StateKey_Menu_LastRoom);
location.node = getStateValue(StateKey_Menu_LastNode);
location.view = getStateValue(StateKey_Menu_LastView);
location.offset = getStateValue(StateKey_Menu_LastViewPos);
return location;
}
void ScriptManager::addEvent(Common::Event event) {
_controlEvents.push_back(event);
}
void ScriptManager::flushEvent(Common::EventType type) {
EventList::iterator it = _controlEvents.begin();
while (it != _controlEvents.end()) {
if ((*it).type == type)
it = _controlEvents.erase(it);
else
it++;
}
}
void ScriptManager::trimCommentsAndWhiteSpace(Common::String *string) const {
for (int i = string->size() - 1; i >= 0; i--) {
if ((*string)[i] == '#') {
string->erase(i);
}
}
string->trim();
}
ValueSlot::ValueSlot(ScriptManager *scriptManager, const char *slotValue):
_scriptManager(scriptManager) {
value = 0;
slot = false;
const char *isSlot = strstr(slotValue, "[");
if (isSlot) {
slot = true;
value = atoi(isSlot + 1);
} else {
slot = false;
value = atoi(slotValue);
}
}
int16 ValueSlot::getValue() {
if (slot) {
if (value >= 0)
return _scriptManager->getStateValue(value);
else
return 0;
} else
return value;
}
} // End of namespace ZVision