aboutsummaryrefslogtreecommitdiff
path: root/engines/zvision/scripting/script_manager.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'engines/zvision/scripting/script_manager.cpp')
-rw-r--r--engines/zvision/scripting/script_manager.cpp958
1 files changed, 709 insertions, 249 deletions
diff --git a/engines/zvision/scripting/script_manager.cpp b/engines/zvision/scripting/script_manager.cpp
index 41b835e550..70eaab2a0a 100644
--- a/engines/zvision/scripting/script_manager.cpp
+++ b/engines/zvision/scripting/script_manager.cpp
@@ -1,24 +1,24 @@
/* 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.
- *
- */
+*
+* 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"
@@ -26,172 +26,254 @@
#include "zvision/zvision.h"
#include "zvision/graphics/render_manager.h"
-#include "zvision/cursors/cursor_manager.h"
-#include "zvision/core/save_manager.h"
+#include "zvision/graphics/cursors/cursor_manager.h"
+#include "zvision/file/save_manager.h"
#include "zvision/scripting/actions.h"
-#include "zvision/utility/utility.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) {
+ _currentlyFocusedControl(0),
+ _activeControls(NULL) {
}
ScriptManager::~ScriptManager() {
- for (PuzzleList::iterator iter = _activePuzzles.begin(); iter != _activePuzzles.end(); ++iter) {
- delete (*iter);
- }
- for (PuzzleList::iterator iter = _globalPuzzles.begin(); iter != _globalPuzzles.end(); ++iter) {
- delete (*iter);
- }
- for (ControlList::iterator iter = _activeControls.begin(); iter != _activeControls.end(); ++iter) {
- delete (*iter);
- }
+ cleanScriptScope(universe);
+ cleanScriptScope(world);
+ cleanScriptScope(room);
+ cleanScriptScope(nodeview);
+ _controlEvents.clear();
}
void ScriptManager::initialize() {
- parseScrFile("universe.scr", true);
+ 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 != _nextLocation) {
+ ChangeLocationReal(false);
+ }
+
updateNodes(deltaTimeMillis);
- checkPuzzleCriteria();
+ if (!execScope(nodeview)) {
+ return;
+ }
+ if (!execScope(room)) {
+ return;
+ }
+ if (!execScope(world)) {
+ return;
+ }
+ if (!execScope(universe)) {
+ return;
+ }
+ updateControls(deltaTimeMillis);
}
-void ScriptManager::createReferenceTable() {
- // Iterate through each local Puzzle
- for (PuzzleList::iterator activePuzzleIter = _activePuzzles.begin(); activePuzzleIter != _activePuzzles.end(); ++activePuzzleIter) {
- Puzzle *puzzlePtr = (*activePuzzleIter);
+bool ScriptManager::execScope(ScriptScope &scope) {
+ // Swap queues
+ PuzzleList *tmp = scope.execQueue;
+ scope.execQueue = scope.scopeQueue;
+ scope.scopeQueue = tmp;
+ scope.scopeQueue->clear();
- // Iterate through each CriteriaEntry and add a reference from the criteria key to the Puzzle
- for (Common::List<Common::List<Puzzle::CriteriaEntry> >::iterator criteriaIter = (*activePuzzleIter)->criteriaList.begin(); criteriaIter != (*activePuzzleIter)->criteriaList.end(); ++criteriaIter) {
- for (Common::List<Puzzle::CriteriaEntry>::iterator entryIter = criteriaIter->begin(); entryIter != criteriaIter->end(); ++entryIter) {
- _referenceTable[entryIter->key].push_back(puzzlePtr);
+ for (PuzzleList::iterator PuzzleIter = scope.puzzles.begin(); PuzzleIter != scope.puzzles.end(); ++PuzzleIter) {
+ (*PuzzleIter)->addedBySetState = false;
+ }
- // If the argument is a key, add a reference to it as well
- if (entryIter->argumentIsAKey) {
- _referenceTable[entryIter->argument].push_back(puzzlePtr);
- }
+ 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;
}
}
}
- // Iterate through each global Puzzle
- for (PuzzleList::iterator globalPuzzleIter = _globalPuzzles.begin(); globalPuzzleIter != _globalPuzzles.end(); ++globalPuzzleIter) {
- Puzzle *puzzlePtr = (*globalPuzzleIter);
-
- // Iterate through each CriteriaEntry and add a reference from the criteria key to the Puzzle
- for (Common::List<Common::List<Puzzle::CriteriaEntry> >::iterator criteriaIter = (*globalPuzzleIter)->criteriaList.begin(); criteriaIter != (*globalPuzzleIter)->criteriaList.end(); ++criteriaIter) {
- for (Common::List<Puzzle::CriteriaEntry>::iterator entryIter = criteriaIter->begin(); entryIter != criteriaIter->end(); ++entryIter) {
- _referenceTable[entryIter->key].push_back(puzzlePtr);
+ if (scope.procCount < 2) {
+ scope.procCount++;
+ }
+ return true;
+}
- // If the argument is a key, add a reference to it as well
- if (entryIter->argumentIsAKey) {
- _referenceTable[entryIter->argument].push_back(puzzlePtr);
- }
+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;
}
}
}
- // Remove duplicate entries
- for (PuzzleMap::iterator referenceTableIter = _referenceTable.begin(); referenceTableIter != _referenceTable.end(); ++referenceTableIter) {
- removeDuplicateEntries(referenceTableIter->_value);
+ _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 (ControlList::iterator iter = _activeControls.begin(); iter != _activeControls.end();) {
+ for (SideFXList::iterator iter = _activeSideFx.begin(); iter != _activeSideFx.end();) {
if ((*iter)->process(deltaTimeMillis)) {
- delete (*iter);
+ delete(*iter);
// Remove the node
- iter = _activeControls.erase(iter);
+ iter = _activeSideFx.erase(iter);
} else {
++iter;
}
}
}
-void ScriptManager::checkPuzzleCriteria() {
- while (!_puzzlesToCheck.empty()) {
- Puzzle *puzzle = _puzzlesToCheck.pop();
+void ScriptManager::updateControls(uint deltaTimeMillis) {
+ if (!_activeControls) {
+ return;
+ }
- // Check if the puzzle is already finished
- // Also check that the puzzle isn't disabled
- if (getStateValue(puzzle->key) == 1 && (getStateFlags(puzzle->key) & DISABLED) == 0) {
- continue;
+ // 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;
+ }
+ }
+}
- // Check each Criteria
+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)) {
+ return true;
+ }
- bool criteriaMet = false;
- for (Common::List<Common::List<Puzzle::CriteriaEntry> >::iterator criteriaIter = puzzle->criteriaList.begin(); criteriaIter != puzzle->criteriaList.end(); ++criteriaIter) {
- criteriaMet = false;
+ // Check each Criteria
+ if (counter == 0 && (getStateFlag(puzzle->key) & Puzzle::DO_ME_NOW) == 0) {
+ return true;
+ }
- for (Common::List<Puzzle::CriteriaEntry>::iterator entryIter = criteriaIter->begin(); entryIter != criteriaIter->end(); ++entryIter) {
- // Get the value to compare against
- uint 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;
- }
+ 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 any of the Criteria are *fully* met, then execute the results
- if (criteriaMet) {
+ // If one check returns false, don't keep checking
+ 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);
+ // If any of the Criteria are *fully* met, then execute the results
+ if (criteriaMet) {
+ break;
+ }
+ }
- // Set the puzzle as completed
- setStateValue(puzzle->key, 1);
+ // 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);
- bool shouldContinue = true;
- for (Common::List<ResultAction *>::iterator resultIter = puzzle->resultActions.begin(); resultIter != puzzle->resultActions.end(); ++resultIter) {
- shouldContinue = shouldContinue && (*resultIter)->execute(_engine);
- if (!shouldContinue) {
- break;
- }
- }
+ // Set the puzzle as completed
+ setStateValue(puzzle->key, 1);
- if (!shouldContinue) {
- break;
+ for (Common::List<ResultAction *>::iterator resultIter = puzzle->resultActions.begin(); resultIter != puzzle->resultActions.end(); ++resultIter) {
+ if (!(*resultIter)->execute()) {
+ return false;
}
}
}
+
+ return true;
}
void ScriptManager::cleanStateTable() {
@@ -205,52 +287,102 @@ void ScriptManager::cleanStateTable() {
}
}
-uint ScriptManager::getStateValue(uint32 key) {
- if (_globalState.contains(key))
+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
+ } else {
return 0;
+ }
}
-void ScriptManager::setStateValue(uint32 key, uint value) {
- _globalState[key] = value;
-
+void ScriptManager::queuePuzzles(uint32 key) {
if (_referenceTable.contains(key)) {
- for (Common::Array<Puzzle *>::iterator iter = _referenceTable[key].begin(); iter != _referenceTable[key].end(); ++iter) {
- _puzzlesToCheck.push((*iter));
+ 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;
+ }
}
}
}
-uint ScriptManager::getStateFlags(uint32 key) {
- if (_globalStateFlags.contains(key))
+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
+ } else {
return 0;
+ }
}
-void ScriptManager::setStateFlags(uint32 key, uint flags) {
- _globalStateFlags[key] = flags;
+void ScriptManager::setStateFlag(uint32 key, uint value) {
+ queuePuzzles(key);
- if (_referenceTable.contains(key)) {
- for (Common::Array<Puzzle *>::iterator iter = _referenceTable[key].begin(); iter != _referenceTable[key].end(); ++iter) {
- _puzzlesToCheck.push((*iter));
- }
- }
+ _globalStateFlags[key] |= value;
}
-void ScriptManager::addToStateValue(uint32 key, uint valueToAdd) {
- _globalState[key] += valueToAdd;
+void ScriptManager::setStateFlagSilent(uint32 key, uint value) {
+ if (value == 0) {
+ _globalStateFlags.erase(key);
+ } else {
+ _globalStateFlags[key] = value;
+ }
}
-void ScriptManager::addControl(Control *control) {
- _activeControls.push_back(control);
+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) {
+ for (ControlList::iterator iter = _activeControls->begin(); iter != _activeControls->end(); ++iter) {
if ((*iter)->getKey() == key) {
- return (*iter);
+ return *iter;
}
}
@@ -258,9 +390,15 @@ Control *ScriptManager::getControl(uint32 key) {
}
void ScriptManager::focusControl(uint32 key) {
- for (ControlList::iterator iter = _activeControls.begin(); iter != _activeControls.end(); ++iter) {
+ 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) {
@@ -271,167 +409,415 @@ void ScriptManager::focusControl(uint32 key) {
_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) {
- for (ControlList::iterator iter = _activeControls.begin(); iter != _activeControls.end(); ++iter) {
- (*iter)->onMouseDown(screenSpacePos, 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) {
- for (ControlList::iterator iter = _activeControls.begin(); iter != _activeControls.end(); ++iter) {
- (*iter)->onMouseUp(screenSpacePos, 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) {
- bool cursorWasChanged = false;
- for (ControlList::iterator iter = _activeControls.begin(); iter != _activeControls.end(); ++iter) {
- cursorWasChanged = cursorWasChanged || (*iter)->onMouseMove(screenSpacePos, backgroundImageSpacePos);
+ if (!_activeControls) {
+ return false;
}
- return cursorWasChanged;
+ 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) {
- for (ControlList::iterator iter = _activeControls.begin(); iter != _activeControls.end(); ++iter) {
- (*iter)->onKeyDown(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) {
- for (ControlList::iterator iter = _activeControls.begin(); iter != _activeControls.end(); ++iter) {
- (*iter)->onKeyUp(keyState);
+ if (!_activeControls) {
+ return;
+ }
+ for (ControlList::iterator iter = _activeControls->begin(); iter != _activeControls->end(); ++iter) {
+ if ((*iter)->onKeyUp(keyState)) {
+ return;
+ }
}
}
-void ScriptManager::changeLocation(char world, char room, char node, char view, uint32 offset) {
- assert(world != 0);
- debug(1, "Changing location to: %c %c %c %c %u", world, room, node, view, offset);
+void ScriptManager::changeLocation(const Location &_newLocation) {
+ changeLocation(_newLocation.world, _newLocation.room, _newLocation.node, _newLocation.view, _newLocation.offset);
+}
- // Auto save
- _engine->getSaveManager()->autoSave();
+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 == "0000") {
+ 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);
+ }
+ }
+}
- // Clear all the containers
- _referenceTable.clear();
- _puzzlesToCheck.clear();
- for (PuzzleList::iterator iter = _activePuzzles.begin(); iter != _activePuzzles.end(); ++iter) {
- delete (*iter);
+void ScriptManager::ChangeLocationReal(bool isLoading) {
+ assert(_nextLocation.world != 0);
+ debug(1, "Changing location to: %c %c %c %c %u", _nextLocation.world, _nextLocation.room, _nextLocation.node, _nextLocation.view, _nextLocation.offset);
+
+ const bool enteringMenu = (_nextLocation.world == 'g' && _nextLocation.room == 'j');
+ const bool leavingMenu = (_currentLocation.world == 'g' && _currentLocation.room == 'j');
+ const bool isSaveScreen = (enteringMenu && _nextLocation.node == 's' && _nextLocation.view == 'e');
+ const bool isRestoreScreen = (enteringMenu && _nextLocation.node == 'r' && _nextLocation.view == 'e');
+
+ if (enteringMenu && !ConfMan.getBool("originalsaveload")) {
+ if (isSaveScreen || isRestoreScreen) {
+ // Hook up the ScummVM save/restore dialog
+ bool gameSavedOrLoaded = _engine->getSaveManager()->scummVMSaveLoadDialog(isSaveScreen);
+ if (!gameSavedOrLoaded || isSaveScreen) {
+ // Reload the current room
+ _nextLocation.world = _currentLocation.world;
+ _nextLocation.room = _currentLocation.room;
+ _nextLocation.node = _currentLocation.node;
+ _nextLocation.view = _currentLocation.view;
+ _nextLocation.offset = _currentLocation.offset;
+
+ return;
+ } else {
+ _currentLocation.world = 'g';
+ _currentLocation.room = '0';
+ _currentLocation.node = '0';
+ _currentLocation.view = '0';
+ _currentLocation.offset = 0;
+ }
+ }
}
- _activePuzzles.clear();
- for (ControlList::iterator iter = _activeControls.begin(); iter != _activeControls.end(); ++iter) {
- delete (*iter);
+
+ _engine->setRenderDelay(2);
+
+ if (!leavingMenu) {
+ if (!isLoading && !enteringMenu) {
+ 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));
+ }
}
- _activeControls.clear();
- // Revert to the idle cursor
- _engine->getCursorManager()->revertToIdle();
+ if (enteringMenu) {
+ if (isSaveScreen && !leavingMenu) {
+ _engine->getSaveManager()->prepareSaveBuffer();
+ }
+ } else {
+ if (leavingMenu) {
+ _engine->getSaveManager()->flushSaveBuffer();
+ }
+ }
- // Reset the background velocity
- _engine->getRenderManager()->setBackgroundVelocity(0);
+ 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);
- // Remove any alphaEntries
- _engine->getRenderManager()->clearAlphaEntries();
+ _referenceTable.clear();
+ addPuzzlesToReferenceTable(universe);
- // Clean the global state table
- cleanStateTable();
+ _engine->getMenuHandler()->setEnable(0xFFFF);
- // Parse into puzzles and controls
- Common::String fileName = Common::String::format("%c%c%c%c.scr", world, room, node, view);
- parseScrFile(fileName);
+ if (_nextLocation.world != _currentLocation.world) {
+ cleanScriptScope(nodeview);
+ cleanScriptScope(room);
+ cleanScriptScope(world);
- // Change the background position
- _engine->getRenderManager()->setBackgroundPosition(offset);
+ Common::String fileName = Common::String::format("%c%c%c%c.scr", _nextLocation.world, _nextLocation.room, _nextLocation.node, _nextLocation.view);
+ parseScrFile(fileName, nodeview);
+ addPuzzlesToReferenceTable(nodeview);
- // Enable all the controls
- for (ControlList::iterator iter = _activeControls.begin(); iter != _activeControls.end(); ++iter) {
- (*iter)->enable();
+ 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);
}
- // Add all the local puzzles to the queue to be checked
- for (PuzzleList::iterator iter = _activePuzzles.begin(); iter != _activePuzzles.end(); ++iter) {
- // Reset any Puzzles that have the flag ONCE_PER_INST
- if ((getStateFlags((*iter)->key) & ONCE_PER_INST) == ONCE_PER_INST) {
- setStateValue((*iter)->key, 0);
- }
+ _activeControls = &nodeview.controls;
+
+ // Revert to the idle cursor
+ _engine->getCursorManager()->changeCursor(CursorIndex_Idle);
- _puzzlesToCheck.push((*iter));
+ // Change the background position
+ _engine->getRenderManager()->setBackgroundPosition(_nextLocation.offset);
+
+ if (_currentLocation == "0000") {
+ _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);
}
- // Add all the global puzzles to the queue to be checked
- for (PuzzleList::iterator iter = _globalPuzzles.begin(); iter != _globalPuzzles.end(); ++iter) {
- // Reset any Puzzles that have the flag ONCE_PER_INST
- if ((getStateFlags((*iter)->key) & ONCE_PER_INST) == ONCE_PER_INST) {
- setStateValue((*iter)->key, 0);
- }
+ _engine->getRenderManager()->checkBorders();
+}
- _puzzlesToCheck.push((*iter));
+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);
}
- // Create the puzzle reference table
- createReferenceTable();
+ stream->writeUint32BE(MKTAG('F', 'L', 'A', 'G'));
- // Update _currentLocation
- _currentLocation.world = world;
- _currentLocation.room = room;
- _currentLocation.node = node;
- _currentLocation.view = view;
- _currentLocation.offset = offset;
-}
+ int32 slots = 20000;
+ if (_engine->getGameId() == GID_NEMESIS) {
+ slots = 30000;
+ }
-void ScriptManager::serializeStateTable(Common::WriteStream *stream) {
- // Write the number of state value entries
- stream->writeUint32LE(_globalState.size());
+ stream->writeUint32LE(slots * 2);
- for (StateMap::iterator iter = _globalState.begin(); iter != _globalState.end(); ++iter) {
- // Write out the key/value pair
- stream->writeUint32LE(iter->_key);
- stream->writeUint32LE(iter->_value);
+ 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::deserializeStateTable(Common::SeekableReadStream *stream) {
+void ScriptManager::deserialize(Common::SeekableReadStream *stream) {
// Clear out the current table values
_globalState.clear();
+ _globalStateFlags.clear();
- // Read the number of key/value pairs
- uint32 numberOfPairs = stream->readUint32LE();
+ cleanScriptScope(nodeview);
+ cleanScriptScope(room);
+ cleanScriptScope(world);
- for (uint32 i = 0; i < numberOfPairs; ++i) {
- uint32 key = stream->readUint32LE();
- uint32 value = stream->readUint32LE();
- // Directly access the state table so we don't trigger Puzzle checks
- _globalState[key] = value;
- }
-}
+ _currentLocation.node = 0;
+ _currentLocation.world = 0;
+ _currentLocation.room = 0;
+ _currentLocation.view = 0;
-void ScriptManager::serializeControls(Common::WriteStream *stream) {
- // Count how many controls need to save their data
- // Because WriteStream isn't seekable
- uint32 numberOfControlsNeedingSerialization = 0;
- for (ControlList::iterator iter = _activeControls.begin(); iter != _activeControls.end(); ++iter) {
- if ((*iter)->needsSerialization()) {
- numberOfControlsNeedingSerialization++;
- }
+ for (SideFXList::iterator iter = _activeSideFx.begin(); iter != _activeSideFx.end(); iter++) {
+ delete(*iter);
}
- stream->writeUint32LE(numberOfControlsNeedingSerialization);
- for (ControlList::iterator iter = _activeControls.begin(); iter != _activeControls.end(); ++iter) {
- (*iter)->serialize(stream);
+ _activeSideFx.clear();
+
+ _referenceTable.clear();
+
+ if (stream->readUint32BE() != MKTAG('Z', 'N', 'S', 'G') || stream->readUint32LE() != 4) {
+ changeLocation('g', 'a', 'r', 'y', 0);
+ return;
}
-}
-void ScriptManager::deserializeControls(Common::SeekableReadStream *stream) {
- uint32 numberOfControls = stream->readUint32LE();
+ stream->seek(4, SEEK_CUR);
- for (uint32 i = 0; i < numberOfControls; ++i) {
- uint32 key = stream->readUint32LE();
- for (ControlList::iterator iter = _activeControls.begin(); iter != _activeControls.end(); ++iter) {
- if ((*iter)->getKey() == key) {
- (*iter)->deserialize(stream);
- break;
+ 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(true);
+
+ _engine->setRenderDelay(10);
+ setStateValue(StateKey_RestoreFlag, 1);
+
+ _engine->loadSettings();
}
Location ScriptManager::getCurrentLocation() const {
@@ -441,4 +827,78 @@ Location ScriptManager::getCurrentLocation() const {
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