aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--engines/mads/action.cpp696
-rw-r--r--engines/mads/action.h176
-rw-r--r--engines/mads/animation.cpp574
-rw-r--r--engines/mads/animation.h230
-rw-r--r--engines/mads/assets.cpp227
-rw-r--r--engines/mads/assets.h112
-rw-r--r--engines/mads/audio.cpp129
-rw-r--r--engines/mads/audio.h64
-rw-r--r--engines/mads/compression.cpp190
-rw-r--r--engines/mads/compression.h88
-rw-r--r--engines/mads/configure.engine3
-rw-r--r--engines/mads/debugger.cpp326
-rw-r--r--engines/mads/debugger.h61
-rw-r--r--engines/mads/detection.cpp194
-rw-r--r--engines/mads/detection_tables.h104
-rw-r--r--engines/mads/dialogs.cpp396
-rw-r--r--engines/mads/dialogs.h229
-rw-r--r--engines/mads/dragonsphere/dragonsphere_scenes.cpp239
-rw-r--r--engines/mads/dragonsphere/dragonsphere_scenes.h695
-rw-r--r--engines/mads/dragonsphere/game_dragonsphere.cpp172
-rw-r--r--engines/mads/dragonsphere/game_dragonsphere.h151
-rw-r--r--engines/mads/events.cpp254
-rw-r--r--engines/mads/events.h164
-rw-r--r--engines/mads/font.cpp246
-rw-r--r--engines/mads/font.h95
-rw-r--r--engines/mads/game.cpp593
-rw-r--r--engines/mads/game.h229
-rw-r--r--engines/mads/game_data.cpp54
-rw-r--r--engines/mads/game_data.h73
-rw-r--r--engines/mads/globals.cpp33
-rw-r--r--engines/mads/globals.h47
-rw-r--r--engines/mads/hotspots.cpp206
-rw-r--r--engines/mads/hotspots.h114
-rw-r--r--engines/mads/inventory.cpp226
-rw-r--r--engines/mads/inventory.h141
-rw-r--r--engines/mads/mads.cpp156
-rw-r--r--engines/mads/mads.h152
-rw-r--r--engines/mads/messages.cpp566
-rw-r--r--engines/mads/messages.h192
-rw-r--r--engines/mads/module.mk58
-rw-r--r--engines/mads/msurface.cpp551
-rw-r--r--engines/mads/msurface.h240
-rw-r--r--engines/mads/nebular/dialogs_nebular.cpp693
-rw-r--r--engines/mads/nebular/dialogs_nebular.h180
-rw-r--r--engines/mads/nebular/game_nebular.cpp766
-rw-r--r--engines/mads/nebular/game_nebular.h151
-rw-r--r--engines/mads/nebular/globals_nebular.cpp54
-rw-r--r--engines/mads/nebular/globals_nebular.h305
-rw-r--r--engines/mads/nebular/nebular_scenes.cpp615
-rw-r--r--engines/mads/nebular/nebular_scenes.h1383
-rw-r--r--engines/mads/nebular/nebular_scenes1.cpp3168
-rw-r--r--engines/mads/nebular/nebular_scenes1.h264
-rw-r--r--engines/mads/nebular/nebular_scenes2.cpp5374
-rw-r--r--engines/mads/nebular/nebular_scenes2.h325
-rw-r--r--engines/mads/nebular/nebular_scenes3.cpp5807
-rw-r--r--engines/mads/nebular/nebular_scenes3.h540
-rw-r--r--engines/mads/nebular/nebular_scenes4.cpp4191
-rw-r--r--engines/mads/nebular/nebular_scenes4.h258
-rw-r--r--engines/mads/nebular/nebular_scenes5.cpp2871
-rw-r--r--engines/mads/nebular/nebular_scenes5.h254
-rw-r--r--engines/mads/nebular/nebular_scenes6.cpp4771
-rw-r--r--engines/mads/nebular/nebular_scenes6.h322
-rw-r--r--engines/mads/nebular/nebular_scenes7.cpp2678
-rw-r--r--engines/mads/nebular/nebular_scenes7.h238
-rw-r--r--engines/mads/nebular/nebular_scenes8.cpp1524
-rw-r--r--engines/mads/nebular/nebular_scenes8.h165
-rw-r--r--engines/mads/nebular/sound_nebular.cpp3111
-rw-r--r--engines/mads/nebular/sound_nebular.h720
-rw-r--r--engines/mads/palette.cpp829
-rw-r--r--engines/mads/palette.h330
-rw-r--r--engines/mads/phantom/game_phantom.cpp160
-rw-r--r--engines/mads/phantom/game_phantom.h124
-rw-r--r--engines/mads/phantom/phantom_scenes.cpp204
-rw-r--r--engines/mads/phantom/phantom_scenes.h521
-rw-r--r--engines/mads/player.cpp785
-rw-r--r--engines/mads/player.h228
-rw-r--r--engines/mads/rails.cpp284
-rw-r--r--engines/mads/rails.h134
-rw-r--r--engines/mads/resources.cpp416
-rw-r--r--engines/mads/resources.h89
-rw-r--r--engines/mads/scene.cpp718
-rw-r--r--engines/mads/scene.h251
-rw-r--r--engines/mads/scene_data.cpp446
-rw-r--r--engines/mads/scene_data.h223
-rw-r--r--engines/mads/screen.cpp641
-rw-r--r--engines/mads/screen.h240
-rw-r--r--engines/mads/sequence.cpp533
-rw-r--r--engines/mads/sequence.h131
-rw-r--r--engines/mads/sound.cpp142
-rw-r--r--engines/mads/sound.h103
-rw-r--r--engines/mads/sprites.cpp416
-rw-r--r--engines/mads/sprites.h239
-rw-r--r--engines/mads/staticres.cpp58
-rw-r--r--engines/mads/staticres.h47
-rw-r--r--engines/mads/user_interface.cpp1092
-rw-r--r--engines/mads/user_interface.h306
96 files changed, 59864 insertions, 0 deletions
diff --git a/engines/mads/action.cpp b/engines/mads/action.cpp
new file mode 100644
index 0000000000..1db143aaad
--- /dev/null
+++ b/engines/mads/action.cpp
@@ -0,0 +1,696 @@
+/* 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 "mads/mads.h"
+#include "mads/action.h"
+#include "mads/inventory.h"
+#include "mads/resources.h"
+#include "mads/scene.h"
+#include "mads/staticres.h"
+
+namespace MADS {
+
+void ActionDetails::synchronize(Common::Serializer &s) {
+ s.syncAsUint16LE(_verbId);
+ s.syncAsUint16LE(_objectNameId);
+ s.syncAsUint16LE(_indirectObjectId);
+}
+
+void ActionSavedFields::synchronize(Common::Serializer &s) {
+ s.syncAsByte(_commandError);
+ s.syncAsSint16LE(_commandSource);
+ s.syncAsSint16LE(_command);
+ s.syncAsSint16LE(_mainObject);
+ s.syncAsSint16LE(_secondObject);
+ s.syncAsSint16LE(_mainObjectSource);
+ s.syncAsSint16LE(_secondObjectSource);
+ s.syncAsSint16LE(_articleNumber);
+ s.syncAsSint16LE(_lookFlag);
+}
+
+/*------------------------------------------------------------------------*/
+
+MADSAction::MADSAction(MADSEngine *vm) : _vm(vm) {
+ clear();
+ _statusTextIndex = -1;
+ _selectedAction = 0;
+ _inProgress = false;
+
+ _savedFields._commandSource = 0;
+ _savedFields._mainObjectSource = 0;
+ _savedFields._command = -1;
+ _savedFields._mainObject = 0;
+ _savedFields._secondObject = 0;
+ _savedFields._secondObjectSource = 0;
+ _savedFields._articleNumber = PREP_NONE;
+ _savedFields._lookFlag = false;
+}
+
+void MADSAction::clear() {
+ _interAwaiting = AWAITING_COMMAND;
+ _commandSource = CAT_NONE;
+ _mainObjectSource = CAT_NONE;
+ _secondObjectSource = CAT_NONE;
+ _recentCommandSource = CAT_NONE;
+ _articleNumber = 0;
+ _lookFlag = false;
+ _pointEstablished = 0;
+ _statusText.clear();
+ _selectedRow = -1;
+ _hotspotId = -1;
+ _secondObject = -1;
+ _recentCommand = -1;
+ _action._verbId = VERB_NONE;
+ _action._objectNameId = -1;
+ _action._indirectObjectId = -1;
+ _textChanged = true;
+}
+
+void MADSAction::appendVocab(int vocabId, bool capitalize) {
+ Common::String vocabStr = _vm->_game->_scene.getVocab(vocabId);
+ if (capitalize)
+ vocabStr.setChar(toupper(vocabStr[0]), 0);
+
+ _statusText += vocabStr;
+ _statusText += " ";
+}
+
+void MADSAction::startWalkingDirectly(int walkType) {
+ Scene &scene = _vm->_game->_scene;
+ Player &player = _vm->_game->_player;
+
+ if (_pointEstablished && (walkType == -3 || _savedFields._command < 0)) {
+ player._needToWalk = true;
+ player._prepareWalkPos = scene._customDest;
+ }
+}
+
+void MADSAction::set() {
+ Scene &scene = _vm->_game->_scene;
+ UserInterface &userInterface = scene._userInterface;
+ _statusText = "";
+
+ _action._verbId = VERB_NONE;
+ _action._objectNameId = -1;
+ _action._indirectObjectId = -1;
+
+ if (_commandSource == CAT_TALK_ENTRY) {
+ // Handle showing the conversation selection. Rex at least doesn't actually seem to use this
+ if (_selectedRow >= 0) {
+ _action._verbId = userInterface._talkIds[_selectedRow];
+ Common::String desc = userInterface._talkStrings[_selectedRow];
+ if (!desc.empty())
+ _statusText = desc;
+ }
+ } else if (_lookFlag && (_selectedRow == 0)) {
+ // Two 'look' actions in succession, so the action becomes 'Look around'
+ _statusText = kLookAroundStr;
+ } else {
+ bool flag = false;
+ if ((_commandSource == CAT_INV_VOCAB) && (_selectedRow >= 0)
+ && (_verbType == VERB_THAT) && (_prepType == PREP_NONE)) {
+ // Use/to action
+ int invIndex = userInterface._selectedInvIndex;
+ InventoryObject &objEntry = _vm->_game->_objects.getItem(invIndex);
+
+ _action._objectNameId = objEntry._descId;
+ _action._verbId = objEntry._vocabList[_selectedRow]._vocabId;
+
+ // Set up the status text string
+ _statusText = kUseStr;
+ appendVocab(_action._objectNameId);
+ _statusText += kToStr;
+ appendVocab(_action._verbId);
+ } else {
+ // Handling for if an action has been selected
+ if (_selectedRow >= 0) {
+ if (_commandSource == CAT_COMMAND) {
+ // Standard verb action
+ _action._verbId = scene._verbList[_selectedRow]._id;
+ } else {
+ // Selected action on an inventory object
+ int invIndex = userInterface._selectedInvIndex;
+ InventoryObject &objEntry = _vm->_game->_objects.getItem(invIndex);
+
+ _action._verbId = objEntry._vocabList[_selectedRow]._vocabId;
+ }
+
+ appendVocab(_action._verbId, true);
+
+ if (_action._verbId == VERB_LOOK) {
+ // Add in the word 'add'
+ _statusText += kArticleList[PREP_AT];
+ _statusText += " ";
+ }
+ }
+
+ // Add in any necessary article if necessary
+ if ((_hotspotId >= 0) && (_selectedRow >= 0) && (_articleNumber > 0) && (_verbType == VERB_THAT)) {
+ flag = true;
+
+ _statusText += kArticleList[_articleNumber];
+ _statusText += " ";
+ }
+
+ // Handling for hotspot
+ if (_hotspotId >= 0) {
+ if (_selectedRow < 0) {
+ int verbId;
+
+ if (_hotspotId < (int)scene._hotspots.size()) {
+ // Get the verb Id from the hotspot
+ verbId = scene._hotspots[_hotspotId]._verbId;
+ } else {
+ // Get the verb Id from the scene object
+ verbId = scene._dynamicHotspots[_hotspotId - scene._hotspots.size()]._verbId;
+ }
+
+ if (verbId > 0) {
+ // Set the specified action
+ _action._verbId = verbId;
+ appendVocab(_action._verbId, true);
+ } else {
+ // Default to a standard 'walk to'
+ _action._verbId = VERB_WALKTO;
+ _statusText += kWalkToStr;
+ }
+ }
+
+ if ((_mainObjectSource == CAT_INV_LIST) || (_mainObjectSource == CAT_INV_ANIM)) {
+ // Get name from given inventory object
+ InventoryObject &invObject = _vm->_game->_objects.getItem(_hotspotId);
+ _action._objectNameId = invObject._descId;
+ } else if (_hotspotId < (int)scene._hotspots.size()) {
+ // Get name from scene hotspot
+ _action._objectNameId = scene._hotspots[_hotspotId]._vocabId;
+ } else {
+ // Get name from temporary scene hotspot
+ _action._objectNameId = scene._dynamicHotspots[_hotspotId - scene._hotspots.size()]._descId;
+ }
+ appendVocab(_action._objectNameId);
+ }
+ }
+
+ if (_secondObject >= 0) {
+ if (_secondObjectSource == CAT_INV_LIST || _secondObjectSource == CAT_INV_ANIM) {
+ InventoryObject &invObject = _vm->_game->_objects.getItem(_secondObject);
+ _action._indirectObjectId = invObject._descId;
+ } else if (_secondObject < (int)scene._hotspots.size()) {
+ _action._indirectObjectId = scene._hotspots[_secondObject]._vocabId;
+ } else {
+ _action._indirectObjectId = scene._dynamicHotspots[_secondObject - scene._hotspots.size()]._descId;
+ }
+ }
+
+ if ((_hotspotId >= 0) && (_articleNumber > 0) && !flag) {
+ if (_articleNumber == PREP_RELATIONAL) {
+ if (_secondObject >= 0) {
+ int articleNum = 0;
+
+ if ((_secondObjectSource == 2) || (_secondObjectSource == 5)) {
+ InventoryObject &invObject = _vm->_game->_objects.getItem(_hotspotId);
+ articleNum = invObject._article;
+ } else if (_hotspotId < (int)scene._hotspots.size()) {
+ articleNum = scene._hotspots[_hotspotId]._articleNumber;
+ } else {
+ articleNum = scene._dynamicHotspots[_hotspotId - scene._hotspots.size()]._articleNumber;
+ }
+
+ _statusText += kArticleList[articleNum];
+ }
+ } else if ((_articleNumber == VERB_LOOK) || (_vm->getGameID() != GType_RexNebular) ||
+ (_action._indirectObjectId >= 0 && scene._vocabStrings[_action._indirectObjectId] != kFenceStr)) {
+ // Write out the article
+ _statusText += kArticleList[_articleNumber];
+ } else {
+ // Special case for a 'fence' entry in Rex Nebular
+ _statusText += kOverStr;
+ }
+
+ _statusText += " ";
+ }
+
+ // Append object description if necessary
+ if (_secondObject >= 0)
+ appendVocab(_action._indirectObjectId);
+
+ // Remove any trailing space character
+ if (_statusText.hasSuffix(" "))
+ _statusText.deleteLastChar();
+ }
+
+ _textChanged = true;
+}
+
+void MADSAction::refresh() {
+ Scene &scene = _vm->_game->_scene;
+
+ // Exit immediately if nothing has changed
+ if (!_textChanged)
+ return;
+
+ // Remove any old copy of the status text
+ if (_statusTextIndex >= 0) {
+ scene._textDisplay.expire(_statusTextIndex);
+ _statusTextIndex = -1;
+ }
+
+ if (!_statusText.empty()) {
+ if ((_vm->_game->_screenObjects._inputMode == kInputBuildingSentences) ||
+ (_vm->_game->_screenObjects._inputMode == kInputLimitedSentences)) {
+ Font *font = _vm->_font->getFont(FONT_MAIN);
+ int textSpacing = -1;
+
+ int strWidth = font->getWidth(_statusText);
+ if (strWidth > MADS_SCREEN_WIDTH) {
+ // Too large to fit, so fall back on interface font
+ font = _vm->_font->getFont(FONT_INTERFACE);
+ strWidth = font->getWidth(_statusText, 0);
+ textSpacing = 0;
+ }
+
+ // Add a new text display entry to display the status text at the bottom of the screen area
+ _statusTextIndex = scene._textDisplay.add(160 - (strWidth / 2),
+ MADS_SCENE_HEIGHT + scene._posAdjust.y - 13, 3, textSpacing, _statusText, font);
+ }
+ }
+
+ _textChanged = false;
+}
+
+void MADSAction::startAction() {
+ Game &game = *_vm->_game;
+ Player &player = game._player;
+ Scene &scene = _vm->_game->_scene;
+ DynamicHotspots &dynHotspots = scene._dynamicHotspots;
+ Hotspots &hotspots = scene._hotspots;
+
+ player.cancelCommand();
+
+ _inProgress = true;
+ _savedFields._commandError = false;
+ _savedFields._command = _selectedRow;
+ _savedFields._mainObject = _hotspotId;
+ _savedFields._secondObject = _secondObject;
+ _savedFields._articleNumber = _articleNumber;
+ _savedFields._commandSource = _commandSource;
+ _savedFields._mainObjectSource = _mainObjectSource;
+ _savedFields._secondObjectSource = _secondObjectSource;
+ _savedFields._lookFlag = _lookFlag;
+ _activeAction = _action;
+
+ // Copy the action to be active
+ _activeAction = _action;
+ _sentence = _statusText;
+
+ if ((_mainObjectSource == CAT_HOTSPOT) && (_secondObjectSource == 4))
+ _savedFields._commandError = true;
+
+ player._needToWalk = false;
+ int hotspotId = -1;
+
+ if (!_savedFields._lookFlag && (_vm->_game->_screenObjects._inputMode != kInputConversation)) {
+ if (_savedFields._mainObjectSource == CAT_HOTSPOT)
+ hotspotId = _savedFields._mainObject;
+ else if (_secondObjectSource == 4)
+ hotspotId = _savedFields._secondObject;
+
+ if (hotspotId >= (int)hotspots.size()) {
+ DynamicHotspot &hs = dynHotspots[hotspotId - hotspots.size()];
+ if ((hs._feetPos.x == -1) || (hs._feetPos.x == -3)) {
+ startWalkingDirectly(hs._feetPos.x);
+ } else if (hs._feetPos.x == 0) {
+ player._prepareWalkFacing = hs._facing;
+ } else if (_savedFields._commandSource == CAT_NONE || hs._cursor >= CURSOR_WAIT) {
+ player._needToWalk = true;
+ player._prepareWalkPos = hs._feetPos;
+ }
+
+ player._prepareWalkFacing = hs._facing;
+ hotspotId = -1;
+ }
+ }
+
+ if (hotspotId >= 0 && hotspotId < (int)hotspots.size()) {
+ Hotspot &hs = hotspots[hotspotId];
+
+ if (hs._feetPos.x == -1 || hs._feetPos.x == -3) {
+ startWalkingDirectly(hs._feetPos.x);
+ } else if (hs._feetPos.x >= 0) {
+ if (_savedFields._commandSource == CAT_NONE || hs._cursor < CURSOR_WAIT) {
+ player._needToWalk = true;
+ player._prepareWalkPos = hs._feetPos;
+ }
+ }
+
+ player._prepareWalkFacing = hs._facing;
+ }
+
+ player._readyToWalk = player._needToWalk;
+}
+
+void MADSAction::checkAction() {
+ if (isAction(VERB_LOOK) || isAction(VERB_THROW))
+ _vm->_game->_player._needToWalk = false;
+}
+
+bool MADSAction::isAction(int verbId, int objectNameId, int indirectObjectId) {
+ if (_activeAction._verbId != verbId)
+ return false;
+ if ((objectNameId != 0) && (_activeAction._objectNameId != objectNameId))
+ return false;
+ if ((indirectObjectId != 0) && (_activeAction._indirectObjectId != indirectObjectId))
+ return false;
+
+ return true;
+}
+
+bool MADSAction::isObject(int objectNameId) {
+ return _activeAction._objectNameId == objectNameId;
+}
+
+bool MADSAction::isTarget(int objectNameId) {
+ return _activeAction._indirectObjectId == objectNameId;
+}
+
+void MADSAction::checkActionAtMousePos() {
+ Scene &scene = _vm->_game->_scene;
+ UserInterface &userInterface = scene._userInterface;
+
+ if ((userInterface._category == CAT_COMMAND || userInterface._category == CAT_INV_VOCAB) &&
+ _interAwaiting != AWAITING_COMMAND && _pickedWord >= 0) {
+ if (_recentCommandSource == userInterface._category || _recentCommand != _pickedWord ||
+ (_interAwaiting != AWAITING_THIS && _interAwaiting != 3))
+ clear();
+ else if (_selectedRow != 0 || userInterface._category != CAT_COMMAND)
+ scene._lookFlag = false;
+ else
+ scene._lookFlag = true;
+ }
+
+ if (_vm->_events->_rightMousePressed && _vm->_events->_mouseButtons) {
+ switch (userInterface._category) {
+ case CAT_COMMAND:
+ case CAT_INV_VOCAB:
+ return;
+
+ case CAT_INV_LIST:
+ case CAT_HOTSPOT:
+ case CAT_INV_ANIM:
+ if (_interAwaiting != AWAITING_THAT) {
+ if (userInterface._selectedActionIndex >= 0) {
+ _commandSource = CAT_COMMAND;
+ _selectedRow = userInterface._selectedActionIndex;
+ _verbType = scene._verbList[_selectedRow]._verbType;
+ _prepType = scene._verbList[_selectedRow]._prepType;
+ _interAwaiting = AWAITING_THIS;
+ } else if (userInterface._selectedItemVocabIdx >= 0) {
+ _commandSource = CAT_INV_VOCAB;
+ _selectedRow = userInterface._selectedItemVocabIdx;
+ int objectId = _vm->_game->_objects._inventoryList[_selectedRow];
+ InventoryObject &invObject = _vm->_game->_objects[objectId];
+
+ _verbType = invObject._vocabList[_selectedRow - 1]._verbType;
+ _prepType = invObject._vocabList[_selectedRow - 1]._prepType;
+ _mainObjectSource = CAT_INV_LIST;
+ _hotspotId = userInterface._selectedInvIndex;
+ _articleNumber = _prepType;
+
+ if ((_verbType == VERB_THIS && _prepType == PREP_NONE) ||
+ (_verbType == VERB_THAT && _prepType != PREP_NONE))
+ _interAwaiting = AWAITING_RIGHT_MOUSE;
+ else
+ _interAwaiting = AWAITING_THAT;
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ switch (_interAwaiting) {
+ case AWAITING_COMMAND:
+ _articleNumber = 0;
+ switch (userInterface._category) {
+ case CAT_COMMAND:
+ _commandSource = CAT_COMMAND;
+ _selectedRow = _pickedWord;
+ if (_selectedRow >= 0) {
+ _verbType = scene._verbList[_selectedRow]._verbType;
+ _prepType = scene._verbList[_selectedRow]._prepType;
+ }
+ break;
+
+ case CAT_INV_VOCAB:
+ _commandSource = CAT_INV_VOCAB;
+ _selectedRow = _pickedWord;
+ if (_selectedRow < 0) {
+ _hotspotId = -1;
+ _mainObjectSource = CAT_NONE;
+ } else {
+ InventoryObject &invObject = _vm->_game->_objects.getItem(userInterface._selectedInvIndex);
+ _verbType = invObject._vocabList[_selectedRow]._verbType;
+ _prepType = invObject._vocabList[_selectedRow]._prepType;
+ _hotspotId = userInterface._selectedInvIndex;
+ _mainObjectSource = CAT_INV_LIST;
+
+ if (_verbType == VERB_THAT)
+ _articleNumber = _prepType;
+ }
+ break;
+
+ case CAT_HOTSPOT:
+ _selectedRow = -1;
+ _commandSource = CAT_NONE;
+ _mainObjectSource = CAT_HOTSPOT;
+ _hotspotId = _pickedWord;
+ break;
+
+ case CAT_TALK_ENTRY:
+ _commandSource = CAT_TALK_ENTRY;
+ _selectedRow = _pickedWord;
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case AWAITING_THIS:
+ _articleNumber = 0;
+ switch (userInterface._category) {
+ case CAT_INV_LIST:
+ case CAT_HOTSPOT:
+ case CAT_INV_ANIM:
+ _mainObjectSource = userInterface._category;
+ _hotspotId = _pickedWord;
+ break;
+ default:
+ break;
+ }
+ break;
+
+ case AWAITING_THAT:
+ switch (userInterface._category) {
+ case CAT_INV_LIST:
+ case CAT_HOTSPOT:
+ case CAT_INV_ANIM:
+ _secondObjectSource = userInterface._category;
+ _secondObject = _pickedWord;
+ break;
+ default:
+ break;
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+void MADSAction::leftClick() {
+ Scene &scene = _vm->_game->_scene;
+ UserInterface &userInterface = scene._userInterface;
+ bool abortFlag = false;
+
+ if ((userInterface._category == CAT_COMMAND || userInterface._category == CAT_INV_VOCAB) &&
+ _interAwaiting != 1 && _pickedWord >= 0 &&
+ _recentCommandSource == userInterface._category && _recentCommand == _pickedWord &&
+ (_interAwaiting == 2 || userInterface._category == CAT_INV_VOCAB)) {
+ abortFlag = true;
+ if (_selectedRow == 0 && userInterface._category == CAT_COMMAND) {
+ _selectedAction = CAT_COMMAND;
+ scene._lookFlag = true;
+ } else {
+ _selectedAction = CAT_NONE;
+ scene._lookFlag = false;
+ clear();
+ }
+ }
+
+ if (abortFlag || (_vm->_events->_rightMousePressed && (userInterface._category == CAT_COMMAND ||
+ userInterface._category == CAT_INV_VOCAB)))
+ return;
+
+ switch (_interAwaiting) {
+ case AWAITING_COMMAND:
+ switch (userInterface._category) {
+ case CAT_COMMAND:
+ if (_selectedRow >= 0) {
+ if (_verbType == VERB_ONLY) {
+ _selectedAction = -1;
+ }
+ else {
+ _recentCommand = _selectedRow;
+ _recentCommandSource = _commandSource;
+ _interAwaiting = AWAITING_THIS;
+ }
+ }
+ break;
+
+ case CAT_INV_LIST:
+ if (_pickedWord >= 0) {
+ userInterface.selectObject(_pickedWord);
+ }
+ break;
+
+ case CAT_INV_VOCAB:
+ if (_selectedRow >= 0) {
+ if (_verbType != VERB_THIS || _prepType != PREP_NONE) {
+ if (_verbType != VERB_THAT || _prepType == PREP_NONE) {
+ _interAwaiting = AWAITING_THAT;
+ _articleNumber = _prepType;
+ } else {
+ _articleNumber = _prepType;
+ _selectedAction = -1;
+ }
+ } else {
+ _selectedAction = -1;
+ }
+
+ _recentCommand = _selectedRow;
+ _recentCommandSource = _commandSource;
+ }
+ break;
+
+ case CAT_HOTSPOT:
+ _recentCommand = -1;
+ _recentCommandSource = CAT_NONE;
+
+ if (_vm->_events->currentPos().y < MADS_SCENE_HEIGHT) {
+ scene._customDest = _vm->_events->currentPos() + scene._posAdjust;
+ _selectedAction = -1;
+ _pointEstablished = true;
+ }
+ break;
+
+ case CAT_TALK_ENTRY:
+ if (_selectedRow >= 0)
+ _selectedAction = -1;
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case AWAITING_THIS:
+ switch (userInterface._category) {
+ case CAT_INV_LIST:
+ case CAT_HOTSPOT:
+ case CAT_INV_ANIM:
+ if (_hotspotId >= 0) {
+ if (_prepType) {
+ _articleNumber = _prepType;
+ _interAwaiting = AWAITING_THAT;
+ } else {
+ _selectedAction = -1;
+ }
+
+ if (userInterface._category == CAT_HOTSPOT) {
+ scene._customDest = _vm->_events->mousePos() + scene._posAdjust;
+ _pointEstablished = true;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ break;
+
+ case AWAITING_THAT:
+ switch (userInterface._category) {
+ case CAT_INV_LIST:
+ case CAT_HOTSPOT:
+ case CAT_INV_ANIM:
+ if (_secondObject >= 0) {
+ _selectedAction = -1;
+
+ if (userInterface._category == CAT_HOTSPOT) {
+ if (!_pointEstablished) {
+ scene._customDest = _vm->_events->mousePos() + scene._posAdjust;
+ _pointEstablished = true;
+ }
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+void MADSAction::synchronize(Common::Serializer &s) {
+ _action.synchronize(s);
+ _activeAction.synchronize(s);
+ s.syncAsSint16LE(_articleNumber);
+ s.syncAsByte(_lookFlag);
+ s.syncAsByte(_textChanged);
+ s.syncAsSint16LE(_selectedRow);
+ s.syncAsSint16LE(_selectedAction);
+ s.syncAsSint16LE(_statusTextIndex);
+ s.syncAsSint16LE(_hotspotId);
+ _savedFields.synchronize(s);
+ s.syncString(_sentence);
+
+ s.syncAsSint16LE(_verbType);
+ s.syncAsSint16LE(_prepType);
+ s.syncAsSint16LE(_commandSource);
+ s.syncAsSint16LE(_mainObjectSource);
+ s.syncAsSint16LE(_secondObject);
+ s.syncAsSint16LE(_secondObjectSource);
+ s.syncAsSint16LE(_recentCommandSource);
+ s.syncAsSint16LE(_recentCommand);
+ s.syncAsSint16LE(_interAwaiting);
+ s.syncAsSint16LE(_pickedWord);
+ s.syncAsByte(_pointEstablished);
+ s.syncAsByte(_inProgress);
+}
+
+} // End of namespace MADS
diff --git a/engines/mads/action.h b/engines/mads/action.h
new file mode 100644
index 0000000000..3010226787
--- /dev/null
+++ b/engines/mads/action.h
@@ -0,0 +1,176 @@
+/* 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.
+ *
+ */
+
+#ifndef MADS_ACTION_H
+#define MADS_ACTION_H
+
+#include "common/scummsys.h"
+#include "common/serializer.h"
+#include "common/str.h"
+
+namespace MADS {
+
+enum TriggerMode {
+ SEQUENCE_TRIGGER_PARSER = 0, // Triggers parser
+ SEQUENCE_TRIGGER_DAEMON = 1, // Triggers step/daemon code
+ SEQUENCE_TRIGGER_PREPARE = 2 // Triggers preparser
+};
+
+enum InterAwaiting {
+ AWAITING_NONE = 0,
+ AWAITING_COMMAND = 1, // Initial state: waiting for a command verb
+ AWAITING_THIS = 2, // Waiting for object
+ AWAITING_THAT = 3, // Waiting for a second object
+ AWAITING_RIGHT_MOUSE = 4 // Waiting for mouse button release
+};
+
+enum {
+ VERB_NONE = 0,
+ VERB_LOOK = 3,
+ VERB_TAKE = 4,
+ VERB_PUSH = 5,
+ VERB_OPEN = 6,
+ VERB_PUT = 7,
+ VERB_TALKTO = 8,
+ VERB_GIVE = 9,
+ VERB_PULL = 10,
+ VERB_CLOSE = 11,
+ VERB_THROW = 12,
+ VERB_WALKTO = 13
+};
+
+enum VerbType { VERB_ONLY, VERB_THIS, VERB_THAT };
+
+enum PrepType {
+ PREP_NONE, PREP_WITH, PREP_TO, PREP_AT, PREP_FROM, PREP_ON, PREP_IN,
+ PREP_UNDER, PREP_BEHIND, PREP_RELATIONAL = 0xff
+};
+
+enum ScrCategory {
+ CAT_NONE = 0, CAT_COMMAND = 1, CAT_INV_LIST = 2, CAT_INV_VOCAB = 3,
+ CAT_HOTSPOT = 4, CAT_INV_ANIM = 5, CAT_TALK_ENTRY = 6, CAT_INV_SCROLLER = 7,
+ CAT_12 = 12
+};
+
+class MADSEngine;
+
+struct ActionDetails {
+ int _verbId;
+ int _objectNameId;
+ int _indirectObjectId;
+
+ /**
+ * Synchronize the action details
+ */
+ void synchronize(Common::Serializer &s);
+};
+
+struct ActionSavedFields {
+ bool _commandError;
+ int _commandSource;
+ int _command;
+ int _mainObject;
+ int _secondObject;
+ int _mainObjectSource;
+ int _secondObjectSource;
+ int _articleNumber;
+ int _lookFlag;
+
+ /**
+ * Synchronize the saved action details
+ */
+ void synchronize(Common::Serializer &s);
+};
+
+class MADSAction {
+private:
+ MADSEngine *_vm;
+ Common::String _statusText;
+
+ void appendVocab(int vocabId, bool capitalize = false);
+
+ void startWalkingDirectly(int walkType);
+public:
+ ActionDetails _action, _activeAction;
+ int _articleNumber;
+ bool _lookFlag;
+ int _selectedRow;
+ bool _textChanged;
+ int _selectedAction;
+ int _statusTextIndex;
+ int _hotspotId;
+ ActionSavedFields _savedFields;
+ Common::String _sentence;
+
+ VerbType _verbType;
+ PrepType _prepType;
+ ScrCategory _commandSource;
+ ScrCategory _mainObjectSource;
+ int _secondObject;
+ ScrCategory _secondObjectSource;
+ ScrCategory _recentCommandSource;
+ bool _pointEstablished;
+ int _recentCommand;
+ InterAwaiting _interAwaiting;
+ bool _inProgress;
+ int _pickedWord;
+
+public:
+ MADSAction(MADSEngine *vm);
+
+ void clear();
+ void set();
+ const Common::String &statusText() const { return _statusText; }
+ void refresh();
+
+ /**
+ * Accepts the currently defined sentence from the ScreenObjects parser.
+ * Copies the data, and checks to see if the action requires the player
+ * to walk to the given hotspot.
+ */
+ void startAction();
+
+ void checkAction();
+ bool isAction(int verbId, int objectNameId = 0, int indirectObjectId = 0);
+ bool isObject(int objectNameId);
+ bool isTarget(int objectNameId);
+
+ /**
+ * Check the result of the current action on the sentence
+ * with the provision that the action is not yet complete.
+ */
+ void checkActionAtMousePos();
+
+ /**
+ * Execute a click within the scene
+ */
+ void leftClick();
+
+ /**
+ * Synchronize the saved action details
+ */
+ void synchronize(Common::Serializer &s);
+};
+
+} // End of namespace MADS
+
+#endif /* MADS_ACTION_H */
diff --git a/engines/mads/animation.cpp b/engines/mads/animation.cpp
new file mode 100644
index 0000000000..ac8c9969b7
--- /dev/null
+++ b/engines/mads/animation.cpp
@@ -0,0 +1,574 @@
+/* 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 "mads/animation.h"
+#include "mads/compression.h"
+
+#define FILENAME_SIZE 13
+
+namespace MADS {
+
+void AAHeader::load(Common::SeekableReadStream *f) {
+ _spriteSetsCount = f->readUint16LE();
+ _miscEntriesCount = f->readUint16LE();
+ _frameEntriesCount = f->readUint16LE();
+ _messagesCount = f->readUint16LE();
+ f->skip(1);
+ _flags = f->readByte();
+
+ f->skip(2);
+ _bgType = (AnimBgType)f->readUint16LE();
+ _roomNumber = f->readUint16LE();
+ f->skip(2);
+ _manualFlag = f->readUint16LE() != 0;
+ _spritesIndex = f->readUint16LE();
+ _scrollPosition.x = f->readSint16LE();
+ _scrollPosition.y = f->readSint16LE();
+ _scrollTicks = f->readUint32LE();
+ f->skip(6);
+
+ char buffer[FILENAME_SIZE];
+ f->read(buffer, FILENAME_SIZE);
+ buffer[FILENAME_SIZE - 1] = '\0';
+ _interfaceFile = Common::String(buffer);
+
+ for (int i = 0; i < 50; ++i) {
+ f->read(buffer, FILENAME_SIZE);
+ buffer[FILENAME_SIZE - 1] = '\0';
+ if (i < _spriteSetsCount)
+ _spriteSetNames.push_back(Common::String(buffer));
+ }
+
+ f->read(buffer, FILENAME_SIZE);
+ buffer[FILENAME_SIZE - 1] = '\0';
+ _soundName = Common::String(buffer);
+
+ f->skip(13);
+ f->read(buffer, FILENAME_SIZE);
+ buffer[FILENAME_SIZE - 1] = '\0';
+ _dsrName = Common::String(buffer);
+
+ f->read(buffer, FILENAME_SIZE);
+ buffer[FILENAME_SIZE - 1] = '\0';
+ _fontResource = Common::String(buffer);
+}
+
+/*------------------------------------------------------------------------*/
+
+void AnimMessage::load(Common::SeekableReadStream *f) {
+ _soundId = f->readSint16LE();
+
+ char buffer[64];
+ f->read(&buffer[0], 64);
+ _msg = Common::String(buffer);
+ f->skip(4);
+ _pos.x = f->readSint16LE();
+ _pos.y = f->readSint16LE();
+ _flags = f->readUint16LE();
+ _rgb1[0] = f->readByte() << 2;
+ _rgb1[1] = f->readByte() << 2;
+ _rgb1[2] = f->readByte() << 2;
+ _rgb2[0] = f->readByte() << 2;
+ _rgb2[1] = f->readByte() << 2;
+ _rgb2[2] = f->readByte() << 2;
+ f->skip(2); // Space for kernelMsgIndex
+ _kernelMsgIndex = -1;
+ f->skip(6);
+ _startFrame = f->readUint16LE();
+ _endFrame = f->readUint16LE();
+ f->skip(2);
+}
+
+void AnimFrameEntry::load(Common::SeekableReadStream *f, bool uiFlag) {
+ if (uiFlag) {
+ f->skip(2);
+ _frameNumber = -1; // Unused
+ _seqIndex = f->readByte();
+ _spriteSlot._spritesIndex = f->readByte();
+ _spriteSlot._frameNumber = (int8)f->readByte();
+ f->skip(1);
+ _spriteSlot._position.x = f->readSint16LE();
+ _spriteSlot._position.y = f->readSint16LE();
+ } else {
+ _frameNumber = f->readUint16LE();
+ _seqIndex = f->readByte();
+ _spriteSlot._spritesIndex = f->readByte();
+ _spriteSlot._frameNumber = f->readSint16LE();
+ _spriteSlot._position.x = f->readSint16LE();
+ _spriteSlot._position.y = f->readSint16LE();
+ _spriteSlot._depth = f->readSByte();
+ _spriteSlot._scale = (int8)f->readByte();
+ }
+}
+
+/*------------------------------------------------------------------------*/
+
+void AnimMiscEntry::load(Common::SeekableReadStream *f) {
+ _soundId = f->readByte();
+ _msgIndex = f->readSByte();
+ _numTicks = f->readUint16LE();
+ _posAdjust.x = f->readSint16LE();
+ _posAdjust.y = f->readSint16LE();
+ _field8 = f->readUint16LE();
+}
+
+/*------------------------------------------------------------------------*/
+
+void AnimUIEntry::load(Common::SeekableReadStream *f) {
+ _probability = f->readUint16LE();
+ _imageCount = f->readUint16LE();
+ _firstImage = f->readUint16LE();
+ _lastImage = f->readUint16LE();
+ _counter = f->readSint16LE();
+ for (int i = 0; i < ANIM_SPAWN_COUNT; ++i)
+ _spawn[i] = f->readByte();
+ for (int i = 0; i < ANIM_SPAWN_COUNT; ++i)
+ _spawnFrame[i] = f->readUint16LE();
+ _sound = f->readUint16LE() & 0xFF;
+ _soundFrame = f->readUint16LE();
+}
+
+/*------------------------------------------------------------------------*/
+
+Animation *Animation::init(MADSEngine *vm, Scene *scene) {
+ return new Animation(vm, scene);
+}
+
+Animation::Animation(MADSEngine *vm, Scene *scene) : _vm(vm), _scene(scene) {
+ _font = nullptr;
+ _resetFlag = false;
+ _messageCtr = 0;
+ _skipLoad = false;
+}
+
+Animation::~Animation() {
+ Scene &scene = _vm->_game->_scene;
+
+ if (_header._manualFlag)
+ scene._sprites.remove(_spriteListIndexes[_header._spritesIndex]);
+
+ for (int idx = 0; idx < _header._spriteSetsCount; ++idx) {
+ if (!_header._manualFlag || _header._spritesIndex != idx)
+ scene._sprites.remove(_spriteListIndexes[idx]);
+ }
+}
+
+void Animation::load(UserInterface &interfaceSurface, DepthSurface &depthSurface,
+ const Common::String &resName, int flags, Common::Array<PaletteCycle> *palCycles,
+ SceneInfo *sceneInfo) {
+ Common::String resourceName = resName;
+ if (!resourceName.contains("."))
+ resourceName += ".AA";
+
+ File f(resourceName);
+ MadsPack madsPack(&f);
+
+ Common::SeekableReadStream *stream = madsPack.getItemStream(0);
+ _header.load(stream);
+ delete stream;
+
+ if (_header._bgType == ANIMBG_INTERFACE)
+ flags |= PALFLAG_RESERVED;
+
+ if (flags & ANIMFLAG_LOAD_BACKGROUND) {
+ loadInterface(interfaceSurface, depthSurface, _header, flags, palCycles, sceneInfo);
+ }
+ if (flags & ANIMFLAG_LOAD_BACKGROUND_ONLY) {
+ // No data
+ _header._messagesCount = 0;
+ _header._frameEntriesCount = 0;
+ _header._miscEntriesCount = 0;
+ }
+
+ // Initialize the reference list
+ _spriteListIndexes.clear();
+ for (int i = 0; i < _header._spriteSetsCount; ++i)
+ _spriteListIndexes.push_back(-1);
+
+ int streamIndex = 1;
+ _messages.clear();
+ if (_header._messagesCount > 0) {
+ // Chunk 2: Following is a list of any messages for the animation
+ Common::SeekableReadStream *msgStream = madsPack.getItemStream(streamIndex++);
+
+ for (int i = 0; i < _header._messagesCount; ++i) {
+ AnimMessage rec;
+ rec.load(msgStream);
+ _messages.push_back(rec);
+ }
+
+ delete msgStream;
+ }
+
+ _frameEntries.clear();
+ if (_header._frameEntriesCount > 0) {
+ // Chunk 3: animation frame info
+ Common::SeekableReadStream *frameStream = madsPack.getItemStream(streamIndex++);
+
+ for (int i = 0; i < _header._frameEntriesCount; i++) {
+ AnimFrameEntry rec;
+ rec.load(frameStream, flags & ANIMFLAG_LOAD_BACKGROUND);
+ _frameEntries.push_back(rec);
+ }
+
+ delete frameStream;
+ }
+
+ _miscEntries.clear();
+ _uiEntries.clear();
+ if (_header._miscEntriesCount > 0) {
+ // Chunk 4: Misc Data
+ Common::SeekableReadStream *miscStream = madsPack.getItemStream(streamIndex++);
+
+ if (flags & ANIMFLAG_LOAD_BACKGROUND) {
+ for (int i = 0; i < _header._miscEntriesCount; ++i) {
+ AnimUIEntry rec;
+ rec.load(miscStream);
+ _uiEntries.push_back(rec);
+ }
+ } else {
+ for (int i = 0; i < _header._miscEntriesCount; ++i) {
+ AnimMiscEntry rec;
+ rec.load(miscStream);
+ _miscEntries.push_back(rec);
+ }
+ }
+
+ delete miscStream;
+ }
+
+ // If the animation specifies a font, then load it for access
+ delete _font;
+ if (_header._flags & ANIMFLAG_CUSTOM_FONT) {
+ Common::String fontName = "*" + _header._fontResource;
+ _font = _vm->_font->getFont(fontName.c_str());
+ } else {
+ _font = nullptr;
+ }
+
+ // Load all the sprite sets for the animation
+ for (uint i = 0; i < _spriteSets.size(); ++i)
+ delete _spriteSets[i];
+ _spriteSets.clear();
+ _spriteSets.resize(_header._spriteSetsCount);
+
+ for (int i = 0; i < _header._spriteSetsCount; ++i) {
+ if (_header._manualFlag && (i == _header._spritesIndex)) {
+ // Skip over field, since it's manually loaded
+ _spriteSets[i] = nullptr;
+ } else {
+ _spriteSets[i] = new SpriteAsset(_vm, _header._spriteSetNames[i], flags);
+ _spriteListIndexes[i] = _vm->_game->_scene._sprites.add(_spriteSets[i]);
+ }
+ }
+
+ if (_header._manualFlag) {
+ Common::String assetResName = "*" + _header._spriteSetNames[_header._spritesIndex];
+ SpriteAsset *sprites = new SpriteAsset(_vm, assetResName, flags);
+ _spriteSets[_header._spritesIndex] = sprites;
+
+ _spriteListIndexes[_header._spritesIndex] = _scene->_sprites.add(sprites);
+ }
+
+ Common::Array<int> usageList;
+ for (int idx = 0; idx < _header._spriteSetsCount; ++idx)
+ usageList.push_back(_spriteSets[idx]->_usageIndex);
+
+ if (usageList.size() > 0)
+ _vm->_palette->_paletteUsage.updateUsage(usageList, _header._messagesCount);
+
+ // Remaps the sprite list indexes for frames to the loaded sprite list indexes
+ for (uint i = 0; i < _frameEntries.size(); ++i) {
+ int spriteListIndex = _frameEntries[i]._spriteSlot._spritesIndex;
+ _frameEntries[i]._spriteSlot._spritesIndex = _spriteListIndexes[spriteListIndex];
+ }
+
+ f.close();
+}
+
+void Animation::preLoad(const Common::String &resName, int level) {
+ // No implementation in ScummVM, since access is fast enough that data
+ // doesn't need to be preloaded
+}
+
+void Animation::startAnimation(int endTrigger) {
+ _messageCtr = 0;
+ _skipLoad = true;
+
+ if (_header._manualFlag) {
+ _unkIndex = -1;
+ //SpriteAsset *asset = _scene->_sprites[_spriteListIndexes[_header._spritesIndex]];
+
+ // TODO: Weird stuff with _unkList. Seems like it's treated as pointers
+ // here, but in processText, it's used as POINTs?
+
+ loadFrame(1);
+ }
+
+ if (_vm->_game->_kernelMode == KERNEL_ACTIVE_CODE)
+ _vm->_palette->refreshSceneColors();
+
+ _currentFrame = 0;
+ _oldFrameEntry = 0;
+ _nextFrameTimer = _vm->_game->_scene._frameStartTime;
+ _trigger = endTrigger;
+ _triggerMode = _vm->_game->_triggerSetupMode;
+ _actionDetails = _vm->_game->_scene._action._activeAction;
+
+ for (int idx = 0; idx < _header._messagesCount; ++idx) {
+ _messages[idx]._kernelMsgIndex = -1;
+ }
+}
+
+void Animation::loadFrame(int frameNumber) {
+ Scene &scene = _vm->_game->_scene;
+ if (_skipLoad)
+ return;
+
+ Common::Point pt;
+ int spriteListIndex = _spriteListIndexes[_header._spritesIndex];
+ SpriteAsset &spriteSet = *scene._sprites[spriteListIndex];
+
+ if (_unkIndex < 0) {
+ MSurface *frame = spriteSet.getFrame(0);
+ pt.x = frame->getBounds().left;
+ pt.y = frame->getBounds().top;
+ } else {
+ pt.x = _unkList[_unkIndex].x;
+ pt.y = _unkList[_unkIndex].y;
+ _unkIndex = 1 - _unkIndex;
+ }
+
+ if (drawFrame(spriteSet, pt, frameNumber))
+ error("drawFrame failure");
+}
+
+bool Animation::drawFrame(SpriteAsset &spriteSet, const Common::Point &pt, int frameNumber) {
+ return 0;
+}
+
+void Animation::loadInterface(UserInterface &interfaceSurface, DepthSurface &depthSurface,
+ AAHeader &header, int flags, Common::Array<PaletteCycle> *palCycles, SceneInfo *sceneInfo) {
+ _scene->_depthStyle = 0;
+ if (header._bgType <= ANIMBG_FULL_SIZE) {
+ _vm->_palette->_paletteUsage.setEmpty();
+ sceneInfo->load(header._roomNumber, flags, header._interfaceFile, 0, depthSurface, interfaceSurface);
+ _scene->_depthStyle = sceneInfo->_depthStyle == 2 ? 1 : 0;
+ if (palCycles) {
+ palCycles->clear();
+ for (uint i = 0; i < sceneInfo->_paletteCycles.size(); ++i)
+ palCycles->push_back(sceneInfo->_paletteCycles[i]);
+ }
+ } else if (header._bgType == ANIMBG_INTERFACE) {
+ // Load a scene interface
+ Common::String resourceName = "*" + header._interfaceFile;
+ interfaceSurface.load(resourceName);
+
+ if (palCycles)
+ palCycles->clear();
+ } else {
+ // Original has useless code here
+ }
+}
+
+bool Animation::hasScroll() const {
+ return (_header._scrollPosition.x != 0) || (_header._scrollPosition.y != 0);
+}
+
+void Animation::update() {
+ Scene &scene = _vm->_game->_scene;
+
+ if (_header._manualFlag) {
+ int spriteListIndex = _spriteListIndexes[_header._spritesIndex];
+ int newIndex = -1;
+
+ for (uint idx = _oldFrameEntry; idx < _frameEntries.size(); ++idx) {
+ if (_frameEntries[idx]._frameNumber > _currentFrame)
+ break;
+ if (_frameEntries[idx]._spriteSlot._spritesIndex == spriteListIndex)
+ newIndex = _frameEntries[idx]._spriteSlot._frameNumber;
+ }
+
+ if (newIndex >= 0)
+ loadFrame(newIndex);
+ }
+
+ // If it's not time for the next frame, then exit
+ if (_vm->_game->_scene._frameStartTime < _nextFrameTimer)
+ return;
+
+ for (uint idx = 0; idx < scene._spriteSlots.size(); ++idx) {
+ if (scene._spriteSlots[idx]._seqIndex >= 0x80)
+ scene._spriteSlots[idx]._flags = IMG_ERASE;
+ }
+
+ // Validate the current frame
+ if (_currentFrame >= (int)_miscEntries.size()) {
+ // Is the animation allowed to be repeated?
+ if (_resetFlag) {
+ _currentFrame = 0;
+ _oldFrameEntry = 0;
+ } else {
+ _freeFlag = true;
+ return;
+ }
+ }
+
+ // Handle executing any sound command for this frame
+ AnimMiscEntry &misc = _miscEntries[_currentFrame];
+ if (misc._soundId)
+ _vm->_sound->command(misc._soundId);
+
+ // Handle any screen scrolling
+ if (hasScroll()) {
+ scene._backgroundSurface.scrollX(_header._scrollPosition.x);
+ scene._backgroundSurface.scrollY(_header._scrollPosition.y);
+ scene._spriteSlots.fullRefresh();
+ }
+
+ // Handle any offset adjustment for sprites as of this frame
+ bool paChanged = false;
+ if (scene._posAdjust.x != misc._posAdjust.x) {
+ scene._posAdjust.x = misc._posAdjust.x;
+ paChanged = true;
+ }
+ if (scene._posAdjust.y != misc._posAdjust.y) {
+ scene._posAdjust.y = misc._posAdjust.y;
+ paChanged = true;
+ }
+
+ if (paChanged) {
+ int newIndex = scene._spriteSlots.add();
+ scene._spriteSlots[newIndex]._seqIndex = -1;
+ scene._spriteSlots[newIndex]._flags = IMG_REFRESH;
+ }
+
+ // Main frame animation loop - frames get animated by being placed, as necessary, into the
+ // main sprite slot array
+ while ((uint)_oldFrameEntry < _frameEntries.size()) {
+ if (_frameEntries[_oldFrameEntry]._frameNumber > _currentFrame)
+ break;
+ else if (_frameEntries[_oldFrameEntry]._frameNumber == _currentFrame) {
+ // Found the correct frame
+ int spriteSlotIndex = 0;
+ int index = 0;
+
+ for (;;) {
+ if ((spriteSlotIndex == 0) && (index < (int)scene._spriteSlots.size())) {
+ int seqIndex = _frameEntries[_oldFrameEntry]._seqIndex - scene._spriteSlots[index]._seqIndex;
+ if (seqIndex == 0x80) {
+ if (scene._spriteSlots[index] == _frameEntries[_oldFrameEntry]._spriteSlot) {
+ scene._spriteSlots[index]._flags = IMG_STATIC;
+ spriteSlotIndex = -1;
+ }
+ }
+ ++index;
+ continue;
+ }
+
+ if (spriteSlotIndex == 0) {
+ int slotIndex = scene._spriteSlots.add();
+ SpriteSlot &slot = scene._spriteSlots[slotIndex];
+ slot.copy(_frameEntries[_oldFrameEntry]._spriteSlot);
+ slot._seqIndex = _frameEntries[_oldFrameEntry]._seqIndex + 0x80;
+
+ SpriteAsset &spriteSet = *scene._sprites[
+ scene._spriteSlots[slotIndex]._spritesIndex];
+ slot._flags = spriteSet.isBackground() ? IMG_DELTA : IMG_UPDATE;
+ }
+ break;
+ }
+ }
+
+ ++_oldFrameEntry;
+ }
+
+ // Handle the display of any messages
+ for (uint idx = 0; idx < _messages.size(); ++idx) {
+ if (_messages[idx]._kernelMsgIndex >= 0) {
+ // Handle currently active message
+ if ((_currentFrame < _messages[idx]._startFrame) || (_currentFrame > _messages[idx]._endFrame)) {
+ scene._kernelMessages.remove(_messages[idx]._kernelMsgIndex);
+ _messages[idx]._kernelMsgIndex = -1;
+ --_messageCtr;
+ }
+ } else if ((_currentFrame >= _messages[idx]._startFrame) && (_currentFrame <= _messages[idx]._endFrame)) {
+ // Start displaying the message
+ AnimMessage &me = _messages[idx];
+
+ // The color index to use is dependant on how many messages are currently on-screen
+ uint8 colIndex;
+ switch (_messageCtr) {
+ case 1:
+ colIndex = 252;
+ break;
+ case 2:
+ colIndex = 16;
+ break;
+ default:
+ colIndex = 250;
+ break;
+ }
+
+ _vm->_palette->setEntry(colIndex, me._rgb1[0], me._rgb1[1], me._rgb1[2]);
+ _vm->_palette->setEntry(colIndex + 1, me._rgb2[0], me._rgb2[1], me._rgb2[2]);
+
+ // Add a kernel message to display the given text
+ me._kernelMsgIndex = scene._kernelMessages.add(me._pos, colIndex * 0x101 + 0x100,
+ 0, 0, INDEFINITE_TIMEOUT, me._msg);
+ assert(me._kernelMsgIndex >= 0);
+ ++_messageCtr;
+ }
+ }
+
+ // Move to the next frame
+ _currentFrame++;
+ if (_currentFrame >= (int)_miscEntries.size()) {
+ // Animation is complete
+ if (_trigger != 0) {
+ _vm->_game->_trigger = _trigger;
+ _vm->_game->_triggerMode = _triggerMode;
+
+ if (_triggerMode != SEQUENCE_TRIGGER_DAEMON) {
+ // Copy the noun list
+ scene._action._activeAction = _actionDetails;
+ }
+ }
+ }
+
+ int frameNum = MIN(_currentFrame, (int)_miscEntries.size() - 1);
+ _nextFrameTimer = _vm->_game->_scene._frameStartTime + _miscEntries[frameNum]._numTicks;
+}
+
+void Animation::setCurrentFrame(int frameNumber) {
+ _currentFrame = frameNumber;
+ _oldFrameEntry = 0;
+ _freeFlag = false;
+
+ _nextScrollTimer = _nextFrameTimer = _vm->_game->_scene._frameStartTime;
+}
+
+void Animation::setNextFrameTimer(int frameNumber) {
+ _nextFrameTimer = frameNumber;
+}
+
+} // End of namespace MADS
diff --git a/engines/mads/animation.h b/engines/mads/animation.h
new file mode 100644
index 0000000000..15086d3e41
--- /dev/null
+++ b/engines/mads/animation.h
@@ -0,0 +1,230 @@
+/* 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.
+ *
+ */
+
+#ifndef MADS_ANIMATION_H
+#define MADS_ANIMATION_H
+
+#include "common/scummsys.h"
+#include "common/array.h"
+#include "common/rect.h"
+#include "mads/msurface.h"
+#include "mads/scene_data.h"
+#include "mads/font.h"
+#include "mads/user_interface.h"
+
+namespace MADS {
+
+enum AnimFlag {
+ ANIMFLAG_DITHER = 0x0001, // Dither to 16 colors
+ ANIMFLAG_CUSTOM_FONT = 0x0020, // Load ccustom font
+ ANIMFLAG_LOAD_BACKGROUND = 0x0100, // Load background
+ ANIMFLAG_LOAD_BACKGROUND_ONLY = 0x0200 // Load background only
+};
+
+enum AnimBgType {
+ ANIMBG_ROOM = 1, ANIMBG_FULL_SIZE = 2, ANIMBG_BLACK_SCREEN = 3,
+ ANIMBG_INTERFACE = 4
+};
+
+class MADSEngine;
+class Scene;
+
+class AnimMessage {
+public:
+ int16 _soundId;
+ Common::String _msg;
+ Common::Point _pos;
+ byte _rgb1[3], _rgb2[3];
+ int _flags;
+ int _startFrame, _endFrame;
+ int _kernelMsgIndex;
+
+ /**
+ * Loads data for the message from a stream
+ */
+ void load(Common::SeekableReadStream *f);
+};
+
+class AnimFrameEntry {
+public:
+ int _frameNumber;
+ int _seqIndex;
+ SpriteSlotSubset _spriteSlot;
+
+ /**
+ * Loads data for the record
+ */
+ void load(Common::SeekableReadStream *f, bool uiFlag);
+};
+
+class AnimMiscEntry {
+public:
+ int _soundId;
+ int _msgIndex;
+ int _numTicks;
+ Common::Point _posAdjust;
+ int _field8;
+
+ /**
+ * Loads data for the record
+ */
+ void load(Common::SeekableReadStream *f);
+};
+
+#define ANIM_SPAWN_COUNT 2
+
+class AnimUIEntry {
+public:
+ int _probability;
+ int _imageCount;
+ int _firstImage;
+ int _lastImage;
+ int _counter;
+ int _spawn[ANIM_SPAWN_COUNT];
+ int _spawnFrame[ANIM_SPAWN_COUNT];
+ int _sound;
+ int _soundFrame;
+
+ /**
+ * Loads the data for the record
+ */
+ void load(Common::SeekableReadStream *f);
+};
+
+class AAHeader {
+public:
+ int _spriteSetsCount;
+ int _miscEntriesCount;
+ int _frameEntriesCount;
+ int _messagesCount;
+ byte _flags;
+ AnimBgType _bgType;
+ int _roomNumber;
+ bool _manualFlag;
+ int _spritesIndex;
+ Common::Point _scrollPosition;
+ uint32 _scrollTicks;
+ Common::String _interfaceFile;
+ Common::StringArray _spriteSetNames;
+ Common::String _lbmFilename;
+ Common::String _spritesFilename;
+ Common::String _soundName;
+ Common::String _dsrName;
+ Common::String _fontResource;
+
+ /**
+ * Loads the data for a animation file header
+ */
+ void load(Common::SeekableReadStream *f);
+};
+
+class Animation {
+private:
+ MADSEngine *_vm;
+ Scene *_scene;
+
+ Common::Array<AnimMiscEntry> _miscEntries;
+ Common::Array<SpriteAsset *> _spriteSets;
+ Font *_font;
+
+ bool _freeFlag;
+ bool _skipLoad;
+ int _unkIndex;
+ Common::Point _unkList[2];
+ uint32 _nextFrameTimer;
+ uint32 _nextScrollTimer;
+ int _messageCtr;
+ int _trigger;
+ TriggerMode _triggerMode;
+ ActionDetails _actionDetails;
+
+ /**
+ * Load data for a given frame
+ * @param frameNumber Frame number
+ */
+ void loadFrame(int frameNumber);
+
+ bool drawFrame(SpriteAsset &spriteSet, const Common::Point &pt, int frameNumber);
+
+ /**
+ * Load the user interface display for an animation
+ */
+ void loadInterface(UserInterface &interfaceSurface, DepthSurface &depthSurface,
+ AAHeader &header, int flags, Common::Array<PaletteCycle> *palCycles, SceneInfo *sceneInfo);
+
+ /**
+ * Returns true if there is a scroll required
+ */
+ bool hasScroll() const;
+protected:
+ Animation(MADSEngine *vm, Scene *scene);
+public:
+ AAHeader _header;
+ Common::Array<int> _spriteListIndexes;
+ Common::Array<AnimFrameEntry> _frameEntries;
+ Common::Array<AnimUIEntry> _uiEntries;
+ Common::Array<AnimMessage> _messages;
+ bool _resetFlag;
+ int _currentFrame;
+ int _oldFrameEntry;
+
+ static Animation *init(MADSEngine *vm, Scene *scene);
+ /*
+ * Destructor
+ */
+ ~Animation();
+
+ /**
+ * Loads animation data
+ */
+ void load(UserInterface &interfaceSurface, DepthSurface &depthSurface, const Common::String &resName,
+ int flags, Common::Array<PaletteCycle> *palCycles, SceneInfo *sceneInfo);
+
+ /**
+ * Preload animation data for the scene
+ */
+ void preLoad(const Common::String &resName, int level);
+
+ /**
+ * Setups up a loaded animation for playback
+ */
+ void startAnimation(int endTrigger);
+
+ /**
+ * Update the animation
+ */
+ void update();
+
+ void setNextFrameTimer(int frameNumber);
+ int getNextFrameTimer() const { return _nextFrameTimer; }
+ void setCurrentFrame(int frameNumber);
+ int getCurrentFrame() const { return _currentFrame; }
+
+ bool freeFlag() const { return _freeFlag; }
+ int roomNumber() const { return _header._roomNumber; }
+
+ void resetSpriteSetsCount() { _header._spriteSetsCount = 0; } // CHECKME: See if it doesn't leak the memory when the destructor is called
+};
+
+} // End of namespace MADS
+
+#endif /* MADS_ANIMATION_H */
diff --git a/engines/mads/assets.cpp b/engines/mads/assets.cpp
new file mode 100644
index 0000000000..1cb174bbed
--- /dev/null
+++ b/engines/mads/assets.cpp
@@ -0,0 +1,227 @@
+/* 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 "mads/mads.h"
+#include "mads/assets.h"
+#include "mads/compression.h"
+#include "mads/events.h"
+#include "mads/palette.h"
+
+namespace MADS {
+
+SpriteAsset::SpriteAsset(MADSEngine *vm, const Common::String &resourceName, int flags) :
+ _vm(vm) {
+ Common::String resName = resourceName;
+ if (!resName.hasSuffix(".SS") && !resName.hasSuffix(".ss"))
+ resName += ".SS";
+
+ File file(resName);
+ load(&file, flags);
+
+ file.close();
+}
+
+SpriteAsset::SpriteAsset(MADSEngine *vm, Common::SeekableReadStream *stream, int flags) :
+ _vm(vm) {
+ load(stream, flags);
+}
+
+SpriteAsset::~SpriteAsset() {
+ if (_usageIndex)
+ _vm->_palette->_paletteUsage.resetPalFlags(_usageIndex);
+
+ for (uint i = 0; i < _frames.size(); ++i)
+ delete _frames[i]._frame;
+
+ delete _charInfo;
+}
+
+void SpriteAsset::load(Common::SeekableReadStream *stream, int flags) {
+ int curFrame = 0;
+ uint32 frameOffset = 0;
+ MadsPack sprite(stream);
+ _frameRate = 0;
+ _pixelSpeed = 0;
+ _maxWidth = 0;
+ _maxHeight = 0;
+ _usageIndex = -1;
+
+ Common::SeekableReadStream *spriteStream = sprite.getItemStream(0);
+ _mode = spriteStream->readByte();
+ spriteStream->skip(1);
+ int type1 = spriteStream->readUint16LE();
+ int type2 = spriteStream->readUint16LE();
+ _isBackground = (type1 != 0) && (type2 < 4);
+ spriteStream->skip(32);
+ _frameCount = spriteStream->readUint16LE();
+
+ if ((flags & SPRITE_SET_CHAR_INFO) == 0)
+ _charInfo = nullptr;
+ else
+ _charInfo = new SpriteSetCharInfo(spriteStream);
+
+ delete spriteStream;
+
+ // Get the palette data
+ Common::SeekableReadStream *palStream = sprite.getItemStream(2);
+ Common::Array<RGB6> palette;
+
+ int numColors = palStream->readUint16LE();
+ assert(numColors <= 252);
+ _colorCount = numColors;
+
+ // Load in the palette
+ palette.resize(numColors);
+ for (int i = 0; i < numColors; ++i)
+ palette[i].load(palStream);
+ delete palStream;
+
+ // Process the palette data
+ if (flags & 9) {
+ _usageIndex = 0;
+
+ if (flags & 8) {
+ int newPalCtr = 0;
+
+ for (uint i = 0; i < palette.size(); ++i) {
+ RGB6 &rgb = palette[i];
+
+ // Scan for existing rgb at beginning of the main palette
+ bool found = false;
+ for (int pIndex = 0; pIndex < 4 && !found; ++pIndex) {
+ byte *palP = &_vm->_palette->_mainPalette[pIndex * 3];
+ if (palP[0] == rgb.r && palP[1] == rgb.g && palP[2] == rgb.b) {
+ rgb._palIndex = pIndex;
+ found = true;
+ }
+ }
+
+ if (!found) {
+ // Existing palette entry not found, so need to add it in
+ int palIndex = (0xF7F607 >> (8 * newPalCtr)) & 0xff;
+ byte *palP = &_vm->_palette->_mainPalette[palIndex * 3];
+ palP[0] = rgb.r;
+ palP[1] = rgb.g;
+ palP[2] = rgb.b;
+ rgb._palIndex = palIndex;
+
+ newPalCtr = MIN(newPalCtr + 1, 2);
+ }
+ }
+ }
+ } else {
+ _usageIndex = _vm->_palette->_paletteUsage.process(palette, flags);
+ assert(_usageIndex >= 0);
+ }
+
+ spriteStream = sprite.getItemStream(1);
+ Common::SeekableReadStream *spriteDataStream = sprite.getItemStream(3);
+ SpriteAssetFrame frame;
+ Common::Array<int> frameSizes;
+ for (curFrame = 0; curFrame < _frameCount; curFrame++) {
+ frame._stream = 0;
+ frame._comp = 0;
+ frameOffset = spriteStream->readUint32LE();
+ _frameOffsets.push_back(frameOffset);
+ uint32 frameSize = spriteStream->readUint32LE();
+ frameSizes.push_back(frameSize);
+
+ frame._bounds.left = spriteStream->readSint16LE();
+ frame._bounds.top = spriteStream->readSint16LE();
+ frame._bounds.setWidth(spriteStream->readUint16LE());
+ frame._bounds.setHeight(spriteStream->readUint16LE());
+
+ if (curFrame == 0)
+ debugC(1, kDebugGraphics, "%i frames, x = %i, y = %i, w = %i, h = %i\n",
+ _frameCount, frame._bounds.left, frame._bounds.top,
+ frame._bounds.width(), frame._bounds.height());
+
+ if (_mode == 0) {
+ // Create a frame and decompress the raw pixel data
+ uint32 currPos = (uint32)spriteDataStream->pos();
+ frame._frame = new MSprite(spriteDataStream, palette, frame._bounds);
+ assert((uint32)spriteDataStream->pos() == (currPos + frameSize));
+ }
+
+ _frames.push_back(frame);
+ }
+
+ if (_mode != 0) {
+ // Handle decompressing Fab encoded data
+ for (curFrame = 0; curFrame < _frameCount; curFrame++) {
+ FabDecompressor fab;
+
+ int srcSize = (curFrame == (_frameCount - 1)) ? spriteDataStream->size() - _frameOffsets[curFrame] :
+ _frameOffsets[curFrame + 1] - _frameOffsets[curFrame];
+ byte *srcData = new byte[srcSize];
+ assert(srcData);
+ spriteDataStream->read(srcData, srcSize);
+
+ byte *destData = new byte[frameSizes[curFrame]];
+ assert(destData);
+
+ fab.decompress(srcData, srcSize, destData, frameSizes[curFrame]);
+
+ // Load the frames
+ Common::MemoryReadStream *rs = new Common::MemoryReadStream(destData, frameSizes[curFrame]);
+ _frames[curFrame]._frame = new MSprite(rs, palette, _frames[curFrame]._bounds);
+ delete rs;
+
+ delete[] srcData;
+ delete[] destData;
+ }
+ }
+
+ delete spriteStream;
+ delete spriteDataStream;
+}
+
+MSprite *SpriteAsset::getFrame(int frameIndex) {
+ if ((uint)frameIndex < _frames.size()) {
+ return _frames[frameIndex]._frame;
+ } else {
+ debugC(kDebugGraphics, "SpriteAsset::getFrame: Invalid frame %d, out of %d", frameIndex, _frames.size());
+ return _frames[_frames.size() - 1]._frame;
+ }
+}
+
+/*------------------------------------------------------------------------*/
+
+SpriteSetCharInfo::SpriteSetCharInfo(Common::SeekableReadStream *s) {
+ _totalFrames = s->readByte();
+ s->skip(1);
+ _numEntries = s->readUint16LE();
+
+ for (int i = 0; i < 16; ++i)
+ _startFrames[i] = s->readUint16LE();
+ for (int i = 0; i < 16; ++i)
+ _stopFrames[i] = s->readUint16LE();
+ for (int i = 0; i < 16; ++i)
+ _ticksList[i] = s->readUint16LE();
+
+ _velocity = s->readUint16LE();
+ _ticksAmount = s->readByte();
+ _centerOfGravity = s->readByte();
+}
+
+} // End of namespace MADS
diff --git a/engines/mads/assets.h b/engines/mads/assets.h
new file mode 100644
index 0000000000..874eee7925
--- /dev/null
+++ b/engines/mads/assets.h
@@ -0,0 +1,112 @@
+/* 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.
+ *
+ */
+
+#ifndef MADS_ASSETS_H
+#define MADS_ASSETS_H
+
+#include "common/scummsys.h"
+#include "common/array.h"
+#include "mads/palette.h"
+
+namespace MADS {
+
+#define SPRITE_SET_CHAR_INFO 4
+
+class MADSEngine;
+class MSprite;
+class MSurface;
+
+struct SpriteAssetFrame {
+ uint32 _stream;
+ Common::Rect _bounds;
+ uint32 _comp;
+ MSprite *_frame;
+};
+
+class SpriteSetCharInfo {
+public:
+ SpriteSetCharInfo(Common::SeekableReadStream *s);
+
+ int _totalFrames;
+ int _numEntries;
+ int _startFrames[16];
+ int _stopFrames[16];
+ int _ticksList[16];
+ int _velocity;
+ int _ticksAmount;
+ int _centerOfGravity;
+};
+
+class SpriteAsset {
+private:
+ MADSEngine *_vm;
+ byte _palette[PALETTE_SIZE];
+ int _colorCount;
+ uint32 _srcSize;
+ int _frameRate, _pixelSpeed;
+ int _maxWidth, _maxHeight;
+ int _frameCount;
+ Common::Array<uint32> _frameOffsets;
+ Common::Array<SpriteAssetFrame> _frames;
+ uint32 _frameStartOffset;
+ uint8 _mode;
+ bool _isBackground;
+
+ /**
+ * Load the data for the asset
+ */
+ void load(Common::SeekableReadStream *stream, int flags);
+public:
+ SpriteSetCharInfo *_charInfo;
+ int _usageIndex;
+public:
+ /**
+ * Constructor
+ */
+ SpriteAsset(MADSEngine *vm, const Common::String &resourceName, int flags);
+
+ /**
+ * Constructor
+ */
+ SpriteAsset(MADSEngine *vm, Common::SeekableReadStream *stream, int flags);
+
+ /**
+ * Destructor
+ */
+ ~SpriteAsset();
+
+ int getCount() { return _frameCount; }
+ int getFrameRate() const { return _frameRate; }
+ int getPixelSpeed() const { return _pixelSpeed; }
+ int getFrameWidth(int index);
+ int getFrameHeight(int index);
+ int getMaxFrameWidth() const { return _maxWidth; }
+ int getMaxFrameHeight() const { return _maxHeight; }
+ MSprite *getFrame(int frameIndex);
+ byte *getPalette() { return _palette; }
+ int getColorCount() { return _colorCount; }
+ bool isBackground() const { return _isBackground; }
+};
+
+} // End of namespace MADS
+
+#endif /* MADS_ASSETS_H */
diff --git a/engines/mads/audio.cpp b/engines/mads/audio.cpp
new file mode 100644
index 0000000000..1c61e13957
--- /dev/null
+++ b/engines/mads/audio.cpp
@@ -0,0 +1,129 @@
+/* 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 "mads/audio.h"
+#include "mads/compression.h"
+
+#include "common/stream.h"
+#include "audio/audiostream.h"
+#include "audio/mixer.h"
+#include "audio/decoders/raw.h"
+
+namespace MADS {
+
+AudioPlayer::AudioPlayer(Audio::Mixer *mixer, uint32 gameID) : _mixer(mixer), _gameID(gameID) {
+ setVolume(Audio::Mixer::kMaxChannelVolume);
+ setDefaultSoundGroup();
+}
+
+AudioPlayer::~AudioPlayer() {
+ _dsrEntries.clear();
+}
+
+bool AudioPlayer::isPlaying() const {
+ return _mixer->isSoundHandleActive(_handle);
+}
+
+void AudioPlayer::setVolume(int volume) {
+ _mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, volume);
+ _mixer->setVolumeForSoundType(Audio::Mixer::kSpeechSoundType, volume);
+}
+
+void AudioPlayer::setDefaultSoundGroup() {
+ switch (_gameID) {
+ case GType_RexNebular:
+ setSoundGroup("rex009.dsr");
+ break;
+ case GType_Dragonsphere:
+ setSoundGroup("drag009.dsr");
+ break;
+ case GType_Phantom:
+ setSoundGroup("phan009.dsr");
+ break;
+ default:
+ error("setDefaultSoundGroup: Unknown game");
+ }
+}
+
+void AudioPlayer::setSoundGroup(const Common::String &filename) {
+ _dsrEntries.clear();
+
+ _filename = filename;
+ _dsrFile.open(filename);
+
+ // Read header
+ uint16 entryCount = _dsrFile.readUint16LE();
+
+ for (uint16 i = 0; i < entryCount; i++) {
+ DSREntry newEntry;
+ newEntry.frequency = _dsrFile.readUint16LE();
+ newEntry.channels = _dsrFile.readUint32LE();
+ newEntry.compSize = _dsrFile.readUint32LE();
+ newEntry.uncompSize = _dsrFile.readUint32LE();
+ newEntry.offset = _dsrFile.readUint32LE();
+ _dsrEntries.push_back(newEntry);
+ }
+
+ _dsrFile.close();
+}
+
+void AudioPlayer::playSound(int soundIndex, bool loop) {
+ if (_dsrEntries.empty()) {
+ warning("DSR file not loaded, not playing sound");
+ return;
+ }
+
+ if (soundIndex < 0 || soundIndex > (int)_dsrEntries.size() - 1) {
+ warning("Invalid sound index: %i (max %i), not playing sound", soundIndex, _dsrEntries.size() - 1);
+ return;
+ }
+
+ // Get sound data
+ FabDecompressor fab;
+ int32 compSize = _dsrEntries[soundIndex].compSize;
+ int32 uncompSize = _dsrEntries[soundIndex].uncompSize;
+ int32 offset = _dsrEntries[soundIndex].offset;
+ int16 frequency = _dsrEntries[soundIndex].frequency;
+ byte *compData = new byte[compSize];
+ byte *buffer = new byte[uncompSize];
+ _dsrFile.open(_filename);
+ _dsrFile.seek(offset, SEEK_SET);
+ _dsrFile.read(compData, compSize);
+ _dsrFile.close();
+
+ fab.decompress(compData, compSize, buffer, uncompSize);
+
+ // Play sound
+ Audio::AudioStream *stream = Audio::makeLoopingAudioStream(
+ Audio::makeRawStream(buffer, uncompSize, frequency, Audio::FLAG_UNSIGNED),
+ loop ? 0 : 1);
+ _mixer->playStream(Audio::Mixer::kSFXSoundType, &_handle, stream, -1, Audio::Mixer::kMaxChannelVolume);
+
+ /*
+ // Dump the sound file
+ FILE *destFile = fopen("sound.raw", "wb");
+ fwrite(_dsrFile.dsrEntries[soundIndex]->data, _dsrFile.dsrEntries[soundIndex].uncompSize, 1, destFile);
+ fclose(destFile);
+ */
+}
+
+} // End of namespace M4
diff --git a/engines/mads/audio.h b/engines/mads/audio.h
new file mode 100644
index 0000000000..21f4bed59a
--- /dev/null
+++ b/engines/mads/audio.h
@@ -0,0 +1,64 @@
+/* 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.
+ *
+ */
+
+#ifndef MADS_AUDIO_H
+#define MADS_AUDIO_H
+
+#include "mads/resources.h"
+
+#include "common/array.h"
+#include "audio/mixer.h"
+
+namespace MADS {
+
+struct DSREntry {
+ int16 frequency;
+ int channels;
+ int32 compSize;
+ int32 uncompSize;
+ int32 offset;
+};
+
+class AudioPlayer {
+public:
+ AudioPlayer(Audio::Mixer *mixer, uint32 gameID);
+ ~AudioPlayer();
+
+ void setSoundGroup(const Common::String &filename);
+ void setDefaultSoundGroup();
+ void playSound(int soundIndex, bool loop = false);
+ void setVolume(int volume);
+ bool isPlaying() const;
+
+ private:
+ Audio::Mixer *_mixer;
+ Audio::SoundHandle _handle;
+ uint32 _gameID;
+
+ File _dsrFile;
+ Common::String _filename;
+ Common::Array<DSREntry> _dsrEntries;
+};
+
+} // End of namespace MADS
+
+#endif
diff --git a/engines/mads/compression.cpp b/engines/mads/compression.cpp
new file mode 100644
index 0000000000..de893e7b1a
--- /dev/null
+++ b/engines/mads/compression.cpp
@@ -0,0 +1,190 @@
+/* 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 "mads/compression.h"
+
+namespace MADS {
+
+const char *const madsPackString = "MADSPACK";
+const char *const FabInputExceededError = "FabDecompressor - Passed end of input buffer during decompression";
+const char *const FabOutputExceededError = "FabDecompressor - Decompressed data exceeded specified size";
+
+bool MadsPack::isCompressed(Common::SeekableReadStream *stream) {
+ // Check whether the passed stream is packed
+
+ char tempBuffer[8];
+ stream->seek(0);
+ if (stream->read(tempBuffer, 8) == 8) {
+ if (!strncmp(tempBuffer, madsPackString, 8))
+ return true;
+ }
+
+ return false;
+}
+
+MadsPack::MadsPack(Common::SeekableReadStream *stream) {
+ initialise(stream);
+}
+
+MadsPack::MadsPack(const Common::String &resourceName, MADSEngine *vm) {
+ File file(resourceName);
+ initialise(&file);
+ file.close();
+}
+
+void MadsPack::initialise(Common::SeekableReadStream *stream) {
+ if (!MadsPack::isCompressed(stream))
+ error("Attempted to decompress a resource that was not MadsPacked");
+
+ stream->seek(14);
+ _count = stream->readUint16LE();
+ _items = new MadsPackEntry[_count];
+
+ byte *headerData = new byte[0xA0];
+ byte *header = headerData;
+ stream->read(headerData, 0xA0);
+
+ for (int i = 0; i < _count; ++i, header += 10) {
+ // Get header data
+ _items[i].hash = READ_LE_UINT16(header);
+ _items[i].size = READ_LE_UINT32(header + 2);
+ _items[i].compressedSize = READ_LE_UINT32(header + 6);
+
+ byte *sourceData = new byte[_items[i].compressedSize];
+ stream->read(sourceData, _items[i].compressedSize);
+
+ if (_items[i].size == _items[i].compressedSize &&
+ !FabDecompressor::isCompressed(sourceData)) {
+ // Entry isn't compressed
+ _items[i].data = sourceData;
+ } else {
+ // Decompress the entry
+ _items[i].data = new byte[_items[i].size];
+
+ FabDecompressor fab;
+ fab.decompress(sourceData, _items[i].compressedSize, _items[i].data, _items[i].size);
+ delete[] sourceData;
+ }
+ }
+
+ delete[] headerData;
+ _dataOffset = stream->pos();
+}
+
+MadsPack::~MadsPack() {
+ for (int i = 0; i < _count; ++i)
+ delete[] _items[i].data;
+ delete[] _items;
+}
+
+//--------------------------------------------------------------------------
+
+bool FabDecompressor::isCompressed(const byte *srcData) {
+ return strncmp((const char *)srcData, "FAB", 3) == 0;
+}
+
+void FabDecompressor::decompress(const byte *srcData, int srcSize, byte *destData, int destSize) {
+ byte copyLen, copyOfsShift, copyOfsMask, copyLenMask;
+ unsigned long copyOfs;
+ byte *destP;
+
+ // Validate that the data starts with the FAB header
+ if (strncmp((const char *)srcData, "FAB", 3) != 0)
+ error("FabDecompressor - Invalid compressed data");
+
+ int shiftVal = srcData[3];
+ if ((shiftVal < 10) || (shiftVal > 13))
+ error("FabDecompressor - Invalid shift start");
+
+ copyOfsShift = 16 - shiftVal;
+ copyOfsMask = 0xFF << (shiftVal - 8);
+ copyLenMask = (1 << copyOfsShift) - 1;
+ copyOfs = 0xFFFF0000;
+ destP = destData;
+
+ // Initialise data fields
+ _srcData = srcData;
+ _srcP = _srcData + 6;
+ _srcSize = srcSize;
+ _bitsLeft = 16;
+ _bitBuffer = READ_LE_UINT16(srcData + 4);
+
+ for (;;) {
+ if (getBit() == 0) {
+ if (getBit() == 0) {
+ copyLen = ((getBit() << 1) | getBit()) + 2;
+ copyOfs = *_srcP++ | 0xFFFFFF00;
+ } else {
+ copyOfs = (((_srcP[1] >> copyOfsShift) | copyOfsMask) << 8) | _srcP[0];
+ copyLen = _srcP[1] & copyLenMask;
+ _srcP += 2;
+ if (copyLen == 0) {
+ copyLen = *_srcP++;
+ if (copyLen == 0)
+ break;
+ else if (copyLen == 1)
+ continue;
+ else
+ copyLen++;
+ } else {
+ copyLen += 2;
+ }
+ copyOfs |= 0xFFFF0000;
+ }
+ while (copyLen-- > 0) {
+ if (destP - destData == destSize)
+ error(FabOutputExceededError);
+
+ *destP = destP[(signed int)copyOfs];
+ destP++;
+ }
+ } else {
+ if (_srcP - srcData == srcSize)
+ error(FabInputExceededError);
+ if (destP - destData == destSize)
+ error(FabOutputExceededError);
+
+ *destP++ = *_srcP++;
+ }
+ }
+
+ if (destP - destData != destSize)
+ error("FabDecompressor - Decompressed data does not match header decompressed size");
+}
+
+int FabDecompressor::getBit() {
+ _bitsLeft--;
+ if (_bitsLeft == 0) {
+ if (_srcP - _srcData == _srcSize)
+ error(FabInputExceededError);
+
+ _bitBuffer = (READ_LE_UINT16(_srcP) << 1) | (_bitBuffer & 1);
+ _srcP += 2;
+ _bitsLeft = 16;
+ }
+
+ int bit = _bitBuffer & 1;
+ _bitBuffer >>= 1;
+ return bit;
+}
+
+} // End of namespace MADS
diff --git a/engines/mads/compression.h b/engines/mads/compression.h
new file mode 100644
index 0000000000..43a966f48c
--- /dev/null
+++ b/engines/mads/compression.h
@@ -0,0 +1,88 @@
+/* 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.
+ *
+ */
+
+#ifndef MADS_COMPRESSION_H
+#define MADS_COMPRESSION_H
+
+#include "common/scummsys.h"
+#include "common/endian.h"
+#include "common/memstream.h"
+#include "common/stream.h"
+
+#include "mads/mads.h"
+
+namespace MADS {
+
+struct MadsPackEntry {
+public:
+ uint16 hash;
+ uint32 size;
+ uint32 compressedSize;
+ byte *data;
+};
+
+class MadsPack {
+private:
+ MadsPackEntry *_items;
+ int _count;
+ int _dataOffset;
+
+ void initialise(Common::SeekableReadStream *stream);
+public:
+ static bool isCompressed(Common::SeekableReadStream *stream);
+ MadsPack(Common::SeekableReadStream *stream);
+ MadsPack(const Common::String &resourceName, MADSEngine *_vm);
+ ~MadsPack();
+
+ int getCount() const { return _count; }
+ MadsPackEntry &getItem(int index) const {
+ assert(index < _count);
+ return _items[index]; }
+ MadsPackEntry &operator[](int index) const {
+ assert(index < _count);
+ return _items[index];
+ }
+ Common::MemoryReadStream *getItemStream(int index) {
+ assert(index < _count);
+ return new Common::MemoryReadStream(_items[index].data, _items[index].size,
+ DisposeAfterUse::NO);
+ }
+ int getDataOffset() const { return _dataOffset; }
+};
+
+class FabDecompressor {
+private:
+ int _bitsLeft;
+ uint32 _bitBuffer;
+ const byte *_srcData, *_srcP;
+ int _srcSize;
+
+ int getBit();
+public:
+ void decompress(const byte *srcData, int srcSize, byte *destData, int destSize);
+
+ static bool isCompressed(const byte *srcData);
+};
+
+} // End of namespace MADS
+
+#endif
diff --git a/engines/mads/configure.engine b/engines/mads/configure.engine
new file mode 100644
index 0000000000..60d833e9e8
--- /dev/null
+++ b/engines/mads/configure.engine
@@ -0,0 +1,3 @@
+# This file is included from the main "configure" script
+# add_engine [name] [desc] [build-by-default] [subengines] [base games] [deps]
+add_engine mads "Rex Nebular and the Cosmic Gender Bender" no
diff --git a/engines/mads/debugger.cpp b/engines/mads/debugger.cpp
new file mode 100644
index 0000000000..9f5735f318
--- /dev/null
+++ b/engines/mads/debugger.cpp
@@ -0,0 +1,326 @@
+/* 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/file.h"
+#include "mads/mads.h"
+#include "mads/debugger.h"
+
+namespace MADS {
+
+Debugger::Debugger(MADSEngine *vm) : GUI::Debugger(), _vm(vm) {
+ _showMousePos = false;
+
+ DCmd_Register("continue", WRAP_METHOD(Debugger, Cmd_Exit));
+ DCmd_Register("mouse", WRAP_METHOD(Debugger, Cmd_Mouse));
+ DCmd_Register("scene", WRAP_METHOD(Debugger, Cmd_LoadScene));
+ DCmd_Register("show_hotspots", WRAP_METHOD(Debugger, Cmd_ShowHotSpots));
+ DCmd_Register("list_hotspots", WRAP_METHOD(Debugger, Cmd_ListHotSpots));
+ DCmd_Register("play_sound", WRAP_METHOD(Debugger, Cmd_PlaySound));
+ DCmd_Register("play_audio", WRAP_METHOD(Debugger, Cmd_PlayAudio));
+ DCmd_Register("show_codes", WRAP_METHOD(Debugger, Cmd_ShowCodes));
+ DCmd_Register("dump_file", WRAP_METHOD(Debugger, Cmd_DumpFile));
+ DCmd_Register("show_quote", WRAP_METHOD(Debugger, Cmd_ShowQuote));
+ DCmd_Register("show_vocab", WRAP_METHOD(Debugger, Cmd_ShowVocab));
+ DCmd_Register("dump_vocab", WRAP_METHOD(Debugger, Cmd_DumpVocab));
+ DCmd_Register("show_message", WRAP_METHOD(Debugger, Cmd_ShowMessage));
+ DCmd_Register("show_item", WRAP_METHOD(Debugger, Cmd_ShowItem));
+ DCmd_Register("dump_items", WRAP_METHOD(Debugger, Cmd_DumpItems));
+ DCmd_Register("item", WRAP_METHOD(Debugger, Cmd_Item));
+}
+
+static int strToInt(const char *s) {
+ if (!*s)
+ // No string at all
+ return 0;
+ else if (toupper(s[strlen(s) - 1]) != 'H')
+ // Standard decimal string
+ return atoi(s);
+
+ // Hexadecimal string
+ uint tmp = 0;
+ int read = sscanf(s, "%xh", &tmp);
+ if (read < 1)
+ error("strToInt failed on string \"%s\"", s);
+ return (int)tmp;
+}
+
+bool Debugger::Cmd_Mouse(int argc, const char **argv) {
+ if (argc < 2) {
+ DebugPrintf("Usage: %s [ on | off ]\n", argv[0]);
+ } else {
+ _showMousePos = strcmp(argv[1], "on") == 0;
+ }
+
+ return true;
+}
+
+bool Debugger::Cmd_LoadScene(int argc, const char **argv) {
+ if (argc != 2) {
+ DebugPrintf("Current scene is: %d\n", _vm->_game->_scene._currentSceneId);
+ DebugPrintf("Usage: %s <scene number>\n", argv[0]);
+ return true;
+ } else {
+ _vm->_game->_scene._nextSceneId = strToInt(argv[1]);
+ return false;
+ }
+}
+
+bool Debugger::Cmd_ShowHotSpots(int argc, const char **argv) {
+ Scene &scene = _vm->_game->_scene;
+
+ // hotspots
+ byte hotspotCol = _vm->getRandomNumber(255);
+ for (uint i = 0; i < scene._hotspots.size(); i++) {
+ scene._backgroundSurface.frameRect(scene._hotspots[i]._bounds, hotspotCol);
+ }
+
+ // Dynamic hotspots (red)
+ hotspotCol = _vm->getRandomNumber(255);
+ for (uint i = 0; i < scene._dynamicHotspots.size(); i++) {
+ scene._backgroundSurface.frameRect(scene._dynamicHotspots[i]._bounds, hotspotCol);
+ }
+
+ scene._spriteSlots.fullRefresh();
+ return false;
+}
+
+bool Debugger::Cmd_ListHotSpots(int argc, const char **argv) {
+ Hotspots &hotspots = _vm->_game->_scene._hotspots;
+
+ DebugPrintf("%d hotspots present\n", hotspots.size());
+
+ for (uint index = 0; index < hotspots.size(); ++index) {
+ DebugPrintf("(%d): %p x1 = %d; y1 = %d; x2 = %d; y2 = %d\n",
+ index, (void *)&hotspots[index],
+ hotspots[index]._bounds.left, hotspots[index]._bounds.top,
+ hotspots[index]._bounds.right, hotspots[index]._bounds.bottom);
+ }
+
+ return true;
+}
+
+bool Debugger::Cmd_PlaySound(int argc, const char **argv) {
+ if (argc < 2) {
+ DebugPrintf("Usage: %s <sound file>\n", argv[0]);
+ } else {
+ int commandId = strToInt(argv[1]);
+ int param = (argc >= 3) ? strToInt(argv[2]) : 0;
+
+ _vm->_sound->command(commandId, param);
+ }
+
+ return false;
+}
+
+bool Debugger::Cmd_PlayAudio(int argc, const char **argv) {
+ if (argc < 2) {
+ DebugPrintf("Usage: %s <sound index> <sound group>\n", argv[0]);
+ DebugPrintf("If the sound group isn't defined, the default one will be used\n");
+ } else {
+ int index = strToInt(argv[1]);
+ Common::String soundGroup = (argc >= 3) ? argv[2] : "";
+ if (argc >= 3)
+ _vm->_audio->setSoundGroup(argv[2]);
+ else
+ _vm->_audio->setDefaultSoundGroup();
+
+ _vm->_audio->playSound(index);
+ }
+
+ return true;
+}
+
+bool Debugger::Cmd_ShowCodes(int argc, const char **argv) {
+ Scene &scene = _vm->_game->_scene;
+
+ // Copy the depth/walk surface to the background and flag for screen refresh
+ scene._depthSurface.copyTo(&scene._backgroundSurface);
+ scene._spriteSlots.fullRefresh();
+
+ // Draw the locations of scene nodes onto the background
+ int color = _vm->getRandomNumber(255);
+ for (int i = 0; i < (int)scene._sceneInfo->_nodes.size(); ++i) {
+ Common::Point &pt = scene._sceneInfo->_nodes[i]._walkPos;
+
+ scene._backgroundSurface.hLine(pt.x - 2, pt.y, pt.x + 2, color);
+ scene._backgroundSurface.vLine(pt.x, pt.y - 2, pt.y + 2, color);
+ }
+
+ return false;
+}
+
+bool Debugger::Cmd_DumpFile(int argc, const char **argv) {
+ if (argc != 2) {
+ DebugPrintf("Usage: %s <resource>\n", argv[0]);
+ } else {
+ Common::DumpFile outFile;
+ Common::File inFile;
+
+ if (!inFile.open(argv[1])) {
+ DebugPrintf("Specified resource does not exist\n");
+ } else {
+ outFile.open(argv[1]);
+ byte *data = new byte[inFile.size()];
+
+ inFile.read(data, inFile.size());
+ outFile.write(data, inFile.size());
+ outFile.flush();
+
+ delete[] data;
+ inFile.close();
+ outFile.close();
+
+ DebugPrintf("File written successfully.\n");
+ }
+ }
+
+ return true;
+}
+
+bool Debugger::Cmd_ShowQuote(int argc, const char **argv) {
+ if (argc != 2)
+ DebugPrintf("Usage: %s <quote number>\n", argv[0]);
+ else
+ DebugPrintf("%s", _vm->_game->getQuote(strToInt(argv[1])).c_str());
+
+ return true;
+}
+
+bool Debugger::Cmd_ShowVocab(int argc, const char **argv) {
+ if (argc != 2) {
+ for (uint32 i = 0; i < _vm->_game->_scene.getVocabStringsCount(); i++) {
+ DebugPrintf("%03d: '%s'\n", i, _vm->_game->_scene.getVocab(i + 1).c_str());
+ }
+ } else {
+ int vocabId = strToInt(argv[1]);
+ DebugPrintf("%03d: '%s'\n", vocabId, _vm->_game->_scene.getVocab(vocabId + 1).c_str());
+ }
+
+ return true;
+}
+
+bool Debugger::Cmd_DumpVocab(int argc, const char **argv) {
+ Common::DumpFile outFile;
+ outFile.open("vocab.txt");
+
+ for (uint32 i = 0; i < _vm->_game->_scene.getVocabStringsCount(); i++) {
+ Common::String curId = Common::String::format("%x", i + 1);
+ Common::String curVocab = _vm->_game->_scene.getVocab(i + 1);
+ curVocab.toUppercase();
+
+ for (uint j = 0; j < curVocab.size(); j++) {
+ if (curVocab[j] == ' ' || curVocab[j] == '-')
+ curVocab.setChar('_', j);
+ }
+
+ Common::String cur = "\tNOUN_" + curVocab + " = 0x" + curId + ",\n";
+
+ outFile.writeString(cur.c_str());
+ }
+
+ outFile.flush();
+ outFile.close();
+
+ DebugPrintf("Game vocab dumped\n");
+
+ return true;
+}
+
+bool Debugger::Cmd_ShowMessage(int argc, const char **argv) {
+ if (argc != 2) {
+ DebugPrintf("Usage: %s <message number>\n", argv[0]);
+ } else {
+ int messageId = strToInt(argv[1]);
+ Common::StringArray msg = _vm->_game->getMessage(messageId);
+ for (uint idx = 0; idx < msg.size(); ++idx) {
+ Common::String srcLine = msg[idx];
+ DebugPrintf("%s\n", srcLine.c_str());
+ }
+ }
+
+ return true;
+}
+
+bool Debugger::Cmd_ShowItem(int argc, const char **argv) {
+ InventoryObjects &objects = _vm->_game->_objects;
+
+ if (argc != 2) {
+ for (uint32 i = 0; i < objects.size(); i++) {
+ Common::String desc = _vm->_game->_scene.getVocab(objects[i]._descId);
+ DebugPrintf("%03d: '%s'\n", i, desc.c_str());
+ }
+ } else {
+ int vocabId = strToInt(argv[1]);
+ Common::String desc = _vm->_game->_scene.getVocab(objects[vocabId]._descId);
+ DebugPrintf("%03d: '%s'\n", vocabId, desc.c_str());
+ }
+
+ return true;
+}
+
+bool Debugger::Cmd_DumpItems(int argc, const char **argv) {
+ InventoryObjects &objects = _vm->_game->_objects;
+
+ Common::DumpFile outFile;
+ outFile.open("items.txt");
+
+ for (uint32 i = 0; i < objects.size(); i++) {
+ Common::String curId = Common::String::format("%d", i);
+ Common::String desc = _vm->_game->_scene.getVocab(objects[i]._descId);
+ desc.toUppercase();
+
+ for (uint j = 0; j < desc.size(); j++) {
+ if (desc[j] == ' ' || desc[j] == '-')
+ desc.setChar('_', j);
+ }
+
+ Common::String cur = "\tOBJ_" + desc + " = " + curId + ",\n";
+
+ outFile.writeString(cur.c_str());
+ }
+
+ outFile.flush();
+ outFile.close();
+
+ DebugPrintf("Game items dumped\n");
+
+ return true;
+}
+
+bool Debugger::Cmd_Item(int argc, const char **argv) {
+ InventoryObjects &objects = _vm->_game->_objects;
+
+ if (argc != 2) {
+ DebugPrintf("Usage: %s <item number>\n", argv[0]);
+ return true;
+ } else {
+ int objectId = strToInt(argv[1]);
+
+ if (!objects.isInInventory(objectId))
+ objects.addToInventory(objectId);
+
+ DebugPrintf("Item added.\n");
+ return false;
+ }
+}
+
+} // End of namespace MADS
diff --git a/engines/mads/debugger.h b/engines/mads/debugger.h
new file mode 100644
index 0000000000..351eb13615
--- /dev/null
+++ b/engines/mads/debugger.h
@@ -0,0 +1,61 @@
+/* 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.
+ *
+ */
+
+#ifndef MADS_DEBUGGER_H
+#define MADS_DEBUGGER_H
+
+#include "common/scummsys.h"
+#include "gui/debugger.h"
+
+namespace MADS {
+
+class MADSEngine;
+
+class Debugger : public GUI::Debugger {
+private:
+ MADSEngine *_vm;
+protected:
+ bool Cmd_Mouse(int argc, const char **argv);
+ bool Cmd_LoadScene(int argc, const char **argv);
+ bool Cmd_ShowHotSpots(int argc, const char **argv);
+ bool Cmd_ListHotSpots(int argc, const char **argv);
+ bool Cmd_PlaySound(int argc, const char **argv);
+ bool Cmd_PlayAudio(int argc, const char **argv);
+ bool Cmd_ShowCodes(int argc, const char **argv);
+ bool Cmd_DumpFile(int argc, const char **argv);
+ bool Cmd_ShowQuote(int argc, const char **argv);
+ bool Cmd_ShowVocab(int argc, const char **argv);
+ bool Cmd_DumpVocab(int argc, const char **argv);
+ bool Cmd_ShowMessage(int argc, const char **argv);
+ bool Cmd_ShowItem(int argc, const char **argv);
+ bool Cmd_DumpItems(int argc, const char **argv);
+ bool Cmd_Item(int argc, const char **argv);
+public:
+ bool _showMousePos;
+public:
+ Debugger(MADSEngine *vm);
+ virtual ~Debugger() {}
+};
+
+} // End of namespace MADS
+
+#endif /* MADS_DEBUGGER_H */
diff --git a/engines/mads/detection.cpp b/engines/mads/detection.cpp
new file mode 100644
index 0000000000..971acde024
--- /dev/null
+++ b/engines/mads/detection.cpp
@@ -0,0 +1,194 @@
+/* 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 "mads/mads.h"
+
+#include "base/plugins.h"
+#include "common/savefile.h"
+#include "common/str-array.h"
+#include "common/memstream.h"
+#include "engines/advancedDetector.h"
+#include "common/system.h"
+#include "graphics/colormasks.h"
+#include "graphics/surface.h"
+#include "mads/events.h"
+#include "mads/game.h"
+
+#define MAX_SAVES 99
+
+namespace MADS {
+
+struct MADSGameDescription {
+ ADGameDescription desc;
+
+ int gameID;
+ uint32 features;
+};
+
+uint32 MADSEngine::getGameID() const {
+ return _gameDescription->gameID;
+}
+
+uint32 MADSEngine::getGameFeatures() const {
+ return _gameDescription->features;
+}
+
+uint32 MADSEngine::getFeatures() const {
+ return _gameDescription->desc.flags;
+}
+
+Common::Language MADSEngine::getLanguage() const {
+ return _gameDescription->desc.language;
+}
+
+Common::Platform MADSEngine::getPlatform() const {
+ return _gameDescription->desc.platform;
+}
+
+} // End of namespace MADS
+
+static const PlainGameDescriptor MADSGames[] = {
+ {"MADS", "MADS"},
+ {"dragonsphere", "Dragonsphere"},
+ {"nebular", "Rex Nebular and the Cosmic Gender Bender"},
+ {"phantom", "Return of the Phantom"},
+ {0, 0}
+};
+
+#include "mads/detection_tables.h"
+
+class MADSMetaEngine : public AdvancedMetaEngine {
+public:
+ MADSMetaEngine() : AdvancedMetaEngine(MADS::gameDescriptions, sizeof(MADS::MADSGameDescription), MADSGames) {
+ _maxScanDepth = 3;
+ }
+
+ virtual const char *getName() const {
+ return "MADS Engine";
+ }
+
+ virtual const char *getOriginalCopyright() const {
+ return "MADS (c)";
+ }
+
+ virtual bool hasFeature(MetaEngineFeature f) const;
+ virtual bool createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const;
+ virtual SaveStateList listSaves(const char *target) const;
+ virtual int getMaximumSaveSlot() const;
+ virtual void removeSaveState(const char *target, int slot) const;
+ SaveStateDescriptor querySaveMetaInfos(const char *target, int slot) const;
+};
+
+bool MADSMetaEngine::hasFeature(MetaEngineFeature f) const {
+ return
+ (f == kSupportsListSaves) ||
+ (f == kSupportsLoadingDuringStartup) ||
+ (f == kSupportsDeleteSave) ||
+ (f == kSavesSupportMetaInfo) ||
+ (f == kSavesSupportThumbnail);
+}
+
+bool MADS::MADSEngine::hasFeature(EngineFeature f) const {
+ return
+ (f == kSupportsRTL) ||
+ (f == kSupportsLoadingDuringRuntime) ||
+ (f == kSupportsSavingDuringRuntime);
+}
+
+bool MADSMetaEngine::createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const {
+ const MADS::MADSGameDescription *gd = (const MADS::MADSGameDescription *)desc;
+ if (gd) {
+ *engine = new MADS::MADSEngine(syst, gd);
+ }
+ return gd != 0;
+}
+
+SaveStateList MADSMetaEngine::listSaves(const char *target) const {
+ Common::SaveFileManager *saveFileMan = g_system->getSavefileManager();
+ Common::StringArray filenames;
+ Common::String saveDesc;
+ Common::String pattern = Common::String::format("%s.0??", target);
+ MADS::MADSSavegameHeader header;
+
+ filenames = saveFileMan->listSavefiles(pattern);
+ sort(filenames.begin(), filenames.end()); // Sort to get the files in numerical order
+
+ SaveStateList saveList;
+ for (Common::StringArray::const_iterator file = filenames.begin(); file != filenames.end(); ++file) {
+ const char *ext = strrchr(file->c_str(), '.');
+ int slot = ext ? atoi(ext + 1) : -1;
+
+ if (slot >= 0 && slot < MAX_SAVES) {
+ Common::InSaveFile *in = g_system->getSavefileManager()->openForLoading(*file);
+
+ if (in) {
+ MADS::Game::readSavegameHeader(in, header);
+ saveList.push_back(SaveStateDescriptor(slot, header._saveName));
+
+ header._thumbnail->free();
+ delete header._thumbnail;
+ delete in;
+ }
+ }
+ }
+
+ return saveList;
+}
+
+int MADSMetaEngine::getMaximumSaveSlot() const {
+ return MAX_SAVES;
+}
+
+void MADSMetaEngine::removeSaveState(const char *target, int slot) const {
+ Common::String filename = Common::String::format("%s.%03d", target, slot);
+ g_system->getSavefileManager()->removeSavefile(filename);
+}
+
+SaveStateDescriptor MADSMetaEngine::querySaveMetaInfos(const char *target, int slot) const {
+ Common::String filename = Common::String::format("%s.%03d", target, slot);
+ Common::InSaveFile *f = g_system->getSavefileManager()->openForLoading(filename);
+
+ if (f) {
+ MADS::MADSSavegameHeader header;
+ MADS::Game::readSavegameHeader(f, header);
+ delete f;
+
+ // Create the return descriptor
+ SaveStateDescriptor desc(slot, header._saveName);
+ desc.setThumbnail(header._thumbnail);
+ desc.setSaveDate(header._year, header._month, header._day);
+ desc.setSaveTime(header._hour, header._minute);
+ desc.setPlayTime(header._totalFrames * GAME_FRAME_TIME);
+
+ return desc;
+ }
+
+ return SaveStateDescriptor();
+}
+
+
+#if PLUGIN_ENABLED_DYNAMIC(MADS)
+ REGISTER_PLUGIN_DYNAMIC(MADS, PLUGIN_TYPE_ENGINE, MADSMetaEngine);
+#else
+ REGISTER_PLUGIN_STATIC(MADS, PLUGIN_TYPE_ENGINE, MADSMetaEngine);
+#endif
diff --git a/engines/mads/detection_tables.h b/engines/mads/detection_tables.h
new file mode 100644
index 0000000000..a5a9c33456
--- /dev/null
+++ b/engines/mads/detection_tables.h
@@ -0,0 +1,104 @@
+/* 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.
+ *
+ */
+
+namespace MADS {
+
+static const MADSGameDescription gameDescriptions[] = {
+#if 0
+ {
+ // Rex Nebular and the Cosmic Gender Bender DOS English (compressed)
+ // Removed for now, until the original floppy compression is supported
+ {
+ "nebular",
+ 0,
+ {
+ {"mpslabs.001", 0, "4df5c557b52abb5b661cf4befe5ae301", 1315354},
+ AD_LISTEND
+ },
+ Common::EN_ANY,
+ Common::kPlatformDOS,
+ ADGF_NO_FLAGS,
+ GUIO1(GUIO_NONE)
+ },
+ GType_RexNebular,
+ 0
+ },
+#endif
+
+ {
+ // Rex Nebular and the Cosmic Gender Bender DOS English
+ {
+ "nebular",
+ 0,
+ {
+ {"section1.hag", 0, "6f725eb38660de8af31ec7cdd628d615", 927222},
+ AD_LISTEND
+ },
+ Common::EN_ANY,
+ Common::kPlatformDOS,
+ ADGF_NO_FLAGS,
+ GUIO1(GUIO_NONE)
+ },
+ GType_RexNebular,
+ 0
+ },
+
+ {
+ // Return of the Phantom DOS English
+ {
+ "phantom",
+ 0,
+ {
+ {"section1.hag", 0, "76e2d47a7aebafe48edc9884b3d91782", 1130939},
+ AD_LISTEND
+ },
+ Common::EN_ANY,
+ Common::kPlatformDOS,
+ ADGF_NO_FLAGS,
+ GUIO1(GUIO_NONE)
+ },
+ GType_Phantom,
+ 0
+ },
+
+ {
+ // Dragonsphere DOS English
+ {
+ "dragonsphere",
+ 0,
+ {
+ {"section1.hag", 0, "2770e441d296be5e806194693eebd95a", 2061199},
+ AD_LISTEND
+ },
+ Common::EN_ANY,
+ Common::kPlatformDOS,
+ ADGF_NO_FLAGS,
+ GUIO1(GUIO_NONE)
+ },
+ GType_Dragonsphere,
+ 0
+ },
+
+ { AD_TABLE_END_MARKER, 0, 0 }
+};
+
+} // End of namespace MADS
diff --git a/engines/mads/dialogs.cpp b/engines/mads/dialogs.cpp
new file mode 100644
index 0000000000..b1a0b53b5a
--- /dev/null
+++ b/engines/mads/dialogs.cpp
@@ -0,0 +1,396 @@
+/* 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 "common/config-manager.h"
+#include "mads/mads.h"
+#include "mads/screen.h"
+#include "mads/msurface.h"
+#include "mads/nebular/dialogs_nebular.h"
+
+namespace MADS {
+
+Dialog::Dialog(MADSEngine *vm): _vm(vm), _savedSurface(nullptr),
+ _position(Common::Point(-1, -1)), _width(0), _height(0) {
+ TEXTDIALOG_CONTENT1 = 0XF8;
+ TEXTDIALOG_CONTENT2 = 0XF9;
+ TEXTDIALOG_EDGE = 0XFA;
+ TEXTDIALOG_BACKGROUND = 0XFB;
+ TEXTDIALOG_FC = 0XFC;
+ TEXTDIALOG_FD = 0XFD;
+ TEXTDIALOG_FE = 0XFE;
+ TEXTDIALOG_BLACK = 0;
+}
+
+Dialog::~Dialog() {
+}
+
+void Dialog::save() {
+ _savedSurface = new MSurface(_width, _height);
+ _vm->_screen.copyTo(_savedSurface,
+ Common::Rect(_position.x, _position.y, _position.x + _width, _position.y + _height),
+ Common::Point());
+
+ _vm->_screen.copyRectToScreen(getBounds());
+}
+
+void Dialog::restore() {
+ if (_savedSurface) {
+ _savedSurface->copyTo(&_vm->_screen, _position);
+ delete _savedSurface;
+ _savedSurface = nullptr;
+
+ _vm->_screen.copyRectToScreen(getBounds());
+
+ Common::copy(&_dialogPalette[0], &_dialogPalette[8 * 3],
+ &_vm->_palette->_mainPalette[248 * 3]);
+ _vm->_palette->setPalette(_vm->_palette->_mainPalette, 248, 8);
+ }
+}
+
+void Dialog::draw() {
+ // Calculate the dialog positioning
+ calculateBounds();
+
+ // Save the screen portion the dialog will overlap
+ save();
+
+ setDialogPalette();
+
+ // Draw the dialog
+ // Fill entire content of dialog
+ Common::Rect bounds = getBounds();
+ _vm->_screen.fillRect(bounds, TEXTDIALOG_BACKGROUND);
+
+ // Draw the outer edge lines
+ _vm->_screen.hLine(_position.x + 1, _position.y + _height - 2,
+ _position.x + _width - 2, TEXTDIALOG_EDGE);
+ _vm->_screen.hLine(_position.x, _position.y + _height - 1,
+ _position.x + _width - 1, TEXTDIALOG_EDGE);
+ _vm->_screen.vLine(_position.x + _width - 2, _position.y + 2,
+ _position.y + _height - 2, TEXTDIALOG_EDGE);
+ _vm->_screen.vLine(_position.x + _width - 1, _position.y + 1,
+ _position.y + _height - 1, TEXTDIALOG_EDGE);
+
+ // Draw the gravelly dialog content
+ drawContent(Common::Rect(_position.x + 2, _position.y + 2,
+ _position.x + _width - 2, _position.y + _height - 2), 0,
+ TEXTDIALOG_CONTENT1, TEXTDIALOG_CONTENT2);
+}
+
+void Dialog::setDialogPalette() {
+ // Save the high end of the palette, and set up the entries for dialog display
+ Common::copy(&_vm->_palette->_mainPalette[TEXTDIALOG_CONTENT1 * 3],
+ &_vm->_palette->_mainPalette[TEXTDIALOG_CONTENT1 * 3 + 8 * 3],
+ &_dialogPalette[0]);
+ Palette::setGradient(_vm->_palette->_mainPalette, TEXTDIALOG_CONTENT1, 2, 0x90, 0x80);
+ Palette::setGradient(_vm->_palette->_mainPalette, TEXTDIALOG_EDGE, 2, 0x9C, 0x70);
+ Palette::setGradient(_vm->_palette->_mainPalette, TEXTDIALOG_FC, 2, 0x90, 0x80);
+ Palette::setGradient(_vm->_palette->_mainPalette, TEXTDIALOG_FE, 1, 0xDC, 0xDC);
+
+ _vm->_palette->setPalette(_vm->_palette->_mainPalette + (TEXTDIALOG_CONTENT1 * 3),
+ TEXTDIALOG_CONTENT1, 8);
+}
+
+void Dialog::calculateBounds() {
+}
+
+void Dialog::drawContent(const Common::Rect &r, int seed, byte color1, byte color2) {
+ uint16 currSeed = seed ? seed : 0xB78E;
+
+ for (int yp = 0; yp < r.height(); ++yp) {
+ byte *destP = _vm->_screen.getBasePtr(r.left, r.top + yp);
+
+ for (int xp = 0; xp < r.width(); ++xp) {
+ uint16 seedAdjust = currSeed;
+ currSeed += 0x181D;
+ seedAdjust = (seedAdjust >> 9) | ((seedAdjust & 0x1ff) << 7);
+ currSeed ^= seedAdjust;
+ seedAdjust = (seedAdjust >> 3) | ((seedAdjust & 7) << 13);
+ currSeed += seedAdjust;
+
+ *destP++ = (currSeed & 0x10) ? color2 : color1;
+ }
+ }
+}
+
+/*------------------------------------------------------------------------*/
+
+TextDialog::TextDialog(MADSEngine *vm, const Common::String &fontName,
+ const Common::Point &pos, int maxChars):
+ Dialog(vm) {
+ _vm = vm;
+ _font = _vm->_font->getFont(fontName);
+ _position = pos;
+
+ _vm->_font->setColors(TEXTDIALOG_BLACK, TEXTDIALOG_BLACK, TEXTDIALOG_BLACK, TEXTDIALOG_BLACK);
+
+ _innerWidth = (_font->maxWidth() + 1) * maxChars;
+ _width = _innerWidth + 10;
+ _lineSize = maxChars * 2;
+ _lineWidth = 0;
+ _currentX = 0;
+ _numLines = 0;
+ Common::fill(&_lineXp[0], &_lineXp[TEXT_DIALOG_MAX_LINES], 0);
+ _askLineNum = -1;
+ _askXp = 0;
+}
+
+TextDialog::~TextDialog() {
+}
+
+void TextDialog::addLine(const Common::String &line, bool underline) {
+ if (_lineWidth > 0 || _currentX > 0)
+ incNumLines();
+
+ int stringWidth = _font->getWidth(line, 1);
+ if (stringWidth >= _innerWidth || (int)line.size() >= _lineSize) {
+ wordWrap(line);
+ } else {
+ _lineXp[_numLines] = (_innerWidth / 2) - (stringWidth / 2);
+ _lines[_numLines] = line;
+
+ if (underline)
+ underlineLine();
+ }
+
+ incNumLines();
+}
+
+void TextDialog::underlineLine() {
+ _lineXp[_numLines] |= 0x80;
+}
+
+void TextDialog::downPixelLine() {
+ _lineXp[_numLines] |= 0x40;
+}
+
+void TextDialog::incNumLines() {
+ _lineWidth = 0;
+ _currentX = 0;
+ if (++_numLines == TEXT_DIALOG_MAX_LINES)
+ error("Exceeded text dialog line max");
+}
+
+void TextDialog::wordWrap(const Common::String &line) {
+ Common::String tempLine;
+
+ if (!line.empty()) {
+ const char *srcP = line.c_str();
+
+ do {
+ tempLine = "";
+ bool endWord = false;
+ bool newLine = false;
+ bool continueFlag = true;
+
+ do {
+ if (!*srcP) {
+ continueFlag = false;
+ } else {
+ tempLine += *srcP;
+
+ if (*srcP == 10) {
+ continueFlag = false;
+ newLine = true;
+ ++srcP;
+ tempLine.deleteLastChar();
+ } else if (*srcP == ' ') {
+ ++srcP;
+ endWord = true;
+ } else if (!endWord) {
+ ++srcP;
+ } else {
+ tempLine.deleteLastChar();
+ continueFlag = false;
+ }
+ }
+ } while (continueFlag);
+
+ if (tempLine.hasSuffix(" "))
+ tempLine.deleteLastChar();
+
+ Common::String tempLine2;
+ if (_currentX > 0)
+ tempLine2 += ' ';
+ tempLine2 += tempLine;
+
+ int lineWidth = _font->getWidth(tempLine2, 1);
+ if (((_currentX + (int)tempLine2.size()) > _lineSize) ||
+ ((_lineWidth + lineWidth) > _innerWidth)) {
+ incNumLines();
+ appendLine(tempLine);
+ } else {
+ appendLine(tempLine2);
+ }
+
+ if (newLine)
+ incNumLines();
+ } while (*srcP);
+ }
+}
+
+void TextDialog::appendLine(const Common::String &line) {
+ _currentX += line.size();
+ _lineWidth += _font->getWidth(line, 1) + 1;
+ _lines[_numLines] += line;
+}
+
+void TextDialog::addInput() {
+ _askXp = _currentX + 1;
+ _askLineNum = _numLines;
+ incNumLines();
+}
+
+void TextDialog::addBarLine() {
+ if (_lineWidth > 0 || _currentX > 0)
+ incNumLines();
+
+ _lineXp[_numLines] = 0xFF;
+ incNumLines();
+}
+
+void TextDialog::setLineXp(int xp) {
+ _lineXp[_numLines] = xp;
+}
+
+void TextDialog::draw() {
+ if (!_lineWidth)
+ --_numLines;
+
+ // Figure out the size and position for the dialog
+ calculateBounds();
+
+ // Draw the underlying dialog
+ Dialog::draw();
+
+ // Draw the text lines
+ int lineYp = _position.y + 5;
+ for (int lineNum = 0; lineNum <= _numLines; ++lineNum) {
+ if (_lineXp[lineNum] == -1) {
+ // Draw a line across the entire dialog
+ _vm->_screen.hLine(_position.x + 2,
+ lineYp + (_font->getHeight() + 1) / 2,
+ _position.x + _width - 4, TEXTDIALOG_BLACK);
+ } else {
+ // Draw a text line
+ int xp = (_lineXp[lineNum] & 0x7F) + _position.x + 5;
+ int yp = lineYp;
+ if (_lineXp[lineNum] & 0x40)
+ ++yp;
+
+ _font->writeString(&_vm->_screen, _lines[lineNum],
+ Common::Point(xp, yp), 1);
+
+ if (_lineXp[lineNum] & 0x80) {
+ // Draw an underline under the text
+ int lineWidth = _font->getWidth(_lines[lineNum], 1);
+ _vm->_screen.hLine(xp, yp + _font->getHeight(), xp + lineWidth,
+ TEXTDIALOG_BLACK);
+ }
+ }
+
+ lineYp += _font->getHeight() + 1;
+ }
+
+ _vm->_screen.copyRectToScreen(getBounds());
+}
+
+void TextDialog::calculateBounds() {
+ _height = (_font->getHeight() + 1) * (_numLines + 1) + 10;
+ if (_position.x == -1)
+ _position.x = 160 - (_width / 2);
+ if (_position.y == -1)
+ _position.y = 100 - (_height / 2);
+
+ if ((_position.x + _width) > _vm->_screen.getWidth())
+ _position.x = _vm->_screen.getWidth() - (_position.x + _width);
+ if ((_position.y + _height) > _vm->_screen.getHeight())
+ _position.y = _vm->_screen.getHeight() - (_position.y + _height);
+}
+
+void TextDialog::drawWithInput() {
+ //int innerWidth = _innerWidth;
+ //int lineHeight = _font->getHeight() + 1;
+ //int xp = _position.x + 5;
+
+ // Draw the content of the dialog
+ drawContent(Common::Rect(_position.x + 2, _position.y + 2,
+ _position.x + _width - 2, _position.y + _height - 2), 0,
+ TEXTDIALOG_CONTENT1, TEXTDIALOG_CONTENT2);
+
+ error("TODO: drawWithInput");
+}
+
+void TextDialog::show() {
+ // Draw the dialog
+ draw();
+ _vm->_events->showCursor();
+
+ // Wait for mouse click
+ do {
+ _vm->_events->waitForNextFrame();
+ } while (!_vm->shouldQuit() && !_vm->_events->isKeyPressed() && !_vm->_events->_mouseReleased);
+
+ // Allow the mouse release or keypress to be gobbled up
+ if (!_vm->shouldQuit()) {
+ _vm->_events->waitForNextFrame();
+ _vm->_events->_pendingKeys.clear();
+ }
+
+ // Restore the background
+ restore();
+}
+
+/*------------------------------------------------------------------------*/
+
+MessageDialog::MessageDialog(MADSEngine *vm, int maxChars, ...):
+ TextDialog(vm, FONT_INTERFACE, Common::Point(-1, -1), maxChars) {
+ // Add in passed line list
+ va_list va;
+ va_start(va, maxChars);
+
+ const char *line = va_arg(va, const char *);
+ while (line) {
+ addLine(line);
+ line = va_arg(va, const char *);
+ }
+ va_end(va);
+}
+
+/*------------------------------------------------------------------------*/
+
+Dialogs *Dialogs::init(MADSEngine *vm) {
+ if (vm->getGameID() == GType_RexNebular)
+ return new Nebular::DialogsNebular(vm);
+
+ // Throw a warning for now, since the associated Dialogs class isn't implemented yet
+ warning("Dialogs: Unknown game");
+ // HACK: Reuse the implemented Nebular dialogs for now, to avoid crashing later on
+ return new Nebular::DialogsNebular(vm);
+}
+
+Dialogs::Dialogs(MADSEngine *vm): _vm(vm) {
+ _pendingDialog = DIALOG_NONE;
+}
+
+} // End of namespace MADS
diff --git a/engines/mads/dialogs.h b/engines/mads/dialogs.h
new file mode 100644
index 0000000000..6de6ea71c1
--- /dev/null
+++ b/engines/mads/dialogs.h
@@ -0,0 +1,229 @@
+/* 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.
+ *
+ */
+
+#ifndef MADS_DIALOGS_H
+#define MADS_DIALOGS_H
+
+#include "common/scummsys.h"
+#include "mads/game.h"
+#include "mads/font.h"
+#include "mads/msurface.h"
+
+namespace MADS {
+
+class Dialog {
+private:
+ void setDialogPalette();
+protected:
+ MADSEngine *_vm;
+ MSurface *_savedSurface;
+ Common::Point _position;
+ int _width;
+ int _height;
+ byte _dialogPalette[8 * 3];
+
+ int TEXTDIALOG_CONTENT1;
+ int TEXTDIALOG_CONTENT2;
+ int TEXTDIALOG_EDGE;
+ int TEXTDIALOG_BACKGROUND;
+ int TEXTDIALOG_FC;
+ int TEXTDIALOG_FD;
+ int TEXTDIALOG_FE;
+ int TEXTDIALOG_BLACK;
+protected:
+ /**
+ * Draw the dialog
+ */
+ virtual void draw();
+
+ /**
+ * Calculate bounds for the dialog
+ */
+ virtual void calculateBounds();
+
+ /**
+ * Save the section of the passed surface the dialog will cover.
+ */
+ virtual void save();
+
+ /**
+ * Restore saved dialog surface
+ */
+ virtual void restore();
+
+ /**
+ * Draws the content of a dialog with a gravelly alternating color.
+ */
+ void drawContent(const Common::Rect &r, int seed, byte color1, byte color2);
+public:
+ /**
+ * Constructor
+ */
+ Dialog(MADSEngine *vm);
+
+ /**
+ * Destructor
+ */
+ virtual ~Dialog();
+
+ /**
+ * Return the bounds of the dialog.
+ */
+ Common::Rect getBounds() const {
+ return Common::Rect(_position.x, _position.y,
+ _position.x + _width, _position.y + _height);
+ }
+};
+
+#define TEXT_DIALOG_MAX_LINES 20
+
+class TextDialog: protected Dialog {
+private:
+ /**
+ * Append text to the currently end line.
+ */
+ void appendLine(const Common::String &line);
+
+ /**
+ * Clean up after finishing displaying the dialog
+ */
+ void restorePalette();
+protected:
+ Font *_font;
+ int _innerWidth;
+ int _lineWidth;
+ int _currentX;
+ int _numLines;
+ int _lineSize;
+ int _askXp;
+ int _askLineNum;
+ Common::String _lines[TEXT_DIALOG_MAX_LINES];
+ int _lineXp[TEXT_DIALOG_MAX_LINES];
+
+ /**
+ * Calculate the bounds for the dialog
+ */
+ virtual void calculateBounds();
+public:
+ /**
+ * Constructor
+ * @param vm Engine reference
+ * @param fontName Font to use for display
+ * @param pos Position for window top-left
+ * @param maxChars Horizontal width of window in characters
+ */
+ TextDialog(MADSEngine *vm, const Common::String &fontName, const Common::Point &pos,
+ int maxChars);
+
+ /**
+ * Destructor
+ */
+ virtual ~TextDialog();
+
+ /**
+ * Draw the dialog
+ */
+ virtual void draw();
+
+ /**
+ * Draw the dialog along with any input box
+ */
+ void drawWithInput();
+
+ /**
+ * Add a new line to the dialog
+ */
+ void addLine(const Common::String &line, bool underline = false);
+
+ /**
+ * Adds one or more lines, word wrapping the passed text
+ */
+ void wordWrap(const Common::String &line);
+
+ /**
+ * Increments the number of text lines the text dialog uses
+ */
+ void incNumLines();
+
+ /**
+ * Adds an input area following previously added text
+ */
+ void addInput();
+
+ /**
+ * Adds a bar line to separate sections of text
+ */
+ void addBarLine();
+
+ /**
+ * Flags the previously added line to be underlined
+ */
+ void underlineLine();
+
+ void downPixelLine();
+
+ /**
+ * Set the x position for the given line
+ */
+ void setLineXp(int xp);
+
+ /**
+ * Show the dialog, and wait until a key or mouse press.
+ */
+ virtual void show();
+};
+
+class MessageDialog: public TextDialog {
+public:
+ MessageDialog(MADSEngine *vm, int lines, ...);
+
+ virtual ~MessageDialog() {}
+};
+
+enum DialogId {
+ DIALOG_NONE = 0, DIALOG_GAME_MENU = 1, DIALOG_SAVE = 2, DIALOG_RESTORE = 3,
+ DIALOG_OPTIONS = 4, DIALOG_DIFFICULTY = 5, DIALOG_ERROR = 6
+};
+
+class Dialogs {
+protected:
+ MADSEngine *_vm;
+
+ Dialogs(MADSEngine *vm);
+public:
+ static Dialogs *init(MADSEngine *vm);
+public:
+ Common::Point _defaultPosition;
+ DialogId _pendingDialog;
+ int _indexList[10];
+
+ virtual ~Dialogs() {}
+
+ virtual void showDialog() = 0;
+ virtual void showItem(int objectId, int messageId, int speech = 0) = 0;
+ virtual Common::String getVocab(int vocabId) = 0;
+ virtual bool show(int messageId, int objectId = -1) = 0;
+};
+
+} // End of namespace MADS
+
+#endif /* MADS_DIALOGS_H */
diff --git a/engines/mads/dragonsphere/dragonsphere_scenes.cpp b/engines/mads/dragonsphere/dragonsphere_scenes.cpp
new file mode 100644
index 0000000000..40c9a89f44
--- /dev/null
+++ b/engines/mads/dragonsphere/dragonsphere_scenes.cpp
@@ -0,0 +1,239 @@
+/* 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 "common/config-manager.h"
+#include "mads/mads.h"
+#include "mads/compression.h"
+#include "mads/resources.h"
+#include "mads/scene.h"
+#include "mads/dragonsphere/game_dragonsphere.h"
+#include "mads/dragonsphere/dragonsphere_scenes.h"
+
+namespace MADS {
+
+namespace Dragonsphere {
+
+SceneLogic *SceneFactory::createScene(MADSEngine *vm) {
+ Scene &scene = vm->_game->_scene;
+
+ // TODO
+ //scene.addActiveVocab(NOUN_DROP);
+
+ // TODO: Just return a dummy scene for now
+ return new DummyScene(vm);
+
+ switch (scene._nextSceneId) {
+ // Scene group #1 (Castle, river and caves)
+ case 101: // king's bedroom
+ return new DummyScene(vm); // TODO
+ case 102: // queen's bedroom
+ return new DummyScene(vm); // TODO
+ case 103: // outside king's bedroom
+ return new DummyScene(vm); // TODO
+ case 104: // fireplace / bookshelf
+ return new DummyScene(vm); // TODO
+ case 105: // dining room
+ return new DummyScene(vm); // TODO
+ case 106: // throne room
+ return new DummyScene(vm); // TODO
+ case 107: // council chamber
+ return new DummyScene(vm); // TODO
+ case 108: // dungeon, cell entrance
+ return new DummyScene(vm); // TODO
+ case 109: // cell
+ return new DummyScene(vm); // TODO
+ case 110: // outside castle, merchants and well
+ return new DummyScene(vm); // TODO
+ case 111: // Dragonsphere closeup
+ return new DummyScene(vm); // TODO
+ case 112: // well descend
+ return new DummyScene(vm); // TODO
+ case 113: // bottom of well, river and trap door
+ return new DummyScene(vm); // TODO
+ case 114: // cave
+ return new DummyScene(vm); // TODO
+ case 115: // cave with passageway to west
+ return new DummyScene(vm); // TODO
+ case 116: // cave with pedestral
+ return new DummyScene(vm); // TODO
+ case 117: // river
+ return new DummyScene(vm); // TODO
+ case 118: // castle courtyard and gate
+ return new DummyScene(vm); // TODO
+ case 119: // castle stairs
+ return new DummyScene(vm); // TODO
+ case 120: // map
+ return new DummyScene(vm); // TODO
+
+ // Scene group #2 (Slathan ni Patan, land of shapeshifters)
+ case 201: // guardhouse, entrance to Slathan ni Patan
+ return new DummyScene(vm); // TODO
+ case 203: // forest
+ return new DummyScene(vm); // TODO
+ case 204: // cave
+ return new DummyScene(vm); // TODO
+ case 205: // outside village
+ return new DummyScene(vm); // TODO
+ case 206: // village
+ return new DummyScene(vm); // TODO
+
+ // Scene group #3 (Brynn-Fann, Land of faeries)
+ case 301: // maze entrance
+ return new DummyScene(vm); // TODO
+ case 302: // maze
+ return new DummyScene(vm); // TODO
+ case 303: // toads
+ return new DummyScene(vm); // TODO
+
+ // Scene group #4 (The Desert)
+ case 401: // desert
+ return new DummyScene(vm); // TODO
+ case 402: // desert
+ return new DummyScene(vm); // TODO
+ case 403: // desert
+ return new DummyScene(vm); // TODO
+ case 404: // desert with dunes
+ return new DummyScene(vm); // TODO
+ case 405: // oasis
+ return new DummyScene(vm); // TODO
+ case 406: // inside tent
+ return new DummyScene(vm); // TODO
+ case 407: // gem sack closeup
+ return new DummyScene(vm); // TODO
+ case 408: // spirit plane
+ return new DummyScene(vm); // TODO
+ case 409: // spirit plane top down view, disks
+ return new DummyScene(vm); // TODO
+ case 410: // snake pit and spirit tree
+ return new DummyScene(vm); // TODO
+ case 411: // nest
+ return new DummyScene(vm); // TODO
+ case 412: // desert
+ return new DummyScene(vm); // TODO
+ case 454: // cutscene
+ return new DummyScene(vm); // TODO
+
+ // Scene group #5 (The Mountain)
+ case 501: // base of mountain / wall
+ return new DummyScene(vm); // TODO
+ case 502: // base of mountain
+ return new DummyScene(vm); // TODO
+ case 503: // waterfall
+ return new DummyScene(vm); // TODO
+ case 504: // hermit's cave
+ return new DummyScene(vm); // TODO
+ case 505: // rock trees
+ return new DummyScene(vm); // TODO
+ case 506: // nest
+ return new DummyScene(vm); // TODO
+ case 507: // above nest
+ return new DummyScene(vm); // TODO
+ case 508: // ledge, right
+ return new DummyScene(vm); // TODO
+ case 509: // ledge, left
+ return new DummyScene(vm); // TODO
+ case 510: // nest top down view and pillars
+ return new DummyScene(vm); // TODO
+ case 511: // pillars
+ return new DummyScene(vm); // TODO
+ case 512: // nest
+ return new DummyScene(vm); // TODO
+ case 557: // cutscene
+ return new DummyScene(vm); // TODO
+
+ // Scene group #6 (The Tower)
+ case 601: // ??? (tile count mismatch)
+ return new DummyScene(vm); // TODO
+ case 603: // eye chamber
+ return new DummyScene(vm); // TODO
+ case 604: // room of magic
+ return new DummyScene(vm); // TODO
+ case 605: // science room
+ return new DummyScene(vm); // TODO
+ case 606: // doorway
+ return new DummyScene(vm); // TODO
+ case 607: // prison
+ return new DummyScene(vm); // TODO
+ case 609: // stone pedestral chamber
+ return new DummyScene(vm); // TODO
+ case 612: // infernal machine room
+ return new DummyScene(vm); // TODO
+ case 613: // room with lava floor
+ return new DummyScene(vm); // TODO
+ case 614: // sorcerer's room
+ return new DummyScene(vm); // TODO
+
+ default:
+ error("Invalid scene %d called", scene._nextSceneId);
+ }
+}
+
+/*------------------------------------------------------------------------*/
+
+DragonsphereScene::DragonsphereScene(MADSEngine *vm) : SceneLogic(vm),
+ _globals(static_cast<GameDragonsphere *>(vm->_game)->_globals),
+ _game(*static_cast<GameDragonsphere *>(vm->_game)),
+ _action(vm->_game->_scene._action) {
+}
+
+Common::String DragonsphereScene::formAnimName(char sepChar, int suffixNum) {
+ return Resources::formatName(_scene->_currentSceneId, sepChar, suffixNum,
+ EXT_NONE, "");
+}
+
+/*------------------------------------------------------------------------*/
+
+void SceneInfoDragonsphere::loadCodes(MSurface &depthSurface, int variant) {
+ File f(Resources::formatName(RESPREFIX_RM, _sceneId, ".DAT"));
+ MadsPack codesPack(&f);
+ Common::SeekableReadStream *stream = codesPack.getItemStream(variant + 1);
+
+ loadCodes(depthSurface, stream);
+
+ delete stream;
+ f.close();
+}
+
+void SceneInfoDragonsphere::loadCodes(MSurface &depthSurface, Common::SeekableReadStream *stream) {
+ byte *destP = depthSurface.getData();
+ byte *endP = depthSurface.getBasePtr(0, depthSurface.h);
+
+ byte runLength = stream->readByte();
+ while (destP < endP && runLength > 0) {
+ byte runValue = stream->readByte();
+
+ // Write out the run length
+ Common::fill(destP, destP + runLength, runValue);
+ destP += runLength;
+
+ // Get the next run length
+ runLength = stream->readByte();
+ }
+
+ if (destP < endP)
+ Common::fill(destP, endP, 0);
+}
+
+} // End of namespace Dragonsphere
+
+} // End of namespace MADS
diff --git a/engines/mads/dragonsphere/dragonsphere_scenes.h b/engines/mads/dragonsphere/dragonsphere_scenes.h
new file mode 100644
index 0000000000..2d23381d25
--- /dev/null
+++ b/engines/mads/dragonsphere/dragonsphere_scenes.h
@@ -0,0 +1,695 @@
+/* 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.
+ *
+ */
+
+#ifndef MADS_DRAGONSPHERE_SCENES_H
+#define MADS_DRAGONSPHERE_SCENES_H
+
+#include "common/scummsys.h"
+#include "mads/game.h"
+#include "mads/scene.h"
+#include "mads/dragonsphere/game_dragonsphere.h"
+//#include "mads/dragonsphere/globals_dragonsphere.h"
+
+
+namespace MADS {
+
+namespace Dragonsphere {
+
+enum Noun {
+ NOUN_GAME = 0x1,
+ NOUN_QSAVE = 0x2,
+ NOUN_LOOK = 0x3,
+ NOUN_TAKE = 0x4,
+ NOUN_PUSH = 0x5,
+ NOUN_OPEN = 0x6,
+ NOUN_PUT = 0x7,
+ NOUN_TALK_TO = 0x8,
+ NOUN_GIVE = 0x9,
+ NOUN_PULL = 0xA,
+ NOUN_CLOSE = 0xB,
+ NOUN_THROW = 0xC,
+ NOUN_WALK_TO = 0xD,
+ NOUN_NOTHING = 0xE,
+ NOUN_ = 0xF,
+ NOUN_FLOOR = 0x10,
+ NOUN_WALK_ACROSS = 0x11,
+ NOUN_RUG = 0x12,
+ NOUN_CARPET = 0x13,
+ NOUN_WALL = 0x14,
+ NOUN_BED = 0x15,
+ NOUN_PILLOW = 0x16,
+ NOUN_CHEST = 0x17,
+ NOUN_WINDOW = 0x18,
+ NOUN_NIGHTSTAND = 0x19,
+ NOUN_TAPESTRY = 0x1A,
+ NOUN_DRESSING_SCREEN = 0x1B,
+ NOUN_WALK_BEHIND = 0x1C,
+ NOUN_ROYAL_CREST = 0x1D,
+ NOUN_LOOK_AT = 0x1E,
+ NOUN_WASHBASIN = 0x1F,
+ NOUN_WASH_AT = 0x20,
+ NOUN_BOOK = 0x21,
+ NOUN_FIREPLACE = 0x22,
+ NOUN_FIREPLACE_SCREEN = 0x23,
+ NOUN_DOOR_TO_QUEENS_ROOM = 0x24,
+ NOUN_WALK_THROUGH = 0x25,
+ NOUN_HALL_TO_SOUTH = 0x26,
+ NOUN_WALK_INTO = 0x27,
+ NOUN_WALL_PLAQUE = 0x28,
+ NOUN_DECORATION = 0x29,
+ NOUN_SWORDS = 0x2A,
+ NOUN_WALL_SCONCE = 0x2B,
+ NOUN_BUST_ON_WALL = 0x2C,
+ NOUN_WALL_ARCH = 0x2D,
+ NOUN_SIGNET_RING = 0x2E,
+ NOUN_INVOKE = 0x2F,
+ NOUN_POLISH = 0x30,
+ NOUN_GANGBANG = 0x31,
+ NOUN_BIRD_FIGURINE = 0x32,
+ NOUN_RUB = 0x33,
+ NOUN_BIRDCALL = 0x34,
+ NOUN_USE = 0x35,
+ NOUN_MAKE_NOISE = 0x36,
+ NOUN_SHIELDSTONE = 0x37,
+ NOUN_SWORD = 0x38,
+ NOUN_ATTACK = 0x39,
+ NOUN_CARVE_UP = 0x3A,
+ NOUN_GOBLET = 0x3B,
+ NOUN_FILL = 0x3C,
+ NOUN_DRINK_FROM = 0x3D,
+ NOUN_BONE = 0x3E,
+ NOUN_GNAW = 0x3F,
+ NOUN_FRUIT = 0x40,
+ NOUN_EAT = 0x41,
+ NOUN_DOLL = 0x42,
+ NOUN_PLAY_WITH = 0x43,
+ NOUN_HEAL = 0x44,
+ NOUN_HEAL_THYSELF = 0x45,
+ NOUN_HEAL_SELF = 0x46,
+ NOUN_POLYSTONE = 0x47,
+ NOUN_MIMIC = 0x48,
+ NOUN_RED_POWERSTONE = 0x49,
+ NOUN_YELLOW_POWERSTONE = 0x4A,
+ NOUN_BLUE_POWERSTONE = 0x4B,
+ NOUN_KEY_CROWN = 0x4C,
+ NOUN_WEAR = 0x4D,
+ NOUN_DATES = 0x4E,
+ NOUN_STATUE = 0x4F,
+ NOUN_BOTTLE_OF_FLIES = 0x50,
+ NOUN_LISTEN_TO = 0x51,
+ NOUN_SOUL_EGG = 0x52,
+ NOUN_BREAK = 0x53,
+ NOUN_MAGIC_BELT = 0x54,
+ NOUN_ADJUST = 0x55,
+ NOUN_AMULET = 0x56,
+ NOUN_THRUST = 0x57,
+ NOUN_MUD = 0x58,
+ NOUN_FEEL = 0x59,
+ NOUN_TASTE = 0x5A,
+ NOUN_FEATHERS = 0x5B,
+ NOUN_TICKLE = 0x5C,
+ NOUN_TORCH = 0x5D,
+ NOUN_WAVE = 0x5E,
+ NOUN_FLASK = 0x5F,
+ NOUN_FLASK_FULL_OF_ACID = 0x60,
+ NOUN_POUR_CONTENTS = 0x61,
+ NOUN_POUR = 0x62,
+ NOUN_POUR_CONTENTS_OF = 0x63,
+ NOUN_DRINK = 0x64,
+ NOUN_ROPE = 0x65,
+ NOUN_TIE = 0x66,
+ NOUN_POWER_VACUUM_STONE = 0x67,
+ NOUN_TAKE_MAGIC_FROM = 0x68,
+ NOUN_DEAD_RAT = 0x69,
+ NOUN_PET = 0x6A,
+ NOUN_MAP = 0x6B,
+ NOUN_FOLD = 0x6C,
+ NOUN_CRYSTAL_BALL = 0x6D,
+ NOUN_GAZE_INTO = 0x6E,
+ NOUN_INVOKE_POWER_OF = 0x6F,
+ NOUN_BLACK_SPHERE = 0x70,
+ NOUN_SOPTUS_SOPORIFIC = 0x71,
+ NOUN_SHIFTER_RING = 0x72,
+ NOUN_SHIFT_SELF = 0x73,
+ NOUN_SHIFT_INTO_BEAR = 0x74,
+ NOUN_SHIFT_INTO_SEAL = 0x75,
+ NOUN_SHIFT_INTO_SNAKE = 0x76,
+ NOUN_REVERT = 0x77,
+ NOUN_MEDICINE_BUNDLE = 0x78,
+ NOUN_SHAKE = 0x79,
+ NOUN_PARTLY_BUILT_BUNDLE = 0x7A,
+ NOUN_RATSICLE = 0x7B,
+ NOUN_LICK = 0x7C,
+ NOUN_TENTACLE_PARTS = 0x7D,
+ NOUN_CHEW = 0x7E,
+ NOUN_TELEPORT_DOOR = 0x7F,
+ NOUN_UNROLL = 0x80,
+ NOUN_RARE_COIN = 0x81,
+ NOUN_ADMIRE = 0x82,
+ NOUN_CRYSTAL_FLOWER = 0x83,
+ NOUN_DIAMOND_DUST = 0x84,
+ NOUN_RUBY_RING = 0x85,
+ NOUN_GOLD_NUGGET = 0x86,
+ NOUN_MAGIC_MUSIC_BOX = 0x87,
+ NOUN_EMERALD = 0x88,
+ NOUN_PIECE_OF_PAPER = 0x89,
+ NOUN_SPEAK_WORDS_ON = 0x8A,
+ NOUN_VORTEX_STONE = 0x8B,
+ NOUN_RUG2 = 0x8C,
+ NOUN_FIREPLACE_SCREEN2 = 0x8D,
+ NOUN_BUST_ON_WALL2 = 0x8E,
+ NOUN_LOOK_AT2 = 0x8F,
+ NOUN_DRAGON = 0x90,
+ NOUN_DRAGONSPHERE = 0x91,
+ NOUN_TOUCH = 0x92,
+ NOUN_THRONE_ROOM = 0x93,
+ NOUN_RETURN_TO = 0x94,
+ NOUN_CAVE = 0x95,
+ NOUN_PASSAGEWAY_TO_WEST = 0x96,
+ NOUN_PASSAGEWAY_TO_EAST = 0x97,
+ NOUN_CAVE_FLOOR = 0x98,
+ NOUN_STONE_COLUMN = 0x99,
+ NOUN_ABYSS = 0x9A,
+ NOUN_LOOK_INTO = 0x9B,
+ NOUN_CASTLE = 0x9C,
+ NOUN_CASTLE_GATE = 0x9D,
+ NOUN_GROUND = 0x9E,
+ NOUN_BARREL = 0x9F,
+ NOUN_BARRELS = 0xA0,
+ NOUN_HAYSTACK = 0xA1,
+ NOUN_ROOT_THROUGH = 0xA2,
+ NOUN_BATTLEMENTS = 0xA3,
+ NOUN_GATE_TO_THRONE_ROOM = 0xA4,
+ NOUN_CASTLE_WALL = 0xA5,
+ NOUN_DOOR = 0xA6,
+ NOUN_WALL_SWITCH = 0xA7,
+ NOUN_STAIRS = 0xA8,
+ NOUN_WALK_DOWN = 0xA9,
+ NOUN_EDGE_OF_ABYSS = 0xAA,
+ NOUN_COURTYARD = 0xAB,
+ NOUN_ROCK = 0xAC,
+ NOUN_CAVE_CEILING = 0xAD,
+ NOUN_CAVE_WALL = 0xAE,
+ NOUN_BRAZIER = 0xAF,
+ NOUN_DOOR_TO_THRONE_ROOM = 0xB0,
+ NOUN_GO_THROUGH = 0xB1,
+ NOUN_DINING_TABLE = 0xB2,
+ NOUN_ACTIVATE = 0xB3,
+ NOUN_BATTLEMENT = 0xB4,
+ NOUN_DOOR_TO_GAURDROOM = 0xB5,
+ NOUN_DUNGEON_FLOOR = 0xB6,
+ NOUN_DUNGEON_WALLS = 0xB7,
+ NOUN_DUNGEON_CEILING = 0xB8,
+ NOUN_BEDDING = 0xB9,
+ NOUN_FLOOR_GRATE = 0xBA,
+ NOUN_MANACLES = 0xBB,
+ NOUN_CALENDAR = 0xBC,
+ NOUN_DOOR_TO_GUARDROOM = 0xBD,
+ NOUN_DOOR_TO_COUNCIL_ROOM = 0xBE,
+ NOUN_GUARD_STATION = 0xBF,
+ NOUN_DOOR_TO_DUNGEON_CELL = 0xC0,
+ NOUN_DOORWAY_TO_CELL = 0xC1,
+ NOUN_DUNGEON_DOOR = 0xC2,
+ NOUN_DUNGEON_WALL = 0xC3,
+ NOUN_CEILING = 0xC4,
+ NOUN_DOOR_TO_HALLWAY = 0xC5,
+ NOUN_TABLE = 0xC6,
+ NOUN_BOOKSHELF = 0xC7,
+ NOUN_TROPHY = 0xC8,
+ NOUN_READING_BENCH = 0xC9,
+ NOUN_CHAIR = 0xCA,
+ NOUN_LOVESEAT = 0xCB,
+ NOUN_WOOD_BASKET = 0xCC,
+ NOUN_STOOL = 0xCD,
+ NOUN_GUARD_STOOL = 0xCE,
+ NOUN_ROCKS = 0xCF,
+ NOUN_DIVIDING_WALL = 0xD0,
+ NOUN_ARCHWAY = 0xD1,
+ NOUN_MARKET_GROUNDS = 0xD2,
+ NOUN_HEDGE = 0xD3,
+ NOUN_SKY = 0xD4,
+ NOUN_PLAINS = 0xD5,
+ NOUN_FIELDS = 0xD6,
+ NOUN_GATE_TO_COURTYARD = 0xD7,
+ NOUN_ROAD_TO_EAST = 0xD8,
+ NOUN_TREES = 0xD9,
+ NOUN_CLOUDS = 0xDA,
+ NOUN_MERCHANTS_STALL = 0xDB,
+ NOUN_WELL = 0xDC,
+ NOUN_DOWN_WELL = 0xDD,
+ NOUN_GO = 0xDE,
+ NOUN_GO_DOWN = 0xDF,
+ NOUN_CRANK = 0xE0,
+ NOUN_BUCKET = 0xE1,
+ NOUN_JUMP_DOWN = 0xE2,
+ NOUN_WALLS = 0xE3,
+ NOUN_DOORWAY_TO_SOUTH = 0xE4,
+ NOUN_PEDESTAL = 0xE5,
+ NOUN_DOOR_TO_NORTH = 0xE6,
+ NOUN_PAINTING = 0xE7,
+ NOUN_DOCUMENT = 0xE8,
+ NOUN_INK_BOTTLE = 0xE9,
+ NOUN_QUILL_PEN = 0xEA,
+ NOUN_CHANDELIER = 0xEB,
+ NOUN_COUNCIL_TABLE = 0xEC,
+ NOUN_CANDLESTICK = 0xED,
+ NOUN_DESK = 0xEE,
+ NOUN_TURN = 0xEF,
+ NOUN_POLE = 0xF0,
+ NOUN_THE_SCENE = 0xF1,
+ NOUN_LEAVE = 0xF2,
+ NOUN_END_TABLE = 0xF3,
+ NOUN_BATTLE_AXES = 0xF4,
+ NOUN_DOOR_TO_KINGS_ROOM = 0xF5,
+ NOUN_COAT_OF_ARMS = 0xF6,
+ NOUN_LARGE_WINDOW = 0xF7,
+ NOUN_SMALL_WINDOW = 0xF8,
+ NOUN_DOOR_TO_MEETING_ROOM = 0xF9,
+ NOUN_DOOR_TO_BALLROOM = 0xFA,
+ NOUN_FLOWERS = 0xFB,
+ NOUN_SHUTTERS = 0xFC,
+ NOUN_BOOKCASE = 0xFD,
+ NOUN_DOOR_TO_COURTYARD = 0xFE,
+ NOUN_PLATFORM = 0xFF,
+ NOUN_STEP = 0x100,
+ NOUN_RED_CARPET = 0x101,
+ NOUN_KINGS_THRONE = 0x102,
+ NOUN_SIT_IN = 0x103,
+ NOUN_QUEENS_THRONE = 0x104,
+ NOUN_TRAPDOOR = 0x105,
+ NOUN_GRATE = 0x106,
+ NOUN_RIVER = 0x107,
+ NOUN_DIARIES = 0x108,
+ NOUN_SWIM_DOWN = 0x109,
+ NOUN_SCULLERY_MAID = 0x10A,
+ NOUN_DOORWAY_TO_DUNGEON = 0x10B,
+ NOUN_WARD = 0x10C,
+ NOUN_DARKNESS_BEAST = 0x10D,
+ NOUN_BEAST = 0x10E,
+ NOUN_PUT_MAGIC_INTO = 0x10F,
+ NOUN_GUARD = 0x110,
+ NOUN_CROWN = 0x111,
+ NOUN_BOOKS = 0x112,
+ NOUN_SECRET_DOOR = 0x113,
+ NOUN_WALL_PANEL = 0x114,
+ NOUN_DOORWAY = 0x115,
+ NOUN_FAERIE = 0x116,
+ NOUN_SOPTUS_ECLIPTUS = 0x117,
+ NOUN_GUARD_CAPTAIN = 0x118,
+ NOUN_MERCHANT = 0x119,
+ NOUN_SHAPECHANGER = 0x11A,
+ NOUN_RED_STONE = 0x11B,
+ NOUN_YELLOW_STONE = 0x11C,
+ NOUN_BLUE_STONE = 0x11D,
+ NOUN_FLIES = 0x11E,
+ NOUN_FLASK_OF_ACID = 0x11F,
+ NOUN_PARTIAL_BUNDLE = 0x120,
+ NOUN_SOPORIFIC = 0x121,
+ NOUN_PARCHMENT = 0x122,
+ NOUN_KING = 0x123,
+ NOUN_MACMORN = 0x124,
+ NOUN_MOUNTAINSIDE = 0x125,
+ NOUN_PATH_TO_SOUTH = 0x126,
+ NOUN_ROUGH_STONE = 0x127,
+ NOUN_CLIMB_UP = 0x128,
+ NOUN_LARGE_ROCK = 0x129,
+ NOUN_SMALL_ROCK = 0x12A,
+ NOUN_PATH_TO_WEST = 0x12B,
+ NOUN_CAVE_ENTRANCE = 0x12C,
+ NOUN_PALLET = 0x12D,
+ NOUN_BLANKET = 0x12E,
+ NOUN_FIREPIT = 0x12F,
+ NOUN_FLAT_STONE = 0x130,
+ NOUN_MOVE = 0x131,
+ NOUN_SPIRIT_BUNDLE = 0x132,
+ NOUN_TRAIL_LEADING_UP = 0x133,
+ NOUN_FOLLOW = 0x134,
+ NOUN_TRAIL_LEADING_DOWN = 0x135,
+ NOUN_NEST = 0x136,
+ NOUN_REACH_IN = 0x137,
+ NOUN_TRAIL_LEADING_WEST = 0x138,
+ NOUN_PATH_TO_EAST = 0x139,
+ NOUN_WATERFALL = 0x13A,
+ NOUN_PUDDLE = 0x13B,
+ NOUN_EDGE_OF_CLIFF = 0x13C,
+ NOUN_LEDGE = 0x13D,
+ NOUN_CLIMB_DOWN = 0x13E,
+ NOUN_LANDING = 0x13F,
+ NOUN_BOULDERS = 0x140,
+ NOUN_ROCK_TUMBLE = 0x141,
+ NOUN_ROCK_TREE = 0x142,
+ NOUN_PILLAR = 0x143,
+ NOUN_JUMP_TO = 0x144,
+ NOUN_CLIFF = 0x145,
+ NOUN_PILLARS = 0x146,
+ NOUN_SPECIAL_ROCK = 0x147,
+ NOUN_GAZE_UPON = 0x148,
+ NOUN_SCONCE = 0x149,
+ NOUN_LADDER = 0x14A,
+ NOUN_STAIRWAY = 0x14B,
+ NOUN_MECHANISM = 0x14C,
+ NOUN_SPEARHEADS = 0x14D,
+ NOUN_TRAP_DOOR = 0x14E,
+ NOUN_SWIM = 0x14F,
+ NOUN_DOWN_RIVER = 0x150,
+ NOUN_SWIM_UP = 0x151,
+ NOUN_UP_RIVER = 0x152,
+ NOUN_SHORE = 0x153,
+ NOUN_SWIM_TO = 0x154,
+ NOUN_SWIM_TOWARDS = 0x155,
+ NOUN_KING_CALLASH = 0x156,
+ NOUN_KINGS_THRONE2 = 0x157,
+ NOUN_KING2 = 0x158,
+ NOUN_GROTTO = 0x159,
+ NOUN_CLIMB_THROUGH = 0x15A,
+ NOUN_QUEEN_MOTHER = 0x15B,
+ NOUN_MACMORN2 = 0x15C,
+ NOUN_SMALL_LEDGE = 0x15D,
+ NOUN_MACMORN3 = 0x15E,
+ NOUN_TO_110 = 0x15F,
+ NOUN_TO_KITTY_HEAVEN = 0x160,
+ NOUN_KITTY_HEAVEN = 0x161,
+ NOUN_ROOM_110 = 0x162,
+ NOUN_LLANIE = 0x163,
+ NOUN_CW = 0x164,
+ NOUN_HERMIT = 0x165,
+ NOUN_TROU = 0x166,
+ NOUN_SHAK = 0x167,
+ NOUN_ROOM_501 = 0x168,
+ NOUN_MOON = 0x169,
+ NOUN_UFO = 0x16A,
+ NOUN_SIT_ON = 0x16B,
+ NOUN_STRANGER = 0x16C,
+ NOUN_TOWER_DOOR = 0x16D,
+ NOUN_DOOR_TO_EAST = 0x16E,
+ NOUN_DOOR_TO_WEST = 0x16F,
+ NOUN_EYE = 0x170,
+ NOUN_DOORWAY_TO_EAST = 0x171,
+ NOUN_DOORWAY_TO_WEST = 0x172,
+ NOUN_SKULL = 0x173,
+ NOUN_DOOR_TO_MAGIC_ROOM = 0x174,
+ NOUN_ANCIENT_BARREL = 0x175,
+ NOUN_COBWEBS = 0x176,
+ NOUN_SHELF = 0x177,
+ NOUN_MUSTY_CHART = 0x178,
+ NOUN_LAB_TABLE = 0x179,
+ NOUN_PETCOCK = 0x17A,
+ NOUN_NOZZLE = 0x17B,
+ NOUN_TUBING = 0x17C,
+ NOUN_BEAKER = 0x17D,
+ NOUN_FLAME = 0x17E,
+ NOUN_METAL_PLATE = 0x17F,
+ NOUN_SHAFT_OF_LIGHT = 0x180,
+ NOUN_CABINET = 0x181,
+ NOUN_BALANCE = 0x182,
+ NOUN_CAGE = 0x183,
+ NOUN_FREEZER = 0x184,
+ NOUN_CONTENTS_OF_FREEZER = 0x185,
+ NOUN_CAGE_WITH_RATS = 0x186,
+ NOUN_DOOR_TO_SOUTH = 0x187,
+ NOUN_TRAIL_OF_GREEN_SLIME = 0x188,
+ NOUN_NECK_LOCK = 0x189,
+ NOUN_BENCH = 0x18A,
+ NOUN_SKELETON = 0x18B,
+ NOUN_LEG_CLAMPS = 0x18C,
+ NOUN_LEG_LOCK = 0x18D,
+ NOUN_WAIST_LOCK = 0x18E,
+ NOUN_NER_TOM = 0x18F,
+ NOUN_BELT = 0x190,
+ NOUN_JUMP_INTO = 0x191,
+ NOUN_CLOSET = 0x192,
+ NOUN_DOOR_TO_EYE_CHAMBER = 0x193,
+ NOUN_DRESSER = 0x194,
+ NOUN_SCROLL = 0x195,
+ NOUN_WITCH_PARAPHERNALIA = 0x196,
+ NOUN_SHELVES = 0x197,
+ NOUN_MAGIC_TOMES = 0x198,
+ NOUN_MAGIC_PARAPHERNALIA = 0x199,
+ NOUN_BOOK_OF_MAGIC = 0x19A,
+ NOUN_HOURGLASS = 0x19B,
+ NOUN_STONE_SPHERE = 0x19C,
+ NOUN_SHADOW_OF_WINDOW = 0x19D,
+ NOUN_MUSIC_BOX = 0x19E,
+ NOUN_LARGE_SPIDER_WEB = 0x19F,
+ NOUN_INFERNAL_MACHINE = 0x1A0,
+ NOUN_WATER_SOURCE = 0x1A1,
+ NOUN_FLOW_OF_WATER = 0x1A2,
+ NOUN_RETORT = 0x1A3,
+ NOUN_DOORWAY_TO_CORRIDOR = 0x1A4,
+ NOUN_TELESCOPE = 0x1A5,
+ NOUN_STRANGE_MAP = 0x1A6,
+ NOUN_CIRCLE_OF_SPHERES = 0x1A7,
+ NOUN_STONE_BED = 0x1A8,
+ NOUN_DRAGON_SCULPTURE = 0x1A9,
+ NOUN_RAT = 0x1AA,
+ NOUN_RAT_CAGE = 0x1AB,
+ NOUN_DOWN_BUTTON = 0x1AC,
+ NOUN_DOOR_TO_MACHINE_ROOM = 0x1AD,
+ NOUN_STRANGE_PORTAL = 0x1AE,
+ NOUN_DOOR_FRAME = 0x1AF,
+ NOUN_ELEVATOR_HOLE = 0x1B0,
+ NOUN_UP_BUTTON = 0x1B1,
+ NOUN_DOORWAY_TO_DARK_ROOM = 0x1B2,
+ NOUN_BIG_SKULL = 0x1B3,
+ NOUN_ELEVATOR_PLATFORM = 0x1B4,
+ NOUN_BUTTON = 0x1B5,
+ NOUN_TOP_BUTTON = 0x1B6,
+ NOUN_BOTTOM_BUTTON = 0x1B7,
+ NOUN_TELEPORTAL = 0x1B8,
+ NOUN_EYE_CHAMBER_DOORWAY = 0x1B9,
+ NOUN_MACHINE_ROOM_DOORWAY = 0x1BA,
+ NOUN_GLOWING_FLOOR = 0x1BB,
+ NOUN_BRYNN_FANN = 0x1BC,
+ NOUN_GRAN_CALLAHACH = 0x1BD,
+ NOUN_SLATHAN_NI_PATAN = 0x1BE,
+ NOUN_HIGHTOWER = 0x1BF,
+ NOUN_SOPTUS_ECLIPTUS2 = 0x1C0,
+ NOUN_TOWER = 0x1C1,
+ NOUN_MOUNTAIN_PATH = 0x1C2,
+ NOUN_PATH_BEHIND_TOWER = 0x1C3,
+ NOUN_VINES = 0x1C4,
+ NOUN_SLATHAN_NI_PATAN2 = 0x1C5,
+ NOUN_SICK = 0x1C6,
+ NOUN_PATH_AROUND_TOWER = 0x1C7,
+ NOUN_PATH_TO_HIGHTOWER = 0x1C8,
+ NOUN_SPIRIT_PLANE = 0x1C9,
+ NOUN_SPIRIT_TREE = 0x1CA,
+ NOUN_WALK = 0x1CB,
+ NOUN_REMAINS = 0x1CC,
+ NOUN_DOORWAY_TO_ELEVATOR = 0x1CD,
+ NOUN_DRAGON_DOOR = 0x1CE,
+ NOUN_DRAGON_BONES = 0x1CF,
+ NOUN_IRON_FLOOR = 0x1D0,
+ NOUN_HOLE = 0x1D1,
+ NOUN_STONE = 0x1D2,
+ NOUN_HOMEMADE_BUNDLE = 0x1D3,
+ NOUN_LEFT = 0x1D4,
+ NOUN_RIGHT = 0x1D5,
+ NOUN_UP = 0x1D6,
+ NOUN_DOWN = 0x1D7,
+ NOUN_WEST = 0x1D8,
+ NOUN_DESERT_TO_WEST = 0x1D9,
+ NOUN_CROSS = 0x1DA,
+ NOUN_DESERT_TO_EAST = 0x1DB,
+ NOUN_DESERT_TO_SOUTH = 0x1DC,
+ NOUN_DESERT_TO_NORTH = 0x1DD,
+ NOUN_DESERT = 0x1DE,
+ NOUN_POWERSTONE = 0x1DF,
+ NOUN_BONES = 0x1E0,
+ NOUN_TENT = 0x1E1,
+ NOUN_BUSH = 0x1E2,
+ NOUN_SANWE = 0x1E3,
+ NOUN_TANGLE = 0x1E4,
+ NOUN_SAND = 0x1E5,
+ NOUN_MAGIC_GRAPES = 0x1E6,
+ NOUN_ROCS_NEST = 0x1E7,
+ NOUN_GRAPE_VINE = 0x1E8,
+ NOUN_STRANGE_SQUARE = 0x1E9,
+ NOUN_WATER_SPHERE = 0x1EA,
+ NOUN_EAST_END_OF_ISLAND = 0x1EB,
+ NOUN_ISLAND = 0x1EC,
+ NOUN_SECRET_MESSAGE = 0x1ED,
+ NOUN_FIND = 0x1EE,
+ NOUN_SAND_NEAR_STONES = 0x1EF,
+ NOUN_DESERT_SKY = 0x1F0,
+ NOUN_POOL = 0x1F1,
+ NOUN_PALM_TREE = 0x1F2,
+ NOUN_OASIS = 0x1F3,
+ NOUN_LEAN_TO = 0x1F4,
+ NOUN_TRADER = 0x1F5,
+ NOUN_SIGN = 0x1F6,
+ NOUN_WATER_FLOW = 0x1F7,
+ NOUN_FLOATING_DISK = 0x1F8,
+ NOUN_GNARLED_ROOT = 0x1F9,
+ NOUN_SNAKE_PIT = 0x1FA,
+ NOUN_MARKER = 0x1FB,
+ NOUN_SHAMAN = 0x1FC,
+ NOUN_GUARDHOUSE = 0x1FD,
+ NOUN_BONE_TREE = 0x1FE,
+ NOUN_EAR_ROCK = 0x1FF,
+ NOUN_MOUTH_ROCK = 0x200,
+ NOUN_NOSE_ROCK = 0x201,
+ NOUN_NEW_BUNDLE = 0x202,
+ NOUN_LIZARD = 0x203,
+ NOUN_ROC = 0x204,
+ NOUN_ROCS_NEST2 = 0x205,
+ NOUN_SELECT = 0x206,
+ NOUN_PURPLE_GEM = 0x207,
+ NOUN_PURPLE_STONE = 0x208,
+ NOUN_GREEN_STONE = 0x209,
+ NOUN_PATH = 0x20A,
+ NOUN_GUARDS = 0x20B,
+ NOUN_LAMP = 0x20C,
+ NOUN_SCIMITAR = 0x20D,
+ NOUN_SITTING_PILLOW = 0x20E,
+ NOUN_WATER_GOURD = 0x20F,
+ NOUN_JAR = 0x210,
+ NOUN_TENT_POLE = 0x211,
+ NOUN_EXIT = 0x212,
+ NOUN_PARAPHERNALIA = 0x213,
+ NOUN_SLATHAN_NI_PATAN3 = 0x214,
+ NOUN_EYE_ROCK = 0x215,
+ NOUN_BODY_TREE = 0x216,
+ NOUN_CLEARING = 0x217,
+ NOUN_TENTACLES = 0x218,
+ NOUN_SPELL_SHIELD = 0x219,
+ NOUN_POOL_MONSTER = 0x21A,
+ NOUN_SHIFTER_BOULDER = 0x21B,
+ NOUN_DEAD_TREE = 0x21C,
+ NOUN_PIT = 0x21D,
+ NOUN_SHIFTER_VILLAGE = 0x21E,
+ NOUN_SLATHAN_SKY = 0x21F,
+ NOUN_SHIFTER = 0x220,
+ NOUN_WALK_AROUND = 0x221,
+ NOUN_WRECKED_BRIDGE = 0x222,
+ NOUN_SHACK = 0x223,
+ NOUN_WRECKED_SHACK = 0x224,
+ NOUN_WISE_SHIFTER = 0x225,
+ NOUN_GRASS = 0x226,
+ NOUN_ENTRANCE_TO_MAZE = 0x227,
+ NOUN_TOPIARY_TOAD = 0x228,
+ NOUN_BOULDER = 0x229,
+ NOUN_MUSHROOM = 0x22A,
+ NOUN_SLATHAN_SKY2 = 0x22B,
+ NOUN_GRETA = 0x22C,
+ NOUN_TREE_STUMP = 0x22D,
+ NOUN_SANCTUARY_WOODS = 0x22E,
+ NOUN_TOADS = 0x22F,
+ NOUN_DOOFUS = 0x230,
+ NOUN_SHIFTING_MONSTER = 0x231,
+ NOUN_SPRITE = 0x232,
+ NOUN_MAZE = 0x233,
+ NOUN_TOPIARY_TOADSTOOL = 0x234,
+ NOUN_TOPIARY_GARGOYLE = 0x235,
+ NOUN_TOPIARY_DRAGON = 0x236,
+ NOUN_GUARDIAN = 0x237,
+ NOUN_BUTTERFLY_KING = 0x238,
+ NOUN_ROBE = 0x239,
+ NOUN_CEDAR_CHEST = 0x23A,
+ NOUN_DRAGONSPHERE2 = 0x23B,
+ NOUN_PATH_TO_HIGHTOWER2 = 0x23C,
+ NOUN_CALIPH = 0x23D
+};
+
+class SceneFactory {
+public:
+ static SceneLogic *createScene(MADSEngine *vm);
+};
+
+/**
+ * Specialized base class for Dragonsphere game scenes
+ */
+class DragonsphereScene : public SceneLogic {
+protected:
+ DragonsphereGlobals &_globals;
+ GameDragonsphere &_game;
+ MADSAction &_action;
+
+ /**
+ * Forms an animation resource name
+ */
+ Common::String formAnimName(char sepChar, int suffixNum);
+
+ /**
+ * Plays appropriate sound for entering varous rooms
+ */
+ void lowRoomsEntrySound();
+public:
+ /**
+ * Constructor
+ */
+ DragonsphereScene(MADSEngine *vm);
+
+ void sub7178C();
+};
+
+class SceneInfoDragonsphere : public SceneInfo {
+ friend class SceneInfo;
+protected:
+ virtual void loadCodes(MSurface &depthSurface, int variant);
+
+ virtual void loadCodes(MSurface &depthSurface, Common::SeekableReadStream *stream);
+
+ /**
+ * Constructor
+ */
+ SceneInfoDragonsphere(MADSEngine *vm) : SceneInfo(vm) {}
+};
+
+// TODO: Temporary, remove once implemented properly
+class Scene1xx : public DragonsphereScene {
+protected:
+ /**
+ * Plays an appropriate sound when entering a scene
+ */
+ void sceneEntrySound() {}
+
+ /**
+ *Sets the AA file to use for the scene
+ */
+ void setAAName() {}
+
+ /**
+ * Updates the prefix used for getting player sprites for the scene
+ */
+ void setPlayerSpritesPrefix() {}
+public:
+ Scene1xx(MADSEngine *vm) : DragonsphereScene(vm) {}
+};
+
+// TODO: Temporary, remove once implemented properly
+class DummyScene: public DragonsphereScene {
+public:
+ DummyScene(MADSEngine *vm) : DragonsphereScene(vm) {
+ warning("Unimplemented scene");
+ }
+
+ virtual void setup() {}
+ virtual void enter() {}
+ virtual void actions() {}
+};
+
+} // End of namespace Dragonsphere
+
+} // End of namespace MADS
+
+#endif /* MADS_DRAGONSPHERE_SCENES_H */
diff --git a/engines/mads/dragonsphere/game_dragonsphere.cpp b/engines/mads/dragonsphere/game_dragonsphere.cpp
new file mode 100644
index 0000000000..bee5312660
--- /dev/null
+++ b/engines/mads/dragonsphere/game_dragonsphere.cpp
@@ -0,0 +1,172 @@
+/* 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 "common/config-manager.h"
+#include "mads/mads.h"
+#include "mads/game.h"
+#include "mads/screen.h"
+#include "mads/msurface.h"
+#include "mads/dragonsphere/game_dragonsphere.h"
+//#include "mads/nebular/dialogs_nebular.h"
+//#include "mads/nebular/globals_nebular.h"
+#include "mads/dragonsphere/dragonsphere_scenes.h"
+
+namespace MADS {
+
+namespace Dragonsphere {
+
+GameDragonsphere::GameDragonsphere(MADSEngine *vm): Game(vm) {
+ _surface = new MSurface(MADS_SCREEN_WIDTH, MADS_SCENE_HEIGHT);
+ _storyMode = STORYMODE_NAUGHTY;
+}
+
+ProtectionResult GameDragonsphere::checkCopyProtection() {
+ /*
+ // DEBUG: Flag copy protection failure
+ _globals[5] = -1;
+
+ if (!ConfMan.getBool("copy_protection"))
+ return true;
+
+ * DEBUG: Disabled for now
+ CopyProtectionDialog *dlg = new CopyProtectionDialog(_vm, false);
+ dlg->show();
+ delete dlg;
+ */
+
+ // DEBUG: Return that copy protection failed
+ return PROTECTION_SUCCEED;
+}
+
+void GameDragonsphere::initializeGlobals() {
+ //int count, count2;
+ //int bad;
+
+ _globals.reset();
+ //_globals[kTalkInanimateCount] = 8;
+
+ /* Section #1 variables */
+ // TODO
+
+ /* Section #2 variables */
+ // TODO
+
+ /* Section #3 variables */
+ // TODO
+
+ /* Section #4 variables */
+ // TODO
+
+ /* Section #5 variables */
+ // TODO
+
+ /* Section #6 variables */
+ // TODO
+
+ /* Section #9 variables */
+ // TODO
+
+ _player._facing = FACING_NORTH;
+ _player._turnToFacing = FACING_NORTH;
+
+ //Player::preloadSequences("RXM", 1);
+ //Player::preloadSequences("ROX", 1);
+}
+
+void GameDragonsphere::setSectionHandler() {
+ delete _sectionHandler;
+
+ switch (_sectionNumber) {
+ case 1:
+ _sectionHandler = new Section1Handler(_vm);
+ break;
+ case 2:
+ _sectionHandler = new Section2Handler(_vm);
+ break;
+ case 3:
+ _sectionHandler = new Section3Handler(_vm);
+ break;
+ case 4:
+ _sectionHandler = new Section4Handler(_vm);
+ break;
+ case 5:
+ _sectionHandler = new Section5Handler(_vm);
+ break;
+ case 6:
+ _sectionHandler = new Section6Handler(_vm);
+ break;
+ case 7:
+ _sectionHandler = new Section7Handler(_vm);
+ break;
+ case 8:
+ _sectionHandler = new Section8Handler(_vm);
+ break;
+ default:
+ break;
+ }
+}
+
+void GameDragonsphere::checkShowDialog() {
+ // TODO: Copied from Nebular
+ if (_vm->_dialogs->_pendingDialog && _player._stepEnabled && !_globals[5]) {
+ _player.releasePlayerSprites();
+ _vm->_dialogs->showDialog();
+ _vm->_dialogs->_pendingDialog = DIALOG_NONE;
+ }
+}
+
+void GameDragonsphere::doObjectAction() {
+ // TODO: Copied from Nebular
+ //Scene &scene = _scene;
+ MADSAction &action = _scene._action;
+ //Dialogs &dialogs = *_vm->_dialogs;
+ //int id;
+
+ action._inProgress = false;
+}
+
+void GameDragonsphere::unhandledAction() {
+ // TODO
+}
+
+void GameDragonsphere::step() {
+ if (_player._visible && _player._stepEnabled && !_player._moving &&
+ (_player._facing == _player._turnToFacing)) {
+
+ // TODO
+ }
+
+}
+
+void GameDragonsphere::synchronize(Common::Serializer &s, bool phase1) {
+ Game::synchronize(s, phase1);
+
+ // TODO: Copied from Nebular
+ if (!phase1) {
+ _globals.synchronize(s);
+ }
+}
+
+} // End of namespace Dragonsphere
+
+} // End of namespace MADS
diff --git a/engines/mads/dragonsphere/game_dragonsphere.h b/engines/mads/dragonsphere/game_dragonsphere.h
new file mode 100644
index 0000000000..259c4168c1
--- /dev/null
+++ b/engines/mads/dragonsphere/game_dragonsphere.h
@@ -0,0 +1,151 @@
+/* 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.
+ *
+ */
+
+#ifndef MADS_GAME_DRAGONSPHERE_H
+#define MADS_GAME_DRAGONSPHERE_H
+
+#include "common/scummsys.h"
+#include "mads/game.h"
+#include "mads/globals.h"
+//#include "mads/nebular/globals_nebular.h"
+
+namespace MADS {
+
+namespace Dragonsphere {
+
+// TODO: Adapt for Dragonsphere's difficulty setting
+enum StoryMode { STORYMODE_NAUGHTY = 1, STORYMODE_NICE = 2 };
+
+enum InventoryObject {
+ OBJ_NONE = -1,
+ OBJ_SIGNET_RING = 0,
+ OBJ_BIRD_FIGURINE = 1,
+ OBJ_BIRDCALL = 2,
+ OBJ_SHIELDSTONE = 3,
+ OBJ_SWORD = 4,
+ OBJ_GOBLET = 5,
+ OBJ_BONE = 6,
+ OBJ_FRUIT = 7,
+ OBJ_DOLL = 8,
+ OBJ_POLYSTONE = 9,
+ OBJ_RED_STONE = 10,
+ OBJ_YELLOW_STONE = 11,
+ OBJ_BLUE_STONE = 12,
+ OBJ_KEY_CROWN = 13,
+ OBJ_DATES = 14,
+ OBJ_STATUE = 15,
+ OBJ_FLIES = 16,
+ OBJ_SOUL_EGG = 17,
+ OBJ_MAGIC_BELT = 18,
+ OBJ_AMULET = 19,
+ OBJ_MUD = 20,
+ OBJ_FEATHERS = 21,
+ OBJ_TORCH = 22,
+ OBJ_FLASK = 23,
+ OBJ_FLASK_OF_ACID = 24,
+ OBJ_ROPE = 25,
+ OBJ_VORTEX_STONE = 26,
+ OBJ_DEAD_RAT = 27,
+ OBJ_MAP = 28,
+ OBJ_CRYSTAL_BALL = 29,
+ OBJ_BLACK_SPHERE = 30,
+ OBJ_SOPORIFIC = 31,
+ OBJ_SHIFTER_RING = 32,
+ OBJ_SPIRIT_BUNDLE = 33,
+ OBJ_PARTIAL_BUNDLE = 34,
+ OBJ_RATSICLE = 35,
+ OBJ_TENTACLE_PARTS = 36,
+ OBJ_TELEPORT_DOOR = 37,
+ OBJ_RARE_COIN = 38,
+ OBJ_CRYSTAL_FLOWER = 39,
+ OBJ_DIAMOND_DUST = 40,
+ OBJ_RUBY_RING = 41,
+ OBJ_GOLD_NUGGET = 42,
+ OBJ_MUSIC_BOX = 43,
+ OBJ_EMERALD = 44,
+ OBJ_PARCHMENT = 45,
+ OBJ_GAME = 46,
+ OBJ_GAME2 = 47,
+ OBJ_NEW_BUNDLE = 48
+};
+
+// HACK: A stub for now, remove from here once it's implemented properly
+class DragonsphereGlobals: public Globals {
+public:
+ DragonsphereGlobals() {
+ resize(210); // Rex has 210 globals
+ }
+ virtual ~DragonsphereGlobals() {}
+};
+
+class GameDragonsphere: public Game {
+ friend class Game;
+protected:
+ GameDragonsphere(MADSEngine *vm);
+
+ virtual ProtectionResult checkCopyProtection();
+
+ virtual void initializeGlobals();
+
+ virtual void setSectionHandler();
+
+ virtual void checkShowDialog();
+public:
+ DragonsphereGlobals _globals;
+ StoryMode _storyMode;
+
+ virtual Globals &globals() { return _globals; }
+
+ virtual void doObjectAction();
+
+ virtual void unhandledAction();
+
+ virtual void step();
+
+ virtual void synchronize(Common::Serializer &s, bool phase1);
+};
+
+
+class Section1Handler: public SectionHandler {
+public:
+ Section1Handler(MADSEngine *vm): SectionHandler(vm) {}
+
+ // TODO: Properly implement handler methods
+ virtual void preLoadSection() {}
+ virtual void sectionPtr2() {}
+ virtual void postLoadSection() {}
+};
+
+// TODO: Properly implement handler classes
+typedef Section1Handler Section2Handler;
+typedef Section1Handler Section3Handler;
+typedef Section1Handler Section4Handler;
+typedef Section1Handler Section5Handler;
+typedef Section1Handler Section6Handler;
+typedef Section1Handler Section7Handler;
+typedef Section1Handler Section8Handler;
+
+} // End of namespace Nebular
+
+} // End of namespace MADS
+
+#endif /* MADS_GAME_DRAGONSPHERE_H */
diff --git a/engines/mads/events.cpp b/engines/mads/events.cpp
new file mode 100644
index 0000000000..3f2a7390fb
--- /dev/null
+++ b/engines/mads/events.cpp
@@ -0,0 +1,254 @@
+/* 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 "graphics/cursorman.h"
+#include "common/events.h"
+#include "engines/util.h"
+#include "mads/mads.h"
+#include "mads/events.h"
+#include "mads/scene.h"
+
+namespace MADS {
+
+EventsManager::EventsManager(MADSEngine *vm) {
+ _vm = vm;
+ _cursorSprites = nullptr;
+ _frameCounter = 10;
+ _priorFrameTime = 0;
+ _mouseClicked = false;
+ _mouseReleased = false;
+ _mouseButtons = 0;
+ _mouseStatus = 0;
+ _vD2 = 0;
+ _mouseStatusCopy = 0;
+ _mouseMoved = false;
+ _vD8 = 0;
+ _rightMousePressed = false;
+}
+
+EventsManager::~EventsManager() {
+ freeCursors();
+}
+
+void EventsManager::loadCursors(const Common::String &spritesName) {
+ delete _cursorSprites;
+ _cursorSprites = new SpriteAsset(_vm, spritesName, 0x4000);
+}
+
+void EventsManager::setCursor(CursorType cursorId) {
+ _cursorId = cursorId;
+ changeCursor();
+}
+
+void EventsManager::setCursor2(CursorType cursorId) {
+ _cursorId = cursorId;
+ _newCursorId = cursorId;
+ changeCursor();
+}
+
+void EventsManager::showCursor() {
+ CursorMan.showMouse(true);
+}
+
+void EventsManager::hideCursor() {
+ CursorMan.showMouse(false);
+}
+
+bool EventsManager::isCursorVisible() {
+ return CursorMan.isVisible();
+}
+
+void EventsManager::waitCursor() {
+ CursorType cursorId = (CursorType)MIN(_cursorSprites->getCount(), (int)CURSOR_WAIT);
+ _newCursorId = cursorId;
+ if (_cursorId != _newCursorId) {
+ changeCursor();
+ _cursorId = _newCursorId;
+ }
+}
+
+void EventsManager::changeCursor() {
+ if (_cursorSprites) {
+ MSprite *cursor = _cursorSprites->getFrame(_cursorId - 1);
+ assert(cursor->w == cursor->h);
+ byte transIndex = cursor->getTransparencyIndex();
+
+ // Check for hotspot indication pixels along the right-hand and bottom
+ // row. Put together, these give the cursor's hotspot x,y
+ int hotspotX = 0, hotspotY = 0;
+ byte *cursorData = cursor->getData();
+ for (int idx = 0; idx < cursor->w; ++idx) {
+ if (cursorData[(cursor->h - 1) * cursor->w + idx] != transIndex)
+ hotspotX = idx;
+
+ if (cursorData[(idx + 1) * cursor->w - 1] != transIndex)
+ hotspotY = idx;
+ }
+
+ // Reduce the cursor data to remove the last column from each row, since
+ // the cursor routines don't have a pitch option
+ byte *destCursor = new byte[(cursor->w - 1) * (cursor->h - 1)];
+ byte *srcP = cursorData;
+ byte *destP = destCursor;
+
+ for (int idx = 0; idx < (cursor->h - 1); ++idx) {
+ Common::copy(srcP, srcP + cursor->w - 1, destP);
+ srcP += cursor->w;
+ destP += cursor->w - 1;
+ }
+
+ // Set the raw cursor data to use
+ CursorMan.replaceCursor(destCursor, cursor->w - 1, cursor->h - 1,
+ hotspotX, hotspotY, transIndex);
+ showCursor();
+ delete[] destCursor;
+ }
+}
+
+void EventsManager::freeCursors() {
+ delete _cursorSprites;
+ _cursorSprites = nullptr;
+}
+
+void EventsManager::pollEvents() {
+ checkForNextFrameCounter();
+ _mouseMoved = false;
+
+ Common::Event event;
+ while (g_system->getEventManager()->pollEvent(event)) {
+ // Handle keypress
+ switch (event.type) {
+ case Common::EVENT_QUIT:
+ case Common::EVENT_RTL:
+ return;
+
+ case Common::EVENT_KEYDOWN:
+ // Check for debugger
+ if (event.kbd.keycode == Common::KEYCODE_d && (event.kbd.flags & Common::KBD_CTRL)) {
+ // Attach to the debugger
+ _vm->_debugger->attach();
+ _vm->_debugger->onFrame();
+ } else {
+ _pendingKeys.push(event);
+ }
+ return;
+ case Common::EVENT_KEYUP:
+ return;
+ case Common::EVENT_LBUTTONDOWN:
+ case Common::EVENT_RBUTTONDOWN:
+ _mouseClicked = true;
+ _mouseButtons = 1;
+ _mouseMoved = true;
+ if (event.type == Common::EVENT_RBUTTONDOWN) {
+ _rightMousePressed = true;
+ _mouseStatus |= 2;
+ } else {
+ _mouseStatus |= 1;
+ }
+ return;
+ case Common::EVENT_LBUTTONUP:
+ case Common::EVENT_RBUTTONUP:
+ _mouseClicked = false;
+ _mouseReleased = true;
+ _mouseMoved = true;
+ _rightMousePressed = false;
+ if (event.type == Common::EVENT_RBUTTONUP) {
+ _mouseStatus &= ~2;
+ } else {
+ _mouseStatus &= ~1;
+ }
+ return;
+ case Common::EVENT_MOUSEMOVE:
+ _mousePos = event.mouse;
+ _currentPos = event.mouse;
+ _mouseMoved = true;
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+void EventsManager::checkForNextFrameCounter() {
+ // Check for next game frame
+ uint32 milli = g_system->getMillis();
+ if ((milli - _priorFrameTime) >= GAME_FRAME_TIME) {
+ ++_frameCounter;
+ _priorFrameTime = milli;
+
+ // Do any palette cycling
+ _vm->_game->_scene.animatePalette();
+
+ // Give time to the debugger
+ _vm->_debugger->onFrame();
+
+ // Display the frame
+ _vm->_screen.updateScreen();
+
+ // Signal the ScummVM debugger
+ _vm->_debugger->onFrame();
+ }
+}
+
+void EventsManager::delay(int cycles) {
+ uint32 totalMilli = cycles * 1000 / GAME_FRAME_RATE;
+ uint32 delayEnd = g_system->getMillis() + totalMilli;
+
+ while (!_vm->shouldQuit() && g_system->getMillis() < delayEnd) {
+ g_system->delayMillis(10);
+
+ pollEvents();
+ }
+}
+
+void EventsManager::waitForNextFrame() {
+ _mouseClicked = false;
+ _mouseReleased = false;
+ _mouseButtons = 0;
+
+ bool mouseClicked = false;
+ bool mouseReleased = false;
+ int mouseButtons = 0;
+
+ uint32 frameCtr = getFrameCounter();
+ while (!_vm->shouldQuit() && frameCtr == _frameCounter) {
+ delay(1);
+
+ mouseClicked |= _mouseClicked;
+ mouseReleased |= _mouseReleased;
+ mouseButtons |= _mouseButtons;
+ }
+
+ _mouseClicked = mouseClicked;
+ _mouseReleased = mouseReleased;
+ _mouseButtons = mouseButtons;
+ _mouseMoved |= _mouseClicked || _mouseReleased;
+}
+
+void EventsManager::initVars() {
+ _mousePos = Common::Point(-1, -1);
+ _mouseStatusCopy = _mouseStatus;
+ _vD2 = _vD8 = 0;
+}
+
+} // End of namespace MADS
diff --git a/engines/mads/events.h b/engines/mads/events.h
new file mode 100644
index 0000000000..3d7504c0bd
--- /dev/null
+++ b/engines/mads/events.h
@@ -0,0 +1,164 @@
+/* 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.
+ *
+ */
+
+#ifndef MADS_EVENTS_H
+#define MADS_EVENTS_H
+
+#include "common/scummsys.h"
+#include "common/events.h"
+#include "common/stack.h"
+#include "mads/assets.h"
+#include "mads/sprites.h"
+
+namespace MADS {
+
+enum CursorType { CURSOR_NONE = 0, CURSOR_ARROW = 1, CURSOR_WAIT = 2, CURSOR_GO_DOWN = 3,
+ CURSOR_GO_UP = 4, CURSOR_GO_LEFT = 5, CURSOR_GO_RIGHT = 6 };
+
+#define GAME_FRAME_RATE 50
+#define GAME_FRAME_TIME (1000 / GAME_FRAME_RATE)
+
+class MADSEngine;
+
+class EventsManager {
+private:
+ MADSEngine *_vm;
+ uint32 _frameCounter;
+ uint32 _priorFrameTime;
+ Common::Point _mousePos;
+ Common::Point _currentPos;
+
+ /**
+ * Updates the cursor image when the current cursor changes
+ */
+ void changeCursor();
+
+ /**
+ * Checks for whether the next game frame number has been reached.
+ */
+ void checkForNextFrameCounter();
+public:
+ SpriteAsset *_cursorSprites;
+ CursorType _cursorId;
+ CursorType _newCursorId;
+ bool _mouseClicked;
+ bool _mouseReleased;
+ byte _mouseButtons;
+ bool _rightMousePressed;
+ int _mouseStatus;
+ int _vD2;
+ int _mouseStatusCopy;
+ bool _mouseMoved;
+ int _vD8;
+ Common::Stack<Common::Event> _pendingKeys;
+public:
+ /**
+ * Constructor
+ */
+ EventsManager(MADSEngine *vm);
+
+ /**
+ * Destructor
+ */
+ ~EventsManager();
+
+ /**
+ * Loads the sprite set containing the cursors
+ */
+ void loadCursors(const Common::String &spritesName);
+
+ /**
+ * Sets the cursor
+ */
+ void setCursor(CursorType cursorId);
+
+ /**
+ * Sets the cursor
+ */
+ void setCursor2(CursorType cursorId);
+
+ /**
+ * Show the mouse cursor
+ */
+ void showCursor();
+
+ /**
+ * Hide the mouse cursor
+ */
+ void hideCursor();
+
+ /**
+ * Returns if the mouse cursor is visible
+ */
+ bool isCursorVisible();
+
+ /**
+ * Shows the wait cursor
+ */
+ void waitCursor();
+
+ /**
+ * Free currently loaded cursors
+ */
+ void freeCursors();
+
+ /**
+ * Poll any pending events
+ */
+ void pollEvents();
+
+ /**
+ * Return the current mouse position
+ */
+ Common::Point mousePos() const { return _mousePos; }
+
+ /**
+ * Return the current mouse position
+ */
+ Common::Point currentPos() const { return _currentPos; }
+
+ /**
+ * Delay for a given number of frames
+ */
+ void delay(int amount);
+
+ /**
+ * Wait for the next frame
+ */
+ void waitForNextFrame();
+
+ /**
+ * Gets the current frame counter
+ */
+ uint32 getFrameCounter() const { return _frameCounter; }
+
+ void initVars();
+
+ /**
+ * Returns true if there's any pending keys to be processed
+ */
+ bool isKeyPressed() const { return !_pendingKeys.empty(); }
+};
+
+} // End of namespace MADS
+
+#endif /* MADS_EVENTS_H */
diff --git a/engines/mads/font.cpp b/engines/mads/font.cpp
new file mode 100644
index 0000000000..6f2d2b8168
--- /dev/null
+++ b/engines/mads/font.cpp
@@ -0,0 +1,246 @@
+/* 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 "mads/mads.h"
+#include "mads/compression.h"
+#include "mads/font.h"
+#include "mads/msurface.h"
+
+namespace MADS {
+
+MADSEngine *Font::_vm;
+
+Common::HashMap<Common::String, Font *> *Font::_fonts;
+
+uint8 Font::_fontColors[4];
+
+void Font::init(MADSEngine *vm) {
+ _vm = vm;
+ _fontColors[0] = 0xFF;
+ _fontColors[1] = 0xF;
+ _fontColors[2] = 7;
+ _fontColors[3] = 8;
+
+ _fonts = new Common::HashMap<Common::String, Font *>();
+}
+
+void Font::deinit() {
+ Common::HashMap<Common::String, Font *>::iterator i;
+ for (i = _fonts->begin(); i != _fonts->end(); ++i)
+ delete (*i)._value;
+
+ delete _fonts;
+}
+
+Font *Font::getFont(const Common::String &fontName) {
+ if (_fonts->contains(fontName)) {
+ return _fonts->getVal(fontName);
+ } else {
+ Font *font = new Font(fontName);
+ _fonts->setVal(fontName, font);
+ return font;
+ }
+}
+
+Font::Font() {
+ setFont(FONT_INTERFACE);
+}
+
+Font::Font(const Common::String &filename) {
+ setFont(filename);
+}
+
+Font::~Font() {
+ delete[] _charWidths;
+ delete[] _charOffs;
+ delete[] _charData;
+}
+
+void Font::setFont(const Common::String &filename) {
+ if (!_filename.empty() && (filename == _filename))
+ // Already using specified font, so don't bother reloading
+ return;
+
+ _filename = filename;
+
+ MadsPack fontData(filename, _vm);
+ Common::SeekableReadStream *fontFile = fontData.getItemStream(0);
+
+ _maxHeight = fontFile->readByte();
+ _maxWidth = fontFile->readByte();
+
+ _charWidths = new uint8[128];
+ // Char data is shifted by 1
+ _charWidths[0] = 0;
+ fontFile->read(_charWidths + 1, 127);
+ fontFile->readByte(); // remainder
+
+ _charOffs = new uint16[128];
+
+ uint startOffs = 2 + 128 + 256;
+ uint fontSize = fontFile->size() - startOffs;
+
+ // Char data is shifted by 1
+ _charOffs[0] = 0;
+ for (int i = 1; i < 128; i++)
+ _charOffs[i] = fontFile->readUint16LE() - startOffs;
+ fontFile->readUint16LE(); // remainder
+
+ _charData = new uint8[fontSize];
+ fontFile->read(_charData, fontSize);
+
+ delete fontFile;
+}
+
+void Font::setColors(uint8 v1, uint8 v2, uint8 v3, uint8 v4) {
+ _fontColors[0] = v1;
+ _fontColors[1] = v2;
+ _fontColors[2] = v3;
+ _fontColors[3] = v4;
+}
+
+void Font::setColorMode(SelectionMode mode) {
+ switch (mode) {
+ case SELMODE_UNSELECTED:
+ setColors(0xFF, 4, 4, 0);
+ break;
+ case SELMODE_HIGHLIGHTED:
+ setColors(0xFF, 5, 5, 0);
+ break;
+ case SELMODE_SELECTED:
+ setColors(0xFF, 6, 6, 0);
+ break;
+ default:
+ break;
+ }
+}
+
+int Font::writeString(MSurface *surface, const Common::String &msg, const Common::Point &pt,
+ int spaceWidth, int width) {
+ int xEnd;
+ if (width > 0)
+ xEnd = MIN((int)surface->w, pt.x + width);
+ else
+ xEnd = surface->w;
+
+ int x = pt.x;
+ int y = pt.y;
+
+ int skipY = 0;
+ if (y < 0) {
+ skipY = -y;
+ y = 0;
+ }
+
+ int height = MAX(0, _maxHeight - skipY);
+ if (height == 0)
+ return x;
+
+ int bottom = y + height - 1;
+ if (bottom > surface->getHeight() - 1) {
+ height -= MIN(height, bottom - (surface->getHeight() - 1));
+ }
+
+ if (height <= 0)
+ return x;
+
+ byte *destPtr = surface->getBasePtr(x, y);
+ uint8 *oldDestPtr = destPtr;
+
+ int xPos = x;
+
+ const char *text = msg.c_str();
+ while (*text) {
+ char theChar = (*text++) & 0x7F;
+ int charWidth = _charWidths[(byte)theChar];
+
+ if (charWidth > 0) {
+
+ if (xPos + charWidth > xEnd)
+ return xPos;
+
+ uint8 *charData = &_charData[_charOffs[(byte)theChar]];
+ int bpp = getBpp(charWidth);
+
+ if (skipY != 0)
+ charData += bpp * skipY;
+
+ for (int i = 0; i < height; i++) {
+ for (int j = 0; j < bpp; j++) {
+ if (*charData & 0xc0)
+ *destPtr = _fontColors[(*charData & 0xc0) >> 6];
+ destPtr++;
+ if (*charData & 0x30)
+ *destPtr = _fontColors[(*charData & 0x30) >> 4];
+ destPtr++;
+ if (*charData & 0x0C)
+ *destPtr = _fontColors[(*charData & 0x0C) >> 2];
+ destPtr++;
+ if (*charData & 0x03)
+ *destPtr = _fontColors[*charData & 0x03];
+ destPtr++;
+ charData++;
+ }
+
+ destPtr += surface->getWidth() - bpp * 4;
+
+ }
+
+ destPtr = oldDestPtr + charWidth + spaceWidth;
+ oldDestPtr = destPtr;
+
+ }
+
+ xPos += charWidth + spaceWidth;
+
+ }
+
+ return xPos;
+
+}
+
+int Font::getWidth(const Common::String &msg, int spaceWidth) {
+ int width = 0;
+ const char *text = msg.c_str();
+
+ if (msg.size() > 0) {
+ while (*text)
+ width += _charWidths[*text++ & 0x7F] + spaceWidth;
+ width -= spaceWidth;
+ }
+
+ return width;
+}
+
+int Font::getBpp(int charWidth) {
+ if (charWidth > 12)
+ return 4;
+ else if (charWidth > 8)
+ return 3;
+ else if (charWidth > 4)
+ return 2;
+ else
+ return 1;
+}
+
+} // End of namespace MADS
diff --git a/engines/mads/font.h b/engines/mads/font.h
new file mode 100644
index 0000000000..1d733280df
--- /dev/null
+++ b/engines/mads/font.h
@@ -0,0 +1,95 @@
+/* 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.
+ *
+ */
+
+#ifndef MADS_FONT_H
+#define MADS_FONT_H
+
+#include "common/scummsys.h"
+#include "common/hashmap.h"
+#include "common/endian.h"
+#include "common/util.h"
+#include "mads/msurface.h"
+
+namespace MADS {
+
+#define FONT_CONVERSATION "*FONTCONV.FF"
+#define FONT_INTERFACE "*FONTINTR.FF"
+#define FONT_MAIN "*FONTMAIN.FF"
+#define FONT_MENU "*FONTMENU.FF" // Not in Rex (uses bitmap files for menu strings)
+#define FONT_MISC "*FONTMISC.FF"
+#define FONT_TELE "*FONTTELE.FF" // Not in Phantom
+#define FONT_PHAN "*FONTPHAN.FF" // Phantom only
+
+enum SelectionMode {
+ SELMODE_UNSELECTED = 0, SELMODE_HIGHLIGHTED = 1, SELMODE_SELECTED = 2
+};
+
+class MADSEngine;
+
+class Font {
+private:
+ static uint8 _fontColors[4];
+ static MADSEngine *_vm;
+ static Common::HashMap<Common::String, Font *> *_fonts;
+public:
+ /**
+ * Initialise the font system
+ */
+ static void init(MADSEngine *vm);
+
+ /**
+ * Free up the resources used by the font
+ */
+ static void deinit();
+
+ /**
+ * Returns a new Font instance using the specified font name
+ */
+ static Font *getFont(const Common::String &fontName);
+private:
+ uint8 _maxWidth, _maxHeight;
+ uint8 *_charWidths;
+ uint16 *_charOffs;
+ uint8 *_charData;
+ Common::String _filename;
+
+ int getBpp(int charWidth);
+
+ void setFont(const Common::String &filename);
+public:
+ Font();
+ Font(const Common::String &filename);
+ virtual ~Font();
+
+ void setColors(uint8 v1, uint8 v2, uint8 v3, uint8 v4);
+ void setColorMode(SelectionMode mode);
+
+ int maxWidth() const { return _maxWidth; }
+ int getWidth(const Common::String &msg, int spaceWidth = -1);
+ int getHeight() const { return _maxHeight; }
+ int writeString(MSurface *surface, const Common::String &msg, const Common::Point &pt,
+ int spaceWidth = 0, int width = 0);
+};
+
+} // End of namespace MADS
+
+#endif /* MADS_FONT_H */
diff --git a/engines/mads/game.cpp b/engines/mads/game.cpp
new file mode 100644
index 0000000000..3f424711f7
--- /dev/null
+++ b/engines/mads/game.cpp
@@ -0,0 +1,593 @@
+/* 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 "common/config-manager.h"
+#include "common/memstream.h"
+#include "common/serializer.h"
+#include "graphics/palette.h"
+#include "graphics/scaler.h"
+#include "graphics/thumbnail.h"
+#include "mads/mads.h"
+#include "mads/compression.h"
+#include "mads/game.h"
+#include "mads/game_data.h"
+#include "mads/events.h"
+#include "mads/screen.h"
+#include "mads/msurface.h"
+#include "mads/resources.h"
+#include "mads/dragonsphere/game_dragonsphere.h"
+#include "mads/nebular/game_nebular.h"
+#include "mads/phantom/game_phantom.h"
+
+namespace MADS {
+
+Game *Game::init(MADSEngine *vm) {
+ switch (vm->getGameID()) {
+ case GType_RexNebular:
+ return new Nebular::GameNebular(vm);
+ case GType_Dragonsphere:
+ return new Dragonsphere::GameDragonsphere(vm);
+ case GType_Phantom:
+ return new Phantom::GamePhantom(vm);
+ default:
+ error("Game: Unknown game");
+ }
+
+ return nullptr;
+}
+
+Game::Game(MADSEngine *vm): _vm(vm), _surface(nullptr), _objects(vm),
+ _scene(vm), _screenObjects(vm), _player(vm) {
+ _sectionNumber = _priorSectionNumber = 0;
+ _loadGameSlot = -1;
+ _lastSave = -1;
+ _saveFile = nullptr;
+ _statusFlag = 0;
+ _sectionHandler = nullptr;
+ _sectionNumber = 1;
+ _priorSectionNumber = 0;
+ _currentSectionNumber = -1;
+ _kernelMode = KERNEL_GAME_LOAD;
+ _quoteEmergency = false;
+ _vocabEmergency = false;
+ _aaName = "*I0.AA";
+ _priorFrameTimer = 0;
+ _anyEmergency = false;
+ _triggerMode = SEQUENCE_TRIGGER_PARSER;
+ _triggerSetupMode = SEQUENCE_TRIGGER_DAEMON;
+ _winStatus = 0;
+ _widepipeCtr = 0;
+
+ // Load the inventory object list
+ _objects.load();
+ if (_objects._inventoryList.size() > 0)
+ // At least one item in default inventory, so select first item for display
+ _scene._userInterface._selectedInvIndex = 0;
+
+ // Load the quotes
+ loadQuotes();
+}
+
+Game::~Game() {
+ delete _saveFile;
+ delete _surface;
+ delete _sectionHandler;
+}
+
+void Game::run() {
+ initializeGlobals();
+
+ // If requested, load a savegame instead of showing the intro
+ if (ConfMan.hasKey("save_slot")) {
+ int saveSlot = ConfMan.getInt("save_slot");
+ if (saveSlot >= 0 && saveSlot <= 999)
+ _loadGameSlot = saveSlot;
+ }
+
+ _statusFlag = true;
+ int protectionResult = -1;
+
+ if (_loadGameSlot == -1) {
+ protectionResult = checkCopyProtection();
+ switch (protectionResult) {
+ case PROTECTION_FAIL:
+ // Copy protection failed
+ _scene._nextSceneId = 804;
+ break;
+ case PROTECTION_ESCAPE:
+ // User escaped out of copy protection dialog
+ _vm->quitGame();
+ break;
+ default:
+ // Copy protection check succeeded
+ _scene._nextSceneId = 101;
+ _scene._priorSceneId = -1;
+ break;
+ }
+ }
+
+ // Get the initial starting time for the first scene
+ _scene._frameStartTime = _vm->_events->getFrameCounter();
+
+ if (_saveFile == nullptr && protectionResult != -1 && protectionResult != -2) {
+ initSection(_sectionNumber);
+ _statusFlag = true;
+
+ _vm->_dialogs->_pendingDialog = DIALOG_DIFFICULTY;
+ _vm->_dialogs->showDialog();
+ _vm->_dialogs->_pendingDialog = DIALOG_NONE;
+
+ _priorSectionNumber = 0;
+ _priorSectionNumber = -1;
+ _scene._priorSceneId = 0;
+ _scene._currentSceneId = -1;
+ }
+
+ if (protectionResult != 1 && protectionResult != 2) {
+ initializeGlobals();
+ }
+
+ if (_statusFlag)
+ gameLoop();
+}
+
+void Game::gameLoop() {
+ while (!_vm->shouldQuit() && _statusFlag) {
+ if (_loadGameSlot != -1) {
+ loadGame(_loadGameSlot);
+ _loadGameSlot = -1;
+ }
+
+ setSectionHandler();
+ _sectionHandler->preLoadSection();
+ initSection(_sectionNumber);
+ _vm->_sound->init(_sectionNumber);
+ _sectionHandler->postLoadSection();
+
+ _scene._spriteSlots.reset();
+
+ if (_sectionNumber == _currentSectionNumber)
+ sectionLoop();
+
+ _player.releasePlayerSprites();
+ assert(_scene._sprites._assetCount == 0);
+
+ _vm->_palette->unlock();
+ _vm->_events->waitCursor();
+ _vm->_events->freeCursors();
+ _vm->_sound->closeDriver();
+ }
+
+ _vm->_palette->close();
+}
+
+void Game::sectionLoop() {
+ while (!_vm->shouldQuit() && _statusFlag && (_sectionNumber == _currentSectionNumber)) {
+ _kernelMode = KERNEL_ROOM_PRELOAD;
+ _player._spritesChanged = true;
+ _quoteEmergency = false;
+ _vocabEmergency = false;
+ _vm->_events->waitCursor();
+
+ _scene.clearVocab();
+ _scene._dynamicHotspots.clear();
+ _scene.loadSceneLogic();
+
+ _player._walkAnywhere = false;
+ _player._stepEnabled = true;
+ _player._visible = true;
+ _vm->_dialogs->_defaultPosition = Common::Point(-1, -1);
+ _visitedScenes.add(_scene._nextSceneId);
+
+ // Reset the user interface
+ _screenObjects._forceRescan = true;
+ _screenObjects._inputMode = kInputBuildingSentences;
+ _scene._userInterface._scrollbarActive = SCROLLBAR_NONE;
+
+ _player._loadsFirst = true;
+
+ _scene._sceneLogic->setup();
+ if (_player._spritesChanged || _player._loadsFirst) {
+ if (_player._spritesLoaded)
+ _player.releasePlayerSprites();
+ _vm->_palette->resetGamePalette(18, 10);
+ _scene._spriteSlots.reset();
+ } else {
+ _vm->_palette->initPalette();
+ }
+
+ // Set up scene palette usage
+ _scene._scenePaletteUsage.clear();
+ _scene._scenePaletteUsage.push_back(PaletteUsage::UsageEntry(0xF0));
+ _scene._scenePaletteUsage.push_back(PaletteUsage::UsageEntry(0xF1));
+ _scene._scenePaletteUsage.push_back(PaletteUsage::UsageEntry(0xF2));
+ _vm->_palette->_paletteUsage.load(&_scene._scenePaletteUsage);
+
+ if (!_player._spritesLoaded && _player._loadsFirst) {
+ if (_player.loadSprites(""))
+ _vm->quitGame();
+ _player._loadedFirst = true;
+ }
+
+ _scene.loadScene(_scene._nextSceneId, _aaName, 0);
+ _vm->_sound->pauseNewCommands();
+
+ if (!_player._spritesLoaded) {
+ if (_player.loadSprites(""))
+ _vm->quitGame();
+ _player._loadedFirst = false;
+ }
+
+ _vm->_events->initVars();
+ _scene._userInterface._highlightedCommandIndex = -1;
+ _scene._userInterface._highlightedInvIndex = -1;
+ _scene._userInterface._highlightedItemVocabIndex = -1;
+
+ _scene._action.clear();
+ _player.setFinalFacing();
+ _player._facing = _player._turnToFacing;
+ _player.cancelCommand();
+ _kernelMode = KERNEL_ROOM_INIT;
+
+ switch (_vm->_screenFade) {
+ case SCREEN_FADE_SMOOTH:
+ _fx = kTransitionFadeOutIn;
+ break;
+ case SCREEN_FADE_FAST:
+ _fx = kCenterVertTransition;
+ break;
+ default:
+ _fx = kTransitionNone;
+ break;
+ }
+
+ _trigger = 0;
+ _priorFrameTimer = _scene._frameStartTime;
+
+ // Call the scene logic for entering the given scene
+ _triggerSetupMode = SEQUENCE_TRIGGER_DAEMON;
+ _scene._sceneLogic->enter();
+
+ // If in the middle of restoring a game, handle the rest of the loading
+ if (_saveFile != nullptr) {
+ Common::Serializer s(_saveFile, nullptr);
+ synchronize(s, false);
+ delete _saveFile;
+ _saveFile = nullptr;
+ }
+
+ // Set player data
+ _player._targetPos = _player._playerPos;
+ _player._turnToFacing = _player._facing;
+ _player._targetFacing = _player._facing;
+ _player.selectSeries();
+ _player.updateFrame();
+
+ _player._beenVisible = _player._visible;
+ _player._special = _scene.getDepthHighBits(_player._playerPos);
+ _player._priorTimer = _scene._frameStartTime - _player._ticksAmount;
+ _player.idle();
+
+ if (_scene._userInterface._selectedInvIndex >= 0) {
+ _scene._userInterface.loadInventoryAnim(
+ _objects._inventoryList[_scene._userInterface._selectedInvIndex]);
+ } else {
+ _scene._userInterface.noInventoryAnim();
+ }
+
+ _kernelMode = KERNEL_ACTIVE_CODE;
+ _scene._roomChanged = false;
+
+ if ((_quoteEmergency || _vocabEmergency) && !_anyEmergency) {
+ _scene._currentSceneId = _scene._priorSceneId;
+ _anyEmergency = true;
+ } else {
+ _anyEmergency = false;
+ _scene.loop();
+ }
+
+ _vm->_events->waitCursor();
+ _kernelMode = KERNEL_ROOM_PRELOAD;
+
+ delete _scene._activeAnimation;
+ _scene._activeAnimation = nullptr;
+
+ _scene._reloadSceneFlag = false;
+
+ _scene._userInterface.noInventoryAnim();
+ _scene.removeSprites();
+
+ if (!_player._loadedFirst) {
+ _player._spritesLoaded = false;
+ _player._spritesChanged = true;
+ }
+
+ // Clear the scene
+ _scene.freeCurrentScene();
+ _sectionNumber = _scene._nextSceneId / 100;
+
+ // Check whether to show a dialog
+ checkShowDialog();
+ }
+}
+
+void Game::initSection(int sectionNumber) {
+ _priorSectionNumber = _currentSectionNumber;
+ _currentSectionNumber = sectionNumber;
+
+ _vm->_palette->resetGamePalette(18, 10);
+ _vm->_palette->setLowRange();
+
+ if (_scene._layer == LAYER_GUI)
+ _vm->_palette->setPalette(_vm->_palette->_mainPalette, 0, 4);
+
+ _vm->_events->loadCursors("*CURSOR.SS");
+
+ assert(_vm->_events->_cursorSprites);
+ _vm->_events->setCursor2((_vm->_events->_cursorSprites->getCount() <= 1) ?
+ CURSOR_ARROW : CURSOR_WAIT);
+}
+
+void Game::loadQuotes() {
+ File f("*QUOTES.DAT");
+
+ Common::String msg;
+ while (true) {
+ uint8 b = f.readByte();
+
+ msg += b;
+ if (f.eos() || b == '\0') {
+ // end of string, add it to the strings list
+ _quotes.push_back(msg);
+ msg = "";
+ }
+
+ if (f.eos()) break;
+ }
+
+ f.close();
+}
+
+Common::StringArray Game::getMessage(uint32 id) {
+ File f("*MESSAGES.DAT");
+ int count = f.readUint16LE();
+
+ for (int idx = 0; idx < count; ++idx) {
+ uint32 itemId = f.readUint32LE();
+ uint32 offset = f.readUint32LE();
+ uint16 size = f.readUint16LE();
+
+ if (itemId == id) {
+ // Get the source buffer size
+ uint16 sizeIn;
+ if (idx == (count - 1)) {
+ sizeIn = f.size() - offset;
+ } else {
+ f.skip(4);
+ uint32 nextOffset = f.readUint32LE();
+ sizeIn = nextOffset - offset;
+ }
+
+ // Get the compressed data
+ f.seek(offset);
+ byte *bufferIn = new byte[sizeIn];
+ f.read(bufferIn, sizeIn);
+
+ // Decompress it
+ char *bufferOut = new char[size];
+ FabDecompressor fab;
+ fab.decompress(bufferIn, sizeIn, (byte *)bufferOut, size);
+
+ // Form the output string list
+ Common::StringArray result;
+ const char *p = bufferOut;
+ while (p < (bufferOut + size)) {
+ result.push_back(p);
+ p += strlen(p) + 1;
+ }
+
+ delete[] bufferIn;
+ delete[] bufferOut;
+ return result;
+ }
+ }
+
+ error("Invalid message Id specified");
+}
+
+static const char *const DEBUG_STRING = "WIDEPIPE";
+
+void Game::handleKeypress(const Common::Event &event) {
+ if (event.kbd.flags & Common::KBD_CTRL) {
+ if (_widepipeCtr == 8) {
+ // Implement original game cheating keys here someday
+ } else {
+ if (event.kbd.keycode == (Common::KEYCODE_a +
+ (DEBUG_STRING[_widepipeCtr] - 'a'))) {
+ if (++_widepipeCtr == 8) {
+ MessageDialog *dlg = new MessageDialog(_vm, 2,
+ "CHEATING ENABLED", "(for your convenience).");
+ dlg->show();
+ delete dlg;
+ }
+ }
+ }
+ }
+
+ switch (event.kbd.keycode) {
+ case Common::KEYCODE_F1:
+ _vm->_dialogs->_pendingDialog = DIALOG_GAME_MENU;
+ break;
+ case Common::KEYCODE_F5:
+ _vm->_dialogs->_pendingDialog = DIALOG_SAVE;
+ break;
+ case Common::KEYCODE_F7:
+ _vm->_dialogs->_pendingDialog = DIALOG_RESTORE;
+ break;
+ default:
+ break;
+ }
+
+ warning("TODO: handleKeypress - %d", (int)event.kbd.keycode);
+}
+
+void Game::synchronize(Common::Serializer &s, bool phase1) {
+ if (phase1) {
+ s.syncAsSint16LE(_fx);
+ s.syncAsSint16LE(_trigger);
+ s.syncAsUint16LE(_triggerSetupMode);
+ s.syncAsUint16LE(_triggerMode);
+ s.syncString(_aaName);
+ s.syncAsSint16LE(_lastSave);
+
+ _scene.synchronize(s);
+ _objects.synchronize(s);
+ _visitedScenes.synchronize(s);
+ _player.synchronize(s);
+ _screenObjects.synchronize(s);
+ } else {
+ // Load scene specific data for the loaded scene
+ _scene._sceneLogic->synchronize(s);
+ }
+}
+
+void Game::loadGame(int slotNumber) {
+ _saveFile = g_system->getSavefileManager()->openForLoading(
+ _vm->generateSaveName(slotNumber));
+
+ Common::Serializer s(_saveFile, nullptr);
+
+ // Load the savaegame header
+ MADSSavegameHeader header;
+ if (!readSavegameHeader(_saveFile, header))
+ error("Invalid savegame");
+
+ if (header._thumbnail) {
+ header._thumbnail->free();
+ delete header._thumbnail;
+ }
+
+ // Load most of the savegame data with the exception of scene specific info
+ synchronize(s, true);
+
+ // Set up section/scene and other initial states for post-load
+ _currentSectionNumber = -2;
+ _scene._currentSceneId = -2;
+ _sectionNumber = _scene._nextSceneId / 100;
+ _scene._frameStartTime = _vm->_events->getFrameCounter();
+ _vm->_screen._shakeCountdown = -1;
+
+ // Default the selected inventory item to the first one, if the player has any
+ _scene._userInterface._selectedInvIndex = _objects._inventoryList.size() > 0 ? 0 : -1;
+
+ // Set player sprites sets flags
+ _player._spritesLoaded = false;
+ _player._spritesChanged = true;
+}
+
+void Game::saveGame(int slotNumber, const Common::String &saveName) {
+ Common::OutSaveFile *out = g_system->getSavefileManager()->openForSaving(
+ _vm->generateSaveName(slotNumber));
+
+ MADSSavegameHeader header;
+ header._saveName = saveName;
+ writeSavegameHeader(out, header);
+
+ Common::Serializer s(nullptr, out);
+ synchronize(s, true);
+ synchronize(s, false);
+
+ out->finalize();
+ delete out;
+}
+
+const char *const SAVEGAME_STR = "MADS";
+#define SAVEGAME_STR_SIZE 4
+
+bool Game::readSavegameHeader(Common::InSaveFile *in, MADSSavegameHeader &header) {
+ char saveIdentBuffer[SAVEGAME_STR_SIZE + 1];
+ header._thumbnail = nullptr;
+
+ // Validate the header Id
+ in->read(saveIdentBuffer, SAVEGAME_STR_SIZE + 1);
+ if (strncmp(saveIdentBuffer, SAVEGAME_STR, SAVEGAME_STR_SIZE))
+ return false;
+
+ header._version = in->readByte();
+ if (header._version > MADS_SAVEGAME_VERSION)
+ return false;
+
+ // Read in the string
+ header._saveName.clear();
+ char ch;
+ while ((ch = (char)in->readByte()) != '\0') header._saveName += ch;
+
+ // Get the thumbnail
+ header._thumbnail = Graphics::loadThumbnail(*in);
+ if (!header._thumbnail)
+ return false;
+
+ // Read in save date/time
+ header._year = in->readSint16LE();
+ header._month = in->readSint16LE();
+ header._day = in->readSint16LE();
+ header._hour = in->readSint16LE();
+ header._minute = in->readSint16LE();
+ header._totalFrames = in->readUint32LE();
+
+ return true;
+}
+
+void Game::writeSavegameHeader(Common::OutSaveFile *out, MADSSavegameHeader &header) {
+ // Write out a savegame header
+ out->write(SAVEGAME_STR, SAVEGAME_STR_SIZE + 1);
+
+ out->writeByte(MADS_SAVEGAME_VERSION);
+
+ // Write savegame name
+ out->write(header._saveName.c_str(), header._saveName.size());
+ out->writeByte('\0');
+
+ // Get the active palette
+ uint8 thumbPalette[256 * 3];
+ g_system->getPaletteManager()->grabPalette(thumbPalette, 0, 256);
+
+ // Create a thumbnail and save it
+ Graphics::Surface *thumb = new Graphics::Surface();
+ ::createThumbnail(thumb, _vm->_screen.getData(), MADS_SCREEN_WIDTH, MADS_SCREEN_HEIGHT, thumbPalette);
+ Graphics::saveThumbnail(*out, *thumb);
+ thumb->free();
+ delete thumb;
+
+ // Write out the save date/time
+ TimeDate td;
+ g_system->getTimeAndDate(td);
+ out->writeSint16LE(td.tm_year + 1900);
+ out->writeSint16LE(td.tm_mon + 1);
+ out->writeSint16LE(td.tm_mday);
+ out->writeSint16LE(td.tm_hour);
+ out->writeSint16LE(td.tm_min);
+ out->writeUint32LE(_vm->_events->getFrameCounter());
+}
+
+} // End of namespace MADS
diff --git a/engines/mads/game.h b/engines/mads/game.h
new file mode 100644
index 0000000000..a55de617fd
--- /dev/null
+++ b/engines/mads/game.h
@@ -0,0 +1,229 @@
+/* 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.
+ *
+ */
+
+#ifndef MADS_GAME_H
+#define MADS_GAME_H
+
+#include "common/scummsys.h"
+#include "common/savefile.h"
+#include "common/str-array.h"
+#include "common/serializer.h"
+#include "mads/audio.h"
+#include "mads/scene.h"
+#include "mads/game_data.h"
+#include "mads/globals.h"
+#include "mads/inventory.h"
+#include "mads/player.h"
+#include "mads/screen.h"
+
+namespace MADS {
+
+class MADSEngine;
+
+enum {
+ PLAYER_INVENTORY = 2
+};
+
+enum KernelMode {
+ KERNEL_GAME_LOAD = 0, KERNEL_SECTION_PRELOAD = 1, KERNEL_SECTION_INIT = 2,
+ KERNEL_ROOM_PRELOAD = 3, KERNEL_ROOM_INIT = 4, KERNEL_ACTIVE_CODE = 5
+};
+
+enum ProtectionResult {
+ PROTECTION_SUCCEED = 0, PROTECTION_FAIL = 1, PROTECTION_ESCAPE = 2
+};
+
+#define MADS_SAVEGAME_VERSION 1
+
+struct MADSSavegameHeader {
+ uint8 _version;
+ Common::String _saveName;
+ Graphics::Surface *_thumbnail;
+ int _year, _month, _day;
+ int _hour, _minute;
+ int _totalFrames;
+};
+
+class Game {
+private:
+ /**
+ * Main game loop
+ */
+ void gameLoop();
+
+ /**
+ * Inner game loop for executing gameplay within a game section
+ */
+ void sectionLoop();
+
+ /**
+ * Load quotes data
+ */
+ void loadQuotes();
+protected:
+ MADSEngine *_vm;
+ MSurface *_surface;
+ int _statusFlag;
+ Common::StringArray _quotes;
+ bool _quoteEmergency;
+ bool _vocabEmergency;
+ bool _anyEmergency;
+ int _lastSave;
+ Common::String _saveName;
+ Common::InSaveFile *_saveFile;
+
+ /**
+ * Constructor
+ */
+ Game(MADSEngine *vm);
+
+ /**
+ * Initialises the current section number of the game
+ */
+ void initSection(int sectionNumber);
+
+ //@{
+ /** @name Virtual Method list */
+
+ /**
+ * Perform any copy protection check
+ */
+ virtual ProtectionResult checkCopyProtection() = 0;
+
+ /**
+ * Initialises global variables for a new game
+ */
+ virtual void initializeGlobals() = 0;
+
+ /**
+ * Set up the section handler specific to each section
+ */
+ virtual void setSectionHandler() = 0;
+
+ /**
+ * Checks for whether to show a dialog
+ */
+ virtual void checkShowDialog() = 0;
+
+ //@}
+
+public:
+ static Game *init(MADSEngine *vm);
+
+public:
+ Player _player;
+ ScreenObjects _screenObjects;
+ int _sectionNumber;
+ int _priorSectionNumber;
+ int _currentSectionNumber;
+ InventoryObjects _objects;
+ SectionHandler *_sectionHandler;
+ VisitedScenes _visitedScenes;
+ Scene _scene;
+ KernelMode _kernelMode;
+ int _trigger;
+ ScreenTransition _fx;
+ TriggerMode _triggerMode;
+ TriggerMode _triggerSetupMode;
+ uint32 _priorFrameTimer;
+ Common::String _aaName;
+ int _winStatus;
+ int _widepipeCtr;
+ int _loadGameSlot;
+
+public:
+ virtual ~Game();
+
+ /**
+ * Main outer loop for the game
+ */
+ void run();
+
+ uint32 getQuotesSize() { return _quotes.size(); }
+ const Common::String &getQuote(uint32 index) { return _quotes[index - 1]; }
+ void splitQuote(Common::String quote, Common::String part1, Common::String part2) {warning("TODO: splitQuote()");}
+ Common::StringArray getMessage(uint32 id);
+
+ /**
+ * Returns the globals for the game
+ */
+ virtual Globals &globals() = 0;
+
+ /**
+ * Standard object handling across the game
+ */
+ virtual void doObjectAction() = 0;
+
+ /**
+ * Fallback handler for any action that isn't explicitly handled
+ */
+ virtual void unhandledAction() = 0;
+
+ /**
+ * Global game step
+ */
+ virtual void step() = 0;
+
+ /**
+ * Synchronise the game data
+ * @param s Serializer
+ * @param phase1 If true, it's synchronising the basic scene information
+ */
+ virtual void synchronize(Common::Serializer &s, bool phase1);
+
+ // DEPRECATED: ScummVM re-implementation keeps all the quotes loaded, so the methods below are stubs
+ void clearQuotes() {}
+ void loadQuoteRange(int startNum, int endNum) {}
+ void loadQuoteSet(...) {}
+ void loadQuote(int quoteNum) {}
+
+ /**
+ * Handle a keyboard event
+ */
+ void handleKeypress(const Common::Event &event);
+
+ /**
+ * Starts a savegame loading.
+ * @remarks Due to the way the engine is implemented, loading is done in two
+ * parts, the second part after the specific scene has been loaded
+ */
+ void loadGame(int slotNumber);
+
+ /**
+ * Save the current game
+ */
+ void saveGame(int slotNumber, const Common::String &saveName);
+
+ /**
+ * Write out a savegame header
+ */
+ void writeSavegameHeader(Common::OutSaveFile *out, MADSSavegameHeader &header);
+
+ /**
+ * Read in a savegame header
+ */
+ static bool readSavegameHeader(Common::InSaveFile *in, MADSSavegameHeader &header);
+};
+
+} // End of namespace MADS
+
+#endif /* MADS_GAME_H */
diff --git a/engines/mads/game_data.cpp b/engines/mads/game_data.cpp
new file mode 100644
index 0000000000..0e2dcec70f
--- /dev/null
+++ b/engines/mads/game_data.cpp
@@ -0,0 +1,54 @@
+/* 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 "mads/mads.h"
+#include "mads/game.h"
+#include "mads/nebular/game_nebular.h"
+#include "mads/screen.h"
+#include "mads/msurface.h"
+#include "mads/resources.h"
+
+namespace MADS {
+
+void VisitedScenes::add(int sceneId) {
+ _sceneRevisited = exists(sceneId);
+
+ if (!_sceneRevisited)
+ push_back(sceneId);
+}
+
+bool VisitedScenes::exists(int sceneId) {
+ for (uint i = 0; i < size(); ++i) {
+ if ((*this)[i] == sceneId)
+ return true;
+ }
+
+ return false;
+}
+
+void VisitedScenes::synchronize(Common::Serializer &s) {
+ SynchronizedList::synchronize(s);
+ s.syncAsByte(_sceneRevisited);
+}
+
+} // End of namespace MADS
diff --git a/engines/mads/game_data.h b/engines/mads/game_data.h
new file mode 100644
index 0000000000..6ea59d6d2b
--- /dev/null
+++ b/engines/mads/game_data.h
@@ -0,0 +1,73 @@
+/* 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.
+ *
+ */
+
+#ifndef MADS_GAME_DATA_H
+#define MADS_GAME_DATA_H
+
+#include "common/scummsys.h"
+#include "common/array.h"
+#include "mads/resources.h"
+
+namespace MADS {
+
+class MADSEngine;
+class Game;
+
+class VisitedScenes: public SynchronizedList {
+public:
+ /**
+ * Stores true when a previously visited scene is revisited
+ */
+ bool _sceneRevisited;
+
+ /**
+ * Returns true if a given Scene Id exists in the listed of previously visited scenes.
+ */
+ bool exists(int sceneId);
+
+ /**
+ * Adds a scene Id to the list of previously visited scenes, if it doesn't already exist
+ */
+ void add(int sceneId);
+
+ /**
+ * Synchronizes the list
+ */
+ void synchronize(Common::Serializer &s);
+};
+
+class SectionHandler {
+protected:
+ MADSEngine *_vm;
+public:
+ SectionHandler(MADSEngine *vm): _vm(vm) {}
+ virtual ~SectionHandler() {}
+
+ virtual void preLoadSection() = 0;
+ virtual void sectionPtr2() = 0;
+ virtual void postLoadSection() = 0;
+ virtual void step() {}
+};
+
+} // End of namespace MADS
+
+#endif /* MADS_GAME_DATA_H */
diff --git a/engines/mads/globals.cpp b/engines/mads/globals.cpp
new file mode 100644
index 0000000000..1d088992ea
--- /dev/null
+++ b/engines/mads/globals.cpp
@@ -0,0 +1,33 @@
+/* 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 "mads/globals.h"
+
+namespace MADS {
+
+void Globals::reset() {
+ for (uint i = 0; i < size(); ++i)
+ (*this)[i] = 0;
+}
+
+} // End of namespace MADS
diff --git a/engines/mads/globals.h b/engines/mads/globals.h
new file mode 100644
index 0000000000..92cd0bb403
--- /dev/null
+++ b/engines/mads/globals.h
@@ -0,0 +1,47 @@
+/* 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.
+ *
+ */
+
+#ifndef MADS_GLOBALS_H
+#define MADS_GLOBALS_H
+
+#include "common/scummsys.h"
+#include "common/array.h"
+#include "common/serializer.h"
+#include "mads/resources.h"
+
+namespace MADS {
+
+class Globals: public SynchronizedList {
+public:
+ Globals() {}
+
+ virtual ~Globals() {}
+
+ /*
+ * Resets all the globals to empty
+ */
+ void reset();
+};
+
+} // End of namespace MADS
+
+#endif /* MADS_GLOBALS_H */
diff --git a/engines/mads/hotspots.cpp b/engines/mads/hotspots.cpp
new file mode 100644
index 0000000000..d3ce0a9263
--- /dev/null
+++ b/engines/mads/hotspots.cpp
@@ -0,0 +1,206 @@
+/* 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 "mads/mads.h"
+#include "mads/hotspots.h"
+
+namespace MADS {
+
+DynamicHotspot::DynamicHotspot() {
+ _seqIndex = 0;
+ _facing = FACING_NONE;
+ _descId = 0;
+ _verbId = 0;
+ _articleNumber = 0;
+ _cursor = CURSOR_NONE;
+}
+
+void DynamicHotspot::synchronize(Common::Serializer &s) {
+
+}
+
+/*------------------------------------------------------------------------*/
+
+DynamicHotspots::DynamicHotspots(MADSEngine *vm) : _vm(vm) {
+ for (int i = 0; i < DYNAMIC_HOTSPOTS_SIZE; ++i) {
+ DynamicHotspot rec;
+ rec._active = false;
+ _entries.push_back(rec);
+ }
+
+ _changed = true;
+ _count = 0;
+}
+
+int DynamicHotspots::add(int descId, int verbId, int seqIndex, const Common::Rect &bounds) {
+ // Find a free slot
+ uint idx = 0;
+ while ((idx < _entries.size()) && _entries[idx]._active)
+ ++idx;
+ if (idx == _entries.size())
+ error("DynamicHotspots overflow");
+
+ _entries[idx]._active = true;
+ _entries[idx]._descId = descId;
+ _entries[idx]._seqIndex = seqIndex;
+ _entries[idx]._bounds = bounds;
+ _entries[idx]._feetPos = Common::Point(-3, 0);
+ _entries[idx]._facing = FACING_NONE;
+ _entries[idx]._verbId = verbId;
+ _entries[idx]._articleNumber = PREP_IN;
+ _entries[idx]._cursor = CURSOR_NONE;
+
+ ++_count;
+ _changed = true;
+
+ if (seqIndex >= 0)
+ _vm->_game->_scene._sequences[seqIndex]._dynamicHotspotIndex = idx;
+
+ return idx;
+}
+
+int DynamicHotspots::setPosition(int index, const Common::Point &pos, Facing facing) {
+ if (index >= 0) {
+ _entries[index]._feetPos = pos;
+ _entries[index]._facing = facing;
+ }
+
+ return index;
+}
+
+int DynamicHotspots::setCursor(int index, CursorType cursor) {
+ if (index >= 0)
+ _entries[index]._cursor = cursor;
+
+ return index;
+}
+
+void DynamicHotspots::remove(int index) {
+ Scene &scene = _vm->_game->_scene;
+
+ if (index >= 0 && _entries[index]._active) {
+ if (_entries[index]._seqIndex >= 0)
+ scene._sequences[_entries[index]._seqIndex]._dynamicHotspotIndex = -1;
+ _entries[index]._active = false;
+
+ --_count;
+ _changed = true;
+ }
+}
+
+void DynamicHotspots::clear() {
+ for (uint i = 0; i < _entries.size(); ++i)
+ _entries[i]._active = false;
+
+ _changed = false;
+ _count = 0;
+}
+
+void DynamicHotspots::reset() {
+ for (uint i = 0; i < _entries.size(); ++i)
+ remove(i);
+
+ _count = 0;
+ _changed = false;
+}
+
+void DynamicHotspots::refresh() {
+ // Reset the screen objects back to only contain UI elements
+ ScreenObjects &scrObjects = _vm->_game->_screenObjects;
+ scrObjects.resize(scrObjects._uiCount);
+
+ // Loop through adding hotspots
+ for (uint i = 0; i < _entries.size(); ++i) {
+ DynamicHotspot &dh = (*this)[i];
+
+ if ((*this)[i]._active) {
+ switch (scrObjects._inputMode) {
+ case kInputBuildingSentences:
+ case kInputLimitedSentences:
+ scrObjects.add(dh._bounds, _vm->_game->_scene._layer, CAT_12, dh._descId);
+ scrObjects._forceRescan = true;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+}
+
+void DynamicHotspots::synchronize(Common::Serializer &s) {
+ int count = _entries.size();
+ s.syncAsSint16LE(count);
+
+ if (s.isSaving()) {
+ for (int i = 0; i < count; ++i)
+ _entries[i].synchronize(s);
+ } else {
+ DynamicHotspot rec;
+ rec.synchronize(s);
+ _entries.push_back(rec);
+ }
+}
+
+/*------------------------------------------------------------------------*/
+
+Hotspot::Hotspot() {
+ _facing = FACING_NONE;
+ _articleNumber = 0;
+ _cursor = CURSOR_NONE;
+ _vocabId = 0;
+ _verbId = 0;
+ _active = false;
+}
+
+Hotspot::Hotspot(Common::SeekableReadStream &f, bool isV2) {
+ _bounds.left = f.readSint16LE();
+ _bounds.top = f.readSint16LE();
+ _bounds.right = f.readSint16LE();
+ _bounds.bottom = f.readSint16LE();
+ _feetPos.x = f.readSint16LE();
+ _feetPos.y = f.readSint16LE();
+ _facing = (Facing)f.readByte();
+ _articleNumber = f.readByte();
+ _active = f.readByte() != 0;
+ _cursor = (CursorType)f.readByte();
+ if (isV2) {
+ // This looks to be some sort of bitmask. Perhaps it signifies
+ // the valid verbs for this hotspot
+ f.skip(2); // unknown
+ }
+ _vocabId = f.readUint16LE();
+ _verbId = f.readUint16LE();
+}
+
+/*------------------------------------------------------------------------*/
+
+void Hotspots::activate(int vocabId, bool active) {
+ for (uint idx = 0; idx < size(); ++idx) {
+ Hotspot &hotspot = (*this)[idx];
+ if (hotspot._vocabId == vocabId) {
+ hotspot._active = active;
+ _vm->_game->_screenObjects.setActive(CAT_HOTSPOT, idx, active);
+ }
+ }
+}
+
+} // End of namespace MADS
diff --git a/engines/mads/hotspots.h b/engines/mads/hotspots.h
new file mode 100644
index 0000000000..5fd910e1aa
--- /dev/null
+++ b/engines/mads/hotspots.h
@@ -0,0 +1,114 @@
+/* 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.
+ *
+ */
+
+#ifndef MADS_HOTSPOTS_H
+#define MADS_HOTSPOTS_H
+
+#include "common/scummsys.h"
+#include "mads/events.h"
+#include "mads/player.h"
+
+namespace MADS {
+
+class MADSEngine;
+
+class DynamicHotspot {
+public:
+ bool _active;
+ int _seqIndex;
+ Common::Rect _bounds;
+ Common::Point _feetPos;
+ Facing _facing;
+ int _descId;
+ int _verbId;
+ int _articleNumber;
+ CursorType _cursor;
+
+ /**
+ * Constructor
+ */
+ DynamicHotspot();
+
+ /**
+ * Synchronize the data
+ */
+ void synchronize(Common::Serializer &s);
+};
+
+#define DYNAMIC_HOTSPOTS_SIZE 8
+
+class DynamicHotspots {
+private:
+ MADSEngine *_vm;
+ Common::Array<DynamicHotspot> _entries;
+ int _count;
+public:
+ bool _changed;
+public:
+ DynamicHotspots(MADSEngine *vm);
+
+ Common::Array<MADS::DynamicHotspot>::size_type size() const { return _entries.size(); }
+ DynamicHotspot &operator[](uint idx) { return _entries[idx]; }
+ int add(int descId, int verbId, int seqIndex, const Common::Rect &bounds);
+ int setPosition(int index, const Common::Point &pos, Facing facing);
+ int setCursor(int index, CursorType cursor);
+ void remove(int index);
+ void clear();
+ void reset();
+ void refresh();
+
+ /**
+ * Synchronize the data
+ */
+ void synchronize(Common::Serializer &s);
+};
+
+class Hotspot {
+public:
+ Common::Rect _bounds;
+ Common::Point _feetPos;
+ Facing _facing;
+ int _articleNumber;
+ bool _active;
+ CursorType _cursor;
+ int _vocabId;
+ int _verbId;
+
+ Hotspot();
+ Hotspot(Common::SeekableReadStream &f, bool isV2);
+};
+
+class Hotspots : public Common::Array<Hotspot> {
+private:
+ MADSEngine *_vm;
+public:
+ Hotspots(MADSEngine *vm) : _vm(vm) {}
+
+ /**
+ * Sets the active state of a given hotspot
+ */
+ void activate(int vocabId, bool active);
+};
+
+} // End of namespace MADS
+
+#endif /* MADS_HOTSPOTS_H */
diff --git a/engines/mads/inventory.cpp b/engines/mads/inventory.cpp
new file mode 100644
index 0000000000..434d284244
--- /dev/null
+++ b/engines/mads/inventory.cpp
@@ -0,0 +1,226 @@
+/* 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 "mads/mads.h"
+#include "mads/inventory.h"
+
+namespace MADS {
+
+void InventoryObject::synchronize(Common::Serializer &s) {
+ s.syncAsUint16LE(_descId);
+ s.syncAsUint16LE(_roomNumber);
+ s.syncAsByte(_article);
+ s.syncAsByte(_vocabCount);
+ s.syncAsByte(_qualitiesCount);
+ s.skip(1);
+
+ for (int i = 0; i < MAX_VOCAB; ++i) {
+ s.syncAsUint16LE(_vocabList[i]._vocabId);
+ s.syncAsByte(_vocabList[i]._verbType);
+ s.syncAsByte(_vocabList[i]._prepType);
+ }
+
+ for (int i = 0; i < MAX_QUALITIES; ++i)
+ s.syncAsByte(_qualityId[i]);
+ for (int i = 0; i < MAX_QUALITIES; ++i)
+ s.syncAsSint32LE(_qualityValue[i]);
+}
+
+bool InventoryObject::hasQuality(int qualityId) const {
+ for (int i = 0; i < _qualitiesCount; ++i) {
+ if (_qualityId[i] == qualityId)
+ return true;
+ }
+
+ return false;
+}
+
+void InventoryObject::setQuality(int qualityId, int qualityValue) {
+ for (int i = 0; i < _qualitiesCount; ++i) {
+ if (_qualityId[i] == qualityId) {
+ _qualityValue[i] = qualityValue;
+ }
+ }
+}
+
+int InventoryObject::getQuality(int qualityId) const {
+ for (int i = 0; i < _qualitiesCount; ++i) {
+ if (_qualityId[i] == qualityId) {
+ return _qualityValue[i];
+ }
+ }
+
+ return 0;
+}
+
+/*------------------------------------------------------------------------*/
+
+void InventoryObjects::load() {
+ File f("*OBJECTS.DAT");
+ int count = f.readUint16LE();
+ Common::Serializer s(&f, nullptr);
+
+ // Load the objects data
+ reserve(count);
+ for (int i = 0; i < count; ++i) {
+ InventoryObject obj;
+ obj.synchronize(s);
+ push_back(obj);
+
+ // If it's for the player's inventory, add the index to the inventory list
+ if (obj._roomNumber == PLAYER_INVENTORY) {
+ _inventoryList.push_back(i);
+ assert(_inventoryList.size() <= 32);
+ }
+ }
+}
+
+void InventoryObjects::synchronize(Common::Serializer &s) {
+ int count = size();
+ s.syncAsUint16LE(count);
+
+ if (s.isSaving()) {
+ // Store the data for each object in the inventory lsit
+ for (int idx = 0; idx < count; ++idx)
+ (*this)[idx].synchronize(s);
+
+ // Synchronize the player's inventory
+ _inventoryList.synchronize(s);
+ } else {
+ clear();
+
+ // Read in each object
+ reserve(count);
+ for (int i = 0; i < count; ++i) {
+ InventoryObject obj;
+ obj.synchronize(s);
+ push_back(obj);
+ }
+
+ // Synchronize the player's inventory
+ _inventoryList.synchronize(s);
+ }
+}
+
+void InventoryObjects::setRoom(int objectId, int sceneNumber) {
+ InventoryObject &obj = (*this)[objectId];
+
+ if (obj._roomNumber == PLAYER_INVENTORY)
+ removeFromInventory(objectId, 1);
+
+ if (sceneNumber == PLAYER_INVENTORY)
+ addToInventory(objectId);
+ else
+ obj._roomNumber = sceneNumber;
+}
+
+bool InventoryObjects::isInRoom(int objectId) const {
+ return objectId >= 0 && (*this)[objectId]._roomNumber == _vm->_game->_scene._currentSceneId;
+}
+
+bool InventoryObjects::isInInventory(int objectId) const {
+ return objectId >= 0 && (*this)[objectId]._roomNumber == PLAYER_INVENTORY;
+}
+
+void InventoryObjects::addToInventory(int objectId) {
+ assert(_inventoryList.size() < 32);
+ UserInterface &userInterface = _vm->_game->_scene._userInterface;
+
+ if (!isInInventory(objectId)) {
+ _inventoryList.push_back(objectId);
+ userInterface._selectedInvIndex = _inventoryList.size() - 1;
+ userInterface._inventoryTopIndex = CLIP(userInterface._inventoryTopIndex,
+ 0, (int)_inventoryList.size() - 1);
+
+ if ((userInterface._inventoryTopIndex + 5) <= (int)_inventoryList.size())
+ userInterface._inventoryTopIndex = size() - 4;
+ userInterface._inventoryChanged = true;
+
+ (*this)[objectId]._roomNumber = PLAYER_INVENTORY;
+
+ if (_vm->_game->_kernelMode == KERNEL_ACTIVE_CODE &&
+ _vm->_game->_screenObjects._inputMode == kInputBuildingSentences) {
+ userInterface.categoryChanged();
+ userInterface.selectObject(userInterface._selectedInvIndex);
+ }
+ }
+}
+
+void InventoryObjects::removeFromInventory(int objectId, int newScene) {
+ Scene &scene = _vm->_game->_scene;
+ UserInterface &userInterface = scene._userInterface;
+
+ // Scan the inventory list for the object
+ int invIndex = -1;
+ for (int idx = 0; idx < (int)_inventoryList.size() && invIndex == -1; ++idx) {
+ if (_inventoryList[idx] == objectId)
+ invIndex = idx;
+ }
+
+ // If the object isn't in the player's inventory, stop here
+ if (invIndex < 0)
+ return;
+
+ int selectedIndex = userInterface._selectedInvIndex;
+ bool noSelection = selectedIndex < 0;
+
+ if (_vm->_game->_kernelMode == KERNEL_ACTIVE_CODE &&
+ _vm->_game->_screenObjects._inputMode == kInputBuildingSentences)
+ userInterface.selectObject(-1);
+
+ // Remove the item from the inventory list
+ _inventoryList.remove_at(invIndex);
+
+ if (invIndex > userInterface._inventoryTopIndex) {
+ userInterface._inventoryTopIndex = MAX(userInterface._inventoryTopIndex, 0);
+ }
+
+ userInterface._inventoryChanged = true;
+ (*this)[objectId]._roomNumber = newScene;
+
+ int newIndex = selectedIndex;
+ if (!noSelection) {
+ if (newIndex >= invIndex)
+ --newIndex;
+ if (newIndex < 0 && size() > 0)
+ newIndex = 0;
+ }
+
+ if (_vm->_game->_kernelMode == KERNEL_ACTIVE_CODE &&
+ _vm->_game->_screenObjects._inputMode == kInputBuildingSentences) {
+ userInterface.categoryChanged();
+ userInterface.selectObject(newIndex);
+ }
+}
+
+int InventoryObjects::getIdFromDesc(int descId) {
+ for (int i = 0; i < (int)size(); ++i) {
+ InventoryObject &obj = (*this)[i];
+ if (obj._descId == descId)
+ return i;
+ }
+
+ return -1;
+}
+
+} // End of namespace MADS
diff --git a/engines/mads/inventory.h b/engines/mads/inventory.h
new file mode 100644
index 0000000000..7fb123e047
--- /dev/null
+++ b/engines/mads/inventory.h
@@ -0,0 +1,141 @@
+/* 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.
+ *
+ */
+
+#ifndef MADS_INVENTORY_H
+#define MADS_INVENTORY_H
+
+#include "common/scummsys.h"
+#include "common/array.h"
+#include "common/serializer.h"
+
+namespace MADS {
+
+enum {
+ NOWHERE = 1
+};
+
+class MADSEngine;
+
+#define MAX_VOCAB 5
+#define MAX_QUALITIES 4
+
+class InventoryObject {
+public:
+ int _descId;
+ int _roomNumber;
+ int _article;
+ int _vocabCount;
+ int _qualitiesCount;
+ int syntax;
+
+ struct {
+ int _vocabId;
+ VerbType _verbType;
+ PrepType _prepType;
+ } _vocabList[MAX_VOCAB];
+
+ int _qualityId[MAX_QUALITIES];
+ int _qualityValue[MAX_QUALITIES];
+
+ /**
+ * Synchronizes the data for a given object
+ */
+ void synchronize(Common::Serializer &s);
+
+ /**
+ * Returns true if the given object has the specified quality
+ */
+ bool hasQuality(int qualityId) const;
+
+ /**
+ * Sets the quality value for a given quality Id
+ */
+ void setQuality(int qualityId, int qualityValue);
+
+ /**
+ * Gets the quality value for a given quality Id
+ */
+ int getQuality(int qualityId) const;
+};
+
+class InventoryObjects: public Common::Array<InventoryObject> {
+private:
+ MADSEngine *_vm;
+
+public:
+ SynchronizedList _inventoryList;
+
+ /**
+ * Constructor
+ */
+ InventoryObjects(MADSEngine *vm): _vm(vm) {}
+
+ /**
+ * Loads the game's object list
+ */
+ void load();
+
+ /**
+ * Synchronize the objects list in a savegame
+ */
+ void synchronize(Common::Serializer &s);
+
+ /**
+ * Returns the inventory item from the player's inventory
+ */
+ InventoryObject &getItem(int itemIndex) {
+ return (*this)[_inventoryList[itemIndex]];
+ }
+
+ /**
+ * Sets an item's scene number
+ */
+ void setRoom(int objectId, int sceneNumber);
+
+ /**
+ * Returns true if a given object is in the player's current scene
+ */
+ bool isInRoom(int objectId) const;
+
+ /**
+ * Returns true if a given object is in the player's inventory
+ */
+ bool isInInventory(int objectId) const;
+
+ /**
+ * Removes the specified object from the player's inventory
+ */
+ void addToInventory(int objectId);
+
+ /**
+ * Removes the specified object to the player's inventory
+ * @param objectId Object to remove
+ * @param newScene Specifies the new scene to set the item to
+ */
+ void removeFromInventory(int objectId, int newScene);
+
+ int getIdFromDesc(int objectId);
+};
+
+} // End of namespace MADS
+
+#endif /* MADS_INVENTORY_H */
diff --git a/engines/mads/mads.cpp b/engines/mads/mads.cpp
new file mode 100644
index 0000000000..bcd8fdba8f
--- /dev/null
+++ b/engines/mads/mads.cpp
@@ -0,0 +1,156 @@
+/* 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 "common/config-manager.h"
+#include "common/debug-channels.h"
+#include "common/events.h"
+#include "engines/util.h"
+#include "mads/mads.h"
+#include "mads/game.h"
+#include "mads/screen.h"
+#include "mads/msurface.h"
+#include "mads/resources.h"
+#include "mads/sound.h"
+#include "mads/sprites.h"
+
+namespace MADS {
+
+MADSEngine::MADSEngine(OSystem *syst, const MADSGameDescription *gameDesc) :
+ _gameDescription(gameDesc), Engine(syst), _randomSource("MADS") {
+
+ // Initialise fields
+ _easyMouse = true;
+ _invObjectsAnimated = true;
+ _textWindowStill = false;
+ _screenFade = SCREEN_FADE_SMOOTH;
+ _musicFlag = true;
+ _dithering = false;
+
+ _debugger = nullptr;
+ _dialogs = nullptr;
+ _events = nullptr;
+ _font = nullptr;
+ _game = nullptr;
+ _palette = nullptr;
+ _resources = nullptr;
+ _sound = nullptr;
+}
+
+MADSEngine::~MADSEngine() {
+ delete _debugger;
+ delete _dialogs;
+ delete _events;
+ delete _font;
+ Font::deinit();
+ delete _game;
+ delete _palette;
+ delete _resources;
+ delete _sound;
+}
+
+void MADSEngine::initialise() {
+ // Set up debug channels
+ DebugMan.addDebugChannel(kDebugPath, "Path", "Pathfinding debug level");
+ DebugMan.addDebugChannel(kDebugScripts, "scripts", "Game scripts");
+ DebugMan.addDebugChannel(kDebugGraphics, "graphics", "Graphics handling");
+
+ // Initial sub-system engine references
+ MSurface::setVm(this);
+ MSprite::setVm(this);
+
+ Resources::init(this);
+ Conversation::init(this);
+ _debugger = new Debugger(this);
+ _dialogs = Dialogs::init(this);
+ _events = new EventsManager(this);
+ _palette = new Palette(this);
+ Font::init(this);
+ _font = new Font();
+ _screen.init();
+ _sound = new SoundManager(this, _mixer);
+ _audio = new AudioPlayer(_mixer, getGameID());
+ _game = Game::init(this);
+
+ _screen.empty();
+}
+
+Common::Error MADSEngine::run() {
+ initGraphics(MADS_SCREEN_WIDTH, MADS_SCREEN_HEIGHT, false);
+ initialise();
+
+ // Run the game
+ _game->run();
+
+ // Dummy loop to keep application active
+ _events->delay(9999);
+
+ return Common::kNoError;
+}
+
+int MADSEngine::getRandomNumber(int maxNumber) {
+ return _randomSource.getRandomNumber(maxNumber);
+}
+
+int MADSEngine::getRandomNumber(int minNumber, int maxNumber) {
+ int range = maxNumber - minNumber;
+
+ return minNumber + _randomSource.getRandomNumber(range);
+}
+
+int MADSEngine::hypotenuse(int xv, int yv) {
+ return (int)sqrt((double)(xv * xv + yv * yv));
+}
+
+bool MADSEngine::canLoadGameStateCurrently() {
+ return !_game->_winStatus && !_game->globals()[5]
+ && _dialogs->_pendingDialog == DIALOG_NONE
+ && _events->_cursorId != CURSOR_WAIT;
+}
+
+bool MADSEngine::canSaveGameStateCurrently() {
+ return !_game->_winStatus && !_game->globals()[5]
+ && _dialogs->_pendingDialog == DIALOG_NONE
+ && _events->_cursorId != CURSOR_WAIT;
+}
+
+/**
+* Support method that generates a savegame name
+* @param slot Slot number
+*/
+Common::String MADSEngine::generateSaveName(int slot) {
+ return Common::String::format("%s.%03d", _targetName.c_str(), slot);
+}
+
+Common::Error MADSEngine::loadGameState(int slot) {
+ _game->_loadGameSlot = slot;
+ _game->_scene._currentSceneId = -1;
+ _game->_currentSectionNumber = -1;
+ return Common::kNoError;
+}
+
+Common::Error MADSEngine::saveGameState(int slot, const Common::String &desc) {
+ _game->saveGame(slot, desc);
+ return Common::kNoError;
+}
+
+} // End of namespace MADS
diff --git a/engines/mads/mads.h b/engines/mads/mads.h
new file mode 100644
index 0000000000..3f325fd6a1
--- /dev/null
+++ b/engines/mads/mads.h
@@ -0,0 +1,152 @@
+/* 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.
+ *
+ */
+
+#ifndef MADS_MADS_H
+#define MADS_MADS_H
+
+#include "common/scummsys.h"
+#include "common/system.h"
+#include "common/error.h"
+#include "common/random.h"
+#include "common/util.h"
+#include "engines/engine.h"
+#include "graphics/surface.h"
+#include "mads/debugger.h"
+#include "mads/dialogs.h"
+#include "mads/events.h"
+#include "mads/font.h"
+#include "mads/game.h"
+#include "mads/screen.h"
+#include "mads/msurface.h"
+#include "mads/resources.h"
+#include "mads/sound.h"
+
+/**
+ * This is the namespace of the MADS engine.
+ *
+ * Status of this engine: In Development
+ *
+ * Games using this engine:
+ * - Rex Nebular and the Cosmic Gender Bender
+ */
+namespace MADS {
+
+#define DEBUG_BASIC 1
+#define DEBUG_INTERMEDIATE 2
+#define DEBUG_DETAILED 3
+
+enum MADSDebugChannels {
+ kDebugPath = 1 << 0,
+ kDebugScripts = 1 << 1,
+ kDebugGraphics = 1 << 2
+};
+
+enum {
+ GType_RexNebular = 0,
+ GType_Dragonsphere = 1,
+ GType_Phantom = 2
+};
+
+enum ScreenFade {
+ SCREEN_FADE_SMOOTH = 0,
+ SCREEN_FADE_MEDIUM = 1,
+ SCREEN_FADE_FAST = 2
+};
+
+struct MADSGameDescription;
+
+
+class MADSEngine : public Engine {
+private:
+ const MADSGameDescription *_gameDescription;
+ Common::RandomSource _randomSource;
+
+ /**
+ * Handles basic initialisation
+ */
+ void initialise();
+protected:
+ // Engine APIs
+ virtual Common::Error run();
+ virtual bool hasFeature(EngineFeature f) const;
+public:
+ Debugger *_debugger;
+ Dialogs *_dialogs;
+ EventsManager *_events;
+ Font *_font;
+ Game *_game;
+ Palette *_palette;
+ Resources *_resources;
+ ScreenSurface _screen;
+ SoundManager *_sound;
+ AudioPlayer *_audio;
+ bool _easyMouse;
+ bool _invObjectsAnimated;
+ bool _textWindowStill;
+ ScreenFade _screenFade;
+ bool _musicFlag;
+ bool _dithering;
+public:
+ MADSEngine(OSystem *syst, const MADSGameDescription *gameDesc);
+ virtual ~MADSEngine();
+
+ uint32 getFeatures() const;
+ Common::Language getLanguage() const;
+ Common::Platform getPlatform() const;
+ uint16 getVersion() const;
+ uint32 getGameID() const;
+ uint32 getGameFeatures() const;
+
+ int getRandomNumber(int maxNumber);
+ int getRandomNumber(int minNumber, int maxNumber);
+ int hypotenuse(int xv, int yv);
+
+ /**
+ * Returns true if it is currently okay to restore a game
+ */
+ bool canLoadGameStateCurrently();
+
+ /**
+ * Returns true if it is currently okay to save the game
+ */
+ bool canSaveGameStateCurrently();
+
+ /**
+ * Support method that generates a savegame name
+ * @param slot Slot number
+ */
+ Common::String generateSaveName(int slot);
+
+ /**
+ * Handles loading a game via the GMM
+ */
+ virtual Common::Error loadGameState(int slot);
+
+ /**
+ * Handles saving the game via the GMM
+ */
+ virtual Common::Error saveGameState(int slot, const Common::String &desc);
+};
+
+} // End of namespace MADS
+
+#endif /* MADS_MADS_H */
diff --git a/engines/mads/messages.cpp b/engines/mads/messages.cpp
new file mode 100644
index 0000000000..263d8fa661
--- /dev/null
+++ b/engines/mads/messages.cpp
@@ -0,0 +1,566 @@
+/* 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 "mads/mads.h"
+#include "mads/font.h"
+#include "mads/screen.h"
+#include "mads/messages.h"
+#include "mads/scene_data.h"
+
+namespace MADS {
+
+RandomMessages::RandomMessages() {
+ reserve(RANDOM_MESSAGE_SIZE);
+ _randomSpacing = 0;
+}
+
+void RandomMessages::reset() {
+ for (uint i = 0; i < size(); ++i) {
+ (*this)[i]._handle = -1;
+ (*this)[i]._quoteId = -1;
+ }
+}
+
+
+KernelMessages::KernelMessages(MADSEngine *vm): _vm(vm) {
+ for (int i = 0; i < KERNEL_MESSAGES_SIZE; ++i) {
+ KernelMessage rec;
+ _entries.push_back(rec);
+ }
+
+ _talkFont = _vm->_font->getFont(FONT_CONVERSATION);
+}
+
+KernelMessages::~KernelMessages() {
+}
+
+void KernelMessages::clear() {
+ Scene &scene = _vm->_game->_scene;
+
+ for (uint i = 0; i < _entries.size(); ++i)
+ _entries[i]._flags = 0;
+
+ scene._textSpacing = -1;
+}
+
+int KernelMessages::add(const Common::Point &pt, uint fontColor, uint8 flags,
+ uint8 abortTimers, uint32 timeout, const Common::String &msg) {
+ Scene &scene = _vm->_game->_scene;
+
+ // Find a free slot
+ uint idx = 0;
+ while ((idx < _entries.size()) && ((_entries[idx]._flags & KMSG_ACTIVE) != 0))
+ ++idx;
+ if (idx == _entries.size()) {
+ if (abortTimers == 0)
+ return -1;
+
+ error("KernelMessages overflow");
+ }
+
+ KernelMessage &rec = _entries[idx];
+ rec._msg = msg;
+ rec._flags = flags | KMSG_ACTIVE;
+ rec._color1 = fontColor & 0xff;
+ rec._color2 = fontColor >> 8;
+ rec._position = pt;
+ rec._textDisplayIndex = -1;
+ rec._timeout = timeout;
+ rec._frameTimer = _vm->_game->_priorFrameTimer;
+ rec._trigger = abortTimers;
+ rec._abortMode = _vm->_game->_triggerSetupMode;
+
+ rec._actionDetails = scene._action._activeAction;
+
+ if (flags & KMSG_PLAYER_TIMEOUT)
+ rec._frameTimer = _vm->_game->_player._ticksAmount +
+ _vm->_game->_player._priorTimer;
+
+ return idx;
+}
+
+int KernelMessages::addQuote(int quoteId, int abortTimers, uint32 timeout) {
+ Common::String quoteStr = _vm->_game->getQuote(quoteId);
+ return add(Common::Point(), 0x1110, KMSG_PLAYER_TIMEOUT | KMSG_CENTER_ALIGN,
+ abortTimers, timeout, quoteStr);
+}
+
+void KernelMessages::scrollMessage(int msgIndex, int numTicks, bool quoted) {
+ if (msgIndex < 0)
+ return;
+
+ _entries[msgIndex]._flags |= quoted ? (KMSG_SCROLL | KMSG_QUOTED) : KMSG_SCROLL;
+ _entries[msgIndex]._msgOffset = 0;
+ _entries[msgIndex]._numTicks = numTicks;
+ _entries[msgIndex]._frameTimer2 = _vm->_game->_priorFrameTimer;
+
+ Common::String msg = _entries[msgIndex]._msg;
+
+ if (_entries[msgIndex]._flags & KMSG_PLAYER_TIMEOUT)
+ _entries[msgIndex]._frameTimer2 = _vm->_game->_player._ticksAmount +
+ _vm->_game->_player._priorTimer;
+
+ _entries[msgIndex]._frameTimer = _entries[msgIndex]._frameTimer2;
+}
+
+void KernelMessages::setSeqIndex(int msgIndex, int seqIndex) {
+ if (msgIndex >= 0) {
+ _entries[msgIndex]._flags |= KMSG_SEQ_ENTRY;
+ _entries[msgIndex]._sequenceIndex = seqIndex;
+ }
+}
+
+void KernelMessages::remove(int msgIndex) {
+ KernelMessage &rec = _entries[msgIndex];
+ Scene &scene = _vm->_game->_scene;
+
+ if (rec._flags & KMSG_ACTIVE) {
+ if (rec._flags & KMSG_SCROLL) {
+ // WORKAROUND: Code here no longer needed in ScummVM
+ }
+
+ if (rec._textDisplayIndex >= 0)
+ scene._textDisplay.expire(rec._textDisplayIndex);
+
+ rec._flags &= ~KMSG_ACTIVE;
+ }
+}
+
+void KernelMessages::reset() {
+ for (uint i = 0; i < _entries.size(); ++i)
+ remove(i);
+
+ _talkFont = _vm->_font->getFont(FONT_CONVERSATION);
+ _randomMessages.clear();
+}
+
+void KernelMessages::update() {
+ uint32 currentTimer = _vm->_game->_scene._frameStartTime;
+
+ for (uint i = 0; i < _entries.size() && !_vm->_game->_trigger; ++i) {
+ KernelMessage &msg = _entries[i];
+
+ if (((msg._flags & KMSG_ACTIVE) != 0) && (currentTimer >= msg._frameTimer))
+ processText(i);
+ }
+}
+
+void KernelMessages::processText(int msgIndex) {
+ Scene &scene = _vm->_game->_scene;
+ KernelMessage &msg = _entries[msgIndex];
+ uint32 currentTimer = _vm->_game->_priorFrameTimer;
+ bool flag = false;
+
+ if ((msg._flags & KMSG_EXPIRE) != 0) {
+ scene._textDisplay.expire(msg._textDisplayIndex);
+ msg._flags &= !KMSG_ACTIVE;
+ return;
+ }
+
+ if ((msg._flags & KMSG_SCROLL) == 0) {
+ msg._timeout -= 3;
+ }
+
+ if (msg._flags & KMSG_SEQ_ENTRY) {
+ SequenceEntry &seqEntry = scene._sequences[msg._sequenceIndex];
+ if (seqEntry._doneFlag || !seqEntry._active)
+ msg._timeout = 0;
+ }
+
+ if ((msg._timeout <= 0) && (_vm->_game->_trigger == 0)) {
+ msg._flags |= KMSG_EXPIRE;
+ if (msg._trigger != 0) {
+ _vm->_game->_trigger = msg._trigger;
+ _vm->_game->_triggerMode = msg._abortMode;
+
+ if (_vm->_game->_triggerMode != SEQUENCE_TRIGGER_DAEMON) {
+ scene._action._activeAction = msg._actionDetails;
+ }
+ }
+ }
+
+ msg._frameTimer = currentTimer + 3;
+ int x1 = 0, y1 = 0;
+
+ if (msg._flags & KMSG_SEQ_ENTRY) {
+ SequenceEntry &seqEntry = scene._sequences[msg._sequenceIndex];
+ if (!seqEntry._nonFixed) {
+ SpriteAsset &spriteSet = *scene._sprites[seqEntry._spritesIndex];
+ MSprite *frame = spriteSet.getFrame(seqEntry._frameIndex - 1);
+ x1 = frame->getBounds().left;
+ y1 = frame->getBounds().top;
+ } else {
+ x1 = seqEntry._position.x;
+ y1 = seqEntry._position.y;
+ }
+ }
+
+ Player &player = _vm->_game->_player;
+ if (msg._flags & KMSG_PLAYER_TIMEOUT) {
+ if (player._beenVisible) {
+ SpriteAsset &asset = *_vm->_game->_scene._sprites[player._spritesStart + player._spritesIdx];
+ MSprite *frame = asset.getFrame(player._frameNumber - 1);
+
+ int yAmount = player._currentScale * player._centerOfGravity / 100;
+ x1 = player._playerPos.x;
+ y1 = (frame->h * player._currentScale / -100) + yAmount +
+ player._playerPos.y - 15;
+ } else {
+ x1 = 160;
+ y1 = 78;
+ }
+ }
+
+ x1 += msg._position.x;
+ y1 += msg._position.y;
+
+ Common::String displayMsg = msg._msg;
+
+ if ((msg._flags & KMSG_SCROLL) && (msg._frameTimer >= currentTimer)) {
+ ++msg._msgOffset;
+
+ if (msg._msgOffset >= msg._msg.size()) {
+ // End of message
+ msg._flags &= ~KMSG_SCROLL;
+ } else {
+ displayMsg = Common::String(msg._msg.c_str(), msg._msg.c_str() + msg._msgOffset);
+ }
+
+ msg._frameTimer = msg._frameTimer2 = currentTimer + msg._numTicks;
+ flag = true;
+ }
+
+ int strWidth = _talkFont->getWidth(displayMsg, scene._textSpacing);
+
+ if (msg._flags & (KMSG_RIGHT_ALIGN | KMSG_CENTER_ALIGN)) {
+ x1 -= (msg._flags & KMSG_CENTER_ALIGN) ? strWidth / 2 : strWidth;
+ }
+
+ // Make sure text appears entirely on-screen
+ int x2 = x1 + strWidth;
+ if (x2 > MADS_SCREEN_WIDTH)
+ x1 -= x2 - MADS_SCREEN_WIDTH;
+ if (x1 > (MADS_SCREEN_WIDTH - 1))
+ x1 = MADS_SCREEN_WIDTH - 1;
+ if (x1 < 0)
+ x1 = 0;
+
+ if (y1 >(MADS_SCENE_HEIGHT - 1))
+ y1 = MADS_SCENE_HEIGHT - 1;
+ if (y1 < 0)
+ y1 = 0;
+
+ if (msg._textDisplayIndex >= 0) {
+ TextDisplay &textEntry = scene._textDisplay[msg._textDisplayIndex];
+
+ if (flag || (textEntry._bounds.left != x1) || (textEntry._bounds.top != y1)) {
+ // Mark the associated text entry as deleted, so it can be re-created
+ scene._textDisplay.expire(msg._textDisplayIndex);
+ msg._textDisplayIndex = -1;
+ }
+ }
+
+ if (msg._textDisplayIndex < 0) {
+ // Need to create a new text display entry for this message
+ int idx = scene._textDisplay.add(x1, y1, msg._color1 | (msg._color2 << 8),
+ scene._textSpacing, displayMsg, _talkFont);
+ if (idx >= 0)
+ msg._textDisplayIndex = idx;
+ }
+}
+
+void KernelMessages::delay(uint32 priorFrameTime, uint32 currentTime) {
+ for (uint i = 0; i < _entries.size(); ++i) {
+ _entries[i]._timeout += currentTime - priorFrameTime;
+ }
+}
+
+void KernelMessages::setQuoted(int msgIndex, int numTicks, bool quoted) {
+ if (msgIndex >= 0) {
+ KernelMessage &msg = _entries[msgIndex];
+
+ msg._flags |= KMSG_SCROLL;
+ if (quoted)
+ msg._flags |= KMSG_QUOTED;
+
+ msg._msgOffset = 0;
+ msg._numTicks = numTicks;
+ msg._frameTimer2 = _vm->_game->_scene._frameStartTime;
+
+ if (msg._flags & KMSG_PLAYER_TIMEOUT) {
+ msg._frameTimer2 = _vm->_game->_player._priorTimer +
+ _vm->_game->_player._ticksAmount;
+ }
+
+ msg._frameTimer = msg._frameTimer2;
+ }
+}
+
+#define RANDOM_MESSAGE_TRIGGER 240
+
+void KernelMessages::randomServer() {
+ if ((_vm->_game->_trigger >= RANDOM_MESSAGE_TRIGGER) &&
+ (_vm->_game->_trigger < (RANDOM_MESSAGE_TRIGGER + (int)_randomMessages.size()))) {
+ _randomMessages[_vm->_game->_trigger - RANDOM_MESSAGE_TRIGGER]._handle = -1;
+ _randomMessages[_vm->_game->_trigger - RANDOM_MESSAGE_TRIGGER]._quoteId = -1;
+ }
+}
+
+int KernelMessages::checkRandom() {
+ int total = 0;
+
+ for (uint i = 0; i < _randomMessages.size(); ++i) {
+ if (_randomMessages[i]._handle >= 0)
+ ++total;
+ }
+
+ return total;
+}
+
+bool KernelMessages::generateRandom(int major, int minor) {
+ bool generatedMessage = false;
+
+ // Scan through the random messages array
+ for (uint msgCtr = 0; msgCtr < _randomMessages.size(); msgCtr++) {
+ // Find currently active random messages
+ if (_randomMessages[msgCtr]._handle < 0) {
+ // Check whether there's any existing 'scrolling in' message
+ bool bad = false;
+ for (uint scanCtr = 0; scanCtr < _randomMessages.size(); ++scanCtr) {
+ if (_randomMessages[scanCtr]._handle >= 0) {
+ if (_entries[_randomMessages[scanCtr]._handle]._flags & KMSG_SCROLL) {
+ bad = true;
+ break;
+ }
+ }
+ }
+
+ // Do a random check for a new message to appear
+ if (_vm->getRandomNumber(major) <= minor && !bad) {
+ int quoteId;
+
+ // Pick a random quote to display from the available list
+ do {
+ int quoteIdx = _vm->getRandomNumber(_randomQuotes.size() - 1);
+ quoteId = _randomQuotes[quoteIdx];
+
+ // Ensure the quote isn't already in use
+ bad = false;
+ for (uint scanCtr = 0; scanCtr < _randomMessages.size(); ++scanCtr) {
+ if (quoteId == _randomMessages[scanCtr]._quoteId) {
+ bad = true;
+ break;
+ }
+ }
+ } while (bad);
+
+ // Store the quote Id to be used
+ _randomMessages[msgCtr]._quoteId = quoteId;
+
+ // Position the message at a random position
+ Common::Point textPos;
+ textPos.x = _vm->getRandomNumber(_randomMessages._bounds.left,
+ _randomMessages._bounds.right);
+
+ // Figure out Y position, making sure not to be overlapping with
+ // any other on-screen message
+ int abortCounter = 0;
+
+ do {
+ // Ensure we don't get stuck in an infinite loop if too many messages
+ // are alrady on-screen
+ if (abortCounter++ > 100) goto done;
+ bad = false;
+
+ // Set potential new Y position
+ textPos.y = _vm->getRandomNumber(_randomMessages._bounds.top,
+ _randomMessages._bounds.bottom);
+
+ // Ensure it doesn't overlap an existing on-screen message
+ for (uint msgCtr2 = 0; msgCtr2 < _randomMessages.size(); ++msgCtr2) {
+ if (_randomMessages[msgCtr2]._handle >= 0) {
+ int lastY = _entries[_randomMessages[msgCtr2]._handle]._position.y;
+
+ if ((textPos.y >= (lastY - _randomMessages._randomSpacing)) &&
+ (textPos.y <= (lastY + _randomMessages._randomSpacing))) {
+ bad = true;
+ }
+ }
+ }
+ } while (bad);
+
+ // Add the message
+ _randomMessages[msgCtr]._handle = add(textPos, _randomMessages._color, 0,
+ RANDOM_MESSAGE_TRIGGER + msgCtr, _randomMessages._duration,
+ _vm->_game->getQuote(_randomMessages[msgCtr]._quoteId));
+
+ if (_randomMessages._scrollRate > 0) {
+ if (_randomMessages[msgCtr]._handle >= 0) {
+ setQuoted(_randomMessages[msgCtr]._handle,
+ _randomMessages._scrollRate, true);
+ }
+ }
+
+ generatedMessage = true;
+ break;
+ }
+ }
+ }
+
+done:
+ return generatedMessage;
+}
+
+void KernelMessages::initRandomMessages(int maxSimultaneousMessages,
+ const Common::Rect &bounds, int minYSpacing, int scrollRate,
+ int color, int duration, int quoteId, ...) {
+ // Reset the random messages list
+ _randomMessages.clear();
+ _randomMessages.resize(maxSimultaneousMessages);
+
+ // Store passed parameters
+ _randomMessages._bounds = bounds;
+ _randomMessages._randomSpacing = minYSpacing;
+ _randomMessages._scrollRate = scrollRate;
+ _randomMessages._color = color;
+ _randomMessages._duration = duration;
+
+ // Store the variable length random quote list
+ va_list va;
+ va_start(va, quoteId);
+ _randomQuotes.clear();
+
+ while (quoteId > 0) {
+ _randomQuotes.push_back(quoteId);
+ assert(_randomQuotes.size() < 100);
+ quoteId = va_arg(va, int);
+ }
+
+ va_end(va);
+}
+
+
+/*------------------------------------------------------------------------*/
+
+TextDisplay::TextDisplay() {
+ _active = false;
+ _expire = 0;
+ _spacing = 0;
+ _color1 = 0;
+ _color2 = 0;
+ _font = nullptr;
+}
+
+/*------------------------------------------------------------------------*/
+
+TextDisplayList::TextDisplayList(MADSEngine *vm) : _vm(vm) {
+ for (int i = 0; i < TEXT_DISPLAY_SIZE; ++i) {
+ TextDisplay rec;
+ rec._active = false;
+ rec._expire = 0;
+ push_back(rec);
+ }
+}
+
+void TextDisplayList::reset() {
+ for (int i = 0; i < TEXT_DISPLAY_SIZE; ++i)
+ (*this)[i]._active = false;
+}
+
+int TextDisplayList::add(int xp, int yp, uint fontColor, int charSpacing,
+ const Common::String &msg, Font *font) {
+ int usedSlot = -1;
+
+ for (int idx = 0; idx < TEXT_DISPLAY_SIZE; ++idx) {
+ TextDisplay &td = (*this)[idx];
+ if (!td._active) {
+ usedSlot = idx;
+
+ td._bounds.left = xp;
+ td._bounds.top = yp;
+ td._font = font;
+ td._msg = msg;
+ td._bounds.setWidth(font->getWidth(msg, charSpacing));
+ td._bounds.setHeight(font->getHeight());
+ td._color1 = fontColor & 0xff;
+ td._color2 = fontColor >> 8;
+ td._spacing = charSpacing;
+ td._expire = 1;
+ td._active = true;
+ break;
+ }
+ }
+
+ return usedSlot;
+}
+
+void TextDisplayList::setDirtyAreas() {
+ Scene &scene = _vm->_game->_scene;
+
+ for (uint idx = 0, dirtyIdx = SPRITE_SLOTS_MAX_SIZE; dirtyIdx < size(); ++idx, ++dirtyIdx) {
+ if (((*this)[idx]._expire >= 0) || !(*this)[idx]._active) {
+ scene._dirtyAreas[dirtyIdx]._active = false;
+ } else {
+ scene._dirtyAreas[dirtyIdx]._textActive = true;
+ scene._dirtyAreas[dirtyIdx].setTextDisplay(&(*this)[idx]);
+ }
+ }
+}
+
+void TextDisplayList::setDirtyAreas2() {
+ Scene &scene = _vm->_game->_scene;
+
+ for (uint idx = 0, dirtyIdx = SPRITE_SLOTS_MAX_SIZE; idx < size(); ++idx, ++dirtyIdx) {
+ if ((*this)[idx]._active && ((*this)[idx]._expire >= 0)) {
+ scene._dirtyAreas[dirtyIdx].setTextDisplay(&(*this)[idx]);
+ scene._dirtyAreas[dirtyIdx]._textActive = ((*this)[idx]._expire <= 0) ? 0 : 1;
+ }
+ }
+}
+
+void TextDisplayList::draw(MSurface *s) {
+ for (uint idx = 0; idx < size(); ++idx) {
+ TextDisplay &td = (*this)[idx];
+ if (td._active && (td._expire >= 0)) {
+ td._font->setColors(0xFF, td._color1, td._color2, 0);
+ td._font->writeString(s, td._msg,
+ Common::Point(td._bounds.left, td._bounds.top),
+ td._spacing, td._bounds.width());
+ }
+ }
+}
+
+void TextDisplayList::cleanUp() {
+ for (uint idx = 0; idx < size(); ++idx) {
+ if ((*this)[idx]._expire < 0) {
+ (*this)[idx]._active = false;
+ (*this)[idx]._expire = 0;
+ }
+ }
+}
+
+void TextDisplayList::expire(int idx) {
+ (*this)[idx]._expire = -1;
+}
+
+} // End of namespace MADS
diff --git a/engines/mads/messages.h b/engines/mads/messages.h
new file mode 100644
index 0000000000..241f493434
--- /dev/null
+++ b/engines/mads/messages.h
@@ -0,0 +1,192 @@
+/* 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.
+ *
+ */
+
+#ifndef MADS_MESSAGES_H
+#define MADS_MESSAGES_H
+
+#include "common/scummsys.h"
+#include "common/array.h"
+#include "mads/action.h"
+#include "mads/font.h"
+#include "mads/msurface.h"
+
+namespace MADS {
+
+#define KERNEL_MESSAGES_SIZE 10
+#define INDEFINITE_TIMEOUT 9999999
+#define TEXT_DISPLAY_SIZE 40
+#define RANDOM_MESSAGE_SIZE 4
+
+enum KernelMessageFlags {
+ KMSG_QUOTED = 1, KMSG_PLAYER_TIMEOUT = 2, KMSG_SEQ_ENTRY = 4, KMSG_SCROLL = 8,
+ KMSG_RIGHT_ALIGN = 0x10, KMSG_CENTER_ALIGN = 0x20, KMSG_EXPIRE = 0x40,
+ KMSG_ACTIVE = 0x80
+};
+
+class MADSEngine;
+
+class KernelMessage {
+public:
+ uint8 _flags;
+ int _sequenceIndex;
+ int _color1;
+ int _color2;
+ Common::Point _position;
+ int _textDisplayIndex;
+ uint32 _msgOffset;
+ int _numTicks;
+ uint32 _frameTimer2;
+ uint32 _frameTimer;
+ int32 _timeout;
+ int _trigger;
+ TriggerMode _abortMode;
+ ActionDetails _actionDetails;
+ Common::String _msg;
+
+ KernelMessage();
+};
+
+struct RandomEntry {
+ int _handle;
+ int _quoteId;
+
+ RandomEntry() { _handle = _quoteId = -1; }
+};
+
+class RandomMessages: public Common::Array<RandomEntry> {
+public:
+ Common::Rect _bounds;
+ int _randomSpacing;
+ int _color;
+ int _duration;
+ int _scrollRate;
+public:
+ RandomMessages();
+
+ void reset();
+};
+
+class KernelMessages {
+private:
+ MADSEngine *_vm;
+
+ Common::Array<int> _randomQuotes;
+ RandomMessages _randomMessages;
+public:
+ Common::Array<KernelMessage> _entries;
+ Font *_talkFont;
+public:
+ KernelMessages(MADSEngine *vm);
+ ~KernelMessages();
+
+ void clear();
+ int add(const Common::Point &pt, uint fontColor, uint8 flags, uint8 abortTimers,
+ uint32 timeout, const Common::String &msg);
+ int addQuote(int quoteId, int abortTimers, uint32 timeout);
+ void scrollMessage(int msgIndex, int numTicks, bool quoted);
+ void setSeqIndex(int msgIndex, int seqIndex);
+ void remove(int msgIndex);
+ void reset();
+ void update();
+ void processText(int msgIndex);
+ void delay(uint32 priorFrameTime, uint32 currentTime);
+ void setQuoted(int msgIndex, int numTicks, bool quoted);
+
+ void initRandomMessages(int maxSimultaneousMessages,
+ const Common::Rect &bounds, int minYSpacing, int scrollRate,
+ int color, int duration, int quoteId, ...);
+
+ /**
+ * Handles expiring any active random messages as necessary
+ */
+ void randomServer();
+
+ /**
+ * Return the number of currently active random messages
+ */
+ int checkRandom();
+
+ /**
+ * Handles generating new random messages
+ */
+ bool generateRandom(int major, int minor);
+};
+
+class TextDisplay {
+public:
+ bool _active;
+ int _expire;
+ int _spacing;
+ Common::Rect _bounds;
+ uint8 _color1;
+ uint8 _color2;
+ Font *_font;
+ Common::String _msg;
+
+ TextDisplay();
+};
+
+#define TEXT_DISPLAY_SIZE 40
+
+class TextDisplayList: public Common::Array<TextDisplay> {
+private:
+ MADSEngine *_vm;
+public:
+ TextDisplayList(MADSEngine *vm);
+
+ /**
+ * Expire a given text display entry
+ */
+ void expire(int idx);
+
+ int add(int xp, int yp, uint fontColor, int charSpacing, const Common::String &, Font *font);
+
+ /**
+ * Reset all of the text display entries in the list to inactive
+ */
+ void reset();
+
+ /**
+ * Draw any text in the list to the specified surface
+ * @param surface Surface
+ */
+ void draw(MSurface *s);
+
+ /**
+ * Determine dirty areas for active text areas
+ */
+ void setDirtyAreas();
+
+ /**
+ * Secondary setup dirty areas for the text areas
+ */
+ void setDirtyAreas2();
+
+ /**
+ * Deactivates any text display entries that are finished
+ */
+ void cleanUp();
+};
+
+} // End of namespace MADS
+
+#endif /* MADS_MESSAGES_H */
diff --git a/engines/mads/module.mk b/engines/mads/module.mk
new file mode 100644
index 0000000000..61e810e215
--- /dev/null
+++ b/engines/mads/module.mk
@@ -0,0 +1,58 @@
+MODULE := engines/mads
+
+MODULE_OBJS := \
+ dragonsphere/game_dragonsphere.o \
+ dragonsphere/dragonsphere_scenes.o \
+ phantom/game_phantom.o \
+ phantom/phantom_scenes.o \
+ nebular/dialogs_nebular.o \
+ nebular/game_nebular.o \
+ nebular/globals_nebular.o \
+ nebular/sound_nebular.o \
+ nebular/nebular_scenes.o \
+ nebular/nebular_scenes1.o \
+ nebular/nebular_scenes2.o \
+ nebular/nebular_scenes3.o \
+ nebular/nebular_scenes4.o \
+ nebular/nebular_scenes5.o \
+ nebular/nebular_scenes6.o \
+ nebular/nebular_scenes7.o \
+ nebular/nebular_scenes8.o \
+ action.o \
+ animation.o \
+ assets.o \
+ audio.o \
+ compression.o \
+ debugger.o \
+ detection.o \
+ dialogs.o \
+ events.o \
+ font.o \
+ game.o \
+ game_data.o \
+ globals.o \
+ hotspots.o \
+ inventory.o \
+ mads.o \
+ messages.o \
+ msurface.o \
+ palette.o \
+ player.o \
+ rails.o \
+ resources.o \
+ scene.o \
+ scene_data.o \
+ screen.o \
+ sequence.o \
+ sound.o \
+ sprites.o \
+ staticres.o \
+ user_interface.o
+
+# This module can be built as a plugin
+ifeq ($(ENABLE_MADS), DYNAMIC_PLUGIN)
+PLUGIN := 1
+endif
+
+# Include common rules
+include $(srcdir)/rules.mk
diff --git a/engines/mads/msurface.cpp b/engines/mads/msurface.cpp
new file mode 100644
index 0000000000..6d74fefaab
--- /dev/null
+++ b/engines/mads/msurface.cpp
@@ -0,0 +1,551 @@
+/* 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 "engines/util.h"
+#include "mads/compression.h"
+#include "mads/screen.h"
+#include "mads/mads.h"
+#include "mads/msurface.h"
+#include "mads/resources.h"
+#include "mads/sprites.h"
+
+namespace MADS {
+
+MADSEngine *MSurface::_vm = nullptr;
+
+MSurface::MSurface() {
+ pixels = nullptr;
+ _freeFlag = false;
+}
+
+MSurface::MSurface(int width, int height) {
+ pixels = nullptr;
+ _freeFlag = false;
+ setSize(width, height);
+}
+
+MSurface::~MSurface() {
+ if (_freeFlag)
+ Graphics::Surface::free();
+}
+
+void MSurface::setSize(int width, int height) {
+ if (_freeFlag)
+ Graphics::Surface::free();
+ Graphics::Surface::create(width, height, Graphics::PixelFormat::createFormatCLUT8());
+ _freeFlag = true;
+}
+
+void MSurface::setPixels(byte *pData, int horizSize, int vertSize) {
+ _freeFlag = false;
+ pixels = pData;
+ w = pitch = horizSize;
+ h = vertSize;
+ format.bytesPerPixel = 1;
+}
+
+int MSurface::scaleValue(int value, int scale, int err) {
+ int scaled = 0;
+ while (value--) {
+ err -= scale;
+ while (err < 0) {
+ scaled++;
+ err += 100;
+ }
+ }
+ return scaled;
+}
+
+void MSurface::drawSprite(const Common::Point &pt, SpriteInfo &info, const Common::Rect &clipRect) {
+
+ enum {
+ kStatusSkip,
+ kStatusScale,
+ kStatusDraw
+ };
+
+ // NOTE: The current clipping code assumes that the top left corner of the clip
+ // rectangle is always 0, 0
+ assert(clipRect.top == 0 && clipRect.left == 0);
+
+ // TODO: Put err* and scaled* into SpriteInfo
+ int errX = info.hotX * info.scaleX % 100;
+ int errY = info.hotY * info.scaleY % 100;
+ int scaledWidth = scaleValue(info.width, info.scaleX, errX);
+ int scaledHeight = scaleValue(info.height, info.scaleY, errY);
+
+ int x = pt.x, y = pt.y;
+ int clipX = 0, clipY = 0;
+ // Clip the sprite's width and height according to the clip rectangle's dimensions
+ // This clips the sprite to the bottom and right
+ if (x >= 0) {
+ scaledWidth = MIN<int>(x + scaledWidth, clipRect.right) - x;
+ } else {
+ clipX = x;
+ scaledWidth = x + scaledWidth;
+ }
+ if (y >= 0) {
+ scaledHeight = MIN<int>(y + scaledHeight, clipRect.bottom) - y;
+ } else {
+ clipY = y;
+ scaledHeight = y + scaledHeight;
+ }
+
+ // Check if sprite is inside the screen. If it's not, there's no need to draw it
+ if (scaledWidth + x <= 0 || scaledHeight + y <= 0) // check left and top (in case x,y are negative)
+ return;
+ if (scaledWidth <= 0 || scaledHeight <= 0) // check right and bottom
+ return;
+ int heightAmt = scaledHeight;
+
+ byte *src = info.sprite->getData();
+ byte *dst = getBasePtr(x - info.hotX - clipX, y - info.hotY - clipY);
+
+ int status = kStatusSkip;
+ byte *scaledLineBuf = new byte[scaledWidth];
+
+ while (heightAmt > 0) {
+
+ if (status == kStatusSkip) {
+ // Skip line
+ errY -= info.scaleY;
+ if (errY < 0)
+ status = kStatusScale;
+ else
+ src += info.width;
+ } else {
+
+ if (status == kStatusScale) {
+ // Scale current line
+ byte *lineDst = scaledLineBuf;
+ int curErrX = errX;
+ int width = scaledWidth;
+ byte *tempSrc = src;
+ int startX = clipX;
+ while (width > 0) {
+ byte pixel = *tempSrc++;
+ curErrX -= info.scaleX;
+ while (curErrX < 0) {
+ if (startX == 0) {
+ *lineDst++ = pixel;
+ width--;
+ } else {
+ startX++;
+ }
+ curErrX += 100;
+ }
+ }
+ src += info.width;
+ status = kStatusDraw;
+ }
+
+ if (status == kStatusDraw && clipY == 0) {
+ // Draw previously scaled line
+ // TODO Implement different drawing types (depth, shadow etc.)
+ byte *tempDst = dst;
+ for (int lineX = 0; lineX < scaledWidth; lineX++) {
+ byte pixel = scaledLineBuf[lineX];
+
+ if (info.encoding & 0x80) {
+
+ if (pixel == 0x80) {
+ pixel = 0;
+ } else {
+ byte destPixel = *tempDst;
+ byte r, g, b;
+ r = CLIP((info.palette[destPixel * 3] * pixel) >> 10, 0, 31);
+ g = CLIP((info.palette[destPixel * 3 + 1] * pixel) >> 10, 0, 31);
+ b = CLIP((info.palette[destPixel * 3 + 2] * pixel) >> 10, 0, 31);
+ pixel = info.inverseColorTable[(b << 10) | (g << 5) | r];
+ }
+ }
+
+ if (pixel)
+ *tempDst = pixel;
+
+ tempDst++;
+ }
+ dst += pitch;
+ heightAmt--;
+ // TODO depth etc.
+ //depthAddress += Destination -> Width;
+
+ errY += 100;
+ if (errY >= 0)
+ status = kStatusSkip;
+ } else if (status == kStatusDraw && clipY < 0) {
+ clipY++;
+
+ errY += 100;
+ if (errY >= 0)
+ status = kStatusSkip;
+ }
+
+ }
+
+ }
+
+ delete[] scaledLineBuf;
+
+}
+
+void MSurface::empty() {
+ Common::fill(getBasePtr(0, 0), getBasePtr(0, h), 0);
+}
+
+void MSurface::copyFrom(MSurface *src, const Common::Rect &srcBounds,
+ const Common::Point &destPos, int transparentColor) {
+ // Validation of the rectangle and position
+ int destX = destPos.x, destY = destPos.y;
+ if ((destX >= w) || (destY >= h))
+ return;
+
+ Common::Rect copyRect = srcBounds;
+ if (destX < 0) {
+ copyRect.left += -destX;
+ destX = 0;
+ } else if (destX + copyRect.width() > w) {
+ copyRect.right -= destX + copyRect.width() - w;
+ }
+ if (destY < 0) {
+ copyRect.top += -destY;
+ destY = 0;
+ } else if (destY + copyRect.height() > h) {
+ copyRect.bottom -= destY + copyRect.height() - h;
+ }
+
+ if (!copyRect.isValidRect())
+ return;
+
+ // Copy the specified area
+
+ byte *data = src->getData();
+ byte *srcPtr = data + (src->getWidth() * copyRect.top + copyRect.left);
+ byte *destPtr = (byte *)pixels + (destY * getWidth()) + destX;
+
+ for (int rowCtr = 0; rowCtr < copyRect.height(); ++rowCtr) {
+ if (transparentColor == -1) {
+ // No transparency, so copy line over
+ Common::copy(srcPtr, srcPtr + copyRect.width(), destPtr);
+ } else {
+ // Copy each byte one at a time checking for the transparency color
+ for (int xCtr = 0; xCtr < copyRect.width(); ++xCtr)
+ if (srcPtr[xCtr] != transparentColor) destPtr[xCtr] = srcPtr[xCtr];
+ }
+
+ srcPtr += src->getWidth();
+ destPtr += getWidth();
+ }
+}
+
+void MSurface::copyFrom(MSurface *src, const Common::Point &destPos, int depth,
+ DepthSurface *depthSurface, int scale, int transparentColor) {
+
+ int destX = destPos.x, destY = destPos.y;
+ if (scale == 100) {
+ // Copy the specified area
+ Common::Rect copyRect(0, 0, src->getWidth(), src->getHeight());
+
+ if (destX < 0) {
+ copyRect.left += -destX;
+ destX = 0;
+ }
+ else if (destX + copyRect.width() > w) {
+ copyRect.right -= destX + copyRect.width() - w;
+ }
+ if (destY < 0) {
+ copyRect.top += -destY;
+ destY = 0;
+ }
+ else if (destY + copyRect.height() > h) {
+ copyRect.bottom -= destY + copyRect.height() - h;
+ }
+
+ if (!copyRect.isValidRect())
+ return;
+
+ byte *data = src->getData();
+ byte *srcPtr = data + (src->getWidth() * copyRect.top + copyRect.left);
+ byte *destPtr = (byte *)pixels + (destY * pitch) + destX;
+
+ // 100% scaling variation
+ for (int rowCtr = 0; rowCtr < copyRect.height(); ++rowCtr) {
+ // Copy each byte one at a time checking against the depth
+ for (int xCtr = 0; xCtr < copyRect.width(); ++xCtr) {
+ int pixelDepth = depthSurface == nullptr ? 15 :
+ depthSurface->getDepth(Common::Point(destX + xCtr, destY + rowCtr));
+ if ((depth <= pixelDepth) && (srcPtr[xCtr] != transparentColor))
+ destPtr[xCtr] = srcPtr[xCtr];
+ }
+
+ srcPtr += src->getWidth();
+ destPtr += getWidth();
+ }
+
+ return;
+ }
+
+ // Start of draw logic for scaled sprites
+ const byte *srcPixelsP = src->getData();
+
+ int destRight = this->getWidth() - 1;
+ int destBottom = this->getHeight() - 1;
+ bool normalFrame = true;
+ int frameWidth = src->getWidth();
+ int frameHeight = src->getHeight();
+
+ int highestDim = MAX(frameWidth, frameHeight);
+ bool lineDist[MADS_SCREEN_WIDTH];
+ int distIndex = 0;
+ int distXCount = 0, distYCount = 0;
+
+ int distCtr = 0;
+ do {
+ distCtr += scale;
+ if (distCtr < 100) {
+ lineDist[distIndex] = false;
+ } else {
+ lineDist[distIndex] = true;
+ distCtr -= 100;
+
+ if (distIndex < frameWidth)
+ ++distXCount;
+
+ if (distIndex < frameHeight)
+ ++distYCount;
+ }
+ } while (++distIndex < highestDim);
+
+ destX -= distXCount / 2;
+ destY -= distYCount - 1;
+
+ // Check x bounding area
+ int spriteLeft = 0;
+ int spriteWidth = distXCount;
+ int widthAmount = destX + distXCount - 1;
+
+ if (destX < 0) {
+ spriteWidth += destX;
+ spriteLeft -= destX;
+ }
+ widthAmount -= destRight;
+ if (widthAmount > 0)
+ spriteWidth -= widthAmount;
+
+ int spriteRight = spriteLeft + spriteWidth;
+ if (spriteWidth <= 0)
+ return;
+ if (!normalFrame) {
+ destX += distXCount - 1;
+ spriteLeft = -(distXCount - spriteRight);
+ spriteRight = (-spriteLeft + spriteWidth);
+ }
+
+ // Check y bounding area
+ int spriteTop = 0;
+ int spriteHeight = distYCount;
+ int heightAmount = destY + distYCount - 1;
+
+ if (destY < 0) {
+ spriteHeight += destY;
+ spriteTop -= destY;
+ }
+ heightAmount -= destBottom;
+ if (heightAmount > 0)
+ spriteHeight -= heightAmount;
+ int spriteBottom = spriteTop + spriteHeight;
+
+ if (spriteHeight <= 0)
+ return;
+
+ byte *destPixelsP = this->getBasePtr(destX + spriteLeft, destY + spriteTop);
+
+ spriteLeft = (spriteLeft * (normalFrame ? 1 : -1));
+
+ // Loop through the lines of the sprite
+ for (int yp = 0, sprY = -1; yp < frameHeight; ++yp, srcPixelsP += src->pitch) {
+ if (!lineDist[yp])
+ // Not a display line, so skip it
+ continue;
+ // Check whether the sprite line is in the display range
+ ++sprY;
+ if ((sprY >= spriteBottom) || (sprY < spriteTop))
+ continue;
+
+ // Found a line to display. Loop through the pixels
+ const byte *srcP = srcPixelsP;
+ byte *destP = destPixelsP;
+
+ for (int xp = 0, sprX = 0; xp < frameWidth; ++xp, ++srcP) {
+ if (xp < spriteLeft)
+ // Not yet reached start of display area
+ continue;
+ if (!lineDist[sprX++])
+ // Not a display pixel
+ continue;
+
+ // Get depth of current output pixel in depth surface
+ Common::Point pt((destP - (byte *)this->pixels) % this->pitch,
+ (destP - (byte *)this->pixels) / this->pitch);
+ int pixelDepth = (depthSurface == nullptr) ? 15 : depthSurface->getDepth(pt);
+
+ if ((*srcP != transparentColor) && (depth <= pixelDepth))
+ *destP = *srcP;
+
+ ++destP;
+ }
+
+ // Move to the next destination line
+ destPixelsP += this->pitch;
+ }
+}
+
+void MSurface::scrollX(int xAmount) {
+ if (xAmount == 0)
+ return;
+
+ byte buffer[80];
+ int direction = (xAmount > 0) ? -1 : 1;
+ int xSize = ABS(xAmount);
+ assert(xSize <= 80);
+
+ byte *srcP = getBasePtr(0, 0);
+
+ for (int y = 0; y < this->h; ++y, srcP += pitch) {
+ if (direction < 0) {
+ // Copy area to be overwritten
+ Common::copy(srcP, srcP + xSize, &buffer[0]);
+ // Shift the remainder of the line over the given area
+ Common::copy(srcP + xSize, srcP + this->w, srcP);
+ // Move buffered area to the end of the line
+ Common::copy(&buffer[0], &buffer[xSize], srcP + this->w - xSize);
+ } else {
+ // Copy area to be overwritten
+ Common::copy_backward(srcP + this->w - xSize, srcP + this->w, &buffer[80]);
+ // Shift the remainder of the line over the given area
+ Common::copy_backward(srcP, srcP + this->w - xSize, srcP + this->w);
+ // Move buffered area to the start of the line
+ Common::copy_backward(&buffer[80 - xSize], &buffer[80], srcP + xSize);
+ }
+ }
+}
+
+void MSurface::scrollY(int yAmount) {
+ if (yAmount == 0)
+ return;
+
+ int direction = (yAmount > 0) ? 1 : -1;
+ int ySize = ABS(yAmount);
+ assert(ySize < (this->h / 2));
+ assert(this->w == pitch);
+
+ int blockSize = ySize * this->w;
+ byte *tempData = new byte[blockSize];
+ byte *pixelsP = getBasePtr(0, 0);
+
+ if (direction > 0) {
+ // Buffer the lines to be overwritten
+ byte *srcP = (byte *)getBasePtr(0, this->h - ySize);
+ Common::copy(srcP, srcP + (pitch * ySize), tempData);
+ // Vertically shift all the lines
+ Common::copy_backward(pixelsP, pixelsP + (pitch * (this->h - ySize)),
+ pixelsP + (pitch * this->h));
+ // Transfer the buffered lines top the top of the screen
+ Common::copy(tempData, tempData + blockSize, pixelsP);
+ } else {
+ // Buffer the lines to be overwritten
+ Common::copy(pixelsP, pixelsP + (pitch * ySize), tempData);
+ // Vertically shift all the lines
+ Common::copy(pixelsP + (pitch * ySize), pixelsP + (pitch * this->h), pixelsP);
+ // Transfer the buffered lines to the bottom of the screen
+ Common::copy(tempData, tempData + blockSize, pixelsP + (pitch * (this->h - ySize)));
+ }
+
+ delete[] tempData;
+}
+
+
+void MSurface::translate(Common::Array<RGB6> &palette) {
+ for (int y = 0; y < this->h; ++y) {
+ byte *pDest = getBasePtr(0, y);
+
+ for (int x = 0; x < this->w; ++x, ++pDest) {
+ if (*pDest < 255) // scene 752 has some palette indices of 255
+ *pDest = palette[*pDest]._palIndex;
+ }
+ }
+}
+
+void MSurface::translate(byte map[PALETTE_COUNT]) {
+ for (int y = 0; y < this->h; ++y) {
+ byte *pDest = getBasePtr(0, y);
+
+ for (int x = 0; x < this->w; ++x, ++pDest) {
+ *pDest = map[*pDest];
+ }
+ }
+}
+
+MSurface *MSurface::flipHorizontal() const {
+ MSurface *dest = new MSurface(this->w, this->h);
+
+ for (int y = 0; y < this->h; ++y) {
+ const byte *srcP = getBasePtr(this->w - 1, y);
+ byte *destP = dest->getBasePtr(0, y);
+
+ for (int x = 0; x < this->w; ++x)
+ *destP++ = *srcP--;
+ }
+
+ return dest;
+}
+
+/*------------------------------------------------------------------------*/
+
+int DepthSurface::getDepth(const Common::Point &pt) {
+ if (_vm->_game->_scene._sceneInfo->_depthStyle == 2) {
+ int bits = (3 - (pt.x % 4)) * 2;
+ byte v = *getBasePtr(pt.x >> 2, pt.y);
+ return v >> bits;
+ } else {
+ if (pt.x < 0 || pt.y < 0 || pt.x >= this->w || pt.y >= this->h)
+ return 0;
+
+ return *getBasePtr(pt.x, pt.y) & 0xF;
+ }
+}
+
+int DepthSurface::getDepthHighBit(const Common::Point &pt) {
+ if (_vm->_game->_scene._sceneInfo->_depthStyle == 2) {
+ int bits = (3 - (pt.x % 4)) * 2;
+ byte v = *getBasePtr(pt.x >> 2, pt.y);
+ return (v >> bits) & 2;
+ } else {
+ if (pt.x < 0 || pt.y < 0 || pt.x >= this->w || pt.y >= this->h)
+ return 0;
+
+ return *getBasePtr(pt.x, pt.y) & 0x80;
+ }
+}
+
+
+} // End of namespace MADS
diff --git a/engines/mads/msurface.h b/engines/mads/msurface.h
new file mode 100644
index 0000000000..e3cf89d649
--- /dev/null
+++ b/engines/mads/msurface.h
@@ -0,0 +1,240 @@
+/* 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.
+ *
+ */
+
+#ifndef MADS_MSURFACE_H
+#define MADS_MSURFACE_H
+
+#include "common/scummsys.h"
+#include "common/rect.h"
+#include "graphics/surface.h"
+#include "mads/palette.h"
+
+namespace MADS {
+
+class MADSEngine;
+class MSprite;
+class DepthSurface;
+
+/**
+ * Basic sprite information
+ */
+struct SpriteInfo {
+ MSprite *sprite;
+ int hotX, hotY;
+ int width, height;
+ int scaleX, scaleY;
+ uint8 encoding;
+ byte *inverseColorTable;
+ byte *palette;
+};
+
+/*
+ * MADS graphics surface
+ */
+class MSurface : public Graphics::Surface {
+private:
+ bool _freeFlag;
+protected:
+ static MADSEngine *_vm;
+public:
+ /**
+ * Sets the engine refrence used all surfaces
+ */
+ static void setVm(MADSEngine *vm) { _vm = vm; }
+
+ /**
+ * Helper method for calculating new dimensions when scaling a sprite
+ */
+ static int scaleValue(int value, int scale, int err);
+public:
+ /**
+ * Basic constructor
+ */
+ MSurface();
+
+ /**
+ * Constructor for a surface with fixed dimensions
+ */
+ MSurface(int width, int height);
+
+ /**
+ * Destructor
+ */
+ virtual ~MSurface();
+
+ /**
+ * Reinitialises a surface to have a given set of dimensions
+ */
+ void setSize(int width, int height);
+
+ /**
+ * Sets the pixels the surface is associated with
+ * @remarks The surface will not free the data block
+ */
+ void setPixels(byte *pData, int horizSize, int vertSize);
+
+ /**
+ * Draws an arbitrary line on the screen using a specified color
+ * @param startPos Starting position
+ * @param endPos Ending position
+ * @param color Color to use
+ */
+ void line(const Common::Point &startPos, const Common::Point &endPos, byte color);
+
+ /**
+ * Draws a sprite
+ * @param pt Position to draw sprite at
+ * @param info General sprite details
+ * @param clipRect Clipping rectangle to constrain sprite drawing within
+ */
+ void drawSprite(const Common::Point &pt, SpriteInfo &info, const Common::Rect &clipRect);
+
+ /**
+ * Returns the width of the surface
+ */
+ int getWidth() const { return w; }
+
+ /**
+ * Returns the height of the surface
+ */
+ int getHeight() const { return h; }
+
+ /**
+ * Returns the size of the surface as a Rect
+ */
+ Common::Rect getBounds() const {
+ return Common::Rect(0, 0, w, h);
+ }
+
+ /**
+ * Returns a pointer to the surface data
+ */
+ byte *getData() { return (byte *)Graphics::Surface::getPixels(); }
+
+ /**
+ * Returns a pointer to a given position within the surface
+ */
+ byte *getBasePtr(int x, int y) { return (byte *)Graphics::Surface::getBasePtr(x, y); }
+
+ /**
+ * Returns a pointer to a given position within the surface
+ */
+ const byte *getBasePtr(int x, int y) const { return (const byte *)Graphics::Surface::getBasePtr(x, y); }
+
+ /**
+ * Clears the surface
+ */
+ void empty();
+
+ /**
+ * Copys a sub-section of another surface into the current one.
+ * @param src Source surface
+ * @param srcBounds Area of source surface to copy
+ * @param destPos Destination position to draw in current surface
+ * @param transparentColor Transparency palette index
+ */
+ void copyFrom(MSurface *src, const Common::Rect &srcBounds, const Common::Point &destPos,
+ int transparentColor = -1);
+
+ /**
+ * Copys a sub-section of another surface into the current one.
+ * @param src Source surface
+ * @param destPos Destination position to draw in current surface
+ * @param depth Depth of sprite
+ * @param depthSurface Depth surface to use with sprite depth
+ * @param transparentColor Transparency palette index
+ */
+ void copyFrom(MSurface *src, const Common::Point &destPos, int depth, DepthSurface *depthSurface,
+ int scale, int transparentColor = -1);
+
+ /**
+ * Copies the surface to a given destination surface
+ */
+ void copyTo(MSurface *dest, int transparentColor = -1) {
+ dest->copyFrom(this, Common::Rect(w, h), Common::Point(), transparentColor);
+ }
+
+ /**
+ * Copies the surface to a given destination surface
+ */
+ void copyTo(MSurface *dest, const Common::Point &pt, int transparentColor = -1) {
+ dest->copyFrom(this, Common::Rect(w, h), pt, transparentColor);
+ }
+
+ /**
+ * Copies the surface to a given destination surface
+ */
+ void copyTo(MSurface *dest, const Common::Rect &srcBounds, const Common::Point &destPos,
+ int transparentColor = -1) {
+ dest->copyFrom(this, srcBounds, destPos, transparentColor);
+ }
+
+ /**
+ * Scroll the screen horizontally by a given amount
+ * @param xAmount Horizontal amount
+ */
+ void scrollX(int xAmount);
+
+ /**
+ * Scroll the screen vertically by a given amount
+ * @param yAmount Vertical amount
+ */
+ void scrollY(int yAmount);
+
+ /**
+ * Translates the pixels of an image used the passed palette with RGB mapping
+ */
+ void translate(Common::Array<RGB6> &palette);
+
+ /**
+ * Translates the pixels of an image used the passed palette with RGB mapping
+ */
+ void translate(byte map[PALETTE_COUNT]);
+
+ /**
+ * Create a new surface which is a flipped horizontal copy of the current one
+ */
+ MSurface *flipHorizontal() const;
+};
+
+class DepthSurface : public MSurface {
+private:
+ MADSEngine *_vm;
+public:
+ /**
+ * Constructor
+ */
+ DepthSurface(MADSEngine *vm) : _vm(vm) {}
+
+ /**
+ * Returns the depth at a given position
+ */
+ int getDepth(const Common::Point &pt);
+
+ /**
+ */
+ int getDepthHighBit(const Common::Point &pt);
+};
+
+} // End of namespace MADS
+
+#endif /* MADS_MSURFACE_H */
diff --git a/engines/mads/nebular/dialogs_nebular.cpp b/engines/mads/nebular/dialogs_nebular.cpp
new file mode 100644
index 0000000000..a4a7694d2c
--- /dev/null
+++ b/engines/mads/nebular/dialogs_nebular.cpp
@@ -0,0 +1,693 @@
+/* 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 "common/config-manager.h"
+#include "common/util.h"
+#include "mads/mads.h"
+#include "mads/screen.h"
+#include "mads/msurface.h"
+#include "mads/staticres.h"
+#include "mads/nebular/dialogs_nebular.h"
+
+namespace MADS {
+
+namespace Nebular {
+
+bool DialogsNebular::show(int messageId, int objectId) {
+ MADSAction &action = _vm->_game->_scene._action;
+ Common::StringArray msg = _vm->_game->getMessage(messageId);
+ Common::String title;
+ Common::String commandText;
+ Common::String valStr;
+ Common::String dialogText;
+ bool result = true;
+ bool centerFlag = false;
+ bool underlineFlag = false;
+ bool commandFlag = false;
+ bool crFlag = false;
+ TextDialog *dialog = nullptr;
+ _dialogWidth = 17;
+ _capitalizationMode = kUppercase;
+
+ // Loop through the lines of the returned text
+ for (uint idx = 0; idx < msg.size(); ++idx) {
+ Common::String srcLine = msg[idx];
+ const char *srcP = srcLine.c_str();
+
+ // Loop through the text of the line
+ while (srcP < srcLine.c_str() + srcLine.size()) {
+ if (*srcP == '[') {
+ // Starting a command
+ commandText = "";
+ commandFlag = true;
+ } else if (*srcP == ']') {
+ // Ending a command
+ if (commandFlag) {
+ if (commandCheck("CENTER", valStr, commandText)) {
+ centerFlag = true;
+ } else if (commandCheck("TITLE", valStr, commandText)) {
+ centerFlag = true;
+ underlineFlag = true;
+ crFlag = true;
+ int v = atoi(valStr.c_str());
+ if (v != 0)
+ _dialogWidth = v;
+ } else if (commandCheck("CR", valStr, commandText)) {
+ if (centerFlag) {
+ crFlag = true;
+ } else {
+ if (objectId == -1) {
+ dialog = new TextDialog(_vm, FONT_INTERFACE, _defaultPosition, _dialogWidth);
+ } else {
+ dialog = new PictureDialog(_vm, _defaultPosition, _dialogWidth, objectId);
+ }
+ dialog->wordWrap(dialogText);
+ dialog->incNumLines();
+ }
+ } else if (commandCheck("ASK", valStr, commandText)) {
+ dialog->addInput();
+ } else if (commandCheck("VERB", valStr, commandText)) {
+ dialogText += getVocab(action._activeAction._verbId);
+ } else if (commandCheck("INDEX", valStr, commandText)) {
+ int idxLocal = atoi(valStr.c_str());
+ if (_indexList[idxLocal])
+ dialogText += getVocab(_indexList[idxLocal]);
+ } else if (commandCheck("NUMBER", valStr, commandText)) {
+ int idxLocal = atoi(valStr.c_str());
+ dialogText += Common::String::format("%.4d", _indexList[idxLocal]);
+ } else if (commandCheck("NOUN1", valStr, commandText)) {
+ if (!textNoun(dialogText, 1, valStr))
+ dialogText += getVocab(action._activeAction._objectNameId);
+ } else if (commandCheck("NOUN2", valStr, commandText)) {
+ if (!textNoun(dialogText, 2, valStr))
+ dialogText += getVocab(action._activeAction._indirectObjectId);
+ } else if (commandCheck("PREP", valStr, commandText)) {
+ dialogText += kArticleList[action._savedFields._articleNumber];
+ } else if (commandCheck("SENTENCE", valStr, commandText)) {
+ dialogText += action._sentence;
+ } else if (commandCheck("WIDTH", valStr, commandText)) {
+ _dialogWidth = atoi(valStr.c_str());
+ } else if (commandCheck("BAR", valStr, commandText)) {
+ dialog->addBarLine();
+ } else if (commandCheck("UNDER", valStr, commandText)) {
+ underlineFlag = true;
+ } else if (commandCheck("DOWN", valStr, commandText)) {
+ dialog->downPixelLine();
+ } else if (commandCheck("TAB", valStr, commandText)) {
+ int xp = atoi(valStr.c_str());
+ dialog->setLineXp(xp);
+ }
+ }
+
+ commandFlag = false;
+ } else if (commandFlag) {
+ // Add the next character to the command
+ commandText += *srcP;
+ } else {
+ // Add to the text to be displayed in the dialog
+ dialogText += *srcP;
+ }
+
+ ++srcP;
+ }
+
+ if (!dialog) {
+ if (objectId == -1) {
+ dialog = new TextDialog(_vm, FONT_INTERFACE, _defaultPosition, _dialogWidth);
+ } else {
+ dialog = new PictureDialog(_vm, _defaultPosition, _dialogWidth, objectId);
+ }
+ }
+
+ if (centerFlag) {
+ dialog->addLine(dialogText, underlineFlag);
+ if (crFlag)
+ dialog->incNumLines();
+ } else {
+ dialog->wordWrap(dialogText);
+ }
+
+ // Reset line processing flags in preparation for next line
+ dialogText = "";
+ commandFlag = false;
+ underlineFlag = false;
+ centerFlag = false;
+ crFlag = false;
+ }
+
+ if (!centerFlag)
+ dialog->incNumLines();
+
+ // Show the dialog
+ _vm->_events->setCursor(CURSOR_ARROW);
+ dialog->show();
+
+ delete dialog;
+ return result;
+}
+
+void DialogsNebular::showItem(int objectId, int messageId, int speech) {
+ // MADS engine doesn't currently support speech
+ assert(!speech);
+
+ show(messageId, objectId);
+}
+
+Common::String DialogsNebular::getVocab(int vocabId) {
+ assert(vocabId > 0);
+
+ Common::String vocab = _vm->_game->_scene.getVocab(vocabId);
+
+ switch (_capitalizationMode) {
+ case kUppercase:
+ vocab.toUppercase();
+ break;
+ case kLowercase:
+ vocab.toLowercase();
+ break;
+ case kUpperAndLower:
+ vocab.toLowercase();
+ vocab.setChar(toupper(vocab[0]), 0);
+ default:
+ break;
+ }
+
+ return vocab;
+}
+
+bool DialogsNebular::textNoun(Common::String &dest, int nounId, const Common::String &source) {
+ // Ensure the destination has parameter specifications
+ if (!source.hasPrefix(":"))
+ return false;
+
+ // Extract the first (singular) result value
+ Common::String param1 = Common::String(source.c_str() + 1);
+ Common::String param2;
+ const char *sepChar = strchr(source.c_str() + 1, ':');
+ if (sepChar) {
+ param1 = Common::String(source.c_str() + 1, sepChar);
+
+ // Get the second, plural form
+ param2 = Common::String(sepChar + 1);
+ }
+
+ // Get the vocab to use
+ MADSAction &action = _vm->_game->_scene._action;
+ Common::String vocab = _vm->_dialogs->getVocab(action._activeAction._verbId);
+ Common::String *str;
+
+ if (vocab.hasSuffix("s") || vocab.hasSuffix("S")) {
+ str = &param2;
+ } else {
+ str = &param1;
+
+ if (param1 == "a ") {
+ switch (toupper(vocab[0])) {
+ case 'A':
+ case 'E':
+ case 'I':
+ case 'O':
+ case 'U':
+ param1 = "an ";
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ dest += *str;
+ return true;
+}
+
+bool DialogsNebular::commandCheck(const char *idStr, Common::String &valStr,
+ const Common::String &command) {
+ uint idLen = strlen(idStr);
+
+ valStr = (command.size() <= idLen) ? "" : Common::String(command.c_str() + idLen);
+
+ // Check whether the command starts with the given Id
+ int result = scumm_strnicmp(idStr, command.c_str(), idLen) == 0;
+ if (!result)
+ return false;
+
+ // It does, so set the command case mode
+ if (Common::isUpper(command[0]) && Common::isUpper(command[1])) {
+ _capitalizationMode = kUppercase;
+ } else if (Common::isUpper(command[0])) {
+ _capitalizationMode = kUpperAndLower;
+ } else {
+ _capitalizationMode = kLowercase;
+ }
+
+ return true;
+}
+
+void DialogsNebular::showDialog() {
+ switch (_pendingDialog) {
+ case DIALOG_GAME_MENU:
+ //GameMenuDialog::show();
+ break;
+ default:
+ break;
+ }
+}
+
+/*------------------------------------------------------------------------*/
+
+CopyProtectionDialog::CopyProtectionDialog(MADSEngine *vm, bool priorAnswerWrong) :
+TextDialog(vm, FONT_INTERFACE, Common::Point(-1, -1), 32) {
+ getHogAnusEntry(_hogEntry);
+
+ if (priorAnswerWrong) {
+ addLine("ANSWER INCORRECT!", true);
+ wordWrap("\n");
+ addLine("(But we'll give you another chance!)");
+ }
+ else {
+ addLine("REX NEBULAR version 8.43", true);
+ wordWrap("\n");
+ addLine("(Copy Protection, for your convenience)");
+ }
+ wordWrap("\n");
+
+ wordWrap("Now comes the part that everybody hates. But if we don't");
+ wordWrap("do this, nasty rodent-like people will pirate this game");
+ wordWrap("and a whole generation of talented designers, programmers,");
+ wordWrap("artists, and playtesters will go hungry, and will wander");
+ wordWrap("aimlessly through the land at night searching for peace.");
+ wordWrap("So let's grit our teeth and get it over with. Just get");
+
+ Common::String line = "out your copy of ";
+ line += _hogEntry._bookId == 103 ? "the GAME MANUAL" : "REX'S LOGBOOK";
+ line += ". See! That was easy. ";
+ wordWrap(line);
+
+ line = Common::String::format("Next, just turn to page %d. On line %d, find word number %d, ",
+ _hogEntry._pageNum, _hogEntry._lineNum, _hogEntry._wordNum);
+ wordWrap(line);
+
+ wordWrap("and type it on the line below (we',27h,'ve even given you");
+ wordWrap("first letter as a hint). As soon as you do that, we can get");
+ wordWrap("right into this really COOL adventure game!\n");
+ wordWrap("\n");
+ wordWrap(" ");
+ addInput();
+ wordWrap("\n");
+}
+
+void CopyProtectionDialog::show() {
+ draw();
+ _vm->_events->showCursor();
+
+ // TODO: Replace with text input
+ while (!_vm->shouldQuit() && !_vm->_events->isKeyPressed() &&
+ !_vm->_events->_mouseClicked) {
+ _vm->_events->delay(1);
+ }
+
+ _vm->_events->_pendingKeys.clear();
+}
+
+bool CopyProtectionDialog::getHogAnusEntry(HOGANUS &entry) {
+ File f;
+ f.open("*HOGANUS.DAT");
+
+ // Read in the total number of entries, and randomly pick an entry to use
+ int numEntries = f.readUint16LE();
+ int entryIndex = _vm->getRandomNumber(1, numEntries);
+
+ // Read in the encrypted entry
+ f.seek(28 * entryIndex + 2);
+ byte entryData[28];
+ f.read(entryData, 28);
+
+ // Decrypt it
+ for (int i = 0; i < 28; ++i)
+ entryData[i] = ~entryData[i];
+
+ // Fill out the fields
+ entry._bookId = entryData[0];
+ entry._pageNum = READ_LE_UINT16(&entryData[2]);
+ entry._lineNum = READ_LE_UINT16(&entryData[4]);
+ entry._wordNum = READ_LE_UINT16(&entryData[6]);
+ entry._word = Common::String((char *)&entryData[8]);
+
+ f.close();
+ return true;
+}
+
+/*------------------------------------------------------------------------*/
+
+PictureDialog::PictureDialog(MADSEngine *vm, const Common::Point &pos,
+ int maxChars, int objectId) :
+ TextDialog(vm, FONT_INTERFACE, pos, maxChars), _objectId(objectId) {
+ // Turn off cycling if active
+ Scene &scene = _vm->_game->_scene;
+ _cyclingActive = scene._cyclingActive;
+ scene._cyclingActive = false;
+}
+
+PictureDialog::~PictureDialog() {
+ // Restore cycling flag
+ Scene &scene = _vm->_game->_scene;
+ scene._cyclingActive = _cyclingActive;
+}
+
+void PictureDialog::save() {
+ Palette &palette = *_vm->_palette;
+ byte map[PALETTE_COUNT];
+
+ // Save the entire screen
+ _savedSurface = new MSurface(MADS_SCREEN_WIDTH, MADS_SCREEN_HEIGHT);
+ _vm->_screen.copyTo(_savedSurface);
+
+ // Save palette information
+ Common::copy(&palette._mainPalette[0], &palette._mainPalette[PALETTE_SIZE], &_palette[0]);
+ Common::copy(&palette._palFlags[0], &palette._palFlags[PALETTE_COUNT], &_palFlags[0]);
+ _rgbList.copy(palette._rgbList);
+
+ // Set up palette allocation
+ Common::fill(&palette._colorFlags[0], &palette._colorFlags[3], true);
+
+ uint32 *palFlagP = &palette._palFlags[0];
+ for (int idx = 0; idx < PALETTE_COUNT; ++idx, ++palFlagP) {
+ if (idx < PALETTE_RESERVED_LOW_COUNT ||
+ idx >= (PALETTE_COUNT - PALETTE_RESERVED_HIGH_COUNT - 10)) {
+ *palFlagP = 1;
+ map[idx] = idx;
+ } else {
+ *palFlagP = 0;
+ }
+ }
+
+ // Reset the flag list
+ palette._rgbList.reset();
+
+ // Fade the screen to grey
+ int numColors = PALETTE_COUNT - PALETTE_RESERVED_LOW_COUNT - PALETTE_RESERVED_HIGH_COUNT;
+ palette.fadeOut(palette._mainPalette, &map[PALETTE_RESERVED_LOW_COUNT],
+ PALETTE_RESERVED_LOW_COUNT, numColors, 248, 8, 1, 16);
+
+ // Remap the greyed out screen to use the small greyscale range
+ // at the top end of the palette
+ _vm->_screen.translate(map);
+
+ // Load the inventory picture
+ Common::String setName = Common::String::format("*OB%.3d.SS", _objectId);
+ SpriteAsset *asset = new SpriteAsset(_vm, setName, 0x8000);
+ palette.setFullPalette(palette._mainPalette);
+
+ // Get the inventory frame, and adjust the dialog position to allow for it
+ MSprite *frame = asset->getFrame(0);
+ _position.y = frame->h + 12;
+
+ // Draw the inventory picture
+ frame->copyTo(&_vm->_screen, Common::Point(160 - frame->w / 2, 6),
+ frame->getTransparencyIndex());
+ _vm->_screen.copyRectToScreen(_vm->_screen.getBounds());
+
+ // Adjust the dialog colors to use
+ TEXTDIALOG_CONTENT1 -= 10;
+ TEXTDIALOG_CONTENT2 -= 10;
+ TEXTDIALOG_EDGE -= 10;
+ TEXTDIALOG_BACKGROUND -= 10;
+ TEXTDIALOG_FC -= 10;
+ TEXTDIALOG_FD -= 10;
+ TEXTDIALOG_FE -= 10;
+}
+
+void PictureDialog::restore() {
+ if (_savedSurface) {
+ _savedSurface->copyTo(&_vm->_screen);
+ delete _savedSurface;
+ _savedSurface = nullptr;
+
+ _vm->_screen.copyRectToScreen(_vm->_screen.getBounds());
+
+ // Restore palette information
+ Palette &palette = *_vm->_palette;
+ Common::copy(&_palette[0], &_palette[PALETTE_SIZE], &palette._mainPalette[0]);
+ _vm->_palette->setFullPalette(palette._mainPalette);
+ Common::copy(&_palFlags[0], &_palFlags[PALETTE_COUNT], &palette._palFlags[0]);
+ palette._rgbList.copy(_rgbList);
+
+ _vm->_dialogs->_defaultPosition.y = -1;
+ }
+}
+
+/*------------------------------------------------------------------------*/
+
+ScreenDialog::DialogLine::DialogLine() {
+ _state = 0;
+ _textDisplayIndex = -1;
+ _font = nullptr;
+ _widthAdjust = 0;
+}
+
+ScreenDialog::DialogLine::DialogLine(const Common::String &s) {
+ _state = 0;
+ _textDisplayIndex = -1;
+ _font = nullptr;
+ _widthAdjust = -1;
+ _msg = s;
+}
+
+/*------------------------------------------------------------------------*/
+
+ScreenDialog::ScreenDialog(MADSEngine *vm) : _vm(vm),
+ _savedSurface(MADS_SCREEN_WIDTH, MADS_SCREEN_HEIGHT) {
+ Game &game = *_vm->_game;
+ Scene &scene = game._scene;
+
+ _v1 = 0;
+ _selectedLine = 0;
+ _dirFlag = false;
+ _textLineCount = 0;
+
+ game.loadQuoteSet(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
+ 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33,
+ 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 0);
+ game._kernelMode = KERNEL_ROOM_PRELOAD;
+ _vm->_events->waitCursor();
+ scene.clearVocab();
+ scene._dynamicHotspots.clear();
+ _vm->_dialogs->_defaultPosition = Common::Point(-1, -1);
+
+ bool palFlag = false;
+ int nextSceneId = scene._nextSceneId;
+ int currentSceneId = scene._currentSceneId;
+ int priorSceneId = scene._priorSceneId;
+
+ if (_vm->_dialogs->_pendingDialog == DIALOG_DIFFICULTY) {
+ palFlag = true;
+ } else {
+ _vm->_palette->initPalette();
+ }
+ scene.loadScene(_screenId, game._aaName, palFlag);
+
+ scene._priorSceneId = priorSceneId;
+ scene._currentSceneId = currentSceneId;
+ scene._nextSceneId = nextSceneId;
+ _vm->_screen._offset.y = 22;
+ _vm->_sound->pauseNewCommands();
+ _vm->_events->initVars();
+ game._kernelMode = KERNEL_ROOM_INIT;
+
+ SpriteAsset *menuSprites = new SpriteAsset(_vm, "*MENU", 0);
+ _menuSpritesIndex = scene._sprites.add(menuSprites);
+
+ byte pal[768];
+ if (_vm->_screenFade) {
+ Common::fill(&pal[0], &pal[PALETTE_SIZE], 0);
+ _vm->_palette->setFullPalette(pal);
+ } else {
+ _vm->_palette->getFullPalette(pal);
+ _vm->_palette->fadeOut(pal, nullptr, 0, PALETTE_COUNT, 0, 1, 1, 16);
+ }
+
+ _vm->_screen.copyTo(&_savedSurface);
+ /*
+ _vm->_screen.hLine(0, 0, MADS_SCREEN_WIDTH, 2);
+ _vm->_screen.copyRectToScreen(Common::Rect(0, _vm->_screen._offset.y,
+ MADS_SCREEN_WIDTH, _vm->_screen._offset.y + 1));
+ _vm->_screen.copyRectToScreen(Common::Rect(0, _vm->_screen._offset.y + 157,
+ MADS_SCREEN_WIDTH, _vm->_screen._offset.y + 157));
+ */
+
+ game._fx = _vm->_screenFade == SCREEN_FADE_SMOOTH ?
+ kCenterVertTransition : kTransitionFadeIn;
+ game._trigger = 0;
+ _vm->_events->setCursor(CURSOR_ARROW);
+
+ _vm->_palette->setEntry(10, 0, 63, 0);
+ _vm->_palette->setEntry(11, 0, 45, 0);
+ _vm->_palette->setEntry(12, 63, 63, 0);
+ _vm->_palette->setEntry(13, 45, 45, 0);
+ _vm->_palette->setEntry(14, 63, 63, 63);
+ _vm->_palette->setEntry(15, 45, 45, 45);
+}
+
+void ScreenDialog::clearLines() {
+ Scene &scene = _vm->_game->_scene;
+ _lines.clear();
+ scene._spriteSlots.fullRefresh(true);
+}
+
+void ScreenDialog::addQuote(int id1, int id2, DialogTextAlign align,
+ const Common::Point &pt, Font *font) {
+ Common::String msg = _vm->_game->getQuote(id1);
+
+ if (id2 > 0) {
+ msg += " ";
+ msg += _vm->_game->getQuote(id2);
+ }
+
+ addLine(msg, align, pt, font);
+}
+
+void ScreenDialog::addLine(const Common::String &msg, DialogTextAlign align,
+ const Common::Point &pt, Font *font) {
+ Scene &scene = _vm->_game->_scene;
+ DialogLine *line;
+
+ if (_lineIndex < (int)_lines.size()) {
+ if (_lines.size() >= 20)
+ goto finish;
+
+ _lines.push_back(msg);
+ line = &_lines[_lines.size() - 1];
+ } else {
+ line = &_lines[_lineIndex];
+ if (msg.compareToIgnoreCase(msg))
+ goto finish;
+
+ if (line->_textDisplayIndex >= 0) {
+ TextDisplay &textDisplay = scene._textDisplay[line->_textDisplayIndex];
+ if (textDisplay._active) {
+ textDisplay._expire = -1;
+ if (_textLineCount < 20) {
+ textDisplay._msg = msg;
+ ++_textLineCount;
+ }
+ }
+ }
+ }
+
+ line->_font = font;
+ line->_state = 0;
+ line->_pos = pt;
+ line->_widthAdjust = -1;
+ line->_textDisplayIndex = -1;
+
+ int xOffset;
+ switch (align) {
+ case ALIGN_CENTER:
+ xOffset = (MADS_SCREEN_WIDTH / 2) - font->getWidth(msg, -1) / 2;
+ line->_pos.x += xOffset;
+ break;
+
+ case ALIGN_AT_CENTER: {
+ const char *msgP = msg.c_str();
+ const char *ch = strchr(msgP, '@');
+ if (ch) {
+ xOffset = (MADS_SCREEN_WIDTH / 2) - font->getWidth(
+ Common::String(msgP, ch), line->_widthAdjust);
+ line->_pos.x += xOffset;
+ }
+ break;
+ }
+
+ case ALIGN_RIGHT:
+ xOffset = font->getWidth(msg, -1);
+ line->_pos.x -= xOffset;
+ break;
+
+ default:
+ break;
+ }
+
+finish:
+ ++_lineIndex;
+}
+
+void ScreenDialog::initVars() {
+ _v1 = -1;
+ _selectedLine = -1;
+ _lineIndex = 0;
+ _enterFlag = false;
+ _textLineCount = 0;
+}
+
+void ScreenDialog::chooseBackground() {
+ switch (_vm->_game->_currentSectionNumber) {
+ case 1:
+ case 2:
+ _screenId = 921;
+ break;
+ case 3:
+ case 4:
+ _screenId = 922;
+ break;
+ case 5:
+ case 6:
+ case 7:
+ _screenId = 923;
+ break;
+ case 8:
+ _screenId = 924;
+ break;
+ default:
+ _screenId = 920;
+ break;
+ }
+}
+
+void ScreenDialog::setFrame(int frameNumber, int depth) {
+ Scene &scene = _vm->_game->_scene;
+ SpriteSlot &spriteSlot = scene._spriteSlots[scene._spriteSlots.add()];
+ spriteSlot._flags = IMG_UPDATE;
+ spriteSlot._seqIndex = 1;
+ spriteSlot._spritesIndex = _menuSpritesIndex;
+ spriteSlot._frameNumber = frameNumber;
+
+}
+
+/*------------------------------------------------------------------------*/
+
+GameMenuDialog::GameMenuDialog(MADSEngine *vm) : ScreenDialog(vm) {
+ clearLines();
+ setFrame(1, 2);
+}
+
+void GameMenuDialog::addLines() {
+ initVars();
+ Font *font = _vm->_font->getFont(FONT_CONVERSATION);
+ int top = 78 - (font->getHeight() + 2) * 12;
+ addQuote(10, 0, ALIGN_CENTER, Common::Point(0, top), font);
+ // TODO
+}
+
+} // End of namespace Nebular
+
+} // End of namespace MADS
diff --git a/engines/mads/nebular/dialogs_nebular.h b/engines/mads/nebular/dialogs_nebular.h
new file mode 100644
index 0000000000..643d440d67
--- /dev/null
+++ b/engines/mads/nebular/dialogs_nebular.h
@@ -0,0 +1,180 @@
+/* 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.
+ *
+ */
+
+#ifndef MADS_DIALOGS_NEBULAR_H
+#define MADS_DIALOGS_NEBULAR_H
+
+#include "common/scummsys.h"
+#include "mads/game.h"
+#include "mads/dialogs.h"
+
+namespace MADS {
+
+namespace Nebular {
+
+enum CapitalizationMode { kUppercase = 0, kLowercase = 1, kUpperAndLower = 2 };
+
+class DialogsNebular: public Dialogs {
+ friend class Dialogs;
+private:
+ int _dialogWidth;
+ CapitalizationMode _capitalizationMode;
+
+ DialogsNebular(MADSEngine *vm): Dialogs(vm) {}
+
+ virtual Common::String getVocab(int vocabId);
+
+ bool textNoun(Common::String &dest, int nounId, const Common::String &source);
+
+ bool commandCheck(const char *idStr, Common::String &valStr, const Common::String &command);
+public:
+ virtual void showDialog();
+
+ virtual void showItem(int objectId, int messageId, int speech = -1);
+
+ virtual bool show(int messageId, int objectId = -1);
+};
+
+struct HOGANUS {
+ int _bookId;
+ int _pageNum;
+ int _lineNum;
+ int _wordNum;
+ Common::String _word;
+};
+
+class CopyProtectionDialog: public TextDialog {
+private:
+ HOGANUS _hogEntry;
+
+ /**
+ * Get a random copy protection entry from the HOGANUS resource
+ */
+ bool getHogAnusEntry(HOGANUS &entry);
+public:
+ /**
+ * Constructor
+ */
+ CopyProtectionDialog(MADSEngine *vm, bool priorAnswerWrong);
+
+ /**
+ * Show the dialog
+ */
+ virtual void show();
+};
+
+class PictureDialog : public TextDialog {
+private:
+ int _objectId;
+ bool _cyclingActive;
+ byte _palette[PALETTE_SIZE];
+ uint32 _palFlags[PALETTE_COUNT];
+ RGBList _rgbList;
+protected:
+ virtual void save();
+
+ virtual void restore();
+public:
+ PictureDialog(MADSEngine *vm, const Common::Point &pos, int maxChars, int objectId);
+
+ virtual ~PictureDialog();
+};
+
+enum DialogTextAlign { ALIGN_CENTER = -1, ALIGN_AT_CENTER = -2, ALIGN_RIGHT = -3 };
+
+class ScreenDialog {
+ struct DialogLine {
+ int _state;
+ Common::Point _pos;
+ int _textDisplayIndex;
+ Common::String _msg;
+ Font *_font;
+ int _widthAdjust;
+
+ DialogLine();
+ DialogLine(const Common::String &s);
+ };
+protected:
+ MADSEngine *_vm;
+ MSurface _savedSurface;
+ Common::Array<DialogLine> _lines;
+ int _v1;
+ int _selectedLine;
+ bool _dirFlag;
+ int _screenId;
+ int _menuSpritesIndex;
+ int _lineIndex;
+ bool _enterFlag;
+ int _textLineCount;
+
+ /**
+ * Reset the lines list for the dialog
+ */
+ void clearLines();
+
+ /**
+ * Add a quote to the lines list
+ */
+ void addQuote(int id1, int id2, DialogTextAlign align, const Common::Point &pt, Font *font);
+
+ /**
+ * Adds a line to the lines list
+ */
+ void addLine(const Common::String &msg, DialogTextAlign align, const Common::Point &pt, Font *font);
+
+ /**
+ * Initializes variables
+ */
+ void initVars();
+
+ /**
+ * Sets the display for the screen background behind the dialog
+ */
+ void setFrame(int frameNumber, int depth);
+
+ /**
+ * Choose the background to display for the dialog
+ */
+ void chooseBackground();
+public:
+ /**
+ * Constructor
+ */
+ ScreenDialog(MADSEngine *vm);
+};
+
+class GameMenuDialog : public ScreenDialog {
+private:
+ /**
+ * Add the lines for the Game Menu dialog
+ */
+ void addLines();
+public:
+ GameMenuDialog(MADSEngine *vm);
+
+};
+
+} // End of namespace Nebular
+
+} // End of namespace MADS
+
+#endif /* MADS_DIALOGS_NEBULAR_H */
diff --git a/engines/mads/nebular/game_nebular.cpp b/engines/mads/nebular/game_nebular.cpp
new file mode 100644
index 0000000000..51e06d092c
--- /dev/null
+++ b/engines/mads/nebular/game_nebular.cpp
@@ -0,0 +1,766 @@
+/* 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 "common/config-manager.h"
+#include "mads/mads.h"
+#include "mads/game.h"
+#include "mads/screen.h"
+#include "mads/msurface.h"
+#include "mads/nebular/game_nebular.h"
+#include "mads/nebular/dialogs_nebular.h"
+#include "mads/nebular/globals_nebular.h"
+#include "mads/nebular/nebular_scenes.h"
+
+namespace MADS {
+
+namespace Nebular {
+
+GameNebular::GameNebular(MADSEngine *vm): Game(vm) {
+ _surface = new MSurface(MADS_SCREEN_WIDTH, MADS_SCENE_HEIGHT);
+ _storyMode = STORYMODE_NAUGHTY;
+ _difficulty = DIFFICULTY_EASY;
+}
+
+ProtectionResult GameNebular::checkCopyProtection() {
+ /*
+ // DEBUG: Flag copy protection failure
+ _globals[kCopyProtectFailed] = -1;
+
+ if (!ConfMan.getBool("copy_protection"))
+ return true;
+
+ * DEBUG: Disabled for now
+ CopyProtectionDialog *dlg = new CopyProtectionDialog(_vm, false);
+ dlg->show();
+ delete dlg;
+ */
+
+ // DEBUG: Return that copy protection failed
+ return PROTECTION_SUCCEED;
+}
+
+void GameNebular::initializeGlobals() {
+ int count, count2;
+ int bad;
+
+ _globals.reset();
+ _globals[kTalkInanimateCount] = 8;
+
+ /* Section #1 variables */
+ _globals[kNeedToStandUp] = true;
+ _globals[kTurkeyExploded] = false;
+ _globals[kMedicineCabinetOpen] = false;
+ _globals[kMedicineCabinetVirgin] = true;
+ _globals[kWatchedViewScreen] = false;
+ _globals[kHoovicAlive] = true;
+ _globals[kWaterInAPuddle] = false;
+
+ _globals[kFishIn105] = true;
+ _globals[kFishIn107] = true;
+ _globals[kFishIn108] = true;
+
+ /* Section #2 variables */
+ _globals[kLadderBroken] = false;
+ _globals[kBone202Status] = 0;
+ _globals[kRhotundaStatus] = RHOTUNDA_HUNGRY;
+ _globals[kMonkeyStatus] = MONKEY_AMBUSH_READY;
+ _globals[kMeteorologistStatus] = METEOROLOGIST_PRESENT;
+ _globals[kMeteorologistEverSeen] = false;
+ _globals[kMeteorologistWatch] = METEOROLOGIST_NORMAL;
+ _globals[kTeleporterCommand] = TELEPORTER_NONE;
+ _globals[kTeleporterUnderstood] = false;
+ _globals[kTwinklesStatus] = TWINKLES_AT_HOME;
+ _globals[kTwinklesApproached] = 0;
+
+ /* Section #3 variables */
+ _globals[kAfterHavoc] = false;
+ _globals[kKickedIn391Grate] = false;
+
+ /* Section #4 variables */
+ _globals[kBadFirstIngredient] = -1;
+ _objects[OBJ_CHARGE_CASES].setQuality(EXPLOSIVES_INSIDE, 0);
+ _globals[kHasPurchased] = false;
+ _globals[kBeenThruHelgaScene] = false;
+ _globals[kNextIngredient] = 0;
+ _globals[kHasSaidTimer] = false;
+ _globals[kHasSaidBinocs] = false;
+ _globals[kBottleDisplayed] = false;
+ _globals[kHasBeenScanned] = false;
+ _globals[kSomeoneHasExploded] = false;
+
+ // Generate a random ingredient list
+ for (count = 0; count < 4; ++count) {
+ do {
+ _globals[kIngredientList + count] = _vm->getRandomNumber(3);
+ bad = false;
+ for (count2 = 0; count2 < count; ++count2) {
+ if (_globals[kIngredientList + count] == _globals[kIngredientList + count2]) {
+ bad = true;
+ }
+ }
+ } while (bad);
+ }
+
+ // Generate random ingredient quantities
+ for (count = 0; count < 4; ++count) {
+ do {
+ _globals[kIngredientQuantity + count] = _vm->getRandomNumber(3);
+ bad = false;
+ for (count2 = 0; count2 < count; ++count2) {
+ if (_globals[kIngredientQuantity + count] == _globals[kIngredientQuantity + count2]) {
+ bad = true;
+ }
+ }
+ } while (bad);
+ }
+
+
+ /* Section #5 variables */
+ _globals[kHoverCarLocation] = 501;
+ _globals[kHoverCarDestination] = -1;
+ _globals[kCityFlooded] = false;
+ _globals[kBoatRaised] = true;
+ _globals[kLaserHoleIsThere] = false;
+ _globals[kLineStatus] = LINE_NOT_DROPPED;
+
+
+ /* Section #6 variables */
+ _globals[kHasTalkedToHermit] = false;
+ _globals[kHandsetCellStatus] = FIRST_TIME_PHONE_CELLS;
+ _globals[kTimebombStatus] = TIMEBOMB_DEACTIVATED;
+ _globals[kWarnedFloodCity] = false;
+ _globals._timebombClock = 0;
+ _globals._timebombTimer = 0;
+
+
+ /* Section #7 variables */
+ _globals[kBottleStatus] = BOTTLE_EMPTY;
+ _globals[kBoatStatus] = BOAT_UNFLOODED;
+
+
+ /* Section #8 variables */
+ _globals[kWindowFixed] = false;
+ _globals[kInSpace] = false;
+ _globals[kReturnFromCut] = false;
+ _globals[kBeamIsUp] = false;
+ _globals[kForceBeamDown] = false;
+ _globals[kCameFromCut] = false;
+ _globals[kDontRepeat] = false;
+ _globals[kHoppyDead] = false;
+ _globals[kHasWatchedAntigrav] = false;
+ _globals[kRemoteSequenceRan] = false;
+ _globals[kRemoteOnGround] = false;
+ _globals[kFromCockpit] = false;
+ _globals[kExitShip] = false;
+ _globals[kBetweenRooms] = false;
+ _globals[kTopButtonPushed] = false;
+ _globals[kShieldModInstalled] = false;
+ _globals[kTargetModInstalled] = false;
+ _globals[kUpBecauseOfRemote] = false;
+
+
+ /* Set up the game's teleporters */
+ _globals[kTeleporterRoom] = 201;
+ _globals[kTeleporterRoom + 1] = 301;
+ _globals[kTeleporterRoom + 2] = 413;
+ _globals[kTeleporterRoom + 3] = 706;
+ _globals[kTeleporterRoom + 4] = 801;
+ _globals[kTeleporterRoom + 5] = 551;
+ _globals[kTeleporterRoom + 6] = 752;
+ _globals[kTeleporterRoom + 7] = 0;
+ _globals[kTeleporterRoom + 8] = 0;
+ _globals[kTeleporterRoom + 9] = 0;
+
+ for (count = 0; count < TELEPORTER_COUNT; ++count) {
+ do {
+ _globals[kTeleporterCode + count] = _vm->getRandomNumber(9999);
+ bad = false;
+ for (count2 = 0; count2 < count; ++count2) {
+ if (_globals[kTeleporterCode + count] == _globals[kTeleporterCode + count2]) {
+ bad = true;
+ }
+ }
+ } while (bad);
+ }
+
+ // Final setup based on selected difficulty level
+ switch (_difficulty) {
+ case DIFFICULTY_HARD:
+ _objects.setRoom(OBJ_PLANT_STALK, NOWHERE);
+ _objects.setRoom(OBJ_PENLIGHT, NOWHERE);
+
+ _globals[kLeavesStatus] = LEAVES_ON_TRAP;
+ break;
+
+ case DIFFICULTY_MEDIUM:
+ _objects.setRoom(OBJ_PLANT_STALK, NOWHERE);
+
+ _globals[kLeavesStatus] = LEAVES_ON_GROUND;
+ _globals[kDurafailRecharged] = true;
+ _globals[kPenlightCellStatus] = FIRST_TIME_CHARGED_DURAFAIL;
+ break;
+
+ case DIFFICULTY_EASY:
+ _objects.setRoom(OBJ_BLOWGUN, NOWHERE);
+ _objects.setRoom(OBJ_NOTE, NOWHERE);
+
+ _globals[kLeavesStatus] = LEAVES_ON_GROUND;
+ _globals[kPenlightCellStatus] = FIRST_TIME_UNCHARGED_DURAFAIL;
+ _globals[kDurafailRecharged] = false;
+ break;
+ }
+
+ _player._facing = FACING_NORTH;
+ _player._turnToFacing = FACING_NORTH;
+
+ Player::preloadSequences("RXM", 1);
+ Player::preloadSequences("ROX", 1);
+}
+
+void GameNebular::setSectionHandler() {
+ delete _sectionHandler;
+
+ switch (_sectionNumber) {
+ case 1:
+ _sectionHandler = new Section1Handler(_vm);
+ break;
+ case 2:
+ _sectionHandler = new Section2Handler(_vm);
+ break;
+ case 3:
+ _sectionHandler = new Section3Handler(_vm);
+ break;
+ case 4:
+ _sectionHandler = new Section4Handler(_vm);
+ break;
+ case 5:
+ _sectionHandler = new Section5Handler(_vm);
+ break;
+ case 6:
+ _sectionHandler = new Section6Handler(_vm);
+ break;
+ case 7:
+ _sectionHandler = new Section7Handler(_vm);
+ break;
+ case 8:
+ _sectionHandler = new Section8Handler(_vm);
+ break;
+ default:
+ break;
+ }
+}
+
+void GameNebular::checkShowDialog() {
+ if (_vm->_dialogs->_pendingDialog && _player._stepEnabled && !_globals[kCopyProtectFailed]) {
+ _player.releasePlayerSprites();
+ _vm->_dialogs->showDialog();
+ _vm->_dialogs->_pendingDialog = DIALOG_NONE;
+ }
+}
+
+void GameNebular::doObjectAction() {
+ Scene &scene = _scene;
+ MADSAction &action = _scene._action;
+ Dialogs &dialogs = *_vm->_dialogs;
+ int id;
+
+ if (action.isAction(VERB_SMELL) && scene._currentSceneId > 103 && scene._currentSceneId < 111) {
+ dialogs.show(440);
+ } else if (action.isAction(VERB_EAT) && scene._currentSceneId > 103 && scene._currentSceneId < 111) {
+ dialogs.show(441);
+ } else if (action.isAction(VERB_SMELL, NOUN_BURGER)) {
+ dialogs.show(442);
+ } else if (action.isAction(VERB_EAT, NOUN_BURGER)) {
+ dialogs.show(443);
+ } else if (action.isAction(VERB_SMELL, NOUN_STUFFED_FISH)) {
+ dialogs.show(444);
+ } else if (action.isAction(VERB_EAT, NOUN_STUFFED_FISH)) {
+ dialogs.show(445);
+ } else if (action.isAction(401, 289)) {
+ dialogs.show(scene._currentSceneId > 103 && scene._currentSceneId < 111 ? 446 : 447);
+ } else if (action.isAction(306, 371)) {
+ dialogs.show(448);
+ } else if (action.isAction(951, 35)) {
+ dialogs.show(449);
+ } else if (action.isAction(203, 276)) {
+ dialogs.show(450);
+ } else if (action.isAction(VERB_EAT, 378)) {
+ _objects.setRoom(OBJ_TWINKIFRUIT, PLAYER_INVENTORY);
+ dialogs.show(451);
+ } else if (action.isAction(153, 378)) {
+ _objects.setRoom(OBJ_TWINKIFRUIT, PLAYER_INVENTORY);
+ dialogs.show(452);
+ } else if (action.isAction(152)) {
+ dialogs.show(453);
+ } else if (action.isAction(1187, OBJ_PHONE_CELLS)) {
+ dialogs.show(454);
+ } else if (action.isAction(1188, 92)) {
+ dialogs.show(455);
+ } else if (action.isAction(140, 72)) {
+ dialogs.show(456);
+ } else if (action.isAction(1189, OBJ_VASE)) {
+ dialogs.show(457);
+ } else if (action.isAction(306, 369)) {
+ dialogs.show(458);
+ } else if (action.isAction(1192, 774)) {
+ dialogs.show(459);
+ } else if (action.isAction(1191, 359)) {
+ dialogs.show(460);
+ } else if (action.isAction(1190)) {
+ dialogs.show(461);
+ } else if (action.isAction(934, 277)) {
+ dialogs.show(462);
+ } else if (action.isAction(329, 277)) {
+ dialogs.show(465);
+ } else if (action.isAction(368, 135)) {
+ dialogs.show(463);
+ } else if (action.isAction(25, 135)) {
+ dialogs.show(463);
+ } else if (action.isAction(379)) {
+ dialogs.show(464);
+ } else if (action.isAction(869)) {
+ dialogs.show(466);
+ } else if (action.isAction(530, 288)) {
+ dialogs.show(467);
+ } else if (action.isAction(VERB_EAT, 74)) {
+ dialogs.show(469);
+ } else if (action.isAction(50, 381)) {
+ dialogs.show(471);
+ } else if (action.isAction(307, 950)) {
+ dialogs.show(472);
+ } else if (action.isAction(VERB_READ, NOUN_LOG)) {
+ dialogs.show(473);
+ } else if (action.isAction(1189, 43)) {
+ dialogs.show(474);
+ } else if (action.isAction(114, 726)) {
+ dialogs.show(475);
+ } else if (action.isAction(114, 727)) {
+ dialogs.show(476);
+ } else if (action.isAction(114, 937)) {
+ dialogs.show(477);
+ } else if (action.isAction(VERB_PUT, 276, NOUN_PLANT_STALK) && _objects.isInInventory(OBJ_POISON_DARTS)
+ && _objects.isInInventory(OBJ_PLANT_STALK)) {
+ _objects.addToInventory(OBJ_BLOWGUN);
+ _objects.setRoom(OBJ_PLANT_STALK, NOWHERE);
+ _globals[kBlowgunStatus] = 0;
+ dialogs.showItem(OBJ_BLOWGUN, 809);
+ } else if (action.isAction(VERB_PUT, 276, NOUN_BLOWGUN) && _objects.isInInventory(OBJ_POISON_DARTS)
+ && _objects.isInInventory(OBJ_BLOWGUN)) {
+ dialogs.show(433);
+ } else if (action.isAction(1161) && action.isAction(1195) && action.isAction(1197)) {
+ dialogs.show(434);
+ } else if (action.isAction(1196)) {
+ dialogs.show(479);
+ } else if ((action.isAction(287) || action.isAction(VERB_LOOK_AT) || action.isAction(VERB_LOOK)) &&
+ action.isAction(936) && _objects.isInInventory(OBJ_NOTE)) {
+ _objects.setRoom(OBJ_NOTE, PLAYER_INVENTORY);
+ _objects.addToInventory(OBJ_COMBINATION);
+ dialogs.showItem(OBJ_COMBINATION, 851);
+ } else if ((action.isAction(VERB_LOOK) || action.isAction(VERB_READ)) &&
+ ((id = _objects.getIdFromDesc(action._activeAction._objectNameId)) > 0 ||
+ (action._activeAction._indirectObjectId > 0 &&
+ (id = _objects.getIdFromDesc(action._activeAction._indirectObjectId))))) {
+ if (id == OBJ_REPAIR_LIST) {
+ dialogs._indexList[0] = _globals[kTeleporterCode + 7];
+ dialogs._indexList[1] = _globals[kTeleporterCode + 8];
+ dialogs._indexList[2] = _globals[kTeleporterCode + 6];
+ dialogs._indexList[3] = _globals[kTeleporterCode + 9];
+ dialogs._indexList[4] = _globals[kTeleporterCode + 0];
+ dialogs._indexList[5] = _globals[kTeleporterCode + 1];
+ dialogs._indexList[6] = _globals[kTeleporterCode + 4];
+ dialogs._indexList[7] = _globals[kTeleporterCode + 5];
+ dialogs._indexList[8] = _globals[kTeleporterCode + 2];
+
+ dialogs.showItem(id, 402);
+ } else {
+ int messageId = 800 + id;
+ if ((id == OBJ_CHARGE_CASES) && _objects[OBJ_CHARGE_CASES].getQuality(3) != 0) {
+ messageId = 860;
+ }
+
+ if (id == OBJ_TAPE_PLAYER && _objects[OBJ_AUDIO_TAPE]._roomNumber == OBJ_TAPE_PLAYER)
+ messageId = 867;
+
+ if (id == 32 && _objects[OBJ_FISHING_LINE]._roomNumber == 3)
+ messageId = 862;
+
+ if (id == OBJ_BOTTLE && _globals[kBottleStatus] != 0)
+ messageId = 862 + _globals[kBottleStatus];
+
+ if (id == OBJ_PHONE_HANDSET && _globals[kHandsetCellStatus])
+ messageId = 861;
+
+ dialogs.showItem(id, messageId);
+ }
+ } else if (action.isAction(VERB_PUT, NOUN_BURGER, NOUN_DEAD_FISH)) {
+ if (_objects.isInInventory(OBJ_BURGER) || _objects.isInInventory(OBJ_DEAD_FISH)) {
+ _objects.removeFromInventory(OBJ_DEAD_FISH, PLAYER_INVENTORY);
+ _objects.removeFromInventory(OBJ_BURGER, PLAYER_INVENTORY);
+ _objects.addToInventory(OBJ_STUFFED_FISH);
+ dialogs.showItem(OBJ_STUFFED_FISH, 803);
+ }
+ } else if (action.isAction(VERB_PUT, 26, 357) && _objects.isInInventory(OBJ_AUDIO_TAPE) &&
+ _objects.isInInventory(OBJ_TAPE_PLAYER)) {
+ _objects.setRoom(OBJ_AUDIO_TAPE, 25);
+ } else if (action.isAction(118, 357) && _objects.isInInventory(OBJ_TAPE_PLAYER)) {
+ if (_objects[OBJ_AUDIO_TAPE]._roomNumber == 25) {
+ _objects.addToInventory(OBJ_AUDIO_TAPE);
+ } else {
+ dialogs.show(407);
+ }
+ } else if (action.isAction(108, 357)) {
+ dialogs.show(408);
+ } else if (action.isAction(14, 291)) {
+ dialogs.show(_globals[kTopButtonPushed] ? 502 : 501);
+ } else if ((action.isAction(25, 106, 72) || action.isAction(VERB_PUT, 106, 72)) &&
+ _objects.isInInventory(OBJ_DETONATORS) && _objects.isInInventory(OBJ_CHARGE_CASES)) {
+ if (_objects[OBJ_CHARGE_CASES].getQuality(3)) {
+ _objects.setRoom(OBJ_CHARGE_CASES, 1);
+ _objects.setRoom(OBJ_DETONATORS, 1);
+ _objects.addToInventory(OBJ_BOMBS);
+ dialogs.showItem(OBJ_BOMBS, 403);
+ } else {
+ dialogs.show(405);
+ }
+ } else if (action.isAction(25, 106)) {
+ dialogs.show(470);
+ } else if ((action.isAction(25, 371, 43) || action.isAction(7, 371, 43) || action.isAction(25, 371, 42)
+ || action.isAction(VERB_PUT, 371, 42)) && _objects.isInInventory(OBJ_TIMER_MODULE) && (
+ _objects.isInInventory(OBJ_BOMBS) || _objects.isInInventory(OBJ_BOMB))) {
+ if (_objects.isInInventory(OBJ_BOMBS)) {
+ _objects.setRoom(OBJ_BOMBS, PLAYER_INVENTORY);
+ _objects.addToInventory(OBJ_BOMB);
+ } else {
+ _objects.setRoom(OBJ_BOMB, PLAYER_INVENTORY);
+ }
+
+ _objects.setRoom(OBJ_TIMER_MODULE, PLAYER_INVENTORY);
+ _objects.addToInventory(OBJ_TIMEBOMB);
+ dialogs.showItem(OBJ_TIMEBOMB, 404);
+ } else if (action.isAction(140, 271)) {
+ dialogs.show(410);
+ } else if (action.isAction(119, 46)) {
+ _globals[kBottleStatus] = 0;
+ dialogs.show(432);
+ } else if (action.isAction(108, 136)) {
+ if (_objects[OBJ_FISHING_LINE]._roomNumber == 3) {
+ _objects.addToInventory(OBJ_FISHING_LINE);
+ dialogs.showItem(OBJ_FISHING_LINE, 409);
+ } else {
+ dialogs.show(428);
+ }
+ } else if (action.isAction(108, 262)) {
+ switch (_globals[kPenlightCellStatus]) {
+ case 1:
+ case 2:
+ _objects.addToInventory(OBJ_DURAFAIL_CELLS);
+ dialogs.showItem(OBJ_DURAFAIL_CELLS, 412);
+ break;
+ case 3:
+ _objects.addToInventory(OBJ_PHONE_CELLS);
+ dialogs.showItem(OBJ_DURAFAIL_CELLS, 413);
+ break;
+ case 5:
+ _objects.addToInventory(OBJ_DURAFAIL_CELLS);
+ dialogs.showItem(OBJ_DURAFAIL_CELLS, 411);
+ break;
+ case 6:
+ _objects.addToInventory(OBJ_DURAFAIL_CELLS);
+ dialogs.showItem(OBJ_DURAFAIL_CELLS, 429);
+ break;
+ default:
+ dialogs.show(478);
+ break;
+ }
+ } else if (action.isAction(108, 264)) {
+ switch (_globals[kHandsetCellStatus]) {
+ case 1:
+ _objects.addToInventory(OBJ_DURAFAIL_CELLS);
+ dialogs.showItem(OBJ_DURAFAIL_CELLS,
+ _difficulty != 1 || _globals[kDurafailRecharged] ? 415 : 414);
+ break;
+ case 2:
+ _objects.addToInventory(OBJ_DURAFAIL_CELLS);
+ if (_difficulty == 1) {
+ dialogs.showItem(OBJ_DURAFAIL_CELLS, 416);
+ } else {
+ _globals[kHandsetCellStatus] = 0;
+ }
+ break;
+ case 3:
+ _objects.addToInventory(OBJ_PHONE_CELLS);
+ dialogs.showItem(OBJ_PHONE_CELLS, 418);
+ break;
+ case 4:
+ _objects.addToInventory(OBJ_PHONE_CELLS);
+ dialogs.showItem(OBJ_PHONE_CELLS, 417);
+ break;
+ default:
+ dialogs.show(478);
+ break;
+ }
+ } else if (action.isAction(VERB_PUT, 263, 262)) {
+ if (_globals[kPenlightCellStatus] == 0) {
+ _globals[kPenlightCellStatus] = 3;
+ _objects.setRoom(OBJ_PHONE_CELLS, PLAYER_INVENTORY);
+ dialogs.show(419);
+ } else {
+ dialogs.show(420);
+ }
+ } else if (action.isAction(VERB_PUT, 263, 264)) {
+ if (_globals[kHandsetCellStatus] == 0) {
+ _globals[kHandsetCellStatus] = 3;
+ _objects.setRoom(OBJ_PHONE_CELLS, PLAYER_INVENTORY);
+ dialogs.show(421);
+ } else {
+ dialogs.show(422);
+ }
+ } else if (action.isAction(VERB_PUT, 115, 262)) {
+ if (_globals[kPenlightCellStatus]) {
+ dialogs.show(424);
+ } else {
+ _objects.setRoom(OBJ_DURAFAIL_CELLS, PLAYER_INVENTORY);
+ _globals[kPenlightCellStatus] = _difficulty != 1 || _globals[kDurafailRecharged] ? 1 : 2;
+ dialogs.show(423);
+ }
+ } else if (action.isAction(VERB_PUT, 115, 264)) {
+ if (_globals[kHandsetCellStatus]) {
+ dialogs.show(424);
+ } else {
+ _objects.setRoom(OBJ_DURAFAIL_CELLS, PLAYER_INVENTORY);
+ _globals[kDurafailRecharged] = _difficulty != 1 || _globals[kHandsetCellStatus] ? 1 : 2;
+ dialogs.show(425);
+ }
+ } else if (action.isAction(306, 369)) {
+ dialogs.show(427);
+ } else if (action.isAction(VERB_PUT, 42, 73) || action.isAction(VERB_PUT, 43, 73)) {
+ _objects.setRoom(OBJ_CHICKEN, PLAYER_INVENTORY);
+ if (_objects.isInInventory(OBJ_BOMBS)) {
+ _objects.setRoom(OBJ_BOMBS, PLAYER_INVENTORY);
+ _objects.addToInventory(OBJ_BOMB);
+ } else {
+ _objects.setRoom(OBJ_BOMB, PLAYER_INVENTORY);
+ }
+
+ _objects.addToInventory(OBJ_CHICKEN_BOMB);
+ dialogs.showItem(OBJ_CHICKEN_BOMB, 430);
+ } else {
+ return;
+ }
+
+ action._inProgress = false;
+}
+
+void GameNebular::unhandledAction() {
+ int randVal = _vm->getRandomNumber(1, 1000);
+ MADSAction &action = _scene._action;
+
+ if (action.isAction(VERB_THROW, NOUN_BOMB) || action.isAction(VERB_THROW, NOUN_BOMBS)
+ || action.isAction(VERB_THROW, NOUN_TIMEBOMB) || action.isAction(VERB_THROW, NOUN_CHICKEN_BOMB))
+ _vm->_dialogs->show(42);
+ else if (action.isAction(0x6C))
+ _vm->_dialogs->show(435);
+ else if ((action.isAction(VERB_EAT, NOUN_DEAD_FISH) || action.isAction(VERB_EAT, NOUN_STUFFED_FISH)) && _vm->_game->_objects.isInInventory(_vm->_game->_objects.getIdFromDesc(action._activeAction._objectNameId)))
+ _vm->_dialogs->show(12);
+ else if ((action.isAction(VERB_SMELL, NOUN_DEAD_FISH) || action.isAction(VERB_SMELL, NOUN_STUFFED_FISH)) && _vm->_game->_objects.isInInventory(_vm->_game->_objects.getIdFromDesc(action._activeAction._objectNameId)))
+ _vm->_dialogs->show(13);
+ else if (action.isAction(VERB_EAT, NOUN_CHICKEN) && _vm->_game->_objects.isInInventory(OBJ_CHICKEN))
+ _vm->_dialogs->show(912);
+ else if ((action.isAction(VERB_SHOOT) || action.isAction(VERB_HOSE_DOWN)) && action.isObject(NOUN_BLOWGUN)) {
+ if ((_scene._currentSceneId >= 104) && (_scene._currentSceneId <= 111))
+ _vm->_dialogs->show(38);
+ else if (action.isAction(0x10D))
+ _vm->_dialogs->show(41);
+ else if (action.isObject(NOUN_CHICKEN) || action.isAction(0x185) || action.isAction(0x14D)
+ || action.isAction(0x1DD) || action.isAction(0x15F) || action.isObject(NOUN_CAPTIVE_CREATURE)) {
+ _vm->_dialogs->show(40);
+ } else
+ _vm->_dialogs->show(39);
+ } else if (action.isAction(VERB_TALKTO)) {
+ _globals[kTalkInanimateCount] = (_globals[kTalkInanimateCount] + 1) % 16;
+ if (!_globals[kTalkInanimateCount]) {
+ _vm->_dialogs->show(2);
+ } else {
+ Common::String tmpMsg = "\"Greetings, ";
+ tmpMsg += _vm->_game->_scene.getVocab(action._activeAction._objectNameId);
+ tmpMsg += "!\"";
+ _scene._kernelMessages.reset();
+ _scene._kernelMessages.add(Common::Point(0, 0), 0x1110, 34, 0, 120, tmpMsg);
+ }
+ } else if (action.isAction(VERB_GIVE, NOUN_DOOR, 0x46) || action.isAction(VERB_CLOSE, NOUN_CHAIR))
+ _vm->_dialogs->show(3);
+ else if (action.isAction(VERB_THROW)) {
+ int objId = _vm->_game->_objects.getIdFromDesc(action._activeAction._objectNameId);
+ if (objId < 0)
+ _vm->_dialogs->show(4);
+ else if (_vm->_game->_objects[objId]._roomNumber != 2)
+ _vm->_dialogs->show(5);
+ else
+ _vm->_dialogs->show(6);
+ } else if (action.isAction(VERB_LOOK)) {
+ if (action.isAction(0x27) && (action._activeAction._indirectObjectId > 0))
+ _vm->_dialogs->show(10);
+ else if (randVal < 600)
+ _vm->_dialogs->show(7);
+ else
+ _vm->_dialogs->show(21);
+ } else if (action.isAction(VERB_TAKE)) {
+ int objId = _vm->_game->_objects.getIdFromDesc(action._activeAction._objectNameId);
+ if (_vm->_game->_objects.isInInventory(objId))
+ _vm->_dialogs->show(16);
+ else if (randVal <= 333)
+ _vm->_dialogs->show(8);
+ else if (randVal <= 666)
+ _vm->_dialogs->show(22);
+ else
+ _vm->_dialogs->show(23);
+ } else if (action.isAction(VERB_CLOSE)) {
+ if (randVal <= 333)
+ _vm->_dialogs->show(9);
+ else
+ _vm->_dialogs->show(33);
+ } else if (action.isAction(VERB_OPEN)) {
+ if (randVal <= 500)
+ _vm->_dialogs->show(30);
+ else if (randVal <= 750)
+ _vm->_dialogs->show(31);
+ else
+ _vm->_dialogs->show(32);
+ } else if (action.isAction(VERB_PULL))
+ _vm->_dialogs->show(18);
+ else if (action.isAction(VERB_PUSH)) {
+ if (randVal < 750)
+ _vm->_dialogs->show(19);
+ else
+ _vm->_dialogs->show(20);
+ } else if (action.isAction(VERB_PUT)) {
+ int objId = _vm->_game->_objects.getIdFromDesc(action._activeAction._objectNameId);
+ if (_vm->_game->_objects.isInInventory(objId))
+ _vm->_dialogs->show(25);
+ else
+ _vm->_dialogs->show(24);
+ } else if (action.isAction(VERB_GIVE)) {
+ int objId = _vm->_game->_objects.getIdFromDesc(action._activeAction._objectNameId);
+ if (!_vm->_game->_objects.isInInventory(objId))
+ _vm->_dialogs->show(26);
+ else if (randVal <= 500)
+ _vm->_dialogs->show(28);
+ else
+ _vm->_dialogs->show(29);
+ } else if (!action.isAction(VERB_WALKTO) && !action.isAction(0x187) && !action.isAction(0x18C) && !action.isAction(0x1AD)
+ && !action.isAction(0x15C) && !action.isAction(0x159) && !action.isAction(0x15A) && !action.isAction(0x15B)
+ && !action.isAction(0x15E)) {
+ if (randVal <= 100)
+ _vm->_dialogs->show(36);
+ else if (randVal <= 200)
+ _vm->_dialogs->show(1);
+ else if (randVal <= 475)
+ _vm->_dialogs->show(34);
+ else if (randVal <= 750)
+ _vm->_dialogs->show(35);
+ else
+ _vm->_dialogs->show(37);
+ }
+}
+
+void GameNebular::step() {
+ if (_player._visible && _player._stepEnabled && !_player._moving &&
+ (_player._facing == _player._turnToFacing)) {
+ if (_scene._frameStartTime >= *((uint32 *)&_globals[kWalkerTiming])) {
+ if (!_player._stopWalkerIndex) {
+ int randomVal = _vm->getRandomNumber(29999);;
+ if (_globals[kSexOfRex] == REX_MALE) {
+ switch (_player._facing) {
+ case FACING_SOUTHWEST:
+ case FACING_SOUTHEAST:
+ case FACING_NORTHWEST:
+ case FACING_NORTHEAST:
+ if (randomVal < 200) {
+ _player.addWalker(-1, 0);
+ _player.addWalker(1, 0);
+ }
+ break;
+
+ case FACING_WEST:
+ case FACING_EAST:
+ if (randomVal < 500) {
+ for (int count = 0; count < 10; ++count) {
+ _player.addWalker(1, 0);
+ }
+ }
+ break;
+
+ case FACING_SOUTH:
+ if (randomVal < 500) {
+ for (int count = 0; count < 10; ++count) {
+ _player.addWalker((randomVal < 250) ? 1 : 2, 0);
+ }
+ } else if (randomVal < 750) {
+ for (int count = 0; count < 5; ++count) {
+ _player.addWalker(1, 0);
+ }
+
+ _player.addWalker(0, 0);
+ _player.addWalker(0, 0);
+
+ for (int count = 0; count < 5; ++count) {
+ _player.addWalker(2, 0);
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+
+ *((uint32 *)&_globals[kWalkerTiming]) += 6;
+ }
+ }
+
+ // Below is countdown to set the timebomb off in room 604
+ if (_globals[kTimebombStatus] == TIMEBOMB_ACTIVATED) {
+ int diff = _scene._frameStartTime - *((uint32 *)&_globals[kTimebombClock]);
+ if ((diff >= 0) && (diff <= 60)) {
+ *((uint32 *)&_globals[kTimebombTimer]) += diff;
+ } else {
+ ++*((uint32 *)&_globals[kTimebombTimer]);
+ }
+ *((uint32 *)&_globals[kTimebombClock]) = _scene._frameStartTime;
+ }
+}
+
+void GameNebular::synchronize(Common::Serializer &s, bool phase1) {
+ Game::synchronize(s, phase1);
+
+ if (phase1) {
+ _globals.synchronize(s);
+ s.syncAsByte(_storyMode);
+ s.syncAsByte(_difficulty);
+ }
+}
+
+} // End of namespace Nebular
+
+} // End of namespace MADS
diff --git a/engines/mads/nebular/game_nebular.h b/engines/mads/nebular/game_nebular.h
new file mode 100644
index 0000000000..da252219f4
--- /dev/null
+++ b/engines/mads/nebular/game_nebular.h
@@ -0,0 +1,151 @@
+/* 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.
+ *
+ */
+
+#ifndef MADS_GAME_NEBULAR_H
+#define MADS_GAME_NEBULAR_H
+
+#include "common/scummsys.h"
+#include "mads/game.h"
+#include "mads/globals.h"
+#include "mads/nebular/globals_nebular.h"
+
+namespace MADS {
+
+namespace Nebular {
+
+enum StoryMode { STORYMODE_NAUGHTY = 1, STORYMODE_NICE = 2 };
+
+enum Difficulty {
+ DIFFICULTY_HARD = 1, DIFFICULTY_MEDIUM = 2, DIFFICULTY_EASY = 3
+};
+
+enum InventoryObject {
+ OBJ_NONE = -1,
+ OBJ_BINOCULARS = 0,
+ OBJ_BURGER = 1,
+ OBJ_DEAD_FISH = 2,
+ OBJ_STUFFED_FISH = 3,
+ OBJ_REBREATHER = 4,
+ OBJ_TIMER_MODULE = 5,
+ OBJ_BIG_LEAVES = 6,
+ OBJ_POISON_DARTS = 7,
+ OBJ_PLANT_STALK = 8,
+ OBJ_BLOWGUN = 9,
+ OBJ_TWINKIFRUIT = 10,
+ OBJ_BONE = 11,
+ OBJ_CHICKEN = 12,
+ OBJ_SCALPEL = 13,
+ OBJ_AUDIO_TAPE = 14,
+ OBJ_CREDIT_CHIP = 15,
+ OBJ_SECURITY_CARD = 16,
+ OBJ_CHARGE_CASES = 17,
+ OBJ_ESTROTOXIN = 18,
+ OBJ_BOMB = 19,
+ OBJ_TIMEBOMB = 20,
+ OBJ_REPAIR_LIST = 21,
+ OBJ_ALIEN_LIQUOR = 22,
+ OBJ_TARGET_MODULE = 23,
+ OBJ_SHIELD_MODULATOR = 24,
+ OBJ_TAPE_PLAYER = 25,
+ OBJ_PHONE_CELLS = 26,
+ OBJ_PENLIGHT = 27,
+ OBJ_DURAFAIL_CELLS = 28,
+ OBJ_FAKE_ID = 29,
+ OBJ_ID_CARD = 30,
+ OBJ_POLYCEMENT = 31,
+ OBJ_FISHING_ROD = 32,
+ OBJ_FISHING_LINE = 33,
+ OBJ_PADLOCK_KEY = 34,
+ OBJ_DOOR_KEY = 35,
+ OBJ_REARVIEW_MIRROR = 36,
+ OBJ_COMPACT_CASE = 37,
+ OBJ_DETONATORS = 39,
+ OBJ_BOTTLE = 40,
+ OBJ_CHICKEN_BOMB = 41,
+ OBJ_VASE = 42,
+ OBJ_REMOTE = 43,
+ OBJ_COMPUTER_GAME = 44,
+ OBJ_PHONE_HANDSET = 45,
+ OBJ_BONES = 46,
+ OBJ_GUARDS_ARM = 47,
+ OBJ_LOG = 48,
+ OBJ_BOMBS = 49,
+ OBJ_NOTE = 50,
+ OBJ_COMBINATION = 51,
+ OBJ_FORMALDEHYDE = 52,
+ OBJ_PETROX = 53,
+ OBJ_LECITHIN = 54
+};
+
+class GameNebular: public Game {
+ friend class Game;
+protected:
+ GameNebular(MADSEngine *vm);
+
+ virtual ProtectionResult checkCopyProtection();
+
+ virtual void initializeGlobals();
+
+ virtual void setSectionHandler();
+
+ virtual void checkShowDialog();
+public:
+ NebularGlobals _globals;
+ StoryMode _storyMode;
+ Difficulty _difficulty;
+
+ virtual Globals &globals() { return _globals; }
+
+ virtual void doObjectAction();
+
+ virtual void unhandledAction();
+
+ virtual void step();
+
+ virtual void synchronize(Common::Serializer &s, bool phase1);
+};
+
+
+class Section1Handler: public SectionHandler {
+public:
+ Section1Handler(MADSEngine *vm): SectionHandler(vm) {}
+
+ // TODO: Properly implement handler methods
+ virtual void preLoadSection() {}
+ virtual void sectionPtr2() {}
+ virtual void postLoadSection() {}
+};
+
+// TODO: Properly implement handler classes
+typedef Section1Handler Section2Handler;
+typedef Section1Handler Section3Handler;
+typedef Section1Handler Section4Handler;
+typedef Section1Handler Section5Handler;
+typedef Section1Handler Section6Handler;
+typedef Section1Handler Section7Handler;
+typedef Section1Handler Section8Handler;
+
+} // End of namespace Nebular
+
+} // End of namespace MADS
+
+#endif /* MADS_GAME_NEBULAR_H */
diff --git a/engines/mads/nebular/globals_nebular.cpp b/engines/mads/nebular/globals_nebular.cpp
new file mode 100644
index 0000000000..7bb89a570c
--- /dev/null
+++ b/engines/mads/nebular/globals_nebular.cpp
@@ -0,0 +1,54 @@
+/* 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 "common/config-manager.h"
+#include "mads/nebular/globals_nebular.h"
+
+namespace MADS {
+
+namespace Nebular {
+
+NebularGlobals::NebularGlobals(): Globals() {
+ // Initialize lists
+ resize(210);
+ _spriteIndexes.resize(30);
+ _sequenceIndexes.resize(30);
+
+ // Initialize game flags
+ _timebombClock = 0;
+ _timebombTimer = 0;
+}
+
+void NebularGlobals::synchronize(Common::Serializer &s) {
+ Globals::synchronize(s);
+
+ s.syncAsUint32LE(_timebombClock);
+ s.syncAsUint32LE(_timebombTimer);
+ _spriteIndexes.synchronize(s);
+ _sequenceIndexes.synchronize(s);
+}
+
+
+} // End of namespace Nebular
+
+} // End of namespace MADS
diff --git a/engines/mads/nebular/globals_nebular.h b/engines/mads/nebular/globals_nebular.h
new file mode 100644
index 0000000000..980e6ea1eb
--- /dev/null
+++ b/engines/mads/nebular/globals_nebular.h
@@ -0,0 +1,305 @@
+/* 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.
+ *
+ */
+
+#ifndef MADS_GLOBALS_NEBULAR_H
+#define MADS_GLOBALS_NEBULAR_H
+
+#include "common/scummsys.h"
+#include "common/array.h"
+#include "mads/game.h"
+#include "mads/resources.h"
+
+namespace MADS {
+
+namespace Nebular {
+
+enum GlobalId {
+ kSexOfRex = 0,
+ kOldSexOfRex = 1,
+ kWalkerTiming = 2,
+// kWalkerTiming0 = 3,
+ kTalkInanimateCount = 4,
+ kCopyProtectFailed = 5,
+
+ /* Section #1 variables */
+ kNeedToStandUp = 10,
+ kTurkeyExploded = 11,
+ kMedicineCabinetOpen = 12,
+ kMedicineCabinetVirgin = 13,
+ kWatchedViewScreen = 14,
+ kHoovicAlive = 15,
+ kHoovicSated = 16,
+ kHoovicFishEaten = 17,
+ kWaterInAPuddle = 18,
+ kFishIn105 = 19,
+ kFishIn107 = 20,
+ kFishIn108 = 21,
+ kRandomNumber = 29,
+
+ /* Section #2 variables */
+ kCurtainOpen = 30,
+ kLadderBroken = 31,
+ kBone202Status = 32,
+ kMeteorologistStatus = 33,
+ kRhotundaStatus = 34,
+ kLeavesStatus = 35,
+ kMonkeyStatus = 36,
+ kMeteorologistEverSeen = 37,
+ kMeteorologistWatch = 38,
+ kTeleporterCommand = 39,
+
+ kTeleporterDestination = 40,
+ kTeleporterUnderstood = 41,
+ kConv205 = 42,
+ kChickenPermitted = 43,
+ kTwinklesStatus = 44,
+ kTwinklesApproached = 45,
+ kConvTwinkles1 = 46,
+ kConvTwinkles2 = 47,
+ kConvTwinkles3 = 48,
+ kConvTwinkles5 = 49,
+
+ kConvTwinkles6 = 50,
+ kConvTwinkles7 = 51,
+ kConvTwinkles8 = 52,
+ kBlowgunStatus = 53,
+
+ /* Section #3 Variables */
+ kAfterHavoc = 60,
+ kHaveYourStuff = 61,
+ kRightView320 = 62,
+ kConvBuddy1 = 63,
+ kConvBuddy2 = 64,
+ kMetBuddyBeast = 65,
+ kKnowsBuddyBeast = 66,
+ kConvSlache1 = 67,
+ kConvSlache2 = 68,
+ kConvSlache3 = 69,
+
+ kRexHasMetSlache = 70,
+ kConvIntern = 71,
+ kHasSeenProfPyro = 72,
+ kKickedIn391Grate = 73,
+
+ /* Section #4 Variables */
+ kArmoryDoorOpen = 80,
+ kStorageDoorOpen = 81,
+ kNextIngredient = 82,
+ kIngredientList = 83,
+ kIngredientList1 = 84,
+ kIngredientList2 = 85,
+ kIngredientList3 = 86,
+ kIngredientQuantity = 87,
+ kIngredientQuantity1 = 88,
+ kIngredientQuantity2 = 89,
+
+ kIngredientQuantity3 = 90,
+ kconvPyro_1 = 91,
+ kconvPyro_2 = 92,
+ kconvPyro_3 = 93,
+ kconvPyro_4 = 94,
+ kBadFirstIngredient = 95,
+ kConvBartender1 = 96,
+ kConvBartender2 = 97,
+ kConvBartender3 = 98,
+ kConvBartender4 = 99,
+
+ kHasPurchased = 100,
+ kBeenThruHelgaScene = 101,
+ kHasSaidBinocs = 102,
+ kHasSaidTimer = 103,
+ kBottleDisplayed = 104,
+ kHasBeenScanned = 105,
+ kSomeoneHasExploded = 106,
+
+ /* Section #5 Variables */
+ kBoatRaised = 110,
+ kCarStatus = 111,
+ kCityFlooded = 112,
+ kLaserOn = 113,
+ kLaserHoleIsThere = 114,
+ kCarIsGone = 115,
+ kRegisterOpen = 116,
+ kSafeStatus = 117,
+ kDogStatus = 118,
+ kLineStatus = 119,
+
+ kHoverCarLocation = 120,
+ kHoverCarDestination = 121,
+
+ /* Section #6 Variables */
+ kConvHermit1 = 130,
+ kconvHermit2 = 131,
+ kHasTalkedToHermit = 132,
+ kExecuted_1_11 = 133,
+ kHandsetCellStatus = 134,
+ kBeenInVideoStore = 135,
+ kDurafailRecharged = 136,
+ kPenlightCellStatus = 137,
+ kTimebombStatus = 138,
+ kCheckDaemonTimebomb = 140,
+
+ kResurrectRoom = 141,
+
+ /* Section #6 Time-Bomb Variables */
+ kTimebombClock = 142,
+// kTimebombClock0 = 143,
+ kTimebombTimer = 144,
+// kTimebombTimer0 = 145,
+ kWarnedFloodCity = 146,
+
+ /* Section #7 Variables */
+ kBottleStatus = 150,
+ kMonsterAlive = 151,
+ kConvBottleFillNode = 152,
+ kBoatStatus = 153,
+
+ /* Section #8 Variables */
+ kAntigravClock = 160,
+// kAntigravClock0 = 161,
+ kAntigravTiming = 162,
+// kAntigravTiming0 = 163,
+ kWindowFixed = 164,
+ kInSpace = 165,
+ kReturnFromCut = 166,
+ kBeamIsUp = 167,
+ kForceBeamDown = 168,
+ kCameFromCut = 169,
+
+ kCutX = 170,
+ kCutY = 171,
+ kCutFacing = 172,
+ kDontRepeat = 173,
+ kHoppyDead = 174,
+ kHasWatchedAntigrav = 175,
+ kRemoteSequenceRan = 176,
+ kRemoteOnGround = 177,
+ kFromCockpit = 178,
+ kExitShip = 179,
+
+ kBetweenRooms = 180,
+ kTopButtonPushed = 181,
+ kTargetModInstalled = 182,
+ kShieldModInstalled = 183,
+ kUpBecauseOfRemote = 184,
+
+ kTeleporterRoom = 190,
+ kTeleporterCode = 200
+};
+
+/* Enums used for specific individual globals */
+/* Section #1 */
+// Rex's sex/swimming state
+enum { REX_MALE = 0, REX_MALE_SWIMMER = 1, REX_FEMALE = 2 };
+// State of Meteorologist in the outpost
+enum { METEOROLOGIST_ABSENT = 0, METEOROLOGIST_PRESENT = 1, METEOROLOGIST_GONE = 2 };
+
+// State of watching the Meteorologist
+enum { METEOROLOGIST_NORMAL = 0, METEOROLOGIST_GROUND = 1, METEOROLOGIST_TOWER = 2 };
+
+// The fat bouncy lady that can squish you on the plains
+enum { RHOTUNDA_HUNGRY = 0, RHOTUNDA_STUCK = 1, RHOTUNDA_GONE = 2 };
+
+// Flags for the bones you can take
+enum { BONE_202_LEFT_GONE = 1, BONE_202_RIGHT_GONE = 2 };
+
+// Leaves used to cover the trap
+enum { LEAVES_ON_GROUND = 0, LEAVES_WITH_PLAYER = 1, LEAVES_ON_TRAP = 2 };
+
+// Monkey ambush state
+enum { MONKEY_AMBUSH_READY = 0, MONKEY_HAS_BINOCULARS = 1, MONKEY_IS_GONE = 2 };
+
+// Teleporter status flags
+enum {
+ TELEPORTER_NONE = 0, TELEPORTER_BEAM_IN = 1, TELEPORTER_BEAM_OUT = 2,
+ TELEPORTER_STEP_OUT = 3, TELEPORTER_WRONG = 4
+};
+
+// TWinkies status
+enum { TWINKLES_AT_HOME = 0, TWINKLES_GONE = 1 };
+
+/* Section #4 */
+// Status of the explosives
+enum { EXPLOSIVES_INSIDE = 3 };
+
+/* Section # 5 */
+enum { LINE_NOT_DROPPED = 1, LINE_DROPPED = 2, LINE_TIED = 3, LINE_NOW_UNTIED = 4 };
+
+/* Section #6 */
+enum {
+ NO_CELLS = 0, // Handset doesn't contain any cells
+ CHARGED_DURAFAIL = 1, // Handset has charged durafail cells
+ UNCHARGED_DURAFAIL = 2, // Handset has uncharged durafail cells */
+ PHONE_CELLS = 3, // Handset has already charged phone cells
+ FIRST_TIME_PHONE_CELLS = 4, // First time phone cells are in the handset
+ FIRST_TIME_UNCHARGED_DURAFAIL = 5, // First time uncharged cells are in penlight
+ FIRST_TIME_CHARGED_DURAFAIL = 6 // First time charged cells are in penlight
+};
+
+// Time bomb status
+enum {
+ TIMEBOMB_DEACTIVATED = 0, TIMEBOMB_ACTIVATED = 1,
+ TIMEBOMB_BLOW_UP = 2, TIMEBOMB_DEAD = 3
+};
+
+/* Section #7 */
+// Status of the the bottle
+enum {
+ BOTTLE_EMPTY = 0, BOTTLE_ONE_QUARTER_FULL = 1, BOTTLE_HALF_FULL = 2,
+ BOTTLE_THREE_QUARTERS_FULL = 3, BOTTLE_FULL = 4
+};
+
+// Status of the boat
+enum {
+ BOAT_UNFLOODED = 0, BOAT_ADRIFT = 1, BOAT_TIED_FLOATING = 2,
+ BOAT_TIED = 3, BOAT_GONE = 4
+};
+
+
+/* Miscellaneous defines */
+#define TELEPORTER_COUNT 10 // Total number of teleporters
+#define TELEPORTER_WORK_COUNT 6 // Total number that actually work
+
+
+class NebularGlobals: public Globals {
+public:
+ SynchronizedList _spriteIndexes;
+ SynchronizedList _sequenceIndexes;
+
+ int _timebombClock, _timebombTimer;
+public:
+ /**
+ * Constructor
+ */
+ NebularGlobals();
+
+ /**
+ * Synchronize the globals data
+ */
+ virtual void synchronize(Common::Serializer &s);
+};
+
+} // End of namespace Nebular
+
+} // End of namespace MADS
+
+#endif /* MADS_GLOBALS_NEBULAR_H */
diff --git a/engines/mads/nebular/nebular_scenes.cpp b/engines/mads/nebular/nebular_scenes.cpp
new file mode 100644
index 0000000000..cbfc055b6f
--- /dev/null
+++ b/engines/mads/nebular/nebular_scenes.cpp
@@ -0,0 +1,615 @@
+/* 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 "common/config-manager.h"
+#include "mads/mads.h"
+#include "mads/compression.h"
+#include "mads/resources.h"
+#include "mads/scene.h"
+#include "mads/nebular/game_nebular.h"
+#include "mads/nebular/nebular_scenes.h"
+#include "mads/nebular/nebular_scenes1.h"
+#include "mads/nebular/nebular_scenes2.h"
+#include "mads/nebular/nebular_scenes3.h"
+#include "mads/nebular/nebular_scenes4.h"
+#include "mads/nebular/nebular_scenes5.h"
+#include "mads/nebular/nebular_scenes6.h"
+#include "mads/nebular/nebular_scenes7.h"
+#include "mads/nebular/nebular_scenes8.h"
+
+namespace MADS {
+
+namespace Nebular {
+
+SceneLogic *SceneFactory::createScene(MADSEngine *vm) {
+ Scene &scene = vm->_game->_scene;
+
+ scene.addActiveVocab(NOUN_DROP);
+ scene.addActiveVocab(NOUN_DOLLOP);
+ scene.addActiveVocab(NOUN_DASH);
+ scene.addActiveVocab(NOUN_SPLASH);
+ scene.addActiveVocab(NOUN_ALCOHOL);
+
+ switch (scene._nextSceneId) {
+ // Scene group #1 (ship, ocean, cave)
+ case 101: // Ship, cockpit
+ return new Scene101(vm);
+ case 102: // Ship, dining room
+ return new Scene102(vm);
+ case 103: // Ship, engine room
+ return new Scene103(vm);
+ case 104: // Ocean, northwest cliff
+ return new Scene104(vm);
+ case 105: // Ocean, northeast cliff with mine
+ return new Scene105(vm);
+ case 106: // Ocean, outside ship
+ return new Scene106(vm);
+ case 107: // Ocean, bushes
+ return new Scene107(vm);
+ case 108: // Ocean, southwest cliff
+ return new Scene108(vm);
+ case 109: // Ocean, tunnel
+ return new Scene109(vm);
+ case 110: // Ocean, cave with tunnel
+ return new Scene110(vm);
+ case 111: // Cave with pool and opening
+ return new Scene111(vm);
+ case 112: // cutscene, looking at view screen
+ return new Scene112(vm);
+
+ // Scene group #2 (island)
+ case 201: // outside teleporter
+ return new Scene201(vm);
+ case 202: // village
+ return new Scene202(vm);
+ case 203: // tree with Rhotunda (fat woman)
+ return new Scene203(vm);
+ case 205: // village
+ return new Scene205(vm);
+ case 207: // outside witch doctor's hut
+ return new Scene207(vm);
+ case 208: // pit with leaves (trap)
+ return new Scene208(vm);
+ case 209: // palm tree and bamboo plant
+ return new Scene209(vm);
+ case 210: // outside native woman's hut
+ return new Scene210(vm);
+ case 211: // palm tree with monkey
+ return new Scene211(vm);
+ case 212: // outside cave
+ return new Scene212(vm);
+ case 213: // inside teleporter
+ return new Scene213(vm);
+ case 214: // inside witch doctor's hut
+ return new Scene214(vm);
+ case 215: // inside native woman's hut
+ return new Scene215(vm);
+ case 216: // cutscene, monitor showing Rex and native woman
+ return new Scene216(vm);
+
+ // Scene group #3 (women's base, cell block)
+ case 301: // outside teleporter (before chaos)
+ return new Scene301(vm);
+ case 302: // room with statue (before chaos)
+ return new Scene302(vm);
+ case 303: // western corridor (before chaos)
+ return new Scene303(vm);
+ case 304: // crossing with traffic light (before chaos)
+ return new Scene304(vm);
+ case 307: // Rex's cell (before chaos)
+ return new Scene307(vm);
+ case 308: // sauropod's cell (before chaos)
+ return new Scene308(vm);
+ case 309: // multihand monster's cell (before chaos)
+ return new Scene309(vm);
+ case 310: // empty cell (before chaos)
+ return new Scene310(vm);
+ case 311: // warden's desk (before chaos)
+ return new Scene311(vm);
+ case 313: // air shaft overview
+ return new Scene313(vm);
+ case 316: // Gender Bender
+ return new Scene316(vm);
+ case 318: // doctor's gurney
+ return new Scene318(vm);
+ case 319: // doctor Slache closeup (lying on the gurney)
+ return new Scene319(vm);
+ case 320: // warden's desk closeup / monitors
+ return new Scene320(vm);
+ case 321: // gender bender sex change sequence
+ return new Scene321(vm);
+ case 322: // inside teleporter
+ return new Scene322(vm);
+ case 351: // outside teleporter (after chaos)
+ return new Scene351(vm);
+ case 352: // room with statue (after chaos)
+ return new Scene352(vm);
+ case 353: // western corridor (after chaos)
+ return new Scene353(vm);
+ case 354: // crossing with traffic light (after chaos)
+ return new Scene354(vm);
+ case 357: // Rex's cell (after chaos)
+ return new Scene357(vm);
+ case 358: // sauropod's cell (after chaos)
+ return new Scene358(vm);
+ case 359: // multihand monster's cell (after chaos)
+ return new Scene359(vm);
+ case 360: // empty cell (after chaos)
+ return new Scene360(vm);
+ case 361: // warden's desk (after chaos)
+ return new Scene361(vm);
+ case 366: // air shaft ending at Gender Bender
+ return new Scene366(vm);
+ case 387: // air shaft ending at cell
+ return new Scene387(vm);
+ case 388: // air shaft ending at sauropod's cell
+ return new Scene388(vm);
+ case 389: // air shaft ending at multihand monster's cell (before chaos)
+ return new Scene389(vm);
+ case 390: // air shaft ending at cell
+ return new Scene390(vm);
+ case 391: // air shaft ending at warden's desk
+ return new Scene391(vm);
+ case 399: // air shaft ending at multihand monster's cell (after chaos)
+ return new Scene399(vm);
+
+ // Scene group #4 (women's base)
+ case 401: // outside bar
+ return new Scene401(vm);
+ case 402: // inside bar
+ return new Scene402(vm);
+ case 405: // outside armory
+ return new Scene405(vm);
+ case 406: // outside storage room
+ return new Scene406(vm);
+ case 407: // eastern corridor
+ return new Scene407(vm);
+ case 408: // inside armory
+ return new Scene408(vm);
+ case 409: // inside female only teleporter
+ return new Scene409(vm);
+ case 410: // inside storage room
+ return new Scene410(vm);
+ case 411: // lab
+ return new Scene411(vm);
+ case 413: // outside female only teleporter
+ return new Scene413(vm);
+
+ // Scene group #5 (men's city, lower floor)
+ case 501: // outside car
+ return new Scene501(vm);
+ case 502: // inside male only teleporter
+ return new Scene502(vm);
+ case 503: // guard tower
+ return new Scene503(vm);
+ case 504: // inside car
+ return new Scene504(vm);
+ case 505: // car view screen
+ return new Scene505(vm);
+ case 506: // shopping street
+ return new Scene506(vm);
+ case 507: // inside software house
+ return new Scene507(vm);
+ case 508: // laser cannon
+ return new Scene508(vm);
+ case 511: // outside pleasure dome
+ return new Scene511(vm);
+ case 512: // inside pleasure dome
+ return new Scene512(vm);
+ case 513: // outside mall
+ return new Scene513(vm);
+ case 515: // overview
+ return new Scene515(vm);
+ case 551: // outside teleporter (with skeleton)
+ return new Scene551(vm);
+
+ // Scene group #6 (men's city, upper floor)
+ case 601: // outside Bruce's house
+ return new Scene601(vm);
+ case 602: // Bruce's house, living room
+ return new Scene602(vm);
+ case 603: // Bruce's house, bedroom
+ return new Scene603(vm);
+ case 604: // viewport
+ return new Scene604(vm);
+ case 605: // viewport closeup
+ return new Scene605(vm);
+ case 607: // outside Abdul's garage
+ return new Scene607(vm);
+ case 608: // inside Abdul's garage
+ return new Scene608(vm);
+ case 609: // outside Buckluster video store
+ return new Scene609(vm);
+ case 610: // inside Buckluster video store
+ return new Scene610(vm);
+ case 611: // back alley
+ return new Scene611(vm);
+ case 612: // expressway / maintenance building
+ return new Scene612(vm);
+ case 620: // cutscene, viewport glass breaking
+ return new Scene620(vm);
+
+ // Scene group #7 (submerged men's city / upper floor)
+ case 701: // outside elevator (after city is submerged)
+ return new Scene701(vm);
+ case 702: // outside teleporter (after city is submerged)
+ return new Scene702(vm);
+ case 703: // water
+ return new Scene703(vm);
+ case 704: // water, building in the distance
+ return new Scene704(vm);
+ case 705: // water, outside building
+ return new Scene705(vm);
+ case 706: // inside building, pedestral room, outside teleporter
+ return new Scene706(vm);
+ case 707: // teleporter
+ return new Scene707(vm);
+ case 710: // looking at pedestral room through binoculars
+ return new Scene710(vm);
+ case 711: // inside teleporter
+ return new Scene711(vm);
+ case 751: // outside elevator (before city is submerged)
+ return new Scene751(vm);
+ case 752: // outside teleporter (before city is submerged)
+ return new Scene752(vm);
+
+ // Scene group #8
+ case 801: // control room, outside teleporter
+ return new Scene801(vm);
+ case 802: // launch pad with destroyed ship
+ return new Scene802(vm);
+ case 803: // empty launch pad
+ return new Scene803(vm);
+ case 804: // inside Rex's ship - cockpit
+ return new Scene804(vm);
+ case 805: // service panel
+ return new Scene805(vm);
+ case 807: // teleporter
+ return new Scene807(vm);
+ case 808: // antigrav control
+ return new Scene808(vm);
+ case 810: // cutscene: Rex's ship leaving the planet
+ return new Scene810(vm);
+
+ default:
+ error("Invalid scene %d called", scene._nextSceneId);
+ }
+}
+
+/*------------------------------------------------------------------------*/
+
+NebularScene::NebularScene(MADSEngine *vm) : SceneLogic(vm),
+ _globals(static_cast<GameNebular *>(vm->_game)->_globals),
+ _game(*static_cast<GameNebular *>(vm->_game)),
+ _action(vm->_game->_scene._action) {
+}
+
+Common::String NebularScene::formAnimName(char sepChar, int suffixNum) {
+ return Resources::formatName(_scene->_currentSceneId, sepChar, suffixNum,
+ EXT_NONE, "");
+}
+
+/*------------------------------------------------------------------------*/
+
+void SceneInfoNebular::loadCodes(MSurface &depthSurface, int variant) {
+ File f(Resources::formatName(RESPREFIX_RM, _sceneId, ".DAT"));
+ MadsPack codesPack(&f);
+ Common::SeekableReadStream *stream = codesPack.getItemStream(variant + 1);
+
+ loadCodes(depthSurface, stream);
+
+ delete stream;
+ f.close();
+}
+
+void SceneInfoNebular::loadCodes(MSurface &depthSurface, Common::SeekableReadStream *stream) {
+ byte *destP = depthSurface.getData();
+ byte *endP = depthSurface.getBasePtr(0, depthSurface.h);
+
+ byte runLength = stream->readByte();
+ while (destP < endP && runLength > 0) {
+ byte runValue = stream->readByte();
+
+ // Write out the run length
+ Common::fill(destP, destP + runLength, runValue);
+ destP += runLength;
+
+ // Get the next run length
+ runLength = stream->readByte();
+ }
+
+ if (destP < endP)
+ Common::fill(destP, endP, 0);
+}
+
+/*------------------------------------------------------------------------*/
+
+int SceneTeleporter::teleporterAddress(int code, bool working) {
+ int limit = working ? 6 : 10;
+
+ for (int i = 0; i < limit; i++) {
+ if (code == _globals[kTeleporterCode + i])
+ return _globals[kTeleporterRoom + i];
+ }
+
+ return -1;
+}
+
+Common::Point SceneTeleporter::teleporterComputeLocation() {
+ Common::Point result;
+
+ switch (_buttonTyped) {
+ case 0:
+ result = Common::Point(179, 200);
+ break;
+
+ case 1:
+ result = Common::Point(166, 170);
+ break;
+
+ case 2:
+ result = Common::Point(179, 170);
+ break;
+
+ case 3:
+ result = Common::Point(192, 170);
+ break;
+
+ case 4:
+ result = Common::Point(166, 180);
+ break;
+
+ case 5:
+ result = Common::Point(179, 180);
+ break;
+
+ case 6:
+ result = Common::Point(192, 180);
+ break;
+
+ case 7:
+ result = Common::Point(166, 190);
+ break;
+
+ case 8:
+ result = Common::Point(179, 190);
+ break;
+
+ case 9:
+ result = Common::Point(192, 190);
+ break;
+
+ case 10:
+ result = Common::Point(194, 200);
+ break;
+
+ case 11:
+ result = Common::Point(164, 200);
+ break;
+
+ default:
+ error("teleporterComputeLocation() - Unexpected button pressed");
+ }
+
+ return result;
+}
+
+void SceneTeleporter::teleporterHandleKey() {
+ switch (_game._trigger) {
+ case 0: {
+ _game._player._stepEnabled = false;
+ Common::Point msgPos = teleporterComputeLocation();
+ _handSequenceId = _scene->_sequences.startReverseCycle(_handSpriteId, false, 4, 2, 0, 0);
+ _scene->_sequences.setPosition(_handSequenceId, msgPos);
+ _scene->_sequences.setDepth(_handSequenceId, 2);
+ _scene->_sequences.addSubEntry(_handSequenceId, SEQUENCE_TRIGGER_LOOP, 0, 1);
+ _scene->_sequences.addSubEntry(_handSequenceId, SEQUENCE_TRIGGER_EXPIRE, 0, 2);
+
+ if (_globals[kMeteorologistWatch] == METEOROLOGIST_NORMAL)
+ _vm->_events->hideCursor();
+
+ }
+ break;
+
+ case 1:
+ _scene->_sequences.addSubEntry(_handSequenceId, SEQUENCE_TRIGGER_SPRITE, 3, 3);
+ if (_buttonTyped <= 9) {
+ if (_digitCount < 4) {
+ _curCode *= 10;
+ _curCode += _buttonTyped;
+ _digitCount++;
+ _msgText = Common::String::format("%d", _curCode);
+ if (_digitCount < 4)
+ _msgText += "_";
+
+ if (_scene->_currentSceneId != 711)
+ _vm->_sound->command(32);
+ }
+ } else if (_buttonTyped == 11) {
+ _digitCount = 0;
+ _curCode = 0;
+ _msgText = "_";
+ if (_scene->_currentSceneId != 711)
+ _vm->_sound->command(33);
+ } else if (_digitCount == 4) {
+ if (_scene->_currentSceneId != 711)
+ _finishedCodeCounter = 1;
+
+ if (teleporterAddress(_curCode, true) > 0) {
+ _vm->_palette->setEntry(252, 0, 63, 0);
+ if (_scene->_currentSceneId != 711)
+ _vm->_sound->command(34);
+ } else {
+ _vm->_palette->setEntry(252, 63, 0, 0);
+ if (_scene->_currentSceneId != 711)
+ _vm->_sound->command(35);
+ }
+ }
+
+ if (_scene->_currentSceneId != 711) {
+ if (_curMessageId >= 0)
+ _scene->_kernelMessages.remove(_curMessageId);
+ _curMessageId = _scene->_kernelMessages.add(Common::Point(143, 61), 0xFDFC, 16, 0, 9999999, _msgText);
+ }
+ break;
+
+ case 2:
+ if (_finishedCodeCounter == 1) {
+ _finishedCodeCounter++;
+
+ if (_globals[kMeteorologistWatch] != METEOROLOGIST_NORMAL)
+ _scene->_nextSceneId = 202;
+ else {
+ _vm->_events->showCursor();
+ int destination = teleporterAddress(_curCode, true);
+
+ if (destination > 0) {
+ _globals[kTeleporterCommand] = 2;
+ _scene->_nextSceneId = _teleporterSceneId;
+ _globals[kTeleporterDestination] = destination;
+ } else {
+ _globals[kTeleporterCommand] = 4;
+ _scene->_nextSceneId = _teleporterSceneId;
+ }
+ }
+ } else if (_globals[kMeteorologistWatch] != METEOROLOGIST_NORMAL)
+ _scene->_sequences.addTimer(30, 230 + _meteorologistCurPlace);
+
+ break;
+
+ case 3:
+ if (!_finishedCodeCounter) {
+ if (_globals[kMeteorologistWatch] == METEOROLOGIST_NORMAL) {
+ _game._player._stepEnabled = true;
+ _vm->_events->showCursor();
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+void SceneTeleporter::teleporterEnter() {
+ _game._player._visible = false;
+ _game._player._stepEnabled = (_globals[kMeteorologistWatch] == METEOROLOGIST_NORMAL);
+ _scene->_kernelMessages._talkFont = _vm->_font->getFont(FONT_TELE);
+ _scene->_textSpacing = 0;
+ _curCode = 0;
+ _digitCount = 0;
+ _finishedCodeCounter = 0;
+ _curMessageId = -1;
+ _msgText = "_";
+
+ if (_scene->_priorSceneId == -2)
+ _scene->_priorSceneId = _globals[kTeleporterDestination];
+
+ if (_scene->_priorSceneId < 101)
+ _scene->_priorSceneId = 201;
+
+ _globals[kTeleporterDestination] = _scene->_priorSceneId;
+ _vm->_palette->setEntry(252, 63, 63, 0);
+ _vm->_palette->setEntry(253, 0, 0, 0);
+ _teleporterSceneId = _scene->_priorSceneId;
+ if (_teleporterSceneId == 202)
+ _teleporterSceneId = 201;
+
+ int tmpVal = 0;
+ for (int i = 0; i < 10; i++) {
+ if (_teleporterSceneId == _globals[kTeleporterRoom + i])
+ tmpVal = _globals[kTeleporterRoom + i];
+
+ if (_globals[kTeleporterRoom + i] == 301)
+ _meteorologistNextPlace = _globals[kTeleporterCode + i];
+ }
+
+ Common::String msgText2 = Common::String::format("#%.4d", tmpVal);
+
+ if (_scene->_currentSceneId != 711) {
+ _scene->_kernelMessages.add(Common::Point(133, 34), 0, 32, 0, 9999999, msgText2);
+ _scene->_kernelMessages.add(Common::Point(143, 61), 0xFDFC, 16, 0, 9999999, _msgText);
+ }
+
+ _meteorologistCurPlace = 0;
+
+ if (_globals[kMeteorologistWatch] != METEOROLOGIST_NORMAL)
+ _scene->_sequences.addTimer(30, 230);
+
+ _vm->_sound->command(36);
+}
+
+bool SceneTeleporter::teleporterActions() {
+ bool retVal = false;
+ static int _buttonList[12] = { NOUN_0_KEY, NOUN_1_KEY, NOUN_2_KEY, NOUN_3_KEY, NOUN_4_KEY, NOUN_5_KEY, NOUN_6_KEY, NOUN_7_KEY, NOUN_8_KEY, NOUN_9_KEY, NOUN_SMILE_KEY, NOUN_FROWN_KEY };
+
+ if (_action.isAction(VERB_PRESS) || _action.isAction(VERB_PUSH)) {
+ for (int i = 0; i < 12; i++) {
+ if (_action._activeAction._objectNameId == _buttonList[i])
+ _buttonTyped = i;
+ }
+ teleporterHandleKey();
+ retVal = true;
+ }
+
+ if (_action.isAction(VERB_EXIT_FROM, NOUN_DEVICE)) {
+ _globals[kTeleporterCommand] = 3;
+ _scene->_nextSceneId = _teleporterSceneId;
+ retVal = true;
+ }
+
+ return (retVal);
+}
+
+void SceneTeleporter::teleporterStep() {
+ if (_globals[kMeteorologistWatch] == METEOROLOGIST_NORMAL)
+ return;
+
+ if (_game._trigger >= 230) {
+ int place = _game._trigger - 230;
+ int digit;
+
+ if (place < 4) {
+ digit = _meteorologistNextPlace;
+ for (int i = 0; i < (3 - place); i++)
+ digit = digit / 10;
+
+ digit = digit % 10;
+ } else {
+ digit = 10;
+ }
+ _buttonTyped = digit;
+ _meteorologistCurPlace = place + 1;
+ _game._trigger = -1;
+ }
+
+ if (_game._trigger) {
+ if (_game._trigger == -1)
+ _game._trigger = 0;
+ teleporterHandleKey();
+ }
+}
+
+} // End of namespace Nebular
+
+} // End of namespace MADS
diff --git a/engines/mads/nebular/nebular_scenes.h b/engines/mads/nebular/nebular_scenes.h
new file mode 100644
index 0000000000..8df43e92e9
--- /dev/null
+++ b/engines/mads/nebular/nebular_scenes.h
@@ -0,0 +1,1383 @@
+/* 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.
+ *
+ */
+
+#ifndef MADS_NEBULAR_SCENES_H
+#define MADS_NEBULAR_SCENES_H
+
+#include "common/scummsys.h"
+#include "mads/game.h"
+#include "mads/scene.h"
+#include "mads/nebular/game_nebular.h"
+#include "mads/nebular/globals_nebular.h"
+
+
+namespace MADS {
+
+namespace Nebular {
+
+enum {
+ SEX_MALE = 0, SEX_UNKNOWN = 1, SEX_FEMALE = 2
+};
+
+enum Verb {
+ VERB_ACTIVATE = 0x00E,
+ VERB_ATTACH = 0x019,
+ VERB_BREAK = 0x032,
+ VERB_BREATHE_AIR = 0x033,
+ VERB_CAST = 0x03D,
+ VERB_CLIMB_DOWN = 0x04E,
+ VERB_CLIMB_THROUGH = 0x04F,
+ VERB_CLIMB_UP = 0x050,
+ VERB_CUT = 0x061,
+ VERB_DAMPEN = 0x064,
+ VERB_DIVE_INTO = 0x06D,
+ VERB_DRINK = 0x072,
+ VERB_EAT = 0x075,
+ VERB_EXAMINE = 0x07D,
+ VERB_HOSE_DOWN = 0x0A6,
+ VERB_IGNITE = 0x0B4,
+ VERB_INFLATE = 0x0B5,
+ VERB_INSERT = 0x0B6,
+ VERB_INSPECT = 0x0B7,
+ VERB_HURL = 0x0A9,
+ VERB_LOOK_AT = 0x0D1,
+ VERB_LOOK_IN = 0x0D2,
+ VERB_LOOK_THROUGH = 0x0D3,
+ VERB_PEER_THROUGH = 0x103,
+ VERB_PLAY = 0x112,
+ VERB_PRESS = 0x11A,
+ VERB_PRY = 0x11C,
+ VERB_READ = 0x11F,
+ VERB_SHOOT = 0x13A,
+ VERB_SIT_IN = 0x13F,
+ VERB_SMELL = 0x147,
+ VERB_STARE_AT = 0x155,
+ VERB_SWIM_INTO = 0x15A,
+ VERB_SWIM_THROUGH = 0x15B,
+ VERB_SWIM_TO = 0x15C,
+ VERB_SWIM_TOWARDS = 0x15D,
+ VERB_SWIM_UNDER = 0x15E,
+ VERB_UNLOCK = 0x17B,
+ VERB_WALK_INSIDE = 0x188,
+ VERB_WALK_THROUGH = 0x18B,
+ VERB_WALK_TOWARDS = 0x18C,
+ VERB_WALK_DOWN = 0x1AD,
+ VERB_LEAVE = 0x1CD,
+ VERB_EXIT_FROM = 0x1CE,
+ VERB_USE = 0x20C,
+ VERB_SIT_AT = 0x21F,
+ VERB_WALK_UP = 0x227,
+ VERB_WALK_INTO = 0x242,
+ VERB_EXIT = 0x298,
+ VERB_WALK_ONTO = 0x2B5,
+ VERB_RETURN_TO = 0x2D5,
+ VERB_CLIMB_INTO = 0x2F7,
+ VERB_STEP_INTO = 0x2F9,
+ VERB_CRAWL_TO = 0x2FB,
+ VERB_SIT_ON = 0x30B,
+ VERB_WALK_ALONG = 0x312,
+ VERB_WALK = 0x32F,
+ VERB_REFLECT = 0x365,
+ VERB_GET_INTO = 0x36A,
+ VERB_ENTER = 0x3B8,
+ VERB_INSTALL = 0x474,
+ VERB_REMOVE = 0x476
+};
+
+enum Noun {
+ //NOUN_GAME = 0x1,
+ //NOUN_QSAVE = 0x2,
+ //NOUN_LOOK = 0x3,
+ //NOUN_TAKE = 0x4,
+ //NOUN_PUSH = 0x5,
+ //NOUN_OPEN = 0x6,
+ //NOUN_PUT = 0x7,
+ //NOUN_TALK_TO = 0x8,
+ //NOUN_GIVE = 0x9,
+ //NOUN_PULL = 0xA,
+ //NOUN_CLOSE = 0xB,
+ //NOUN_THROW = 0xC,
+ //NOUN_WALK_TO = 0xD,
+ //NOUN_ACTIVATE = 0xE,
+ //NOUN_ADMIRE = 0xF,
+ NOUN_ADSM = 0x10,
+ NOUN_AIR_VENT = 0x11,
+ NOUN_ALOE_PLANT = 0x12,
+ NOUN_ANEMONE = 0x13,
+ NOUN_ANOMOMETER = 0x14,
+ NOUN_AREA_AROUND_HUT = 0x15,
+ NOUN_AREA_TO_SOUTH = 0x16,
+ NOUN_AREA_TO_WEST = 0x17,
+ NOUN_AROMATIC_MEAT = 0x18,
+ //NOUN_ATTACH = 0x19,
+ NOUN_AUDIO_TAPE = 0x1A,
+ NOUN_AUXILIARY_POWER = 0x1B,
+ NOUN_BADMITTON_BRAT = 0x1C,
+ NOUN_BAG = 0x1D,
+ NOUN_BAMBOO_TREE = 0x1E,
+ NOUN_BATS = 0x1F,
+ NOUN_BAWLEMER_ORIOLE_HUN = 0x20,
+ NOUN_BEAR_RUG = 0x21,
+ NOUN_BEASTLY_TROPHY = 0x22,
+ NOUN_BIG_LEAVES = 0x23,
+ NOUN_BIG_PIPES = 0x24,
+ NOUN_BIG_SKY = 0x25,
+ NOUN_BIG_STONE = 0x26,
+ NOUN_BINOCULARS = 0x27,
+ NOUN_BIRDIES = 0x28,
+ NOUN_BLOWGUN = 0x29,
+ NOUN_BOMB = 0x2A,
+ NOUN_BOMBS = 0x2B,
+ NOUN_BONE = 0x2C,
+ NOUN_BONES = 0x2D,
+ NOUN_BOTTLE = 0x2E,
+ NOUN_BOULDER = 0x2F,
+ NOUN_BOULDERS = 0x30,
+ NOUN_BRA = 0x31,
+ //NOUN_BREAK = 0x32,
+ //NOUN_BREATHE_AIR = 0x33,
+ NOUN_BULKHEAD = 0x34,
+ NOUN_BURGER = 0x35,
+ NOUN_BURN = 0x36,
+ NOUN_BURNT_OUT_WARP_COIL = 0x37,
+ NOUN_BUSH_LIKE_FORMATION = 0x38,
+ NOUN_BUSHES = 0x39,
+ NOUN_BUSHY_FERN = 0x3A,
+ NOUN_CACTUS = 0x3B,
+ NOUN_CARD = 0x3C,
+ //NOUN_CAST = 0x3D,
+ NOUN_CAULDRON = 0x3E,
+ NOUN_CAVE = 0x3F,
+ NOUN_CAVE_CEILING = 0x40,
+ NOUN_CAVE_ENTRANCE = 0x41,
+ NOUN_CAVE_EXIT = 0x42,
+ NOUN_CAVE_FLOOR = 0x43,
+ NOUN_CAVE_TO_EAST = 0x44,
+ NOUN_CAVE_WALL = 0x45,
+ NOUN_CEILING = 0x46,
+ NOUN_CHAIR = 0x47,
+ NOUN_CHARGE_CASES = 0x48,
+ NOUN_CHICKEN = 0x49,
+ NOUN_CHICKEN_BOMB = 0x4A,
+ NOUN_CLEARING_TO_EAST = 0x4B,
+ NOUN_CLEARING_TO_SOUTH = 0x4C,
+ NOUN_CLIFF_FACE = 0x4D,
+ NOUN_CLIMB_DOWN = 0x4E,
+ NOUN_CLIMB_THROUGH = 0x4F,
+ NOUN_CLIMB_UP = 0x50,
+ NOUN_CLOCK = 0x51,
+ NOUN_CLOSET = 0x52,
+ NOUN_CLOTHESLINE = 0x53,
+ NOUN_CLUMP_OF_TREES = 0x54,
+ NOUN_COAL = 0x55,
+ NOUN_COCOANUT = 0x56,
+ NOUN_COMPACT_CASE = 0x57,
+ NOUN_COMPUTER_GAME = 0x58,
+ NOUN_CONTROL_PANEL = 0x59,
+ NOUN_CORAL = 0x5A,
+ NOUN_CRAB = 0x5B,
+ NOUN_CREDIT_CHIP = 0x5C,
+ NOUN_CUMULOUS_CLOUD = 0x5D,
+ NOUN_CURIOUS_WEED_PATCH = 0x5E,
+ NOUN_CURTAIN = 0x5F,
+ NOUN_CURTAINS = 0x60,
+ //NOUN_CUT = 0x61,
+ NOUN_DAMAGE_CONTROL = 0x62,
+ NOUN_DAMAGE_CONTROL_PANEL = 0x63,
+ //NOUN_DAMPEN = 0x64,
+ NOUN_DEAD_FISH = 0x65,
+ NOUN_DEAD_PURPLE_MONSTER = 0x66,
+ NOUN_DECLIVITOUS_CHASM = 0x67,
+ NOUN_DEEP_DARK_FOREST = 0x68,
+ NOUN_DENSE_FOREST = 0x69,
+ NOUN_DETONATORS = 0x6A,
+ NOUN_DINO_MITE = 0x6B,
+ //NOUN_DISASSEMBLE = 0x6C,
+ //NOUN_DIVE_INTO = 0x6D,
+ NOUN_DOOR = 0x6E,
+ NOUN_DOOR_KEY = 0x6F,
+ NOUN_DOORWAY = 0x70,
+ NOUN_DRAWER = 0x71,
+ //NOUN_DRINK = 0x72,
+ NOUN_DURAFAIL_CELLS = 0x73,
+ NOUN_EASTERN_CLIFF_FACE = 0x74,
+ //NOUN_EAT = 0x75,
+ //NOUN_EJECT = 0x76,
+ //NOUN_EMPTY = 0x77,
+ NOUN_ENGINEERING_CONTROLS = 0x78,
+ NOUN_ENGINEERING_SECTION = 0x79,
+ NOUN_ENTER_KEY = 0x7A,
+ NOUN_ESCAPE_HATCH = 0x7B,
+ NOUN_ESTROTOXIN = 0x7C,
+ //NOUN_EXAMINE = 0x7D,
+ NOUN_EXPERIMENT_CAGE = 0x7E,
+ NOUN_EXTINGUISH = 0x7F,
+ NOUN_FACE_ID = 0x80,
+ NOUN_FERN = 0x81,
+ NOUN_FIELD_TO_NORTH = 0x82,
+ NOUN_FIELD_TO_SOUTH = 0x83,
+ NOUN_FIELD_TO_WEST = 0x84,
+ NOUN_FILL = 0x85,
+ NOUN_FIRE_PIT = 0x86,
+ NOUN_FISHING_LINE = 0x87,
+ NOUN_FISHING_ROD = 0x88,
+ NOUN_FLOOR = 0x89,
+ NOUN_FLOOR_OF_HUT = 0x8A,
+ NOUN_FLOOR_TILE = 0x8B,
+ //NOUN_FONDLE = 0x8C,
+ NOUN_FOREST_TO_EAST = 0x8D,
+ NOUN_FRONT_WINDOW = 0x8E,
+ NOUN_FUNGOIDS = 0x8F,
+ NOUN_FURNACE = 0x90,
+ NOUN_FUZZY_DICE = 0x91,
+ //NOUN_GAZE = 0x92,
+ //NOUN_GAZE_AT = 0x93,
+ //NOUN_GAZE_IN = 0x94,
+ //NOUN_GLANCE_AT = 0x95,
+ NOUN_GLOVE = 0x96,
+ NOUN_GNARLY_SHRUB = 0x97,
+ //NOUN_GNAW_ON = 0x98,
+ //NOUN_GORGE_ON = 0x99,
+ NOUN_GRAIN_ALCHOHOL = 0x9A,
+ NOUN_GRASSLAND_TO_EAST = 0x9B,
+ NOUN_GRASSLAND_TO_SOUTH = 0x9C,
+ NOUN_GRASSY_AREA = 0x9D,
+ NOUN_GRASSY_AREA_TO_NORTH = 0x9E,
+ NOUN_GRASSY_KNOLL = 0x9F,
+ //NOUN_GRIND = 0xA0,
+ NOUN_GROOVILACTIC_TREE = 0xA1,
+ NOUN_GUARDS_ARM = 0xA2,
+ NOUN_HATCHWAY = 0xA3,
+ //NOUN_HOOK_UP = 0xA4,
+ NOUN_HORIZON = 0xA5,
+ //NOUN_HOSE_DOWN = 0xA6,
+ NOUN_HOTPANTS = 0xA7,
+ NOUN_HULL = 0xA8,
+ //NOUN_HURL = 0xA9,
+ NOUN_HUT = 0xAA,
+ NOUN_HUT_AREA = 0xAB,
+ NOUN_HUT_TO_EAST = 0xAC,
+ NOUN_HUT_TO_SOUTH = 0xAD,
+ NOUN_HUT_TO_THE_SOUTH = 0xAE,
+ NOUN_HUT_TO_WEST = 0xAF,
+ NOUN_HUTS_TO_NORTH = 0xB0,
+ NOUN_HYDROSPANNER = 0xB1,
+ NOUN_HYPERDRIVE_JUMP_UNIT = 0xB2,
+ NOUN_ID_CARD = 0xB3,
+ //NOUN_IGNITE = 0xB4,
+ //NOUN_INFLATE = 0xB5,
+ //NOUN_INSERT = 0xB6,
+ //NOUN_INSPECT = 0xB7,
+ NOUN_JUNGLE = 0xB8,
+ NOUN_JUNGLE_TO_EAST = 0xB9,
+ NOUN_JUNGLE_TO_WEST = 0xBA,
+ NOUN_KEY_1 = 0xBB,
+ NOUN_KEY_2 = 0xBC,
+ NOUN_KEY_3 = 0xBD,
+ NOUN_KEY_4 = 0xBE,
+ NOUN_KEY_5 = 0xBF,
+ NOUN_KEY_6 = 0xC0,
+ NOUN_KEY_7 = 0xC1,
+ NOUN_KEY_8 = 0xC2,
+ NOUN_KEY_9 = 0xC3,
+ NOUN_KEYPAD = 0xC4,
+ NOUN_KNEELING_WOMAN = 0xC5,
+ NOUN_KNIFE = 0xC6,
+ NOUN_LADDER = 0xC7,
+ NOUN_LARGE_STALAGMITE = 0xC8,
+ //NOUN_LEER_AT = 0xC9,
+ NOUN_LIBRARY_COMPUTER = 0xCA,
+ //NOUN_LICK = 0xCB,
+ NOUN_LIFE_SUPPORT_SECTION = 0xCC,
+ NOUN_LIGHT = 0xCD,
+ //NOUN_LOAD = 0xCE,
+ //NOUN_LOCK = 0xCF,
+ NOUN_LOG = 0xD0,
+ //NOUN_LOOK_AT = 0xD1,
+ //NOUN_LOOK_IN = 0xD2,
+ //NOUN_LOOK_THROUGH = 0xD3,
+ NOUN_LOUNGE_AREA = 0xD4,
+ NOUN_LOVE_ALTAR = 0xD5,
+ NOUN_LOWLANDS = 0xD6,
+ NOUN_MACHINE = 0xD7,
+ NOUN_MAGNET = 0xD8,
+ NOUN_MAIN_AIRLOCK = 0xD9,
+ NOUN_MANTA_RAY = 0xDA,
+ NOUN_MARSHY_WETLANDS = 0xDB,
+ NOUN_MATCH = 0xDC,
+ NOUN_MEDICAL_WASTE = 0xDD,
+ NOUN_MEDICINE_CABINET = 0xDE,
+ NOUN_MEN_WHO_CAME_BEFORE = 0xDF,
+ NOUN_MINE = 0xE0,
+ NOUN_MIRROR = 0xE1,
+ NOUN_MONITOR = 0xE2,
+ NOUN_MONKEY = 0xE3,
+ NOUN_MONKEY_LIVER_JUICE = 0xE4,
+ NOUN_MONSTER_SLUDGE = 0xE5,
+ NOUN_MOUNTAIN = 0xE6,
+ NOUN_MOUNTAIN_RANGE = 0xE7,
+ NOUN_MOUNTAINS = 0xE8,
+ NOUN_MTAM = 0xE9,
+ NOUN_MUSHROOMS = 0xEA,
+ NOUN_NAVIGATION_CONTROLS = 0xEB,
+ NOUN_NORTH_PATH = 0xEC,
+ NOUN_NORTHERN_EXPOSURE = 0xED,
+ NOUN_NORTHERN_SEA_CLIFF = 0xEE,
+ NOUN_OBSTACLE = 0xEF,
+ NOUN_OCEAN_FLOOR = 0xF0,
+ NOUN_ODD_ROCK_FORMATION = 0xF1,
+ NOUN_OOGLY_BOOGLY_JUICE = 0xF2,
+ NOUN_OPEN_AREA_TO_EAST = 0xF3,
+ NOUN_OPEN_AREA_TO_NORTH = 0xF4,
+ NOUN_OPEN_AREA_TO_SOUTH = 0xF5,
+ NOUN_OPEN_AREA_TO_WEST = 0xF6,
+ NOUN_OPEN_FIELD = 0xF7,
+ NOUN_OUTER_HULL = 0xF8,
+ NOUN_OUTSIDE = 0xF9,
+ NOUN_OVEN = 0xFA,
+ NOUN_OVERHANG_TO_EAST = 0xFB,
+ NOUN_OVERHANG_TO_WEST = 0xFC,
+ NOUN_OVERHEAD_LAMP = 0xFD,
+ NOUN_PAD_OF_PAPER = 0xFE,
+ NOUN_PADLOCK_KEY = 0xFF,
+ NOUN_PALM_TREE = 0x100,
+ NOUN_PASSAGE_WAY_TO_SOUTH = 0x101,
+ NOUN_PASSION_PUSS = 0x102,
+ NOUN_PEER_THROUGH = 0x103,
+ NOUN_PENCIL = 0x104,
+ NOUN_PENDULOUS_CRAG = 0x105,
+ NOUN_PENLIGHT = 0x106,
+ NOUN_PHONE_CELLS = 0x107,
+ NOUN_PHONE_HANDSET = 0x108,
+ NOUN_PILE_OF_ROCKS = 0x109,
+ NOUN_PILLOW = 0x10A,
+ NOUN_PILOTS_CHAIR = 0x10B,
+ NOUN_PIPE = 0x10C,
+ NOUN_PIRANHA = 0x10D,
+ NOUN_PLANT = 0x10E,
+ NOUN_PLANT_STALK = 0x10F,
+ NOUN_PLANTS = 0x110,
+ NOUN_PLASTIC_JESUS = 0x111,
+ //NOUN_PLAY = 0x112,
+ NOUN_PLUNGER = 0x113,
+ NOUN_POISON_DARTS = 0x114,
+ NOUN_POLYCEMENT = 0x115,
+ NOUN_POOL = 0x116,
+ NOUN_POSTER = 0x117,
+ NOUN_POWER_STATUS_PANEL = 0x118,
+ NOUN_PRECIPICE = 0x119,
+ //NOUN_PRESS = 0x11A,
+ NOUN_PRESSURE_GAUGE = 0x11B,
+ //NOUN_PRY = 0x11C,
+ NOUN_RAGING_RIVER = 0x11D,
+ NOUN_RAMOLYAN_RUGBY_RATS = 0x11E,
+ //NOUN_READ = 0x11F,
+ NOUN_REARVIEW_MIRROR = 0x120,
+ NOUN_REBREATHER = 0x121,
+ NOUN_REFRIGERATOR = 0x122,
+ NOUN_REMOTE = 0x123,
+ NOUN_REPAIR_LIST = 0x124,
+ NOUN_RIVER = 0x125,
+ NOUN_RIVER_TO_WEST = 0x126,
+ NOUN_ROBO_KITCHEN = 0x127,
+ NOUN_ROCK = 0x128,
+ NOUN_ROCKS = 0x129,
+ NOUN_ROCKY_AREA = 0x12A,
+ NOUN_ROLLING_HILL = 0x12B,
+ NOUN_SCALPEL = 0x12C,
+ NOUN_SCENIC_MOUNTAINS = 0x12D,
+ NOUN_SEA_CLIFF = 0x12E,
+ NOUN_SEAWEED = 0x12F,
+ NOUN_SEAWEED_BANK = 0x130,
+ NOUN_SECURITY_CARD = 0x131,
+ //NOUN_SET = 0x132,
+ NOUN_SHAKE_HANDS = 0x133,
+ NOUN_SHARPEN = 0x134,
+ NOUN_SHIELD_ACCESS_PANEL = 0x135,
+ NOUN_SHIELD_GENERATOR = 0x136,
+ NOUN_SHIELD_MODULATOR = 0x137,
+ NOUN_SHIELD_STATUS_PANEL = 0x138,
+ NOUN_SHIP = 0x139,
+ //NOUN_SHOOT = 0x13A,
+ NOUN_SHOVEL = 0x13B,
+ //NOUN_SHRED = 0x13C,
+ NOUN_SHRUNKEN_HEADS = 0x13D,
+ NOUN_SINGED_MEAT = 0x13E,
+ //NOUN_SIT_IN = 0x13F,
+ NOUN_SKULL = 0x140,
+ NOUN_SKULL_AND_CROSSBONES = 0x141,
+ NOUN_SKY = 0x142,
+ //NOUN_SLEEP_ON = 0x143,
+ NOUN_SLITHERING_SNAKE = 0x144,
+ NOUN_SLUG_SECRETION = 0x145,
+ NOUN_SMALL_HOLE = 0x146,
+ //NOUN_SMELL = 0x147,
+ NOUN_SNAKE = 0x148,
+ //NOUN_SNIFF = 0x149,
+ //NOUN_SOAK = 0x14A,
+ NOUN_SPECIAL_KEY_1 = 0x14B,
+ NOUN_SPECIAL_KEY_2 = 0x14C,
+ NOUN_SPIDER = 0x14D,
+ NOUN_SPILT_MILK = 0x14E,
+ NOUN_SPIT_FIRE = 0x14F,
+ //NOUN_SPRAY = 0x150,
+ //NOUN_STAB = 0x151,
+ NOUN_STAIRS = 0x152,
+ NOUN_STALAGMITES = 0x153,
+ //NOUN_STAND_INSIDE = 0x154,
+ //NOUN_STARE_AT = 0x155,
+ NOUN_STEPS = 0x156,
+ NOUN_STUFFED_FISH = 0x157,
+ NOUN_SURFACE = 0x158,
+ //NOUN_SWIM_ACROSS = 0x159,
+ //NOUN_SWIM_INTO = 0x15A,
+ //NOUN_SWIM_THROUGH = 0x15B,
+ //NOUN_SWIM_TO = 0x15C,
+ //NOUN_SWIM_TOWARDS = 0x15D,
+ //NOUN_SWIM_UNDER = 0x15E,
+ NOUN_SWOOPING_CREATURE = 0x15F,
+ NOUN_TABLE = 0x160,
+ //NOUN_TAKE_LIVER = 0x161,
+ //NOUN_TAKE_OFF = 0x162,
+ //NOUN_TAKE_PAGE = 0x163,
+ NOUN_TALL_GRASS = 0x164,
+ NOUN_TAPE_PLAYER = 0x165,
+ NOUN_TARGET_COMPUTER = 0x166,
+ NOUN_TARGET_MODULE = 0x167,
+ NOUN_TARGETTING_COMPUTER = 0x168,
+ NOUN_TASMANIAN_DEVIL = 0x169,
+ NOUN_TASTY_TURKEY = 0x16A,
+ NOUN_TELEPORT_DEVICE = 0x16B,
+ NOUN_TELEPORTER = 0x16C,
+ NOUN_THATCHED_ROOF = 0x16D,
+ NOUN_THORNS = 0x16E,
+ NOUN_THORNY_BUSH = 0x16F,
+ //NOUN_TIE = 0x170,
+ NOUN_TIMEBOMB = 0x171,
+ NOUN_TIMER = 0x172,
+ NOUN_TIMER_MODULE = 0x173,
+ NOUN_TREE = 0x174,
+ NOUN_TREES = 0x175,
+ NOUN_TRODDEN_PATH = 0x176,
+ NOUN_TUBE = 0x177,
+ NOUN_TUNNEL = 0x178,
+ NOUN_TWINKIE_BUSH = 0x179,
+ NOUN_TWINKIFRUIT = 0x17A,
+ //NOUN_UNLOCK = 0x17B,
+ NOUN_UZI = 0x17C,
+ NOUN_VASE = 0x17D,
+ NOUN_VIDEO_GAME = 0x17E,
+ //NOUN_VIEW = 0x17F,
+ NOUN_VIEW_SCREEN = 0x180,
+ NOUN_VIEWPORT = 0x181,
+ NOUN_VILLAGE_AREA = 0x182,
+ NOUN_VILLAGE_TO_WEST = 0x183,
+ NOUN_VOLCANO = 0x184,
+ NOUN_VULTURE = 0x185,
+ NOUN_WAD_OF_CATTLE_PARTS = 0x186,
+ //NOUN_WALK_ACROSS = 0x187,
+ //NOUN_WALK_INSIDE = 0x188,
+ //NOUN_WALK_ON = 0x189,
+ //NOUN_WALK_OUTSIDE = 0x18A,
+ //NOUN_WALK_THROUGH = 0x18B,
+ //NOUN_WALK_TOWARDS = 0x18C,
+ NOUN_WALL = 0x18D,
+ NOUN_WATCH_TOWER = 0x18E,
+ NOUN_WATER = 0x18F,
+ NOUN_WEAPONS_DISPLAY = 0x190,
+ //NOUN_WEAR = 0x191,
+ NOUN_WEATHER_STATION = 0x192,
+ NOUN_WEATHER_VANE = 0x193,
+ NOUN_WEIGHT_MACHINE = 0x194,
+ NOUN_WESTERN_CLIFF_FACE = 0x195,
+ NOUN_WHEEL = 0x196,
+ NOUN_WINDOW = 0x197,
+ NOUN_WITCHDOCTOR_HUT = 0x198,
+ NOUN_WORKBENCH = 0x199,
+ //NOUN_WRITE_ON = 0x19A,
+ NOUN_YELLOW_BIRDY = 0x19B,
+ NOUN_GRASS = 0x19C,
+ NOUN_BOUNCING_REPTILE = 0x19D,
+ NOUN_DEEP_PIT = 0x19E,
+ NOUN_LOWLANDS_TO_NORTH = 0x19F,
+ NOUN_SMALL_BUSH = 0x1A0,
+ NOUN_SMALL_CACTUS = 0x1A1,
+ NOUN_ROCKY_AREA_TO_NORTH = 0x1A2,
+ NOUN_BAMBOO_LIKE_PLANT = 0x1A3,
+ NOUN_MOUNTAINSIDE = 0x1A4,
+ NOUN_FIELD = 0x1A5,
+ NOUN_GRASSY_FIELD = 0x1A6,
+ NOUN_CRAG = 0x1A7,
+ NOUN_HUGE_LEGS = 0x1A8,
+ NOUN_LEAF_COVERED_PIT = 0x1A9,
+ NOUN_PILE_OF_LEAVES = 0x1AA,
+ NOUN_OPEN_FIELD_TO_EAST = 0x1AB,
+ NOUN_LAWN = 0x1AC,
+ //NOUN_WALK_DOWN = 0x1AD,
+ NOUN_PATH_TO_WEST = 0x1AE,
+ NOUN_HEDGE = 0x1AF,
+ NOUN_VILLAGE_PATH = 0x1B0,
+ NOUN_PATH_TO_NORTHEAST = 0x1B1,
+ NOUN_JUNGLE_PATH = 0x1B2,
+ NOUN_THICK_UNDERGROWTH = 0x1B3,
+ NOUN_OCEAN = 0x1B4,
+ NOUN_OCEAN_IN_DISTANCE = 0x1B5,
+ NOUN_STRANGE_DEVICE = 0x1B6,
+ NOUN_BUSH = 0x1B7,
+ NOUN_ANEMOMETER = 0x1B8,
+ NOUN_ISLAND_IN_DISTANCE = 0x1B9,
+ NOUN_PATH = 0x1BA,
+ NOUN_TROPHY = 0x1BB,
+ NOUN_SPECIMEN_JARS = 0x1BC,
+ NOUN_BOWL = 0x1BD,
+ NOUN_LARGE_BOWL = 0x1BE,
+ NOUN_PATH_TO_NORTH = 0x1BF,
+ NOUN_HUT_TO_NORTH = 0x1C0,
+ NOUN_PATH_TO_EAST = 0x1C1,
+ NOUN_CHICKEN_ON_SPIT = 0x1C2,
+ NOUN_CAPTIVE_CREATURE = 0x1C3,
+ NOUN_TWINKIFRUIT_BUSH = 0x1C4,
+ NOUN_STREAM = 0x1C5,
+ NOUN_OPPOSITE_SHORE = 0x1C6,
+ NOUN_PATH_TO_SOUTH = 0x1C7,
+ NOUN_OPPOSITE_BANK = 0x1C8,
+ NOUN_BROKEN_LADDER = 0x1C9,
+ NOUN_BAG_OF_TWINKIFRUITS = 0x1CA,
+ NOUN_BED = 0x1CB,
+ NOUN_DISPLAY = 0x1CC,
+ //NOUN_LEAVE = 0x1CD,
+ //NOUN_EXIT_FROM = 0x1CE,
+ NOUN_DEVICE = 0x1CF,
+ NOUN_0_KEY = 0x1D0,
+ NOUN_1_KEY = 0x1D1,
+ NOUN_2_KEY = 0x1D2,
+ NOUN_3_KEY = 0x1D3,
+ NOUN_4_KEY = 0x1D4,
+ NOUN_5_KEY = 0x1D5,
+ NOUN_6_KEY = 0x1D6,
+ NOUN_7_KEY = 0x1D7,
+ NOUN_8_KEY = 0x1D8,
+ NOUN_9_KEY = 0x1D9,
+ NOUN_FROWN_KEY = 0x1DA,
+ NOUN_SMILE_KEY = 0x1DB,
+ NOUN_NATIVE_WOMAN = 0x1DC,
+ NOUN_YELLOW_BIRD = 0x1DD,
+ NOUN_BLEEPER = 0x1DE,
+ NOUN_SIZEMOMETER = 0x1DF,
+ NOUN_PANEL = 0x1E0,
+ NOUN_PRINTER = 0x1E1,
+ NOUN_HARD_DRIVE = 0x1E2,
+ NOUN_BATHROOM = 0x1E3,
+ NOUN_DESK = 0x1E4,
+ NOUN_PASSAGEWAY = 0x1E5,
+ NOUN_FIRE_HYDRANT = 0x1E6,
+ NOUN_FREEZER = 0x1E7,
+ NOUN_EQUIDIGITIZER = 0x1E8,
+ NOUN_VISION_VIEW = 0x1E9,
+ NOUN_TELEDETECTOR = 0x1EA,
+ NOUN_POLE = 0x1EB,
+ NOUN_TRANSPOSITION_DEVICE = 0x1EC,
+ NOUN_STATUESQUE = 0x1ED,
+ NOUN_TEMPERATURE_GAUGE = 0x1EE,
+ NOUN_CHECK = 0x1EF,
+ NOUN_WATCH = 0x1F0,
+ NOUN_ELECTRO_SCANNER = 0x1F1,
+ NOUN_HALL = 0x1F2,
+ NOUN_SCANNER = 0x1F3,
+ //NOUN_PLACE_HAND_ON = 0x1F4,
+ NOUN_SECURITY_MONITOR = 0x1F5,
+ NOUN_DIGITORAMA = 0x1F6,
+ NOUN_RAIL_BEAM = 0x1F7,
+ NOUN_VAULT = 0x1F8,
+ NOUN_HALLWAY = 0x1F9,
+ NOUN_PIPES = 0x1FA,
+ NOUN_AIR_VENT_GRATE = 0x1FB,
+ NOUN_SECURITY_OFFICE = 0x1FC,
+ NOUN_SIGNAL = 0x1FD,
+ NOUN_BLEEP = 0x1FE,
+ NOUN_BLIP = 0x1FF,
+ NOUN_LOFT = 0x200,
+ NOUN_ELECTRONIC_ANT_FARM = 0x201,
+ NOUN_ELECTRIC_WIRING = 0x202,
+ NOUN_SECURITY_PANEL = 0x203,
+ NOUN_CORRIDOR = 0x204,
+ NOUN_CIRCUIT_CONTROLS = 0x205,
+ NOUN_AIR_DUCT = 0x206,
+ NOUN_CELL_WALL = 0x207,
+ NOUN_LIGHTS = 0x208,
+ //NOUN_STARE_INTO = 0x209,
+ NOUN_CELL_CONTROLS = 0x20A,
+ NOUN_COMMODE = 0x20B,
+ //NOUN_USE = 0x20C,
+ NOUN_BASIN = 0x20D,
+ //NOUN_JUMP_INSIDE = 0x20E,
+ NOUN_PREVIOUS_CELL = 0x20F,
+ NOUN_NEXT_ROOM = 0x210,
+ NOUN_ZINK = 0x211,
+ //NOUN_GAZE_INTO = 0x212,
+ NOUN_THRONE = 0x213,
+ NOUN_SACK = 0x214,
+ NOUN_LIMB = 0x215,
+ NOUN_SINK = 0x216,
+ NOUN_JOHNNY_ON_THE_SPOT = 0x217,
+ NOUN_DEBRIS = 0x218,
+ NOUN_BUNK = 0x219,
+ NOUN_NEXT_CELL = 0x21A,
+ NOUN_TOILET = 0x21B,
+ NOUN_MONITOR_AREA = 0x21C,
+ NOUN_SIDEWALL = 0x21D,
+ NOUN_COFFEE_MUG = 0x21E,
+ //NOUN_SIT_AT = 0x21F,
+ NOUN_LIGHTING_FIXTURE = 0x220,
+ NOUN_MONITORS = 0x221,
+ NOUN_GENDER_CONTROLS = 0x222,
+ NOUN_NEURO_ANALYZER = 0x223,
+ NOUN_MOLECULAR_RECORDER = 0x224,
+ NOUN_MAINTENANCE_PANEL = 0x225,
+ NOUN_RAMP = 0x226,
+ //NOUN_WALK_UP = 0x227,
+ NOUN_SUBSONIC_ATOMIZER = 0x228,
+ NOUN_EIGHT_BALL = 0x229,
+ NOUN_DNA_INVERTER = 0x22A,
+ NOUN_DNA_CONVERTER = 0x22B,
+ NOUN_PLATFORM = 0x22C,
+ NOUN_GUINEA_PIG_TEST_BOX = 0x22D,
+ NOUN_GASEOUS_PROBE_WARPER = 0x22E,
+ NOUN_TOOL_CABINET = 0x22F,
+ NOUN_SURGICAL_BOXES = 0x230,
+ NOUN_FETAL_HEART_MONITOR = 0x231,
+ NOUN_XRAY_CABINET = 0x232,
+ NOUN_STERILIZATION_SINK = 0x233,
+ NOUN_DRIPOLATOR = 0x234,
+ NOUN_SHOCK_MACHINE = 0x235,
+ NOUN_INTERROGATION_TABLE = 0x236,
+ NOUN_LIE_DOWN_ON = 0x237,
+ //NOUN_DECIPHER = 0x238,
+ NOUN_GUARD = 0x239,
+ NOUN_RIP_IN_FLOOR = 0x23A,
+ NOUN_TELEPORT_AREA = 0x23B,
+ NOUN_BROKEN_BEAM = 0x23C,
+ NOUN_ROCK_CHUNK = 0x23D,
+ NOUN_BLOODY_CELL_WALL = 0x23E,
+ NOUN_WALL_BOARD = 0x23F,
+ NOUN_GENDER_SCANNER = 0x240,
+ NOUN_BAR = 0x241,
+ //NOUN_WALK_INTO = 0x242,
+ NOUN_HALLWAY_TO_SOUTH = 0x243,
+ NOUN_SIGN = 0x244,
+ NOUN_HALLWAY_TO_NORTH = 0x245,
+ NOUN_BOTTLES = 0x246,
+ NOUN_UPPER_DANCE_FLOOR = 0x247,
+ NOUN_DANCE_FLOOR = 0x248,
+ NOUN_RAILING = 0x249,
+ NOUN_BAR_STOOL = 0x24A,
+ NOUN_LADY = 0x24B,
+ NOUN_UPPER_LEVEL = 0x24C,
+ NOUN_ALCOVE = 0x24D,
+ NOUN_DISCO_BALL = 0x24E,
+ NOUN_LADIES = 0x24F,
+ NOUN_COACH_LAMP = 0x250,
+ NOUN_CARD_SLOT = 0x251,
+ NOUN_HOOP = 0x252,
+ NOUN_CANNONBALLS = 0x253,
+ NOUN_WATER_FOUNTAIN = 0x254,
+ NOUN_HALLWAY_TO_EAST = 0x255,
+ NOUN_HALLWAY_TO_WEST = 0x256,
+ NOUN_SUPPORT = 0x257,
+ NOUN_BACKBOARD = 0x258,
+ NOUN_WIDE_DOOR = 0x259,
+ NOUN_SIGN_POST = 0x25A,
+ NOUN_FIRE_EXTINGUISHER = 0x25B,
+ NOUN_TRASH = 0x25C,
+ NOUN_MISSILES = 0x25D,
+ NOUN_TANK = 0x25E,
+ NOUN_TWO_TON_WEIGHT = 0x25F,
+ NOUN_ONE_TON_TOMATO = 0x260,
+ NOUN_ANVIL = 0x261,
+ NOUN_MINUTEMAN_IV_ICBM = 0x262,
+ NOUN_CHEST = 0x263,
+ NOUN_ARMOR = 0x264,
+ NOUN_CARTON = 0x265,
+ NOUN_POWDER = 0x266,
+ NOUN_RAFT = 0x267,
+ NOUN_WHATZIT = 0x268,
+ NOUN_CATAPULT = 0x269,
+ NOUN_HAND_GRENADE = 0x26A,
+ NOUN_BARRELS = 0x26B,
+ NOUN_LOADING_RAMP = 0x26C,
+ NOUN_BLIMP = 0x26D,
+ NOUN_FLOUR = 0x26E,
+ NOUN_FLY_PAPER = 0x26F,
+ NOUN_RUG = 0x270,
+ NOUN_CARPET = 0x271,
+ NOUN_CAN = 0x272,
+ NOUN_RUBBER_DUCKIE = 0x273,
+ NOUN_GOLF_CLUBS = 0x274,
+ NOUN_RAT = 0x275,
+ NOUN_BARREL = 0x276,
+ NOUN_BUCKET_OF_TAR = 0x277,
+ NOUN_SACKS = 0x278,
+ NOUN_STORAGE = 0x279,
+ NOUN_120V_3_PHASE_400HZ = 0x27A,
+ NOUN_LAB_EQUIPMENT = 0x27B,
+ NOUN_AIR_HORN = 0x27C,
+ NOUN_JAR = 0x27D,
+ NOUN_SEVERED_CABLE = 0x27E,
+ NOUN_PROBE_ASSEMBLY = 0x27F,
+ NOUN_KNIFE_SWITCH = 0x280,
+ NOUN_WORK_BENCH = 0x281,
+ NOUN_HEATER = 0x282,
+ NOUN_TOXIC_WASTE = 0x283,
+ NOUN_EXPERIMENT = 0x284,
+ NOUN_DRAWING_BOARD = 0x285,
+ NOUN_MISHAP = 0x286,
+ NOUN_AIR_PURIFIER = 0x287,
+ NOUN_DUMMY = 0x288,
+ NOUN_PICTURE = 0x289,
+ NOUN_BAGGAGE_CHECK = 0x28A,
+ NOUN_DEPARTURE_SCHEDULE = 0x28B,
+ NOUN_SHADE_OF_PALE = 0x28C,
+ NOUN_ITINERARY = 0x28D,
+ NOUN_BARGAIN_VAT = 0x28E,
+ NOUN_PENCILS = 0x28F,
+ NOUN_PAD_IF_PAPER = 0x290,
+ NOUN_DEEPEST_DEPTHS = 0x291,
+ NOUN_ROLODEX = 0x292,
+ NOUN_MONA_TISA = 0x293,
+ NOUN_ABSTRACT_ART = 0x294,
+ NOUN_SPACE_QUESTING_VIII = 0x295,
+ NOUN_THEATRICAL_ART = 0x296,
+ NOUN_METAL_POLE = 0x297,
+ NOUN_EXIT = 0x298,
+ NOUN_SWIRLING_LIGHT = 0x299,
+ NOUN_REGISTER = 0x29A,
+ NOUN_PEACHY_BUNS = 0x29B,
+ NOUN_OUR_TOWN = 0x29C,
+ NOUN_EMBROIDERED_ART = 0x29D,
+ NOUN_GEORGE_BUSH_ALIKE = 0x29E,
+ NOUN_COUNTER = 0x29F,
+ NOUN_SENSOR = 0x2A0,
+ NOUN_SOFTWARE_INFORMATION = 0x2A1,
+ NOUN_WALK_BEHIND = 0x2A2,
+ NOUN_BARGAINS = 0x2A3,
+ NOUN_SCAN_LIGHT = 0x2A4,
+ NOUN_OLD_SOFTWARE_STAND = 0x2A5,
+ NOUN_SOFTWARE_SHELF = 0x2A6,
+ NOUN_HOTTEST_SOFTWARE = 0x2A7,
+ NOUN_GREAT_PAINTBALL_ART = 0x2A8,
+ NOUN_SCENIC_VISTA = 0x2A9,
+ NOUN_LASER = 0x2AA,
+ NOUN_LASER_JET = 0x2AB,
+ NOUN_LEVER = 0x2AC,
+ NOUN_BULLSEYE = 0x2AD,
+ NOUN_STAND = 0x2AE,
+ NOUN_CONTROL_STATION = 0x2AF,
+ NOUN_STRANGE_MONSTER = 0x2B0,
+ NOUN_GHASTLY_BEAST = 0x2B1,
+ //NOUN_GAWK_AT = 0x2B2,
+ NOUN_CORRIDOR_TO_SOUTH = 0x2B3,
+ NOUN_CORRIDOR_TO_NORTH = 0x2B4,
+ NOUN_WALK_ONTO = 0x2B5,
+ NOUN_ROCK_WALL = 0x2B6,
+ NOUN_WOMAN = 0x2B7,
+ NOUN_WOMEN = 0x2B8,
+ NOUN_CORRIDOR_TO_EAST = 0x2B9,
+ NOUN_CORRIDOR_TO_WEST = 0x2BA,
+ NOUN_AMMUNITION = 0x2BB,
+ NOUN_ARMORED_VEHICLE = 0x2BC,
+ NOUN_TOMATO = 0x2BD,
+ NOUN_MISSILE = 0x2BE,
+ NOUN_SUIT_OF_ARMOR = 0x2BF,
+ NOUN_POWDER_CONTAINER = 0x2C0,
+ NOUN_INFLATABLE_RAFT = 0x2C1,
+ NOUN_GRENADE = 0x2C2,
+ NOUN_FENCE = 0x2C3,
+ NOUN_WOODEN_STATUE = 0x2C4,
+ NOUN_CONVEYER_BELT = 0x2C5,
+ NOUN_CONTROLS = 0x2C6,
+ NOUN_EQUIPMENT = 0x2C7,
+ NOUN_SHELF = 0x2C8,
+ NOUN_CABINETS = 0x2C9,
+ NOUN_CONTROL_CONSOLE = 0x2CA,
+ NOUN_FAUCET = 0x2CB,
+ NOUN_PANEL_BOX = 0x2CC,
+ NOUN_STATUE = 0x2CD,
+ NOUN_GAUGE = 0x2CE,
+ NOUN_CIRCUIT_PANEL = 0x2CF,
+ NOUN_CATWALK = 0x2D0,
+ NOUN_CIRCUITS = 0x2D1,
+ NOUN_BLOOD_STAIN = 0x2D2,
+ NOUN_GRATE = 0x2D3,
+ NOUN_AIR_SHAFT = 0x2D4,
+ //NOUN_RETURN_TO = 0x2D5,
+ NOUN_FORMALDEHYDE = 0x2D6,
+ NOUN_PETROX = 0x2D7,
+ NOUN_SODIUM_BENZOATE = 0x2D8,
+ NOUN_GURNEY = 0x2D9,
+ NOUN_IRONING_BOARD = 0x2DA,
+ NOUN_LEFT_MONITOR = 0x2DB,
+ NOUN_RIGHT_MONITOR = 0x2DC,
+ NOUN_RED_BUTTON = 0x2DD,
+ NOUN_GREEN_BUTTON = 0x2DE,
+ NOUN_RIGHT_ONE_KEY = 0x2DF,
+ NOUN_RIGHT_1_KEY = 0x2E0,
+ NOUN_RIGHT_2_KEY = 0x2E1,
+ NOUN_RIGHT_3_KEY = 0x2E2,
+ NOUN_RIGHT_4_KEY = 0x2E3,
+ NOUN_RIGHT_5_KEY = 0x2E4,
+ NOUN_RIGHT_6_KEY = 0x2E5,
+ NOUN_RIGHT_7_KEY = 0x2E6,
+ NOUN_RIGHT_8_KEY = 0x2E7,
+ NOUN_LEFT_1_KEY = 0x2E8,
+ NOUN_LEFT_2_KEY = 0x2E9,
+ NOUN_LEFT_3_KEY = 0x2EA,
+ NOUN_LEFT_4_KEY = 0x2EB,
+ NOUN_CORRIDOR_WALL = 0x2EC,
+ NOUN_MUG = 0x2ED,
+ NOUN_DOUGHNUT = 0x2EE,
+ NOUN_SECURITY_STATION = 0x2EF,
+ NOUN_NEWSPAPER = 0x2F0,
+ NOUN_MAGAZINE = 0x2F1,
+ NOUN_CLIPBOARD = 0x2F2,
+ NOUN_PAPER_FOOTBALL = 0x2F3,
+ NOUN_YOUR_STUFF = 0x2F4,
+ NOUN_OTHER_STUFF = 0x2F5,
+ NOUN_LAMP = 0x2F6,
+ NOUN_CLIMB_INTO = 0x2F7,
+ NOUN_LIGHT_BULB = 0x2F8,
+ //NOUN_STEP_INTO = 0x2F9,
+ NOUN_ROOM = 0x2FA,
+ //NOUN_CRAWL_TO = 0x2FB,
+ NOUN_FOURTH_CELL = 0x2FC,
+ NOUN_THIRD_CELL = 0x2FD,
+ NOUN_SECOND_CELL = 0x2FE,
+ NOUN_FIRST_CELL = 0x2FF,
+ NOUN_EQUIPMENT_ROOM = 0x300,
+ //NOUN_CRAWL_DOWN = 0x301,
+ NOUN_DESCENDING_SHAFT = 0x302,
+ NOUN_SAUROPOD = 0x303,
+ NOUN_MONSTER = 0x304,
+ NOUN_FAKE_ID = 0x305,
+ NOUN_ALIEN_LIQUOR = 0x306,
+ NOUN_INTERN = 0x307,
+ NOUN_INSTRUMENT_TABLE = 0x308,
+ NOUN_WOMAN_ON_BALCONY = 0x309,
+ NOUN_WOMAN_IN_CHAIR = 0x30A,
+ //NOUN_SIT_ON = 0x30B,
+ NOUN_WOMAN_IN_ALCOVE = 0x30C,
+ NOUN_KETTLE = 0x30D,
+ NOUN_BARTENDER = 0x30E,
+ NOUN_WHISKEY = 0x30F,
+ NOUN_ALCOHOL = 0x310,
+ NOUN_RIM = 0x311,
+ //NOUN_WALK_ALONG = 0x312,
+ NOUN_SUBMERGED_CITY = 0x313,
+ NOUN_GOVERNORS_HOUSE = 0x314,
+ NOUN_RIM_TOWARDS_EAST = 0x315,
+ NOUN_CEMENT_PYLON = 0x316,
+ NOUN_ELEVATOR = 0x317,
+ NOUN_ELEVATOR_SHAFT = 0x318,
+ NOUN_CONVEYOR_BELT = 0x319,
+ NOUN_CANNON_BALLS = 0x31A,
+ NOUN_ELECTRICAL_OVERHANG = 0x31B,
+ NOUN_GUTTER_PIPE = 0x31C,
+ NOUN_SIDEWALK = 0x31D,
+ NOUN_STREET = 0x31E,
+ NOUN_BARRICADE = 0x31F,
+ NOUN_DOOR_CONTROL_SLOT = 0x320,
+ NOUN_STREET_TO_EAST = 0x321,
+ NOUN_SIDEWALK_TO_EAST = 0x322,
+ NOUN_BUILDING = 0x323,
+ NOUN_CAR = 0x324,
+ //NOUN_GET_INSIDE = 0x325,
+ NOUN_MARQUEE = 0x326,
+ NOUN_BUILDING_ENTRANCE = 0x327,
+ NOUN_GUARD_STATION = 0x328,
+ NOUN_TECHNICAL_EQUIPMENT = 0x329,
+ NOUN_GUARD_TURRET = 0x32A,
+ NOUN_PILLAR = 0x32B,
+ NOUN_PAPERS = 0x32C,
+ NOUN_FILE_CABINET = 0x32D,
+ NOUN_WINDOWS = 0x32E,
+ //NOUN_WALK = 0x32F,
+ NOUN_STORAGE_BOX = 0x330,
+ NOUN_WATER_COOLER = 0x331,
+ NOUN_BOX = 0x332,
+ NOUN_RIFLES = 0x333,
+ NOUN_SLINGSHOT = 0x334,
+ NOUN_MAUSOLEUM = 0x335,
+ NOUN_SOFTWARE_STORE = 0x336,
+ NOUN_CONCRETE_BUILDING = 0x337,
+ NOUN_HUMONGOUS_MONITOR = 0x338,
+ NOUN_SPACE_BIKE = 0x339,
+ NOUN_BILLBOARD = 0x33A,
+ NOUN_LACK_OF_NOOKIE_MOTEL = 0x33B,
+ NOUN_BIDETS_XCREETZA_HUT = 0x33C,
+ NOUN_BUILDINGS = 0x33D,
+ NOUN_SKYSCRAPER = 0x33E,
+ NOUN_SOFTWARE_LOGO = 0x33F,
+ NOUN_GIANT_TELESCOPE = 0x340,
+ NOUN_HANDLE = 0x341,
+ NOUN_HOLE = 0x342,
+ NOUN_LASER_BEAM = 0x343,
+ NOUN_PEDESTAL = 0x344,
+ NOUN_BOAT = 0x345,
+ NOUN_GIANT_MONUMENT = 0x346,
+ NOUN_ROPE = 0x347,
+ NOUN_SAND_BAR_RESTAURANT = 0x348,
+ NOUN_PORTHOLE = 0x349,
+ NOUN_TICKET_BOOTH = 0x34A,
+ NOUN_POLLYS_ENTRANCE = 0x34B,
+ NOUN_RESTAURANT_ENTRANCE = 0x34C,
+ NOUN_THE_PLEASURE_DOME = 0x34D,
+ NOUN_STARFISH = 0x34E,
+ NOUN_FLIPPER = 0x34F,
+ NOUN_SAND_DOLLAR = 0x350,
+ NOUN_SHELL = 0x351,
+ NOUN_GUEST_LIST = 0x352,
+ NOUN_WEIRD_ANIMAL_HEAD = 0x353,
+ NOUN_SHIPS_WHEEL = 0x354,
+ NOUN_HANDICAP_SIGN = 0x355,
+ NOUN_ELEVATOR_CONTROLS = 0x356,
+ NOUN_BRICK_WALL = 0x357,
+ NOUN_BIKE_RACK = 0x358,
+ NOUN_ODONALDS_SIGN = 0x359,
+ NOUN_ELEVATOR_ENTRANCE = 0x35A,
+ NOUN_SPECIAL_SALE_SIGN = 0x35B,
+ NOUN_ATTORNEYS_AT_LAW = 0x35C,
+ NOUN_SLEDGE_MALL = 0x35D,
+ NOUN_SKELETON = 0x35E,
+ NOUN_STRANGE_EQUIPMENT = 0x35F,
+ NOUN_STREET_TO_WEST = 0x360,
+ NOUN_SIDEWALK_TO_WEST = 0x361,
+ NOUN_TELEPORTER_ENTRANCE = 0x362,
+ NOUN_SOFTWARE_DOOR = 0x363,
+ NOUN_SPINACH_PATCH_DOLL = 0x364,
+ //NOUN_REFLECT = 0x365,
+ NOUN_REGISTER_DRAWER = 0x366,
+ NOUN_ELEVATOR_DOOR = 0x367,
+ NOUN_HYDRAULIC_SUPPORT = 0x368,
+ NOUN_EQUIPMENT_OVERHEAD = 0x369,
+ //NOUN_GET_INTO = 0x36A,
+ NOUN_WARNING_LABEL = 0x36B,
+ NOUN_NUCLEAR_SLINGSHOT = 0x36C,
+ NOUN_DISPLAY_CASE = 0x36D,
+ NOUN_PHOTON_RIFLES = 0x36E,
+ NOUN_MONITORING_EQUIPMENT = 0x36F,
+ NOUN_TELESCOPE = 0x370,
+ NOUN_MOTEL = 0x371,
+ NOUN_RESTAURANT = 0x372,
+ NOUN_SOFTWARE_STORE_SIGN = 0x373,
+ NOUN_ADVERTISING_POSTER = 0x374,
+ NOUN_ADVERTISEMENT = 0x375,
+ NOUN_OLD_SOFTWARE = 0x376,
+ NOUN_CASH_REGISTER = 0x377,
+ NOUN_ENTRANCE = 0x378,
+ NOUN_LASER_CANNON = 0x379,
+ NOUN_SAND_BAGS = 0x37A,
+ NOUN_PLEASURE_DOME = 0x37B,
+ NOUN_DOME_ENTRANCE = 0x37C,
+ NOUN_LABORATORY = 0x37D,
+ NOUN_STREET_TO_SOUTH = 0x37E,
+ NOUN_ELEVATOR_ACCESS_SLOT = 0x37F,
+ NOUN_CAR_CONTROLS = 0x380,
+ NOUN_SCENT_PACKET = 0x381,
+ NOUN_KITTY = 0x382,
+ NOUN_GLOVE_COMPARTMENT = 0x383,
+ NOUN_MOLDY_SOCK = 0x384,
+ NOUN_SODA_CANS = 0x385,
+ NOUN_WINDSHIELD = 0x386,
+ NOUN_DASHBOARD = 0x387,
+ NOUN_INTERIOR_OF_CAR = 0x388,
+ NOUN_VIEW_RIGHT_BUTTON = 0x389,
+ NOUN_BLACK_BUTTON = 0x38A,
+ NOUN_WHITE_BUTTON = 0x38B,
+ NOUN_INSIDE_OF_CAR = 0x38C,
+ NOUN_RIM_TOWARDS_WEST = 0x38D,
+ NOUN_CEMENT_BLOCK = 0x38E,
+ NOUN_CITY = 0x38F,
+ NOUN_SPEAKER = 0x390,
+ NOUN_EYE_CHART = 0x391,
+ NOUN_LAUNCH_PAD = 0x392,
+ NOUN_BUILDING_TO_WEST = 0x393,
+ NOUN_PAD_TO_EAST = 0x394,
+ NOUN_PAD_TO_WEST = 0x395,
+ NOUN_TOWER = 0x396,
+ NOUN_LOOK_OUT = 0x397,
+ NOUN_SERVICE_PANEL = 0x398,
+ NOUN_CRACK = 0x399,
+ NOUN_THROTTLE = 0x39A,
+ NOUN_GRAB = 0x39B,
+ NOUN_INSTRUMENTATION = 0x39C,
+ NOUN_TP = 0x39D,
+ NOUN_SEAT = 0x39E,
+ NOUN_STATUS_PANEL = 0x39F,
+ NOUN_SHIPS_CONTROLS = 0x3A0,
+ NOUN_PROFESSOR = 0x3A1,
+ NOUN_PROFESSORS_GURNEY = 0x3A2,
+ NOUN_WELCOME_MAT = 0x3A3,
+ NOUN_MELON_MUSH = 0x3A4,
+ NOUN_BADMINTON_BRAT = 0x3A5,
+ //NOUN_APPLY = 0x3A6,
+ NOUN_COMBINATION = 0x3A7,
+ NOUN_NOTE = 0x3A8,
+ NOUN_LECITHIN = 0x3A9,
+ NOUN_REPAIR_WOMAN = 0x3AA,
+ NOUN_EXPLOSIVES = 0x3AB,
+ NOUN_DOLLOP = 0x3AC,
+ NOUN_DROP = 0x3AD,
+ NOUN_DASH = 0x3AE,
+ NOUN_SPLASH = 0x3AF,
+ NOUN_DOCK_TO_SOUTH = 0x3B0,
+ NOUN_STEER_TOWARDS = 0x3B1,
+ NOUN_BUILDING_TO_NORTH = 0x3B2,
+ NOUN_VOLCANO_RIM = 0x3B3,
+ NOUN_OPEN_WATER_TO_SOUTH = 0x3B4,
+ NOUN_PROJECTOR = 0x3B5,
+ NOUN_GUARDS_ARM2 = 0x3B6,
+ //NOUN_NIBBLE_ON = 0x3B7,
+ //NOUN_ENTER = 0x3B8,
+ NOUN_ = 0x3B9,
+ NOUN_TIMER_BUTTON_1 = 0x3BA,
+ NOUN_REMOTE_BUTTON_1 = 0x3BB,
+ NOUN_START_BUTTON_2 = 0x3BC,
+ NOUN_REMOTE_BUTTON_2 = 0x3BD,
+ NOUN_TIMER_BUTTON_2 = 0x3BE,
+ NOUN_START_BUTTON_1 = 0x3BF,
+ NOUN_ANTIGRAV_CONTROLS = 0x3C0,
+ NOUN_BRUCES_TREE = 0x3C1,
+ NOUN_COLISEUM = 0x3C2,
+ NOUN_BRUCES_GARDEN_ROOM = 0x3C3,
+ NOUN_FOUNTAIN = 0x3C4,
+ NOUN_HOUSE_OF_BRUCE = 0x3C5,
+ NOUN_CITY_BACKDROP = 0x3C6,
+ NOUN_BRUCES_BALCONY = 0x3C7,
+ NOUN_BRUCES_ENTRANCE = 0x3C8,
+ NOUN_BRUCES_LOGO = 0x3C9,
+ NOUN_LOUNGE_CHAIR = 0x3CA,
+ NOUN_LIVING_ROOM_FLOOR = 0x3CB,
+ NOUN_LIVINGROOM_FLOOR = 0x3CC,
+ NOUN_PERFUME_BOTTLE = 0x3CD,
+ NOUN_COOL_NEON_LIGHT = 0x3CE,
+ NOUN_FLOWER_POT = 0x3CF,
+ NOUN_COFFEE_TABLE = 0x3D0,
+ NOUN_FLOWERS = 0x3D1,
+ NOUN_ART_DECO_CHAIR = 0x3D2,
+ NOUN_SAFE = 0x3D3,
+ NOUN_SPLASHY_DECOR = 0x3D4,
+ NOUN_THEATRICAL_FACES = 0x3D5,
+ NOUN_ART_DECO_PIECE = 0x3D6,
+ NOUN_END_OF_ROOM = 0x3D7,
+ NOUN_FIREPLACE = 0x3D8,
+ NOUN_ARTWORK = 0x3D9,
+ NOUN_COOL_NEON_LIGHTS = 0x3DA,
+ NOUN_GLASS_PLATED_WINDOW = 0x3DB,
+ NOUN_BEDROOM_FLOOR = 0x3DC,
+ NOUN_BAUBLE = 0x3DD,
+ NOUN_SNAPSHOT = 0x3DE,
+ NOUN_PERFUME = 0x3DF,
+ NOUN_CLAPBOARD = 0x3E0,
+ NOUN_BERET = 0x3E1,
+ NOUN_HORSE_WHIP = 0x3E2,
+ NOUN_CORNER_TABLE = 0x3E3,
+ NOUN_BOA = 0x3E4,
+ NOUN_WIG_STAND = 0x3E5,
+ NOUN_PARTITION = 0x3E6,
+ NOUN_MEGAPHONE = 0x3E7,
+ NOUN_SLIP = 0x3E8,
+ NOUN_SCONCE = 0x3E9,
+ NOUN_VANITY = 0x3EA,
+ NOUN_BEDBOARD = 0x3EB,
+ NOUN_LOVE_SEAT = 0x3EC,
+ NOUN_SOUVENIR_TICKETS = 0x3ED,
+ NOUN_REVIEW = 0x3EE,
+ NOUN_BRUCE_AT_THE_GALA = 0x3EF,
+ NOUN_ART_DECO_RUG = 0x3F0,
+ NOUN_LIVINGROOM = 0x3F1,
+ NOUN_SCULPTURE = 0x3F2,
+ NOUN_SPECIMEN_EPITHET = 0x3F3,
+ NOUN_VENT = 0x3F4,
+ NOUN_FLOWER_BOX = 0x3F5,
+ NOUN_LEDGE = 0x3F6,
+ NOUN_BOLT = 0x3F7,
+ NOUN_OBSERVATION_WINDOW = 0x3F8,
+ NOUN_AIR_HOSE = 0x3F9,
+ NOUN_AUTO_SHOP = 0x3FA,
+ NOUN_MANHOLE = 0x3FB,
+ NOUN_AUTO_SHOP_ENTRANCE = 0x3FC,
+ NOUN_BROKEN_WINDOW = 0x3FD,
+ NOUN_WOMANHOLE = 0x3FE,
+ NOUN_GARAGE_DOOR = 0x3FF,
+ NOUN_SCRATCH_PAD = 0x400,
+ NOUN_GAS_PRICES = 0x401,
+ NOUN_UP_BUTTON = 0x402,
+ NOUN_DOWN_BUTTON = 0x403,
+ NOUN_SPARE_PARTS_LIST = 0x404,
+ NOUN_SKYLIGHT = 0x405,
+ NOUN_TOOL_BOX = 0x406,
+ NOUN_CAR_LIFT = 0x407,
+ NOUN_CAR_SEAT = 0x408,
+ NOUN_GARAGE_FLOOR = 0x409,
+ NOUN_GARAGE_DOOR_CONTROLS = 0x40A,
+ NOUN_AMISH_HAT = 0x40B,
+ NOUN_JACK = 0x40C,
+ NOUN_COILS = 0x40D,
+ NOUN_OIL_CAN = 0x40E,
+ NOUN_FAN_BELTS = 0x40F,
+ NOUN_REAR_OF_GARAGE = 0x410,
+ NOUN_FRONT_OF_GARAGE = 0x411,
+ NOUN_MUFFLER = 0x412,
+ NOUN_SPARE_PART = 0x413,
+ NOUN_HUBCAP = 0x414,
+ NOUN_CANDLE = 0x415,
+ NOUN_RATES = 0x416,
+ NOUN_GREASE_CAN = 0x417,
+ NOUN_CALENDAR = 0x418,
+ NOUN_FORK_LIFT = 0x419,
+ NOUN_TRASH_CAN = 0x41A,
+ NOUN_SHAKER_CHAIR = 0x41B,
+ NOUN_QUARTER_PANEL = 0x41C,
+ NOUN_AREA_BEHIND_CAR = 0x41D,
+ NOUN_DANGER_ZONE = 0x41E,
+ NOUN_NEWSSTAND = 0x41F,
+ NOUN_LADY_GODIVA_MONUMENT = 0x420,
+ NOUN_SPOT_A_POT = 0x421,
+ NOUN_GUARD_RAIL = 0x422,
+ NOUN_ALLEY = 0x423,
+ NOUN_DITCH = 0x424,
+ NOUN_VIDEO_STORE_DOOR = 0x425,
+ NOUN_BUCKLUSTER_MARQUEE = 0x426,
+ NOUN_VIDEO_STORE = 0x427,
+ NOUN_HORMONE_BILLBOARD = 0x428,
+ NOUN_PHONE_ANTENNA = 0x429,
+ NOUN_RETURN_SLOT = 0x42A,
+ NOUN_NOOSE = 0x42B,
+ NOUN_COMEDY_VIDEOS = 0x42C,
+ NOUN_SMELLY_SNEAKER = 0x42D,
+ NOUN_PIPPYS_STOCKING = 0x42E,
+ NOUN_PHONE_CRADLE = 0x42F,
+ NOUN_DRAMA_VIDEOS = 0x430,
+ NOUN_SPOTLIGHT = 0x431,
+ NOUN_STOREROOM_FLOOR = 0x432,
+ NOUN_ALL_SALES_FINAL = 0x433,
+ NOUN_MACHOPROSE_TEE_SHIRT = 0x434,
+ NOUN_UNKNOWN_COMIC_HANDS = 0x435,
+ NOUN_WET_CEMENT = 0x436,
+ NOUN_PIPPYS_TINY_IMPRINT = 0x437,
+ NOUN_OBNOXIOUS_DOG_PAWS = 0x438,
+ NOUN_LEG_AND_A_LEG_JEANS = 0x439,
+ NOUN_VIDEO_STORE_EXIT = 0x43A,
+ NOUN_AISLE = 0x43B,
+ NOUN_VIDEO_MONITOR = 0x43C,
+ NOUN_POLLY_PIGS_IMPRINT = 0x43D,
+ NOUN_JOHN_WYNNS_IMPRINT = 0x43E,
+ NOUN_MR_NEDS_IMPRINT = 0x43F,
+ NOUN_PEG_LEG_PETE_IMPRINT = 0x440,
+ NOUN_MARX_BROS_POSTER = 0x441,
+ NOUN_PIPPY_BILLBOARD = 0x442,
+ NOUN_VIDEOS_NOONE_WANTS = 0x443,
+ NOUN_MORE_CLASSIC_VIDEOS = 0x444,
+ NOUN_JOIN_OUR_PRICE_CLUB = 0x445,
+ NOUN_EDUCATIONAL_VIDEOS = 0x446,
+ NOUN_DEEP_DISCOUNT_TITLES = 0x447,
+ NOUN_WORLD_CHAMPS_POSTER = 0x448,
+ NOUN_WORKOUT_VIDEOS = 0x449,
+ NOUN_20_PERCENT_OFF_SIGN = 0x44A,
+ NOUN_CIVILIZATION_AD = 0x44B,
+ NOUN_NEW_RELEASE_VIDEOS = 0x44C,
+ NOUN_PORNO_VIDEOS = 0x44D,
+ NOUN_FOREIGN_VIDEOS = 0x44E,
+ NOUN_CLASSIC_VIDEOS = 0x44F,
+ NOUN_ADVENTURE_VIDEOS = 0x450,
+ NOUN_BUCKLUSTER_LOGO = 0x451,
+ NOUN_WINE_BOTTLE = 0x452,
+ NOUN_DIRT_PILE = 0x453,
+ NOUN_MAMMOTH_PENCIL_HEAD = 0x454,
+ NOUN_WREAKY_PUMPKIN = 0x455,
+ NOUN_MILK_CARTON = 0x456,
+ NOUN_BUCKET = 0x457,
+ NOUN_EMPTY_BOX = 0x458,
+ NOUN_DIAPER_BOX = 0x459,
+ NOUN_HERMIT = 0x45A,
+ NOUN_METAL_PIPE = 0x45B,
+ NOUN_CONCRETE_SUPPORT = 0x45C,
+ NOUN_VARIOUS_TRASH = 0x45D,
+ NOUN_ARMATURE = 0x45E,
+ NOUN_CONTROL_BOX = 0x45F,
+ NOUN_TOP_OF_DOME = 0x460,
+ NOUN_EXPRESSWAY_TO_EAST = 0x461,
+ NOUN_GO_TOWARDS = 0x462,
+ NOUN_EXPRESSWAY_TO_WEST = 0x463,
+ NOUN_DOME = 0x464,
+ NOUN_VIEW_OF_CITY = 0x465,
+ NOUN_EXPRESSWAY = 0x466,
+ NOUN_HOOK = 0x467,
+ NOUN_SEA_MONSTER = 0x468,
+ NOUN_EDGE_OF_VOLCANO = 0x469,
+ NOUN_JUMP_THROUGH = 0x46A,
+ NOUN_OLD_TEA_CUP = 0x46B,
+ NOUN_NAME_PLATE = 0x46C,
+ NOUN_OLD_VASE = 0x46D,
+ NOUN_PORTRAIT = 0x46E,
+ NOUN_PUT_DOWN = 0x46F,
+ NOUN_TALL_BUILDING = 0x470,
+ NOUN_OBNOXIOUS_DOG = 0x471,
+ NOUN_GUTS = 0x472,
+ NOUN_BIG_HEADS = 0x473,
+ NOUN_INSTALL = 0x474,
+ NOUN_LIFE_SUPPORT_MODULE = 0x475,
+ NOUN_REMOVE = 0x476,
+ NOUN_LARGE_BLADE = 0x477,
+ NOUN_SIDE_ENTRANCE = 0x478,
+ NOUN_INDICATOR = 0x479,
+ NOUN_SIGNPOST = 0x47A,
+ NOUN_PIN = 0x47B,
+ NOUN_POWDER_PUFF = 0x47C,
+ NOUN_SHELVES = 0x47D,
+ NOUN_ELECTRODES = 0x47E,
+ NOUN_MISHAP2 = 0x47F,
+ NOUN_ISLD_SUPERSTRUCTURE = 0x480,
+ NOUN_FILE_CABINETS = 0x481,
+ NOUN_CYCLE_SHOP = 0x482,
+ NOUN_AIR_BIKE = 0x483,
+ NOUN_EMERGENCY_LIGHT = 0x484,
+ NOUN_TARGET_AREA = 0x485,
+ NOUN_ICE_CHESTS = 0x486,
+ NOUN_BIRDS = 0x487,
+ NOUN_DOCTORS_OFFICE = 0x488,
+ NOUN_DEFACE = 0x489,
+ NOUN_LARGE_HEADS = 0x48A,
+ NOUN_SMALL_TABLE = 0x48B,
+ NOUN_COLLOSSEUM = 0x48C,
+ NOUN_HOUSE = 0x48D,
+ NOUN_BALCONY = 0x48E,
+ NOUN_GARDEN_ROOM = 0x48F,
+ NOUN_COVE_LIGHTS = 0x490,
+ NOUN_MASKS = 0x491,
+ NOUN_NEON_LIGHTS = 0x492,
+ NOUN_GLASS_BLOCK_WALL = 0x493,
+ NOUN_SCREEN = 0x494,
+ NOUN_SPARE_RIBS = 0x495,
+ NOUN_BANNER = 0x496,
+ NOUN_INSTRUCTIONAL_VIDEOS = 0x497,
+ NOUN_CEMENT = 0x498,
+ NOUN_STORE = 0x499,
+ NOUN_CARDBOARD_BOX = 0x49A,
+ NOUN_GRAFFITTI = 0x49B,
+ NOUN_GRAFFITI = 0x49C,
+ NOUN_PHOTOGRAPH = 0x49D,
+ NOUN_DIRECTORS_SLATE = 0x49E,
+ NOUN_CROP = 0x49F,
+ NOUN_HAT = 0x4A0,
+ NOUN_LOGO = 0x4A1,
+ NOUN_MAINTENANCE_BUILDING = 0x4A2,
+ NOUN_MASSAGE = 0x4A3,
+ NOUN_MANGLE = 0x4A4,
+ NOUN_RUB = 0x4A5,
+ NOUN_JUGGLE = 0x4A6,
+ NOUN_SMASH = 0x4A7,
+ NOUN_GUZZLE = 0x4A8,
+ NOUN_WEST_END_OF_PLATFORM = 0x4A9,
+ NOUN_EAST_END_OF_PLATFORM = 0x4AA,
+ NOUN_FOLD = 0x4AB,
+ NOUN_SPINDLE = 0x4AC
+ //NOUN_MUTILATE = 0x4AD
+};
+
+class SceneFactory {
+public:
+ static SceneLogic *createScene(MADSEngine *vm);
+};
+
+/**
+ * Specialized base class for Rex Nebular game scenes
+ */
+class NebularScene : public SceneLogic {
+protected:
+ NebularGlobals &_globals;
+ GameNebular &_game;
+ MADSAction &_action;
+
+ /**
+ * Forms an animation resource name
+ */
+ Common::String formAnimName(char sepChar, int suffixNum);
+
+ /**
+ * Plays appropriate sound for entering various rooms
+ */
+ void lowRoomsEntrySound();
+public:
+ /**
+ * Constructor
+ */
+ NebularScene(MADSEngine *vm);
+
+ void sub7178C();
+};
+
+class SceneInfoNebular : public SceneInfo {
+ friend class SceneInfo;
+protected:
+ virtual void loadCodes(MSurface &depthSurface, int variant);
+
+ virtual void loadCodes(MSurface &depthSurface, Common::SeekableReadStream *stream);
+
+ /**
+ * Constructor
+ */
+ SceneInfoNebular(MADSEngine *vm) : SceneInfo(vm) {}
+};
+
+class SceneTeleporter : public NebularScene {
+protected:
+ int _buttonTyped;
+ int _curCode;
+ int _digitCount;
+ int _curMessageId;
+ int _handSpriteId;
+ int _handSequenceId;
+ int _finishedCodeCounter;
+ int _meteorologistNextPlace;
+ int _meteorologistCurPlace;
+ int _teleporterSceneId;
+ Common::String _msgText;
+
+ int teleporterAddress(int code, bool working);
+
+ void teleporterHandleKey();
+ Common::Point teleporterComputeLocation();
+ void teleporterEnter();
+ bool teleporterActions();
+ void teleporterStep();
+
+protected:
+ /**
+ * Constructor
+ */
+ SceneTeleporter(MADSEngine *vm) : NebularScene(vm) {}
+};
+
+} // End of namespace Nebular
+} // End of namespace MADS
+
+#endif /* MADS_NEBULAR_SCENES_H */
diff --git a/engines/mads/nebular/nebular_scenes1.cpp b/engines/mads/nebular/nebular_scenes1.cpp
new file mode 100644
index 0000000000..cd3b90089e
--- /dev/null
+++ b/engines/mads/nebular/nebular_scenes1.cpp
@@ -0,0 +1,3168 @@
+/* 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 "mads/mads.h"
+#include "mads/scene.h"
+#include "mads/nebular/nebular_scenes.h"
+#include "mads/nebular/nebular_scenes1.h"
+
+namespace MADS {
+
+namespace Nebular {
+
+void Scene1xx::setAAName() {
+ int idx = (_scene->_nextSceneId > 103 && _scene->_nextSceneId < 112) ? 1 : 0;
+ _game._aaName = Resources::formatAAName(idx);
+}
+
+void Scene1xx::sceneEntrySound() {
+ if (_vm->_musicFlag) {
+ switch (_scene->_nextSceneId) {
+ case 101:
+ _vm->_sound->command(11);
+ break;
+ case 102:
+ _vm->_sound->command(12);
+ break;
+ case 103:
+ _vm->_sound->command(3);
+ _vm->_sound->command(25);
+ break;
+ case 109:
+ _vm->_sound->command(13);
+ break;
+ case 110:
+ _vm->_sound->command(10);
+ break;
+ case 111:
+ _vm->_sound->command(3);
+ break;
+ case 112:
+ _vm->_sound->command(15);
+ break;
+ default:
+ if (_scene->_priorSceneId < 104 || _scene->_priorSceneId > 108)
+ _vm->_sound->command(10);
+ break;
+ }
+ }
+}
+
+void Scene1xx::setPlayerSpritesPrefix() {
+ _vm->_sound->command(5);
+ Common::String oldName = _game._player._spritesPrefix;
+ if (_scene->_nextSceneId <= 103 || _scene->_nextSceneId == 111) {
+ if (_globals[kSexOfRex] == SEX_FEMALE)
+ _game._player._spritesPrefix = "ROX";
+ else {
+ _game._player._spritesPrefix = "RXM";
+ _globals[kSexOfRex] = SEX_MALE;
+ }
+ } else if (_scene->_nextSceneId <= 110) {
+ _game._player._spritesPrefix = "RXSW";
+ _globals[kSexOfRex] = SEX_UNKNOWN;
+ } else if (_scene->_nextSceneId == 112)
+ _game._player._spritesPrefix = "";
+
+ if (oldName == _game._player._spritesPrefix)
+ _game._player._spritesChanged = true;
+
+ if (_scene->_nextSceneId == 105 || (_scene->_nextSceneId == 109 && _globals[kHoovicAlive])) {
+ _game._player._spritesChanged = true;
+ _game._player._loadsFirst = false;
+ }
+
+ _game._player._trigger = 0;
+ _vm->_palette->setEntry(16, 10, 63, 63);
+ _vm->_palette->setEntry(17, 10, 45, 45);
+}
+
+/*------------------------------------------------------------------------*/
+
+Scene101::Scene101(MADSEngine *vm) : Scene1xx(vm) {
+ _sittingFl = false;
+ _panelOpened = false;
+ _messageNum = 0;
+ _posY = 0;
+ _shieldSpriteIdx = 0;
+ _chairHotspotId = 0;
+ _oldSpecial = 0;
+}
+
+void Scene101::synchronize(Common::Serializer &s) {
+ Scene1xx::synchronize(s);
+
+ s.syncAsByte(_sittingFl);
+ s.syncAsByte(_panelOpened);
+ s.syncAsSint16LE(_messageNum);
+ s.syncAsSint16LE(_posY);
+ s.syncAsSint16LE(_shieldSpriteIdx);
+ s.syncAsSint16LE(_chairHotspotId);
+ s.syncAsSint16LE(_oldSpecial);
+}
+
+void Scene101::setup() {
+ _scene->_animationData->preLoad(formAnimName('A', -1), 3);
+ setPlayerSpritesPrefix();
+ setAAName();
+}
+
+void Scene101::sayDang() {
+ _game._triggerSetupMode = SEQUENCE_TRIGGER_DAEMON;
+ _game._player._stepEnabled = false;
+
+ switch (_game._trigger) {
+ case 0:
+ _scene->_sequences.remove(_globals._sequenceIndexes[11]);
+ _globals._sequenceIndexes[11] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[11], false, 3, 6, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[11], 17, 21);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[11], SEQUENCE_TRIGGER_EXPIRE, 0, 72);
+ _vm->_sound->command(17);
+ _globals._sequenceIndexes[8] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[8], false, 3, 2, 0, 0);
+ break;
+
+ case 72:
+ _globals._sequenceIndexes[11] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[11], false, 6, 0, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[11], 17, 17);
+ _scene->_kernelMessages.add(Common::Point(143, 61), 0x1110, 0, 0, 60, _game.getQuote(57));
+ _scene->_sequences.addTimer(120, 73);
+ break;
+
+ case 73:
+ _vm->_dialogs->show(10117);
+ _game._player._stepEnabled = true;
+ break;
+
+ default:
+ break;
+ }
+}
+
+void Scene101::enter() {
+ _globals._spriteIndexes[1] = _scene->_sprites.addSprites(formAnimName('x', 1));
+ _globals._spriteIndexes[2] = _scene->_sprites.addSprites(formAnimName('x', 2));
+ _globals._spriteIndexes[3] = _scene->_sprites.addSprites(formAnimName('x', 3));
+ _globals._spriteIndexes[4] = _scene->_sprites.addSprites(formAnimName('x', 4));
+ _globals._spriteIndexes[5] = _scene->_sprites.addSprites(formAnimName('x', 5));
+ _globals._spriteIndexes[6] = _scene->_sprites.addSprites(formAnimName('x', 6));
+ _globals._spriteIndexes[7] = _scene->_sprites.addSprites(formAnimName('x', 7));
+ _globals._spriteIndexes[8] = _scene->_sprites.addSprites(formAnimName('m', -1));
+ _globals._spriteIndexes[9] = _scene->_sprites.addSprites(formAnimName('b', 1));
+ _globals._spriteIndexes[10] = _scene->_sprites.addSprites(formAnimName('b', 2));
+ _globals._spriteIndexes[11] = _scene->_sprites.addSprites(formAnimName('a', 0));
+ _globals._spriteIndexes[12] = _scene->_sprites.addSprites(formAnimName('a', 1));
+ _globals._spriteIndexes[13] = _scene->_sprites.addSprites(formAnimName('x', 8));
+ _globals._spriteIndexes[14] = _scene->_sprites.addSprites(formAnimName('x', 0));
+
+ _globals._sequenceIndexes[1] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[1], false, 5, 0, 0, 25);
+ _globals._sequenceIndexes[2] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[2], false, 4, 0, 1, 0);
+ _globals._sequenceIndexes[3] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[3], false, 6, 0, 2, 0);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[3], SEQUENCE_TRIGGER_SPRITE, 7, 70);
+ _globals._sequenceIndexes[4] = _scene->_sequences.addReverseSpriteCycle(_globals._spriteIndexes[4], false, 10, 0, 0, 60);
+ _globals._sequenceIndexes[5] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[5], false, 5, 0, 1, 0);
+ _globals._sequenceIndexes[6] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[6], false, 10, 0, 2, 0);
+ _globals._sequenceIndexes[7] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[7], false, 6, 0, 0, 0);
+ _globals._sequenceIndexes[9] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[9], false, 6, 0, 10, 4);
+ _globals._sequenceIndexes[10] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[10], false, 6, 0, 32, 47);
+
+ _scene->_hotspots.activate(NOUN_SHIELD_MODULATOR, false);
+ _panelOpened = false;
+
+ // HACK: set the prior scene to 102 for now when the game starts, to avoid Rex's getting up animation
+ if (_scene->_priorSceneId == -1)
+ _scene->_priorSceneId = 102;
+
+ if (_scene->_priorSceneId != -1)
+ _globals[kNeedToStandUp] = false;
+
+ if (_scene->_priorSceneId != -2)
+ _game._player._playerPos = Common::Point(100, 152);
+
+ if ((_scene->_priorSceneId == 112) || ((_scene->_priorSceneId == -2) && _sittingFl )) {
+ _game._player._visible = false;
+ _sittingFl = true;
+ _game._player._playerPos = Common::Point(161, 123);
+ _game._player._facing = FACING_NORTHEAST;
+ _globals._sequenceIndexes[11] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[11], false, 3, 0, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[11], 17, 17);
+ _scene->_hotspots.activate(NOUN_CHAIR, false);
+ _chairHotspotId = _scene->_dynamicHotspots.add(NOUN_CHAIR, 0x13F, -1, Common::Rect(159, 84, 159 + 33, 84 + 36));
+ if (_scene->_priorSceneId == 112)
+ sayDang();
+ } else {
+ _globals._sequenceIndexes[12] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[12], false, 6, 0, 0, 0);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[12], 4);
+ }
+
+ _game.loadQuoteSet(0x31, 0x32, 0x39, 0x36, 0x37, 0x38, 0);
+
+ if (_globals[kNeedToStandUp]) {
+ _scene->loadAnimation(Resources::formatName(101, 'S', -1, EXT_AA, ""), 71);
+ _game._player._visible = false;
+ _game._player._stepEnabled = false;
+ _game._player._playerPos = Common::Point(68, 140);
+ _game._player._facing = FACING_WEST;
+
+ _messageNum = 0;
+ _posY = 30;
+ }
+
+ _oldSpecial = false;
+
+ sceneEntrySound();
+}
+
+void Scene101::step() {
+ if (_oldSpecial != _game._player._special) {
+ _oldSpecial = _game._player._special;
+ if (_oldSpecial)
+ _vm->_sound->command(39);
+ else
+ _vm->_sound->command(11);
+ }
+
+ switch (_game._trigger) {
+ case 70:
+ _vm->_sound->command(9);
+ break;
+
+ case 71:
+ _globals[kNeedToStandUp] = false;
+ _game._player._visible = true;
+ _game._player._stepEnabled = true;
+ _game._player._priorTimer = _scene->_frameStartTime - _game._player._ticksAmount;
+ break;
+
+ case 72:
+ case 73:
+ sayDang();
+ break;
+
+ default:
+ break;
+ }
+
+ if (_scene->_activeAnimation != nullptr) {
+ if ((_scene->_activeAnimation->getCurrentFrame() >= 6) && (_messageNum == 0)) {
+ _messageNum++;
+ _scene->_kernelMessages.add(Common::Point(63, _posY), 0x1110, 0, 0, 240, _game.getQuote(49));
+ _posY += 14;
+ }
+
+ if ((_scene->_activeAnimation->getCurrentFrame() >= 7) && (_messageNum == 1)) {
+ _messageNum++;
+ _scene->_kernelMessages.add(Common::Point(63, _posY), 0x1110, 0, 0, 240, _game.getQuote(54));
+ _posY += 14;
+ }
+
+ if ((_scene->_activeAnimation->getCurrentFrame() >= 10) && (_messageNum == 2)) {
+ _messageNum++;
+ _scene->_kernelMessages.add(Common::Point(63, _posY), 0x1110, 0, 0, 240, _game.getQuote(55));
+ _posY += 14;
+ }
+
+ if ((_scene->_activeAnimation->getCurrentFrame() >= 17) && (_messageNum == 3)) {
+ _messageNum++;
+ _scene->_kernelMessages.add(Common::Point(63, _posY), 0x1110, 0, 0, 240, _game.getQuote(56));
+ _posY += 14;
+ }
+
+ if ((_scene->_activeAnimation->getCurrentFrame() >= 20) && (_messageNum == 4)) {
+ _messageNum++;
+ _scene->_kernelMessages.add(Common::Point(63, _posY), 0x1110, 0, 0, 240, _game.getQuote(50));
+ _posY += 14;
+ }
+ }
+}
+
+void Scene101::preActions() {
+ if (_action.isAction(VERB_LOOK, NOUN_VIEW_SCREEN))
+ _game._player._needToWalk = true;
+
+ if (_sittingFl) {
+ if (_action.isAction(VERB_LOOK) || _action.isObject(NOUN_CHAIR) || _action.isAction(VERB_TALKTO) || _action.isAction(VERB_PEER_THROUGH) || _action.isAction(VERB_EXAMINE))
+ _game._player._needToWalk = false;
+
+ if (_game._player._needToWalk) {
+ switch (_game._trigger) {
+ case 0:
+ _game._player._readyToWalk = false;
+ _game._player._stepEnabled = false;
+ _scene->_sequences.remove(_globals._sequenceIndexes[11]);
+ _globals._sequenceIndexes[11] = _scene->_sequences.addReverseSpriteCycle(_globals._spriteIndexes[11], false, 3, 1, 0, 0);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[11], SEQUENCE_TRIGGER_EXPIRE, 0, 1);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[11], 1, 17);
+ _vm->_sound->command(16);
+ break;
+
+ case 1:
+ _sittingFl = false;
+ _game._player._visible = true;
+ _game._player._stepEnabled = true;
+ _game._player._readyToWalk = true;
+ _scene->_hotspots.activate(71, true);
+ _scene->_dynamicHotspots.remove(_chairHotspotId);
+ _globals._sequenceIndexes[12] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[12], false, 6, 0, 0, 0);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[12], 4);
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+
+ if (_panelOpened && !(_action.isObject(NOUN_SHIELD_ACCESS_PANEL) || _action.isObject(NOUN_SHIELD_MODULATOR))) {
+ switch (_game._trigger) {
+ case 0:
+ if (_game._player._needToWalk) {
+ _scene->_sequences.remove(_globals._sequenceIndexes[13]);
+ _shieldSpriteIdx = _game._objects.isInRoom(OBJ_SHIELD_MODULATOR) ? 13 : 14;
+ _globals._sequenceIndexes[13] = _scene->_sequences.addReverseSpriteCycle(_globals._spriteIndexes[_shieldSpriteIdx], false, 6, 1, 0, 0);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[13], SEQUENCE_TRIGGER_EXPIRE, 0, 1);
+ _game._player._stepEnabled = false;
+ _vm->_sound->command(20);
+ }
+ break;
+
+ case 1:
+ _game._player._stepEnabled = true;
+ _panelOpened = false;
+ _scene->_hotspots.activate(NOUN_SHIELD_MODULATOR, false);
+ break;
+
+ default:
+ break;
+ }
+ }
+}
+
+void Scene101::actions() {
+ if (_action._lookFlag) {
+ _vm->_dialogs->show(10125);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_WALKTO, NOUN_LIFE_SUPPORT_SECTION)) {
+ _scene->_nextSceneId = 102;
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_SIT_IN, NOUN_CHAIR) || (_action.isAction(VERB_LOOK, NOUN_VIEW_SCREEN) && !_sittingFl)) {
+ if (!_sittingFl) {
+ switch (_game._trigger) {
+ case 0:
+ _scene->_sequences.remove(_globals._sequenceIndexes[12]);
+ _globals._sequenceIndexes[11] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[11], false, 3, 1);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[11], 1, 17);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[11], SEQUENCE_TRIGGER_SPRITE, 10, 1);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[11], SEQUENCE_TRIGGER_EXPIRE, 0, 2);
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _action._inProgress = false;
+ return;
+
+ case 1:
+ _vm->_sound->command(16);
+ break;
+
+ case 2:
+ _globals._sequenceIndexes[11] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[11], false, 3, 0, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[11], 17, 17);
+ _game._player._stepEnabled = true;
+ _sittingFl = true;
+ _scene->_hotspots.activate(71, false);
+ _chairHotspotId = _scene->_dynamicHotspots.add(71, 0x13F, -1, Common::Rect(159, 84, 159 + 33, 84 + 36));
+ if (!_action.isAction(VERB_LOOK, NOUN_VIEW_SCREEN)) {
+ _action._inProgress = false;
+ return;
+ }
+ _game._trigger = 0;
+ break;
+
+ default:
+ break;
+ }
+ } else {
+ _vm->_dialogs->show(10131);
+ _action._inProgress = false;
+ return;
+ }
+ }
+
+ if ((_action.isAction(VERB_WALKTO, NOUN_SHIELD_ACCESS_PANEL) || _action.isAction(VERB_OPEN, NOUN_SHIELD_ACCESS_PANEL)) && !_panelOpened) {
+ switch (_game._trigger) {
+ case 0:
+ _shieldSpriteIdx = _game._objects.isInRoom(OBJ_SHIELD_MODULATOR) ? 13 : 14;
+ _globals._sequenceIndexes[13] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[_shieldSpriteIdx], false, 6, 1, 0, 0);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[13], SEQUENCE_TRIGGER_EXPIRE, 0, 1);
+ _game._player._stepEnabled = false;
+ _vm->_sound->command(20);
+ break;
+
+ case 1:
+ _scene->_sequences.remove(_globals._sequenceIndexes[13]);
+ _globals._sequenceIndexes[13] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[_shieldSpriteIdx], false, 6, 0, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[13], -2, -2);
+ _game._player._stepEnabled = true;
+ _panelOpened = true;
+ if (_game._objects.isInRoom(OBJ_SHIELD_MODULATOR))
+ _scene->_hotspots.activate(NOUN_SHIELD_MODULATOR, true);
+ break;
+
+ default:
+ break;
+ }
+ _action._inProgress = false;
+ return;
+ }
+
+ if ((_action.isAction(VERB_TAKE, NOUN_SHIELD_MODULATOR) || _action.isAction(VERB_PULL, NOUN_SHIELD_MODULATOR)) && _game._objects.isInRoom(OBJ_SHIELD_MODULATOR)) {
+ _game._objects.addToInventory(OBJ_SHIELD_MODULATOR);
+ _scene->_sequences.remove(_globals._sequenceIndexes[13]);
+ _globals._sequenceIndexes[13] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[14], false, 6, 0, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[13], -2, -2);
+ _scene->_hotspots.activate(NOUN_SHIELD_MODULATOR, false);
+ _vm->_dialogs->showItem(OBJ_SHIELD_MODULATOR, 10120);
+ _vm->_sound->command(22);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_LOOK, NOUN_SHIELD_ACCESS_PANEL) || (_action.isAction(VERB_LOOK, NOUN_SHIELD_MODULATOR) && !_game._objects.isInInventory(OBJ_SHIELD_MODULATOR)) ) {
+ if (_panelOpened) {
+ if (_game._objects.isInRoom(OBJ_SHIELD_MODULATOR))
+ _vm->_dialogs->show(10128);
+ else
+ _vm->_dialogs->show(10129);
+ } else
+ _vm->_dialogs->show(10127);
+
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_OPEN, NOUN_SHIELD_ACCESS_PANEL) && _panelOpened) {
+ _vm->_dialogs->show(10130);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_LOOK, NOUN_VIEW_SCREEN) && _sittingFl) {
+ if (_globals[kWatchedViewScreen])
+ sayDang();
+ else {
+ switch (_game._trigger) {
+ case 0:
+ _game._player._stepEnabled = false;
+ _scene->_sequences.remove(_globals._sequenceIndexes[11]);
+ _globals._sequenceIndexes[11] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[11], false, 3, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[11], 17, 21);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[11], SEQUENCE_TRIGGER_EXPIRE, 0, 1);
+ _vm->_sound->command(17);
+ break;
+
+ case 1:
+ _globals._sequenceIndexes[11] = _scene->_sequences.addReverseSpriteCycle(_globals._spriteIndexes[11], false, 3, 1, 0, 0);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[11], SEQUENCE_TRIGGER_EXPIRE, 0, 2);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[11], 17, 21);
+ break;
+
+ case 2:
+ _globals._sequenceIndexes[11] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[11], false, 3, 0, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[11], 17, 17);
+ _globals._sequenceIndexes[8] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[8], false, 3, 1, 0, 0);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[8], SEQUENCE_TRIGGER_EXPIRE, 0, 3);
+ break;
+
+ case 3:
+ _game._player._stepEnabled = true;
+ _globals[kWatchedViewScreen] = true;
+ _sittingFl = true;
+ _scene->_nextSceneId = 112;
+ break;
+
+ default:
+ break;
+ }
+ }
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_LOOK, NOUN_CHAIR)) {
+ _vm->_dialogs->show(10101);
+ _action._inProgress = false;
+ return;
+ }
+
+ if ((_action.isAction(VERB_LOOK) || _action.isAction(VERB_PEER_THROUGH)) && (_action.isObject(NOUN_FRONT_WINDOW) || _action.isObject(NOUN_OUTSIDE))) {
+ _vm->_dialogs->show(10102);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_LOOK, NOUN_HULL) || _action.isAction(VERB_LOOK, NOUN_OUTER_HULL) || _action.isAction(VERB_EXAMINE, NOUN_HULL) || _action.isAction(VERB_EXAMINE, NOUN_OUTER_HULL)) {
+ _vm->_dialogs->show(10103);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_LOOK, NOUN_FUZZY_DICE)) {
+ _vm->_dialogs->show(10104);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_LOOK, NOUN_MIRROR) || _action.isAction(VERB_LOOK_IN, NOUN_MIRROR)) {
+ _vm->_dialogs->show(10105);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_LOOK, NOUN_CURTAINS)) {
+ _vm->_dialogs->show(10106);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_LOOK, NOUN_PLASTIC_JESUS)) {
+ _vm->_dialogs->show(10107);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_LOOK, NOUN_ESCAPE_HATCH) || (_action.isAction(VERB_OPEN, NOUN_ESCAPE_HATCH) && !_game._objects.isInInventory(OBJ_REBREATHER))) {
+ _vm->_dialogs->show(10109);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_OPEN, NOUN_ESCAPE_HATCH)) {
+ _vm->_dialogs->show(10110);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_LOOK, NOUN_TARGET_COMPUTER)) {
+ _vm->_dialogs->show(10111);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_LOOK, NOUN_LIBRARY_COMPUTER)) {
+ _vm->_dialogs->show(10126);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_LOOK, NOUN_DAMAGE_CONTROL_PANEL)) {
+ _vm->_dialogs->show(10112);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_LOOK, NOUN_NAVIGATION_CONTROLS)) {
+ _vm->_dialogs->show(10113);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_LOOK, NOUN_ENGINEERING_CONTROLS)) {
+ _vm->_dialogs->show(10114);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_LOOK, NOUN_WEAPONS_DISPLAY)) {
+ _vm->_dialogs->show(10115);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_LOOK, NOUN_SHIELD_STATUS_PANEL)) {
+ _vm->_dialogs->show(10116);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_TAKE, NOUN_PLASTIC_JESUS)) {
+ _vm->_dialogs->show(10118);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_TAKE, NOUN_FUZZY_DICE)) {
+ _vm->_dialogs->show(10119);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_OPEN, NOUN_DAMAGE_CONTROL_PANEL)) {
+ _vm->_dialogs->show(10121);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_OPEN, NOUN_CURTAINS)) {
+ _vm->_dialogs->show(10122);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_CLOSE, NOUN_CURTAINS)) {
+ _vm->_dialogs->show(10123);
+ _action._inProgress = false;
+ return;
+ }
+
+ if ((_action.isAction(VERB_LOOK) || _action.isAction(VERB_PLAY)) && _action.isObject(NOUN_VIDEO_GAME)) {
+ _vm->_dialogs->show(10124);
+ _action._inProgress = false;
+ return;
+ }
+}
+
+/*------------------------------------------------------------------------*/
+
+Scene102::Scene102(MADSEngine *vm) : Scene1xx(vm) {
+ _fridgeOpenedFl = false;
+ _fridgeOpenedDescr = false;
+ _fridgeFirstOpenFl = false;
+ _chairDescrFl = false;
+ _drawerDescrFl = false;
+ _activeMsgFl = false;
+ _fridgeCommentCount = 0;
+}
+
+void Scene102::synchronize(Common::Serializer &s) {
+ Scene1xx::synchronize(s);
+
+ s.syncAsByte(_fridgeOpenedFl);
+ s.syncAsByte(_fridgeOpenedDescr);
+ s.syncAsByte(_fridgeFirstOpenFl);
+ s.syncAsByte(_chairDescrFl);
+ s.syncAsByte(_drawerDescrFl);
+ s.syncAsByte(_activeMsgFl);
+
+ s.syncAsSint16LE(_fridgeCommentCount);
+}
+
+void Scene102::setup() {
+ _scene->_animationData->preLoad(formAnimName('A', -1), 3);
+ setPlayerSpritesPrefix();
+ setAAName();
+}
+
+void Scene102::addRandomMessage() {
+ _scene->_kernelMessages.reset();
+ _game._triggerSetupMode = SEQUENCE_TRIGGER_DAEMON;
+ int quoteId = _vm->getRandomNumber(65, 69);
+ _scene->_kernelMessages.add(Common::Point(0, 0), 0x1110, 34, 73, 120, _game.getQuote(quoteId));
+ _activeMsgFl = true;
+}
+
+void Scene102::enter() {
+ sceneEntrySound();
+
+ _globals._spriteIndexes[1] = _scene->_sprites.addSprites(formAnimName('x', 1));
+ _globals._spriteIndexes[2] = _scene->_sprites.addSprites(formAnimName('x', 2));
+ _globals._spriteIndexes[3] = _scene->_sprites.addSprites(formAnimName('x', 3));
+ _globals._spriteIndexes[4] = _scene->_sprites.addSprites(formAnimName('x', 4));
+ _globals._spriteIndexes[5] = _scene->_sprites.addSprites(formAnimName('x', 5));
+ _globals._spriteIndexes[6] = _scene->_sprites.addSprites(formAnimName('b', -1));
+ _globals._spriteIndexes[7] = _scene->_sprites.addSprites(formAnimName('c', -1));
+ _globals._spriteIndexes[8] = _scene->_sprites.addSprites(formAnimName('e', -1));
+ _globals._spriteIndexes[9] = _scene->_sprites.addSprites(formAnimName('n', -1));
+ _globals._spriteIndexes[10] = _scene->_sprites.addSprites(formAnimName('g', -1));
+ _globals._spriteIndexes[11] = _scene->_sprites.addSprites("*RXMRC_8");
+ _globals._spriteIndexes[13] = _scene->_sprites.addSprites(formAnimName('x', 0));
+
+ _globals._sequenceIndexes[1] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[1], false, 8, 0, 0, 0);
+ _globals._sequenceIndexes[2] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[2], false, 170, 0, 1, 6);
+ _globals._sequenceIndexes[3] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[3], false, 11, 0, 2, 3);
+ _globals._sequenceIndexes[4] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[4], false, 4, 0, 1, 0);
+ _globals._sequenceIndexes[5] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[5], false, 3, 0, 0, 5);
+
+ if (_game._objects.isInRoom(OBJ_BINOCULARS))
+ _globals._sequenceIndexes[9] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[9], false, 24, 0, 0, 24);
+ else
+ _scene->_hotspots.activate(NOUN_BINOCULARS, false);
+
+ _scene->_hotspots.activate(NOUN_BURGER, false);
+
+ if (_globals[kMedicineCabinetOpen]) {
+ _globals._sequenceIndexes[8] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[8], false, 6, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[8], -2, -2);
+ }
+
+ if (_scene->_priorSceneId == 101) {
+ _game._player._playerPos = Common::Point(229, 109);
+ _game._player._stepEnabled = false;
+ _globals._sequenceIndexes[6] = _scene->_sequences.addReverseSpriteCycle(_globals._spriteIndexes[6], false, 6, 1, 2, 0);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[6], SEQUENCE_TRIGGER_EXPIRE, 0, 70);
+ } else if (_scene->_priorSceneId == 103)
+ _game._player._playerPos = Common::Point(47, 152);
+ else if (_scene->_priorSceneId != -2) {
+ _game._player._facing = FACING_NORTHWEST;
+ _game._player._playerPos = Common::Point(32, 129);
+ }
+
+ if (_scene->_priorSceneId != 106) {
+ if (_globals[kWaterInAPuddle]) {
+ _globals._sequenceIndexes[13] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[13], false, 6, 0, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[13], -2, -2);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[13], 5);
+ }
+ } else {
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._sequenceIndexes[13] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[13], false, 6, 1, 0, 0);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[13], SEQUENCE_TRIGGER_EXPIRE, 0, 72);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[13], 5);
+ _vm->_sound->command(24);
+ _vm->_sound->command(28);
+ }
+
+ _fridgeOpenedFl = false;
+ _fridgeOpenedDescr = false;
+ _fridgeCommentCount = 0;
+ _fridgeFirstOpenFl = true;
+ _chairDescrFl = false;
+ _activeMsgFl = false;
+
+ _game.loadQuoteSet(0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x45, 0x43, 0);
+
+ if (_scene->_priorSceneId == 101)
+ _vm->_sound->command(20);
+}
+
+void Scene102::step() {
+ if (_game._trigger == 70)
+ _game._player._stepEnabled = true;
+
+ if (_game._trigger == 72) {
+ _globals._sequenceIndexes[13] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[13], false, 6, 0, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[13], -2, -2);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[13], 5);
+ _scene->_sequences.addTimer(48, 90);
+ }
+
+ if (_game._trigger >= 90) {
+ if (_game._trigger >= 94) {
+ _scene->loadAnimation(formAnimName('B', -1), 71);
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+
+ _globals[kWaterInAPuddle] = true;
+ _vm->_sound->command(24);
+ } else {
+ _vm->_sound->command(23);
+ _scene->_sequences.addTimer(48, _game._trigger + 1);
+ }
+ }
+
+ if (_game._trigger == 71) {
+ _game._player._stepEnabled = true;
+ _game._player._visible = true;
+ _game._player._priorTimer = _scene->_frameStartTime - _game._player._ticksAmount;
+ }
+
+ if (_fridgeOpenedFl && !_fridgeOpenedDescr) {
+ _fridgeCommentCount++;
+ if (_fridgeCommentCount > 16384) {
+ _fridgeOpenedDescr = true;
+ _vm->_dialogs->show(10213);
+ }
+ }
+
+ if (!_activeMsgFl && (_game._player._playerPos == Common::Point(177, 114)) && (_game._player._facing == FACING_NORTH)
+ && (_vm->getRandomNumber(1, 5000) == 1)) {
+ _scene->_kernelMessages.reset();
+ _activeMsgFl = false;
+ addRandomMessage();
+ }
+
+ if (_game._trigger == 73)
+ _activeMsgFl = false;
+}
+
+void Scene102::preActions() {
+ if (_action.isObject(NOUN_REFRIGERATOR) || _action.isObject(NOUN_POSTER))
+ _game._player._needToWalk = _game._player._readyToWalk;
+
+ if (_fridgeOpenedFl && !_action.isObject(NOUN_REFRIGERATOR)) {
+ switch (_game._trigger) {
+ case 0:
+ if (_game._player._needToWalk) {
+ _scene->_sequences.remove(_globals._sequenceIndexes[7]);
+ _globals._sequenceIndexes[7] = _scene->_sequences.addReverseSpriteCycle(_globals._spriteIndexes[7], false, 6, 1, 0, 0);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[7], SEQUENCE_TRIGGER_EXPIRE, 0, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[7], 15);
+ _game._player._stepEnabled = false;
+ _vm->_sound->command(20);
+ }
+ break;
+
+ case 1:
+ if (_game._objects.isInRoom(OBJ_BURGER)) {
+ _scene->_sequences.remove(_globals._sequenceIndexes[10]);
+ _scene->_hotspots.activate(NOUN_BURGER, false);
+ }
+ _fridgeOpenedFl = false;
+ _game._player._stepEnabled = true;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ if (_game._player._needToWalk)
+ _scene->_kernelMessages.reset();
+}
+
+void Scene102::actions() {
+ if (_action._lookFlag) {
+ _vm->_dialogs->show(10234);
+ _action._inProgress = false;
+ return;
+ }
+
+ bool justOpenedFl = false;
+ if (_action.isObject(NOUN_REFRIGERATOR) && !_fridgeOpenedFl) {
+ switch (_game._trigger) {
+ case 0:
+ _globals._sequenceIndexes[7] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[7], false, 6, 1, 0, 0);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[7], 15);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[7], SEQUENCE_TRIGGER_EXPIRE, 0, 1);
+ if (_game._objects.isInRoom(OBJ_BURGER)) {
+ _globals._sequenceIndexes[10] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[10], false, 7, 0, 0, 0);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[10], 14);
+ }
+ _game._player._stepEnabled = false;
+ _vm->_sound->command(20);
+ _action._inProgress = false;
+ return;
+
+ case 1:
+ _globals._sequenceIndexes[7] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[7], false, 6, 0, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[7], -2, -2);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[7], 15);
+ int delay;
+ if (_action.isAction(VERB_WALKTO) && !_fridgeFirstOpenFl)
+ delay = 0;
+ else
+ delay = 48;
+ _scene->_sequences.addTimer(delay, 2);
+ _action._inProgress = false;
+ return;
+
+ case 2:
+ _fridgeOpenedFl = true;
+ _fridgeOpenedDescr = false;
+ _fridgeCommentCount = 0;
+ _game._player._stepEnabled = true;
+ justOpenedFl = true;
+ if (_game._objects.isInRoom(OBJ_BURGER))
+ _scene->_hotspots.activate(NOUN_BURGER, true);
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ if (_action.isAction(VERB_LOOK, NOUN_REFRIGERATOR) || _action.isAction(VERB_OPEN, NOUN_REFRIGERATOR)) {
+ if (_game._objects.isInRoom(OBJ_BURGER))
+ _vm->_dialogs->show(10230);
+ else
+ _vm->_dialogs->show(10229);
+
+ _fridgeFirstOpenFl = false;
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_WALKTO, NOUN_REFRIGERATOR) && justOpenedFl) {
+ _fridgeFirstOpenFl = false;
+ int quoteId = _vm->getRandomNumber(59, 63);
+ Common::String curQuote = _game.getQuote(quoteId);
+ int width = _vm->_font->getWidth(curQuote, -1);
+ _scene->_kernelMessages.reset();
+ _game._triggerSetupMode = SEQUENCE_TRIGGER_DAEMON;
+ _scene->_kernelMessages.add(Common::Point(210, 60), 0x1110, 0, 73, 120, curQuote);
+ _scene->_kernelMessages.add(Common::Point(214 + width, 60), 0x1110, 0, 73, 120, _game.getQuote(64));
+ _activeMsgFl = true;
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_CLOSE, NOUN_REFRIGERATOR)) {
+ _vm->_dialogs->show(10213);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_TAKE, NOUN_REFRIGERATOR)) {
+ _vm->_dialogs->show(8);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_WALK_THROUGH, NOUN_DOOR)) {
+ switch (_game._trigger) {
+ case 0:
+ _globals._sequenceIndexes[6] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[6], false, 6, 1, 0, 0);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[6], SEQUENCE_TRIGGER_EXPIRE, 0, 1);
+ _game._player._stepEnabled = false;
+ _vm->_sound->command(20);
+ break;
+
+ case 1:
+ _scene->_nextSceneId = 101;
+ break;
+
+ default:
+ break;
+ }
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_WALKTO, NOUN_ENGINEERING_SECTION)) {
+ _scene->_nextSceneId = 103;
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_WALKTO, NOUN_POSTER) || _action.isAction(VERB_LOOK, NOUN_POSTER) || _action.isAction(VERB_WALKTO, NOUN_BINOCULARS)) {
+ addRandomMessage();
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_LOOK, NOUN_WEIGHT_MACHINE)) {
+ _vm->_dialogs->show(10212);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_LOOK, NOUN_ENGINEERING_SECTION)) {
+ _vm->_dialogs->show(10205);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_LOOK, NOUN_DOOR)) {
+ _vm->_dialogs->show(10204);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_STARE_AT, NOUN_CEILING) || _action.isAction(VERB_LOOK, NOUN_CEILING)) {
+ _vm->_dialogs->show(10203);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_STARE_AT, NOUN_OVERHEAD_LAMP) || _action.isAction(VERB_LOOK, NOUN_OVERHEAD_LAMP)) {
+ _vm->_dialogs->show(10202);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_LOOK, NOUN_ROBO_KITCHEN)) {
+ _vm->_dialogs->show(10215);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_PUT, NOUN_BURGER, NOUN_ROBO_KITCHEN) && _game._objects.isInInventory(OBJ_BURGER)) {
+ _vm->_dialogs->show(10216);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_PUT, NOUN_REFRIGERATOR) && _game._objects.isInInventory(_game._objects.getIdFromDesc(_action._activeAction._objectNameId))) {
+ _vm->_dialogs->show(10217);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_PUT, NOUN_DEAD_FISH, NOUN_ROBO_KITCHEN) || _action.isAction(VERB_PUT, NOUN_STUFFED_FISH, NOUN_ROBO_KITCHEN)) {
+ _vm->_dialogs->show(10230);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_OPEN, NOUN_ROBO_KITCHEN)) {
+ _vm->_dialogs->show(10218);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_LOOK, NOUN_CLOSET)) {
+ _vm->_dialogs->show(10219);
+ _action._inProgress = false;
+ return;
+ }
+
+ if ((_action.isObject(NOUN_LADDER) || _action.isObject(NOUN_HATCHWAY)) && (_action.isAction(VERB_LOOK) || _action.isAction(VERB_CLIMB_UP) || _action.isAction(VERB_CLIMB_THROUGH))) {
+ if (_game._objects.isInInventory(OBJ_REBREATHER)) {
+ if (!_action.isAction(VERB_CLIMB_UP) && !_action.isAction(VERB_CLIMB_THROUGH)) {
+ _vm->_dialogs->show(10231);
+ _action._inProgress = false;
+ return;
+ }
+ } else if (_action.isAction(VERB_LOOK) || (_game._difficulty != DIFFICULTY_EASY)) {
+ _vm->_dialogs->show(10222);
+ _action._inProgress = false;
+ return;
+ }
+ }
+
+ if ((_action.isObject(NOUN_LADDER) || _action.isObject(NOUN_HATCHWAY)) && (_action.isAction(VERB_CLIMB_UP) || _action.isAction(VERB_CLIMB_THROUGH)) ) {
+ switch (_game._trigger) {
+ case 0:
+ _scene->loadAnimation(formAnimName('A', -1), 1);
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ break;
+
+ case 1:
+ _vm->_sound->command(24);
+ _scene->_sequences.addTimer(48, 2);
+ break;
+
+ case 2:
+ case 3:
+ case 4:
+ _vm->_sound->command(23);
+ _scene->_sequences.addTimer(48, _game._trigger + 1);
+ break;
+
+ case 5:
+ _vm->_sound->command(24);
+ _scene->_sequences.addTimer(48, _game._trigger + 1);
+ break;
+
+ case 6:
+ if (_game._objects.isInInventory(OBJ_REBREATHER) && !_game._visitedScenes.exists(106))
+ _vm->_dialogs->show(10237);
+ _scene->_nextSceneId = 106;
+ break;
+
+ default:
+ break;
+ }
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_LOOK, NOUN_POWER_STATUS_PANEL)) {
+ _vm->_dialogs->show(10226);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_LOOK, NOUN_WINDOW) || _action.isAction(VERB_LOOK_THROUGH, NOUN_WINDOW)) {
+ _vm->_dialogs->show(10227);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_LOOK, NOUN_DOORWAY) || _action.isAction(VERB_WALKTO, NOUN_DOORWAY)) {
+ _vm->_dialogs->show(10228);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_LOOK, NOUN_DRAWER) || ((_action.isAction(VERB_CLOSE, NOUN_DRAWER) || _action.isAction(VERB_PUSH, NOUN_DRAWER)) && !_drawerDescrFl)) {
+ _vm->_dialogs->show(10220);
+ _drawerDescrFl = true;
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_CLOSE, NOUN_DRAWER) || _action.isAction(VERB_PUSH, NOUN_DRAWER)) {
+ _vm->_dialogs->show(10221);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_OPEN, NOUN_DRAWER)) {
+ _vm->_dialogs->show(10236);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_LOOK, NOUN_CHAIR) || (_action.isAction(VERB_SIT_IN, NOUN_CHAIR) && !_chairDescrFl)) {
+ _chairDescrFl = true;
+ _vm->_dialogs->show(10210);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_SIT_IN, NOUN_CHAIR)) {
+ _vm->_dialogs->show(10211);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_LOOK, NOUN_MEDICINE_CABINET)) {
+ if (_globals[kMedicineCabinetOpen])
+ _vm->_dialogs->show(10207);
+ else
+ _vm->_dialogs->show(10206);
+
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_CLOSE, NOUN_MEDICINE_CABINET) && _globals[kMedicineCabinetOpen]) {
+ switch (_game._trigger) {
+ case 0:
+ _scene->_sequences.remove(_globals._sequenceIndexes[8]);
+ _globals._sequenceIndexes[8] = _scene->_sequences.addReverseSpriteCycle(_globals._spriteIndexes[8], false, 6, 1, 0, 0);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[8], SEQUENCE_TRIGGER_EXPIRE, 0, 1);
+ _game._player._stepEnabled = false;
+ _vm->_sound->command(21);
+ break;
+
+ case 1:
+ _scene->_sequences.addTimer(48, 2);
+ break;
+
+ case 2:
+ _game._player._stepEnabled = true;
+ _globals[kMedicineCabinetOpen] = false;
+ _vm->_dialogs->show(10209);
+ break;
+
+ default:
+ break;
+ }
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_OPEN, NOUN_MEDICINE_CABINET) && !_globals[kMedicineCabinetOpen]) {
+ switch (_game._trigger) {
+ case 0:
+ _globals._sequenceIndexes[8] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[8], false, 6, 1, 0, 0);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[8], SEQUENCE_TRIGGER_EXPIRE, 0, 1);
+ _game._player._stepEnabled = false;
+ _vm->_sound->command(21);
+ break;
+
+ case 1:
+ _globals._sequenceIndexes[8] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[8], false, 6, 0, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[8], -2, -2);
+ _scene->_sequences.addTimer(48, 2);
+ break;
+
+ case 2:
+ _game._player._stepEnabled = true;
+ _globals[kMedicineCabinetOpen] = true;
+ if (_globals[kMedicineCabinetVirgin]) {
+ _vm->_dialogs->show(10208);
+ } else {
+ _vm->_dialogs->show(10207);
+ }
+ _globals[kMedicineCabinetVirgin] = false;
+ break;
+
+ default:
+ break;
+ }
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_TAKE, NOUN_BINOCULARS) && _game._objects.isInRoom(OBJ_BINOCULARS)) {
+ switch (_game._trigger) {
+ case 0:
+ _globals._sequenceIndexes[11] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[11], false, 3, 1, 0, 0);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[11]);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[11], SEQUENCE_TRIGGER_EXPIRE, 0, 1);
+ _game._player._visible = false;
+ _game._player._stepEnabled = false;
+ break;
+
+ case 1:
+ _game._objects.addToInventory(OBJ_BINOCULARS);
+ _scene->_sequences.remove(_globals._sequenceIndexes[9]);
+ _scene->_hotspots.activate(NOUN_BINOCULARS, false);
+ _game._player._visible = true;
+ _game._player._stepEnabled = true;
+ _vm->_sound->command(22);
+ _vm->_dialogs->showItem(OBJ_BINOCULARS, 10201);
+ break;
+
+ default:
+ break;
+ }
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_TAKE, NOUN_BURGER) && _game._objects.isInRoom(OBJ_BURGER)) {
+ if (_game._trigger == 0) {
+ _vm->_dialogs->showItem(OBJ_BURGER, 10235);
+ _scene->_sequences.remove(_globals._sequenceIndexes[10]);
+ _game._objects.addToInventory(OBJ_BURGER);
+ _scene->_hotspots.activate(NOUN_BURGER, false);
+ _vm->_sound->command(22);
+ _game._player._visible = true;
+ _game._player._stepEnabled = true;
+ }
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_TAKE, NOUN_POSTER)) {
+ _vm->_dialogs->show(10224);
+ _action._inProgress = false;
+ return;
+ }
+
+ if ((_action.isAction(VERB_PUSH) || _action.isAction(VERB_PULL)) && _action.isObject(NOUN_WEIGHT_MACHINE)) {
+ _vm->_dialogs->show(10225);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_LOOK, NOUN_FLOOR)) {
+ _vm->_dialogs->show(10232);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_LOOK, NOUN_BINOCULARS) && !_game._objects.isInInventory(OBJ_BINOCULARS)) {
+ _vm->_dialogs->show(10233);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_LOOK, NOUN_BURGER) && (_action._mainObjectSource == 4)) {
+ _vm->_dialogs->show(801);
+ _action._inProgress = false;
+ }
+}
+
+void Scene102::postActions() {
+ if (_action.isAction(VERB_PUT, NOUN_ROBO_KITCHEN) && _game._objects.isInInventory(_game._objects.getIdFromDesc(_action._activeAction._objectNameId))) {
+ _vm->_dialogs->show(10217);
+ _action._inProgress = false;
+ }
+}
+
+/*------------------------------------------------------------------------*/
+
+Scene103::Scene103(MADSEngine *vm) : Scene1xx(vm) {
+ _updateClock = 0;
+}
+
+void Scene103::synchronize(Common::Serializer &s) {
+ Scene1xx::synchronize(s);
+
+ byte dummy = 0;
+ s.syncAsByte(dummy); // In order to avoid to break savegame compatibility
+ s.syncAsUint32LE(_updateClock);
+}
+
+void Scene103::setup() {
+ setPlayerSpritesPrefix();
+ setAAName();
+}
+
+void Scene103::enter() {
+ _globals._spriteIndexes[0] = _scene->_sprites.addSprites(formAnimName('x', 0));
+ _globals._spriteIndexes[1] = _scene->_sprites.addSprites(formAnimName('x', 1));
+ _globals._spriteIndexes[2] = _scene->_sprites.addSprites(formAnimName('x', 2));
+ _globals._spriteIndexes[3] = _scene->_sprites.addSprites(formAnimName('x', 3));
+ _globals._spriteIndexes[4] = _scene->_sprites.addSprites(formAnimName('x', 4));
+ _globals._spriteIndexes[5] = _scene->_sprites.addSprites(formAnimName('x', 5));
+ _globals._spriteIndexes[6] = _scene->_sprites.addSprites(formAnimName('b', -1));
+ _globals._spriteIndexes[7] = _scene->_sprites.addSprites(formAnimName('h', -1));
+ _globals._spriteIndexes[8] = _scene->_sprites.addSprites(formAnimName('m', -1));
+ _globals._spriteIndexes[9] = _scene->_sprites.addSprites(formAnimName('t', -1));
+ _globals._spriteIndexes[10] = _scene->_sprites.addSprites(formAnimName('r', -1));
+ _globals._spriteIndexes[11] = _scene->_sprites.addSprites(formAnimName('c', -1));
+ _globals._spriteIndexes[12] = _scene->_sprites.addSprites("*RXMBD_2");
+ _globals._spriteIndexes[13] = _scene->_sprites.addSprites("*RXMRD_3");
+ _globals._spriteIndexes[15] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[0], false, 7, 0, 1, 0);
+
+ _globals._sequenceIndexes[1] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[1], false, 6, 0, 2, 0);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 0);
+
+ _globals._sequenceIndexes[2] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[2], false, 6, 0, 0, 25);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[2], SEQUENCE_TRIGGER_SPRITE, 2, 72);
+
+ _globals._sequenceIndexes[3] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[3], false, 6, 0, 1, 37);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[3], SEQUENCE_TRIGGER_SPRITE, 2, 73);
+
+ _globals._sequenceIndexes[8] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[8], false, 8);
+ _globals._sequenceIndexes[7] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[7], false, 6);
+ _globals._sequenceIndexes[4] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[4], false, 6);
+ _globals._sequenceIndexes[5] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[5], false, 6);
+
+ if (_game._objects.isInRoom(OBJ_TIMER_MODULE))
+ _globals._sequenceIndexes[11] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[11], false, 6);
+ else
+ _vm->_game->_scene._hotspots.activate(371, false);
+
+ if (_game._objects.isInRoom(OBJ_REBREATHER))
+ _globals._sequenceIndexes[10] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[10], false, 6);
+ else
+ _vm->_game->_scene._hotspots.activate(289, false);
+
+ if (_globals[kTurkeyExploded]) {
+ _globals._sequenceIndexes[9] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[9], false, 6);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[9], -2, -2);
+ _scene->_hotspots.activate(362, false);
+ }
+
+ if (_scene->_priorSceneId != -2)
+ _game._player._playerPos = Common::Point(237, 74);
+
+ if (_scene->_priorSceneId == 102) {
+ _game._player._stepEnabled = false;
+ _globals._sequenceIndexes[6] = _scene->_sequences.addReverseSpriteCycle(_globals._spriteIndexes[6], false, 6, 1, 0, 0);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[6], SEQUENCE_TRIGGER_EXPIRE, 0, 70);
+ }
+
+ sceneEntrySound();
+ _vm->_game->loadQuoteSet(70, 51, 71, 7, 73, 0);
+
+ if (!_game._visitedScenes._sceneRevisited) {
+ int msgIndex = _scene->_kernelMessages.add(Common::Point(0, 0), 0x1110, 34, 0, 120, _game.getQuote(70));
+ _scene->_kernelMessages.setQuoted(msgIndex, 4, true);
+ }
+
+ if (_scene->_priorSceneId == 102)
+ _vm->_sound->command(20);
+
+ _vm->_palette->setEntry(252, 63, 63, 10);
+ _vm->_palette->setEntry(253, 45, 45, 10);
+ _updateClock = _scene->_frameStartTime;
+}
+
+void Scene103::step() {
+ switch (_vm->_game->_trigger) {
+ case 70:
+ _vm->_game->_player._stepEnabled = true;
+ break;
+
+ case 72: {
+ Common::Point pt = _vm->_game->_player._playerPos;
+ int dist = _vm->hypotenuse(pt.x - 58, pt.y - 93);
+ _vm->_sound->command(27, (dist * -128 / 378) + 127);
+ }
+ break;
+
+ case 73: {
+ Common::Point pt = _vm->_game->_player._playerPos;
+ int dist = _vm->hypotenuse(pt.x - 266, pt.y - 81);
+ _vm->_sound->command(27, (dist * -127 / 378) + 127);
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ if (_scene->_frameStartTime >= _updateClock) {
+ Common::Point pt = _vm->_game->_player._playerPos;
+ int dist = _vm->hypotenuse(pt.x - 79, pt.y - 137);
+ _vm->_sound->command(29, (dist * -127 / 378) + 127);
+
+ pt = _vm->_game->_player._playerPos;
+ dist = _vm->hypotenuse(pt.x - 69, pt.y - 80);
+ _vm->_sound->command(30, (dist * -127 / 378) + 127);
+
+ pt = _vm->_game->_player._playerPos;
+ dist = _vm->hypotenuse(pt.x - 266, pt.y - 138);
+ _vm->_sound->command(32, (dist * -127 / 378) + 127);
+
+ _updateClock = _scene->_frameStartTime + _vm->_game->_player._ticksAmount;
+ }
+}
+
+void Scene103::actions() {
+ if (_action._savedFields._lookFlag)
+ _vm->_dialogs->show(10322);
+ else if (_action.isAction(VERB_WALK_THROUGH, NOUN_DOOR)) {
+ switch (_vm->_game->_trigger) {
+ case 0:
+ _globals._sequenceIndexes[6] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[6], false, 6, 1);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[6], SEQUENCE_TRIGGER_EXPIRE, 0, 1);
+ _game._player._stepEnabled = false;
+ _vm->_sound->command(20);
+ break;
+
+ case 1:
+ _vm->_sound->command(1);
+ _scene->_nextSceneId = 102;
+ _game._player._stepEnabled = true;
+ break;
+
+ default:
+ break;
+ }
+ } else if (_action.isAction(VERB_TAKE, 371) && _game._objects.isInRoom(OBJ_TIMER_MODULE)) {
+ switch (_vm->_game->_trigger) {
+ case 0:
+ _scene->changeVariant(1);
+ _globals._sequenceIndexes[13] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[13], false, 3, 2);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[13]);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[13], SEQUENCE_TRIGGER_SPRITE, 7, 1);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[13], SEQUENCE_TRIGGER_EXPIRE, 0, 2);
+ _vm->_game->_player._visible = false;
+ _vm->_game->_player._stepEnabled = false;
+ break;
+
+ case 1:
+ _scene->_sequences.remove(_globals._sequenceIndexes[11]);
+ break;
+
+ case 2:
+ _vm->_sound->command(22);
+ _game._objects.addToInventory(OBJ_TIMER_MODULE);
+ _scene->changeVariant(0);
+ _scene->drawElements(kTransitionNone, false);
+ _scene->_hotspots.activate(371, false);
+ _vm->_game->_player._visible = true;
+ _vm->_game->_player._stepEnabled = true;
+ _vm->_dialogs->showItem(OBJ_REBREATHER, 805);
+ break;
+
+ default:
+ break;
+ }
+ } else if (_action.isAction(VERB_TAKE, 289, 0) && _game._objects.isInRoom(OBJ_REBREATHER)) {
+ switch (_vm->_game->_trigger) {
+ case 0:
+ _scene->changeVariant(1);
+ _globals._sequenceIndexes[12] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[12], false, 3, 2);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[12]);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[12], SEQUENCE_TRIGGER_SPRITE, 6, 1);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[12], SEQUENCE_TRIGGER_EXPIRE, 0, 2);
+ _vm->_game->_player._visible = false;
+ _vm->_game->_player._stepEnabled = false;
+ break;
+
+ case 1:
+ _scene->_sequences.remove(_globals._sequenceIndexes[10]);
+ break;
+
+ case 2:
+ _vm->_sound->command(22);
+ _game._objects.addToInventory(OBJ_REBREATHER);
+ _scene->_hotspots.activate(289, false);
+ _vm->_game->_player._visible = true;
+ _vm->_game->_player._stepEnabled = true;
+ _vm->_dialogs->showItem(OBJ_REBREATHER, 804);
+ break;
+
+ default:
+ break;
+ }
+ } else if (_action.isAction(VERB_LOOK, 362))
+ _vm->_dialogs->show(10301);
+ else if (_action.isAction(VERB_TAKE, 362)) {
+ // Take Turkey
+ if (!_vm->_game->_trigger)
+ _vm->_sound->command(31);
+
+ if (_vm->_game->_trigger < 2) {
+ _globals._sequenceIndexes[9] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[9], false, 6, _vm->_game->_trigger < 1 ? 1 : 0);
+ if (_vm->_game->_trigger) {
+ // Lock the turkey into a permanent "exploded" frame
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[9], -2, -2);
+
+ // Rex says "Gads.."
+ Common::String msg = _game.getQuote(51);
+ _scene->_kernelMessages.add(Common::Point(0, 0), 0x1110, 18, 0, 60, msg);
+ _scene->_sequences.addTimer(120, _vm->_game->_trigger + 1);
+ } else {
+ // Initial turky explosion
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[9], SEQUENCE_TRIGGER_EXPIRE, 0, 1);
+ }
+ }
+
+ // Re-enable player if sequence is ended, and set global flag
+ _game._player._stepEnabled = _game._trigger == 2;
+ _globals[kTurkeyExploded] = -1;
+
+ if (_game._trigger == 2) {
+ // Show exposition dialog at end of sequence
+ _vm->_dialogs->show(10302);
+ _scene->_hotspots.activate(362, false);
+ }
+ } else if (_action.isAction(VERB_LOOK, 250))
+ _vm->_dialogs->show(!_globals[kTurkeyExploded] ? 10323 : 10303);
+ else if (_action.isAction(VERB_TALKTO, 27)) {
+ switch (_vm->_game->_trigger) {
+ case 0: {
+ _game._player._stepEnabled = false;
+ Common::String msg = _game.getQuote(71);
+ _scene->_kernelMessages.add(Common::Point(), 0x1110, 18, 1, 120, msg);
+ break;
+ }
+
+ case 1: {
+ Common::String msg = _game.getQuote(72);
+ _scene->_kernelMessages.add(Common::Point(310, 132), 0xFDFC, 16, 2, 120, msg);
+ break;
+ }
+
+ case 2:
+ _scene->_kernelMessages.reset();
+ _scene->_sequences.addTimer(1, 3);
+ break;
+
+ case 3:
+ _game._player._stepEnabled = true;
+ _vm->_dialogs->show(10306);
+ break;
+
+ default:
+ break;
+ }
+ } else if (_action.isAction(VERB_LOOK, 27))
+ _vm->_dialogs->show(10304);
+ else if (_action.isAction(VERB_LOOK, 36))
+ _vm->_dialogs->show(10307);
+ else if (_action.isAction(VERB_LOOK, 55))
+ _vm->_dialogs->show(10308);
+ else if (_action.isAction(VERB_TAKE, 315))
+ _vm->_dialogs->show(10309);
+ else if (_action.isAction(VERB_TAKE, 85))
+ _vm->_dialogs->show(10310);
+ else if (_action.isAction(VERB_LOOK, 144))
+ _vm->_dialogs->show(10312);
+ else if (_action.isAction(VERB_OPEN, 144))
+ _vm->_dialogs->show(10313);
+ else if (_action.isAction(VERB_CLOSE, 27))
+ _vm->_dialogs->show(10314);
+ else if (_action.isAction(VERB_LOOK, 310))
+ _vm->_dialogs->show(10315);
+ else if (_action.isAction(VERB_LOOK, 178))
+ _vm->_dialogs->show(10316);
+ else if (_action.isAction(VERB_LOOK, 283))
+ _vm->_dialogs->show(10317);
+ else if (_action.isAction(VERB_LOOK, 120))
+ _vm->_dialogs->show(10318);
+ else if (_action.isAction(VERB_LOOK, 289) && _game._objects.isInInventory(OBJ_REBREATHER))
+ _vm->_dialogs->show(10319);
+ else if (_action.isAction(VERB_LOOK, 371) && _game._objects.isInInventory(OBJ_TIMER_MODULE))
+ _vm->_dialogs->show(10320);
+ else if (_action.isAction(VERB_LOOK, 137))
+ _vm->_dialogs->show(10321);
+ else if (_action.isAction(VERB_LOOK, 409))
+ _vm->_dialogs->show(_game._objects.isInInventory(OBJ_TIMER_MODULE) ? 10324 : 10325);
+ else
+ return;
+
+ _action._inProgress = false;
+}
+
+void Scene103::postActions() {
+ if (_action.isAction(27) && !_action.isAction(VERB_WALKTO)) {
+ _vm->_dialogs->show(10305);
+ _action._inProgress = false;
+ } else if (_action.isAction(VERB_PUT, 85, 144)) {
+ Common::String msg = _game.getQuote(73);
+ _scene->_kernelMessages.add(Common::Point(0, 0), 0x1110, 34, 0, 120, msg);
+ _action._inProgress = false;
+ }
+}
+
+/*------------------------------------------------------------------------*/
+
+Scene104::Scene104(MADSEngine *vm) : Scene1xx(vm) {
+ _kargShootingFl = false;
+ _loseFl = false;
+}
+
+void Scene104::synchronize(Common::Serializer &s) {
+ Scene1xx::synchronize(s);
+
+ s.syncAsByte(_kargShootingFl);
+ s.syncAsByte(_loseFl);
+}
+
+void Scene104::setup() {
+ // Preloading has been skipped
+ setPlayerSpritesPrefix();
+ setAAName();
+}
+
+void Scene104::enter() {
+ _globals._spriteIndexes[1] = _scene->_sprites.addSprites(formAnimName('h', -1));
+ _globals._sequenceIndexes[1] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[1], false, 14, 0, 0, 1);
+
+ if (_scene->_priorSceneId == 105)
+ _game._player._playerPos = Common::Point(302, 107);
+ else if (_scene->_priorSceneId != -2)
+ _game._player._playerPos = Common::Point(160, 134);
+
+ _loseFl = false;
+ _game.loadQuoteSet(0x35, 0x34, 0);
+ _kargShootingFl = false;
+
+ if (_vm->getRandomNumber(1, 3) == 1) {
+ _scene->loadAnimation(Resources::formatName(104, 'B', -1, EXT_AA, ""), 0);
+ _kargShootingFl = true;
+ }
+
+ sceneEntrySound();
+}
+
+void Scene104::step() {
+ if ((_game._player._playerPos == Common::Point(189, 70)) && (_game._trigger || !_loseFl)) {
+ if (_game._player._facing == FACING_SOUTHWEST || _game._player._facing == FACING_SOUTHEAST)
+ _game._player._facing = FACING_SOUTH;
+
+ if (_game._player._facing == FACING_NORTHWEST || _game._player._facing == FACING_NORTHEAST)
+ _game._player._facing = FACING_NORTH;
+
+ bool mirrorFl = false;
+ if (_game._player._facing == FACING_WEST) {
+ _game._player._facing = FACING_EAST;
+ mirrorFl = true;
+ }
+
+ _loseFl = true;
+
+ switch (_game._player._facing) {
+ case FACING_EAST:
+ switch (_game._trigger) {
+ case 0:
+ _scene->_kernelMessages.reset();
+ _scene->freeAnimation();
+ _scene->resetScene();
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._spriteIndexes[2] = _scene->_sprites.addSprites(formAnimName('a', 0));
+ _vm->_palette->refreshSceneColors();
+ _globals._sequenceIndexes[2] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[2], mirrorFl, 7, 1, 0, 0);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[2], Common::Point(198, 143));
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 4);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[2], SEQUENCE_TRIGGER_EXPIRE, 0, 1);
+ break;
+
+ case 1:
+ _globals._sequenceIndexes[2] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[2], mirrorFl, 7, 0, 0, 0);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[2], Common::Point(198, 143));
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[2], -2, -2);
+ _scene->_sequences.addTimer(90, 2);
+ break;
+
+ case 2:
+ _vm->_dialogs->show(10406);
+ _scene->_reloadSceneFlag = true;
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case FACING_SOUTH:
+ switch (_game._trigger) {
+ case 0:
+ _scene->_kernelMessages.reset();
+ _scene->freeAnimation();
+ _scene->resetScene();
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._spriteIndexes[3] = _scene->_sprites.addSprites(formAnimName('a', 1));
+ _vm->_palette->refreshSceneColors();
+ _globals._sequenceIndexes[3] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[3], false, 6, 1, 0, 0);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[3], Common::Point(198, 143));
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 4);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[3], 1, 14);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[3], SEQUENCE_TRIGGER_EXPIRE, 0, 1);
+ break;
+
+ case 1:
+ _globals._sequenceIndexes[3] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[3], false, 5, 1, 0, 0);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[3], Common::Point(198, 143));
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 4);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[3], 15, 32);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[3], SEQUENCE_TRIGGER_EXPIRE, 0, 2);
+ break;
+
+ case 2:
+ _globals._sequenceIndexes[3] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[3], false, 3, 0, 0, 0);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[3], Common::Point(198, 143));
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[3], -2, -2);
+ _scene->_sequences.addTimer(90, 3);
+ break;
+
+ case 3:
+ _vm->_dialogs->show(10406);
+ _scene->_reloadSceneFlag = true;
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case FACING_NORTH:
+ switch (_game._trigger) {
+ case 0:
+ _scene->_kernelMessages.reset();
+ _scene->freeAnimation();
+ _scene->resetScene();
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._spriteIndexes[4] = _scene->_sprites.addSprites(formAnimName('a', 2));
+ _vm->_palette->refreshSceneColors();
+ _globals._sequenceIndexes[4] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[4], false, 8, 1, 0, 0);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[4], Common::Point(198, 143));
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[4], 4);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[4], SEQUENCE_TRIGGER_EXPIRE, 0, 1);
+ if (_game._storyMode >= STORYMODE_NICE)
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[4], SEQUENCE_TRIGGER_SPRITE, 15, 2);
+ break;
+
+ case 1:
+ _globals._sequenceIndexes[4] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[4], false, 8, 0, 0, 0);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[4], Common::Point(198, 143));
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[4], -2, -2);
+ _scene->_sequences.addTimer(90, 2);
+ break;
+
+ case 2:
+ _vm->_dialogs->show(10406);
+ _scene->_reloadSceneFlag = true;
+ break;
+
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (!_game._trigger)
+ _vm->_sound->command(34);
+ }
+
+ if (_game._player._moving && (_scene->_rails.getNext() > 0)) {
+ _game._player.cancelCommand();
+ _game._player.startWalking(Common::Point(189, 70), FACING_NONE);
+ _scene->_rails.resetNext();
+ }
+
+ if ((_game._player._special > 0) && _game._player._stepEnabled)
+ _game._player._stepEnabled = false;
+
+ if (_kargShootingFl && (_scene->_activeAnimation->getCurrentFrame() >= 19)) {
+ _scene->_kernelMessages.add(Common::Point(0, 0), 0x1110, 34, 0, 120, _game.getQuote(52));
+ _kargShootingFl = false;
+ }
+}
+
+void Scene104::preActions() {
+ if (_action.isAction(VERB_SWIM_TOWARDS, NOUN_EASTERN_CLIFF_FACE))
+ _game._player._walkOffScreenSceneId = 105;
+
+ if (_action.isAction(VERB_SWIM_TOWARDS, NOUN_OPEN_AREA_TO_SOUTH))
+ _game._player._walkOffScreenSceneId = 106;
+}
+
+void Scene104::actions() {
+ if (_action._lookFlag)
+ _vm->_dialogs->show(10405);
+ else if (_action.isAction(VERB_LOOK, NOUN_CURIOUS_WEED_PATCH))
+ _vm->_dialogs->show(10404);
+ else if (_action.isAction(VERB_LOOK, NOUN_SURFACE))
+ _vm->_dialogs->show(10403);
+ else if (_action.isAction(VERB_LOOK, NOUN_CLIFF_FACE))
+ _vm->_dialogs->show(10401);
+ else if (_action.isAction(VERB_LOOK, NOUN_OCEAN_FLOOR))
+ _vm->_dialogs->show(10402);
+ else
+ return;
+
+ _action._inProgress = false;
+}
+
+/*------------------------------------------------------------------------*/
+
+Scene105::Scene105(MADSEngine *vm) : Scene1xx(vm) {
+ _explosionFl = false;
+}
+
+void Scene105::synchronize(Common::Serializer &s) {
+ Scene1xx::synchronize(s);
+
+ s.syncAsByte(_explosionFl);
+}
+
+void Scene105::setup() {
+ // Preloading has been skipped
+ setPlayerSpritesPrefix();
+ setAAName();
+}
+
+void Scene105::enter() {
+ _globals._spriteIndexes[1] = _scene->_sprites.addSprites(formAnimName('m', 1));
+ _globals._spriteIndexes[4] = _scene->_sprites.addSprites(formAnimName('f', 4));
+ _globals._sequenceIndexes[1] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[1], false, 8, 0, 0, 0);
+
+ if (_globals[kFishIn105]) {
+ _globals._sequenceIndexes[4] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[4], false, 6, 0, 0, 0);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[4], Common::Point(48, 144));
+
+ int idx = _scene->_dynamicHotspots.add(101, 348, _globals._sequenceIndexes[4], Common::Rect(0, 0, 0, 0));
+ _scene->_dynamicHotspots.setPosition(idx, Common::Point(56, 141), FACING_NORTHWEST);
+ }
+
+ if (_scene->_priorSceneId == 104)
+ _game._player._playerPos = Common::Point(13, 97);
+ else if (_scene->_priorSceneId != -2)
+ _game._player._playerPos = Common::Point(116, 147);
+
+ _game.loadQuoteSet(0x4A, 0x4B, 0x4C, 0x35, 0x34, 0);
+ _explosionFl = false;
+
+ sceneEntrySound();
+}
+
+void Scene105::step() {
+ if ((_game._player._playerPos == Common::Point(170, 87)) && (_game._trigger || !_explosionFl)) {
+ _explosionFl = true;
+ switch (_game._trigger) {
+ case 0:
+ _scene->_kernelMessages.reset();
+ _scene->resetScene();
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+
+ _globals._spriteIndexes[0] = _scene->_sprites.addSprites(formAnimName('m', 0));
+ _globals._spriteIndexes[2] = _scene->_sprites.addSprites(formAnimName('m', 2));
+ _globals._spriteIndexes[3] = _scene->_sprites.addSprites(formAnimName('m', 3));
+ _vm->_sound->command(33);
+ _scene->clearSequenceList();
+ _vm->_palette->refreshSceneColors();
+
+ _globals._sequenceIndexes[0] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[0], false, 6, 1, 0, 0);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[0], 8);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[0], SEQUENCE_TRIGGER_EXPIRE, 0, 1);
+
+ if (_game._storyMode >= STORYMODE_NICE)
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[0], SEQUENCE_TRIGGER_SPRITE, 8, 3);
+ break;
+
+ case 1:
+ _globals._sequenceIndexes[3] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[3], false, 6, 0, 0, 0);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 8);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[3], -2, -2);
+ _globals._sequenceIndexes[2] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[2], false, 9, 1, 0, 0);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[2], _globals._sequenceIndexes[0]);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 8);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[2], 5, 7);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[2], SEQUENCE_TRIGGER_EXPIRE, 0, 2);
+ break;
+
+ case 2: {
+ int oldIdx = _globals._sequenceIndexes[2];
+ _globals._sequenceIndexes[2] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[2], false, 9, 0, 0, 0);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[2], oldIdx);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 8);
+ _scene->_sequences.addTimer(90, 3);
+ }
+ break;
+
+ case 3:
+ _vm->_dialogs->show(10507);
+ _scene->_reloadSceneFlag = true;
+ _scene->_sequences.addTimer(90, 4);
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ if (_game._player._moving && (_scene->_rails.getNext() > 0)) {
+ _game._player.cancelCommand();
+ _game._player.startWalking(Common::Point(170, 87), FACING_NONE);
+ _scene->_rails.resetNext();
+ }
+
+ if ((_game._player._special > 0) && _game._player._stepEnabled)
+ _game._player._stepEnabled = false;
+}
+
+void Scene105::preActions() {
+ if (_action.isAction(VERB_SWIM_TOWARDS, NOUN_WESTERN_CLIFF_FACE))
+ _game._player._walkOffScreenSceneId = 104;
+
+ if (_action.isAction(VERB_SWIM_TOWARDS, NOUN_OPEN_AREA_TO_SOUTH))
+ _game._player._walkOffScreenSceneId = 107;
+
+ if (_action.isObject(NOUN_MINE) && (_action.isAction(VERB_TALKTO) || _action.isAction(VERB_LOOK)))
+ _game._player._needToWalk = false;
+}
+
+void Scene105::actions() {
+ if (_action._lookFlag)
+ _vm->_dialogs->show(10512);
+ else if (_action.isAction(VERB_TAKE, NOUN_DEAD_FISH) && _globals[kFishIn105]) {
+ if (_game._objects.isInInventory(OBJ_DEAD_FISH)) {
+ int randVal = _vm->getRandomNumber(74, 76);
+ _scene->_kernelMessages.reset();
+ _scene->_kernelMessages.add(Common::Point(0, 0), 0x1110, 34, 0, 120, _game.getQuote(randVal));
+ } else {
+ _scene->_sequences.remove(_globals._sequenceIndexes[4]);
+ _game._objects.addToInventory(OBJ_DEAD_FISH);
+ _globals[kFishIn105] = false;
+ _vm->_dialogs->showItem(OBJ_DEAD_FISH, 802, 0);
+ }
+ } else if (_action.isAction(VERB_LOOK, NOUN_WESTERN_CLIFF_FACE))
+ _vm->_dialogs->show(10501);
+ else if (_action.isAction(VERB_LOOK, NOUN_CLIFF_FACE))
+ _vm->_dialogs->show(10502);
+ else if (_action.isAction(VERB_LOOK, NOUN_OCEAN_FLOOR))
+ _vm->_dialogs->show(10503);
+ else if (_action.isAction(VERB_LOOK, NOUN_MEDICAL_WASTE))
+ _vm->_dialogs->show(10504);
+ else if (_action.isAction(VERB_TAKE, NOUN_MEDICAL_WASTE))
+ _vm->_dialogs->show(10505);
+ else if (_action.isAction(VERB_LOOK, NOUN_MINE))
+ _vm->_dialogs->show(10506);
+ else if (_action.isAction(VERB_LOOK, NOUN_DEAD_FISH))
+ _vm->_dialogs->show(10508);
+ else if (_action.isAction(VERB_LOOK, NOUN_SURFACE))
+ _vm->_dialogs->show(10509);
+ else if (_action.isAction(VERB_LOOK, NOUN_OPEN_AREA_TO_SOUTH))
+ _vm->_dialogs->show(10510);
+ else if (_action.isAction(VERB_LOOK, NOUN_ROCKS))
+ _vm->_dialogs->show(10511);
+ else
+ return;
+
+ _action._inProgress = false;
+}
+
+/*------------------------------------------------------------------------*/
+
+Scene106::Scene106(MADSEngine *vm) : Scene1xx(vm) {
+ _backToShipFl = false;
+ _shadowFl = false;
+ _firstEmergingFl = false;
+ _positionY = 0;
+}
+
+void Scene106::synchronize(Common::Serializer &s) {
+ Scene1xx::synchronize(s);
+
+ s.syncAsByte(_backToShipFl);
+ s.syncAsByte(_shadowFl);
+ s.syncAsByte(_firstEmergingFl);
+ s.syncAsSint32LE(_positionY);
+}
+
+void Scene106::setup() {
+ setPlayerSpritesPrefix();
+ setAAName();
+
+ if ((_scene->_priorSceneId == 102) && !_game._objects.isInInventory(OBJ_REBREATHER) && !_scene->_roomChanged)
+ _game._player._spritesPrefix = "";
+
+ _vm->_dialogs->_defaultPosition.y = 100;
+}
+
+void Scene106::enter() {
+ _globals._spriteIndexes[0] = _scene->_sprites.addSprites(formAnimName('H', -1));
+
+ if (_game._objects.isInInventory(OBJ_REBREATHER) || (_scene->_priorSceneId != 102) || _scene->_roomChanged) {
+ _globals._spriteIndexes[1] = _scene->_sprites.addSprites(formAnimName('A', 0));
+ _globals._spriteIndexes[3] = _scene->_sprites.addSprites(formAnimName('A', 1));
+ }
+
+ _globals._spriteIndexes[2] = _scene->_sprites.addSprites(formAnimName('G', -1));
+ _globals._sequenceIndexes[2] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[2], false, 21, 0, 0, 0);
+ _globals._spriteIndexes[4] = _scene->_sprites.addSprites(formAnimName('I', -1));
+ _globals._sequenceIndexes[4] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[4], false, 6, 0, 32, 47);
+
+ if (_scene->_priorSceneId == 102) {
+ _globals._sequenceIndexes[0] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[0], false, 6, 1, 4, 0);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[0], SEQUENCE_TRIGGER_EXPIRE, 0, 70);
+ _game._player._visible = false;
+ _game._player._stepEnabled = false;
+ _game._player._facing = FACING_EAST;
+ _game._player._playerPos = Common::Point(106, 69);
+ } else if (_scene->_priorSceneId != -2) {
+ if (_scene->_priorSceneId == 107) {
+ _game._player._playerPos = Common::Point(319, 84);
+ _game._player._facing = _game._player._prepareWalkFacing = FACING_WEST;
+ } else {
+ _game._player._playerPos = Common::Point(319, 44);
+ _game._player._facing = _game._player._prepareWalkFacing = FACING_SOUTHWEST;
+ _scene->_sprites[_game._player._spritesStart + 3]->_charInfo->_velocity = 24;
+ }
+
+ _game._player._prepareWalkPos = Common::Point(246, 69);
+ _game._player._needToWalk = true;
+ _game._player._readyToWalk = true;
+ }
+
+ if (_scene->_priorSceneId != 102) {
+ _globals._sequenceIndexes[0] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[0], false, 6, 0, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[0], -2, -2);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[0], 14);
+ }
+
+ _backToShipFl = false;
+ _shadowFl = false;
+ _firstEmergingFl = false;
+
+ _game.loadQuoteSet(0x31, 0x32, 0x34, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0);
+ sceneEntrySound();
+}
+
+void Scene106::step() {
+ if (_game._trigger == 70) {
+ _globals._sequenceIndexes[0] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[0], false, 6, 0, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[0], -2, -2);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[0], 14);
+
+ if (!_game._objects.isInInventory(OBJ_REBREATHER) && !_scene->_roomChanged) {
+ _scene->loadAnimation(Resources::formatName(106, 'A', -1, EXT_AA, ""), 75);
+ } else {
+ _globals._sequenceIndexes[1] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[1], false, 4, 1, 0, 0);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[1], SEQUENCE_TRIGGER_SPRITE, 28, 71);
+ }
+ }
+
+ if (_game._trigger == 71) {
+ _game._player._prepareWalkPos = Common::Point(246, 69);
+ _game._player._prepareWalkFacing = FACING_EAST;
+ _game._player._needToWalk = true;
+ _game._player._readyToWalk = true;
+ _game._player._visible = true;
+
+ if (_game._visitedScenes._sceneRevisited) {
+ _game._player._stepEnabled = true;
+ } else {
+ _game._player._prepareWalkFacing = FACING_SOUTHWEST;
+ _firstEmergingFl = true;
+ _scene->loadAnimation(Resources::formatName(106, 'B', -1, EXT_AA, ""), 80);
+ }
+ }
+
+ if (_firstEmergingFl && (_scene->_activeAnimation->getCurrentFrame() >= 19)) {
+ _firstEmergingFl = false;
+ _scene->_kernelMessages.add(Common::Point(0, 0), 0x1110, 34, 0, 120, _game.getQuote(52));
+ }
+
+ if ((_game._trigger >= 80) && (_game._trigger <= 87)) {
+ int tmpVal = _game._trigger - 80;
+ int msgId = -1;
+ switch (tmpVal) {
+ case 0:
+ _positionY = 26;
+ msgId = 49;
+ break;
+
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ msgId = 76 + tmpVal;
+ break;
+
+ case 6:
+ msgId = 50;
+ break;
+
+ default:
+ msgId = -1;
+ _game._player._stepEnabled = true;
+ break;
+ }
+
+ if (msgId >= 0) {
+ int nextAbortVal = _game._trigger + 1;
+ _scene->_kernelMessages.add(Common::Point(15, _positionY), 0x1110, 0, 0, 360, _game.getQuote(msgId));
+ _scene->_sequences.addTimer(150, nextAbortVal);
+ _positionY += 14;
+ }
+ }
+
+ if (_backToShipFl) {
+ if (!_shadowFl) {
+ if (_game._player._playerPos.x < 204) {
+ _shadowFl = true;
+ _globals._sequenceIndexes[3] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[3], false, 4, 1, 0, 0);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[3], SEQUENCE_TRIGGER_EXPIRE, 0, 72);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[3], SEQUENCE_TRIGGER_SPRITE, 44, 73);
+ }
+ } else if (_game._trigger == 73)
+ _game._player._visible = false;
+ else if (_game._trigger == 72)
+ _scene->_sequences.addTimer(24, 74);
+ else if (_game._trigger == 74)
+ _scene->_nextSceneId = 102;
+ }
+
+ if (_game._trigger == 75) {
+ _game._visitedScenes.pop_back();
+ _scene->_nextSceneId = 102;
+ }
+}
+
+void Scene106::preActions() {
+ if (_action.isAction(VERB_SWIM_TOWARDS, NOUN_SEA_CLIFF) || _action.isAction(VERB_SWIM_TOWARDS, NOUN_SEAWEED_BANK)) {
+ _game._player._stepEnabled = false;
+ _scene->_sprites[_game._player._spritesStart + 1]->_charInfo->_velocity = 24;
+ _game._player._walkOffScreenSceneId = 104;
+ }
+
+ if (_action.isAction(VERB_SWIM_TOWARDS, NOUN_OPEN_AREA_TO_EAST))
+ _game._player._walkOffScreenSceneId = 107;
+}
+
+void Scene106::actions() {
+ if (_action._lookFlag)
+ _vm->_dialogs->show(10614);
+ else if (_action.isAction(VERB_SWIM_TO, NOUN_MAIN_AIRLOCK)) {
+ _game._player._stepEnabled = false;
+ _game._player._prepareWalkPos = Common::Point(95, 72);
+ _game._player._prepareWalkFacing = FACING_WEST;
+ _game._player._needToWalk = true;
+ _game._player._readyToWalk = true;
+ _game._player._frameNumber = 9;
+ _backToShipFl = true;
+ } else if (_action.isAction(VERB_LOOK, NOUN_ANEMONE) || _action.isAction(VERB_LOOK_AT, NOUN_ANEMONE))
+ _vm->_dialogs->show(10601);
+ else if (_action.isAction(VERB_TAKE, NOUN_ANEMONE))
+ _vm->_dialogs->show(10602);
+ else if (_action.isAction(VERB_LOOK, NOUN_SEAWEED) || _action.isAction(VERB_LOOK, NOUN_SEAWEED_BANK))
+ _vm->_dialogs->show(10603);
+ else if (_action.isAction(VERB_TAKE, NOUN_SEAWEED) || _action.isAction(VERB_TAKE, NOUN_SEAWEED_BANK))
+ _vm->_dialogs->show(10604);
+ else if (_action.isAction(VERB_LOOK, NOUN_OPEN_AREA_TO_EAST))
+ _vm->_dialogs->show(10605);
+ else if (_action.isAction(VERB_LOOK, NOUN_PILE_OF_ROCKS) || _action.isAction(VERB_LOOK_AT, NOUN_PILE_OF_ROCKS))
+ _vm->_dialogs->show(10606);
+ else if (_action.isObject(NOUN_PILE_OF_ROCKS) && (_action.isAction(VERB_PUSH) || _action.isAction(VERB_PULL) || _action.isAction(VERB_TAKE)))
+ _vm->_dialogs->show(10607);
+ else if (_action.isAction(VERB_LOOK, NOUN_SHIP) || _action.isAction(VERB_LOOK_AT, NOUN_SHIP))
+ _vm->_dialogs->show(10608);
+ else if (_action.isAction(VERB_LOOK, NOUN_MAIN_AIRLOCK))
+ _vm->_dialogs->show(10609);
+ else if (_action.isAction(VERB_OPEN, NOUN_MAIN_AIRLOCK))
+ _vm->_dialogs->show(10610);
+ else if (_action.isAction(VERB_CLOSE, NOUN_MAIN_AIRLOCK))
+ _vm->_dialogs->show(10611);
+ else if (_action.isAction(VERB_LOOK, NOUN_SEA_CLIFF))
+ _vm->_dialogs->show(10612);
+ else if (_action.isAction(VERB_LOOK, NOUN_OCEAN_FLOOR))
+ _vm->_dialogs->show(10613);
+ else
+ return;
+
+ _action._inProgress = false;
+}
+
+/*------------------------------------------------------------------------*/
+
+Scene107::Scene107(MADSEngine *vm) : Scene1xx(vm) {
+ _shootingFl = false;
+}
+
+void Scene107::synchronize(Common::Serializer &s) {
+ Scene1xx::synchronize(s);
+
+ s.syncAsByte(_shootingFl);
+}
+
+void Scene107::setup() {
+ setPlayerSpritesPrefix();
+ setAAName();
+
+ _scene->addActiveVocab(NOUN_MANTA_RAY);
+}
+
+void Scene107::enter() {
+ for (int i = 0; i < 3; i++)
+ _globals._spriteIndexes[i + 1] = _scene->_sprites.addSprites(formAnimName('G', i));
+
+ _globals._spriteIndexes[4] = _scene->_sprites.addSprites(Resources::formatName(105, 'f', 4, EXT_SS, ""));
+
+ _globals._sequenceIndexes[1] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[1], false, 14, 0, 0, 7);
+ _globals._sequenceIndexes[2] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[2], false, 17, 0, 0, 13);
+ _globals._sequenceIndexes[3] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[3], false, 19, 0, 0, 9);
+
+ for (int i = 1; i < 4; i++)
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[i], 0);
+
+ if (_globals[kFishIn107]) {
+ _globals._sequenceIndexes[4] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[4], false, 6, 0, 0, 0);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[4], Common::Point(68, 151));
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[4], 1);
+ int idx = _scene->_dynamicHotspots.add(101, 348, _globals._sequenceIndexes[4], Common::Rect(0, 0, 0, 0));
+ _scene->_dynamicHotspots.setPosition(idx, Common::Point(78, 135), FACING_SOUTHWEST);
+ }
+
+ if (_scene->_priorSceneId == 105)
+ _game._player._playerPos = Common::Point(132, 47);
+ else if (_scene->_priorSceneId == 106)
+ _game._player._playerPos = Common::Point(20, 91);
+ else if (_scene->_priorSceneId != -2)
+ _game._player._playerPos = Common::Point(223, 151);
+
+ if (((_scene->_priorSceneId == 105) || (_scene->_priorSceneId == 106)) && (_vm->getRandomNumber(1, 3) == 1)) {
+ _globals._spriteIndexes[0] = _scene->_sprites.addSprites(Resources::formatName(105, 'R', 1, EXT_SS, ""));
+ _globals._sequenceIndexes[0] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[0], true, 4, 0, 0, 0);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[0], Common::Point(270, 150));
+ _scene->_sequences.setMotion(_globals._sequenceIndexes[0], SEQUENCE_TRIGGER_SPRITE, -200, 0);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[0], 2);
+ _scene->_dynamicHotspots.add(218, 348, _globals._sequenceIndexes[0], Common::Rect(0, 0, 0, 0));
+ }
+
+ _game.loadQuoteSet(0x4A, 0x4B, 0x4C, 0x35, 0x34, 0);
+ _shootingFl = false;
+
+ if (_vm->getRandomNumber(1, 3) == 1) {
+ _scene->loadAnimation(Resources::formatName(107, 'B', -1, EXT_AA, ""), 0);
+ _shootingFl = true;
+ }
+
+ sceneEntrySound();
+}
+
+void Scene107::step() {
+ if (_shootingFl && (_scene->_activeAnimation->getCurrentFrame() >= 19)) {
+ _scene->_kernelMessages.add(Common::Point(0, 0), 0x1110, 34, 0, 120, _game.getQuote(52));
+ _shootingFl = false;
+ }
+}
+
+void Scene107::preActions() {
+ if (_action.isAction(VERB_SWIM_TOWARDS, NOUN_OPEN_AREA_TO_WEST))
+ _game._player._walkOffScreenSceneId = 106;
+
+ if (_action.isAction(VERB_SWIM_TOWARDS, NOUN_OPEN_AREA_TO_SOUTH))
+ _game._player._walkOffScreenSceneId = 108;
+}
+
+void Scene107::actions() {
+ if (_action._lookFlag)
+ _vm->_dialogs->show(10708);
+ else if (_action.isAction(VERB_TAKE, NOUN_DEAD_FISH) && _globals[kFishIn107]) {
+ if (_game._objects.isInInventory(OBJ_DEAD_FISH)) {
+ int randVal = _vm->getRandomNumber(74, 76);
+ _scene->_kernelMessages.reset();
+ _scene->_kernelMessages.add(Common::Point(0, 0), 0x1110, 34, 0, 120, _game.getQuote(randVal));
+ } else {
+ _scene->_sequences.remove(_globals._sequenceIndexes[4]);
+ _game._objects.addToInventory(OBJ_DEAD_FISH);
+ _globals[kFishIn107] = false;
+ _vm->_dialogs->showItem(OBJ_DEAD_FISH, 802);
+ }
+ } else if (_action.isAction(VERB_SWIM_TOWARDS, NOUN_NORTHERN_SEA_CLIFF))
+ _scene->_nextSceneId = 105;
+ else if (_action.isAction(VERB_LOOK, NOUN_NORTHERN_SEA_CLIFF))
+ _vm->_dialogs->show(10701);
+ else if (_action.isAction(VERB_LOOK, NOUN_DEAD_FISH) && (_action._mainObjectSource == 4))
+ _vm->_dialogs->show(10702);
+ else if (_action.isAction(VERB_LOOK, NOUN_BUSH_LIKE_FORMATION))
+ _vm->_dialogs->show(10703);
+ else if (_action.isAction(VERB_LOOK, NOUN_ROCK))
+ _vm->_dialogs->show(10704);
+ else if (_action.isAction(VERB_LOOK, NOUN_SEAWEED))
+ _vm->_dialogs->show(10705);
+ else if (_action.isAction(VERB_LOOK, NOUN_OPEN_AREA_TO_SOUTH))
+ _vm->_dialogs->show(10706);
+ else if (_action.isAction(VERB_LOOK, NOUN_CLIFF_FACE))
+ _vm->_dialogs->show(10707);
+ else if (_action.isAction(VERB_LOOK, NOUN_MANTA_RAY))
+ _vm->_dialogs->show(10709);
+ else if (_action.isAction(VERB_TAKE, NOUN_MANTA_RAY))
+ _vm->_dialogs->show(10710);
+ else
+ return;
+
+ _action._inProgress = false;
+}
+
+/*------------------------------------------------------------------------*/
+
+void Scene108::setup() {
+ setPlayerSpritesPrefix();
+ setAAName();
+}
+
+void Scene108::enter() {
+ if (_globals[kHoovicSated] == 2)
+ _globals[kHoovicSated] = 0;
+
+ _globals._spriteIndexes[0] = _scene->_sprites.addSprites(formAnimName('X', 0));
+ _globals._spriteIndexes[1] = _scene->_sprites.addSprites(formAnimName('X', 1));
+ _globals._spriteIndexes[2] = _scene->_sprites.addSprites(formAnimName('X', 2));
+ _globals._spriteIndexes[3] = _scene->_sprites.addSprites(formAnimName('X', 3));
+ _globals._spriteIndexes[4] = _scene->_sprites.addSprites(Resources::formatName(105, 'f', 4, EXT_SS, ""));
+
+ _globals._sequenceIndexes[0] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[0], false, 13, 0, 0, 7);
+ _globals._sequenceIndexes[1] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[1], false, 16, 0, 0, 9);
+ _globals._sequenceIndexes[2] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[2], false, 17, 0, 0, 3);
+ _globals._sequenceIndexes[3] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[3], false, 14, 0, 0, 13);
+
+ for (int i = 0; i <= 3; i++)
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[i], 0);
+
+ if (_globals[kFishIn108]) {
+ _globals._sequenceIndexes[4] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[4], false, 6, 0, 0, 0);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[4], Common::Point(41, 109));
+ int idx = _scene->_dynamicHotspots.add(101, 348, _globals._sequenceIndexes[4], Common::Rect(0, 0, 0, 0));
+ _scene->_dynamicHotspots.setPosition(idx, Common::Point(41, 109), FACING_NORTHWEST);
+ }
+
+ if (_scene->_priorSceneId == 107)
+ _game._player._playerPos = Common::Point(138, 58);
+ else if (_scene->_priorSceneId != -2)
+ _game._player._playerPos = Common::Point(305, 98);
+
+ _game.loadQuoteSet(0x4A, 0x4B, 0x4C, 0x35, 0x34, 0);
+ sceneEntrySound();
+}
+
+void Scene108::preActions() {
+ if (_action.isAction(VERB_SWIM_UNDER, NOUN_OVERHANG_TO_EAST))
+ _game._player._walkOffScreenSceneId = 109;
+}
+
+void Scene108::actions() {
+ if (_action._lookFlag)
+ _vm->_dialogs->show(10812);
+ else if (_action.isAction(VERB_TAKE, NOUN_DEAD_FISH) && _globals[kFishIn108]) {
+ if (_game._objects.isInInventory(OBJ_DEAD_FISH)) {
+ int randVal = _vm->getRandomNumber(74, 76);
+ _scene->_kernelMessages.reset();
+ _scene->_kernelMessages.add(Common::Point(0, 0), 0x1110, 34, 0, 120, _game.getQuote(randVal));
+ } else {
+ _scene->_sequences.remove(_globals._sequenceIndexes[4]);
+ _game._objects.addToInventory(OBJ_DEAD_FISH);
+ _globals[kFishIn108] = false;
+ _vm->_dialogs->showItem(OBJ_DEAD_FISH, 10808);
+ }
+ } else if (_action.isAction(VERB_SWIM_TOWARDS, NOUN_OPEN_AREA_TO_NORTH))
+ _scene->_nextSceneId = 107;
+ else if (_action.isAction(VERB_LOOK, NOUN_CLIFF_FACE))
+ _vm->_dialogs->show(10801);
+ else if (_action.isAction(VERB_LOOK, NOUN_OCEAN_FLOOR))
+ _vm->_dialogs->show(10802);
+ else if (_action.isAction(VERB_LOOK, NOUN_ODD_ROCK_FORMATION))
+ _vm->_dialogs->show(10803);
+ else if (_action.isAction(VERB_TAKE, NOUN_ODD_ROCK_FORMATION))
+ _vm->_dialogs->show(10804);
+ else if (_action.isAction(VERB_LOOK, NOUN_ROCKS))
+ _vm->_dialogs->show(10805);
+ else if (_action.isAction(VERB_TAKE, NOUN_ROCKS))
+ _vm->_dialogs->show(10806);
+ else if (_action.isAction(VERB_LOOK, NOUN_DEAD_FISH))
+ _vm->_dialogs->show(10807);
+ else if (_action.isAction(VERB_LOOK, NOUN_OVERHANG_TO_EAST))
+ _vm->_dialogs->show(10809);
+ else if (_action.isAction(VERB_LOOK, NOUN_OPEN_AREA_TO_NORTH))
+ _vm->_dialogs->show(10810);
+ else if (_action.isAction(VERB_LOOK, NOUN_SURFACE))
+ _vm->_dialogs->show(10811);
+ else
+ return;
+
+ _action._inProgress = false;
+}
+
+/*------------------------------------------------------------------------*/
+
+Scene109::Scene109(MADSEngine *vm) : Scene1xx(vm) {
+ _rexThrowingObject = false;
+ _hoovicDifficultFl = false;
+ _beforeEatingRex = false;
+ _eatingRex = false;
+ _hungryFl = false;
+ _eatingFirstFish = false;
+
+ _throwingObjectId = -1;
+ _hoovicTrigger = 0;
+}
+
+void Scene109::synchronize(Common::Serializer &s) {
+ Scene1xx::synchronize(s);
+
+ s.syncAsByte(_rexThrowingObject);
+ s.syncAsByte(_hoovicDifficultFl);
+ s.syncAsByte(_beforeEatingRex);
+ s.syncAsByte(_eatingRex);
+ s.syncAsByte(_hungryFl);
+ s.syncAsByte(_eatingFirstFish);
+ s.syncAsSint32LE(_throwingObjectId);
+ s.syncAsSint32LE(_hoovicTrigger);
+}
+
+void Scene109::setup() {
+ _scene->addActiveVocab(NOUN_DEAD_PURPLE_MONSTER);
+ _scene->addActiveVocab(NOUN_MONSTER_SLUDGE);
+
+ setPlayerSpritesPrefix();
+ setAAName();
+}
+
+void Scene109::enter() {
+ _globals[kFishIn105] = true;
+
+ _globals._spriteIndexes[0] = _scene->_sprites.addSprites("*RXSWRC_6");
+ _globals._spriteIndexes[1] = _scene->_sprites.addSprites(formAnimName('O', 1));
+ _globals._spriteIndexes[2] = _scene->_sprites.addSprites(formAnimName('O', 2));
+ _globals._spriteIndexes[3] = _scene->_sprites.addSprites(formAnimName('O', 0));
+ _globals._spriteIndexes[6] = _scene->_sprites.addSprites(formAnimName('H', 4));
+
+ _rexThrowingObject = false;
+ _throwingObjectId = 0;
+ _beforeEatingRex = false;
+ _eatingRex = false;
+ _hungryFl = false;
+
+ if (_scene->_priorSceneId == 110) {
+ _game._player._playerPos = Common::Point(248, 38);
+ _globals[kHoovicSated] = 2;
+ } else if (_scene->_priorSceneId != -2) {
+ _game._player._playerPos = Common::Point(20, 68);
+ _game._player._facing = FACING_EAST;
+ }
+
+ if (!_globals[kHoovicAlive]) {
+ _globals._sequenceIndexes[6] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[6], false, 6, 1, 0, 0);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[6], 4);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[6], -2, -2);
+
+ int idx = _scene->_dynamicHotspots.add(102, 348, -1, Common::Rect(256, 57, 267, 87));
+ _scene->_dynamicHotspots.setPosition(idx, Common::Point(241, 91), FACING_NORTHEAST);
+ idx = _scene->_dynamicHotspots.add(102, 348, -1, Common::Rect(242, 79, 265, 90));
+ _scene->_dynamicHotspots.setPosition(idx, Common::Point(241, 91), FACING_NORTHEAST);
+ idx = _scene->_dynamicHotspots.add(229, 348, -1, Common::Rect(231, 88, 253, 94));
+ _scene->_dynamicHotspots.setPosition(idx, Common::Point(241, 91), FACING_NORTHEAST);
+ }
+
+ if (!_globals[kHoovicAlive] || _globals[kHoovicSated])
+ _scene->changeVariant(1);
+
+ if (_game._objects.isInRoom(OBJ_BURGER)) {
+ _globals._sequenceIndexes[3] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[3], false, 6, 0, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[3], -2, -2);
+ int idx = _scene->_dynamicHotspots.add(53, 348, _globals._sequenceIndexes[3], Common::Rect(0, 0, 0, 0));
+ _scene->_dynamicHotspots.setPosition(idx, Common::Point(-3, 0), FACING_NORTHEAST);
+ } else if (_scene->_roomChanged)
+ _game._objects.addToInventory(OBJ_BURGER);
+
+ if (_scene->_roomChanged) {
+ _game._objects.addToInventory(OBJ_DEAD_FISH);
+ _game._objects.addToInventory(OBJ_STUFFED_FISH);
+ }
+
+ _vm->_palette->setEntry(252, 50, 50, 63);
+ _vm->_palette->setEntry(253, 30, 30, 50);
+
+ _game.loadQuoteSet(0x53, 0x52, 0x54, 0x55, 0x56, 0x57, 0x58, 0);
+ _eatingFirstFish = (!_game._visitedScenes._sceneRevisited) && (_scene->_priorSceneId < 110);
+
+ if (_eatingFirstFish) {
+ _globals._spriteIndexes[10] = _scene->_sprites.addSprites(Resources::formatName(105, 'F', 1, EXT_SS, ""));
+ _globals._spriteIndexes[9] = _scene->_sprites.addSprites(formAnimName('H', 1));
+
+ _globals._sequenceIndexes[10] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[10], true, 4, 0, 0, 0);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[10], 5);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[10], Common::Point(126, 39));
+ _scene->_sequences.setMotion(_globals._sequenceIndexes[10], 0, 200, 0);
+ _scene->_sequences.setScale(_globals._sequenceIndexes[10], 80);
+ _game._player._stepEnabled = false;
+ }
+
+ sceneEntrySound();
+}
+
+void Scene109::step() {
+ if (_beforeEatingRex) {
+ if (!_eatingRex) {
+ if (_game._player._playerPos.x > 205) {
+ _globals._sequenceIndexes[4] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[4], false, 6, 1, 0, 0);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[4], 4);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[4], SEQUENCE_TRIGGER_SPRITE, 6, 70);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[4], SEQUENCE_TRIGGER_EXPIRE, 0, 71);
+
+ _eatingRex = true;
+ _vm->_sound->command(34);
+ }
+ } else {
+ switch (_game._trigger) {
+ case 70:
+ _game._player._visible = false;
+ break;
+
+ case 71:
+ _scene->_reloadSceneFlag = true;
+ break;
+ }
+ }
+ }
+
+ if (_hungryFl && (_game._player._playerPos == Common::Point(160, 32)) && (_game._player._facing == FACING_EAST)) {
+ _game._player.walk(Common::Point(226, 24), FACING_EAST);
+ _game._player._stepEnabled = false;
+ _hungryFl = false;
+ _beforeEatingRex = true;
+ _scene->_sprites.remove(_globals._spriteIndexes[6]);
+ _globals._spriteIndexes[4] = _scene->_sprites.addSprites(formAnimName('H', 0));
+ _vm->_palette->refreshSceneColors();
+ }
+
+ if (_game._player._moving && (_scene->_rails.getNext() > 0) && _globals[kHoovicAlive] && !_globals[kHoovicSated] && !_hungryFl && !_beforeEatingRex) {
+ _game._player.cancelCommand();
+ _game._player.startWalking(Common::Point(160, 32), FACING_EAST);
+ _scene->_rails.resetNext();
+ _hungryFl = true;
+ }
+
+ if (_eatingFirstFish && (_scene->_sequences[_globals._sequenceIndexes[10]]._position.x >= 178)) {
+ _globals._sequenceIndexes[9] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[9], false, 4, 1, 0, 0);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[9], 4);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[9], SEQUENCE_TRIGGER_SPRITE, 29, 72);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[9], SEQUENCE_TRIGGER_EXPIRE, 29, 73);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[10], _globals._sequenceIndexes[9]);
+ _eatingFirstFish = false;
+ _game._player._stepEnabled = true;
+ _vm->_sound->command(34);
+ }
+
+ if (_game._trigger == 72)
+ _scene->_sequences.remove(_globals._sequenceIndexes[10]);
+
+ if (_game._trigger == 73) {
+ _scene->_sequences.remove(_globals._sequenceIndexes[9]);
+ _scene->_sprites.remove(_globals._spriteIndexes[9]);
+ _scene->_sprites.remove(_globals._spriteIndexes[10]);
+
+ _scene->_spriteSlots.clear();
+ _scene->_spriteSlots.fullRefresh();
+
+ int randVal = _vm->getRandomNumber(85, 88);
+ int idx = _scene->_kernelMessages.add(Common::Point(0, 0), 0x1110, 34, 0, 120, _game.getQuote(randVal));
+ _scene->_kernelMessages.setQuoted(idx, 4, true);
+ _scene->_kernelMessages._entries[idx]._frameTimer = _scene->_frameStartTime + 4;
+ }
+}
+
+void Scene109::preActions() {
+ if (_action.isAction(VERB_SWIM_UNDER, NOUN_OVERHANG_TO_WEST))
+ _game._player._walkOffScreenSceneId = 108;
+
+ if ((_action.isAction(VERB_THROW) || _action.isAction(VERB_GIVE) || _action.isAction(VERB_PUT))
+ && (_action.isObject(NOUN_SMALL_HOLE) || _action.isObject(NOUN_TUNNEL))
+ && (_action.isObject(NOUN_DEAD_FISH) || _action.isObject(NOUN_STUFFED_FISH) || _action.isObject(NOUN_BURGER))) {
+ int idx = _game._objects.getIdFromDesc(_action._activeAction._objectNameId);
+ if ((idx >= 0) && _game._objects.isInInventory(idx)) {
+ _game._player._prepareWalkPos = Common::Point(106, 38);
+ _game._player._prepareWalkFacing = FACING_EAST;
+ _game._player._needToWalk = true;
+ _game._player._readyToWalk = true;
+ }
+ }
+
+ if ((_action.isAction(VERB_SWIM_INTO, NOUN_TUNNEL) || _action.isAction(VERB_SWIM_TO, NOUN_SMALL_HOLE))
+ && (!_globals[kHoovicAlive] || _globals[kHoovicSated]) && (_action.isObject(NOUN_TUNNEL)))
+ _game._player._walkOffScreenSceneId = 110;
+
+ _hungryFl = false;
+}
+
+void Scene109::actions() {
+ if (_action._lookFlag) {
+ _vm->_dialogs->show(10912);
+ _action._inProgress = false;
+ return;
+ }
+
+ if ((_action.isAction(VERB_THROW) || _action.isAction(VERB_GIVE)) && (_action.isTarget(0x146) || _action.isTarget(0x178))) {
+ if (_action.isObject(NOUN_DEAD_FISH) || _action.isObject(NOUN_STUFFED_FISH) || _action.isObject(NOUN_BURGER)) {
+ _throwingObjectId = _game._objects.getIdFromDesc(_action._activeAction._objectNameId);
+ if (_throwingObjectId >= 0) {
+ if ((_game._objects.isInInventory(_throwingObjectId) && _globals[kHoovicAlive]) || _rexThrowingObject) {
+ switch (_game._trigger) {
+ case 0:
+ _rexThrowingObject = true;
+ _hoovicDifficultFl = false;
+ _game._objects.setRoom(_throwingObjectId, NOWHERE);
+ _globals._sequenceIndexes[0] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[0], false, 4, 1, 0, 0);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[0]);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[0], SEQUENCE_TRIGGER_EXPIRE, 0, 1);
+ _game._player._visible = false;
+ _game._player._stepEnabled = false;
+
+ switch (_throwingObjectId) {
+ case OBJ_DEAD_FISH:
+ case OBJ_STUFFED_FISH:
+ _globals._spriteIndexes[8] = _scene->_sprites.addSprites(formAnimName('H', 1));
+ break;
+
+ case OBJ_BURGER:
+ _hoovicDifficultFl = (_game._difficulty == DIFFICULTY_EASY);
+ _globals._spriteIndexes[8] = _scene->_sprites.addSprites(formAnimName('H', (_hoovicDifficultFl ? 3 : 1)));
+ break;
+ }
+
+ _vm->_palette->refreshSceneColors();
+ break;
+
+ case 1:
+ _game._player._visible = true;
+ _hoovicTrigger = 4;
+ switch (_throwingObjectId) {
+ case OBJ_BURGER:
+ _globals._sequenceIndexes[3] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[3], false, (_hoovicDifficultFl ? 4 : 6), 1, 0, 0);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[3], SEQUENCE_TRIGGER_SPRITE, 2, 2);
+ if (_hoovicDifficultFl) {
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[3], 1, 30);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[3], SEQUENCE_TRIGGER_EXPIRE, 0, 5);
+ } else {
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[3], 1, 4);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[3], SEQUENCE_TRIGGER_EXPIRE, 0, 8);
+ _hoovicTrigger = 3;
+ }
+ break;
+ case OBJ_DEAD_FISH:
+ _globals._sequenceIndexes[1] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[1], false, 4, 1, 0, 0);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[1], SEQUENCE_TRIGGER_SPRITE, 2, 2);
+ break;
+ case OBJ_STUFFED_FISH:
+ _globals._sequenceIndexes[2] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[2], false, 4, 1, 0, 0);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[2], SEQUENCE_TRIGGER_SPRITE, 2, 2);
+ _hoovicTrigger = 3;
+ break;
+ }
+ break;
+
+ case 2:
+ if (_hoovicDifficultFl)
+ _globals._sequenceIndexes[8] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[8], false, 4, 2, 0, 0);
+ else
+ _globals._sequenceIndexes[8] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[8], false, 4, 1, 0, 0);
+
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[8], 4);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[8], SEQUENCE_TRIGGER_EXPIRE, 0, _hoovicTrigger);
+ _vm->_sound->command(34);
+ break;
+
+ case 3:
+ _scene->loadAnimation(Resources::formatName(109, 'H', 2, EXT_AA, ""), 4);
+ _vm->_sound->command(35);
+ _globals[kHoovicAlive] = false;
+ break;
+
+ case 4:
+ if (!_globals[kHoovicAlive]) {
+ _globals._sequenceIndexes[6] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[6], false, 6, 1, 0, 0);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[6], 4);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[6], -2, -2);
+ int idx = _scene->_dynamicHotspots.add(102, 348, -1, Common::Rect(256, 57, 256 + 12, 57 + 31));
+ _scene->_dynamicHotspots.setPosition(idx, Common::Point(241, 91), FACING_NORTHEAST);
+ idx = _scene->_dynamicHotspots.add(102, 348, -1, Common::Rect(242, 79, 242 + 24, 79 + 12));
+ _scene->_dynamicHotspots.setPosition(idx, Common::Point(241, 91), FACING_NORTHEAST);
+ idx = _scene->_dynamicHotspots.add(229, 348, -1, Common::Rect(231, 88, 231 + 23, 88 + 7));
+ _scene->_dynamicHotspots.setPosition(idx, Common::Point(241, 91), FACING_NORTHEAST);
+ _scene->changeVariant(1);
+ } else {
+ if (_throwingObjectId == OBJ_DEAD_FISH) {
+ ++_globals[kHoovicFishEaten];
+ int threshold;
+ switch (_game._difficulty) {
+ case DIFFICULTY_HARD:
+ threshold = 1;
+ break;
+ case DIFFICULTY_MEDIUM:
+ threshold = 3;
+ break;
+ default:
+ threshold = 50;
+ break;
+ }
+
+ if (_globals[kHoovicFishEaten] >= threshold) {
+ int randVal = _vm->getRandomNumber(83, 84);
+ _scene->_kernelMessages.add(Common::Point(230, 24), 0xFDFC, 0, 0, 120, _game.getQuote(randVal));
+ _globals[kHoovicFishEaten] = 0;
+ _globals[kHoovicSated] = 1;
+ _scene->changeVariant(1);
+ }
+ }
+ }
+ _scene->freeAnimation();
+ _scene->_sequences.remove(_globals._sequenceIndexes[8]);
+ _scene->_sprites.remove(_globals._spriteIndexes[8]);
+ _scene->_spriteSlots.clear();
+ _scene->_spriteSlots.fullRefresh();
+ _scene->_sequences.scan();
+ if (_game._player._visible) {
+ _game._player._forceRefresh = true;
+ _game._player.update();
+ }
+
+ _game._player._stepEnabled = true;
+ _rexThrowingObject = false;
+ break;
+
+ case 5: {
+ _game._objects.setRoom(OBJ_BURGER, _scene->_currentSceneId);
+ _globals._sequenceIndexes[3] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[3], false, 6, 0, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[3], 30, 30);
+ int idx = _scene->_dynamicHotspots.add(53, 348, _globals._sequenceIndexes[3], Common::Rect(0, 0, 0, 0));
+ _scene->_dynamicHotspots.setPosition(idx, Common::Point(-3, 0), FACING_NORTHEAST);
+ _scene->_sequences.addTimer(65, 6);
+ }
+ break;
+
+ case 6: {
+ _scene->_sequences.remove(_globals._sequenceIndexes[3]);
+ _globals._sequenceIndexes[3] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[3], false, 6, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[3], 31, 46);
+ int idx = _scene->_dynamicHotspots.add(53, 348, _globals._sequenceIndexes[3], Common::Rect(0, 0, 0, 0));
+ _scene->_dynamicHotspots.setPosition(idx, Common::Point(-3, 0), FACING_NORTHEAST);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[3], SEQUENCE_TRIGGER_EXPIRE, 0, 7);
+ }
+ break;
+
+ case 7: {
+ _scene->_sequences.remove(_globals._sequenceIndexes[3]);
+ _globals._sequenceIndexes[3] = _scene->_sequences.startCycle(_globals._spriteIndexes[3], false, -2);
+ int idx = _scene->_dynamicHotspots.add(53, 348, _globals._sequenceIndexes[3], Common::Rect(0, 0, 0, 0));
+ _scene->_dynamicHotspots.setPosition(idx, Common::Point(-3, 0), FACING_NORTHEAST);
+ _vm->_dialogs->show(10915);
+ }
+ break;
+
+ case 8:
+ _globals._sequenceIndexes[3] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[3], false, 7, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[3], 5, 16);
+ break;
+ }
+ _action._inProgress = false;
+ return;
+ } else if (_game._objects.isInInventory(_throwingObjectId)) {
+ // Nothing.
+ }
+ }
+ }
+ }
+
+ if (_action.isAction(VERB_TAKE, NOUN_BURGER) && _game._objects.isInRoom(OBJ_BURGER)) {
+ _scene->_sequences.remove(_globals._sequenceIndexes[3]);
+ _game._objects.addToInventory(OBJ_BURGER);
+ } else if (_action.isAction(VERB_LOOK, NOUN_OCEAN_FLOOR))
+ _vm->_dialogs->show(10901);
+ else if (_action.isAction(VERB_LOOK, NOUN_CORAL))
+ _vm->_dialogs->show(10902);
+ else if ((_action.isAction(VERB_TAKE) || _action.isAction(VERB_PULL)) && _action.isObject(NOUN_CORAL))
+ _vm->_dialogs->show(10903);
+ else if (_action.isAction(VERB_LOOK, NOUN_ROCKS))
+ _vm->_dialogs->show(10904);
+ else if (_action.isAction(VERB_TAKE, NOUN_ROCKS))
+ _vm->_dialogs->show(10905);
+ else if (_action.isAction(VERB_LOOK, NOUN_CAVE_WALL))
+ _vm->_dialogs->show(10906);
+ else if (_action.isAction(VERB_LOOK, NOUN_TUNNEL)) {
+ if (_globals[kHoovicAlive])
+ _vm->_dialogs->show(10907);
+ else
+ _vm->_dialogs->show(10913);
+ } else if (_action.isAction(VERB_LOOK, NOUN_SMALL_HOLE))
+ _vm->_dialogs->show(10908);
+ else if (_action.isAction(VERB_LOOK, NOUN_OVERHANG_TO_WEST))
+ _vm->_dialogs->show(10911);
+ else if (_action.isAction(VERB_PUT, NOUN_SMALL_HOLE))
+ _vm->_dialogs->show(10910);
+ else if (_action.isAction(VERB_LOOK, NOUN_DEAD_PURPLE_MONSTER))
+ _vm->_dialogs->show(10914);
+ else
+ return;
+
+ _action._inProgress = false;
+}
+
+/*------------------------------------------------------------------------*/
+
+Scene110::Scene110(MADSEngine *vm) : Scene1xx(vm) {
+ _crabsFl = false;
+}
+
+void Scene110::synchronize(Common::Serializer &s) {
+ Scene1xx::synchronize(s);
+
+ s.syncAsByte(_crabsFl);
+}
+
+void Scene110::setup() {
+ setPlayerSpritesPrefix();
+ setAAName();
+
+ _scene->addActiveVocab(NOUN_CRAB);
+}
+
+void Scene110::enter() {
+ _globals._spriteIndexes[0] = _scene->_sprites.addSprites(formAnimName('X', 0));
+ _globals._spriteIndexes[1] = _scene->_sprites.addSprites(formAnimName('X', 1));
+ _globals._spriteIndexes[2] = _scene->_sprites.addSprites(formAnimName('X', 2));
+ _globals._spriteIndexes[3] = _scene->_sprites.addSprites(formAnimName('X', 3));
+
+ _crabsFl = false;
+
+ if (_scene->_priorSceneId == 109) {
+ _game._player._playerPos = Common::Point(59, 71);
+
+ _globals._sequenceIndexes[0] = _scene->_sequences.startCycle(_globals._spriteIndexes[0], false, 1);
+ _globals._sequenceIndexes[1] = _scene->_sequences.startCycle(_globals._spriteIndexes[1], false, 1);
+ _globals._sequenceIndexes[2] = _scene->_sequences.startCycle(_globals._spriteIndexes[2], false, 1);
+ _globals._sequenceIndexes[3] = _scene->_sequences.startCycle(_globals._spriteIndexes[3], false, 1);
+
+ _crabsFl = true;
+
+ int idx = _scene->_dynamicHotspots.add(91, 348, _globals._sequenceIndexes[0], Common::Rect(0, 0, 0, 0));
+ _scene->_dynamicHotspots.setPosition(idx, Common::Point(-1, 0), FACING_NONE);
+ idx = _scene->_dynamicHotspots.add(91, 348, _globals._sequenceIndexes[1], Common::Rect(0, 0, 0, 0));
+ _scene->_dynamicHotspots.setPosition(idx, Common::Point(-1, 0), FACING_NONE);
+ idx = _scene->_dynamicHotspots.add(91, 348, _globals._sequenceIndexes[2], Common::Rect(0, 0, 0, 0));
+ _scene->_dynamicHotspots.setPosition(idx, Common::Point(-1, 0), FACING_NONE);
+ idx = _scene->_dynamicHotspots.add(91, 348, _globals._sequenceIndexes[3], Common::Rect(0, 0, 0, 0));
+ _scene->_dynamicHotspots.setPosition(idx, Common::Point(-1, 0), FACING_NONE);
+ } else if (_scene->_priorSceneId != -2) {
+ _game._player._playerPos = Common::Point(194, 23);
+ _game._player._facing = FACING_SOUTH;
+ _game._player._visible = false;
+ _game._player._stepEnabled = false;
+ _scene->loadAnimation(Resources::formatName(110, 'T', 1,EXT_AA, ""), 70);
+ }
+
+ sceneEntrySound();
+ _game.loadQuoteSet(0x59, 0);
+
+ if (!_game._visitedScenes._sceneRevisited && (_scene->_priorSceneId == 109))
+ _scene->_kernelMessages.add(Common::Point(0, 0), 0x1110, 34, 0, 120, _game.getQuote(109));
+}
+
+void Scene110::step() {
+ if (_game._trigger == 70) {
+ _game._player._visible = true;
+ _game._player._stepEnabled = true;
+ }
+}
+
+void Scene110::preActions() {
+ if (_action.isAction(VERB_SWIM_THROUGH, NOUN_CAVE_ENTRANCE))
+ _game._player._walkOffScreenSceneId = 109;
+
+ if (_crabsFl) {
+ _crabsFl = false;
+
+ _scene->_sequences.remove(_globals._sequenceIndexes[0]);
+ _scene->_sequences.remove(_globals._sequenceIndexes[1]);
+ _scene->_sequences.remove(_globals._sequenceIndexes[2]);
+ _scene->_sequences.remove(_globals._sequenceIndexes[3]);
+
+ _globals._sequenceIndexes[0] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[0], false, 16, 1, 0, 0);
+ _globals._sequenceIndexes[1] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[1], false, 16, 1, 0, 0);
+ _globals._sequenceIndexes[2] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[2], false, 16, 1, 0, 0);
+ _globals._sequenceIndexes[3] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[3], false, 16, 1, 0, 0);
+
+ int idx = _scene->_dynamicHotspots.add(91, 348, _globals._sequenceIndexes[0], Common::Rect(0, 0, 0, 0));
+ _scene->_dynamicHotspots.setPosition(idx, Common::Point(-1, 0), FACING_NONE);
+ idx = _scene->_dynamicHotspots.add(91, 348, _globals._sequenceIndexes[1], Common::Rect(0, 0, 0, 0));
+ _scene->_dynamicHotspots.setPosition(idx, Common::Point(-1, 0), FACING_NONE);
+ idx = _scene->_dynamicHotspots.add(91, 348, _globals._sequenceIndexes[2], Common::Rect(0, 0, 0, 0));
+ _scene->_dynamicHotspots.setPosition(idx, Common::Point(-1, 0), FACING_NONE);
+ idx = _scene->_dynamicHotspots.add(91, 348, _globals._sequenceIndexes[3], Common::Rect(0, 0, 0, 0));
+ _scene->_dynamicHotspots.setPosition(idx, Common::Point(-1, 0), FACING_NONE);
+ }
+}
+
+void Scene110::actions() {
+ if (_action.isAction(VERB_SWIM_THROUGH, NOUN_TUNNEL)) {
+ switch (_game._trigger) {
+ case 0:
+ _scene->loadAnimation(Resources::formatName(110, 'T', 0, EXT_AA, ""), 1);
+ _scene->_activeAnimation->setNextFrameTimer(_game._player._ticksAmount + _game._player._priorTimer);
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ break;
+ case 1:
+ _game._player._visible = true;
+ _game._player._stepEnabled = true;
+ _scene->_nextSceneId = 111;
+ break;
+ }
+ } else if ((_action._lookFlag) || _action.isAction(VERB_LOOK, NOUN_CAVE))
+ _vm->_dialogs->show(11001);
+ else if (_action.isAction(VERB_LOOK, NOUN_CAVE_CEILING) || _action.isAction(VERB_LOOK_AT, NOUN_CAVE_CEILING))
+ _vm->_dialogs->show(11002);
+ else if (_action.isAction(VERB_LOOK, NOUN_ROCKS))
+ _vm->_dialogs->show(11003);
+ else if (_action.isAction(VERB_TAKE, NOUN_ROCKS))
+ _vm->_dialogs->show(11004);
+ else if (_action.isAction(VERB_LOOK, NOUN_TUNNEL))
+ _vm->_dialogs->show(11005);
+ else if (_action.isAction(VERB_LOOK, NOUN_CAVE_ENTRANCE))
+ _vm->_dialogs->show(11006);
+ else if (_action.isAction(VERB_LOOK, NOUN_FUNGOIDS))
+ _vm->_dialogs->show(11007);
+ else if (_action.isAction(VERB_TAKE, NOUN_FUNGOIDS))
+ _vm->_dialogs->show(11008);
+ else
+ return;
+
+ _action._inProgress = false;
+}
+
+/*------------------------------------------------------------------------*/
+
+Scene111::Scene111(MADSEngine *vm) : Scene1xx(vm) {
+ _stampedFl = false;
+ _launch1Fl = false;
+ _launched2Fl = false;
+ _rexDivingFl = false;
+}
+
+void Scene111::synchronize(Common::Serializer &s) {
+ Scene1xx::synchronize(s);
+
+ s.syncAsByte(_stampedFl);
+ s.syncAsByte(_launch1Fl);
+ s.syncAsByte(_launched2Fl);
+ s.syncAsByte(_rexDivingFl);
+}
+
+void Scene111::setup() {
+ _scene->addActiveVocab(NOUN_BATS);
+
+ setPlayerSpritesPrefix();
+ setAAName();
+}
+
+void Scene111::enter() {
+ _globals._spriteIndexes[0] = _scene->_sprites.addSprites(formAnimName('X', 0));
+ _globals._spriteIndexes[1] = _scene->_sprites.addSprites(formAnimName('X', 1));
+ _globals._spriteIndexes[2] = _scene->_sprites.addSprites(formAnimName('X', 2));
+
+ _globals._spriteIndexes[3] = _scene->_sprites.addSprites(formAnimName('B', 0));
+ _globals._spriteIndexes[4] = _scene->_sprites.addSprites(formAnimName('B', 1));
+ _globals._spriteIndexes[5] = _scene->_sprites.addSprites(formAnimName('B', 2));
+
+ _globals._sequenceIndexes[0] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[0], false, 8, 0, 0, 0);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[0], SEQUENCE_TRIGGER_SPRITE, 9, 73);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[0], SEQUENCE_TRIGGER_SPRITE, 13, 73);
+
+ _globals._sequenceIndexes[1] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[1], false, 5, 0, 0, 0);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[1], SEQUENCE_TRIGGER_SPRITE, 71, 71);
+
+ _globals._sequenceIndexes[3] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[3], false, 12, 0, 0, 0);
+ _globals._sequenceIndexes[4] = _scene->_sequences.startCycle(_globals._spriteIndexes[4], false, 1);
+ _globals._sequenceIndexes[5] = _scene->_sequences.startCycle(_globals._spriteIndexes[5], false, 1);
+
+ int idx = _scene->_dynamicHotspots.add(NOUN_BATS, 0xD1, _globals._sequenceIndexes[3], Common::Rect(0, 0, 0, 0));
+ _scene->_dynamicHotspots.setPosition(idx, Common::Point(-2, 0), FACING_NONE);
+ idx = _scene->_dynamicHotspots.add(NOUN_BATS, 0xD1, _globals._sequenceIndexes[4], Common::Rect(0, 0, 0, 0));
+ _scene->_dynamicHotspots.setPosition(idx, Common::Point(-2, 0), FACING_NONE);
+ idx = _scene->_dynamicHotspots.add(NOUN_BATS, 0xD1, _globals._sequenceIndexes[5], Common::Rect(0, 0, 0, 0));
+ _scene->_dynamicHotspots.setPosition(idx, Common::Point(-2, 0), FACING_NONE);
+
+ _launch1Fl = false;
+ _launched2Fl = false;
+ _stampedFl = false;
+
+ if ((_scene->_priorSceneId < 201) && (_scene->_priorSceneId != -2)) {
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _scene->loadAnimation(Resources::formatName(111, 'A', 0, EXT_AA, ""), 70);
+ _game._player._playerPos = Common::Point(234, 116);
+ _game._player._facing = FACING_EAST;
+
+ _launch1Fl = true;
+ _launched2Fl = true;
+
+ _vm->_sound->command(36);
+ } else if (_scene->_priorSceneId != -2) {
+ _game._player._playerPos = Common::Point(300, 130);
+ _game._player._facing = FACING_WEST;
+ }
+
+ _rexDivingFl = false;
+
+ sceneEntrySound();
+}
+
+void Scene111::step() {
+ if (_game._trigger == 70) {
+ _game._player._stepEnabled = true;
+ _game._player._visible = true;
+ _launch1Fl = false;
+ _launched2Fl = false;
+ }
+
+ if ((_game._trigger == 71) && !_stampedFl) {
+ _stampedFl = true;
+ _globals._sequenceIndexes[2] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[2], false, 18, 1, 0, 0);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[2], SEQUENCE_TRIGGER_EXPIRE, 0, 72);
+ }
+
+ if (_game._trigger == 72) {
+ _scene->_sequences.remove(_globals._sequenceIndexes[2]);
+ _globals._sequenceIndexes[2] = _scene->_sequences.startCycle(_globals._spriteIndexes[2], false, 20);
+ }
+
+ if (!_launch1Fl && (_vm->getRandomNumber(1, 5000) == 1)) {
+ _scene->_sequences.remove(_globals._sequenceIndexes[4]);
+ _globals._sequenceIndexes[4] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[4], false, 5, 1, 0, 0);
+ _launch1Fl = true;
+ int idx = _scene->_dynamicHotspots.add(NOUN_BATS, 0xD1, _globals._sequenceIndexes[4], Common::Rect(0, 0, 0, 0));
+ _scene->_dynamicHotspots.setPosition(idx, Common::Point(-2, 0), FACING_NONE);
+ }
+
+ if (!_launched2Fl && (_vm->getRandomNumber(1, 30000) == 1)) {
+ _scene->_sequences.remove(_globals._sequenceIndexes[5]);
+ _globals._sequenceIndexes[5] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[5], false, 5, 1, 0, 0);
+ int idx = _scene->_dynamicHotspots.add(NOUN_BATS, 0xD1, _globals._sequenceIndexes[5], Common::Rect(0, 0, 0, 0));
+ _scene->_dynamicHotspots.setPosition(idx, Common::Point(-2, 0), FACING_NONE);
+ _launched2Fl = true;
+ }
+
+ if (_game._trigger == 73)
+ _vm->_sound->command(37);
+
+ if (_rexDivingFl && (_scene->_activeAnimation->getCurrentFrame() >= 9)) {
+ _vm->_sound->command(36);
+ _rexDivingFl = false;
+ }
+}
+
+void Scene111::preActions() {
+ if (_action.isAction(VERB_WALK_THROUGH, NOUN_CAVE_ENTRANCE))
+ _game._player._walkOffScreenSceneId = 212;
+}
+
+void Scene111::actions() {
+ if (_action.isAction(VERB_DIVE_INTO, NOUN_POOL) && _game._objects.isInInventory(OBJ_REBREATHER)) {
+ switch (_game._trigger) {
+ case 0:
+ _scene->loadAnimation(Resources::formatName(111, 'A', 1, EXT_AA, ""), 1);
+ _rexDivingFl = true;
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ break;
+
+ case 1:
+ _scene->_nextSceneId = 110;
+ break;
+ }
+ } else if (_action.isAction(VERB_LOOK, NOUN_CAVE_FLOOR))
+ _vm->_dialogs->show(11101);
+ else if (_action.isAction(VERB_LOOK, NOUN_POOL))
+ _vm->_dialogs->show(11102);
+ else if (_action.isAction(VERB_LOOK, NOUN_CAVE_ENTRANCE))
+ _vm->_dialogs->show(11103);
+ else if (_action.isAction(VERB_LOOK, NOUN_STALAGMITES))
+ _vm->_dialogs->show(11104);
+ else if (_action.isAction(VERB_LOOK, NOUN_LARGE_STALAGMITE))
+ _vm->_dialogs->show(11105);
+ else if ((_action.isAction(VERB_PULL) || _action.isAction(VERB_TAKE)) && (_action.isObject(NOUN_STALAGMITES) || _action.isObject(NOUN_LARGE_STALAGMITE)))
+ _vm->_dialogs->show(11106);
+ else
+ return;
+
+ _action._inProgress = false;
+}
+
+/*------------------------------------------------------------------------*/
+
+void Scene112::setup() {
+ setPlayerSpritesPrefix();
+ setAAName();
+}
+
+void Scene112::enter() {
+ sceneEntrySound();
+
+ _globals._spriteIndexes[0] = _scene->_sprites.addSprites(formAnimName('X', 0));
+ _globals._spriteIndexes[1] = _scene->_sprites.addSprites(formAnimName('X', 1));
+ _globals._spriteIndexes[2] = _scene->_sprites.addSprites(formAnimName('X', 2));
+ _globals._spriteIndexes[3] = _scene->_sprites.addSprites(formAnimName('X', 5));
+
+ _globals._sequenceIndexes[0] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[0], false, 10, 0, 17, 20);
+ _globals._sequenceIndexes[1] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[1], false, 4, 0, 0, 0);
+ _globals._sequenceIndexes[2] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[2], false, 6, 0, 3, 0);
+
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+
+ _scene->_userInterface.emptyConversationList();
+ _scene->_userInterface.setup(kInputConversation);
+
+ _scene->loadAnimation(Resources::formatName(112, 'X', -1, EXT_AA, ""), 70);
+}
+
+void Scene112::step() {
+ if ((_scene->_activeAnimation != nullptr) && (_game._storyMode == STORYMODE_NICE)) {
+ if (_scene->_activeAnimation->getCurrentFrame() >= 54) {
+ _scene->freeAnimation();
+ _game._trigger = 70;
+ }
+ }
+
+ if (_game._trigger == 70) {
+ _globals._sequenceIndexes[3] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[3], false, 7, 3, 0, 11);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 1);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[3], SEQUENCE_TRIGGER_EXPIRE, 0, 71);
+ }
+
+ if (_game._trigger == 71) {
+ _scene->_nextSceneId = 101;
+ _game._player._stepEnabled = true;
+ _game._player._visible = true;
+ }
+}
+
+/*------------------------------------------------------------------------*/
+
+} // End of namespace Nebular
+} // End of namespace MADS
diff --git a/engines/mads/nebular/nebular_scenes1.h b/engines/mads/nebular/nebular_scenes1.h
new file mode 100644
index 0000000000..96d2bb95eb
--- /dev/null
+++ b/engines/mads/nebular/nebular_scenes1.h
@@ -0,0 +1,264 @@
+/* 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.
+ *
+ */
+
+#ifndef MADS_NEBULAR_SCENES1_H
+#define MADS_NEBULAR_SCENES1_H
+
+#include "common/scummsys.h"
+#include "common/serializer.h"
+#include "mads/game.h"
+#include "mads/scene.h"
+#include "mads/nebular/nebular_scenes.h"
+
+namespace MADS {
+
+namespace Nebular {
+
+class Scene1xx : public NebularScene {
+protected:
+ /**
+ * Plays an appropriate sound when entering a scene
+ */
+ void sceneEntrySound();
+
+ /**
+ *Sets the AA file to use for the scene
+ */
+ void setAAName();
+
+ /**
+ * Updates the prefix used for getting player sprites for the scene
+ */
+ void setPlayerSpritesPrefix();
+public:
+ Scene1xx(MADSEngine *vm) : NebularScene(vm) {}
+};
+
+class Scene101: public Scene1xx {
+private:
+ bool _sittingFl;
+ bool _panelOpened;
+
+ int _messageNum;
+ int _posY;
+ int _shieldSpriteIdx;
+ int _chairHotspotId;
+ int _oldSpecial;
+
+ void sayDang();
+
+public:
+ Scene101(MADSEngine *vm);
+ virtual void synchronize(Common::Serializer &s);
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+ virtual void preActions();
+ virtual void actions();
+};
+
+class Scene102 : public Scene1xx {
+private:
+ bool _fridgeOpenedFl;
+ bool _fridgeOpenedDescr;
+ bool _fridgeFirstOpenFl;
+ bool _chairDescrFl;
+ bool _drawerDescrFl;
+ bool _activeMsgFl;
+
+ int _fridgeCommentCount;
+
+ void addRandomMessage();
+
+public:
+ Scene102(MADSEngine *vm);
+ virtual void synchronize(Common::Serializer &s);
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+ virtual void preActions();
+ virtual void actions();
+ virtual void postActions();
+};
+
+class Scene103 : public Scene1xx {
+private:
+ uint32 _updateClock;
+
+public:
+ Scene103(MADSEngine *vm);
+ virtual void synchronize(Common::Serializer &s);
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+ virtual void actions();
+ virtual void postActions();
+};
+
+class Scene104 : public Scene1xx {
+private:
+ bool _kargShootingFl;
+ bool _loseFl;
+
+public:
+ Scene104(MADSEngine *vm);
+ virtual void synchronize(Common::Serializer &s);
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+ virtual void preActions();
+ virtual void actions();
+};
+
+class Scene105 : public Scene1xx {
+private:
+ bool _explosionFl;
+
+public:
+ Scene105(MADSEngine *vm);
+ virtual void synchronize(Common::Serializer &s);
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+ virtual void preActions();
+ virtual void actions();
+};
+
+class Scene106 : public Scene1xx {
+private:
+ bool _backToShipFl;
+ bool _shadowFl;
+ bool _firstEmergingFl;
+
+ int _positionY;
+
+public:
+ Scene106(MADSEngine *vm);
+ virtual void synchronize(Common::Serializer &s);
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+ virtual void preActions();
+ virtual void actions();
+};
+
+class Scene107 : public Scene1xx {
+private:
+ bool _shootingFl;
+
+public:
+ Scene107(MADSEngine *vm);
+ virtual void synchronize(Common::Serializer &s);
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+ virtual void preActions();
+ virtual void actions();
+};
+
+class Scene108 : public Scene1xx {
+public:
+ Scene108(MADSEngine *vm) : Scene1xx(vm) {}
+
+ virtual void setup();
+ virtual void enter();
+ virtual void preActions();
+ virtual void actions();
+};
+
+class Scene109 : public Scene1xx {
+private:
+ bool _rexThrowingObject;
+ bool _hoovicDifficultFl;
+ bool _beforeEatingRex;
+ bool _eatingRex;
+ bool _hungryFl;
+ bool _eatingFirstFish;
+
+ int _throwingObjectId;
+ int _hoovicTrigger;
+
+public:
+ Scene109(MADSEngine *vm);
+ virtual void synchronize(Common::Serializer &s);
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+ virtual void preActions();
+ virtual void actions();
+};
+
+class Scene110 : public Scene1xx {
+private:
+ bool _crabsFl;
+
+public:
+ Scene110(MADSEngine *vm);
+ virtual void synchronize(Common::Serializer &s);
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+ virtual void preActions();
+ virtual void actions();
+};
+
+class Scene111 : public Scene1xx {
+private:
+ bool _stampedFl;
+ bool _launch1Fl;
+ bool _launched2Fl;
+ bool _rexDivingFl;
+
+public:
+ Scene111(MADSEngine *vm);
+ virtual void synchronize(Common::Serializer &s);
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+ virtual void preActions();
+ virtual void actions();
+};
+
+class Scene112 : public Scene1xx {
+public:
+ Scene112(MADSEngine *vm) : Scene1xx(vm) {}
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+ virtual void actions() {};
+};
+
+} // End of namespace Nebular
+} // End of namespace MADS
+
+#endif /* MADS_NEBULAR_SCENES1_H */
diff --git a/engines/mads/nebular/nebular_scenes2.cpp b/engines/mads/nebular/nebular_scenes2.cpp
new file mode 100644
index 0000000000..f93ea3931d
--- /dev/null
+++ b/engines/mads/nebular/nebular_scenes2.cpp
@@ -0,0 +1,5374 @@
+/* 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 "mads/mads.h"
+#include "mads/scene.h"
+#include "mads/nebular/nebular_scenes.h"
+#include "mads/nebular/nebular_scenes2.h"
+
+namespace MADS {
+
+namespace Nebular {
+
+void Scene2xx::setAAName() {
+ int idx = (_scene->_nextSceneId == 216) ? 4 : 2;
+ _game._aaName = Resources::formatAAName(idx);
+}
+
+void Scene2xx::setPlayerSpritesPrefix() {
+ _vm->_sound->command(5);
+ Common::String oldName = _game._player._spritesPrefix;
+
+ switch(_scene->_nextSceneId) {
+ case 213:
+ case 216:
+ _game._player._spritesPrefix = "";
+ break;
+ default:
+ if (_globals[kSexOfRex] != SEX_MALE) {
+ _game._player._spritesPrefix = "ROX";
+ } else {
+ _game._player._spritesPrefix = "RXM";
+ }
+ break;
+ }
+
+ _game._player._scalingVelocity = (_scene->_nextSceneId <= 212);
+
+ if (oldName != _game._player._spritesPrefix)
+ _game._player._spritesChanged = true;
+
+ if ((_scene->_nextSceneId == 203 || _scene->_nextSceneId == 204) && _globals[kRhotundaStatus])
+ _game._player._loadsFirst = false;
+
+ _vm->_palette->setEntry(16, 10, 63, 63);
+ _vm->_palette->setEntry(17, 10, 45, 45);
+}
+
+void Scene2xx::sceneEntrySound() {
+ if (_vm->_musicFlag) {
+ switch (_scene->_nextSceneId) {
+ case 201:
+ if ((_globals[kTeleporterCommand] == 2) || (_globals[kTeleporterCommand] == 4) || (_globals[kMeteorologistStatus] != 1))
+ _vm->_sound->command(9);
+ else
+ _vm->_sound->command(17);
+ break;
+ case 202:
+ case 203:
+ case 204:
+ case 205:
+ case 208:
+ case 209:
+ case 212:
+ _vm->_sound->command(9);
+ break;
+ case 206:
+ case 211:
+ case 215:
+ _vm->_sound->command(10);
+ break;
+ case 207:
+ case 214:
+ _vm->_sound->command(11);
+ break;
+ case 210:
+ if (_globals[kTwinklesStatus] == 0)
+ _vm->_sound->command(15);
+ else
+ _vm->_sound->command(10);
+ break;
+ case 213:
+ if (_globals[kMeteorologistWatch] == METEOROLOGIST_NORMAL)
+ _vm->_sound->command(1);
+ else
+ _vm->_sound->command(9);
+ break;
+ case 216:
+ _vm->_sound->command(16);
+ break;
+ default:
+ _vm->_sound->command(10);
+ break;
+ }
+ } else
+ _vm->_sound->command(2);
+}
+
+/*------------------------------------------------------------------------*/
+
+Scene201::Scene201(MADSEngine *vm) : Scene2xx(vm) {
+ _pterodactylFlag = false;
+}
+
+void Scene201::synchronize(Common::Serializer &s) {
+ Scene2xx::synchronize(s);
+
+ s.syncAsByte(_pterodactylFlag);
+}
+
+void Scene201::setup() {
+ setPlayerSpritesPrefix();
+ setAAName();
+
+ _scene->addActiveVocab(NOUN_SWOOPING_CREATURE);
+ _scene->addActiveVocab(NOUN_BIRDS);
+ _scene->addActiveVocab(VERB_WALKTO);
+}
+
+void Scene201::enter() {
+ _globals._spriteIndexes[1] = _scene->_sprites.addSprites(formAnimName('x', 0));
+ _globals._spriteIndexes[2] = _scene->_sprites.addSprites(formAnimName('x', 1));
+ _globals._spriteIndexes[3] = _scene->_sprites.addSprites(formAnimName('m', -1));
+ _globals._spriteIndexes[4] = _scene->_sprites.addSprites(formAnimName('b', -1));
+ _globals._spriteIndexes[5] = _scene->_sprites.addSprites("*SC002Z1");
+ _globals._sequenceIndexes[1] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[1], false, 6, 0, 1, 0);
+ _globals._sequenceIndexes[2] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[2], false, 15, 0, 0, 50);
+ _globals._sequenceIndexes[3] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[3], false, 4, 0, 0, 0);
+ _globals._sequenceIndexes[4] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[4], false, 6, 0, 0, 0);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[4], 8);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[4], Common::Point(185, 46));
+
+ int idx = _scene->_dynamicHotspots.add(NOUN_BIRDS, 209, _globals._sequenceIndexes[4], Common::Rect(0, 0, 0, 0));
+ _scene->_dynamicHotspots.setPosition(idx, Common::Point(186, 81), FACING_NORTH);
+
+ if ((_scene->_priorSceneId == 202) || (_scene->_priorSceneId == -1)) {
+ _game._player._playerPos = Common::Point(165, 152);
+ } else {
+ _game._player._playerPos = Common::Point(223, 149);
+ _game._player._facing = FACING_SOUTH;
+ }
+
+ if (_globals[kTeleporterCommand]) {
+ _game._player._visible = false;
+ _game._player._stepEnabled = false;
+ int sepChar = (_globals[kSexOfRex] == SEX_UNKNOWN) ? 't' : 'u';
+ // Guess values. What is the default value used by the compiler?
+ int suffixNum = -1;
+ int abortTimers = -1;
+ switch(_globals[kTeleporterCommand]) {
+ case 1:
+ suffixNum = 3;
+ abortTimers = 76;
+ _globals[kTeleporterUnderstood] = true;
+ break;
+ case 2:
+ suffixNum = 1;
+ abortTimers = 77;
+ break;
+ case 3:
+ _game._player._visible = true;
+ _game._player._stepEnabled = true;
+ suffixNum = -1;
+ break;
+ case 4:
+ suffixNum = 2;
+ abortTimers = 78;
+ break;
+ }
+ _globals[kTeleporterCommand] = 0;
+ if (suffixNum >= 0)
+ _scene->loadAnimation(formAnimName(sepChar, suffixNum), abortTimers);
+ }
+
+ if ((_scene->_priorSceneId == 202) && (_globals[kMeteorologistStatus] == METEOROLOGIST_PRESENT) && !_scene->_roomChanged) {
+ _globals._spriteIndexes[6] = _scene->_sprites.addSprites(formAnimName('a', 0));
+ _globals._spriteIndexes[7] = _scene->_sprites.addSprites(formAnimName('a', 1));
+ _game.loadQuoteSet(90, 91, 0);
+ _game._player._stepEnabled = false;
+ _globals._sequenceIndexes[6] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[6], false, 7, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[6], -1, 12);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[6], SEQUENCE_TRIGGER_SPRITE, 12, 70);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[6], 1);
+ _pterodactylFlag = false;
+ _game._player.walk(Common::Point(157, 143), FACING_NORTH);
+ _vm->_palette->setEntry(252, 45, 63, 45);
+ _vm->_palette->setEntry(253, 20, 45, 20);
+ _scene->_kernelMessages.add(Common::Point(0, 0), 0x1110, 2, 0, 120, _game.getQuote(90));
+ } else
+ _pterodactylFlag = true;
+
+ if (_globals[kTeleporterUnderstood])
+ _scene->_hotspots.activate(NOUN_STRANGE_DEVICE, false);
+
+ sceneEntrySound();
+}
+
+void Scene201::step() {
+ if (_pterodactylFlag && (_vm->getRandomNumber(5000) == 9)) {
+ _globals._sequenceIndexes[5] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[5], false, 5, 1, 6, 0);
+ int idx = _scene->_dynamicHotspots.add(351, 13, _globals._sequenceIndexes[5], Common::Rect(0, 0, 0, 0));
+ _scene->_dynamicHotspots.setPosition(idx, Common::Point(270, 80), FACING_EAST);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[5], 8);
+ _vm->_sound->command(14);
+ _pterodactylFlag = false;
+ }
+
+ if (_game._trigger == 70) {
+ _globals._sequenceIndexes[6] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[6], false, 9, 1, 0, 0);
+ _game._player._visible = false;
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[6], 12, 16);
+ _globals._sequenceIndexes[7] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[7], false, 9, 1, 0, 0);
+ _vm->_sound->command(42);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[6], 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[7], 1);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[7], SEQUENCE_TRIGGER_SPRITE, 3, 81);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[7], SEQUENCE_TRIGGER_EXPIRE, 0, 71);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[6], SEQUENCE_TRIGGER_EXPIRE, 0, 73);
+ }
+
+ if (_game._trigger == 81) {
+ _scene->_kernelMessages.reset();
+ }
+
+ if (_game._trigger == 71) {
+ _globals._sequenceIndexes[7] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[7], false, 9, 0, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[7], -2, -2);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[7], 1);
+ }
+
+ if (_game._trigger == 73) {
+ _globals._sequenceIndexes[6] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[6], false, 9, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[6], 17, -2);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[6], SEQUENCE_TRIGGER_EXPIRE, 0, 74);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[6], 1);
+ }
+
+ if (_game._trigger == 74) {
+ _vm->_sound->command(40);
+
+ _scene->_kernelMessages.add(Common::Point(125, 56), 0xFDFC, 32, 82, 180, _game.getQuote(91));
+ _globals._sequenceIndexes[6] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[6], false, 9, 0, 0, 0);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[6], 1);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[6], -2, -2);
+ _scene->_sequences.addTimer(180, 75);
+ }
+
+ if (_game._trigger == 75) {
+ _globals[kMeteorologistEverSeen] = 0;
+ _scene->_nextSceneId = 202;
+ }
+
+ if (_game._trigger == 76) {
+ _game._player._stepEnabled = true;
+ _game._player._visible = true;
+ _game._player._priorTimer = _scene->_frameStartTime - _game._player._ticksAmount;
+ }
+
+ if (_game._trigger == 77) {
+ _globals[kTeleporterCommand] = 1;
+ _scene->_nextSceneId = _globals[kTeleporterDestination];
+ _scene->_reloadSceneFlag = true;
+ }
+
+ if (_game._trigger == 78) {
+ _vm->_sound->command(40);
+ _vm->_dialogs->show(20114);
+ _scene->_reloadSceneFlag = true;
+ }
+}
+
+void Scene201::actions() {
+ if (_action._lookFlag == false) {
+ if (_action.isAction(VERB_WALK_TOWARDS, NOUN_FIELD_TO_SOUTH))
+ _scene->_nextSceneId = 202;
+ else if ((_action.isAction(VERB_CLIMB_UP, NOUN_STEPS)) || (_action.isAction(VERB_WALK_INSIDE, NOUN_TELEPORTER)) || (_action.isAction(VERB_WALK_INSIDE, NOUN_STRANGE_DEVICE))) {
+ if (_game._trigger == 0) {
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ int sepChar = (_globals[kSexOfRex] == SEX_MALE) ? 't' : 'u';
+ _scene->loadAnimation(formAnimName(sepChar, 0), 1);
+ } else if (_game._trigger == 1) {
+ _scene->_nextSceneId = 213;
+ }
+ } else if (_action.isAction(VERB_LOOK, NOUN_GRASSY_FIELD)) {
+ _vm->_dialogs->show(20101);
+ } else if (_action.isAction(VERB_LOOK, NOUN_ROCKS)) {
+ _vm->_dialogs->show(20102);
+ } else if (_action.isAction(VERB_LOOK, NOUN_THORNY_BUSH)) {
+ _vm->_dialogs->show(20103);
+ } else if (_action.isAction(VERB_LOOK, NOUN_SKY)) {
+ _vm->_dialogs->show(20104);
+ } else if (_action.isAction(VERB_LOOK, NOUN_WATER)) {
+ _vm->_dialogs->show(20105);
+ } else if (_action.isAction(VERB_LOOK, NOUN_ISLAND_IN_DISTANCE)) {
+ _vm->_dialogs->show(20106);
+ } else if (_action.isAction(VERB_LOOK, NOUN_WEATHER_STATION)) {
+ _vm->_dialogs->show(20107);
+ } else if (_action.isAction(VERB_LOOK, NOUN_PATH)) {
+ _vm->_dialogs->show(20108);
+ } else if (_action.isAction(VERB_LOOK, NOUN_FIELD_TO_SOUTH)) {
+ _vm->_dialogs->show(20110);
+ } else if (_action.isAction(VERB_LOOK, NOUN_STRANGE_DEVICE)) {
+ if (_globals[kMeteorologistEverSeen])
+ _vm->_dialogs->show(20112);
+ else
+ _vm->_dialogs->show(20109);
+ } else if (_action.isAction(VERB_LOOK, NOUN_TELEPORTER)) {
+ _vm->_dialogs->show(20113);
+ } else
+ return;
+ } else {
+ _vm->_dialogs->show(20111);
+ }
+ _action._inProgress = false;
+}
+
+/*------------------------------------------------------------------------*/
+
+Scene202::Scene202(MADSEngine *vm) : Scene2xx(vm) {
+ _activeMsgFl = false;
+ _ladderTopFl = false;
+ _waitingMeteoFl = false;
+ _ladderHotspotId = -1;
+ _meteoClock1 = 0;
+ _meteoClock2 = 0;
+ _toStationFl = false;
+ _toTeleportFl = false;
+ _lastRoute = 0;
+ _stationCounter = 0;
+ _meteoFrame = 0;
+}
+
+void Scene202::synchronize(Common::Serializer &s) {
+ Scene2xx::synchronize(s);
+
+ s.syncAsByte(_activeMsgFl);
+ s.syncAsByte(_ladderTopFl);
+ s.syncAsByte(_waitingMeteoFl);
+ s.syncAsByte(_toStationFl);
+ s.syncAsByte(_toTeleportFl);
+
+ s.syncAsSint32LE(_ladderHotspotId);
+ s.syncAsSint32LE(_lastRoute);
+ s.syncAsSint32LE(_stationCounter);
+ s.syncAsSint32LE(_meteoFrame);
+
+ s.syncAsUint32LE(_meteoClock1);
+ s.syncAsUint32LE(_meteoClock2);
+ s.syncAsUint32LE(_startTime);
+
+ s.syncAsByte(_meteorologistSpecial);
+}
+
+void Scene202::setup() {
+ setPlayerSpritesPrefix();
+ setAAName();
+
+ _scene->addActiveVocab(NOUN_LADDER);
+ _scene->addActiveVocab(VERB_CLIMB_DOWN);
+ _scene->addActiveVocab(VERB_WALKTO);
+ _scene->addActiveVocab(NOUN_BONE);
+ _scene->addActiveVocab(NOUN_SKULL);
+ _scene->addActiveVocab(NOUN_BROKEN_LADDER);
+}
+
+void Scene202::enter() {
+ _game._player._beenVisible = true;
+ _globals._spriteIndexes[1] = _scene->_sprites.addSprites(formAnimName('b', 0));
+ _globals._spriteIndexes[2] = _scene->_sprites.addSprites(formAnimName('b', 1));
+ _globals._spriteIndexes[6] = _scene->_sprites.addSprites(formAnimName('b', 2));
+ _globals._spriteIndexes[3] = _scene->_sprites.addSprites(formAnimName('x', 0));
+ _globals._spriteIndexes[5] = _scene->_sprites.addSprites(formAnimName('l', -1));
+ if (_globals[kSexOfRex] != SEX_MALE) {
+ _globals._spriteIndexes[7] = _scene->_sprites.addSprites("*ROXBD_2");
+ } else {
+ _globals._spriteIndexes[7] = _scene->_sprites.addSprites("*RXMBD_2");
+ }
+ _globals._spriteIndexes[8] = _scene->_sprites.addSprites(formAnimName('a', 0));
+ _globals._spriteIndexes[9] = _scene->_sprites.addSprites(formAnimName('a', 1));
+ _globals._spriteIndexes[11] = _scene->_sprites.addSprites(formAnimName('a', 2));
+
+ _globals._sequenceIndexes[3] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[3], false, 6, 0, 0, 0);
+ _globals._sequenceIndexes[2] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[2], false, 6, 0, 0, 0);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[2], Common::Point(149, 113));
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 10);
+ int idx = _scene->_dynamicHotspots.add(NOUN_BONE, VERB_WALKTO, _globals._sequenceIndexes[2], Common::Rect(0, 0, 0, 0));
+ _scene->_dynamicHotspots.setPosition(idx, Common::Point(153, 97), FACING_SOUTH);
+
+ if (!(_globals[kBone202Status] & 1)) {
+ _globals._sequenceIndexes[1] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[1], false, 6, 0, 0, 0);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[1], Common::Point(130, 108));
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 10);
+ idx = _scene->_dynamicHotspots.add(NOUN_BONE, VERB_WALKTO, _globals._sequenceIndexes[1], Common::Rect(0, 0, 0, 0));
+ _scene->_dynamicHotspots.setPosition(idx, Common::Point(132, 97), FACING_SOUTH);
+ }
+
+ if (!(_globals[kBone202Status] & 2)) {
+ _globals._sequenceIndexes[6] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[6], false, 6, 0, 0, 0);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[6], Common::Point(166, 110));
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[6], 10);
+ idx = _scene->_dynamicHotspots.add(NOUN_BONE, VERB_WALKTO, _globals._sequenceIndexes[6], Common::Rect(0, 0, 0, 0));
+ _scene->_dynamicHotspots.setPosition(idx, Common::Point(165, 99), FACING_SOUTH);
+ }
+
+ if (_globals[kBone202Status])
+ _scene->changeVariant(_globals[kBone202Status]);
+
+ if (_scene->_priorSceneId == 201) {
+ _game._player._playerPos = Common::Point(190, 91);
+ _game._player._facing = FACING_SOUTH;
+ } else if (_scene->_priorSceneId != -2) {
+ _game._player._playerPos = Common::Point(178, 152);
+ _game._player._facing = FACING_NORTH;
+ }
+
+ if (_globals[kLadderBroken]) {
+ _globals._sequenceIndexes[5] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[5], false, 6, 0, 0, 0);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[5], 6);
+ _scene->_hotspots.activate(NOUN_LADDER, false);
+ idx = _scene->_dynamicHotspots.add(NOUN_BROKEN_LADDER, VERB_WALKTO, _globals._sequenceIndexes[5], Common::Rect(0, 0, 0, 0));
+ _scene->_dynamicHotspots.setPosition(idx, Common::Point(246, 124), FACING_NORTH);
+ }
+
+ _game.loadQuoteSet(0x5C, 0x5D, 0x5E, 0x5F, 0x60, 0x62, 0x63, 0x64, 0x65, 0x66, 0x61, 0);
+ _activeMsgFl = false;
+
+ if (_scene->_priorSceneId == -2) {
+ if (_waitingMeteoFl) {
+ _globals._sequenceIndexes[9] = _scene->_sequences.startCycle(_globals._spriteIndexes[9], false, 1);
+ _game._player._visible = false;
+ }
+ } else {
+ _waitingMeteoFl = false;
+ _ladderTopFl = false;
+ }
+
+ _meteoClock1 = _meteoClock2 = _scene->_frameStartTime;
+
+ if (_scene->_roomChanged)
+ _game._objects.addToInventory(OBJ_BINOCULARS);
+
+ if (_globals[kMeteorologistWatch] != METEOROLOGIST_NORMAL) {
+ _game._player._visible = false;
+ _game._player._stepEnabled = false;
+ _ladderTopFl = (_globals[kMeteorologistWatch] == METEOROLOGIST_TOWER);
+
+ if (_ladderTopFl) {
+ _globals._sequenceIndexes[10] = _scene->_sequences.startCycle(_globals._spriteIndexes[9], true, 8);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[10], 1);
+
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[10], Common::Point(247, 82));
+ _game._player._playerPos = Common::Point(246, 124);
+ _game._player._facing = FACING_NORTH;
+ _globals[kTeleporterUnderstood] = true;
+ } else {
+ _globals._sequenceIndexes[10] = _scene->_sequences.startCycle(_globals._spriteIndexes[9], false, 6);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[10], 1);
+
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[10], Common::Point(172, 123));
+ _game._player._playerPos = Common::Point(171, 122);
+ _game._player._facing = FACING_NORTH;
+ }
+
+ _scene->loadAnimation(formAnimName('M', -1), 71);
+ _scene->_activeAnimation->setCurrentFrame(200);
+ } else {
+ if (_ladderTopFl) {
+ _game._player._visible = false;
+ _scene->_sequences.startCycle(_globals._sequenceIndexes[9], true, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[9], 1);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[9], Common::Point(247, 82));
+ _game._player._playerPos = Common::Point(246, 124);
+ _game._player._facing = FACING_NORTH;
+ }
+ }
+
+ _meteorologistSpecial = false;
+}
+
+void Scene202::setRandomKernelMessage() {
+ int vocabId = _vm->getRandomNumber(92, 96);
+ _scene->_kernelMessages.reset();
+ _game._triggerSetupMode = SEQUENCE_TRIGGER_DAEMON;
+ _scene->_kernelMessages.add(Common::Point(0, 0), 0x1110, 34, 70, 120, _game.getQuote(vocabId));
+ _activeMsgFl = true;
+}
+
+void Scene202::step() {
+ if (!_activeMsgFl && (_game._player._playerPos == Common::Point(77, 105)) && (_game._player._facing == FACING_NORTH) && (_vm->getRandomNumber(999) == 0)) {
+ _scene->_kernelMessages.reset();
+ _activeMsgFl = false;
+ if (_vm->getRandomNumber(4) == 0)
+ setRandomKernelMessage();
+ }
+
+ if (_game._trigger == 70)
+ _activeMsgFl = false;
+
+ if (_game._trigger == 71) {
+ _vm->_sound->command(3);
+ _vm->_sound->command(9);
+
+ _meteoClock1 = _scene->_frameStartTime + 15 * 60;
+
+ if (_globals[kMeteorologistWatch] != METEOROLOGIST_NORMAL) {
+ Common::Point msgPos;
+ int msgFlag;
+ if (!_ladderTopFl) {
+ msgPos = Common::Point(0, 0);
+ msgFlag = 2;
+ } else {
+ msgPos = Common::Point(248, 15);
+ msgFlag = 0;
+ }
+ int msgIndex = _scene->_kernelMessages.add(msgPos, 0x1110, msgFlag | 32, 0, 120, _game.getQuote(102));
+ _scene->_kernelMessages.setQuoted(msgIndex, 4, true);
+
+ if (_globals[kMeteorologistWatch] == METEOROLOGIST_GROUND) {
+ _action._activeAction._verbId = VERB_LOOK;
+ _action._activeAction._objectNameId = NOUN_BINOCULARS;
+ _action._activeAction._indirectObjectId = NOUN_STRANGE_DEVICE;
+ _game._triggerSetupMode = SEQUENCE_TRIGGER_PARSER;
+ _scene->_sequences.addTimer(2 * 60, 2);
+ _meteorologistSpecial = true;
+ } else if (_globals[kMeteorologistWatch] == METEOROLOGIST_TOWER) {
+ _scene->_sequences.addTimer(2 * 60, 90);
+ }
+ }
+
+ _globals[kMeteorologistWatch] = METEOROLOGIST_NORMAL;
+ }
+
+ switch (_game._trigger) {
+ case 90:
+ _vm->_sound->command(41);
+ _scene->_sequences.remove(_globals._sequenceIndexes[10]);
+ _globals._sequenceIndexes[9] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[9], true, 6, 1, 0, 0);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[9], Common::Point(247, 82));
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[9], 1);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[9], SEQUENCE_TRIGGER_EXPIRE, 0, 91);
+ break;
+ case 91:
+ _globals._sequenceIndexes[9] = _scene->_sequences.startCycle(_globals._spriteIndexes[9], true, 1);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[9], Common::Point(247, 82));
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[9], 1);
+ _scene->_sequences.addTimer(60, 92);
+ break;
+ case 92: {
+ _scene->_sequences.remove(_globals._sequenceIndexes[9]);
+ _globals._sequenceIndexes[11] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[11], false, 6, 1, 0, 0);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[11], 1);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[11], SEQUENCE_TRIGGER_EXPIRE, 0, 93);
+ _scene->_kernelMessages.reset();
+ int msgIndex = _scene->_kernelMessages.add(Common::Point(0, -65), 0x1110, 32, 0, 60, _game.getQuote(98));
+ _scene->_kernelMessages.setSeqIndex(msgIndex, _globals._sequenceIndexes[11]);
+ }
+ break;
+ case 93: {
+ _globals[kLadderBroken] = false;
+ _globals._sequenceIndexes[5] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[5], false, 6, 0, 0, 0);
+ _scene->_hotspots.activate(NOUN_LADDER, false);
+ int idx = _scene->_dynamicHotspots.add(NOUN_BROKEN_LADDER, VERB_WALKTO, _globals._sequenceIndexes[5], Common::Rect(0, 0, 0, 0));
+ _scene->_dynamicHotspots.setPosition(idx, Common::Point(246, 124), FACING_NORTH);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[11], _globals._sequenceIndexes[5]);
+ _scene->_sequences.updateTimeout(-1, _globals._sequenceIndexes[11]);
+ _game._player._stepEnabled = true;
+ _game._player._visible = true;
+ _ladderTopFl = false;
+ _scene->_kernelMessages.reset();
+ _scene->_kernelMessages.add(Common::Point(0, 0), 0x1110, 34, 0, 120, _game.getQuote(99));
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (!_scene->_activeAnimation && (_globals[kMeteorologistStatus] != METEOROLOGIST_GONE) && (_meteoClock2 <= _scene->_frameStartTime) && (_meteoClock1 <= _scene->_frameStartTime)) {
+ int randVal = _vm->getRandomNumber(1, 500);
+ int threshold = 1;
+ if (_ladderTopFl)
+ threshold += 25;
+ if (!_globals[kMeteorologistEverSeen])
+ threshold += 25;
+ if (threshold >= randVal) {
+ _vm->_sound->command(17);
+ _scene->loadAnimation(formAnimName('M', -1), 71);
+ _toStationFl = true;
+ _toTeleportFl = false;
+ _globals[kMeteorologistEverSeen] = true;
+ _lastRoute = 0;
+ _stationCounter = 0;
+ _meteoClock2 = _scene->_frameStartTime + 2;
+ }
+ }
+
+ if (!_scene->_activeAnimation)
+ return;
+
+ if (_waitingMeteoFl) {
+ if (_scene->_activeAnimation->getCurrentFrame() >= 200) {
+ if ((_globals[kMeteorologistWatch] == METEOROLOGIST_TOWER) || _globals[kLadderBroken]) {
+ _scene->_nextSceneId = 213;
+ } else {
+ _vm->_dialogs->show(20201);
+ _scene->_reloadSceneFlag = true;
+ }
+ }
+
+ if ((_scene->_activeAnimation->getCurrentFrame() == 160) && (_meteoFrame != _scene->_activeAnimation->getCurrentFrame())) {
+ Common::Point msgPos;
+ int msgFlag;
+ if (!_ladderTopFl) {
+ msgPos = Common::Point(0, 0);
+ msgFlag = 2;
+ } else {
+ msgPos = Common::Point(248, 15);
+ msgFlag = 0;
+ }
+ int msgIndex = _scene->_kernelMessages.add(msgPos, 0x1110, msgFlag | 32, 0, 120, _game.getQuote(101));
+ _scene->_kernelMessages.setQuoted(msgIndex, 4, true);
+ }
+ }
+
+ if (_meteoClock2 + 120 * 60 <= _scene->_frameStartTime) {
+ _toTeleportFl = true;
+ }
+
+ if (_scene->_activeAnimation->getCurrentFrame() == _meteoFrame) {
+ return;
+ }
+
+ _meteoFrame = _scene->_activeAnimation->getCurrentFrame();
+ int randVal = _vm->getRandomNumber(1, 1000);
+ int frameStep = -1;
+
+ switch (_scene->_activeAnimation->getCurrentFrame()) {
+ case 42:
+ case 77:
+ case 96:
+ _stationCounter = 0;
+ frameStep = subStep1(randVal);
+ break;
+ case 51:
+ case 74:
+ _toStationFl = false;
+ frameStep = subStep2(randVal);
+ break;
+ case 27:
+ case 119:
+ case 159:
+ frameStep = subStep3(randVal);
+ break;
+ case 176:
+ frameStep = subStep4(randVal);
+ break;
+ case 59:
+ _lastRoute = 3;
+ ++_stationCounter;
+ if (randVal <= 800)
+ frameStep = 55;
+ break;
+ case 89:
+ _lastRoute = 1;
+ if (randVal <= 700)
+ frameStep = 83;
+ break;
+ case 137:
+ _lastRoute = 2;
+ if (randVal <= 700)
+ frameStep = 126;
+ break;
+ }
+
+ if (frameStep >= 0 && frameStep != _scene->_activeAnimation->getCurrentFrame() + 1) {
+ _scene->_activeAnimation->setCurrentFrame(frameStep);
+ _meteoFrame = frameStep;
+ }
+}
+
+int Scene202::subStep1(int randVal) {
+ if ((randVal <= 100) || _toStationFl)
+ return 42;
+
+ if ((randVal <= 200) || _toTeleportFl)
+ return 96;
+
+ if ((randVal <= 300) && (_lastRoute != 1))
+ return 77;
+
+ return 76;
+}
+
+int Scene202::subStep2(int randVal) {
+ if ((randVal <= 150) && (_stationCounter < 5))
+ return 51;
+
+ if ((randVal <= 300) || _toTeleportFl)
+ return 74;
+
+ if (randVal <= 400)
+ return 64;
+
+ return 44;
+}
+
+int Scene202::subStep3(int randVal) {
+ if ((randVal <= 100) || _toStationFl)
+ return 27;
+
+ if ((randVal <= 200) || _toTeleportFl)
+ return 159;
+
+ if ((randVal <= 300) && (_lastRoute != 2))
+ return 119;
+
+ return 110;
+}
+
+int Scene202::subStep4(int randVal) {
+ if ((randVal <= 100) || _toTeleportFl)
+ return 176;
+
+ if (randVal <= 200)
+ return 19;
+
+ return 166;
+}
+
+void Scene202::preActions() {
+ Player &player = _vm->_game->_player;
+
+ if (player._readyToWalk)
+ _scene->_kernelMessages.reset();
+
+ if (!_ladderTopFl && (_action.isAction(VERB_CLIMB_DOWN, NOUN_LADDER) || !player._readyToWalk)) {
+ if (_game._trigger == 0) {
+ _vm->_sound->command(29);
+ player._readyToWalk = false;
+ _game._player._stepEnabled = false;
+ _scene->_sequences.remove(_globals._sequenceIndexes[9]);
+ _globals._sequenceIndexes[8] = _scene->_sequences.addReverseSpriteCycle(_globals._spriteIndexes[8], false, 6, 1, 0, 0);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[8], 1);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[8], SEQUENCE_TRIGGER_EXPIRE, 0, 1);
+ } else if (_game._trigger == 1) {
+ _scene->_sequences.updateTimeout(-1, _globals._sequenceIndexes[8]);
+ _scene->_dynamicHotspots.remove(_ladderHotspotId);
+ _game._player._visible = true;
+ player._readyToWalk = true;
+ _game._player._stepEnabled = true;
+ _ladderTopFl = false;
+ }
+ }
+
+ if (_action.isAction(VERB_LOOK, NOUN_BINOCULARS) && (_action._activeAction._indirectObjectId > 0)) {
+ if (!player._readyToWalk || _ladderTopFl)
+ _game._player._needToWalk = false;
+ else
+ _game._player._needToWalk = true;
+
+ if (!_ladderTopFl)
+ _game._player.walk(Common::Point(171, 122), FACING_NORTH);
+ }
+}
+
+void Scene202::actions() {
+ if (_action._lookFlag) {
+ _vm->_dialogs->show(20219);
+ return;
+ }
+
+ if (_action.isAction(VERB_CLIMB_DOWN, NOUN_LADDER)) {
+ _action._inProgress = false;
+ return;
+ } else if (_action.isAction(VERB_WALK_TOWARDS, NOUN_FIELD_TO_SOUTH)) {
+ _scene->_nextSceneId = 203;
+ } else if (_action.isAction(VERB_WALK_TOWARDS, NOUN_FIELD_TO_NORTH)) {
+ if (_globals[kMeteorologistStatus] != METEOROLOGIST_GONE) {
+ if (_scene->_activeAnimation)
+ _globals[kMeteorologistStatus] = METEOROLOGIST_PRESENT;
+ else
+ _globals[kMeteorologistStatus] = METEOROLOGIST_ABSENT;
+ }
+ _scene->_nextSceneId = 201;
+ } else if (_action.isAction(VERB_TAKE, NOUN_BONE) && (_action._mainObjectSource == 4)) {
+ switch (_game._trigger) {
+ case 0:
+ if (_game._objects.isInInventory(OBJ_BONES)) {
+ _vm->_dialogs->show(20221);
+ } else {
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._sequenceIndexes[7] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[7], false, 3, 2, 0, 0);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[7]);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[7], SEQUENCE_TRIGGER_SPRITE, 6, 1);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[7], SEQUENCE_TRIGGER_EXPIRE, 0, 2);
+ }
+ break;
+ case 1:
+ if (_game._player._playerPos == Common::Point(132, 97)) {
+ _scene->_sequences.remove(_globals._sequenceIndexes[1]);
+ _globals[kBone202Status] |= BONE_202_LEFT_GONE;
+ } else {
+ _scene->_sequences.remove(_globals._sequenceIndexes[6]);
+ _globals[kBone202Status] |= BONE_202_RIGHT_GONE;
+ }
+ break;
+ case 2:
+ if (_game._objects.isInInventory(OBJ_BONE)) {
+ _game._objects.removeFromInventory(OBJ_BONE, NOWHERE);
+ _game._objects.addToInventory(OBJ_BONES);
+ _vm->_dialogs->showItem(OBJ_BONES, 20218);
+ } else {
+ _game._objects.addToInventory(OBJ_BONE);
+ _vm->_dialogs->showItem(OBJ_BONE, 20218);
+ }
+ _scene->changeVariant(_globals[kBone202Status]);
+ _game._player._stepEnabled = true;
+ _game._player._visible = true;
+ break;
+ default:
+ break;
+ }
+
+ _action._inProgress = false;
+ } else if ((_action.isAction(VERB_CLIMB_UP, NOUN_LADDER)) && !_globals[kLadderBroken]) {
+ switch (_game._trigger) {
+ case 0:
+ _vm->_sound->command(29);
+ _meteoClock1 = _scene->_frameStartTime;
+ _game._player._visible = false;
+ _game._player._stepEnabled = false;
+
+ _ladderHotspotId = _scene->_dynamicHotspots.add(NOUN_LADDER, 79, -1, Common::Rect(241, 68, 241 + 12, 68 + 54));
+ _scene->_dynamicHotspots.setPosition(_ladderHotspotId, Common::Point(246, 124), FACING_NORTH);
+ _globals._sequenceIndexes[8] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[8], false, 6, 1, 0, 0);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[8], 1);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[8], SEQUENCE_TRIGGER_EXPIRE, 0, 1);
+ break;
+ case 1: {
+ _globals._sequenceIndexes[9] = _scene->_sequences.startCycle(_globals._spriteIndexes[9], true, 1);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[9], Common::Point(247, 82));
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[9], 1);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[8], _globals._sequenceIndexes[9]);
+ _ladderTopFl = true;
+ _game._player._stepEnabled = true;
+ int msgIndex = _scene->_kernelMessages.add(Common::Point(248, 15), 0x1110, 32, 0, 60, _game.getQuote(97));
+ _scene->_kernelMessages.setQuoted(msgIndex, 4, true);
+ }
+ break;
+ default:
+ _action._inProgress = false;
+ return;
+ }
+ } else if (((_action.isAction(VERB_LOOK, NOUN_BINOCULARS, 0x82)) || (_action.isAction(VERB_LOOK, NOUN_BINOCULARS, 0x1B6))) && (_globals[kSexOfRex] == SEX_MALE)) {
+ if (!_ladderTopFl) {
+ switch (_game._trigger) {
+ case 0:
+ _game._player._stepEnabled = false;
+ _game._player._visible= false;
+ _globals._sequenceIndexes[10] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[9], false, 6, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[10], 1, 6);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[10], Common::Point(172, 123));
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[10], 1);
+ _scene->_sequences.updateTimeout(-1, _globals._sequenceIndexes[10]);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[10], SEQUENCE_TRIGGER_EXPIRE, 0, 1);
+ break;
+ case 1:
+ _globals._sequenceIndexes[10] = _scene->_sequences.startCycle(_globals._spriteIndexes[9], false, 6);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[10], 1);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[10], Common::Point(172, 123));
+ if (_scene->_activeAnimation) {
+ _waitingMeteoFl = true;
+ _globals[kMeteorologistWatch] = METEOROLOGIST_GROUND;
+ } else {
+ _scene->_sequences.addTimer(120, 2);
+ }
+ break;
+ case 2:
+ if (!_scene->_activeAnimation && !_meteorologistSpecial) {
+ _vm->_dialogs->show(20222);
+ }
+ _scene->_sequences.remove(_globals._sequenceIndexes[10]);
+ _globals._sequenceIndexes[10] = _scene->_sequences.addReverseSpriteCycle(_globals._spriteIndexes[9], false, 6, 1, 0, 0);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[10], 1);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[10], 1, 6);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[10], Common::Point(172, 123));
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[10], SEQUENCE_TRIGGER_EXPIRE, 0, 3);
+ break;
+ case 3:
+ _scene->_sequences.updateTimeout(-1, _globals._sequenceIndexes[10]);
+ _game._player._stepEnabled = true;
+ _game._player._visible = true;
+ break;
+ default:
+ _action._inProgress = false;
+ return;
+ }
+ } else {
+ switch (_game._trigger) {
+ case 0:
+ _toTeleportFl = true;
+ _game._player._stepEnabled = false;
+ _scene->_sequences.remove(_globals._sequenceIndexes[9]);
+ _globals._sequenceIndexes[9] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[9], true, 6, 1, 0, 0);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[9], Common::Point(247, 82));
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[9], 1);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[9], SEQUENCE_TRIGGER_EXPIRE, 0, 1);
+ break;
+ case 1:
+ _globals._sequenceIndexes[10] = _scene->_sequences.startCycle(_globals._spriteIndexes[9], true, -2);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[10], Common::Point(247, 82));
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[10], 1);
+ if (_scene->_activeAnimation) {
+ if (_scene->_activeAnimation->getCurrentFrame() > 200) {
+ _scene->_sequences.addTimer(120, 2);
+ } else {
+ _waitingMeteoFl = true;
+ _globals[kMeteorologistWatch] = METEOROLOGIST_GONE;
+ if ((_scene->_activeAnimation->getCurrentFrame() >= 44) && (_scene->_activeAnimation->getCurrentFrame() <= 75)) {
+ _scene->_kernelMessages.reset();
+ int msgIndex = _scene->_kernelMessages.add(Common::Point(248, 15), 0x1110, 32, 0, 60, _game.getQuote(100));
+ _scene->_kernelMessages.setQuoted(msgIndex, 4, false);
+ } else {
+ _action._inProgress = false;
+ return;
+ }
+ }
+ } else {
+ _scene->_sequences.addTimer(120, 2);
+ }
+ break;
+ case 2:
+ if (!_scene->_activeAnimation)
+ _vm->_dialogs->show(20222);
+ _meteorologistSpecial = false;
+ _scene->_sequences.remove(_globals._sequenceIndexes[10]);
+ _globals._sequenceIndexes[9] = _scene->_sequences.addReverseSpriteCycle(_globals._spriteIndexes[9], false, 6, 1, 0, 0);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[9], Common::Point(247, 82));
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[9], 1);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[9], SEQUENCE_TRIGGER_EXPIRE, 0, 3);
+ break;
+ case 3:
+ _globals._sequenceIndexes[9] = _scene->_sequences.startCycle(_globals._spriteIndexes[9], true, 1);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[9], Common::Point(247, 82));
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[9], 1);
+ _game._player._stepEnabled = true;
+ break;
+ default:
+ _action._inProgress = false;
+ return;
+ }
+ }
+ } else if (_action.isAction(VERB_WALK_INSIDE, NOUN_HUT)) {
+ setRandomKernelMessage();
+ } else if (_action.isAction(VERB_LOOK, NOUN_ROCKS)) {
+ _vm->_dialogs->show(20202);
+ } else if (_action.isAction(VERB_LOOK, NOUN_FIRE_PIT)) {
+ _vm->_dialogs->show(20203);
+ } else if (_action.isAction(VERB_LOOK, NOUN_GRASS)) {
+ _vm->_dialogs->show(20204);
+ } else if (_action.isAction(VERB_LOOK, NOUN_FIELD_TO_NORTH)) {
+ if ((_globals[kMeteorologistStatus] == METEOROLOGIST_ABSENT) || (_globals[kMeteorologistStatus] == METEOROLOGIST_GONE))
+ _vm->_dialogs->show(20205);
+ else if (_globals[kMeteorologistStatus] == METEOROLOGIST_PRESENT)
+ _vm->_dialogs->show(20220);
+ } else if (_action.isAction(VERB_LOOK, NOUN_WATCH_TOWER)) {
+ _vm->_dialogs->show(20206);
+ } else if (_action.isAction(VERB_LOOK, NOUN_TALL_GRASS)) {
+ _vm->_dialogs->show(20207);
+ } else if (_action.isAction(VERB_LOOK, NOUN_TREES)) {
+ _vm->_dialogs->show(20208);
+ } else if (_action.isAction(VERB_LOOK, NOUN_TREE)) {
+ _vm->_dialogs->show(20209);
+ } else if (_action.isAction(VERB_LOOK, NOUN_SKY)) {
+ _vm->_dialogs->show(20210);
+ } else if (_action.isAction(VERB_LOOK, NOUN_HUT)) {
+ if ((_game._player._playerPos == Common::Point(77, 105)) && (_game._player._facing == FACING_NORTH))
+ _vm->_dialogs->show(20212);
+ else
+ _vm->_dialogs->show(20211);
+ } else if (_action.isAction(VERB_LOOK, NOUN_STRANGE_DEVICE)) {
+ _vm->_dialogs->show(20213);
+ } else if (_action.isAction(VERB_LOOK, NOUN_OCEAN_IN_DISTANCE)) {
+ _vm->_dialogs->show(20214);
+ } else if (_action.isAction(VERB_LOOK, NOUN_SKULL)) {
+ _vm->_dialogs->show(20215);
+ } else if (_action.isAction(VERB_TAKE, NOUN_SKULL)) {
+ _vm->_dialogs->show(20216);
+ } else if (_action.isAction(VERB_LOOK, NOUN_BONES) && _action._commandSource == 4) {
+ _vm->_dialogs->show(20217);
+ }
+
+ _action._inProgress = false;
+}
+
+/*****************************************************************************/
+
+Scene203::Scene203(MADSEngine *vm) : Scene2xx(vm) {
+ _rhotundaEat2Fl = false;
+ _rhotundaEatFl = false;
+}
+
+void Scene203::synchronize(Common::Serializer &s) {
+ Scene2xx::synchronize(s);
+
+ s.syncAsByte(_rhotundaEat2Fl);
+ s.syncAsByte(_rhotundaEatFl);
+}
+
+void Scene203::setup() {
+ setPlayerSpritesPrefix();
+ setAAName();
+ _scene->addActiveVocab(477);
+}
+
+void Scene203::enter() {
+ if (_scene->_priorSceneId == 202) {
+ _game._player._playerPos = Common::Point(187, 99);
+ _game._player._facing = FACING_SOUTH;
+ } else if (_scene->_priorSceneId == 209) {
+ _game._player._playerPos = Common::Point(308, 117);
+ _game._player._facing = FACING_WEST;
+ } else if (_scene->_priorSceneId != -2) {
+ _game._player._playerPos = Common::Point(155, 152);
+ _game._player._facing = FACING_NORTH;
+ }
+
+ _rhotundaEatFl = false;
+ _rhotundaEat2Fl = false;
+
+ if ((_globals[kRhotundaStatus] == 0) && (!_scene->_roomChanged)) {
+ _rhotundaEatFl = true;
+ _game._player.walk(Common::Point(158, 135), FACING_SOUTH);
+ int idx = _scene->_dynamicHotspots.add(131, 396, 0, Common::Rect(0, 0, 320, 156));
+ _scene->_dynamicHotspots.setPosition(idx, Common::Point(155, 152), FACING_SOUTH);
+ _scene->_dynamicHotspots.setCursor(idx, CURSOR_GO_DOWN);
+ }
+
+ if (!_rhotundaEatFl) {
+ _globals._spriteIndexes[0] = _scene->_sprites.addSprites(formAnimName('b', -1));
+ if (_vm->getRandomNumber(1, 3) == 2) {
+ _globals._spriteIndexes[15] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[0], false, 9, 1, 0, 0);
+ int idx = _scene->_dynamicHotspots.add(477, 209, _globals._spriteIndexes[15], Common::Rect(0, 0, 0, 0));
+ _scene->_dynamicHotspots.setPosition(idx, Common::Point(-2, 0), FACING_NONE);
+ _vm->_sound->command(14);
+ }
+ }
+
+ _game.loadQuoteSet(0x67, 0x68, 0x69, 0x6A, 0x5A, 0);
+
+ if (_rhotundaEatFl) {
+ _scene->_kernelMessages.add(Common::Point(0, 0), 0x1110, 34, 0, 120, _game.getQuote(_vm->getRandomNumber(103, 106)));
+ }
+
+ sceneEntrySound();
+}
+
+void Scene203::step() {
+ if (!_rhotundaEatFl)
+ return;
+
+ if ((_game._trigger == 0) && _rhotundaEat2Fl)
+ return;
+
+ if ((_game._player._playerPos != Common::Point(158, 136)) || (_game._player._facing != FACING_SOUTH))
+ return;
+
+ _rhotundaEat2Fl = true;
+
+ if (_game._trigger == 0) {
+ _game._player._visible = false;
+ _game._player._stepEnabled = false;
+ _vm->_palette->lock();
+ _scene->_kernelMessages.reset();
+ _scene->resetScene();
+ _vm->_events->setCursor2(CURSOR_WAIT);
+ _scene->loadAnimation(Resources::formatName(203, 'a', -1, EXT_AA, ""), 81);
+ } else if (_game._trigger == 81) {
+ _scene->_nextSceneId = 208;
+ _scene->_reloadSceneFlag = true;
+ }
+}
+
+void Scene203::preActions() {
+ if (_rhotundaEatFl && !_action.isAction(VERB_WALK_TOWARDS, NOUN_FIELD_TO_SOUTH)) {
+ _game._player.walk(Common::Point(158, 136), FACING_SOUTH);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_WALKTO, NOUN_OPEN_AREA_TO_EAST))
+ _game._player._walkOffScreenSceneId = 209;
+}
+
+void Scene203::actions() {
+ if (_action._savedFields._lookFlag) {
+ _vm->_dialogs->show(20307);
+ } else if (_action.isAction(VERB_WALK_TOWARDS, NOUN_FIELD_TO_SOUTH)) {
+ _scene->_nextSceneId = 208;
+ } else if (_action.isAction(VERB_WALK_TOWARDS, NOUN_FIELD_TO_NORTH)) {
+ _scene->_nextSceneId = 202;
+ } else if (_action.isAction(VERB_LOOK, NOUN_SKY)) {
+ _vm->_dialogs->show(20301);
+ } else if (_action.isAction(VERB_LOOK, NOUN_CLIFF_FACE)) {
+ _vm->_dialogs->show(20302);
+ } else if (_action.isAction(VERB_LOOK, NOUN_PALM_TREE)) {
+ _vm->_dialogs->show(20303);
+ } else if (_action.isAction(VERB_LOOK, NOUN_FIELD_TO_NORTH)) {
+ _vm->_dialogs->show(20304);
+ } else if (_action.isAction(VERB_LOOK, NOUN_GRASSY_FIELD)) {
+ _vm->_dialogs->show(20305);
+ } else if (_action.isAction(VERB_LOOK, NOUN_BOULDERS)) {
+ _vm->_dialogs->show(20305);
+ } else
+ return;
+
+ _action._inProgress = false;
+}
+
+/*****************************************************************************/
+
+void Scene205::setup() {
+ setPlayerSpritesPrefix();
+ setAAName();
+ _scene->addActiveVocab(VERB_WALKTO);
+ _scene->addActiveVocab(NOUN_CHICKEN);
+ _scene->addActiveVocab(NOUN_PIRANHA);
+}
+
+Scene205::Scene205(MADSEngine *vm) : Scene2xx(vm) {
+ _lastFishTime = 0;
+ _chickenTime = 0;
+ _beingKicked = false;
+ _kernelMessage = -1;
+}
+
+void Scene205::synchronize(Common::Serializer &s) {
+ Scene2xx::synchronize(s);
+
+ s.syncAsUint32LE(_lastFishTime);
+ s.syncAsUint32LE(_chickenTime);
+ s.syncAsByte(_beingKicked);
+ s.syncAsSint16LE(_kernelMessage);
+}
+
+void Scene205::enter() {
+ _globals._spriteIndexes[1] = _scene->_sprites.addSprites(formAnimName('x', 0));
+ _globals._spriteIndexes[2] = _scene->_sprites.addSprites(formAnimName('x', 1));
+ _globals._spriteIndexes[3] = _scene->_sprites.addSprites(formAnimName('x', 2));
+ _globals._spriteIndexes[5] = _scene->_sprites.addSprites(formAnimName('f', -1));
+ _globals._spriteIndexes[4] = _scene->_sprites.addSprites(formAnimName('c', -1));
+ _globals._spriteIndexes[6] = _scene->_sprites.addSprites(formAnimName('p', -1));
+
+ if (_globals[kSexOfRex] == SEX_MALE)
+ _globals._spriteIndexes[8] = _scene->_sprites.addSprites(formAnimName('a', 1));
+
+ _globals._sequenceIndexes[1] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[1], false, 10, 0, 0, 3);
+ int idx = _scene->_dynamicHotspots.add(73, 13, _globals._sequenceIndexes[1], Common::Rect(0, 0, 0, 0));
+ _scene->_dynamicHotspots.setPosition(idx, Common::Point(162, 120), FACING_NORTHEAST);
+
+ _globals._sequenceIndexes[2] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[2], false, 15, 0, 0, 0);
+ idx = _scene->_dynamicHotspots.add(73, 13, _globals._sequenceIndexes[1], Common::Rect(0, 0, 0, 0));
+ _scene->_dynamicHotspots.setPosition(idx, Common::Point(162, 120), FACING_NORTHEAST);
+
+ _globals._sequenceIndexes[3] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[3], false, 9, 0, 0, 0);
+ _globals._sequenceIndexes[5] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[5], false, 6, 0, 0, 0);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[5], 11);
+
+ if (!_game._visitedScenes._sceneRevisited) {
+ _lastFishTime = _scene->_frameStartTime;
+ _globals._sequenceIndexes[6] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[6], false, 7, 1, 0, 0);
+ idx = _scene->_dynamicHotspots.add(269, 13, _globals._sequenceIndexes[6], Common::Rect(0, 0, 0, 0));
+ _scene->_dynamicHotspots.setPosition(idx, Common::Point(49, 86), FACING_NORTH);
+ }
+
+ if (_game._objects[12]._roomNumber == 205) {
+ _globals._sequenceIndexes[4] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[4], false, 7, 0, 0, 0);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[4], 11);
+ } else {
+ _scene->_hotspots.activate(450, false);
+ }
+
+ _beingKicked = false;
+ _game.loadQuoteSet(0x6B, 0x70, 0x71, 0x72, 0x5A, 0x74, 0x75, 0x76, 0x77, 0x78, 0x73, 0x79, 0x7A, 0x7B, 0x7C,
+ 0x7D, 0x7E, 0x7F, 0x80, 0xAC, 0xAD, 0xAE, 0x6C, 0x6D, 0x6E, 0x6F, 0x2, 0);
+ _dialog1.setup(0x2A, 0x5A, 0x78, 0x74, 0x75, 0x76, 0x77, 0);
+
+ if (!_game._visitedScenes._sceneRevisited)
+ _dialog1.set(0x5A, 0x74, 0x75, 0x77, 0);
+
+ _vm->_palette->setEntry(250, 63, 50, 20);
+ _vm->_palette->setEntry(251, 50, 40, 15);
+ _vm->_palette->setEntry(252, 63, 63, 40);
+ _vm->_palette->setEntry(253, 50, 50, 30);
+
+ _chickenTime = _vm->_game->_scene._frameStartTime;
+
+ if (_globals[kSexOfRex] == SEX_FEMALE)
+ _scene->_kernelMessages.initRandomMessages(3,
+ Common::Rect(195, 99, 264, 134), 13, 2, 0xFDFC, 60,
+ 108, 108, 109, 109, 110, 110, 111, 108, 0);
+
+ if (_scene->_priorSceneId != -2)
+ _game._player._playerPos = Common::Point(99, 152);
+
+ if (_globals[kSexOfRex] != SEX_MALE) {
+ _scene->loadAnimation(formAnimName('a', -1));
+ _scene->_activeAnimation->_resetFlag = false;
+ } else {
+ _beingKicked = true;
+ _globals._sequenceIndexes[8] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[8], false, 8, 1, 0, 0);
+ _game._player._visible = false;
+ _game._player._stepEnabled = false;
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[8], 2);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[8], SEQUENCE_TRIGGER_SPRITE, 6, 73);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[8], SEQUENCE_TRIGGER_SPRITE, 11, 74);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[8], SEQUENCE_TRIGGER_EXPIRE, 0, 0);
+ }
+ sceneEntrySound();
+}
+
+void Scene205::step() {
+ if (_globals[kSexOfRex] == SEX_FEMALE) {
+ _scene->_kernelMessages.randomServer();
+
+ if (_vm->_game->_scene._frameStartTime >= _chickenTime) {
+ int chanceMinor = _scene->_kernelMessages.checkRandom() + 1;
+ if (_scene->_kernelMessages.generateRandom(100, chanceMinor))
+ _vm->_sound->command(28);
+
+ _chickenTime = _vm->_game->_scene._frameStartTime + 2;
+ }
+ }
+
+ if (_vm->_game->_scene._frameStartTime - _lastFishTime > 1300) {
+ _globals._sequenceIndexes[6] = _scene->_sequences.addSpriteCycle(
+ _globals._spriteIndexes[6], false, 5, 1, 0, 0);
+ int idx = _scene->_dynamicHotspots.add(269, 13, _globals._sequenceIndexes[6],
+ Common::Rect(0, 0, 0, 0));
+ _scene->_dynamicHotspots.setPosition(idx, Common::Point(49, 86), FACING_NORTH);
+ _lastFishTime = _vm->_game->_scene._frameStartTime;
+ }
+
+ if (_game._trigger == 73)
+ _scene->_kernelMessages.add(Common::Point(160, 68), 0xFBFA, 32, 0, 60, _game.getQuote(112));
+
+ if (_game._trigger == 74) {
+ _vm->_sound->command(26);
+ _scene->_kernelMessages.add(Common::Point(106, 90), 0x1110, 32, 0, 60, _game.getQuote(113));
+ }
+
+ if (_game._trigger == 71) {
+ _globals._sequenceIndexes[8] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[8], false, 6, 0, 0, 0);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[8], 2);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[8], -2, -2);
+ _scene->_kernelMessages.reset();
+ _scene->_kernelMessages.add(Common::Point(160, 68), 0xFBFA, 32, 72, 180, _game.getQuote(114));
+ }
+
+ if (_game._trigger == 72)
+ _scene->_nextSceneId = 211;
+}
+
+void Scene205::handleWomanSpeech(int quote) {
+ _kernelMessage = _scene->_kernelMessages.add(Common::Point(186, 27), 0xFBFA, 0, 0, 9999999, _game.getQuote(quote));
+}
+
+void Scene205::actions() {
+ if (_game._screenObjects._inputMode == 1) {
+ if (_kernelMessage >= 0)
+ _scene->_kernelMessages.remove(_kernelMessage);
+ _kernelMessage = -1;
+
+ if (_game._trigger == 0) {
+ _game._player._stepEnabled = false;
+ _scene->_kernelMessages.add(Common::Point(0, 0), 0x1110, 18, 1, 120, _game.getQuote(_action._activeAction._verbId));
+ } else {
+ if ((_game._trigger > 1) || (_action._activeAction._verbId != 0x76))
+ _game._player._stepEnabled = true;
+
+ switch (_action._activeAction._verbId) {
+ case 0x5A:
+ handleWomanSpeech(0x7A);
+ _dialog1.write(0x78, true);
+ _dialog1.write(0x5A, false);
+ break;
+
+ case 0x74:
+ handleWomanSpeech(0x7C);
+ _dialog1.write(0x74, false);
+ _dialog1.write(0x76, true);
+ break;
+
+ case 0x75:
+ case 0x78:
+ handleWomanSpeech(0x7B);
+ _dialog1.write(_action._activeAction._verbId, false);
+ _vm->_dialogs->show(20501);
+ break;
+
+ case 0x76:
+ if (_game._trigger == 1) {
+ handleWomanSpeech(0x7D);
+ _scene->_sequences.addTimer(120, 2);
+ } else if (_game._trigger == 2) {
+ handleWomanSpeech(0x7E);
+ _dialog1.write(0x76, false);
+ _globals[kChickenPermitted] = true;
+ }
+ break;
+
+ case 0x77:
+ _scene->_kernelMessages.add(Common::Point(186, 27), 0xFBFA, 0, 0, 120, _game.getQuote(0x7F));
+ _scene->_userInterface.setup(kInputBuildingSentences);
+ break;
+
+ default:
+ break;
+ }
+
+ if (_action._activeAction._verbId != 0x77)
+ _dialog1.start();
+ }
+ } else if (_action._lookFlag)
+ _vm->_dialogs->show(20502);
+ else if (_action.isAction(VERB_LOOK, NOUN_BINOCULARS, 0x1C8))
+ _vm->_dialogs->show(20518);
+ else if (_action.isAction(VERB_TALKTO, NOUN_NATIVE_WOMAN)) {
+ if (_game._trigger == 0) {
+ _game._player._stepEnabled = false;
+ _scene->_kernelMessages.add(Common::Point(0, 0), 0x1110, 18, 1, 120, _game.getQuote(0x73));
+ } else if (_game._trigger == 1) {
+ _game._player._stepEnabled = true;
+ handleWomanSpeech (0x79);
+ _dialog1.write(0x5A, true);
+ _dialog1.write(0x75, true);
+ _dialog1.start();
+ }
+ } else if (_action.isAction(VERB_GIVE, NOUN_NATIVE_WOMAN) && _game._objects.isInInventory(_game._objects.getIdFromDesc(_action._activeAction._objectNameId))) {
+ if (_game._trigger == 0) {
+ _game._player._stepEnabled = false;
+ int rndVal = _vm->getRandomNumber(0xAC, 0xAE);
+ _scene->_kernelMessages.add(Common::Point(186, 27), 0xFBFA, 32, 1, 120, _game.getQuote(rndVal));
+ } else if (_game._trigger == 1)
+ _game._player._stepEnabled = true;
+ } else if (_action.isAction(VERB_WALKTO, NOUN_OPPOSITE_BANK)) {
+ if (_game._trigger == 0) {
+ _game._player._visible = false;
+ _game._player._stepEnabled = false;
+ _vm->_palette->lock();
+ _scene->_kernelMessages.reset();
+ _game._player.removePlayerSprites();
+ _globals._spriteIndexes[9] = _scene->_sprites.addSprites(formAnimName('a', 0));
+ _vm->_palette->refreshSceneColors();
+ _globals._sequenceIndexes[9] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[9], false, 6, 1, 0, 0);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[9], SEQUENCE_TRIGGER_EXPIRE, 0, 1);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[9], -1);
+ _vm->_sound->command(27);
+ } else if (_game._trigger == 1) {
+ if (_scene->_activeAnimation != nullptr)
+ _scene->_activeAnimation->resetSpriteSetsCount();
+
+ _vm->_dialogs->show(20516);
+ _scene->_reloadSceneFlag = true;
+ }
+ } else {
+ if (_action.isAction(VERB_WALK_DOWN, NOUN_PATH_TO_SOUTH))
+ _scene->_nextSceneId = 210;
+
+ if (_action.isAction(VERB_WALKTO, NOUN_FIRE_PIT) || _action.isAction(VERB_WALKTO, NOUN_CHICKEN_ON_SPIT)) {
+ if (_game._objects.isInRoom(OBJ_CHICKEN)) {
+ _scene->_kernelMessages.reset();
+ _scene->_kernelMessages.add(Common::Point(0, 0), 0x1110, 34, 0, 120, _game.getQuote(0x6B));
+ }
+ } else if (_action.isAction(VERB_TAKE, NOUN_CHICKEN_ON_SPIT) && _globals[kChickenPermitted] && _game._objects.isInRoom(OBJ_CHICKEN)) {
+ _game._objects.addToInventory(OBJ_CHICKEN);
+ _scene->_sequences.remove(_globals._sequenceIndexes[4]);
+ _scene->_hotspots.activate(NOUN_CHICKEN_ON_SPIT, false);
+ _vm->_dialogs->showItem(OBJ_CHICKEN, 812);
+ } else if (_action.isAction(VERB_TAKE, NOUN_CHICKEN_ON_SPIT) && (!_globals[kChickenPermitted]))
+ _scene->_kernelMessages.add(Common::Point(186, 27), 0xFBFA, 32, 0, 120, _game.getQuote(0x80));
+ else if (_action.isAction(VERB_LOOK, NOUN_NATIVE_WOMAN))
+ _vm->_dialogs->show(20503);
+ else if (_action.isAction(VERB_LOOK, NOUN_HUT))
+ _vm->_dialogs->show(20504);
+ else if (_action.isAction(VERB_LOOK, NOUN_CHICKEN) && (_action._mainObjectSource == 4))
+ _vm->_dialogs->show(20505);
+ else if (_action.isAction(VERB_TAKE, NOUN_CHICKEN) && (_action._mainObjectSource == 4))
+ _vm->_dialogs->show(20506);
+ else if (_action.isAction(VERB_LOOK, NOUN_CHICKEN_ON_SPIT))
+ _vm->_dialogs->show(20507);
+ else if (_action.isAction(VERB_LOOK, NOUN_FIRE_PIT))
+ _vm->_dialogs->show(20508);
+ else if (_action.isAction(VERB_TAKE, NOUN_FIRE_PIT))
+ _vm->_dialogs->show(20509);
+ else if (_action.isAction(VERB_LOOK, NOUN_STREAM))
+ _vm->_dialogs->show(20510);
+ else if (_action.isAction(VERB_LOOK, NOUN_OPPOSITE_BANK))
+ _vm->_dialogs->show(20511);
+ else if (_game._objects.isInInventory(_game._objects.getIdFromDesc(_action._activeAction._objectNameId))
+ && ( _action.isAction(VERB_GIVE, NOUN_STREAM) || _action.isAction(VERB_THROW, NOUN_STREAM)
+ || _action.isAction(VERB_GIVE, NOUN_PIRANHA) || _action.isAction(VERB_THROW, NOUN_PIRANHA)))
+ _vm->_dialogs->show(20512);
+ else if (_action.isAction(VERB_LOOK, NOUN_PIRANHA))
+ _vm->_dialogs->show(20513);
+ else if (_action.isAction(VERB_LOOK, NOUN_TWINKIFRUIT_BUSH))
+ _vm->_dialogs->show(20514);
+ else if (_action.isAction(VERB_TAKE, NOUN_TWINKIFRUIT_BUSH))
+ _vm->_dialogs->show(20515);
+ else if (_action.isAction(VERB_TAKE, NOUN_NATIVE_WOMAN))
+ _vm->_dialogs->show(20517);
+ else
+ return;
+ }
+
+ _action._inProgress = false;
+}
+
+/*****************************************************************************/
+
+Scene207::Scene207(MADSEngine *vm) : Scene2xx(vm) {
+ _vultureFl = false;
+ _spiderFl = false;
+ _eyeFl = false;
+ _spiderHotspotId = -1;
+ _vultureHotspotId = -1;
+ _spiderTime = 0;
+ _vultureTime = 0;
+}
+
+void Scene207::synchronize(Common::Serializer &s) {
+ Scene2xx::synchronize(s);
+
+ s.syncAsByte(_vultureFl);
+ s.syncAsByte(_spiderFl);
+ s.syncAsByte(_eyeFl);
+
+ s.syncAsSint32LE(_spiderHotspotId);
+ s.syncAsSint32LE(_vultureHotspotId);
+ s.syncAsSint32LE(_spiderTime);
+ s.syncAsSint32LE(_vultureTime);
+}
+
+void Scene207::setup() {
+ setPlayerSpritesPrefix();
+ setAAName();
+ _scene->addActiveVocab(NOUN_VULTURE);
+ _scene->addActiveVocab(VERB_WALKTO);
+ _scene->addActiveVocab(NOUN_SPIDER);
+ _scene->addActiveVocab(VERB_WALKTO);
+}
+
+void Scene207::enter() {
+ _globals._spriteIndexes[1] = _scene->_sprites.addSprites(formAnimName('h', 0));
+ _globals._spriteIndexes[2] = _scene->_sprites.addSprites(formAnimName('h', 1));
+ _globals._spriteIndexes[4] = _scene->_sprites.addSprites(formAnimName('c', -1));
+ _globals._spriteIndexes[5] = _scene->_sprites.addSprites(formAnimName('e', 0));
+ _globals._spriteIndexes[6] = _scene->_sprites.addSprites(formAnimName('e', 1));
+ _globals._spriteIndexes[7] = _scene->_sprites.addSprites(formAnimName('g', 1));
+ _globals._spriteIndexes[8] = _scene->_sprites.addSprites(formAnimName('g', 0));
+ _globals._sequenceIndexes[5] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[5], false, 7, 0, 0, 0);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[5], 7);
+
+ int var2;
+ if (!_game._visitedScenes._sceneRevisited) {
+ var2 = 1;
+ } else {
+ var2 = _vm->getRandomNumber(4) + 1;
+ }
+
+ if (var2 > 2)
+ _vultureFl = false;
+ else
+ _vultureFl = true;
+
+ _spiderFl = (var2 & 1);
+
+ if (_vultureFl) {
+ _globals._sequenceIndexes[1] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[1], false, 30, 0, 0, 400);
+ _vultureTime = _game._player._priorTimer;
+ _vultureHotspotId = _scene->_dynamicHotspots.add(389, 13, _globals._sequenceIndexes[1], Common::Rect(0, 0, 0, 0));
+ _scene->_dynamicHotspots.setPosition(_vultureHotspotId, Common::Point(254, 94), FACING_WEST);
+ }
+
+ if (_spiderFl) {
+ _globals._sequenceIndexes[4] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[4], false, 7, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[4], -1, -1);
+ _spiderTime = _game._player._priorTimer;
+ _spiderHotspotId = _scene->_dynamicHotspots.add(333, 13, _globals._sequenceIndexes[4], Common::Rect(0, 0, 0, 0));
+ _scene->_dynamicHotspots.setPosition(_spiderHotspotId, Common::Point(59, 132), FACING_SOUTH);
+ }
+
+ _eyeFl = false;
+ if (_scene->_priorSceneId == 211) {
+ _game._player._playerPos = Common::Point(13, 105);
+ _game._player._facing = FACING_EAST;
+ } else if (_scene->_priorSceneId == 214) {
+ _game._player._playerPos = Common::Point(164, 117);
+ _game._player._facing = FACING_SOUTH;
+ } else if (_scene->_priorSceneId != -2) {
+ _game._player._playerPos = Common::Point(305, 131);
+ }
+
+ _globals._sequenceIndexes[6] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[6], false, 10, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[6], 1, 22);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[6], 6);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[6], SEQUENCE_TRIGGER_EXPIRE, 0, 70);
+}
+
+void Scene207::moveVulture() {
+ _scene->_sequences.remove(_globals._sequenceIndexes[1]);
+ _globals._sequenceIndexes[2] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[2], false, 7, 1, 0, 0);
+ _vm->_sound->command(43);
+ _vultureFl = false;
+ _vultureTime = _game._player._priorTimer;
+ _scene->_dynamicHotspots.remove(_vultureHotspotId);
+}
+
+void Scene207::moveSpider() {
+ _scene->_sequences.remove(_globals._sequenceIndexes[4]);
+ _globals._sequenceIndexes[4] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[4], false, 5, 1, 0, 0);
+ _spiderFl = false;
+ _spiderTime = _game._player._priorTimer;
+ _scene->_dynamicHotspots.remove(_spiderHotspotId);
+}
+
+void Scene207::step() {
+ if (!_vultureFl)
+ moveVulture();
+
+ if (_spiderFl)
+ moveSpider();
+
+ if (_game._trigger == 70) {
+ _globals._sequenceIndexes[6] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[6], false, 10, 0, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[6], 23, 34);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[6], 6);
+ }
+
+ if (_game._trigger == 71)
+ _eyeFl = false;
+
+ if (_eyeFl)
+ return;
+
+ if ((_game._player._playerPos.x >= 124) && (_game._player._playerPos.x <= 201)) {
+ _globals._sequenceIndexes[7] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[7], false, 10, 1, 0, 0);
+ _globals._sequenceIndexes[8] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[8], false, 8, 1, 0, 0);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[7], 6);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[8], 6);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[7], SEQUENCE_TRIGGER_EXPIRE, 0, 71);
+ _eyeFl = true;
+ }
+}
+
+void Scene207::preActions() {
+ if (_action.isAction(VERB_WALK_DOWN, NOUN_PATH_TO_WEST))
+ _game._player._walkOffScreenSceneId = 211;
+
+ if (_action.isAction(VERB_WALK_TOWARDS, NOUN_OPEN_FIELD_TO_EAST))
+ _game._player._walkOffScreenSceneId = 208;
+
+ if ((_action.isAction(VERB_WALKTO)) || (_action.isAction(VERB_LOOK))) {
+ if (_action.isAction(0x185)) {
+ _vultureTime = -9999;
+ } else if (_action.isAction(0x14D)) {
+ _spiderTime = -9999;
+ }
+ }
+}
+
+void Scene207::actions() {
+ if (_action._savedFields._lookFlag)
+ _vm->_dialogs->show(20711);
+ else if (_action.isAction(VERB_WALK_THROUGH, NOUN_DOORWAY))
+ _scene->_nextSceneId = 214;
+ else {
+ if ((_game._player._playerPos.x > 150) && (_game._player._playerPos.x < 189) &&
+ (_game._player._playerPos.y > 111) && (_game._player._playerPos.y < 130)) {
+ if ((_game._player._playerPos.x <= 162) || (_game._player._playerPos.x >= 181) ||
+ (_game._player._playerPos.y <= 115) || (_game._player._playerPos.y >= 126)) {
+ _globals._sequenceIndexes[7] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[7], false, 10, 2, 0, 0);
+ _globals._sequenceIndexes[8] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[8], false, 8, 2, 0, 0);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[7], 6);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[8], 6);
+ }
+ } else if (_eyeFl) {
+ _scene->_sequences.remove(_globals._sequenceIndexes[7]);
+ _scene->_sequences.remove(_globals._sequenceIndexes[8]);
+ _eyeFl = false;
+ }
+
+ if (_action.isAction(VERB_LOOK, NOUN_DENSE_FOREST))
+ _vm->_dialogs->show(20701);
+ else if (_action.isAction(VERB_LOOK, NOUN_HEDGE))
+ _vm->_dialogs->show(20702);
+ else if (_action.isAction(VERB_LOOK, NOUN_SKULL_AND_CROSSBONES))
+ _vm->_dialogs->show(20703);
+ else if (_action.isAction(VERB_LOOK, NOUN_CAULDRON))
+ _vm->_dialogs->show(20704);
+ else if (_action.isAction(VERB_LOOK, NOUN_WITCHDOCTOR_HUT))
+ _vm->_dialogs->show(20705);
+ else if (_action.isAction(VERB_LOOK, NOUN_PATH_TO_WEST))
+ _vm->_dialogs->show(20706);
+ else if (_action.isAction(VERB_LOOK, NOUN_MOUNTAINS))
+ _vm->_dialogs->show(20707);
+ else if (_action.isAction(VERB_LOOK, NOUN_ALOE_PLANT))
+ _vm->_dialogs->show(20708);
+ else if (_action.isAction(VERB_LOOK, NOUN_LAWN))
+ _vm->_dialogs->show(20709);
+ else if (_action.isAction(VERB_LOOK, NOUN_VULTURE))
+ _vm->_dialogs->show(20710);
+ else if (_action.isAction(VERB_TAKE, NOUN_SKULL_AND_CROSSBONES))
+ _vm->_dialogs->show(20712);
+ else if (_action.isAction(VERB_TAKE, NOUN_ALOE_PLANT))
+ _vm->_dialogs->show(20713);
+ else if (_action.isAction(VERB_LOOK, NOUN_SPIDER))
+ _vm->_dialogs->show(20714);
+ else if (_action.isAction(VERB_TAKE, NOUN_SPIDER))
+ _vm->_dialogs->show(20715);
+ else
+ return;
+ }
+
+ _action._inProgress = false;
+}
+
+/*****************************************************************************/
+
+Scene208::Scene208(MADSEngine *vm) : Scene2xx(vm) {
+ _rhotundaTurnFl = false;
+ _boundingFl = false;
+ _rhotundaTime = 0;
+}
+
+void Scene208::synchronize(Common::Serializer &s) {
+ Scene2xx::synchronize(s);
+
+ s.syncAsByte(_rhotundaTurnFl);
+ s.syncAsByte(_boundingFl);
+ s.syncAsSint32LE(_rhotundaTime);
+}
+
+void Scene208::setup() {
+ setPlayerSpritesPrefix();
+ setAAName();
+ _scene->addActiveVocab(NOUN_HUGE_LEGS);
+ _scene->addActiveVocab(NOUN_LEAF_COVERED_PIT);
+ _scene->addActiveVocab(NOUN_PILE_OF_LEAVES);
+ _scene->addActiveVocab(VERB_WALKTO);
+}
+
+void Scene208::updateTrap() {
+ if (_globals[kRhotundaStatus] == 1) {
+ _globals._sequenceIndexes[1] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[1], false, 8, 0, 0, 24);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 5);
+ int idx = _scene->_dynamicHotspots.add(NOUN_HUGE_LEGS, VERB_WALKTO, _globals._sequenceIndexes[1], Common::Rect(0, 0, 0, 0));
+ _scene->_dynamicHotspots.setPosition(idx, Common::Point(100, 146), FACING_NORTH);
+ _scene->_hotspots.activate(414, false);
+ return;
+ }
+
+ switch (_globals[kLeavesStatus]) {
+ case 0: {
+ _globals._sequenceIndexes[2] = _scene->_sequences.startCycle(_globals._spriteIndexes[2], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 15);
+ int idx = _scene->_dynamicHotspots.add(NOUN_PILE_OF_LEAVES, VERB_WALKTO, _globals._sequenceIndexes[2], Common::Rect(0, 0, 0, 0));
+ _scene->_dynamicHotspots.setPosition(idx, Common::Point(60, 152), FACING_NORTH);
+ }
+ break;
+ case 2: {
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 15);
+ _globals._sequenceIndexes[3] = _scene->_sequences.startCycle(_globals._spriteIndexes[3], false, 1);
+ _scene->_hotspots.activate(NOUN_DEEP_PIT, false);
+ int idx = _scene->_dynamicHotspots.add(NOUN_LEAF_COVERED_PIT, VERB_WALKTO, _globals._sequenceIndexes[2], Common::Rect(0, 0, 0, 0));
+ _scene->_dynamicHotspots.setPosition(idx, Common::Point(100, 146), FACING_NORTH);
+ _scene->_dynamicHotspots[idx]._articleNumber = PREP_ON;
+ }
+ break;
+ }
+}
+
+void Scene208::enter() {
+ _globals._spriteIndexes[1] = _scene->_sprites.addSprites(formAnimName('a', 1));
+ _globals._spriteIndexes[2] = _scene->_sprites.addSprites(formAnimName('x', 0));
+ _globals._spriteIndexes[3] = _scene->_sprites.addSprites(formAnimName('x', 1));
+ _globals._spriteIndexes[4] = _scene->_sprites.addSprites(formAnimName('x', 2));
+ _globals._spriteIndexes[5] = _scene->_sprites.addSprites("*RXMBD_8");
+
+ updateTrap();
+
+ _rhotundaTurnFl = false;
+ _boundingFl = false;
+ _scene->_kernelMessages._talkFont = _vm->_font->getFont(FONT_INTERFACE);
+ _scene->_textSpacing = 0;
+
+ if (_scene->_priorSceneId == 207) {
+ _game._player._playerPos = Common::Point(8, 122);
+ _game._player._facing = FACING_EAST;
+ } else if (_scene->_priorSceneId == 203) {
+ _game._player._playerPos = Common::Point(142, 108);
+ _game._player._facing = FACING_SOUTH;
+ } else if (_scene->_priorSceneId == 209) {
+ _game._player._playerPos = Common::Point(307, 123);
+ _game._player._facing = FACING_WEST;
+ } else if (_scene->_priorSceneId != -2) {
+ _game._player._playerPos = Common::Point(162, 149);
+ _game._player._facing = FACING_NORTH;
+ }
+
+ _game.loadQuoteSet(0x81, 0x46, 0);
+
+ if ((_scene->_priorSceneId == 207) && (_globals[kMonkeyStatus] == MONKEY_HAS_BINOCULARS)) {
+ int msgIndex = _scene->_kernelMessages.add(Common::Point(0, 0), 0x1110, 34, 0, 120, _game.getQuote(129));
+ _scene->_kernelMessages.setQuoted(msgIndex, 4, true);
+ }
+
+ _vm->_palette->setEntry(16, 0, 0, 63);
+ _vm->_palette->setEntry(17, 0, 0, 45);
+ sceneEntrySound();
+}
+
+void Scene208::step() {
+ if (_boundingFl && (_rhotundaTime <= _scene->_activeAnimation->getCurrentFrame())) {
+ _rhotundaTime = _scene->_activeAnimation->getCurrentFrame();
+
+ if (_rhotundaTime == 125)
+ _scene->_sequences.remove(_globals._sequenceIndexes[4]);
+ }
+
+ if (!_rhotundaTurnFl)
+ return;
+
+ if ((_game._player._playerPos != Common::Point(20, 148)) || (_game._player._facing != FACING_EAST))
+ return;
+
+ if ((_game._trigger == 0) && _boundingFl)
+ return;
+
+ _boundingFl = true;
+
+ switch (_game._trigger) {
+ case 0:
+ _scene->loadAnimation(formAnimName('A', -1), 81);
+ _rhotundaTime = 0;
+ break;
+ case 81:
+ _scene->_sequences.remove(_globals._spriteIndexes[15]);
+ _globals[kRhotundaStatus] = 1;
+ updateTrap();
+ _scene->_sequences.addTimer(90, 82);
+ break;
+ case 82:
+ _game._player._stepEnabled = true;
+ break;
+ }
+}
+
+void Scene208::preActions() {
+ Player &player = _vm->_game->_player;
+
+ if (_action.isAction(VERB_LOOK) && player._readyToWalk)
+ player._needToWalk = true;
+
+ if (_action.isAction(VERB_WALK_TOWARDS, NOUN_GRASSLAND_TO_EAST))
+ player._walkOffScreenSceneId = 209;
+
+ if (_action.isAction(VERB_WALK_TOWARDS, NOUN_OPEN_AREA_TO_WEST))
+ player._walkOffScreenSceneId = 207;
+}
+
+void Scene208::subAction(int mode) {
+
+ switch (_game._trigger) {
+ case 0: {
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._sequenceIndexes[5] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[5], false, 6, 1, 0, 0);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[5]);
+
+ int abortVal;
+ if ((mode == 1) || (mode == 2))
+ abortVal = 1;
+ else
+ abortVal = 2;
+
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[5], SEQUENCE_TRIGGER_EXPIRE, 0, abortVal);
+ }
+ break;
+ case 1: {
+ int oldVal = _globals._sequenceIndexes[5];
+ _globals._sequenceIndexes[5] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[6], false, 12, 3, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[5], 3, 4);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[5]);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[5], oldVal);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[5], SEQUENCE_TRIGGER_EXPIRE, 0, 2);
+ _vm->_sound->command(20);
+ }
+ break;
+
+ case 2: {
+ switch (mode) {
+ case 1:
+ _game._objects.addToInventory(OBJ_BIG_LEAVES);
+ _scene->_sequences.remove(_globals._sequenceIndexes[2]);
+ _globals[kLeavesStatus] = 1;
+ break;
+
+ case 2:
+ _game._objects.setRoom(OBJ_BIG_LEAVES, 1);
+ _globals[kLeavesStatus] = 2;
+ updateTrap();
+ break;
+
+ case 3:
+ _scene->_sequences.remove(_globals._sequenceIndexes[3]);
+ _globals._sequenceIndexes[4] = _scene->_sequences.startCycle(_globals._spriteIndexes[4], false, 1);
+ _game._objects.removeFromInventory(OBJ_TWINKIFRUIT, 1);
+ _vm->_sound->command(34);
+ break;
+
+ case 4:
+ _game._objects.removeFromInventory(OBJ_BURGER, 1);
+ _vm->_sound->command(33);
+ break;
+
+ case 5:
+ _game._objects.removeFromInventory(OBJ_DEAD_FISH, 1);
+ _vm->_sound->command(33);
+ break;
+
+ default:
+ break;
+ }
+
+ int oldVal = _globals._sequenceIndexes[5];
+ _globals._sequenceIndexes[5] = _scene->_sequences.addReverseSpriteCycle(_globals._spriteIndexes[5], false, 6, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[5], 1, 3);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[5]);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[5], oldVal);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[5], SEQUENCE_TRIGGER_EXPIRE, 0, 3);
+ }
+ break;
+
+ case 3:
+ _game._player._visible = true;
+ _game._player._stepEnabled = true;
+ break;
+
+ default:
+ break;
+ }
+}
+
+void Scene208::actions() {
+ if (_action.isAction(VERB_WALK_TOWARDS, NOUN_LOWLANDS_TO_NORTH)) {
+ if (_globals[kRhotundaStatus])
+ _scene->_nextSceneId = 203;
+ else if (_game._trigger == 0) {
+ _game._player._stepEnabled = false;
+ int msgIndex = _scene->_kernelMessages.add(Common::Point(0, 0), 0x1110, 34, 1, 120, _game.getQuote(70));
+ _scene->_kernelMessages.setQuoted(msgIndex, 4, true);
+ } else if (_game._trigger == 1)
+ _scene->_nextSceneId = 203;
+ } else if (_action.isAction(VERB_WALK_TOWARDS, NOUN_FIELD_TO_SOUTH))
+ _scene->_nextSceneId = 212;
+ else if (_action.isAction(VERB_TAKE, NOUN_PILE_OF_LEAVES) && (!_globals[kLeavesStatus] || _game._trigger)) {
+ subAction(1);
+ if (_game._player._stepEnabled)
+ _vm->_dialogs->showItem(OBJ_BIG_LEAVES, 0x326, 0);
+ } else if (_action.isAction(VERB_PUT, NOUN_BIG_LEAVES, NOUN_DEEP_PIT) && (_globals[kLeavesStatus] == 1 || _game._trigger))
+ subAction(2);
+ else if (_action.isAction(VERB_PUT, NOUN_TWINKIFRUIT, NOUN_LEAF_COVERED_PIT)) {
+ subAction(3);
+ if (_game._player._stepEnabled) {
+ _game._player._stepEnabled = false;
+ _rhotundaTurnFl = true;
+ _game._player.walk(Common::Point(20, 148), FACING_EAST);
+ }
+ } else if (_action.isAction(VERB_PUT, NOUN_BURGER, NOUN_LEAF_COVERED_PIT)) {
+ subAction(4);
+ if (_game._player._stepEnabled)
+ _vm->_dialogs->show(20812);
+ } else if (_action.isAction(VERB_PUT, NOUN_DEAD_FISH, NOUN_LEAF_COVERED_PIT)) {
+ subAction(5);
+ if (_game._player._stepEnabled)
+ _vm->_dialogs->show(20812);
+ } else if (_action.isAction(VERB_LOOK, NOUN_CUMULOUS_CLOUD))
+ _vm->_dialogs->show(20801);
+ else if (_action.isAction(VERB_LOOK, NOUN_OPEN_AREA_TO_WEST))
+ _vm->_dialogs->show(20802);
+ else if (_action.isAction(VERB_LOOK, NOUN_THORNY_BUSH))
+ _vm->_dialogs->show(20803);
+ else if (_action.isAction(VERB_LOOK, NOUN_ROCKS))
+ _vm->_dialogs->show(20804);
+ else if (_action.isAction(VERB_LOOK, NOUN_SMALL_CACTUS))
+ _vm->_dialogs->show(20805);
+ else if (_action.isAction(VERB_TAKE, NOUN_SMALL_CACTUS))
+ _vm->_dialogs->show(20806);
+ else if (_action.isAction(VERB_LOOK, NOUN_GRASSLAND_TO_EAST))
+ _vm->_dialogs->show(20807);
+ else if (_action.isAction(VERB_LOOK, NOUN_DEEP_PIT))
+ _vm->_dialogs->show(20808);
+ else if (_action.isAction(VERB_LOOK, NOUN_PILE_OF_LEAVES))
+ _vm->_dialogs->show(20809);
+ else if (_action.isAction(VERB_LOOK, NOUN_LEAF_COVERED_PIT)) {
+ if (_game._difficulty == DIFFICULTY_EASY)
+ _vm->_dialogs->show(20810);
+ else
+ _vm->_dialogs->show(20811);
+ } else if (_action.isAction(VERB_LOOK, NOUN_TREE) || _action.isAction(VERB_LOOK, NOUN_TREES))
+ _vm->_dialogs->show(20813);
+ else if (_action.isAction(VERB_TAKE, NOUN_LEAF_COVERED_PIT))
+ _vm->_dialogs->show(20814);
+ else if (_action.isAction(VERB_LOOK, NOUN_HUGE_LEGS))
+ _vm->_dialogs->show(20815);
+ else if (_action.isAction(VERB_TAKE, NOUN_HUGE_LEGS) || _action.isAction(VERB_PULL, NOUN_HUGE_LEGS))
+ _vm->_dialogs->show(20816);
+ else if (_action._savedFields._lookFlag && (_globals[kRhotundaStatus] == 1))
+ _vm->_dialogs->show(20819);
+ else if (_action._savedFields._lookFlag && (_globals[kLeavesStatus] == 2))
+ _vm->_dialogs->show(20818);
+ else if (_action._savedFields._lookFlag)
+ _vm->_dialogs->show(20817);
+ else
+ return;
+
+ _action._inProgress = false;
+}
+
+/*****************************************************************************/
+
+Scene209::Scene209(MADSEngine *vm) : Scene2xx(vm) {
+ _dodgeFl = false;
+ _forceDodgeFl = false;
+ _pitchFl = false;
+ _fallFl = false;
+ _forceFallFl = false;
+ _playingAnimFl = false;
+ _shouldFallFl = false;
+ _shouldDodgeFl = false;
+ _monkeyPosition = 0;
+ _counter = 0;
+ _pauseMode = 0;
+ _binocularsDroppedFl = false;
+ _startShootingInTimerFl = false;
+ _dialogAbortVal = 0;
+ _playingDialogFl = false;
+ _shootMissedLastFl = false;
+ _removeMonkeyFl = false;
+ _shootReadyFl = false;
+ _pauseCounterThreshold = 0;
+ _pauseCounter = 0;
+}
+
+void Scene209::synchronize(Common::Serializer &s) {
+ Scene2xx::synchronize(s);
+
+ s.syncAsByte(_dodgeFl);
+ s.syncAsByte(_forceDodgeFl);
+ s.syncAsByte(_shouldDodgeFl);
+ s.syncAsByte(_pitchFl);
+ s.syncAsByte(_fallFl);
+ s.syncAsByte(_forceFallFl);
+ s.syncAsByte(_shouldFallFl);
+ s.syncAsByte(_playingAnimFl);
+ s.syncAsByte(_playingDialogFl);
+
+ s.syncAsSint32LE(_pauseMode);
+ s.syncAsSint32LE(_pauseCounterThreshold);
+ s.syncAsSint32LE(_pauseCounter);
+
+ s.syncAsByte(_removeMonkeyFl);
+
+ s.syncAsSint32LE(_monkeyPosition);
+
+ s.syncAsByte(_shootReadyFl);
+ s.syncAsByte(_startShootingInTimerFl);
+ s.syncAsByte(_shootMissedLastFl);
+ s.syncAsByte(_binocularsDroppedFl);
+
+ s.syncAsSint32LE(_dialogAbortVal);
+ s.syncAsSint32LE(_counter);
+}
+
+void Scene209::setup() {
+ setPlayerSpritesPrefix();
+ setAAName();
+ _scene->addActiveVocab(NOUN_PLANT_STALK);
+}
+
+void Scene209::handlePause() {
+ switch (_game._trigger) {
+ case 124:
+ if (++_pauseCounter <= _pauseCounterThreshold)
+ _scene->_sequences.addTimer(60, 124);
+ else
+ _pauseMode = 0;
+ break;
+ }
+}
+
+void Scene209::initPauseCounterThreshold() {
+ switch (_game._trigger) {
+ case 226:
+ _scene->_sequences.addTimer(1, 124);
+ _pauseCounterThreshold = _vm->getRandomNumber(7,12);
+ _pauseMode = 2;
+ _pauseCounter = 0;
+ break;
+ }
+}
+
+void Scene209::handlePeek() {
+ switch (_game._trigger) {
+ case 133:
+ _vm->_sound->command(18);
+ _globals._sequenceIndexes[3] = _scene->_sequences.addReverseSpriteCycle(_globals._spriteIndexes[3], false, 8, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[3], 51, 52);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[3], SEQUENCE_TRIGGER_EXPIRE, 0, 134);
+ break;
+
+ case 134: {
+ int oldIdx = _globals._sequenceIndexes[3];
+ _globals._sequenceIndexes[3] = _scene->_sequences.startCycle(_globals._spriteIndexes[3], false, 6);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[3], oldIdx);
+ _scene->_sequences.addTimer(60, 135);
+ }
+ break;
+
+ case 135:
+ _scene->_sequences.remove(_globals._sequenceIndexes[3]);
+ _globals._sequenceIndexes[3] = _scene->_sequences.startCycle(_globals._spriteIndexes[3], false, 7);
+ _scene->_sequences.addTimer(10, 136);
+ break;
+
+ case 136:
+ _scene->_sequences.remove(_globals._sequenceIndexes[3]);
+ _globals._sequenceIndexes[3] = _scene->_sequences.startCycle(_globals._spriteIndexes[3], false, 6);
+ _scene->_sequences.addTimer(50, 137);
+ break;
+
+ case 137:
+ _scene->_sequences.remove(_globals._sequenceIndexes[3]);
+ _globals._sequenceIndexes[3] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[3], false, 8, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[3], 51, 52);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[3], SEQUENCE_TRIGGER_EXPIRE, 0, 138);
+ break;
+
+ case 138:
+ _pauseMode = 1;
+ _scene->_hotspots.activate(227, false);
+ _playingAnimFl = false;
+ break;
+ }
+}
+
+void Scene209::handleVerticalMove() {
+ switch (_game._trigger) {
+ case 140:
+ _globals._sequenceIndexes[3] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[3], false, 8, 8, 0, 1);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[3], 1, 5);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[3], SEQUENCE_TRIGGER_EXPIRE, 0, 141);
+ break;
+
+ case 141: {
+ _vm->_sound->command(18);
+ int oldIdx = _globals._sequenceIndexes[3];
+ _globals._sequenceIndexes[3] = _scene->_sequences.startCycle(_globals._spriteIndexes[3], false, 5);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[3], oldIdx);
+ _scene->_sequences.addTimer(60, 142);
+ }
+ break;
+
+ case 142:
+ _scene->_sequences.remove(_globals._sequenceIndexes[3]);
+ _globals._sequenceIndexes[3] = _scene->_sequences.addReverseSpriteCycle(_globals._spriteIndexes[3], false, 8, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[3], 1, 5);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[3], SEQUENCE_TRIGGER_EXPIRE, 0, 143);
+ break;
+
+ case 143:
+ _pauseMode = 1;
+ _playingAnimFl = false;
+ _scene->_hotspots.activate(227, false);
+ break;
+ }
+}
+
+void Scene209::handleLookStay() {
+ switch (_game._trigger) {
+ case 145:
+ _vm->_sound->command(18);
+ _monkeyPosition = 2;
+ _globals._sequenceIndexes[3] = _scene->_sequences.addReverseSpriteCycle(_globals._spriteIndexes[3], false, 8, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[3], 51, 52);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[3], SEQUENCE_TRIGGER_EXPIRE, 0, 146);
+ break;
+
+ case 146: {
+ int oldIdx = _globals._sequenceIndexes[3];
+ _globals._sequenceIndexes[3] = _scene->_sequences.startCycle(_globals._spriteIndexes[3], false, 6);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[3], oldIdx);
+ _scene->_sequences.addTimer(15, 147);
+ }
+ break;
+
+ case 147:
+ _scene->_sequences.remove(_globals._sequenceIndexes[3]);
+ _globals._sequenceIndexes[3] = _scene->_sequences.startCycle(_globals._spriteIndexes[3], false, 7);
+ _scene->_sequences.addTimer(8, 148);
+ break;
+
+ case 148:
+ _scene->_sequences.remove(_globals._sequenceIndexes[3]);
+ _globals._sequenceIndexes[3] = _scene->_sequences.startCycle(_globals._spriteIndexes[3], false, 6);
+
+ if (!_dodgeFl) {
+ _scene->_sequences.addTimer(90, 149);
+ } else {
+ _scene->_sequences.addTimer(1, 149);
+ _shouldDodgeFl = true;
+ }
+ break;
+
+ case 149:
+ _playingAnimFl = false;
+ break;
+ }
+}
+
+void Scene209::handleLookRight() {
+ switch (_game._trigger) {
+ case 151:
+ _scene->_sequences.remove(_globals._sequenceIndexes[3]);
+ _globals._sequenceIndexes[3] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[3], false, 8, 2, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[3], 8, 14);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[3], SEQUENCE_TRIGGER_EXPIRE, 0, 152);
+ break;
+
+ case 152: {
+ int oldIdx = _globals._sequenceIndexes[3];
+ _globals._sequenceIndexes[3] = _scene->_sequences.startCycle(_globals._spriteIndexes[3], false, 6);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[3], oldIdx);
+ _scene->_sequences.addTimer(60, 153);
+ }
+ break;
+
+ case 153:
+ _playingAnimFl = false;
+ if (_dodgeFl)
+ _shouldDodgeFl = true;
+ break;
+ }
+}
+
+void Scene209::handleBlink() {
+ switch (_game._trigger) {
+ case 155:
+ _scene->_sequences.remove(_globals._sequenceIndexes[3]);
+ _globals._sequenceIndexes[3] = _scene->_sequences.startCycle(_globals._spriteIndexes[3], false, 6);
+ _scene->_sequences.addTimer(50, 156);
+ break;
+
+ case 156:
+ _scene->_sequences.remove(_globals._sequenceIndexes[3]);
+ _globals._sequenceIndexes[3] = _scene->_sequences.startCycle(_globals._spriteIndexes[3], false, 7);
+ _scene->_sequences.addTimer(10, 157);
+ break;
+
+ case 157:
+ _scene->_sequences.remove(_globals._sequenceIndexes[3]);
+ _globals._sequenceIndexes[3] = _scene->_sequences.startCycle(_globals._spriteIndexes[3], false, 6);
+ _scene->_sequences.addTimer(50, 158);
+ break;
+
+ case 158:
+ _playingAnimFl = false;
+ if (_dodgeFl)
+ _shouldDodgeFl = true;
+ break;
+ }
+}
+
+void Scene209::handleGetBinoculars() {
+ switch (_game._trigger) {
+ case 161:
+ _vm->_sound->command(18);
+ _monkeyPosition = 3;
+ _scene->_sequences.remove(_globals._sequenceIndexes[3]);
+ _globals._sequenceIndexes[3] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[3], false, 8, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[3], 8, 24);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[3], SEQUENCE_TRIGGER_SPRITE, 20, 165);
+ if (!_fallFl && !_dodgeFl) {
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[3], SEQUENCE_TRIGGER_EXPIRE, 0, 162);
+ } else {
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[3], SEQUENCE_TRIGGER_EXPIRE, 0, 163);
+ }
+ break;
+
+ case 162: {
+ int oldIdx = _globals._sequenceIndexes[3];
+ _globals._sequenceIndexes[3] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[3], false, 8, 6, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[3], 23, 25);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[3], oldIdx);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[3], SEQUENCE_TRIGGER_EXPIRE, 0, 163);
+ }
+ break;
+
+ case 163: {
+ int oldIdx = _globals._sequenceIndexes[3];
+ _globals._sequenceIndexes[3] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[3], false, 8, 0, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[3], 23, 24);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[3], oldIdx);
+ _scene->_sequences.addTimer(8, 164);
+ }
+ break;
+
+ case 164:
+ _playingAnimFl = false;
+ if (_fallFl)
+ _shouldFallFl = true;
+ break;
+
+ case 165:
+ _vm->_sound->command(18);
+ break;
+ }
+}
+
+void Scene209::handleBinocularBlink() {
+ switch (_game._trigger) {
+ case 167: {
+ int oldIdx = _globals._sequenceIndexes[3];
+ _scene->_sequences.remove(_globals._sequenceIndexes[3]);
+ _globals._sequenceIndexes[3] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[3], false, 8, 2, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[3], 23, 25);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[3], oldIdx);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[3], SEQUENCE_TRIGGER_EXPIRE, 0, 168);
+ }
+ break;
+
+ case 168: {
+ int oldIdx = _globals._sequenceIndexes[3];
+ _globals._sequenceIndexes[3] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[3], false, 8, 0, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[3], 23, 24);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[3], oldIdx);
+ _scene->_sequences.addTimer(30, 169);
+ }
+ break;
+
+ case 169:
+ _playingAnimFl = false;
+ if (_fallFl)
+ _shouldFallFl = true;
+ break;
+ }
+}
+
+void Scene209::handleBinocularScan() {
+ switch (_game._trigger) {
+ case 171: {
+ int oldIdx = _globals._sequenceIndexes[3];
+ _scene->_sequences.remove(_globals._sequenceIndexes[3]);
+ _globals._sequenceIndexes[3] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[3], false, 12, 2, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[3], 43, 45);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[3], oldIdx);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[3], SEQUENCE_TRIGGER_EXPIRE, 0, 172);
+ }
+ break;
+
+ case 172: {
+ int oldIdx = _globals._sequenceIndexes[3];
+ int randAction = _vm->getRandomNumber(1,2);
+ switch (randAction) {
+ case 1:
+ _globals._sequenceIndexes[3] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[3], false, 12, 2, 0, 0);
+ break;
+ case 2:
+ _globals._sequenceIndexes[3] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[3], false, 12, 4, 0, 0);
+ break;
+ }
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[3], 23, 25);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[3], oldIdx);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[3], SEQUENCE_TRIGGER_EXPIRE, 0, 173);
+ }
+ break;
+
+ case 173: {
+ int oldIdx = _globals._sequenceIndexes[3];
+ _globals._sequenceIndexes[3] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[3], false, 12, 2, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[3], 26, 30);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[3], oldIdx);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[3], SEQUENCE_TRIGGER_EXPIRE, 0, 174);
+ }
+ break;
+
+ case 174: {
+ int oldIdx = _globals._sequenceIndexes[3];
+ _globals._sequenceIndexes[3] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[3], false, 12, 0, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[3], 23, 24);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[3], oldIdx);
+ _scene->_sequences.addTimer(60, 175);
+ }
+ break;
+
+ case 175:
+ _playingAnimFl = false;
+ if (_fallFl)
+ _shouldFallFl = true;
+ break;
+ }
+}
+
+void Scene209::handleJumpInTree() {
+ switch (_game._trigger) {
+ case 178: {
+ int oldIdx = 0;
+ _monkeyPosition = 1;
+ if (_removeMonkeyFl)
+ _scene->_sequences.remove(_globals._sequenceIndexes[3]);
+ else
+ oldIdx = _globals._sequenceIndexes[3];
+
+ _globals._sequenceIndexes[3] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[3], false, 8, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[3], 46, 49);
+ if (!_removeMonkeyFl)
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[3], oldIdx);
+
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[3], SEQUENCE_TRIGGER_EXPIRE, 0, 179);
+ }
+ break;
+
+ case 179: {
+ _vm->_sound->command(18);
+ int oldIdx = _globals._sequenceIndexes[3];
+ _globals._sequenceIndexes[3] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[3], false, 8, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[3], 53, 61);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[3], oldIdx);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[3], SEQUENCE_TRIGGER_EXPIRE, 0, 180);
+ }
+ break;
+
+ case 180:
+ _removeMonkeyFl = true;
+ _pauseMode = 1;
+ _playingAnimFl = false;
+ _scene->_hotspots.activate(227, false);
+ break;
+ }
+}
+
+void Scene209::handleTongue() {
+ switch (_game._trigger) {
+ case 182: {
+ int oldIdx = _globals._sequenceIndexes[3];
+ _scene->_sequences.remove(_globals._sequenceIndexes[3]);
+ _globals._sequenceIndexes[3] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[3], false, 12, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[3], 26, 30);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[3], oldIdx);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[3], SEQUENCE_TRIGGER_EXPIRE, 0, 183);
+ }
+ break;
+
+ case 183: {
+ int oldIdx = _globals._sequenceIndexes[3];
+ _globals._sequenceIndexes[3] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[3], false, 12, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[3], 31, 33);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[3], oldIdx);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[3], SEQUENCE_TRIGGER_EXPIRE, 0, 184);
+ }
+ break;
+
+ case 184: {
+ int oldIdx = _globals._sequenceIndexes[3];
+ _globals._sequenceIndexes[3] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[3], false, 12, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[3], 36, 37);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[3], oldIdx);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[3], SEQUENCE_TRIGGER_EXPIRE, 0, 185);
+ }
+ break;
+
+ case 185: {
+ _vm->_sound->command(18);
+ int oldIdx = _globals._sequenceIndexes[3];
+ _globals._sequenceIndexes[3] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[3], false, 6, 20, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[3], 38, 39);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[3], oldIdx);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[3], SEQUENCE_TRIGGER_EXPIRE, 0, 186);
+ }
+ break;
+
+ case 186: {
+ int oldIdx = _globals._sequenceIndexes[3];
+ _globals._sequenceIndexes[3] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[3], false, 12, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[3], 40, 41);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[3], oldIdx);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[3], SEQUENCE_TRIGGER_EXPIRE, 0, 178);
+ _removeMonkeyFl = false;
+ }
+ break;
+ }
+}
+
+void Scene209::handleStandFromPeek() {
+ switch (_game._trigger) {
+ case 189:
+ _monkeyPosition = 4;
+ _scene->_sequences.remove(_globals._sequenceIndexes[3]);
+ _globals._sequenceIndexes[3] = _scene->_sequences.startCycle(_globals._spriteIndexes[3], false, 50);
+ _scene->_sequences.addTimer(8, 190);
+ break;
+
+ case 190:
+ _scene->_sequences.remove(_globals._sequenceIndexes[3]);
+ _globals._sequenceIndexes[3] = _scene->_sequences.startCycle(_globals._spriteIndexes[3], false, 6);
+ _scene->_sequences.addTimer(8, 191);
+ break;
+
+ case 191:
+ _scene->_sequences.remove(_globals._sequenceIndexes[3]);
+ _globals._sequenceIndexes[6] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[6], false, 8, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[6], 1, 5);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[6], SEQUENCE_TRIGGER_EXPIRE, 0, 192);
+ break;
+
+ case 192: {
+ _vm->_sound->command(18);
+ int oldIdx = _globals._sequenceIndexes[6];
+ _globals._sequenceIndexes[5] = _scene->_sequences.startCycle(_globals._spriteIndexes[5], false, 1);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[5], oldIdx);
+ _scene->_sequences.addTimer(8, 193);
+ }
+ break;
+
+ case 193:
+ _scene->_sequences.remove(_globals._sequenceIndexes[5]);
+ _globals._sequenceIndexes[4] = _scene->_sequences.startCycle(_globals._spriteIndexes[4], false, 22);
+ _scene->_sequences.addTimer(5, 194);
+ break;
+
+ case 194:
+ _playingAnimFl = false;
+ _counter = 0;
+ break;
+ }
+}
+
+void Scene209::handleStandBlink() {
+ switch (_game._trigger) {
+ case 246:
+ _scene->_sequences.remove(_globals._sequenceIndexes[4]);
+ _globals._sequenceIndexes[4] = _scene->_sequences.startCycle(_globals._spriteIndexes[4], false, 22);
+ _scene->_sequences.addTimer(10, 247);
+ break;
+
+ case 247:
+ _scene->_sequences.remove(_globals._sequenceIndexes[4]);
+ _globals._sequenceIndexes[4] = _scene->_sequences.startCycle(_globals._spriteIndexes[4], false, 23);
+ _scene->_sequences.addTimer(8, 248);
+ break;
+
+ case 248:
+ _scene->_sequences.remove(_globals._sequenceIndexes[4]);
+ _globals._sequenceIndexes[4] = _scene->_sequences.startCycle(_globals._spriteIndexes[4], false, 22);
+ _scene->_sequences.addTimer(10, 249);
+ break;
+
+ case 249:
+ _playingAnimFl = false;
+ break;
+ }
+}
+
+void Scene209::handleJumpAndHide() {
+ switch (_game._trigger) {
+ case 196:
+ _vm->_sound->command(18);
+ _monkeyPosition = 1;
+ _scene->_sequences.remove(_globals._sequenceIndexes[4]);
+ _globals._sequenceIndexes[5] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[5], false, 8, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[5], 1, 16);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[5], SEQUENCE_TRIGGER_EXPIRE, 0, 197);
+ break;
+
+ case 197:
+ _pauseMode = 1;
+ _scene->_hotspots.activate(227, false);
+ _playingAnimFl = false;
+ break;
+ }
+}
+
+void Scene209::handleMonkeyEating() {
+ switch (_game._trigger) {
+ case 199:
+ _vm->_sound->command(18);
+ _scene->_sequences.remove(_globals._sequenceIndexes[4]);
+ _globals._sequenceIndexes[4] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[4], false, 10, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[4], 1, 14);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[4], SEQUENCE_TRIGGER_EXPIRE, 0, 200);
+ break;
+
+ case 200: {
+ int oldIdx = _globals._sequenceIndexes[4];
+ _globals._sequenceIndexes[4] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[4], false, 10, 10, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[4], 15, 16);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[4], oldIdx);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[4], SEQUENCE_TRIGGER_EXPIRE, 0, 201);
+ }
+ break;
+
+ case 201: {
+ int oldIdx = _globals._sequenceIndexes[4];
+ _globals._sequenceIndexes[4] = _scene->_sequences.startCycle(_globals._spriteIndexes[4], false, 12);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[4], oldIdx);
+ _scene->_sequences.addTimer(20, 202);
+ }
+ break;
+
+ case 202:
+ _scene->_sequences.remove(_globals._sequenceIndexes[4]);
+ _globals._sequenceIndexes[4] = _scene->_sequences.startCycle(_globals._spriteIndexes[4], false, 19);
+ _scene->_sequences.addTimer(20, 203);
+ break;
+
+ case 203:
+ _scene->_sequences.remove(_globals._sequenceIndexes[4]);
+ _globals._sequenceIndexes[4] = _scene->_sequences.startCycle(_globals._spriteIndexes[4], false, 17);
+ _scene->_sequences.addTimer(20, 204);
+ break;
+
+ case 204:
+ _scene->_sequences.remove(_globals._sequenceIndexes[4]);
+ _globals._sequenceIndexes[4] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[4], false, 10, 8, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[4], 18, 19);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[4], SEQUENCE_TRIGGER_EXPIRE, 0, 205);
+ break;
+
+ case 205: {
+ int oldIdx = _globals._sequenceIndexes[4];
+ _globals._sequenceIndexes[4] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[4], false, 10, 8, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[4], 20, 21);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[4], oldIdx);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[4], SEQUENCE_TRIGGER_EXPIRE, 0, 206);
+ }
+ break;
+
+ case 206: {
+ int oldIdx = _globals._sequenceIndexes[4];
+ _globals._sequenceIndexes[4] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[4], false, 10, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[4], 22, 25);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[4], oldIdx);
+ if (!_dodgeFl && !_fallFl)
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[4], SEQUENCE_TRIGGER_EXPIRE, 0, 207);
+ else
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[4], SEQUENCE_TRIGGER_EXPIRE, 0, 209);
+ }
+ break;
+
+ case 207: {
+ _vm->_sound->command(18);
+ int msgIndex = _scene->_kernelMessages.add(Common::Point(180, 25), 0xFDFC, 0, 0, 90, _game.getQuote(130));
+ _scene->_kernelMessages.setQuoted(msgIndex, 4, true);
+
+ int oldIdx = _globals._sequenceIndexes[4];
+ _globals._sequenceIndexes[4] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[4], false, 15, 4, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[4], 26, 27);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[4], oldIdx);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[4], SEQUENCE_TRIGGER_EXPIRE, 0, 208);
+ }
+ break;
+
+ case 208: {
+ _scene->_kernelMessages.add(Common::Point(180, 39), 0xFDFC, 0, 0, 90, _game.getQuote(131));
+ int oldIdx = _globals._sequenceIndexes[4];
+ _globals._sequenceIndexes[4] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[4], false, 10, 4, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[4], 28, 29);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[4], oldIdx);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[4], SEQUENCE_TRIGGER_EXPIRE, 0, 209);
+ }
+ break;
+
+ case 209: {
+ int oldIdx = _globals._sequenceIndexes[4];
+ _globals._sequenceIndexes[4] = _scene->_sequences.startCycle(_globals._spriteIndexes[4], false, 22);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[4], oldIdx);
+ _scene->_sequences.addTimer(1, 210);
+ }
+ break;
+
+ case 210:
+ _playingAnimFl = false;
+ break;
+ }
+}
+
+void Scene209::handleMonkeyFall() {
+ switch (_game._trigger) {
+ case 219: {
+ _vm->_sound->command(25);
+ _scene->_sprites.remove(_globals._spriteIndexes[7]);
+ _scene->_sprites.remove(_globals._spriteIndexes[6]);
+ _scene->_sprites.remove(_globals._spriteIndexes[5]);
+ _scene->_sprites.remove(_globals._spriteIndexes[4]);
+
+ _globals._spriteIndexes[8] = _scene->_sprites.addSprites(formAnimName('m', 4));
+ _scene->_kernelMessages.add(Common::Point(180, 26), 0xFDFC, 0, 0, 90, _game.getQuote(151));
+ _scene->_sequences.addTimer(40, 100);
+ _scene->_hotspots.activate(227, false);
+ int oldIdx = _globals._sequenceIndexes[3];
+ _monkeyPosition = 1;
+ _scene->_sequences.remove(_globals._sequenceIndexes[3]);
+ _globals._sequenceIndexes[8] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[8], false, 8, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[8], 1, 35);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[8], 6);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[3], oldIdx);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[8], SEQUENCE_TRIGGER_EXPIRE, 0, 220);
+ }
+ break;
+
+ case 220: {
+ _vm->_sound->command(18);
+ _scene->_kernelMessages.add(Common::Point(182, 109), 0xFDFC, 0, 0, 90, _game.getQuote(159));
+ _scene->_hotspots.activate(227, false);
+ int oldIdx = _globals._sequenceIndexes[3];
+ _monkeyPosition = 1;
+ _scene->_sequences.remove(_globals._sequenceIndexes[3]);
+ _globals._sequenceIndexes[8] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[8], false, 8, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[8], 36, 42);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[8], 6);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[3], oldIdx);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[8], SEQUENCE_TRIGGER_EXPIRE, 0, 221);
+ }
+ break;
+
+ case 221: {
+ _game._objects.setRoom(OBJ_BINOCULARS, 209);
+ _binocularsDroppedFl = true;
+ int oldIdx = _globals._sequenceIndexes[8];
+ _globals._sequenceIndexes[8] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[8], false, 8, 1, 0, 0);
+ _globals._sequenceIndexes[9] = _scene->_sequences.startCycle(_globals._spriteIndexes[9], false, 1);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[9], oldIdx);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[9], Common::Point(201, 131));
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[9], 8);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[8], oldIdx);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[8], 43, 72);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[8], SEQUENCE_TRIGGER_EXPIRE, 0, 222);
+ int idx = _scene->_dynamicHotspots.add(39, 13, _globals._sequenceIndexes[9], Common::Rect(0, 0, 0, 0));
+ _scene->_dynamicHotspots.setPosition(idx, Common::Point(200, 133), FACING_NORTH);
+ }
+ break;
+
+ case 222: {
+ _scene->_kernelMessages.add(Common::Point(182, 109), 0xFDFC, 0, 0, 70, _game.getQuote(160));
+ int oldIdx = _globals._sequenceIndexes[8];
+ _globals._sequenceIndexes[8] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[8], false, 8, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[8], 73, 78);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[8], oldIdx);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[8], SEQUENCE_TRIGGER_EXPIRE, 0, 223);
+ }
+ break;
+
+ case 223:
+ _scene->loadAnimation(Resources::formatName(209, 'e', -1, EXT_AA, ""), 224);
+ _vm->_sound->command(38);
+ break;
+
+ case 224:
+ _playingAnimFl = false;
+ _fallFl = false;
+ _counter = 0;
+ _pauseMode = 0;
+ _vm->_dialogs->show(20910);
+ _game._player._stepEnabled = true;
+ break;
+ }
+}
+
+void Scene209::handleMonkey1() {
+ switch (_game._trigger) {
+ case 212:
+ _scene->_sequences.remove(_globals._sequenceIndexes[4]);
+ _globals._sequenceIndexes[4] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[4], false, 9, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[4], 1, 13);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[4], SEQUENCE_TRIGGER_EXPIRE, 0, 213);
+ break;
+
+ case 213: {
+ int oldIdx = _globals._sequenceIndexes[4];
+ _globals._sequenceIndexes[7] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[7], false, 7, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[7], 1, 22);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[7], oldIdx);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[7], SEQUENCE_TRIGGER_EXPIRE, 0, 214);
+ }
+ break;
+
+ case 214: {
+ int oldIdx = _globals._sequenceIndexes[7];
+ _globals._sequenceIndexes[7] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[7], false, 7, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[7], 23, 26);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[7], oldIdx);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[7], SEQUENCE_TRIGGER_EXPIRE, 0, 215);
+ int msgIndex = _scene->_kernelMessages.add(Common::Point(170, 21), 0xFDFC, 0, 0, 90, _game.getQuote(156));
+ _scene->_kernelMessages.setQuoted(msgIndex, 3, true);
+ }
+ break;
+
+ case 215: {
+ _vm->_sound->command(18);
+ _scene->loadAnimation(Resources::formatName(209, 'a', -1, EXT_AA, ""), 251);
+ int oldIdx = _globals._sequenceIndexes[7];
+ _globals._sequenceIndexes[7] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[7], false, 7, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[7], 27, 35);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[7], oldIdx);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[7], SEQUENCE_TRIGGER_EXPIRE, 0, 216);
+ }
+ break;
+
+ case 216: {
+ int oldIdx = _globals._sequenceIndexes[7];
+ _globals._sequenceIndexes[4] = _scene->_sequences.startCycle(_globals._spriteIndexes[4], false, 22);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[4], oldIdx);
+ _scene->_sequences.addTimer(25, 217);
+ }
+ break;
+
+ case 217:
+ _pitchFl = false;
+ _counter = 0;
+ _pauseMode = 0;
+ _scene->_sequences.addTimer(1, 196);
+ break;
+ }
+}
+
+void Scene209::handleMonkey2() {
+ switch (_game._trigger) {
+ case 251:
+ _scene->_kernelMessages.add(Common::Point(0, 0), 0x1110, 34, 0, 60, _game.getQuote(137));
+ _vm->_sound->command(22);
+ _globals._sequenceIndexes[12] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[12], false, 11, 1, 0, 0);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[12], Common::Point(111, 133));
+ _scene->_sequences.setScale(_globals._sequenceIndexes[12], 79);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[12], 1, 6);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[12], SEQUENCE_TRIGGER_EXPIRE, 0, 252);
+ _game._player._priorTimer = _scene->_frameStartTime - _game._player._ticksAmount;
+ _game._player._visible = false;
+ break;
+
+ case 252: {
+ _scene->_kernelMessages.reset();
+ _scene->_kernelMessages.add(Common::Point(0, 0), 0x1110, 34, 0, 120, _game.getQuote(132));
+ int oldIdx = _globals._sequenceIndexes[12];
+ _globals._sequenceIndexes[12] = _scene->_sequences.startCycle(_globals._spriteIndexes[12], false, 7);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[12], Common::Point(111, 133));
+ _scene->_sequences.setScale(_globals._sequenceIndexes[12], 79);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[12], oldIdx);
+ _scene->_sequences.addTimer(120, 253);
+ }
+ break;
+
+ case 253:
+ _scene->_sequences.remove(_globals._sequenceIndexes[12]);
+ _game._player._priorTimer = _scene->_frameStartTime - _game._player._ticksAmount;
+ _game._player._visible = true;
+ _game._player._stepEnabled = true;
+ break;
+ }
+}
+
+void Scene209::handleDodge() {
+ switch (_game._trigger) {
+ case 241:
+ _scene->_hotspots.activate(227, true);
+ _scene->_sequences.remove(_globals._sequenceIndexes[3]);
+ _globals._sequenceIndexes[3] = _scene->_sequences.startCycle(_globals._spriteIndexes[3], false, 7);
+ _scene->_sequences.addTimer(6, 242);
+ break;
+
+ case 242:
+ _scene->_sequences.remove(_globals._sequenceIndexes[3]);
+ _globals._sequenceIndexes[3] = _scene->_sequences.startCycle(_globals._spriteIndexes[3], false, 5);
+ _scene->_sequences.addTimer(25, 243);
+ _vm->_sound->command(24);
+ break;
+
+ case 243:
+ _vm->_sound->command(18);
+ _scene->_sequences.remove(_globals._sequenceIndexes[3]);
+ _globals._sequenceIndexes[3] = _scene->_sequences.startCycle(_globals._spriteIndexes[3], false, 6);
+ _playingAnimFl = false;
+ _pauseMode = 0;
+ _scene->_kernelMessages.reset();
+ _scene->_kernelMessages.add(Common::Point(180, 21), 0xFDFC, 0, 0, 90, _game.getQuote(155));
+ if (!_shootMissedLastFl) {
+ _scene->_kernelMessages.add(Common::Point(0, 0), 0x1110, 34, 0, 120, _game.getQuote(135));
+ _shootMissedLastFl = true;
+ } else {
+ _scene->_kernelMessages.add(Common::Point(0, 0), 0x1110, 34, 0, 120, _game.getQuote(136));
+ }
+ break;
+ }
+}
+
+void Scene209::enter() {
+ _globals._spriteIndexes[12] = _scene->_sprites.addSprites(formAnimName('a', 1));
+ _globals._spriteIndexes[1] = _scene->_sprites.addSprites(formAnimName('e', -1));
+ _globals._spriteIndexes[2] = _scene->_sprites.addSprites(formAnimName('a', 0));
+ _globals._spriteIndexes[9] = _scene->_sprites.addSprites(formAnimName('b', 1));
+ _globals._spriteIndexes[3] = _scene->_sprites.addSprites(formAnimName('m', 0));
+ _globals._spriteIndexes[4] = _scene->_sprites.addSprites(formAnimName('m', 1));
+ _globals._spriteIndexes[5] = _scene->_sprites.addSprites(formAnimName('m', 3));
+ _globals._spriteIndexes[6] = _scene->_sprites.addSprites(formAnimName('m', 6));
+ _globals._spriteIndexes[7] = _scene->_sprites.addSprites(formAnimName('m', 8));
+
+ _game.loadQuoteSet(0x82, 0x83, 0x84, 0x9C, 0x97, 0x95, 0x99, 0x9E, 0x98, 0x9B, 0xA0, 0x96, 0x9F,
+ 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, 0x91, 0x92, 0x93, 0x94, 0x89, 0x85, 0x8A, 0x86, 0x87, 0x88, 0);
+
+ _vm->_palette->setEntry(252, 63, 44, 30);
+ _vm->_palette->setEntry(253, 63, 20, 22);
+
+ if (_game._objects.isInRoom(OBJ_PLANT_STALK)) {
+ _globals._sequenceIndexes[1] = _scene->_sequences.startCycle(_globals._spriteIndexes[1], false, 1);
+ int idx = _scene->_dynamicHotspots.add(271, 13, _globals._sequenceIndexes[1], Common::Rect(0, 0, 0, 0));
+ _scene->_dynamicHotspots.setPosition(idx, Common::Point(263, 129), FACING_SOUTH);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 13);
+ }
+
+ if (_scene->_priorSceneId == 208) {
+ _game._player._playerPos = Common::Point(11, 121);
+ _game._player._facing = FACING_EAST;
+ } else if (_scene->_priorSceneId != -2) {
+ _game._player._playerPos = Common::Point(28, 121);
+ _game._player._facing = FACING_SOUTH;
+ }
+
+ if (_game._objects.isInRoom(OBJ_BINOCULARS)) {
+ _globals._sequenceIndexes[9] = _scene->_sequences.startCycle(_globals._spriteIndexes[9], false, 1);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[9], Common::Point(201, 131));
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[9], 8);
+ int idx = _scene->_dynamicHotspots.add(39, 13, _globals._sequenceIndexes[9], Common::Rect(0, 0, 0, 0));
+ _scene->_dynamicHotspots.setPosition(idx, Common::Point(200, 133), FACING_NORTH);
+ }
+
+ if (_scene->_roomChanged) {
+ _game._objects.addToInventory(OBJ_POISON_DARTS);
+ _game._objects.addToInventory(OBJ_BLOWGUN);
+ _globals[kMonkeyStatus] = MONKEY_HAS_BINOCULARS;
+ }
+
+ _pitchFl = false;
+ _fallFl = false;
+ _dodgeFl = false;
+ _playingAnimFl = false;
+ _monkeyPosition = 1;
+ _counter = 0;
+ _pauseMode = 0;
+ _forceFallFl = false;
+ _shouldFallFl = false;
+ _forceDodgeFl = false;
+ _binocularsDroppedFl = false;
+ _shouldDodgeFl = false;
+ _startShootingInTimerFl = false;
+ _dialogAbortVal = 5;
+ _playingDialogFl = false;
+ _shootMissedLastFl = false;
+ _removeMonkeyFl = true;
+ _shootReadyFl = false;
+
+ _scene->_hotspots.activate(227, false);
+
+ sceneEntrySound();
+}
+
+void Scene209::step() {
+ if (!_playingAnimFl && !_pitchFl && !_fallFl && !_dodgeFl && (_pauseMode == 0) && (_globals[kMonkeyStatus] == MONKEY_HAS_BINOCULARS)) {
+ int randAction = _vm->getRandomNumber(1,50);
+ switch (randAction) {
+ case 1:
+ if ((_monkeyPosition == 1) && (_counter < 2)) {
+ _scene->_sequences.addTimer(1, 133);
+ _playingAnimFl = true;
+ _scene->_hotspots.activate(227, true);
+ ++_counter;
+ }
+ break;
+
+ case 2:
+ if ((_monkeyPosition == 1) && (_counter < 2)) {
+ _scene->_sequences.addTimer(1, 140);
+ _scene->_hotspots.activate(227, true);
+ _playingAnimFl = true;
+ ++_counter;
+ }
+ break;
+
+ case 3:
+ if (_monkeyPosition == 1) {
+ _scene->_sequences.addTimer(1, 145);
+ _scene->_hotspots.activate(227, true);
+ _playingAnimFl = true;
+ _counter = 0;
+ }
+ break;
+
+ case 4:
+ if ((_monkeyPosition == 2) && (_counter < 2)) {
+ _scene->_sequences.addTimer(1, 151);
+ _scene->_hotspots.activate(227, true);
+ ++_counter;
+ _playingAnimFl = true;
+ }
+ break;
+
+ case 5:
+ if (_monkeyPosition == 2) {
+ _scene->_sequences.addTimer(1, 161);
+ _scene->_hotspots.activate(227, true);
+ _counter = 0;
+ _playingAnimFl = true;
+ }
+ break;
+
+ case 6:
+ if (_monkeyPosition == 2) {
+ _scene->_sequences.addTimer(1, 189);
+ _scene->_hotspots.activate(227, true);
+ _counter = 0;
+ _playingAnimFl = true;
+ }
+ break;
+ case 7:
+ if (_monkeyPosition == 3) {
+ _scene->_hotspots.activate(227, true);
+ _scene->_sequences.addTimer(1, 167);
+ _playingAnimFl = true;
+ }
+ break;
+
+ case 8:
+ if (_monkeyPosition == 3) {
+ _scene->_sequences.addTimer(1, 178);
+ _playingAnimFl = true;
+ _scene->_hotspots.activate(227, true);
+ _counter = 0;
+ }
+ break;
+
+ case 9:
+ if ((_monkeyPosition == 3) && (_game._player._playerPos.x<120)) {
+ _scene->_sequences.addTimer(1, 182);
+ _scene->_hotspots.activate(227, true);
+ _counter = 0;
+ _playingAnimFl = true;
+ }
+ break;
+
+ case 10:
+ if (_monkeyPosition == 4) {
+ _scene->_sequences.addTimer(1, 196);
+ _scene->_hotspots.activate(227, true);
+ _playingAnimFl = true;
+ _counter = 0;
+ }
+ break;
+
+ case 11:
+ if ((_monkeyPosition == 4) && (_counter < 3)) {
+ _scene->_sequences.addTimer(1, 199);
+ _scene->_hotspots.activate(227, true);
+ ++_counter;
+ _playingAnimFl = true;
+ }
+ break;
+
+ case 30:
+ if (_monkeyPosition == 4) {
+ _scene->_sequences.addTimer(1, 246);
+ _scene->_hotspots.activate(227, true);
+ _counter = 0;
+ _playingAnimFl = true;
+ }
+ break;
+
+ default:
+ if ((randAction >= 12) && (randAction <= 20) && (_monkeyPosition == 2) && (_counter < 5)) {
+ _scene->_sequences.addTimer(1, 155);
+ ++_counter;
+ _playingAnimFl = true;
+ }
+
+ if ((randAction >= 21) && (randAction <= 29) && (_monkeyPosition == 3) && (_counter < 3)) {
+ _scene->_sequences.addTimer(1, 171);
+ _playingAnimFl = true;
+ ++_counter;
+ }
+ break;
+ }
+ }
+
+ if (!_dodgeFl && !_pitchFl && !_fallFl && (_pauseMode == 1))
+ _scene->_sequences.addTimer(1, 226);
+
+ if (!_dodgeFl && !_pitchFl && !_fallFl && (_pauseMode == 2))
+ handlePause();
+
+ if (!_dodgeFl && !_pitchFl && !_fallFl && (_pauseMode == 1))
+ initPauseCounterThreshold();
+
+ handlePeek();
+ handleVerticalMove();
+ handleLookStay();
+ handleLookRight();
+ handleBlink();
+ handleGetBinoculars();
+ handleStandFromPeek();
+ handleDodge();
+ handleBinocularBlink();
+ handleBinocularScan();
+ handleJumpInTree();
+ handleTongue();
+ handleMonkeyFall();
+ handleJumpAndHide();
+ handleMonkeyEating();
+ handleMonkey1();
+ handleStandBlink();
+ handleMonkey2();
+
+ if ((_monkeyPosition == 1) && !_playingAnimFl && _fallFl) {
+ _scene->_sequences.addTimer(1, 145);
+ _playingAnimFl = true;
+ }
+
+ if ((_monkeyPosition == 2) && !_playingAnimFl && _fallFl) {
+ _scene->_sequences.addTimer(1, 161);
+ _playingAnimFl = true;
+ }
+
+ if ((_monkeyPosition == 4) && !_playingAnimFl && _fallFl) {
+ _scene->_sequences.addTimer(1, 196);
+ _playingAnimFl = true;
+ }
+
+ if ((_monkeyPosition == 3) && !_playingAnimFl && _fallFl && _forceFallFl) {
+ _scene->_sequences.addTimer(1, 219);
+ _playingAnimFl = true;
+ }
+
+ if ((_monkeyPosition == 1) && !_playingAnimFl && _pitchFl) {
+ _scene->_sequences.addTimer(1, 145);
+ _playingAnimFl = true;
+ }
+
+ if ((_monkeyPosition == 2) && !_playingAnimFl && _pitchFl) {
+ _scene->_sequences.addTimer(1, 189);
+ _playingAnimFl = true;
+ }
+
+ if ((_monkeyPosition == 4) && !_playingAnimFl && _pitchFl) {
+ _scene->_sequences.addTimer(1, 212);
+ _playingAnimFl = true;
+ }
+
+ if ((_monkeyPosition == 3) && !_playingAnimFl && _pitchFl) {
+ _scene->_sequences.addTimer(1, 178);
+ _playingAnimFl = true;
+ }
+
+ if ((_monkeyPosition == 1) && !_playingAnimFl && _dodgeFl) {
+ _scene->_sequences.addTimer(1, 145);
+ _playingAnimFl = true;
+ }
+
+ if ((_monkeyPosition == 4) && !_playingAnimFl && _dodgeFl) {
+ _scene->_sequences.addTimer(1, 196);
+ _playingAnimFl = true;
+ }
+
+ if ((_monkeyPosition == 3) && !_playingAnimFl && _dodgeFl) {
+ _scene->_sequences.addTimer(1, 178);
+ _playingAnimFl = true;
+ }
+
+ if ((_monkeyPosition == 2) && !_playingAnimFl && _dodgeFl && _forceDodgeFl) {
+ _scene->_sequences.addTimer(1, 241);
+ _playingAnimFl = true;
+ }
+
+ if (_dodgeFl || _fallFl) { /* if want to dodge or fall */
+ if (!_playingAnimFl && (_monkeyPosition == 2))
+ _shouldDodgeFl = true;
+
+ if (!_playingAnimFl && (_monkeyPosition == 3))
+ _shouldFallFl = true;
+
+ switch (_game._trigger) {
+ case 228:
+ _game._player._visible = false;
+ _globals._sequenceIndexes[2] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[2], false, 8, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[2], 1, 7);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[2], Common::Point(116, 131));
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 4);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[2], SEQUENCE_TRIGGER_EXPIRE, 0, 229);
+ break;
+
+ case 229: {
+ int oldIdx = _globals._sequenceIndexes[2];
+ _globals._sequenceIndexes[2] = _scene->_sequences.startCycle(_globals._spriteIndexes[2], false, 7);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[2], Common::Point(116, 131));
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 4);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[2], oldIdx);
+ _scene->_sequences.addTimer(35, 230);
+ }
+ break;
+
+ case 230:
+ _scene->_sequences.remove(_globals._sequenceIndexes[2]);
+ _globals._sequenceIndexes[2] = _scene->_sequences.addReverseSpriteCycle(_globals._spriteIndexes[2], false, 8, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[2], 1, 7);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[2], Common::Point(116, 131));
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 4);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[2], SEQUENCE_TRIGGER_EXPIRE, 0, 231);
+ break;
+
+ case 231: {
+ int oldIdx = _globals._sequenceIndexes[2];
+ _globals._sequenceIndexes[2] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[2], false, 8, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[2], 8, 10);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[2], Common::Point(116, 131));
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 4);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[2], oldIdx);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[2], SEQUENCE_TRIGGER_EXPIRE, 0, 232);
+ _game._player._priorTimer = _scene->_frameStartTime - _game._player._ticksAmount;
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[2], -1);
+ _game._player._visible = false;
+ }
+ break;
+
+ case 232: {
+ int oldIdx = _globals._sequenceIndexes[2];
+ _globals._sequenceIndexes[2] = _scene->_sequences.startCycle(_globals._spriteIndexes[2], false, 10);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[2], Common::Point(116, 131));
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 4);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[2], oldIdx);
+ _scene->_sequences.addTimer(2, 233);
+ _scene->_kernelMessages.reset();
+ if (_dodgeFl && (_monkeyPosition != 1) && (_monkeyPosition != 2))
+ _scene->_kernelMessages.add(Common::Point(0, 0), 0x1110, 34, 0, 34463, _game.getQuote(138));
+ if (_fallFl && (_monkeyPosition != 3))
+ _scene->_kernelMessages.add(Common::Point(0, 0), 0x1110, 34, 0, 34463, _game.getQuote(138));
+ }
+ break;
+
+ case 233:
+ _shootReadyFl = true;
+ break;
+
+ case 234:
+ _scene->_sequences.remove(_globals._sequenceIndexes[2]);
+ _scene->_kernelMessages.reset();
+ if (_action.isAction(VERB_HOSE_DOWN, NOUN_BLOWGUN, NOUN_MONKEY)) {
+ _globals._sequenceIndexes[2] = _scene->_sequences.addReverseSpriteCycle(_globals._spriteIndexes[2], false, 7, 16, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[2], 11, 12);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[2], Common::Point(116, 131));
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 4);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[2], SEQUENCE_TRIGGER_SPRITE, 12, 239);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[2], SEQUENCE_TRIGGER_EXPIRE, 0, 235);
+ } else if (_action.isAction(VERB_SHOOT, NOUN_BLOWGUN, NOUN_MONKEY)) {
+ _globals._sequenceIndexes[2] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[2], false, 8, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[2], 11, 12);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[2], Common::Point(116, 131));
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 4);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[2], SEQUENCE_TRIGGER_EXPIRE, 0, 235);
+ _vm->_sound->command(23);
+ }
+ break;
+
+ case 235: {
+ int oldIdx = _globals._sequenceIndexes[2];
+ _globals._sequenceIndexes[2] = _scene->_sequences.startCycle(_globals._spriteIndexes[2], false, 13);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[2], Common::Point(116, 131));
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 4);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[2], oldIdx);
+ _scene->_sequences.addTimer(12, 236);
+ _forceFallFl = true;
+ _forceDodgeFl = true;
+ }
+ break;
+
+ case 236:
+ _scene->_sequences.remove(_globals._sequenceIndexes[2]);
+ _globals._sequenceIndexes[2] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[2], false, 8, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[2], 14, 16);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[2], Common::Point(116, 131));
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 4);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[2], SEQUENCE_TRIGGER_EXPIRE, 0, 237);
+ break;
+
+ case 237:
+ _game._player._visible = true;
+ _game._player._priorTimer = _scene->_frameStartTime - _game._player._ticksAmount;
+ _scene->_sequences.addTimer(1, 238);
+ break;
+
+ case 238:
+ _scene->_sequences.remove(_globals._sequenceIndexes[2]);
+ if (_dodgeFl)
+ _game._player._stepEnabled = true;
+
+ _startShootingInTimerFl = false;
+
+ if (_fallFl) {
+ _globals[kMonkeyStatus] = MONKEY_IS_GONE;
+ _game._objects.setRoom(OBJ_POISON_DARTS, NOWHERE);
+ }
+ _dodgeFl = false;
+ _fallFl = false;
+ _forceFallFl = false;
+ _forceDodgeFl = false;
+ _shouldFallFl = false;
+ _shouldDodgeFl = false;
+ break;
+
+ case 239:
+ _vm->_sound->command(23);
+ break;
+ }
+ }
+
+ if (_game._trigger == 100)
+ _scene->_kernelMessages.add(Common::Point(0, 0), 0x1110, 34, 0, 120, _game.getQuote(134));
+
+ if (_shootReadyFl && (_shouldFallFl || _shouldDodgeFl)) {
+ _scene->_sequences.addTimer(4, 234);
+ _shootReadyFl = false;
+ }
+}
+
+void Scene209::preActions() {
+ if (_action.isAction(VERB_WALK_TOWARDS, NOUN_FIELD_TO_WEST))
+ _game._player._walkOffScreenSceneId = 208;
+
+ if (_globals[kMonkeyStatus] == MONKEY_HAS_BINOCULARS) {
+ if ((_action.isAction(VERB_SHOOT) || _action.isAction(VERB_HOSE_DOWN)) && _action.isTarget(NOUN_MONKEY)
+ && _action.isObject(NOUN_BLOWGUN) && _game._objects.isInInventory(OBJ_BLOWGUN) && _game._objects.isInInventory(OBJ_POISON_DARTS)) {
+ _game._player._prepareWalkPos = Common::Point(111, 129);
+ _game._player._prepareWalkFacing = FACING_NORTHEAST;
+ _game._player._needToWalk = true;
+ _game._player._readyToWalk = true;
+ }
+
+ if (_action.isAction(VERB_LOOK, NOUN_MONKEY) || _action.isAction(VERB_TALKTO, NOUN_MONKEY)) {
+ _game._player._prepareWalkPos = Common::Point(111, 129);
+ _game._player._prepareWalkFacing = FACING_NORTHEAST;
+ _game._player._needToWalk = true;
+ _game._player._readyToWalk = true;
+ }
+ }
+}
+
+void Scene209::actions() {
+ if (_action._lookFlag) {
+ _vm->_dialogs->show(20912);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_WALK_TOWARDS, NOUN_ROCKY_AREA_TO_NORTH)) {
+ _scene->_nextSceneId = 203;
+ _action._inProgress = false;
+ return;
+ }
+
+ if ((_action.isAction(VERB_TALKTO, NOUN_MONKEY)) && !_pitchFl && !_playingDialogFl) {
+ _scene->_sequences.addTimer(1, _dialogAbortVal);
+ _playingDialogFl = true;
+ _game._player._stepEnabled = false;
+ _action._inProgress = false;
+ return;
+ }
+
+ switch (_game._trigger) {
+ case 130:
+ _game._player._stepEnabled = true;
+ _playingDialogFl = false;
+ _action._inProgress = false;
+ return;
+
+ case 5:
+ _scene->_kernelMessages.reset();
+ _scene->_kernelMessages.add(Common::Point(0, 0), 0x1110, 34, 6, 180, _game.getQuote(139));
+ _action._inProgress = false;
+ return;
+
+ case 6:
+ _scene->_kernelMessages.add(Common::Point(180, 21), 0xFDFC, 0, 0, 60, _game.getQuote(151));
+ _scene->_sequences.addTimer(60, 130);
+ _dialogAbortVal = 7;
+ _action._inProgress = false;
+ return;
+
+ case 7:
+ _scene->_kernelMessages.reset();
+ _scene->_kernelMessages.add(Common::Point(0, 0), 0x1110, 34, 8, 180, _game.getQuote(140));
+ _action._inProgress = false;
+ return;
+
+ case 8:
+ _scene->_kernelMessages.add(Common::Point(180, 21), 0xFDFC, 0, 0, 60, _game.getQuote(149));
+ _scene->_sequences.addTimer(60, 130);
+ _dialogAbortVal = 9;
+ _action._inProgress = false;
+ return;
+
+ case 9:
+ _scene->_kernelMessages.reset();
+ _scene->_kernelMessages.add(Common::Point(0, 0), 0x1110, 34, 0, 180, _game.getQuote(141));
+ _scene->_sequences.addTimer(200, 10);
+ _action._inProgress = false;
+ return;
+
+ case 10:
+ _scene->_kernelMessages.add(Common::Point(0, 0), 0x1110, 34, 11, 180, _game.getQuote(142));
+ _action._inProgress = false;
+ return;
+
+ case 11:
+ _scene->_kernelMessages.add(Common::Point(180, 21), 0xFDFC, 0, 0, 60, _game.getQuote(152));
+ _scene->_sequences.addTimer(60, 130);
+ _dialogAbortVal = 12;
+ _action._inProgress = false;
+ return;
+
+ case 12:
+ _scene->_kernelMessages.reset();
+ _scene->_kernelMessages.add(Common::Point(0, 0), 0x1110, 34, 0, 130, _game.getQuote(143));
+ _scene->_sequences.addTimer(150, 13);
+ _action._inProgress = false;
+ return;
+
+ case 13:
+ _scene->_kernelMessages.add(Common::Point(0, 0), 0x1110, 34, 14, 180, _game.getQuote(145));
+ _action._inProgress = false;
+ return;
+
+ case 14:
+ _scene->_kernelMessages.add(Common::Point(180, 21), 0xFDFC, 0, 0, 60, _game.getQuote(151));
+ _scene->_sequences.addTimer(60, 130);
+ _dialogAbortVal = 15;
+ _action._inProgress = false;
+ return;
+
+ case 15:
+ _scene->_kernelMessages.reset();
+ _scene->_kernelMessages.add(Common::Point(0, 0), 0x1110, 34, 16, 180, _game.getQuote(146));
+ _action._inProgress = false;
+ return;
+
+ case 16:
+ _scene->_kernelMessages.add(Common::Point(180, 21), 0xFDFC, 0, 17, 60, _game.getQuote(154));
+ _action._inProgress = false;
+ return;
+
+ case 17:
+ _scene->_kernelMessages.add(Common::Point(0, 0), 0x1110, 34, 130, 60, _game.getQuote(147));
+ _dialogAbortVal = 18;
+ _action._inProgress = false;
+ return;
+
+ case 18:
+ _scene->_kernelMessages.reset();
+ _scene->_kernelMessages.add(Common::Point(0, 0), 0x1110, 34, 0, 180, _game.getQuote(148));
+ _pitchFl = true;
+ _playingDialogFl = false;
+ _dialogAbortVal = 5;
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_globals[kMonkeyStatus] == MONKEY_HAS_BINOCULARS) {
+ if ((_action.isAction(VERB_SHOOT) || _action.isAction(VERB_HOSE_DOWN)) && _action.isTarget(NOUN_MONKEY)
+ && _action.isObject(NOUN_BLOWGUN) && _game._objects.isInInventory(OBJ_BLOWGUN) && _game._objects.isInInventory(OBJ_POISON_DARTS)) {
+ if (_action.isAction(VERB_SHOOT, NOUN_BLOWGUN, NOUN_MONKEY) && !_startShootingInTimerFl) {
+ _game._triggerSetupMode = SEQUENCE_TRIGGER_DAEMON;
+ _scene->_sequences.addTimer(1, 231);
+ _startShootingInTimerFl = true;
+ _game._player._stepEnabled = false;
+ _dodgeFl = true;
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_HOSE_DOWN, NOUN_BLOWGUN, NOUN_MONKEY) && !_startShootingInTimerFl) {
+ _game._triggerSetupMode = SEQUENCE_TRIGGER_DAEMON;
+ _scene->_sequences.addTimer(1, 228);
+ _game._player._stepEnabled = false;
+ _fallFl = true;
+ _startShootingInTimerFl = true;
+ _action._inProgress = false;
+ return;
+ }
+ }
+
+ if (_action.isAction(VERB_LOOK, NOUN_MONKEY)) {
+ _pitchFl = true;
+ _game._player._stepEnabled = false;
+ _vm->_dialogs->show(20914);
+ _action._inProgress = false;
+ return;
+ }
+ }
+
+ if (_action.isAction(VERB_TAKE, NOUN_PLANT_STALK) && (_game._trigger || _game._objects.isInRoom(OBJ_PLANT_STALK))) {
+ switch (_game._trigger) {
+ case 0:
+ _globals._spriteIndexes[11] = _scene->_sprites.addSprites("*RXMBD_2");
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._sequenceIndexes[11] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[11], false, 3, 2, 0, 0);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[11]);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[11], SEQUENCE_TRIGGER_SPRITE, 4, 1);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[11], SEQUENCE_TRIGGER_EXPIRE, 0, 2);
+ break;
+
+ case 1:
+ _scene->_sequences.remove(_globals._sequenceIndexes[1]);
+ _game._objects.addToInventory(OBJ_PLANT_STALK);
+ break;
+
+ case 2:
+ _game._player._visible = true;
+ _game._player._stepEnabled = true;
+ _scene->_sequences.addTimer(4, 3);
+ _vm->_dialogs->showItem(OBJ_PLANT_STALK, 0x328);
+ break;
+
+ case 3:
+ _scene->_sprites.remove(_globals._spriteIndexes[11]);
+ break;
+ }
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_TAKE, NOUN_BINOCULARS) && (_game._trigger || _game._objects.isInRoom(OBJ_BINOCULARS))) {
+ switch (_game._trigger) {
+ case 0:
+ _globals._spriteIndexes[10] = _scene->_sprites.addSprites("*RXMBD_8");
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._sequenceIndexes[10] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[10], false, 3, 2, 0, 0);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[10]);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[10], SEQUENCE_TRIGGER_SPRITE, 4, 1);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[10], SEQUENCE_TRIGGER_EXPIRE, 0, 2);
+ break;
+
+ case 1:
+ _scene->_sequences.remove(_globals._sequenceIndexes[9]);
+ _game._objects.addToInventory(OBJ_BINOCULARS);
+ break;
+
+ case 2:
+ _game._player._visible = true;
+ _game._player._stepEnabled = true;
+ _binocularsDroppedFl = false;
+ _scene->_sequences.addTimer(4, 3);
+ break;
+
+ case 3:
+ _vm->_dialogs->showItem (OBJ_BINOCULARS, 0x51AF);
+ _scene->_sprites.remove(_globals._spriteIndexes[10]);
+ break;
+ }
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_LOOK, NOUN_SKY)) {
+ _vm->_dialogs->show(20901);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_LOOK, NOUN_BAMBOO_LIKE_PLANT)) {
+ _vm->_dialogs->show(20902);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_LOOK, NOUN_MOUNTAINSIDE)) {
+ _vm->_dialogs->show(20903);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_LOOK, NOUN_GRASSY_FIELD)) {
+ _vm->_dialogs->show(20904);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_LOOK, NOUN_FIELD_TO_WEST)) {
+ _vm->_dialogs->show(20905);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_LOOK, NOUN_ROCKY_AREA_TO_NORTH)) {
+ _vm->_dialogs->show(20906);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_LOOK, NOUN_PLANT_STALK) && (_action._savedFields._mainObjectSource == 4)) {
+ _vm->_dialogs->show(20907);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_GIVE, NOUN_TWINKIFRUIT, 0xE3) || _action.isAction(VERB_THROW, NOUN_TWINKIFRUIT, 0xE3)) {
+ _vm->_dialogs->show(20909);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_LOOK, NOUN_TREES)) {
+ _vm->_dialogs->show(20913);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_THROW, NOUN_MONKEY) && _game._objects.isInInventory(_game._objects.getIdFromDesc(_action._activeAction._objectNameId))) {
+ if (!_action.isAction(0x114)) {
+ _vm->_dialogs->show(20915);
+ }
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_THROW, NOUN_POISON_DARTS, 0xE3)) {
+ _vm->_dialogs->show(20916);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_LOOK, NOUN_PALM_TREE)) {
+ if (_globals[kMonkeyStatus] == MONKEY_HAS_BINOCULARS) {
+ if (_monkeyPosition == 1)
+ _vm->_dialogs->show(20917);
+ else
+ _vm->_dialogs->show(20918);
+ } else {
+ if (_globals[kMonkeyStatus] == MONKEY_AMBUSH_READY)
+ _vm->_dialogs->show(20917);
+ else
+ _vm->_dialogs->show(20919);
+ }
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_LOOK, NOUN_MELON_MUSH)) {
+ _vm->_dialogs->show(20920);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_TAKE, NOUN_MELON_MUSH)) {
+ _vm->_dialogs->show(20921);
+ _action._inProgress = false;
+ return;
+ }
+}
+
+/*****************************************************************************/
+
+Scene210::Scene210(MADSEngine *vm) : Scene2xx(vm) {
+ _curDialogNode = -1;
+ _nextHandsPlace = 0;
+ _twinkleAnimationType = 0;
+ _twinklesCurrentFrame = 0;
+ _shouldTalk = false;
+ _shouldFaceRex = false;
+ _shouldMoveHead = false;
+ _stopWalking = false;
+ _twinklesTalking = false;
+ _twinklesTalk2 = false;
+ _doorway = 0;
+ _subQuote2 = "";
+}
+
+void Scene210::synchronize(Common::Serializer &s) {
+ Scene2xx::synchronize(s);
+
+ s.syncAsSint32LE(_curDialogNode);
+ s.syncAsSint32LE(_nextHandsPlace);
+ s.syncAsSint32LE(_twinkleAnimationType);
+ s.syncAsSint32LE(_twinklesCurrentFrame);
+
+ s.syncAsByte(_shouldTalk);
+ s.syncAsByte(_shouldFaceRex);
+ s.syncAsByte(_shouldMoveHead);
+ s.syncAsByte(_stopWalking);
+ s.syncAsByte(_twinklesTalking);
+ s.syncAsByte(_twinklesTalk2);
+
+ s.syncAsSint32LE(_doorway);
+
+ s.syncString(_subQuote2);
+}
+
+void Scene210::setup() {
+ setPlayerSpritesPrefix();
+ setAAName();
+ _scene->addActiveVocab(NOUN_DOORWAY);
+ _scene->addActiveVocab(VERB_WALK_THROUGH);
+}
+
+void Scene210::handleConversations() {
+ if (_game._trigger == 0) {
+ _scene->_kernelMessages.reset();
+ _game._player._stepEnabled = false;
+ Common::String curQuote = _game.getQuote(_action._activeAction._verbId);
+ if (_vm->_font->getWidth(curQuote, _scene->_textSpacing) > 200) {
+ Common::String subQuote1;
+ _game.splitQuote(curQuote, subQuote1, _subQuote2);
+ _scene->_kernelMessages.add(Common::Point(0, -14), 0x1110, 34, 0, 240, subQuote1);
+ _scene->_sequences.addTimer(60, 50);
+ } else {
+ _scene->_kernelMessages.add(Common::Point(0, 0), 0x1110, 34, 1, 120, curQuote);
+ }
+ } else if (_game._trigger == 50) {
+ _scene->_kernelMessages.add(Common::Point(0, 0), 0x1110, 34, 0, 240, _subQuote2);
+ _scene->_sequences.addTimer(180, 1);
+ } else {
+ if (_game._trigger == 1)
+ _scene->_kernelMessages.reset();
+
+ switch (_curDialogNode) {
+ case 1:
+ handleConversation1();
+ break;
+
+ case 2:
+ handleConversation2();
+ break;
+
+ case 3:
+ handleConversation3();
+ break;
+
+ case 5:
+ handleConversation5();
+ break;
+
+ case 6:
+ handleConversation6();
+ break;
+
+ case 7:
+ handleConversation7();
+ break;
+
+ case 8:
+ handleConversation8();
+ break;
+ }
+ }
+}
+
+void Scene210::handleConversation1() {
+ switch (_action._activeAction._verbId) {
+ case 180:
+ setDialogNode(2);
+ break;
+
+ case 181:
+ setDialogNode(6);
+ break;
+
+ case 182:
+ setDialogNode(4);
+ break;
+
+ case 183:
+ setDialogNode(9);
+ break;
+
+ case 184:
+ setDialogNode(0);
+ break;
+ }
+}
+
+void Scene210::handleConversation2() {
+ switch (_action._activeAction._verbId) {
+ case 187:
+ setDialogNode(3);
+ break;
+
+ case 188:
+ setDialogNode(4);
+ break;
+
+ case 189:
+ setDialogNode(0);
+ break;
+ }
+}
+
+void Scene210::handleConversation3() {
+ switch (_action._activeAction._verbId) {
+ case 193:
+ setDialogNode(6);
+ break;
+
+ case 194:
+ setDialogNode(5);
+ break;
+
+ case 195:
+ setDialogNode(4);
+ break;
+
+ case 196:
+ setDialogNode(0);
+ break;
+ }
+}
+
+void Scene210::handleConversation5() {
+ switch (_action._activeAction._verbId) {
+ case 204:
+ setDialogNode(6);
+ break;
+
+ case 205:
+ case 206:
+ setDialogNode(4);
+ break;
+
+ case 207:
+ setDialogNode(0);
+ break;
+ }
+}
+
+void Scene210::handleConversation6() {
+ switch (_action._activeAction._verbId) {
+ case 211:
+ setDialogNode(7);
+ break;
+
+ case 212:
+ setDialogNode(4);
+ break;
+
+ case 213:
+ setDialogNode(0);
+ break;
+ }
+}
+
+void Scene210::handleConversation7() {
+ switch (_action._activeAction._verbId) {
+ case 216:
+ case 217:
+ case 219:
+ setDialogNode(4);
+ break;
+
+ case 218:
+ setDialogNode(8);
+ break;
+
+ case 220:
+ setDialogNode(0);
+ break;
+ }
+}
+
+void Scene210::handleConversation8() {
+ switch (_action._activeAction._verbId) {
+ case 223:
+ case 224:
+ setDialogNode(4);
+ break;
+
+ case 225:
+ case 226:
+ setDialogNode(9);
+ break;
+
+ case 227:
+ setDialogNode(0);
+ break;
+ }
+}
+
+void Scene210::setDialogNode(int node) {
+ switch (node) {
+ case 0:
+ _scene->_userInterface.setup(kInputBuildingSentences);
+ _shouldFaceRex = false;
+ _shouldTalk = false;
+ _game._player._stepEnabled = true;
+ _curDialogNode = 0;
+ break;
+
+ case 2:
+ switch (_game._trigger) {
+ case 1:
+ _nextHandsPlace = 1;
+ _shouldTalk = true;
+ _game._player._stepEnabled = false;
+ if (_twinklesTalking) {
+ handleTwinklesSpeech(0xB9, -1, 0);
+ _scene->_sequences.addTimer(180, 2);
+ } else {
+ _scene->_sequences.addTimer(6, 1);
+ }
+ break;
+
+ case 2:
+ _nextHandsPlace = 0;
+ handleTwinklesSpeech(186, 0, 0);
+ _scene->_sequences.addTimer(180, 3);
+ break;
+
+ default:
+ _nextHandsPlace = 0;
+ _shouldTalk = false;
+ _game._player._stepEnabled = true;
+ newNode(2);
+ break;
+ }
+ break;
+
+ case 3:
+ switch (_game._trigger) {
+ case 1:
+ _nextHandsPlace = 0;
+ _shouldTalk = true;
+ _game._player._stepEnabled = false;
+ if (_twinklesTalking) {
+ handleTwinklesSpeech(0xBE, -2, 0);
+ _scene->_sequences.addTimer(180, 2);
+ } else {
+ _scene->_sequences.addTimer(6, 1);
+ }
+ break;
+ case 2:
+ _nextHandsPlace = 2;
+ handleTwinklesSpeech(191, -1, 0);
+ _scene->_sequences.addTimer(180, 3);
+ break;
+ case 3:
+ _nextHandsPlace = 0;
+ handleTwinklesSpeech(192, 0, 0);
+ _scene->_sequences.addTimer(180, 4);
+ break;
+ default:
+ _shouldTalk = false;
+ _game._player._stepEnabled = true;
+ newNode(3);
+ break;
+ }
+ break;
+
+ case 4:
+ if (_game._trigger == 1) {
+ _nextHandsPlace = 1;
+ _shouldTalk = true;
+ _game._player._stepEnabled = false;
+
+ int quote;
+ if (_game._storyMode == STORYMODE_NAUGHTY)
+ quote = _vm->getRandomNumber(199, 201);
+ else
+ quote = _vm->getRandomNumber(197, 198);
+
+ if (_twinklesTalking) {
+ handleTwinklesSpeech(quote, 0, 360);
+ _scene->_sequences.addTimer(120, 2);
+ } else {
+ _scene->_sequences.addTimer(6, 1);
+ }
+ } else {
+ _scene->_userInterface.setup(kInputBuildingSentences);
+ _shouldFaceRex = false;
+ _shouldTalk = false;
+ _game._player._stepEnabled = true;
+ }
+ break;
+
+ case 5:
+ switch (_game._trigger) {
+ case 1:
+ _nextHandsPlace = 2;
+ _shouldTalk = true;
+ _game._player._stepEnabled = false;
+ if (_twinklesTalking) {
+ handleTwinklesSpeech(0xCA, -1, 0);
+ _scene->_sequences.addTimer(180, 2);
+ } else {
+ _scene->_sequences.addTimer(6, 1);
+ }
+ break;
+
+ case 2:
+ _nextHandsPlace = 1;
+ handleTwinklesSpeech(0xCB, 0, 0);
+ _scene->_sequences.addTimer(180, 3);
+ break;
+
+ default:
+ _nextHandsPlace = 2;
+ _shouldTalk = false;
+ _game._player._stepEnabled = true;
+ newNode(5);
+ break;
+ }
+ break;
+
+ case 6:
+ switch (_game._trigger) {
+ case 1:
+ _nextHandsPlace = 1;
+ _shouldTalk = true;
+ _game._player._stepEnabled = false;
+ if (_twinklesTalking) {
+ handleTwinklesSpeech(0xD0, -2, 0);
+ _scene->_sequences.addTimer(180, 2);
+ } else {
+ _scene->_sequences.addTimer(6, 1);
+ }
+ break;
+
+ case 2:
+ handleTwinklesSpeech(0xD1, -1, 0);
+ _scene->_sequences.addTimer(180, 3);
+ break;
+
+ case 3:
+ _nextHandsPlace = 1;
+ handleTwinklesSpeech(0xD2, 0, 0);
+ _scene->_sequences.addTimer(180, 4);
+ break;
+
+ default:
+ _nextHandsPlace = 0;
+ _shouldTalk = false;
+ _game._player._stepEnabled = true;
+ newNode(6);
+ break;
+ }
+ break;
+
+ case 7:
+ switch (_game._trigger) {
+ case 1:
+ _nextHandsPlace = 2;
+ _shouldTalk = true;
+ _game._player._stepEnabled = false;
+ if (_twinklesTalking) {
+ handleTwinklesSpeech(0xD6, -1, 0);
+ _scene->_sequences.addTimer(180, 2);
+ } else {
+ _scene->_sequences.addTimer(6, 1);
+ }
+ break;
+
+ case 2:
+ handleTwinklesSpeech(0xD7, 0, 0);
+ _scene->_sequences.addTimer(180, 3);
+ break;
+
+ default:
+ _shouldTalk = false;
+ _game._player._stepEnabled = true;
+ newNode(7);
+ break;
+ }
+ break;
+
+ case 8:
+ switch (_game._trigger) {
+ case 1:
+ _nextHandsPlace = 2;
+ _shouldTalk = true;
+ _game._player._stepEnabled = false;
+ if (_twinklesTalking) {
+ handleTwinklesSpeech(0xDD, -1, 0);
+ _scene->_sequences.addTimer(180, 2);
+ } else {
+ _scene->_sequences.addTimer(6, 1);
+ }
+ break;
+
+ case 2:
+ handleTwinklesSpeech(0xDE, 0, 0);
+ _scene->_sequences.addTimer(180, 3);
+ break;
+
+ default:
+ _shouldTalk = false;
+ _game._player._stepEnabled = true;
+ newNode(8);
+ break;
+ }
+ break;
+
+
+ case 9:
+ switch (_game._trigger) {
+ case 1:
+ _nextHandsPlace = 0;
+ _shouldTalk = true;
+ _game._player._stepEnabled = false;
+ if (_twinklesTalking) {
+ _scene->_userInterface.emptyConversationList();
+ _scene->_userInterface.setup(kInputConversation);
+ handleTwinklesSpeech(0xE4, -1, 0);
+ _scene->_sequences.addTimer(180, 2);
+ } else {
+ _scene->_sequences.addTimer(6, 1);
+ }
+ break;
+
+ case 2:
+ handleTwinklesSpeech(0xE5, 0, 0);
+ _scene->_sequences.addTimer(180, 3);
+ break;
+
+ case 3:
+ _twinkleAnimationType = 2;
+ _globals[kCurtainOpen] = true;
+ _game._player._visible = false;
+ _vm->_palette->lock();
+ _scene->_kernelMessages.reset();
+ _scene->freeAnimation();
+ _scene->_activeAnimation = nullptr;
+ _scene->resetScene();
+
+ _globals._spriteIndexes[1] = _scene->_sprites.addSprites(formAnimName('c', -1));
+ _game.loadQuoteSet(0xE6, 0xE9, 0xEA, 0xE7, 0xE8, 0);
+ _scene->loadAnimation(formAnimName('B', -1), 4);
+ break;
+
+ case 4: {
+ _globals._spriteIndexes[8] = _scene->_sequences.startCycle(_globals._spriteIndexes[1], false, 5);
+ _scene->_sequences.setDepth(_globals._spriteIndexes[8], 1);
+
+ int msgIndex = _scene->_kernelMessages.add(Common::Point(160, 20), 0x1110, 32, 5, 180, _game.getQuote(231));
+ _scene->_kernelMessages.setQuoted(msgIndex, 4, true);
+ }
+ break;
+
+ case 5: {
+ int msgIndex = _scene->_kernelMessages.add(Common::Point(160, 40), 0xFDFC, 32, 6, 180, _game.getQuote(233));
+ _scene->_kernelMessages.setQuoted(msgIndex, 4, true);
+ }
+ break;
+
+ case 6: {
+ int msgIndex = _scene->_kernelMessages.add(Common::Point(160, 60), 0x1110, 32, 7, 180, _game.getQuote(232));
+ _scene->_kernelMessages.setQuoted(msgIndex, 4, true);
+ }
+ break;
+
+ case 7: {
+ int msgIndex = _scene->_kernelMessages.add(Common::Point(160, 80), 0xFDFC, 32, 8, 180, _game.getQuote(234));
+ _scene->_kernelMessages.setQuoted(msgIndex, 4, true);
+ }
+ break;
+
+ case 8:
+ _globals[kTwinklesStatus] = TWINKLES_GONE;
+ _scene->_nextSceneId = 216;
+ break;
+ }
+ break;
+ }
+}
+
+void Scene210::handleTwinklesSpeech(int quoteId, int shiftX, uint32 delay) {
+ _scene->_kernelMessages.add(Common::Point(10, 70 + (shiftX * 14)), 0xFDFC, 0, 0, (delay == 0) ? 9999999 : delay, _game.getQuote(quoteId));
+}
+
+void Scene210::newNode(int node) {
+ _curDialogNode = node;
+
+ switch (_curDialogNode) {
+ case 1:
+ _conv1.start();
+ break;
+
+ case 2:
+ _conv2.start();
+ break;
+
+ case 3:
+ _conv3.start();
+ break;
+
+ case 5:
+ _conv5.start();
+ break;
+
+ case 6:
+ _conv6.start();
+ break;
+
+ case 7:
+ _conv7.start();
+ break;
+
+ case 8:
+ _conv8.start();
+ break;
+
+ default:
+ break;
+ }
+}
+
+void Scene210::restoreDialogNode(int node, int msgId, int posY) {
+ int curQuoteId = msgId;
+ int curY = 1 - posY;
+ for (int count = 0; count < posY; count++) {
+ handleTwinklesSpeech(curQuoteId, curY, 0);
+ curY++;
+ curQuoteId++;
+ }
+
+ newNode(node);
+}
+
+void Scene210::enter() {
+ _globals._spriteIndexes[1] = _scene->_sprites.addSprites(formAnimName('c', -1));
+
+ if (!_game._visitedScenes._sceneRevisited)
+ _globals[kCurtainOpen] = 0;
+
+ if (_scene->_priorSceneId == 205)
+ _game._player._playerPos = Common::Point(277, 56);
+ else if (_scene->_priorSceneId == 215) {
+ _game._player._playerPos = Common::Point(168, 128);
+ _game._player._facing = FACING_SOUTH;
+ _globals[kCurtainOpen] = true;
+ } else if (_scene->_priorSceneId != -2)
+ _game._player._playerPos = Common::Point(308, 132);
+
+ if (!_globals[kCurtainOpen]) {
+ _globals._sequenceIndexes[1] = _scene->_sequences.startCycle(_globals._spriteIndexes[1], false, 5);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 5);
+ } else {
+ int idx = _scene->_dynamicHotspots.add(112, 395, -1, Common::Rect(163, 87, 163 + 19, 87 + 36));
+ _doorway = _scene->_dynamicHotspots.setPosition(idx, Common::Point(168, 127), FACING_NORTH);
+ _scene->_dynamicHotspots.setCursor(_doorway, CURSOR_GO_UP);
+ }
+
+ _game.loadQuoteSet(0x5A, 0x73, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB8, 0xB7,
+ 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA,
+ 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC,
+ 0xDD, 0xDE, 0xDF, 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0);
+
+ _conv1.setup(0x2E, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0);
+
+ if (!_game._visitedScenes._sceneRevisited) {
+ _conv1.set(0x2E, 0xB4, 0xB5, 0xB6, 0xB8, 0);
+
+ if (_game._widepipeCtr >= 2)
+ _conv1.write(0xB7, true);
+ }
+
+ bool sceneRevisited = _game._visitedScenes._sceneRevisited;
+ _conv2.setup(0x2F, 0xBC, 0xBB, 0xBD, sceneRevisited ? 0 : -1);
+ _conv3.setup(0x30, 0xC3, 0xC2, 0xC1, 0xC4, sceneRevisited ? 0 : -1);
+ _conv5.setup(0x31, 0xCD, 0xCC, 0xCE, 0xCF, sceneRevisited ? 0 : -1);
+ _conv6.setup(0x32, 0xD3, 0xD4, 0xD5, sceneRevisited ? 0 : -1);
+ _conv7.setup(0x33, 0xD8, 0xDA, 0xD9, 0xDB, 0xDC, sceneRevisited ? 0 : -1);
+ _conv8.setup(0x34, 0xDF, 0xE0, 0xE1, 0xE2, 0xE3, sceneRevisited ? 0 : -1);
+
+ _twinkleAnimationType = 0;
+ _twinklesCurrentFrame = 0;
+
+ if (_scene->_priorSceneId != -2) {
+ _shouldMoveHead = false;
+ _shouldFaceRex = false;
+ _shouldTalk = false;
+ _nextHandsPlace = 0;
+ _twinklesTalking = false;
+ _curDialogNode = 0;
+ _stopWalking = false;
+ _twinklesTalk2 = (_globals[kTwinklesApproached] > 0);
+ }
+
+ if (_globals[kTwinklesStatus] == 0) {
+ _scene->loadAnimation(formAnimName('A', -1));
+ _twinkleAnimationType = 1;
+ } else
+ _scene->_hotspots.activate(476, false);
+
+ if (_curDialogNode) {
+ int quote = 0;
+ int number = 0;
+
+ switch (_curDialogNode) {
+ case 1:
+ quote = 0xB3;
+ number = 1;
+ break;
+ case 2:
+ quote = 0xB9;
+ number = 2;
+ break;
+ case 3:
+ quote = 0xBE;
+ number = 3;
+ break;
+ case 5:
+ quote = 0xCA;
+ number = 2;
+ break;
+ case 6:
+ quote = 0xD0;
+ number = 3;
+ break;
+ case 7:
+ quote = 0xD6;
+ number = 2;
+ break;
+ case 8:
+ quote = 0xDD;
+ number = 2;
+ break;
+ }
+
+ restoreDialogNode(_curDialogNode, quote, number);
+ _scene->_activeAnimation->setCurrentFrame(131);
+ }
+
+ _vm->_palette->setEntry(252, 63, 63, 10);
+ _vm->_palette->setEntry(253, 45, 45, 5);
+
+ sceneEntrySound();
+}
+
+void Scene210::step() {
+ if ((_twinkleAnimationType == 1) && _scene->_activeAnimation) {
+ if (_twinklesCurrentFrame != _scene->_activeAnimation->getCurrentFrame()) {
+ _twinklesCurrentFrame = _scene->_activeAnimation->getCurrentFrame();
+ int reset_frame = -1;
+ int random = _vm->getRandomNumber(1, 1000);
+
+ switch (_twinklesCurrentFrame) {
+ case 31:
+ case 58:
+ case 74:
+ case 108:
+ case 190:
+ if (_shouldFaceRex)
+ reset_frame = 108;
+ else if ((random <= 100) || _shouldMoveHead)
+ reset_frame = 74;
+ else if (random <= 300)
+ reset_frame = 58;
+ else if (random <= 500)
+ reset_frame = 31;
+ else
+ reset_frame = 0;
+ break;
+
+ case 80:
+ case 90:
+ _twinklesTalking = false;
+ if (_shouldMoveHead) {
+ reset_frame = 90;
+ } else if (_twinklesCurrentFrame == 90) {
+ if ((random <= 400) || _shouldFaceRex)
+ reset_frame = 99;
+ else
+ reset_frame = 79;
+ }
+ break;
+
+ case 98:
+ if (_shouldMoveHead)
+ reset_frame = 91;
+ break;
+
+ case 99:
+ if ((random <= 400) && !_shouldFaceRex)
+ reset_frame = 79;
+ break;
+
+ case 124:
+ case 136:
+ case 174:
+ case 143:
+ case 152:
+ if (_nextHandsPlace == 3)
+ reset_frame = 174;
+ else if (!_shouldFaceRex)
+ reset_frame = 174;
+ else if (_nextHandsPlace == 1)
+ reset_frame = 136;
+ else if (_nextHandsPlace == 2)
+ reset_frame = 152;
+ else if (_shouldTalk)
+ reset_frame = 124;
+ else
+ reset_frame = (random <= 200) ? 131 : 143;
+ break;
+
+ case 131:
+ if (_shouldTalk) {
+ switch (_nextHandsPlace) {
+ case 1:
+ reset_frame = 136;
+ break;
+ case 2:
+ reset_frame = 152;
+ break;
+ default:
+ reset_frame = 124;
+ break;
+ }
+ }
+ break;
+
+ case 138:
+ case 141:
+ if ((_nextHandsPlace == 0) || !_shouldFaceRex)
+ reset_frame = 141;
+ else if (_nextHandsPlace == 2)
+ reset_frame = 152;
+ else if (!_shouldTalk || (_twinklesCurrentFrame == 141))
+ reset_frame = 137;
+ break;
+
+ case 153:
+ case 169:
+ if ((_nextHandsPlace == 0) || !_shouldFaceRex)
+ reset_frame = 169;
+ else if (_nextHandsPlace == 1)
+ reset_frame = 136;
+ else if (_shouldTalk)
+ reset_frame = 153;
+ else
+ reset_frame = 162;
+ break;
+
+ case 162:
+ if (_shouldTalk) {
+ switch (_nextHandsPlace) {
+ case 0:
+ reset_frame = 124;
+ break;
+ case 1:
+ reset_frame = 136;
+ break;
+ default:
+ reset_frame = 153;
+ break;
+ }
+ }
+ break;
+ }
+
+ if (reset_frame >= 0) {
+ if (reset_frame != _scene->_activeAnimation->getCurrentFrame()) {
+ _scene->_activeAnimation->setCurrentFrame(reset_frame);
+ _twinklesCurrentFrame = reset_frame;
+ }
+
+ if ((reset_frame == 90) || (reset_frame == 91) || (reset_frame == 124) || (reset_frame == 153)
+ || ((reset_frame == 137) && _shouldTalk)) {
+ _twinklesTalking = true;
+ } else {
+ _twinklesTalking = false;
+ }
+ }
+ }
+ }
+
+ if ((_twinkleAnimationType == 2) && _scene->_activeAnimation) {
+ if (_twinklesCurrentFrame != _scene->_activeAnimation->getCurrentFrame()) {
+ _twinklesCurrentFrame = _scene->_activeAnimation->getCurrentFrame();
+ int reset_frame = -1;
+
+ if (_twinklesCurrentFrame == 53) {
+ _scene->_kernelMessages.add(Common::Point(151, 61), 0xFDFC, 32, 70, 180, _game.getQuote(230));
+ _shouldTalk = true;
+ } else if ((_twinklesCurrentFrame == 75) && _shouldTalk)
+ reset_frame = 60;
+
+ if ((reset_frame >= 0) && (reset_frame != _scene->_activeAnimation->getCurrentFrame())) {
+ _scene->_activeAnimation->setCurrentFrame(reset_frame);
+ _twinklesCurrentFrame = reset_frame;
+ }
+ }
+
+ if (_game._trigger == 70)
+ _shouldTalk = false;
+ }
+
+ if ((_twinkleAnimationType == 1) && (_scene->_rails.getNext() > 0)) {
+ _game._player.walk(Common::Point(214, 150), FACING_NORTHWEST);
+ _scene->_rails.resetNext();
+ _stopWalking = true;
+ }
+}
+
+void Scene210::preActions() {
+ _stopWalking = false;
+
+ if (_action.isAction(VERB_WALK_DOWN, NOUN_PATH_TO_EAST))
+ _game._player._walkOffScreenSceneId = 211;
+}
+
+void Scene210::actions() {
+ if (_action.isAction(VERB_LOOK, NOUN_BINOCULARS, 0x1C0)) {
+ _vm->_dialogs->show(21017);
+ } else if (_game._screenObjects._inputMode == 1) {
+ handleConversations();
+ } else if (_action.isAction(VERB_TALKTO, NOUN_NATIVE_WOMAN) ||
+ ((_game._player._playerPos == Common::Point(214, 150)) && (_game._player._facing == FACING_NORTHWEST) && (_twinkleAnimationType == 1) && _stopWalking)) {
+ switch (_game._trigger) {
+ case 0: {
+ _game._player._stepEnabled = false;
+ int quote;
+ if (_globals[kTwinklesApproached] == 0)
+ quote = 90;
+ else if (_globals[kTwinklesApproached] == 1)
+ quote = 115;
+ else
+ quote = 171;
+
+ _shouldFaceRex = true;
+ _nextHandsPlace = 0;
+ _scene->_kernelMessages.reset();
+ _scene->_kernelMessages.addQuote(quote, 1, 120);
+ }
+ break;
+
+ case 1:
+ _shouldTalk = true;
+ if (!_twinklesTalking) {
+ _scene->_sequences.addTimer(6, 1);
+ } else {
+ if (_globals[kTwinklesApproached] == 0) {
+ handleTwinklesSpeech(0xAF, -1, 0);
+ handleTwinklesSpeech(0xB0, 0, 0);
+ } else if (_globals[kTwinklesApproached] == 1) {
+ handleTwinklesSpeech(0xB1, 0, 0);
+ } else {
+ int quote = _twinklesTalk2 ? 0xB3 : 0xB2;
+ _twinklesTalk2 = true;
+ handleTwinklesSpeech(quote, 0, 0);
+ }
+ _scene->_sequences.addTimer(60, 3);
+ }
+ break;
+
+ case 3:
+ _game._player._stepEnabled = true;
+ _shouldMoveHead = false;
+ _shouldTalk = false;
+
+ if (_globals[kTwinklesApproached] < 2)
+ _globals[kTwinklesApproached]++;
+
+ _conv1.start();
+ _curDialogNode = 1;
+ break;
+ }
+ } else if (_action.isAction(VERB_GIVE, NOUN_NATIVE_WOMAN) && _game._objects.isInInventory(_game._objects.getIdFromDesc(_action._activeAction._objectNameId))) {
+ switch (_game._trigger) {
+ case 0: {
+ int quote = _vm->getRandomNumber(172, 174);
+ _shouldMoveHead = true;
+ _game._player._stepEnabled = false;
+ handleTwinklesSpeech(quote, 0, 120);
+ _scene->_sequences.addTimer(120, 1);
+ }
+ break;
+
+ case 1:
+ _game._player._stepEnabled = true;
+ _shouldMoveHead = false;
+ break;
+ }
+ } else if (_action.isAction(VERB_WALK_DOWN, NOUN_PATH_TO_NORTH) || _action.isAction(VERB_WALK_TOWARDS, NOUN_HUT_TO_NORTH)) {
+ _scene->_nextSceneId = 205;
+ } else if (_action.isAction(VERB_WALK_THROUGH, NOUN_DOORWAY)) {
+ _scene->_nextSceneId = 215;
+ } else if ((_action.isAction(VERB_PULL, NOUN_CURTAIN) || _action.isAction(VERB_OPEN, NOUN_CURTAIN)) && !_globals[kCurtainOpen]) {
+ switch (_game._trigger) {
+ case 0:
+ _game._player._stepEnabled = false;
+ _scene->_sequences.remove(_globals._sequenceIndexes[1]);
+ _globals._sequenceIndexes[1] = _scene->_sequences.addReverseSpriteCycle(_globals._spriteIndexes[1], false, 12, 1, 0, 0);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 5);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[1], SEQUENCE_TRIGGER_EXPIRE, 0, 1);
+ break;
+
+ case 1:
+ _game._player._stepEnabled = true;
+ _globals[kCurtainOpen] = true;
+ _doorway = _scene->_dynamicHotspots.add(112, 395, -1, Common::Rect(163, 87, 163 + 19, 87 + 36));
+ _scene->_dynamicHotspots.setPosition(_doorway, Common::Point(168, 127), FACING_NORTH);
+ _scene->_dynamicHotspots.setCursor(_doorway, CURSOR_GO_UP);
+ break;
+ }
+ } else if ((_action.isAction(VERB_PULL, NOUN_CURTAIN) || _action.isAction(VERB_CLOSE, NOUN_CURTAIN)) && _globals[kCurtainOpen]) {
+ switch (_game._trigger) {
+ case 0:
+ _scene->_sequences.remove(_globals._sequenceIndexes[1]);
+ _game._player._stepEnabled = false;
+ _game._player._facing = FACING_NORTH;
+ _globals._sequenceIndexes[1] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[1], false, 12, 0, 0, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 5);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[1], SEQUENCE_TRIGGER_EXPIRE, 0, 1);
+ _game._player._stepEnabled = false;
+ break;
+ case 1:
+ _globals._sequenceIndexes[1] = _scene->_sequences.startCycle(_globals._spriteIndexes[1], false, 5);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 5);
+ _scene->_sequences.addTimer(48, 2);
+ break;
+ case 2:
+ _scene->_dynamicHotspots.remove(_doorway);
+ _game._player._stepEnabled = true;
+ _globals[kCurtainOpen] = false;
+ break;
+ }
+ } else if (_action.isAction(VERB_LOOK, NOUN_HUT)) {
+ if (_globals[kTwinklesStatus] == TWINKLES_GONE) {
+ if (_game._storyMode == STORYMODE_NAUGHTY)
+ _vm->_dialogs->show(21003);
+ else
+ _vm->_dialogs->show(21002);
+ } else {
+ _vm->_dialogs->show(21001);
+ }
+ } else if (_action.isAction(VERB_LOOK, NOUN_BRA)) {
+ _vm->_dialogs->show(21004);
+ } else if (_action.isAction(VERB_LOOK, NOUN_HOTPANTS)) {
+ _vm->_dialogs->show(21005);
+ } else if (_action.isAction(VERB_TAKE, NOUN_HOTPANTS) || _action.isAction(VERB_TAKE, NOUN_BRA)) {
+ _vm->_dialogs->show(21006);
+ } else if (_action.isAction(VERB_LOOK, NOUN_STREAM)) {
+ _vm->_dialogs->show(21007);
+ } else if (_action.isAction(VERB_LOOK, NOUN_BUSHY_FERN)) {
+ _vm->_dialogs->show(21008);
+ } else if (_action.isAction(VERB_LOOK, NOUN_VILLAGE_PATH)) {
+ _vm->_dialogs->show(21009);
+ } else if (_action.isAction(VERB_LOOK, NOUN_NATIVE_WOMAN)) {
+ _vm->_dialogs->show(21010);
+ } else if (_action.isAction(VERB_SHOOT, NOUN_NATIVE_WOMAN) || _action.isAction(VERB_HOSE_DOWN, NOUN_NATIVE_WOMAN)) {
+ _vm->_dialogs->show(21011);
+ } else if (_action.isAction(VERB_LOOK, NOUN_PATH_TO_NORTH)) {
+ _vm->_dialogs->show(21012);
+ } else if (_action.isAction(VERB_LOOK, NOUN_CURTAIN)) {
+ _vm->_dialogs->show(21013);
+ } else if (_action.isAction(VERB_LOOK, NOUN_CLOTHESLINE)) {
+ _vm->_dialogs->show(21014);
+ } else if (_action.isAction(VERB_TAKE, NOUN_CLOTHESLINE)) {
+ _vm->_dialogs->show(21015);
+ } else if (_action.isAction(VERB_LOOK, NOUN_HUT_TO_NORTH)) {
+ _vm->_dialogs->show(21016);
+ } else {
+ // Not handled
+ return;
+ }
+
+ _action._inProgress = false;
+}
+
+/*------------------------------------------------------------------------*/
+
+Scene211::Scene211(MADSEngine *vm) : Scene2xx(vm) {
+ _ambushFl = false;
+ _wakeFl = false;
+ _monkeyFrame = 0;
+ _scrollY = 0;
+ _monkeyTime = 0;
+}
+
+void Scene211::synchronize(Common::Serializer &s) {
+ Scene2xx::synchronize(s);
+
+ s.syncAsByte(_ambushFl);
+ s.syncAsByte(_wakeFl);
+
+ s.syncAsSint32LE(_monkeyFrame);
+ s.syncAsSint32LE(_scrollY);
+ s.syncAsUint32LE(_monkeyTime);
+}
+
+void Scene211::setup() {
+ setPlayerSpritesPrefix();
+ setAAName();
+
+ _scene->addActiveVocab(NOUN_SLITHERING_SNAKE);
+}
+
+void Scene211::enter() {
+ _globals._spriteIndexes[1] = _scene->_sprites.addSprites("*SC002Z2");
+ _wakeFl = false;
+
+ if (_scene->_priorSceneId == 210)
+ _game._player._playerPos = Common::Point(25, 148);
+ else if (_scene->_priorSceneId == 205) {
+ _game._player._playerPos = Common::Point(49, 133);
+ _game._player._facing = FACING_WEST;
+ _wakeFl = true;
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _scene->loadAnimation(formAnimName('A', -1), 100);
+ _scene->_activeAnimation->setCurrentFrame(169);
+ } else if (_scene->_priorSceneId != -2) {
+ _game._player._playerPos = Common::Point(310, 31);
+ _game._player._facing = FACING_SOUTHWEST;
+ }
+
+ if (_vm->getRandomNumber(1, 8) == 1) {
+ _globals._sequenceIndexes[2] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[1], false, 6, 0, 0, 0);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[2], Common::Point(202, 126));
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 8);
+ _scene->_sequences.setMotion(_globals._sequenceIndexes[2], SEQUENCE_TRIGGER_SPRITE, -200, 0);
+ _scene->_dynamicHotspots.add(324, 13, _globals._sequenceIndexes[2], Common::Rect(1, 1, 1 + 41, 1 + 10));
+ }
+
+ if (_scene->_roomChanged)
+ _game._objects.addToInventory(OBJ_BINOCULARS);
+
+ _vm->_palette->setEntry(252, 63, 44, 30);
+ _vm->_palette->setEntry(253, 63, 20, 22);
+ _game.loadQuoteSet(0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 1, 0);
+
+ if (_globals[kMonkeyStatus] == MONKEY_AMBUSH_READY)
+ _scene->_kernelMessages.initRandomMessages(2,
+ Common::Rect(0, 0, 54, 30), 13, 2, 0xFDFC, 60,
+ 151, 152, 153, 154, 0);
+
+ _monkeyTime = _vm->_game->_scene._frameStartTime;
+ _scrollY = 30;
+
+ _ambushFl = false;
+ _monkeyFrame = 0;
+
+ sceneEntrySound();
+}
+
+void Scene211::step() {
+ if (_globals[kMonkeyStatus] == MONKEY_AMBUSH_READY) {
+ _scene->_kernelMessages.randomServer();
+
+ if (!_ambushFl && !_wakeFl && (_vm->_game->_scene._frameStartTime >= _monkeyTime)) {
+ int chanceMinor = _scene->_kernelMessages.checkRandom() * 4 + 1;
+ if (_scene->_kernelMessages.generateRandom(80, chanceMinor))
+ _vm->_sound->command(18);
+
+ _monkeyTime = _vm->_game->_scene._frameStartTime + 2;
+ }
+
+ if ((_game._player._playerPos == Common::Point(52, 132)) && (_game._player._facing == FACING_WEST) && !_game._player._moving &&
+ (_game._trigger || !_ambushFl)) {
+ switch (_game._trigger) {
+ case 0:
+ if (_game._objects.isInInventory(OBJ_BINOCULARS)) {
+ _ambushFl = true;
+ _monkeyFrame = 0;
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _scene->_kernelMessages.reset();
+ _scene->loadAnimation(formAnimName('A', -1), 90);
+ _vm->_sound->command(19);
+ int count = (int)_game._objects._inventoryList.size();
+ for (int idx = 0; idx < count; idx++) {
+ if ((_game._objects._inventoryList[idx] == OBJ_BINOCULARS) && (_scene->_userInterface._selectedInvIndex != idx))
+ _scene->_userInterface.selectObject(idx);
+ }
+ }
+ break;
+
+ case 90:
+ _vm->_sound->command(10);
+ _game._player._stepEnabled = true;
+ _game._player._visible = true;
+ _game._player._playerPos = Common::Point(49, 133);
+ _ambushFl = false;
+ _globals[kMonkeyStatus] = MONKEY_HAS_BINOCULARS;
+ break;
+ }
+ }
+ }
+
+ if (_ambushFl && (_scene->_activeAnimation->getCurrentFrame() > _monkeyFrame)) {
+ _monkeyFrame = _scene->_activeAnimation->getCurrentFrame();
+ switch (_monkeyFrame) {
+ case 2: {
+ int msgIndex = _scene->_kernelMessages.add(Common::Point(12, 4), 0xFDFC, 0, 0, 60, _game.getQuote(157));
+ _scene->_kernelMessages.setQuoted(msgIndex, 2, true);
+ }
+ break;
+
+ case 12: {
+ int msgIndex = _scene->_kernelMessages.add(Common::Point(35, 20), 0xFDFC, 0, 0, 60, _game.getQuote(155));
+ _scene->_kernelMessages.setQuoted(msgIndex, 4, true);
+ }
+ break;
+
+ case 42: {
+ int msgIndex = _scene->_kernelMessages.add(Common::Point(60, 45), 0xFDFC, 0, 0, 60, _game.getQuote(156));
+ _scene->_kernelMessages.setQuoted(msgIndex, 6, true);
+ }
+ break;
+
+ case 73:
+ _scene->_kernelMessages.add(Common::Point(102, 95), 0xFDFC, 32, 0, 75, _game.getQuote(157));
+ break;
+
+ case 90: {
+ int msgIndex = _scene->_kernelMessages.add(Common::Point(102, 95), 0xFDFC, 32, 0, 60, _game.getQuote(158));
+ _scene->_kernelMessages.setQuoted(msgIndex, 6, true);
+ }
+ break;
+
+ case 97:
+ _scene->_userInterface.selectObject(-1);
+ _game._objects.removeFromInventory(OBJ_BINOCULARS, 1);
+ break;
+
+ case 177: {
+ int msgIndex = _scene->_kernelMessages.add(Common::Point(63, _scrollY), 0x1110, 0, 0, 180, _game.getQuote(161));
+ _scene->_kernelMessages.setQuoted(msgIndex, 4, true);
+ _scrollY += 14;
+ }
+ break;
+
+ case 181: {
+ int msgIndex = _scene->_kernelMessages.add(Common::Point(63, _scrollY), 0x1110, 0, 0, 180, _game.getQuote(162));
+ _scene->_kernelMessages.setQuoted(msgIndex, 4, true);
+ _scrollY += 14;
+ }
+ break;
+
+ case 188: {
+ int msgIndex = _scene->_kernelMessages.add(Common::Point(63, _scrollY), 0x1110, 0, 0, 180, _game.getQuote(163));
+ _scene->_kernelMessages.setQuoted(msgIndex, 4, true);
+ _scrollY += 14;
+ }
+ break;
+
+ case 200: {
+ int msgIndex = _scene->_kernelMessages.add(Common::Point(63, _scrollY), 0x1110, 0, 0, 180, _game.getQuote(164));
+ _scene->_kernelMessages.setQuoted(msgIndex, 4, true);
+ _scrollY += 14;
+ }
+ break;
+ }
+ }
+
+ if (_wakeFl) {
+ if (_game._trigger == 100) {
+ _game._player._visible = true;
+ _game._player._stepEnabled = true;
+ _wakeFl = false;
+ }
+
+ if (_scene->_activeAnimation->getCurrentFrame() > _monkeyFrame) {
+ _monkeyFrame = _scene->_activeAnimation->getCurrentFrame();
+ switch (_scene->_activeAnimation->getCurrentFrame()) {
+ case 177: {
+ int msgIndex = _scene->_kernelMessages.add(Common::Point(63, _scrollY), 0x1110, 0, 0, 180, _game.getQuote(165));
+ _scene->_kernelMessages.setQuoted(msgIndex, 4, true);
+ _scrollY += 14;
+ }
+ break;
+
+ case 181: {
+ int msgIndex = _scene->_kernelMessages.add(Common::Point(63, _scrollY), 0x1110, 0, 0, 180, _game.getQuote(166));
+ _scene->_kernelMessages.setQuoted(msgIndex, 4, true);
+ _scrollY += 14;
+ }
+ break;
+
+ case 188: {
+ int msgIndex = _scene->_kernelMessages.add(Common::Point(63, _scrollY), 0x1110, 0, 0, 180, _game.getQuote(167));
+ _scene->_kernelMessages.setQuoted(msgIndex, 4, true);
+ _scrollY += 14;
+ }
+ break;
+
+ case 200: {
+ int msgIndex = _scene->_kernelMessages.add(Common::Point(63, _scrollY), 0x1110, 0, 0, 180, _game.getQuote(168));
+ _scene->_kernelMessages.setQuoted(msgIndex, 4, true);
+ _scrollY += 14;
+ }
+ break;
+ }
+ }
+ }
+}
+
+void Scene211::preActions() {
+ if (_action.isAction(VERB_WALK_DOWN, NOUN_JUNGLE_PATH) && _game._objects.isInInventory(OBJ_BINOCULARS) && (_globals[kMonkeyStatus] == MONKEY_AMBUSH_READY)
+ && (_scene->_customDest.x <= 52) && (_scene->_customDest.y >= 132))
+ _game._player.walk(Common::Point(52, 132), FACING_WEST);
+
+ if (_action.isAction(VERB_WALK_DOWN, NOUN_PATH_TO_WEST)) {
+ if (_game._objects.isInInventory(OBJ_BINOCULARS) && (_globals[kMonkeyStatus] == MONKEY_AMBUSH_READY))
+ _game._player.walk(Common::Point(52, 132), FACING_WEST);
+ else
+ _game._player._walkOffScreenSceneId = 210;
+ }
+
+ if (_action.isAction(VERB_WALK_DOWN, NOUN_PATH_TO_NORTHEAST))
+ _game._player._walkOffScreenSceneId = 207;
+}
+
+void Scene211::actions() {
+ if (_action._lookFlag && (_globals[kMonkeyStatus] == MONKEY_AMBUSH_READY))
+ _vm->_dialogs->show(21111);
+ else if (_action.isAction(VERB_LOOK, NOUN_BINOCULARS, 0x100))
+ _vm->_dialogs->show(21116);
+ else if (_action.isAction(VERB_LOOK, NOUN_BUSHY_FERN))
+ _vm->_dialogs->show(21101);
+ else if (_action.isAction(VERB_LOOK, NOUN_JUNGLE_PATH))
+ _vm->_dialogs->show(21102);
+ else if (_action.isAction(VERB_LOOK, NOUN_PALM_TREE)) {
+ if (_globals[kMonkeyStatus] == MONKEY_AMBUSH_READY) {
+ if (_game._storyMode == STORYMODE_NAUGHTY)
+ _vm->_dialogs->show(21103);
+ else
+ _vm->_dialogs->show(21104);
+ } else {
+ _vm->_dialogs->show(21105);
+ }
+ } else if (_action.isAction(VERB_LOOK, NOUN_THICK_UNDERGROWTH)) {
+ if (_game._storyMode == STORYMODE_NAUGHTY)
+ _vm->_dialogs->show(21106);
+ else
+ _vm->_dialogs->show(21107);
+ } else if (_action.isAction(VERB_LOOK, NOUN_JUNGLE))
+ _vm->_dialogs->show(21108);
+ else if (_action.isAction(VERB_LOOK, NOUN_PATH_TO_NORTHEAST))
+ _vm->_dialogs->show(21109);
+ else if (_action.isAction(VERB_LOOK, NOUN_PATH_TO_WEST))
+ _vm->_dialogs->show(21110);
+ else if (_action.isAction(VERB_LOOK, NOUN_SLITHERING_SNAKE))
+ _vm->_dialogs->show(21113);
+ else if (_action.isAction(VERB_TAKE, NOUN_SLITHERING_SNAKE))
+ _vm->_dialogs->show(21114);
+ else if (_action.isAction(VERB_LOOK, NOUN_ROCKS))
+ _vm->_dialogs->show(21115);
+ else
+ return;
+
+ _action._inProgress = false;
+}
+
+/*------------------------------------------------------------------------*/
+
+void Scene212::setup() {
+ setPlayerSpritesPrefix();
+ setAAName();
+
+ _scene->addActiveVocab(NOUN_BOUNCING_REPTILE);
+}
+
+void Scene212::enter() {
+ // CHECKME: Some useless variables have been remove here
+
+ if (_scene->_priorSceneId == 208) {
+ _game._player._playerPos = Common::Point(195, 85);
+ _game._player._facing = FACING_SOUTH;
+ } else if (_scene->_priorSceneId != -2) {
+ _game._player._playerPos = Common::Point(67, 117);
+ _game._player._facing = FACING_NORTHEAST;
+ }
+
+ sceneEntrySound();
+}
+
+void Scene212::step() {
+// CHECKME: Could we move the dino?
+}
+
+void Scene212::preActions() {
+ if (_action.isAction(VERB_WALK_THROUGH, NOUN_CAVE_ENTRANCE))
+ _game._player._walkOffScreenSceneId = 111;
+}
+
+void Scene212::actions() {
+ if (_action._lookFlag)
+ _vm->_dialogs->show(21209);
+ else if (_action.isAction(VERB_WALK_TOWARDS) && (_action.isObject(NOUN_FIELD_TO_NORTH) || _action.isObject(NOUN_MOUNTAINS)))
+ _scene->_nextSceneId = 208;
+ else if (_action.isAction(VERB_WALK_TOWARDS, NOUN_CAVE))
+ _scene->_nextSceneId = 111;
+ else if (_action.isAction(VERB_LOOK, NOUN_GRASS))
+ _vm->_dialogs->show(21201);
+ else if (_action.isAction(VERB_LOOK, NOUN_ROCKS))
+ _vm->_dialogs->show(21202);
+ else if (_action.isAction(VERB_LOOK, NOUN_CAVE_ENTRANCE))
+ _vm->_dialogs->show(21203);
+ else if (_action.isAction(VERB_LOOK, NOUN_SKY))
+ _vm->_dialogs->show(21204);
+ else if (_action.isAction(VERB_LOOK, NOUN_FIELD_TO_NORTH))
+ _vm->_dialogs->show(21205);
+ else if (_action.isAction(VERB_LOOK, NOUN_TREES))
+ _vm->_dialogs->show(21206);
+ else if (_action.isAction(VERB_LOOK, NOUN_PLANTS))
+ _vm->_dialogs->show(21207);
+ else if (_action.isAction(VERB_LOOK, NOUN_MOUNTAINS))
+ _vm->_dialogs->show(21208);
+ else
+ return;
+
+ _action._inProgress = false;
+}
+
+/*------------------------------------------------------------------------*/
+
+void Scene213::setup() {
+ _game._player._spritesPrefix = "";
+
+ // The original is calling Scene2xx::setAAName()
+ _game._aaName = Resources::formatAAName(2);
+}
+
+void Scene213::enter() {
+ if (_globals[kMeteorologistWatch] != METEOROLOGIST_NORMAL)
+ _handSpriteId = _scene->_sprites.addSprites("*METHAND");
+ else if (_globals[kSexOfRex] == REX_MALE)
+ _handSpriteId = _scene->_sprites.addSprites("*REXHAND");
+ else
+ _handSpriteId = _scene->_sprites.addSprites("*ROXHAND");
+
+ teleporterEnter();
+
+ // The original is calling Scene2xx::sceneEntrySound()
+ if (_vm->_musicFlag) {
+ if (_globals[kMeteorologistWatch] == METEOROLOGIST_NORMAL)
+ _vm->_sound->command(1);
+ else
+ _vm->_sound->command(9);
+ } else
+ _vm->_sound->command(2);
+}
+
+void Scene213::step() {
+ teleporterStep();
+}
+
+void Scene213::actions() {
+ if (teleporterActions()) {
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_LOOK, NOUN_CONTROL_PANEL))
+ _vm->_dialogs->show(21301);
+ else if (_action.isAction(VERB_LOOK, NOUN_KEYPAD) || _action.isAction (VERB_INSPECT, NOUN_KEYPAD))
+ _vm->_dialogs->show(21302);
+ else if (_action.isAction(VERB_LOOK, NOUN_DISPLAY))
+ _vm->_dialogs->show(21303);
+ else if (_action.isAction(VERB_LOOK, NOUN_VIEWPORT) || _action.isAction(VERB_PEER_THROUGH, NOUN_VIEWPORT))
+ _vm->_dialogs->show(21304);
+ else if (_action.isAction(VERB_LOOK, NOUN_DEVICE))
+ _vm->_dialogs->show(21305);
+ else if (_action.isAction(VERB_LOOK, NOUN_0_KEY) || _action.isAction(VERB_LOOK, NOUN_1_KEY)
+ || _action.isAction(VERB_LOOK, NOUN_2_KEY) || _action.isAction(VERB_LOOK, NOUN_3_KEY)
+ || _action.isAction(VERB_LOOK, NOUN_4_KEY) || _action.isAction(VERB_LOOK, NOUN_5_KEY)
+ || _action.isAction(VERB_LOOK, NOUN_6_KEY) || _action.isAction(VERB_LOOK, NOUN_7_KEY)
+ || _action.isAction(VERB_LOOK, NOUN_8_KEY) || _action.isAction(VERB_LOOK, NOUN_9_KEY)
+ || _action.isAction(VERB_LOOK, NOUN_SMILE_KEY) || _action.isAction(VERB_LOOK, NOUN_FROWN_KEY)
+ || _action.isAction(VERB_LOOK, NOUN_ENTER_KEY))
+ _vm->_dialogs->show(21306);
+ else
+ return;
+
+ _action._inProgress = false;
+}
+
+/*------------------------------------------------------------------------*/
+
+Scene214::Scene214(MADSEngine *vm) : Scene2xx(vm) {
+ _devilTime = 0;
+ _devilRunningFl = false;
+}
+
+void Scene214::synchronize(Common::Serializer &s) {
+ Scene2xx::synchronize(s);
+
+ s.syncAsUint32LE(_devilTime);
+ s.syncAsByte(_devilRunningFl);
+}
+
+void Scene214::setup() {
+ setPlayerSpritesPrefix();
+ setAAName();
+ _scene->addActiveVocab(NOUN_CAPTIVE_CREATURE);
+ _scene->addActiveVocab(VERB_WALKTO);
+}
+
+void Scene214::enter() {
+ _globals._spriteIndexes[1] = _scene->_sprites.addSprites(formAnimName('e', 0));
+ _globals._spriteIndexes[2] = _scene->_sprites.addSprites(formAnimName('e', 1));
+ _globals._spriteIndexes[3] = _scene->_sprites.addSprites(formAnimName('t', -1));
+ _globals._spriteIndexes[4] = _scene->_sprites.addSprites("*RXMRD_7");
+
+ _devilTime = _game._player._priorTimer;
+ _devilRunningFl = false;
+
+ if (_game._objects.isInRoom(OBJ_POISON_DARTS)) {
+ _globals._sequenceIndexes[1] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[1], false, 6, 0, 0, 0);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[1], Common::Point(103, 86));
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 11);
+ } else {
+ _scene->_hotspots.activate(NOUN_POISON_DARTS, false);
+ }
+
+ if (_game._objects.isInRoom(OBJ_BLOWGUN)) {
+ _globals._sequenceIndexes[2] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[2], false, 6, 0, 0, 0);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[2], Common::Point(90, 87));
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 13);
+ } else {
+ _scene->_hotspots.activate(NOUN_BLOWGUN, false);
+ }
+
+ if (_scene->_priorSceneId != -2)
+ _game._player._playerPos = Common::Point(191, 152);
+
+ sceneEntrySound();
+}
+
+void Scene214::step() {
+ if ((_game._player._priorTimer - _devilTime > 800) && !_devilRunningFl) {
+ _devilRunningFl = true;
+ _globals._sequenceIndexes[3] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[3], false, 9, 1, 6, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[3], 1, 4);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 2);
+ _scene->_dynamicHotspots.add(451, 13, _globals._sequenceIndexes[3], Common::Rect(0, 0, 0, 0));
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[3], SEQUENCE_TRIGGER_EXPIRE, 0, 71);
+ }
+
+ if (_devilRunningFl) {
+ switch (_game._trigger) {
+ case 71: {
+ int oldIdx = _globals._sequenceIndexes[3];
+ _globals._sequenceIndexes[3] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[3], false, 9, 5, 0, 0);
+ _scene->_sequences.updateTimeout(oldIdx, _globals._sequenceIndexes[3]);
+ _scene->_dynamicHotspots.add(451, VERB_WALKTO, _globals._sequenceIndexes[3], Common::Rect(0, 0, 0, 0));
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[3], 5, 8);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 2);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[3], SEQUENCE_TRIGGER_EXPIRE, 0, 72);
+ }
+ break;
+
+ case 72: {
+ int oldIdx = _globals._sequenceIndexes[3];
+ _globals._sequenceIndexes[3] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[3], false, 9, 1, 0, 0);
+ _scene->_sequences.updateTimeout(oldIdx, _globals._sequenceIndexes[3]);
+ _scene->_dynamicHotspots.add(451, VERB_WALKTO, _globals._sequenceIndexes[3], Common::Rect(0, 0, 0, 0));
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[3], 9, -2);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 2);
+ _devilTime = _game._player._priorTimer;
+ _devilRunningFl = false;
+ }
+ break;
+ }
+ }
+}
+
+void Scene214::actions() {
+ if (_action._lookFlag)
+ _vm->_dialogs->show(21427);
+ else if (_action.isAction(0x18A, 0xAA))
+ _scene->_nextSceneId = 207;
+ else if (_action.isAction(VERB_TAKE, NOUN_POISON_DARTS) && (_game._trigger || _game._objects.isInRoom(OBJ_POISON_DARTS))) {
+ switch (_game._trigger) {
+ case 0:
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._sequenceIndexes[4] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[4], true, 6, 1, 0, 0);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[4]);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[4], SEQUENCE_TRIGGER_EXPIRE, 0, 1);
+ break;
+
+ case 1:
+ _globals._sequenceIndexes[4] = _scene->_sequences.addReverseSpriteCycle(_globals._spriteIndexes[4], true, 6, 1, 0, 0);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[4]);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[4], SEQUENCE_TRIGGER_EXPIRE, 0, 2);
+ _scene->_sequences.remove(_globals._sequenceIndexes[1]);
+ _game._objects.addToInventory(OBJ_POISON_DARTS);
+ _scene->_hotspots.activate(NOUN_POISON_DARTS, false);
+ break;
+
+ case 2:
+ _game._player._visible = true;
+ _scene->_sequences.addTimer(48, 3);
+ break;
+
+ case 3:
+ _game._player._stepEnabled = true;
+ _vm->_dialogs->showItem(OBJ_POISON_DARTS, 0x53A5);
+ break;
+ }
+ } else if (_action.isAction(VERB_TAKE, NOUN_BLOWGUN) && (_game._trigger || _game._objects.isInRoom(OBJ_BLOWGUN))) {
+ switch (_game._trigger) {
+ case 0:
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._sequenceIndexes[4] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[4], false, 6, 1, 0, 0);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[4]);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[4], SEQUENCE_TRIGGER_EXPIRE, 0, 1);
+ break;
+
+ case 1:
+ _globals._sequenceIndexes[4] = _scene->_sequences.addReverseSpriteCycle(_globals._spriteIndexes[4], false, 6, 1, 0, 0);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[4]);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[4], SEQUENCE_TRIGGER_EXPIRE, 0, 2);
+ _scene->_sequences.remove(_globals._sequenceIndexes[2]);
+ _game._objects.addToInventory(OBJ_BLOWGUN);
+ _scene->_hotspots.activate(NOUN_BLOWGUN, false);
+ break;
+
+ case 2:
+ _game._player._visible = true;
+ _scene->_sequences.addTimer(48, 3);
+ break;
+
+ case 3:
+ _game._player._stepEnabled = true;
+ _vm->_dialogs->showItem(OBJ_BLOWGUN, 0x329);
+ break;
+ }
+ } else if (_action.isAction(VERB_LOOK, NOUN_WINDOW))
+ _vm->_dialogs->show(21401);
+ else if (_action.isAction(VERB_LOOK, NOUN_EXPERIMENT_CAGE))
+ _vm->_dialogs->show(21402);
+ else if (_action.isAction(VERB_LOOK, NOUN_CAPTIVE_CREATURE))
+ _vm->_dialogs->show(21403);
+ else if (_action.isAction(VERB_LOOK, NOUN_BEAR_RUG))
+ _vm->_dialogs->show(21404);
+ else if (_action.isAction(VERB_LOOK, NOUN_TROPHY))
+ _vm->_dialogs->show(21405);
+ else if (_action.isAction(VERB_LOOK, NOUN_LARGE_BOWL)) {
+ if (_game._storyMode == STORYMODE_NAUGHTY) {
+ _vm->_dialogs->show(21406);
+ } else {
+ _vm->_dialogs->show(21407);
+ }
+ } else if (_action.isAction(VERB_LOOK, NOUN_SPECIMEN_JARS))
+ _vm->_dialogs->show(21408);
+ else if (_action.isAction(VERB_TAKE, NOUN_LARGE_BOWL) || _action.isAction(VERB_TAKE, NOUN_SPECIMEN_JARS))
+ _vm->_dialogs->show(21409);
+ else if (_action.isAction(VERB_LOOK, NOUN_SHRUNKEN_HEADS))
+ _vm->_dialogs->show(21410);
+ else if (_action.isAction(VERB_TAKE, NOUN_SHRUNKEN_HEADS) || _action.isAction(VERB_TAKE, NOUN_LARGE_HEADS))
+ _vm->_dialogs->show(21411);
+ else if (_action.isAction(VERB_LOOK, NOUN_LARGE_HEADS))
+ _vm->_dialogs->show(21428);
+ else if (_action.isAction(VERB_LOOK, NOUN_POISON_DARTS) && (_action._savedFields._mainObjectSource == 4))
+ _vm->_dialogs->show(21412);
+ else if (_action.isAction(VERB_OPEN, NOUN_EXPERIMENT_CAGE))
+ _vm->_dialogs->show(21414);
+ else if (_action.isAction(VERB_TALKTO, NOUN_CAPTIVE_CREATURE))
+ _vm->_dialogs->show(21415);
+ else if (_action.isAction(VERB_GIVE, NOUN_TWINKIFRUIT, 0x1C3))
+ _vm->_dialogs->show(21416);
+ else if (_action.isAction(VERB_SHOOT, 0x29, 0x1C3) || _action.isAction(VERB_HOSE_DOWN, 0x29, 0x1C3))
+ _vm->_dialogs->show(21417);
+ else if (_action.isAction(VERB_LOOK, NOUN_BIG_HEADS))
+ _vm->_dialogs->show(21418);
+ else if (_action.isAction(VERB_TAKE, NOUN_BIG_HEADS))
+ _vm->_dialogs->show(21419);
+ else if (_action.isAction(VERB_TAKE, NOUN_BEAR_RUG))
+ _vm->_dialogs->show(21420);
+ else if (_action.isAction(VERB_LOOK, NOUN_FLOOR_OF_HUT))
+ _vm->_dialogs->show(21421);
+ else if (_action.isAction(VERB_LOOK, NOUN_BLOWGUN))
+ _vm->_dialogs->show(21422);
+ else if (_action.isAction(VERB_LOOK, NOUN_TABLE)) {
+ if (_game._objects.isInRoom(OBJ_POISON_DARTS) && _game._objects.isInRoom(OBJ_BLOWGUN)) {
+ _vm->_dialogs->show(21423);
+ } else if (_game._objects.isInRoom(OBJ_POISON_DARTS) && !_game._objects.isInRoom(OBJ_BLOWGUN)) {
+ _vm->_dialogs->show(21424);
+ } else if (!_game._objects.isInRoom(OBJ_POISON_DARTS) && _game._objects.isInRoom(OBJ_BLOWGUN)) {
+ _vm->_dialogs->show(21425);
+ } else {
+ _vm->_dialogs->show(21426);
+ }
+ } else
+ return;
+
+ _action._inProgress = false;
+}
+
+/*------------------------------------------------------------------------*/
+
+void Scene215::setup() {
+ setPlayerSpritesPrefix();
+ setAAName();
+}
+
+void Scene215::enter() {
+ _globals._spriteIndexes[1] = _scene->_sprites.addSprites(formAnimName('e', 0));
+ _globals._spriteIndexes[3] = _scene->_sprites.addSprites(formAnimName('a', 0));
+
+ _globals._sequenceIndexes[1] = _scene->_sequences.addSpriteCycle (_globals._spriteIndexes[1], false, 7, 0, 0, 0);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[1], Common::Point(235, 83));
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 15);
+
+ if (_globals[kSexOfRex] == REX_MALE)
+ _globals._spriteIndexes[2] = _scene->_sprites.addSprites("*RXMRC_9");
+ else
+ _globals._spriteIndexes[2] = _scene->_sprites.addSprites("*ROXRC_9");
+
+ if (_scene->_priorSceneId == 216) {
+ _game._player._playerPos = Common::Point(140, 119);
+ _game._player._facing = FACING_SOUTHWEST;
+ _game._player._visible = false;
+ _game._player._stepEnabled = false;
+ _globals._sequenceIndexes[3] = _scene->_sequences.startCycle(_globals._spriteIndexes[3], false, 1);
+ _scene->_sequences.addTimer(120, 70);
+ } else if (_scene->_priorSceneId != -2) {
+ _game._player._playerPos = Common::Point(204, 152);
+ _game._player._facing = FACING_NORTH;
+ }
+
+ _game.loadQuoteSet(0xA9, 0xAA, 0);
+ sceneEntrySound();
+}
+
+void Scene215::step() {
+ if (_game._trigger == 70) {
+ _scene->_sequences.remove (_globals._sequenceIndexes[3]);
+ _globals._sequenceIndexes[3] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[3], false, 6, 1, 0, 0);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[3], SEQUENCE_TRIGGER_EXPIRE, 0, 71);
+ }
+
+ if (_game._trigger == 71) {
+ _scene->_sequences.updateTimeout(-1, _globals._sequenceIndexes[3]);
+ _game._player._visible = true;
+ _game._player._stepEnabled = true;
+ }
+}
+
+void Scene215::actions() {
+ if (_action._lookFlag)
+ _vm->_dialogs->show(21509);
+ else if (_action.isAction(VERB_TAKE, NOUN_TWINKIFRUIT)) {
+ if (!_game._objects.isInInventory(OBJ_TWINKIFRUIT) || _game._trigger) {
+ switch (_game._trigger) {
+ case 0:
+ if (_globals[kSexOfRex] == REX_MALE) {
+ _game._player._visible = false;
+ _game._player._stepEnabled = false;
+ _globals._sequenceIndexes[2] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[2], false, 6, 2, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[2], 1, 4);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[2]);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[2], SEQUENCE_TRIGGER_LOOP, 0, 1);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[2], SEQUENCE_TRIGGER_EXPIRE, 0, 2);
+ } else {
+ _game._objects.addToInventory(OBJ_TWINKIFRUIT);
+ _vm->_dialogs->showItem(OBJ_TWINKIFRUIT, 0x5404);
+ }
+ break;
+
+ case 1:
+ if (!_game._objects.isInInventory(OBJ_TWINKIFRUIT)) {
+ _game._objects.addToInventory(OBJ_TWINKIFRUIT);
+ _vm->_dialogs->showItem(OBJ_TWINKIFRUIT, 0x5404);
+ }
+ break;
+
+ case 2:
+ _game._player._visible = true;
+ _game._player._stepEnabled = true;
+ _scene->_sequences.updateTimeout(-1, _globals._sequenceIndexes[2]);
+ break;
+ }
+ } else {
+ int idx = _vm->getRandomNumber(169, 170);
+ _scene->_kernelMessages.reset();
+ _scene->_kernelMessages.add(Common::Point(0, 0), 0x1110, 34, 0, 120, _game.getQuote(idx));
+ }
+ } else if (_action.isAction(0x18A, 0xAA))
+ _scene->_nextSceneId = 210;
+ else if (_action.isAction(VERB_LOOK, NOUN_BEAR_RUG))
+ _vm->_dialogs->show(21501);
+ else if (_action.isAction(VERB_LOOK, NOUN_BED))
+ _vm->_dialogs->show(21502);
+ else if (_action.isAction(VERB_LOOK, NOUN_WELCOME_MAT))
+ _vm->_dialogs->show(21503);
+ else if (_action.isAction(VERB_LOOK, NOUN_LOVE_ALTAR))
+ _vm->_dialogs->show(21504);
+ else if (_action.isAction(VERB_LOOK, NOUN_WINDOW))
+ _vm->_dialogs->show(21505);
+ else if (_action.isAction(VERB_LOOK, NOUN_PICTURE))
+ _vm->_dialogs->show(21506);
+ else if (_action.isAction(VERB_LOOK, NOUN_TWINKIFRUIT) && (_action._savedFields._mainObjectSource == 4))
+ _vm->_dialogs->show(21507);
+ else if (_action.isAction(VERB_TAKE, NOUN_BEAR_RUG))
+ _vm->_dialogs->show(21510);
+ else if (_action.isAction(VERB_TAKE, NOUN_LOVE_ALTAR))
+ _vm->_dialogs->show(21511);
+ else if (_action.isAction(VERB_LOOK, NOUN_BAG_OF_TWINKIFRUITS))
+ _vm->_dialogs->show(21512);
+ else if (_action.isAction(VERB_TAKE, NOUN_BAG_OF_TWINKIFRUITS))
+ _vm->_dialogs->show(21513);
+ else if (_action.isAction(VERB_TAKE, NOUN_WELCOME_MAT))
+ _vm->_dialogs->show(21514);
+ else
+ return;
+
+ _action._inProgress = false;
+}
+
+/*------------------------------------------------------------------------*/
+
+void Scene216::setup() {
+ setPlayerSpritesPrefix();
+ setAAName();
+}
+
+void Scene216::enter() {
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+
+ _scene->_userInterface.emptyConversationList();
+ _scene->_userInterface.setup(kInputConversation);
+ _scene->loadAnimation(formAnimName('A', -1), 60);
+
+ sceneEntrySound();
+}
+
+void Scene216::step() {
+ if (_game._trigger == 60)
+ _scene->_nextSceneId = 215;
+}
+
+/*------------------------------------------------------------------------*/
+
+} // End of namespace Nebular
+} // End of namespace MADS
diff --git a/engines/mads/nebular/nebular_scenes2.h b/engines/mads/nebular/nebular_scenes2.h
new file mode 100644
index 0000000000..e70444a256
--- /dev/null
+++ b/engines/mads/nebular/nebular_scenes2.h
@@ -0,0 +1,325 @@
+/* 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.
+ *
+ */
+
+#ifndef MADS_NEBULAR_SCENES2_H
+#define MADS_NEBULAR_SCENES2_H
+
+#include "common/scummsys.h"
+#include "mads/game.h"
+#include "mads/scene.h"
+#include "mads/nebular/nebular_scenes.h"
+
+namespace MADS {
+
+namespace Nebular {
+
+class Scene2xx : public NebularScene {
+protected:
+ /**
+ * Plays an appropriate sound when entering a scene
+ */
+ void setAAName();
+
+ /**
+ * Updates the prefix used for getting player sprites for the scene
+ */
+ void setPlayerSpritesPrefix();
+
+ void sceneEntrySound();
+public:
+ Scene2xx(MADSEngine *vm) : NebularScene(vm) {}
+};
+
+class Scene201: public Scene2xx {
+private:
+ bool _pterodactylFlag;
+
+public:
+ Scene201(MADSEngine *vm);
+ virtual void synchronize(Common::Serializer &s);
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+ virtual void actions();
+};
+
+class Scene202: public Scene2xx {
+private:
+ bool _activeMsgFl, _ladderTopFl, _waitingMeteoFl, _toStationFl, _toTeleportFl;
+ int _ladderHotspotId, _lastRoute, _stationCounter, _meteoFrame;
+ uint32 _meteoClock1, _meteoClock2, _startTime;
+ bool _meteorologistSpecial;
+
+ int subStep1(int randVal);
+ int subStep2(int randVal);
+ int subStep3(int randVal);
+ int subStep4(int randVal);
+
+public:
+ Scene202(MADSEngine *vm);
+ virtual void synchronize(Common::Serializer &s);
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+ virtual void preActions();
+ virtual void actions();
+
+ void setRandomKernelMessage();
+};
+
+class Scene203: public Scene2xx {
+private:
+ bool _rhotundaEat2Fl, _rhotundaEatFl;
+
+public:
+ Scene203(MADSEngine *vm);
+ virtual void synchronize(Common::Serializer &s);
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+ virtual void preActions();
+ virtual void actions();
+};
+
+class Scene205: public Scene2xx {
+private:
+ uint32 _lastFishTime, _chickenTime;
+ bool _beingKicked;
+ int _kernelMessage;
+ Conversation _dialog1;
+
+ void handleWomanSpeech(int quoteId);
+
+public:
+ Scene205(MADSEngine *vm);
+ virtual void synchronize(Common::Serializer &s);
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+ virtual void actions();
+};
+
+class Scene207: public Scene2xx {
+private:
+ bool _vultureFl, _spiderFl, _eyeFl;
+ int _spiderHotspotId, _vultureHotspotId;
+ int32 _spiderTime, _vultureTime;
+
+ void moveVulture();
+ void moveSpider();
+
+public:
+ Scene207(MADSEngine *vm);
+ virtual void synchronize(Common::Serializer &s);
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+ virtual void preActions();
+ virtual void actions();
+};
+
+class Scene208: public Scene2xx {
+private:
+ bool _rhotundaTurnFl, _boundingFl;
+ int32 _rhotundaTime;
+
+ void updateTrap();
+ void subAction(int mode);
+
+public:
+ Scene208(MADSEngine *vm);
+ virtual void synchronize(Common::Serializer &s);
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+ virtual void preActions();
+ virtual void actions();
+};
+
+class Scene209: public Scene2xx {
+private:
+ bool _dodgeFl, _forceDodgeFl, _shouldDodgeFl;
+ bool _pitchFl;
+ bool _fallFl, _forceFallFl, _shouldFallFl;
+ bool _playingAnimFl, _playingDialogFl;
+ int _pauseMode, _pauseCounterThreshold, _pauseCounter;
+ bool _removeMonkeyFl;
+ int _monkeyPosition;
+ bool _shootReadyFl, _startShootingInTimerFl, _shootMissedLastFl;
+ bool _binocularsDroppedFl;
+ int _dialogAbortVal;
+ int _counter;
+
+ void handlePause();
+ void initPauseCounterThreshold();
+ void handlePeek();
+ void handleVerticalMove();
+ void handleLookStay();
+ void handleLookRight();
+ void handleBlink();
+ void handleGetBinoculars();
+ void handleStandFromPeek();
+ void handleDodge();
+ void handleBinocularBlink();
+ void handleBinocularScan();
+ void handleJumpInTree();
+ void handleTongue();
+ void handleMonkeyFall();
+ void handleJumpAndHide();
+ void handleMonkeyEating();
+ void handleMonkey1();
+ void handleStandBlink();
+ void handleMonkey2();
+
+public:
+ Scene209(MADSEngine *vm);
+ virtual void synchronize(Common::Serializer &s);
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+ virtual void preActions();
+ virtual void actions();
+};
+
+class Scene210: public Scene2xx {
+private:
+ int _curDialogNode;
+ int _nextHandsPlace;
+ int _twinkleAnimationType;
+ int _twinklesCurrentFrame;
+ bool _shouldTalk, _shouldFaceRex, _shouldMoveHead;
+ bool _stopWalking;
+ bool _twinklesTalking;
+ bool _twinklesTalk2;
+ int _doorway;
+ Common::String _subQuote2;
+ Conversation _conv1, _conv2, _conv3;
+ Conversation _conv5, _conv6, _conv7, _conv8;
+
+ void handleConversations();
+ void handleConversation1();
+ void handleConversation2();
+ void handleConversation3();
+ void handleConversation5();
+ void handleConversation6();
+ void handleConversation7();
+ void handleConversation8();
+ void setDialogNode(int node);
+ void handleTwinklesSpeech(int quoteId, int shiftX, uint32 delay);
+ void newNode(int node);
+ void restoreDialogNode(int node, int msgId, int posY);
+
+public:
+ Scene210(MADSEngine *vm);
+ virtual void synchronize(Common::Serializer &s);
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+ virtual void preActions();
+ virtual void actions();
+};
+
+class Scene211: public Scene2xx {
+private:
+ bool _ambushFl, _wakeFl;
+ int _monkeyFrame, _scrollY;
+ uint32 _monkeyTime;
+
+public:
+ Scene211(MADSEngine *vm);
+ virtual void synchronize(Common::Serializer &s);
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+ virtual void preActions();
+ virtual void actions();
+};
+
+class Scene212: public Scene2xx {
+public:
+ Scene212(MADSEngine *vm) : Scene2xx(vm) {}
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+ virtual void preActions();
+ virtual void actions();
+};
+
+class Scene213: public SceneTeleporter {
+public:
+ Scene213(MADSEngine *vm) : SceneTeleporter(vm) {}
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+ virtual void actions();
+};
+
+class Scene214: public Scene2xx {
+private:
+ uint32 _devilTime;
+ bool _devilRunningFl;
+
+public:
+ Scene214(MADSEngine *vm);
+ virtual void synchronize(Common::Serializer &s);
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+ virtual void actions();
+};
+
+class Scene215: public Scene2xx {
+public:
+ Scene215(MADSEngine *vm) : Scene2xx(vm) {}
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+ virtual void actions();
+};
+
+class Scene216: public Scene2xx {
+public:
+ Scene216(MADSEngine *vm) : Scene2xx(vm) {}
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+ virtual void actions() {};
+};
+
+} // End of namespace Nebular
+
+} // End of namespace MADS
+
+#endif /* MADS_NEBULAR_SCENES2_H */
diff --git a/engines/mads/nebular/nebular_scenes3.cpp b/engines/mads/nebular/nebular_scenes3.cpp
new file mode 100644
index 0000000000..d54ffbdb2b
--- /dev/null
+++ b/engines/mads/nebular/nebular_scenes3.cpp
@@ -0,0 +1,5807 @@
+/* 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 "mads/mads.h"
+#include "mads/scene.h"
+#include "mads/nebular/nebular_scenes.h"
+#include "mads/nebular/nebular_scenes3.h"
+
+namespace MADS {
+
+namespace Nebular {
+
+void Scene3xx::setAAName() {
+ _game._aaName = Resources::formatAAName(4);
+}
+
+void Scene3xx::setPlayerSpritesPrefix() {
+ _vm->_sound->command(5);
+
+ Common::String oldName = _game._player._spritesPrefix;
+
+ if (_globals[kSexOfRex] == REX_MALE)
+ _game._player._spritesPrefix = "RXM";
+ else
+ _game._player._spritesPrefix = "ROX";
+
+ if ((_scene->_nextSceneId == 313) || (_scene->_nextSceneId == 366)
+ || ((_scene->_nextSceneId >= 301) && (_scene->_nextSceneId <= 303))
+ || ((_scene->_nextSceneId == 304) && (_scene->_currentSceneId == 303))
+ || ((_scene->_nextSceneId == 311) && (_scene->_currentSceneId == 304))
+ || ((_scene->_nextSceneId >= 308) && (_scene->_nextSceneId <= 310))
+ || ((_scene->_nextSceneId >= 319) && (_scene->_nextSceneId <= 322))
+ || ((_scene->_nextSceneId >= 387) && (_scene->_nextSceneId <= 391))) {
+ _game._player._spritesPrefix = "";
+ _game._player._spritesChanged = true;
+ }
+
+ _game._player._scalingVelocity = true;
+ if (oldName != _game._player._spritesPrefix)
+ _game._player._spritesChanged = true;
+
+ _vm->_palette->setEntry(16, 10, 63, 63);
+ _vm->_palette->setEntry(17, 10, 45, 45);
+}
+
+void Scene3xx::sceneEntrySound() {
+ if (!_vm->_musicFlag) {
+ _vm->_sound->command(2);
+ return;
+ }
+
+ switch (_scene->_nextSceneId) {
+ case 301:
+ case 302:
+ case 303:
+ case 304:
+ case 308:
+ case 309:
+ case 310:
+ _vm->_sound->command(11);
+ break;
+
+ case 311:
+ if (_scene->_priorSceneId == 304)
+ _vm->_sound->command(11);
+ else
+ _vm->_sound->command(10);
+ break;
+
+ case 313:
+ case 316:
+ case 320:
+ case 322:
+ case 357:
+ case 358:
+ case 359:
+ case 360:
+ case 361:
+ case 387:
+ case 388:
+ case 389:
+ case 390:
+ case 391:
+ case 399:
+ _vm->_sound->command(10);
+ break;
+
+ case 318:
+ if ((_scene->_priorSceneId == 357) || (_scene->_priorSceneId == 407))
+ _vm->_sound->command(10);
+ else if (_scene->_priorSceneId == 319)
+ _vm->_sound->command(16);
+ else
+ _vm->_sound->command(3);
+
+ _vm->_sound->command(50);
+ break;
+
+ case 319:
+ _vm->_sound->command(16);
+ break;
+
+ case 321:
+ _vm->_sound->command(18);
+ break;
+
+ default:
+ break;
+ }
+}
+
+void Scene3xx::initForceField(ForceField *force, bool flag) {
+ force->_flag = flag;
+ force->_vertical = 0;
+ force->_horizontal = 0;
+ force->_timer = 0;
+
+ for (int count = 0; count < 40; count++)
+ force->_seqId[count] = -1;
+
+ if (force->_flag)
+ _vm->_sound->command(24);
+}
+
+int Scene3xx::computeScale(int low, int high, int id) {
+ int diff = high - (low + 2);
+ int quotient = diff / 20;
+ int remainder = diff % 20;
+ int value = low + 2 + (quotient * id) + (remainder / (id + 1));
+
+ return (value);
+}
+
+void Scene3xx::handleForceField(ForceField *force, int *sprites) {
+ if (_game._trigger >= 150) {
+ int id = _game._trigger - 150;
+ if (id < 40) {
+ if (id < 20)
+ force->_vertical--;
+ else
+ force->_horizontal--;
+
+ force->_seqId[id] = -1;
+ }
+ return;
+ }
+
+ if (!force->_flag || (_scene->_frameStartTime < force->_timer) || (force->_vertical + force->_horizontal >= 5))
+ return;
+
+ if (_vm->getRandomNumber(1, 1000) <= (200 + ((40 - (force->_vertical + force->_horizontal)) << 5))) {
+ int id = -1;
+ for (int i = 0; i < 100; i++) {
+ int randIdx = _vm->getRandomNumber(0, 39);
+ if (force->_seqId[randIdx] < 0) {
+ id = randIdx;
+ break;
+ }
+ }
+
+ if (id < 0) {
+ for (int i = 0; i < 40; i++) {
+ if (force->_seqId[i] < 0) {
+ id = i;
+ break;
+ }
+ }
+ }
+
+ int speedX, speedY;
+ int posX, posY;
+ int randVal = _vm->getRandomNumber(1, 100);
+ int spriteId;
+ bool mirror;
+
+ if (id >= 20) {
+ spriteId = 2;
+ mirror = (randVal <= 50);
+ posX = mirror ? 315 : 5;
+ posY = computeScale(15, 119, id - 20);
+ speedX = 1000 * (mirror ? -1 : 1);
+ speedY = 0;
+ } else if (randVal <= 50) {
+ spriteId = 1;
+ mirror = false;
+ posX = computeScale(21, 258, id);
+ posY = 0;
+ speedX = 0;
+ speedY = 600;
+ } else {
+ spriteId = 0;
+ mirror = false;
+ posX = computeScale(21, 258, id);
+ posY = 155;
+ speedX = 0;
+ speedY = -600;
+ }
+
+ if (id >= 0) {
+ force->_seqId[id] = _scene->_sequences.addSpriteCycle(sprites[spriteId], mirror, 2, 0, 0, 0);
+ _scene->_sequences.setDepth(force->_seqId[id], 8);
+ _scene->_sequences.setPosition(force->_seqId[id], Common::Point(posX, posY));
+ _scene->_sequences.setMotion(force->_seqId[id], 2, speedX, speedY);
+ _scene->_sequences.addSubEntry(force->_seqId[id], SEQUENCE_TRIGGER_EXPIRE, 0, 150 + id);
+ if (spriteId == 2)
+ force->_horizontal++;
+ else
+ force->_vertical++;
+ }
+ }
+
+ force->_timer = _scene->_frameStartTime + 4;
+}
+
+/*------------------------------------------------------------------------*/
+
+void Scene300s::preActions() {
+ _game._player._needToWalk = false;
+}
+
+/*------------------------------------------------------------------------*/
+
+void Scene301::setup() {
+ setPlayerSpritesPrefix();
+ setAAName();
+}
+
+void Scene301::enter() {
+ _globals._spriteIndexes[1] = _scene->_sprites.addSprites(formAnimName('x', 0));
+ _globals._sequenceIndexes[1] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[1], false, 9, 0, 0, 0);
+
+ _globals[kMeteorologistStatus] = METEOROLOGIST_GONE;
+ _globals[kTeleporterCommand] = TELEPORTER_NONE;
+
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _scene->loadAnimation(formAnimName('a', -1), 60);
+
+ sceneEntrySound();
+}
+
+void Scene301::step() {
+ if (_game._trigger == 60)
+ _scene->_nextSceneId = 302;
+}
+
+/*------------------------------------------------------------------------*/
+
+Scene302::Scene302(MADSEngine *vm) : Scene3xx(vm) {
+ _oldFrame = 0;
+}
+
+void Scene302::synchronize(Common::Serializer &s) {
+ Scene3xx::synchronize(s);
+
+ s.syncAsSint32LE(_oldFrame);
+}
+
+void Scene302::setup() {
+ setPlayerSpritesPrefix();
+ setAAName();
+}
+
+void Scene302::enter() {
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+
+ _scene->loadAnimation(formAnimName('a', -1), 71);
+ sceneEntrySound();
+}
+
+void Scene302::step() {
+ if (_game._trigger == 71)
+ _scene->_nextSceneId = 303;
+
+ if ((_scene->_activeAnimation != nullptr) && (_scene->_activeAnimation->getCurrentFrame() != _oldFrame)) {
+ _oldFrame = _scene->_activeAnimation->getCurrentFrame();
+ if (_oldFrame == 147) {
+ _game._objects.setRoom(OBJ_POISON_DARTS, 1);
+ _game._objects.setRoom(OBJ_BLOWGUN, 1);
+ _game._objects.setRoom(OBJ_REBREATHER, 1);
+ _game._objects.setRoom(OBJ_STUFFED_FISH, 1);
+ _game._objects.setRoom(OBJ_DEAD_FISH, 1);
+ _game._objects.setRoom(OBJ_BURGER, 1);
+
+ int count = (int)_game._objects._inventoryList.size();
+ for (int idx = 0; idx < count; idx++) {
+ if (_game._objects.isInInventory(idx))
+ _game._objects.setRoom(idx, 50);
+ }
+ }
+ }
+}
+
+/*------------------------------------------------------------------------*/
+
+void Scene303::setup() {
+ setPlayerSpritesPrefix();
+ setAAName();
+}
+
+void Scene303::enter() {
+ _globals._spriteIndexes[1] = _scene->_sprites.addSprites(formAnimName('b', 0));
+ _globals._spriteIndexes[2] = _scene->_sprites.addSprites(formAnimName('b', 1));
+
+ _globals._sequenceIndexes[1] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[1], false, 10, 0, 50, 120);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 1);
+ _globals._sequenceIndexes[2] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[2], false, 10, 0, 0, 0);
+
+ _game._player._visible = false;
+ _game._player._stepEnabled = false;
+ _scene->loadAnimation(formAnimName('a', -1), 60);
+
+ sceneEntrySound();
+}
+
+void Scene303::step() {
+ if (_game._trigger == 60)
+ _scene->_nextSceneId = 304;
+}
+
+/*------------------------------------------------------------------------*/
+
+Scene304::Scene304(MADSEngine *vm) : Scene3xx(vm) {
+ _explosionSpriteId = -1;
+}
+
+void Scene304::synchronize(Common::Serializer &s) {
+ Scene3xx::synchronize(s);
+
+ s.syncAsSint32LE(_explosionSpriteId);
+}
+
+void Scene304::setup() {
+ setPlayerSpritesPrefix();
+ setAAName();
+}
+
+void Scene304::enter() {
+ if (_scene->_priorSceneId == 303) {
+ _game._player._visible = false;
+ _game._player._stepEnabled = false;
+ _scene->loadAnimation(formAnimName('a', -1), 60);
+ } else {
+ if (_globals[kSexOfRex] == REX_MALE)
+ _globals._spriteIndexes[1] = _scene->_sprites.addSprites(formAnimName('a', 0));
+ else
+ _globals._spriteIndexes[4] = _scene->_sprites.addSprites(formAnimName('a', 2));
+
+ _globals._spriteIndexes[2] = _scene->_sprites.addSprites(formAnimName('a', 1));
+ _globals._spriteIndexes[3] = _scene->_sprites.addSprites(formAnimName('b', 0));
+
+ _globals._sequenceIndexes[3] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[3], false, 150, 0, 3, 0);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 2);
+ _vm->_palette->setEntry(252, 45, 63, 45);
+ _vm->_palette->setEntry(253, 20, 45, 20);
+
+ if (_globals[kSexOfRex] == REX_MALE)
+ _game._player._playerPos = Common::Point(111, 117);
+ else
+ _game._player._playerPos = Common::Point(113, 116);
+
+ _globals._sequenceIndexes[2] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[2], false, 11, 0, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[2], -1, -1);
+ _scene->_sequences.addTimer(48, 70);
+ }
+
+ sceneEntrySound();
+ _game.loadQuoteSet(0xEB, 0xEC, 0);
+}
+
+void Scene304::step() {
+ if (_game._trigger == 60)
+ _scene->_nextSceneId = 311;
+
+ if (_game._trigger >= 70) {
+ switch (_game._trigger) {
+ case 70: {
+ _game._player._visible = false;
+ _scene->_sequences.remove(_globals._sequenceIndexes[2]);
+ _globals._sequenceIndexes[2] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[2], false, 8, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[2], 2, 4);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 1);
+ if (_globals[kSexOfRex] == REX_MALE)
+ _explosionSpriteId = _globals._spriteIndexes[1];
+ else
+ _explosionSpriteId = _globals._spriteIndexes[4];
+
+ int sprIdx = _scene->_sequences.addSpriteCycle(_explosionSpriteId, false, 8, 1, 0, 0);
+ _scene->_sequences.setAnimRange(sprIdx, -1, 4);
+ _scene->_sequences.setDepth(sprIdx, 1);
+ _scene->_sequences.addSubEntry(sprIdx, SEQUENCE_TRIGGER_EXPIRE, 0, 71);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[2], SEQUENCE_TRIGGER_EXPIRE, 0, 74);
+ }
+ break;
+
+ case 71:
+ _scene->_kernelMessages.reset();
+ _scene->_kernelMessages.add(Common::Point(0, 0), 0x1110, 34, 0, 60, _game.getQuote(0xEB));
+ _scene->_sequences.addTimer(1, 72);
+ break;
+
+ case 72: {
+ _vm->_sound->command(43);
+ int sprIdx = _scene->_sequences.addSpriteCycle(_explosionSpriteId, false, 8, 1, 0, 0);
+ _scene->_sequences.setAnimRange(sprIdx, 5, -2);
+ _scene->_sequences.setDepth(sprIdx, 1);
+ _scene->_sequences.addSubEntry(sprIdx, SEQUENCE_TRIGGER_EXPIRE, 0, 73);
+ if (_game._storyMode == STORYMODE_NICE)
+ _scene->_sequences.addSubEntry(sprIdx, SEQUENCE_TRIGGER_SPRITE, 8, 78);
+ }
+ break;
+
+ case 73: {
+ int sprIdx = _scene->_sequences.addSpriteCycle(_explosionSpriteId, false, 8, 0, 0, 0);
+ _scene->_sequences.setAnimRange(sprIdx, -2, -2);
+ _scene->_sequences.setDepth(sprIdx, 1);
+ }
+ break;
+
+ case 74:
+ _globals._sequenceIndexes[2] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[2], false, 8, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[2], 5, -2);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 1);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[2], SEQUENCE_TRIGGER_EXPIRE, 0, 75);
+ break;
+
+ case 75:
+ _globals._sequenceIndexes[2] = _scene->_sequences.addReverseSpriteCycle(_globals._spriteIndexes[2], false, 8, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[2], 2, -2);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 1);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[2], SEQUENCE_TRIGGER_EXPIRE, 0, 76);
+ break;
+
+ case 76:
+ _globals._sequenceIndexes[2] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[2], false, 8, 0, 0, 0);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 1);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[2], 2, 2);
+ _scene->_sequences.addTimer(48, 77);
+ break;
+
+ case 77:
+ _scene->_kernelMessages.reset();
+ _scene->_kernelMessages.add(Common::Point(211, 45), 0xFDFC, 32, 0, 180, _game.getQuote(0xEC));
+ _scene->_sequences.addTimer(120, 78);
+ break;
+
+ case 78:
+ _scene->_nextSceneId = 316;
+ break;
+
+ default:
+ break;
+ }
+ }
+}
+
+/*------------------------------------------------------------------------*/
+
+Scene307::Scene307(MADSEngine *vm) : Scene3xx(vm) {
+ _afterPeeingFl = false;
+ _duringPeeingFl = false;
+ _grateOpenedFl = false;
+ _activePrisonerFl = false;
+
+ _animationMode = -1;
+ _prisonerMessageId = -1;
+ _fieldCollisionCounter = -1;
+
+ _lastFrameTime = 0;
+ _guardTime = 0;
+ _prisonerTimer = 0;
+
+ _subQuote2 = "";
+}
+
+void Scene307::synchronize(Common::Serializer &s) {
+ Scene3xx::synchronize(s);
+
+ _forceField.synchronize(s);
+
+ s.syncAsByte(_afterPeeingFl);
+ s.syncAsByte(_duringPeeingFl);
+ s.syncAsByte(_grateOpenedFl);
+ s.syncAsByte(_activePrisonerFl);
+
+ s.syncAsSint32LE(_animationMode);
+ s.syncAsSint32LE(_prisonerMessageId);
+ s.syncAsSint32LE(_fieldCollisionCounter);
+
+ s.syncAsUint32LE(_lastFrameTime);
+ s.syncAsUint32LE(_guardTime);
+ s.syncAsUint32LE(_prisonerTimer);
+
+ s.syncString(_subQuote2);
+}
+
+void Scene307::setup() {
+ setPlayerSpritesPrefix();
+ setAAName();
+ _scene->addActiveVocab(NOUN_AIR_VENT);
+ _scene->addActiveVocab(NOUN_CLIMB_INTO);
+}
+
+void Scene307::handleRexDialog(int quote) {
+ Common::String curQuote = _game.getQuote(_action._activeAction._verbId);
+ if (_vm->_font->getWidth(curQuote, _scene->_textSpacing) > 200) {
+ Common::String subQuote1;
+ _game.splitQuote(curQuote, subQuote1, _subQuote2);
+ _scene->_kernelMessages.add(Common::Point(0, -14), 0x1110, 34, 0, 240, subQuote1);
+ _scene->_kernelMessages.add(Common::Point(0, 0), 0x1110, 34, 1, 180, _subQuote2);
+ } else
+ _scene->_kernelMessages.add(Common::Point(0, 0), 0x1110, 34, 1, 120, curQuote);
+}
+
+void Scene307::handlePrisonerEncounter() {
+ switch (_action._activeAction._verbId) {
+ case 275:
+ setDialogNode(5);
+ break;
+
+ case 277:
+ setDialogNode(4);
+ break;
+
+ case 276:
+ setDialogNode(6);
+ break;
+ }
+}
+
+void Scene307::handlePrisonerSpeech(int firstQuoteId, int number, long timeout) {
+ int height = number * 14;
+ int posY;
+
+ if (height < 60)
+ posY = 65 - height;
+ else
+ posY = 78 - (height / 2);
+
+ _scene->_kernelMessages.reset();
+ _activePrisonerFl = true;
+
+ int quoteId = firstQuoteId;
+ for (int count = 0; count < number; count++) {
+ _game._triggerSetupMode = SEQUENCE_TRIGGER_DAEMON;
+ _scene->_kernelMessages.add(Common::Point(5, posY), 0xFDFC, 0, 81, timeout, _game.getQuote(quoteId));
+ posY += 14;
+ quoteId++;
+ }
+}
+
+void Scene307::setDialogNode(int node) {
+ switch (node) {
+ case 0:
+ handlePrisonerSpeech(0x153, 2, 120);
+ _scene->_userInterface.setup(kInputBuildingSentences);
+ break;
+
+ case 1:
+ _globals[kMetBuddyBeast] = true;
+ handlePrisonerSpeech(0x10F, 2, 9999999);
+ _dialog1.start();
+ break;
+
+ case 2:
+ _globals[kMetBuddyBeast] = true;
+ handlePrisonerSpeech(0x111, 2, 9999999);
+ _dialog1.start();
+ break;
+
+ case 4:
+ handlePrisonerSpeech(0x116, 1, 120);
+ _scene->_userInterface.setup(kInputBuildingSentences);
+ break;
+
+ case 5:
+ _globals[kKnowsBuddyBeast] = true;
+ handlePrisonerSpeech(0x117, 2, 9999999);
+ _dialog2.start();
+ break;
+
+ case 6:
+ handlePrisonerSpeech(0x123, 1, 120);
+ _scene->_userInterface.setup(kInputBuildingSentences);
+ break;
+
+ case 7:
+ _globals[kKnowsBuddyBeast] = true;
+ handlePrisonerSpeech(0x124, 10, 9999999);
+ _dialog2.write(0x11A, false);
+ _dialog2.write(0x11B, true);
+ _dialog2.write(0x120, true);
+ _dialog2.start();
+ break;
+
+ case 8:
+ handlePrisonerSpeech(0x12E, 6, 9999999);
+ _dialog2.write(0x11A, false);
+ _dialog2.write(0x11B, false);
+ _dialog2.write(0x11C, true);
+ _dialog2.write(0x11D, true);
+ _dialog2.write(0x11F, true);
+ _dialog2.start();
+ break;
+
+ case 9:
+ handlePrisonerSpeech(0x134, 4, 9999999);
+ _dialog2.write(0x11D, false);
+ _dialog2.start();
+ break;
+
+ case 10:
+ handlePrisonerSpeech(0x138, 6, 9999999);
+ _dialog2.write(0x11E, false);
+ _dialog2.start();
+ break;
+
+ case 11:
+ handlePrisonerSpeech(0x13E, 6, 9999999);
+ _dialog2.write(0x11F, false);
+ _dialog2.write(0x121, true);
+ _dialog2.start();
+ break;
+
+ case 12:
+ handlePrisonerSpeech(0x144, 4, 9999999);
+ _dialog2.write(0x11C, false);
+ _dialog2.start();
+ break;
+
+ case 13:
+ handlePrisonerSpeech(0x148, 7, 9999999);
+ _dialog2.write(0x120, false);
+ _dialog2.start();
+ break;
+
+ case 14:
+ handlePrisonerSpeech(0x14F, 3, 9999999);
+ _dialog2.write(0x121, false);
+ _dialog2.start();
+ break;
+
+ case 15:
+ handlePrisonerSpeech(0x152, 1, 120);
+ _scene->_userInterface.setup(kInputBuildingSentences);
+ break;
+
+ case 16:
+ _globals[kKnowsBuddyBeast] = true;
+ handlePrisonerSpeech(0x10C, 1, 9999999);
+ _dialog2.start();
+ break;
+
+ default:
+ break;
+ }
+}
+
+void Scene307::handlePrisonerDialog() {
+ switch (_action._activeAction._verbId) {
+ case 0x11A:
+ setDialogNode(7);
+ break;
+
+ case 0x11B:
+ setDialogNode(8);
+ break;
+
+ case 0x11C:
+ setDialogNode(12);
+ break;
+
+ case 0x11D:
+ setDialogNode(9);
+ break;
+
+ case 0x11E:
+ setDialogNode(10);
+ break;
+
+ case 0x11F:
+ setDialogNode(11);
+ break;
+
+ case 0x120:
+ setDialogNode(13);
+ break;
+
+ case 0x121:
+ setDialogNode(14);
+ break;
+
+ case 0x122:
+ setDialogNode(15);
+ break;
+ }
+}
+
+void Scene307::handleDialog() {
+ if (_game._trigger == 0) {
+ _scene->_kernelMessages.reset();
+ _game._player._stepEnabled = false;
+ handleRexDialog(_action._activeAction._verbId);
+ } else {
+ _game._player._stepEnabled = true;
+
+ if (!_globals[kKnowsBuddyBeast]) {
+ handlePrisonerEncounter();
+ } else {
+ handlePrisonerDialog();
+ }
+ }
+}
+
+void Scene307::enter() {
+ _globals._spriteIndexes[1] = _scene->_sprites.addSprites("*SC003x0");
+ _globals._spriteIndexes[0] = _scene->_sprites.addSprites("*SC003x1");
+ _globals._spriteIndexes[2] = _scene->_sprites.addSprites("*SC003x2");
+ _globals._spriteIndexes[4] = _scene->_sprites.addSprites(formAnimName('x', 0));
+
+ initForceField(&_forceField, true);
+
+ _globals._sequenceIndexes[4] = _scene->_sequences.startCycle(_globals._spriteIndexes[4], false, 1);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[4], Common::Point(127, 78));
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[4], 15);
+
+ _animationMode = 0;
+ _fieldCollisionCounter = 0;
+
+ _scene->changeVariant(1);
+
+ _game.loadQuoteSet(0xED, 0xEE, 0xEF, 0xF0, 0xF1, 0xF2, 0xF3, 0x10C, 0x104, 0x106, 0x107, 0x108, 0x105,
+ 0x109, 0x10A, 0x10B, 0x10D, 0x10E, 0x10F, 0x110, 0x111, 0x112, 0x113, 0x114, 0x115, 0x116, 0x117,
+ 0x118, 0x119, 0x11A, 0x11B, 0x11C, 0x11D, 0x11E, 0x11F, 0x120, 0x121, 0x122, 0x123, 0x124, 0x125,
+ 0x126, 0x127, 0x128, 0x129, 0x12A, 0x12B, 0x12C, 0x12D, 0x12E, 0x12F, 0x130, 0x131, 0x132, 0x133,
+ 0x134, 0x135, 0x136, 0x137, 0x138, 0x139, 0x13A, 0x13B, 0x13C, 0x13D, 0x13E, 0x13F, 0x140, 0x141,
+ 0x142, 0x143, 0x144, 0x145, 0x146, 0x147, 0x148, 0x149, 0x14A, 0x14B, 0x14C, 0x14D, 0x14E, 0x14F,
+ 0x150, 0x151, 0x152, 0x153, 0);
+
+ _dialog1.setup(0x3F, 0x113, 0x114, 0x115, -1);
+ _dialog2.setup(0x40, 0x11A, 0x11B, 0x11C, 0x11D, 0x11E, 0x11F, 0x120, 0x121, 0x122, 0);
+
+ if (!_game._visitedScenes._sceneRevisited)
+ _dialog2.set(0x11A, 0x122, 0);
+ else if (_scene->_priorSceneId == 318)
+ _dialog2.write(0x11E, true);
+
+
+ if (_scene->_priorSceneId == -2) {
+ if (_grateOpenedFl)
+ _vm->_sound->command(10);
+ else
+ _vm->_sound->command(3);
+ } else {
+ _afterPeeingFl = false;
+ _duringPeeingFl = false;
+ _guardTime = 0;
+ _grateOpenedFl = false;
+ _activePrisonerFl = false;
+ _prisonerTimer = 0;
+ _prisonerMessageId = 0x104;
+
+ if (_scene->_priorSceneId == 308) {
+ _game._player._visible = false;
+ _game._player._stepEnabled = false;
+ _game._player._playerPos = Common::Point(156, 113);
+ _game._player._facing = FACING_NORTH;
+ _animationMode = 1;
+ _vm->_sound->command(11);
+ _scene->loadAnimation(formAnimName('a', -1), 60);
+ } else if (_scene->_priorSceneId == 387) {
+ _game._player._playerPos = Common::Point(129, 108);
+ _game._player._facing = FACING_NORTH;
+ _vm->_sound->command(3);
+ _grateOpenedFl = true;
+ } else {
+ _game._player._playerPos = Common::Point(159, 109);
+ _game._player._facing = FACING_SOUTH;
+ _vm->_sound->command(3);
+ }
+ }
+
+ if (_grateOpenedFl) {
+ _scene->_hotspots.activate(17, false);
+
+ int idx = _scene->_dynamicHotspots.add(17, 0x2F7, -1, Common::Rect(117, 67, 117 + 19, 67 + 13));
+ int hotspotId = _scene->_dynamicHotspots.setPosition(idx, Common::Point(129, 104), FACING_NORTH);
+ _scene->_dynamicHotspots.setCursor(hotspotId, CURSOR_GO_UP);
+
+ _scene->_sequences.remove(_globals._sequenceIndexes[4]);
+ _globals._sequenceIndexes[4] = _scene->_sequences.startCycle(_globals._spriteIndexes[4], false, 2);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[4], Common::Point(127, 78));
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[4], 15);
+ }
+
+ _vm->_palette->setEntry(252, 63, 30, 20);
+ _vm->_palette->setEntry(253, 45, 15, 12);
+
+ sceneEntrySound();
+
+ if ((_scene->_priorSceneId == 318) || (_scene->_priorSceneId == 387))
+ _scene->_kernelMessages.addQuote(0xF3, 120, 0);
+}
+
+void Scene307::step() {
+ handleForceField(&_forceField, &_globals._spriteIndexes[0]);
+
+ if ((_animationMode == 1) && (_scene->_activeAnimation != nullptr)) {
+ if (_scene->_activeAnimation->getCurrentFrame() == 126) {
+ _forceField._flag = false;
+ _vm->_sound->command(5);
+ }
+
+ if (_scene->_activeAnimation->getCurrentFrame() == 194) {
+ _forceField._flag = true;
+ _vm->_sound->command(24);
+ }
+ }
+
+ if ((_animationMode == 2) && (_scene->_activeAnimation != nullptr)) {
+ if (_scene->_activeAnimation->getCurrentFrame() == 54)
+ _forceField._flag = false;
+
+ if (_scene->_activeAnimation->getCurrentFrame() == 150) {
+ _game._player._visible = false;
+ _game._player._priorTimer = _scene->_frameStartTime - _game._player._ticksAmount;
+ }
+ }
+
+ if (_game._trigger == 60) {
+ _game._player._visible = true;
+ _game._player._stepEnabled = true;
+ _game._player._priorTimer = _scene->_frameStartTime - _game._player._ticksAmount;
+ _animationMode = 0;
+ _vm->_sound->command(9);
+ }
+
+ if ((_lastFrameTime != _scene->_frameStartTime) && !_duringPeeingFl) {
+ int32 elapsedTime = _lastFrameTime - _scene->_frameStartTime;
+ if ((elapsedTime > 0) && (elapsedTime <= 4)) {
+ _guardTime += elapsedTime;
+ _prisonerTimer += elapsedTime;
+ } else {
+ _guardTime++;
+ _prisonerTimer++;
+ }
+ _lastFrameTime = _scene->_frameStartTime;
+
+ // FIXME: The active animation is never a zero pointer, so the guards never show up
+ if ((_guardTime > 3000) && !_duringPeeingFl /*&& (_scene->_activeAnimation == nullptr)*/
+ && (_game._screenObjects._inputMode != 1) && _globals[kMetBuddyBeast] && !_activePrisonerFl) {
+ if (!_game._objects.isInInventory(OBJ_SCALPEL) && !_grateOpenedFl) {
+ _game._player._stepEnabled = false;
+ _game._player.walk(Common::Point(151, 119), FACING_SOUTHEAST);
+ _animationMode = 2;
+ _vm->_sound->command(11);
+ _scene->loadAnimation(formAnimName('b', -1), 70);
+ }
+ _guardTime = 0;
+ } else if ((_prisonerTimer > 300) && (_game._screenObjects._inputMode != 1) && (_scene->_activeAnimation == nullptr) && !_activePrisonerFl) {
+ if (!_globals[kMetBuddyBeast]) {
+ int idx = _scene->_kernelMessages.add(Common::Point(5, 51), 0xFDFC, 0, 81, 120, _game.getQuote(_prisonerMessageId));
+ _scene->_kernelMessages.setQuoted(idx, 4, true);
+ _prisonerMessageId++;
+ if (_prisonerMessageId > 0x10A)
+ _prisonerMessageId = 0x104;
+ } else if (_globals[kKnowsBuddyBeast] && (_dialog2.read(0) > 1) && (_vm->getRandomNumber(1, 3) == 1)) {
+ int idx = _scene->_kernelMessages.add(Common::Point(5, 51), 0xFDFC, 0, 81, 120, _game.getQuote(267));
+ _scene->_kernelMessages.setQuoted(idx, 4, true);
+ }
+ _prisonerTimer = 0;
+ }
+ }
+
+ if (_game._trigger == 70)
+ _scene->_nextSceneId = 318;
+
+ if (_game._trigger == 81) {
+ _prisonerTimer = 0;
+ if (_activePrisonerFl && (_guardTime > 2600))
+ _guardTime = 3000 - _vm->getRandomNumber(1, 800);
+
+ _activePrisonerFl = false;
+ }
+}
+
+void Scene307::actions() {
+ if (_action._lookFlag)
+ _vm->_dialogs->show(30715);
+ else if (_game._screenObjects._inputMode == 1)
+ handleDialog();
+ else if (_action.isAction(VERB_TALKTO, NOUN_CELL_WALL) || _action.isAction(VERB_TALKTO, NOUN_WALL) || _action.isAction(VERB_TALKTO, NOUN_TOILET)) {
+ int node, say;
+ if (_globals[kKnowsBuddyBeast]) {
+ say = 0x10E;
+ node = 16;
+ } else if (_globals[kMetBuddyBeast]) {
+ say = 0x10E;
+ node = 2;
+ } else {
+ say = 0x10D;
+ node = 1;
+ }
+
+ switch (_game._trigger) {
+ case 0:
+ handleRexDialog(say);
+ break;
+
+ case 1:
+ setDialogNode(node);
+ break;
+ }
+ } else if (_action.isAction(VERB_PRY, 0x12C, 0x11)) {
+ switch (_game._trigger) {
+ case 0:
+ _game._player._stepEnabled = false;
+ _scene->_kernelMessages.reset();
+ _scene->_kernelMessages.add(Common::Point(0, 0), 0x1110, 34, 0, 120, _game.getQuote(239));
+ _scene->_sequences.addTimer(120, 1);
+ break;
+
+ case 1:
+ _globals._spriteIndexes[5] = _scene->_sprites.addSprites("*RXCL_8");
+ _game._player._visible = false;
+ _globals._sequenceIndexes[5] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[5], false, 12, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[5], -1, 3);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[5]);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[5], SEQUENCE_TRIGGER_EXPIRE, 0, 2);
+ break;
+
+ case 2: {
+ int oldIdx = _globals._sequenceIndexes[5];
+ _globals._sequenceIndexes[5] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[5], false, 12, 6, 0, 0);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[5]);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[5], 2, 3);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[5], oldIdx);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[5], SEQUENCE_TRIGGER_EXPIRE, 0, 3);
+ }
+ break;
+
+ case 3: {
+ int oldIdx = _globals._sequenceIndexes[5];
+ _globals._sequenceIndexes[5] = _scene->_sequences.startCycle(_globals._spriteIndexes[5], false, 1);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[5]);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[5], oldIdx);
+ _scene->_sequences.addTimer(48, 4);
+ }
+ break;
+
+ case 4:
+ _vm->_sound->command(26);
+ _scene->_sequences.remove(_globals._sequenceIndexes[4]);
+ _globals._sequenceIndexes[4] = _scene->_sequences.startCycle(_globals._spriteIndexes[4], false, 2);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[4], Common::Point(127, 78));
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[4], 15);
+ _scene->_sequences.addTimer(90, 5);
+ break;
+
+ case 5:
+ _vm->_sound->command(10);
+ _scene->_kernelMessages.reset();
+ _scene->_kernelMessages.add(Common::Point(0, 0), 0x1110, 34, 0, 120, _game.getQuote(241));
+ _scene->_sequences.addTimer(120, 6);
+ break;
+
+ case 6: {
+ _game._player._visible = true;
+ _game._player._priorTimer = _scene->_frameStartTime - _game._player._ticksAmount;
+ _scene->_sequences.remove(_globals._sequenceIndexes[5]);
+ _grateOpenedFl = true;
+ _scene->_hotspots.activate(17, false);
+ int idx = _scene->_dynamicHotspots.add(17, 0x2F7, -1, Common::Rect(117, 67, 117 + 19, 67 + 13));
+ int hotspotId = _scene->_dynamicHotspots.setPosition(idx, Common::Point(129, 104), FACING_NORTH);
+ _scene->_dynamicHotspots.setCursor(hotspotId, CURSOR_GO_UP);
+ _game._objects.removeFromInventory(OBJ_SCALPEL, NOWHERE);
+ _scene->_kernelMessages.addQuote(0xF2, 120, 7);
+ }
+ break;
+
+ case 7:
+ _scene->_sprites.remove(_globals._spriteIndexes[5]);
+ _game._player._stepEnabled = true;
+ break;
+
+ default:
+ break;
+ }
+ }else if (_action.isAction(VERB_CLIMB_INTO, NOUN_AIR_VENT)) {
+ if (_grateOpenedFl) {
+ switch (_game._trigger) {
+ case 0:
+ _globals._spriteIndexes[5] = _scene->_sprites.addSprites("*RXCL_8");
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _scene->_sequences.remove(_globals._sequenceIndexes[4]);
+ _globals._sequenceIndexes[4] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[4], false, 60, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[4], 3, -2);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[4], Common::Point(127, 78));
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[4], 15);
+ _globals._sequenceIndexes[5] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[5], false, 18, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[5], -1, 4);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[5]);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[4], SEQUENCE_TRIGGER_EXPIRE, 0, 1);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[5], SEQUENCE_TRIGGER_EXPIRE, 0, 2);
+ break;
+
+ case 1:
+ _globals._sequenceIndexes[4] = _scene->_sequences.startCycle(_globals._spriteIndexes[4], false, -2);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[4], Common::Point(127, 78));
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[4], 15);
+ break;
+
+ case 2: {
+ int oldIdx = _globals._sequenceIndexes[5];
+ _globals._sequenceIndexes[5] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[5], false, 12, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[5], 4, 10);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[5]);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[5], oldIdx);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[5], SEQUENCE_TRIGGER_EXPIRE, 0, 3);
+ }
+ break;
+
+ case 3:
+ _scene->_sequences.remove(_globals._sequenceIndexes[4]);
+ _globals._sequenceIndexes[4] = _scene->_sequences.startCycle(_globals._spriteIndexes[4], false, 3);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[4], Common::Point(127, 78));
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[4], 1);
+ _globals._sequenceIndexes[5] = _scene->_sequences.startCycle(_globals._spriteIndexes[5], false, 11);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[5]);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[5], Common::Point(129, 102));
+ _scene->_sequences.addTimer(48, 4);
+ break;
+
+ case 4:
+ _scene->_sequences.remove(_globals._sequenceIndexes[4]);
+ _globals._sequenceIndexes[4] = _scene->_sequences.startCycle(_globals._spriteIndexes[4], false, 2);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[4], Common::Point(127, 78));
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[4], 1);
+ _scene->_sequences.remove(_globals._sequenceIndexes[5]);
+ _globals._sequenceIndexes[5] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[5], false, 12, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[5], 12, 14);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[5]);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[5], Common::Point(129, 102));
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[5], SEQUENCE_TRIGGER_EXPIRE, 0, 5);
+ break;
+
+ case 5:
+ _globals._sequenceIndexes[5] = _scene->_sequences.startCycle(_globals._spriteIndexes[5], false, 15);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[5]);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[5], Common::Point(129, 102));
+ _scene->_sequences.addTimer(48, 6);
+ break;
+
+ case 6:
+ _scene->_sequences.remove(_globals._sequenceIndexes[5]);
+ _scene->_sequences.remove(_globals._sequenceIndexes[4]);
+ _globals._sequenceIndexes[4] = _scene->_sequences.startCycle(_globals._spriteIndexes[4], false, 1);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[4], Common::Point(127, 78));
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[4], 1);
+ _scene->_sequences.addTimer(48, 7);
+ break;
+
+ case 7:
+ _scene->_nextSceneId = 313;
+ break;
+
+ default:
+ break;
+ }
+ }
+ } else if (_action.isAction(VERB_USE, NOUN_TOILET) && (_game._storyMode != STORYMODE_NAUGHTY))
+ _vm->_dialogs->show(30723);
+ else if (_action.isAction(VERB_USE, NOUN_TOILET)) {
+ if (!_afterPeeingFl) {
+ switch (_game._trigger) {
+ case 0:
+ _vm->_sound->command(25);
+ _globals._spriteIndexes[3] = _scene->_sprites.addSprites(formAnimName('a', 0));
+ _duringPeeingFl = true;
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._sequenceIndexes[3] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[3], false, 9, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[3], -1, 2);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 9);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[3], SEQUENCE_TRIGGER_EXPIRE, 0, 1);
+ break;
+
+ case 1:
+ _globals._sequenceIndexes[3] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[3], false, 9, 5, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[3], 3, -2);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 9);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[3], SEQUENCE_TRIGGER_EXPIRE, 0, 2);
+ break;
+
+ case 2:
+ _scene->_sequences.updateTimeout(-1, _globals._sequenceIndexes[3]);
+ _game._player._visible = true;
+ _scene->_sequences.addTimer(48, 3);
+ break;
+
+ case 3: {
+ _scene->_sprites.remove(_globals._spriteIndexes[3]);
+ _scene->_kernelMessages.reset();
+ int idx = _scene->_kernelMessages.add(Common::Point(0, 0), 0x1110, 34, 4, 120, _game.getQuote(237));
+ _scene->_kernelMessages.setQuoted(idx, 4, true);
+ }
+ break;
+
+ case 4:
+ _game._player._stepEnabled = true;
+ _duringPeeingFl = false;
+ _afterPeeingFl = true;
+ break;
+
+ default:
+ break;
+ }
+ } else {
+ _scene->_kernelMessages.reset();
+ int idx = _scene->_kernelMessages.add(Common::Point(85, 39), 0x1110, 0, 0, 180, _game.getQuote(238));
+ _scene->_kernelMessages.setQuoted(idx, 4, true);
+ }
+ } else if (_action.isAction(VERB_LOOK, NOUN_AIR_VENT)) {
+ if (!_grateOpenedFl)
+ _vm->_dialogs->show(30710);
+ else
+ _vm->_dialogs->show(30711);
+ } else if (_action.isAction(VERB_LOOK, NOUN_BED))
+ _vm->_dialogs->show(30712);
+ else if (_action.isAction(VERB_LOOK, NOUN_SINK))
+ _vm->_dialogs->show(30713);
+ else if (_action.isAction(VERB_LOOK, NOUN_TOILET))
+ _vm->_dialogs->show(30714);
+ else if (_action.isAction(0x134, 0x12C))
+ _vm->_dialogs->show(30716);
+ else if (_action.isAction(VERB_LOOK, NOUN_CELL_WALL))
+ _vm->_dialogs->show(30717);
+ else if (_action.isAction(VERB_LOOK, NOUN_LIGHT))
+ _vm->_dialogs->show(30718);
+ else if (_action.isAction(VERB_WALK_INTO, NOUN_CORRIDOR)) {
+ switch (_fieldCollisionCounter) {
+ case 0:
+ _vm->_dialogs->show(30719);
+ _fieldCollisionCounter = 1;
+ break;
+
+ case 1:
+ _vm->_dialogs->show(30720);
+ _fieldCollisionCounter = 2;
+ break;
+
+ case 2:
+ _vm->_dialogs->show(30721);
+ _fieldCollisionCounter = 3;
+ break;
+
+ case 3:
+ _vm->_dialogs->show(30722);
+ break;
+ }
+ } else
+ return;
+
+ _action._inProgress = false;
+}
+
+/*------------------------------------------------------------------------*/
+
+void Scene308::setup() {
+ setPlayerSpritesPrefix();
+ setAAName();
+}
+
+void Scene308::synchronize(Common::Serializer &s) {
+ Scene3xx::synchronize(s);
+
+ _forceField.synchronize(s);
+}
+
+void Scene308::enter() {
+ _globals._spriteIndexes[1] = _scene->_sprites.addSprites("*SC003x0");
+ _globals._spriteIndexes[0] = _scene->_sprites.addSprites("*SC003x1");
+ _globals._spriteIndexes[2] = _scene->_sprites.addSprites("*SC003x2");
+
+ initForceField(&_forceField, true);
+
+ _globals._spriteIndexes[3] = _scene->_sprites.addSprites(formAnimName('b', 0));
+ _globals._spriteIndexes[4] = _scene->_sprites.addSprites(Resources::formatName(307, 'X', 0, EXT_SS, ""));
+
+ _vm->_palette->setEntry(252, 63, 30, 20);
+ _vm->_palette->setEntry(253, 45, 15, 12);
+
+ _globals._sequenceIndexes[4] = _scene->_sequences.startCycle(_globals._spriteIndexes[4], false, 1);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[4], Common::Point(127, 78));
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[4], 15);
+ _globals._sequenceIndexes[3] = _scene->_sequences.startCycle(_globals._spriteIndexes[3], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 9);
+ _scene->_sequences.addTimer(48, 70);
+
+ _game._player._visible = false;
+ _game._player._stepEnabled = false;
+ _scene->loadAnimation(formAnimName('a', -1), 60);
+
+ sceneEntrySound();
+ _game.loadQuoteSet(0xF4, 0xF5, 0xF6, 0);
+}
+
+void Scene308::step() {
+ handleForceField(&_forceField, &_globals._spriteIndexes[0]);
+
+ if (_game._trigger == 60)
+ _scene->_nextSceneId = 307;
+
+ if (_game._trigger < 70)
+ return;
+
+ switch (_game._trigger) {
+ case 70: {
+ _scene->_sequences.remove(_globals._sequenceIndexes[3]);
+ _globals._sequenceIndexes[3] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[3], false, 18, 9, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[3], 2, 3);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 9);
+ _scene->_kernelMessages.reset();
+ int idx = _scene->_kernelMessages.add(Common::Point(171, 21), 0xFDFC, 0, 0, 120, _game.getQuote(244));
+ _scene->_kernelMessages.setQuoted(idx, 2, true);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[3], SEQUENCE_TRIGGER_EXPIRE, 0, 71);
+ }
+ break;
+
+ case 71: {
+ int seqIdx = _globals._sequenceIndexes[3];
+ _globals._sequenceIndexes[3] = _scene->_sequences.startCycle(_globals._spriteIndexes[3], false, 4);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 9);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[3], seqIdx);
+ _scene->_sequences.addTimer(48, 72);
+ }
+ break;
+
+ case 72:
+ _scene->_sequences.remove(_globals._sequenceIndexes[3]);
+ _globals._sequenceIndexes[3] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[3], false, 20, 5, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[3], 3, 4);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 9);
+ _scene->_kernelMessages.reset();
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[3], SEQUENCE_TRIGGER_EXPIRE, 0, 73);
+ break;
+
+ case 73: {
+ int seqIdx = _globals._sequenceIndexes[3];
+ _globals._sequenceIndexes[3] = _scene->_sequences.startCycle(_globals._spriteIndexes[3], false, 5);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 9);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[3], seqIdx);
+ _scene->_sequences.addTimer(48, 74);
+ }
+ break;
+
+ case 74: {
+ _scene->_sequences.remove(_globals._sequenceIndexes[3]);
+ _globals._sequenceIndexes[3] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[3], false, 20, 8, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[3], 6, 7);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 9);
+ _scene->_kernelMessages.reset();
+ int idx = _scene->_kernelMessages.add(Common::Point(171, 21), 0xFDFC, 0, 0, 120, _game.getQuote(245));
+ _scene->_kernelMessages.setQuoted(idx, 2, true);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[3], SEQUENCE_TRIGGER_EXPIRE, 0, 75);
+ }
+ break;
+
+ case 75: {
+ int seqIdx = _globals._sequenceIndexes[3];
+ _globals._sequenceIndexes[3] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[3], false, 23, 5, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[3], 8, 10);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 9);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[3], seqIdx);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[3], SEQUENCE_TRIGGER_EXPIRE, 0, 76);
+ }
+ break;
+
+ case 76: {
+ int seqIdx = _globals._sequenceIndexes[3];
+ _globals._sequenceIndexes[3] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[3], false, 26, 0, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[3], 2, 3);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 9);
+ _scene->_kernelMessages.reset();
+ int idx = _scene->_kernelMessages.add(Common::Point(171, 21), 0xFDFC, 0, 0, 120, _game.getQuote(246));
+ _scene->_kernelMessages.setQuoted(idx, 2, true);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[3], seqIdx);
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+/*------------------------------------------------------------------------*/
+
+Scene309::Scene309(MADSEngine *vm) : Scene3xx(vm) {
+ for (int i = 0; i < 3; i++) {
+ _characterSpriteIndexes[i] = -1;
+ _messagesIndexes[i] = -1;
+ }
+
+ _lastFrame = -1;
+}
+
+void Scene309::synchronize(Common::Serializer &s) {
+ Scene3xx::synchronize(s);
+
+ _forceField.synchronize(s);
+
+ for (int i = 0; i < 3; ++i)
+ s.syncAsSint32LE(_characterSpriteIndexes[i]);
+ for (int i = 0; i < 3; ++i)
+ s.syncAsSint32LE(_messagesIndexes[i]);
+ s.syncAsSint32LE(_lastFrame);
+}
+
+void Scene309::setup() {
+ setPlayerSpritesPrefix();
+ setAAName();
+}
+
+void Scene309::enter() {
+ _globals._spriteIndexes[1] = _scene->_sprites.addSprites("*SC003x0");
+ _globals._spriteIndexes[0] = _scene->_sprites.addSprites("*SC003x1");
+ _globals._spriteIndexes[2] = _scene->_sprites.addSprites("*SC003x2");
+
+ initForceField(&_forceField, true);
+
+ _globals._spriteIndexes[3] = _scene->_sprites.addSprites(formAnimName('x', 0));
+ _globals._spriteIndexes[4] = _scene->_sprites.addSprites(Resources::formatName(307, 'X', 0, EXT_SS, ""));
+
+ _globals._sequenceIndexes[4] = _scene->_sequences.startCycle(_globals._spriteIndexes[4], false, 1);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[4], Common::Point(127, 78));
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[4], 15);
+
+ _globals._sequenceIndexes[3] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[3], false, 7, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[3], -1, 3);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 11);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[3], SEQUENCE_TRIGGER_SPRITE, 3, 70);
+
+ _vm->_palette->setEntry(252, 63, 37, 26);
+ _vm->_palette->setEntry(253, 45, 24, 17);
+ _vm->_palette->setEntry(16, 63, 63, 63);
+ _vm->_palette->setEntry(17, 45, 45, 45);
+ _vm->_palette->setEntry(250, 63, 20, 20);
+ _vm->_palette->setEntry(251, 45, 10, 10);
+
+ _game._player._visible = false;
+ _game._player._stepEnabled = false;
+ _scene->loadAnimation(formAnimName('a', -1), 60);
+
+ _characterSpriteIndexes[0] = _scene->_activeAnimation->_spriteListIndexes[2];
+ _characterSpriteIndexes[1] = _scene->_activeAnimation->_spriteListIndexes[2];
+ _characterSpriteIndexes[2] = _scene->_activeAnimation->_spriteListIndexes[1];
+
+ _messagesIndexes[0] = -1;
+ _messagesIndexes[1] = -1;
+ _messagesIndexes[2] = -1;
+
+ sceneEntrySound();
+
+ _game.loadQuoteSet(0xF7, 0xF8, 0xF9, 0x15C, 0x15D, 0x15E, 0);
+}
+
+void Scene309::step() {
+ handleForceField(&_forceField, &_globals._spriteIndexes[0]);
+
+ if (_game._trigger == 61) {
+ _messagesIndexes[0] = -1;
+ _messagesIndexes[1] = -1;
+ }
+
+ if (_game._trigger == 62)
+ _messagesIndexes[2] = -1;
+
+ if (_scene->_activeAnimation != nullptr) {
+ if (_lastFrame != _scene->_activeAnimation->getCurrentFrame()) {
+ _lastFrame = _scene->_activeAnimation->getCurrentFrame();
+ if (_lastFrame == 39) {
+ _messagesIndexes[0] = _scene->_kernelMessages.add(Common::Point(0, 0), 0x1110, 32, 61, 210, _game.getQuote(348));
+ _messagesIndexes[1] = _scene->_kernelMessages.add(Common::Point(0, 0), 0x1110, 32, 0, 210, _game.getQuote(349));
+ }
+
+ if (_lastFrame == 97)
+ _messagesIndexes[2] = _scene->_kernelMessages.add(Common::Point(0, 0), 0xFBFA, 32, 62, 180, _game.getQuote(350));
+
+ for (int charIdx = 0; charIdx < 3; charIdx++) {
+ if (_messagesIndexes[charIdx] >= 0) {
+ bool match = false;
+ int j = -1;
+ for (j = _scene->_activeAnimation->_oldFrameEntry; j < _scene->_activeAnimation->_header._frameEntriesCount; j++) {
+ if (_scene->_activeAnimation->_frameEntries[j]._spriteSlot._spritesIndex == _characterSpriteIndexes[charIdx]) {
+ match = true;
+ break;
+ }
+ }
+
+ if (match) {
+ SpriteSlotSubset *curSpriteSlot = &_scene->_activeAnimation->_frameEntries[j]._spriteSlot;
+ _scene->_kernelMessages._entries[_messagesIndexes[charIdx]]._position.x = curSpriteSlot->_position.x;
+ _scene->_kernelMessages._entries[_messagesIndexes[charIdx]]._position.y = curSpriteSlot->_position.y - (50 + (14 * ((charIdx == 0) ? 2 : 1)));
+ }
+ }
+ }
+ }
+ }
+
+ if (_game._trigger >= 70) {
+ switch (_game._trigger) {
+ case 70: {
+ int idx = _scene->_dynamicHotspots.add(689, 690, _globals._sequenceIndexes[3], Common::Rect(0, 0, 0, 0));
+ _scene->_dynamicHotspots.setPosition(idx, Common::Point(142, 146), FACING_NORTHEAST);
+ _globals._sequenceIndexes[3] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[3], false, 7, 4, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[3], 2, 3);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 11);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[3], SEQUENCE_TRIGGER_EXPIRE, 0, 71);
+ }
+ break;
+
+ case 71: {
+ int _oldIdx = _globals._sequenceIndexes[3];
+ _globals._sequenceIndexes[3] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[3], false, 7, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[3], 4, 7);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 11);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[3], _oldIdx);
+ int idx = _scene->_kernelMessages.add(Common::Point(85, 37), 0xFDFC, 0, 0, 120, _game.getQuote(248));
+ _scene->_kernelMessages.setQuoted(idx, 2, true);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[3], SEQUENCE_TRIGGER_EXPIRE, 0, 72);
+ }
+ break;
+
+ case 72: {
+ int _oldIdx = _globals._sequenceIndexes[3];
+ _globals._sequenceIndexes[3] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[3], false, 7, 8, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[3], 8, 11);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 11);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[3], _oldIdx);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[3], SEQUENCE_TRIGGER_EXPIRE, 0, 73);
+ }
+ break;
+
+ case 73: {
+ int _oldIdx = _globals._sequenceIndexes[3];
+ _globals._sequenceIndexes[3] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[3], false, 7, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[3], 12, 20);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 11);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[3], _oldIdx);
+ int idx = _scene->_kernelMessages.add(Common::Point(170, 49), 0xFDFC, 0, 0, 120, _game.getQuote(249));
+ _scene->_kernelMessages.setQuoted(idx, 2, true);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[3], SEQUENCE_TRIGGER_EXPIRE, 0, 74);
+ }
+ break;
+
+ case 74: {
+ int _oldIdx = _globals._sequenceIndexes[3];
+ _globals._sequenceIndexes[3] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[3], false, 7, 6, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[3], 21, 23);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 11);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[3], _oldIdx);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[3], SEQUENCE_TRIGGER_EXPIRE, 0, 75);
+ }
+ break;
+
+ case 75: {
+ int _oldIdx = _globals._sequenceIndexes[3];
+ _globals._sequenceIndexes[3] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[3], false, 12, 6, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[3], 24, 25);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[3], _oldIdx);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 11);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[3], SEQUENCE_TRIGGER_EXPIRE, 0, 76);
+ }
+ break;
+
+ case 76: {
+ int _oldIdx = _globals._sequenceIndexes[3];
+ _globals._sequenceIndexes[3] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[3], false, 12, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[3], 26, 28);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[3], _oldIdx);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 11);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[3], SEQUENCE_TRIGGER_EXPIRE, 0, 77);
+ }
+ break;
+
+ case 77: {
+ _globals._sequenceIndexes[3] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[3], false, 90, 0, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[3], 29, 30);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 11);
+ int idx = _scene->_kernelMessages.add(Common::Point(15, 46), 0xFDFC, 0, 0, 120, _game.getQuote(247));
+ _scene->_kernelMessages.setQuoted(idx, 2, true);
+ _scene->_sequences.addTimer(120, 78);
+ }
+ break;
+ }
+ }
+
+ if (_game._trigger == 60)
+ _scene->_nextSceneId = 308;
+}
+
+/*------------------------------------------------------------------------*/
+
+void Scene310::setup() {
+ setPlayerSpritesPrefix();
+ setAAName();
+}
+
+void Scene310::synchronize(Common::Serializer &s) {
+ Scene3xx::synchronize(s);
+
+ _forceField.synchronize(s);
+}
+
+void Scene310::enter() {
+ _globals._spriteIndexes[1] = _scene->_sprites.addSprites("*SC003x0");
+ _globals._spriteIndexes[0] = _scene->_sprites.addSprites("*SC003x1");
+ _globals._spriteIndexes[2] = _scene->_sprites.addSprites("*SC003x2");
+
+ initForceField(&_forceField, true);
+
+ _globals._spriteIndexes[3] = _scene->_sprites.addSprites(Resources::formatName(307, 'X', 0, EXT_SS, ""));
+ _globals._sequenceIndexes[3] = _scene->_sequences.startCycle(_globals._spriteIndexes[3], false, 1);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[3], Common::Point(127, 78));
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 15);
+
+ _game._player._visible = false;
+ _game._player._stepEnabled = false;
+ _scene->loadAnimation(formAnimName('a', -1), 70);
+
+ sceneEntrySound();
+}
+
+void Scene310::step() {
+ handleForceField(&_forceField, &_globals._spriteIndexes[0]);
+
+ if (_game._trigger == 70)
+ _scene->_nextSceneId = 309;
+}
+
+/*------------------------------------------------------------------------*/
+
+Scene311::Scene311(MADSEngine *vm) : Scene3xx(vm) {
+ _checkGuardFl = false;
+}
+
+void Scene311::synchronize(Common::Serializer &s) {
+ Scene3xx::synchronize(s);
+
+ s.syncAsByte(_checkGuardFl);
+}
+
+void Scene311::setup() {
+ if (_scene->_currentSceneId == 391)
+ _globals[kSexOfRex] = REX_MALE;
+
+ setPlayerSpritesPrefix();
+ setAAName();
+
+ if (_scene->_currentSceneId == 304)
+ _game._player._spritesPrefix = "";
+}
+
+void Scene311::enter() {
+ _globals._spriteIndexes[1] = _scene->_sprites.addSprites(Resources::formatName(307, 'X', 0, EXT_SS, ""));
+ _globals._spriteIndexes[2] = _scene->_sprites.addSprites("*RXCL_8");
+ _globals._spriteIndexes[3] = _scene->_sprites.addSprites("*RXCL_2");
+
+ _globals._sequenceIndexes[1] = _scene->_sequences.startCycle(_globals._spriteIndexes[1], false, 1);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[1], Common::Point(165, 76));
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 15);
+
+ _checkGuardFl = false;
+ _game.loadQuoteSet(0xFA, 0);
+
+ if (_scene->_priorSceneId == 391) {
+ _globals[kSexOfRex] = REX_MALE;
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _game._player._facing = FACING_SOUTH;
+ _game._player._playerPos = Common::Point(166, 101);
+ _scene->_sequences.addTimer(120, 71);
+ } else if (_scene->_priorSceneId == 310)
+ _game._player._playerPos = Common::Point(302, 145);
+ else if (_scene->_priorSceneId == 320) {
+ _game._player._playerPos = Common::Point(129, 113);
+ _game._player._facing = FACING_SOUTH;
+ } else if (_scene->_priorSceneId != -2) {
+ _game._player._visible = false;
+ _game._player._stepEnabled = false;
+ _scene->loadAnimation(formAnimName('a', -1), 70);
+ }
+
+ sceneEntrySound();
+}
+
+void Scene311::step() {
+ if (_game._trigger == 70)
+ _scene->_nextSceneId = 310;
+
+ if (_game._trigger >= 71) {
+ switch (_game._trigger) {
+ case 71:
+ _scene->_sequences.remove(_globals._sequenceIndexes[1]);
+ _globals._sequenceIndexes[1] = _scene->_sequences.startCycle(_globals._spriteIndexes[1], false, 2);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[1], Common::Point(165, 76));
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 1);
+
+ _globals._sequenceIndexes[3] = _scene->_sequences.startCycle(_globals._spriteIndexes[3], false, 1);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[3]);
+ _scene->_sequences.addTimer(15, 72);
+ break;
+
+ case 72:
+ _scene->_sequences.setDone(_globals._sequenceIndexes[3]);
+ _globals._sequenceIndexes[3] = _scene->_sequences.startCycle(_globals._spriteIndexes[3], false, 2);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[3]);
+ _scene->_sequences.addTimer(15, 73);
+ break;
+
+ case 73:
+ _scene->_sequences.remove(_globals._sequenceIndexes[1]);
+ _globals._sequenceIndexes[1] = _scene->_sequences.startCycle(_globals._spriteIndexes[1], false, 3);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[1], Common::Point(165, 76));
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 1);
+
+ _scene->_sequences.setDone(_globals._sequenceIndexes[3]);
+ _globals._sequenceIndexes[3] = _scene->_sequences.startCycle(_globals._spriteIndexes[3], false, 3);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[3]);
+ _scene->_sequences.addTimer(15, 74);
+ break;
+
+ case 74:
+ _scene->_sequences.setDone(_globals._sequenceIndexes[3]);
+ _globals._sequenceIndexes[3] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[3], false, 12, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[3], 4, 5);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[3]);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[3], SEQUENCE_TRIGGER_EXPIRE, 0, 75);
+ break;
+
+ case 75: {
+ int oldIdx = _globals._sequenceIndexes[3];
+ _globals._sequenceIndexes[3] = _scene->_sequences.startCycle(_globals._spriteIndexes[3], false, 6);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[3]);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[3], oldIdx);
+ _scene->_sequences.addTimer(15, 76);
+ }
+ break;
+
+ case 76:
+ _scene->_sequences.setDone(_globals._sequenceIndexes[3]);
+ _globals._sequenceIndexes[3] = _scene->_sequences.startCycle(_globals._spriteIndexes[3], false, 7);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[3]);
+ _scene->_sequences.addTimer(15, 77);
+ break;
+
+ case 77:
+ _scene->_sequences.remove(_globals._sequenceIndexes[1]);
+ _globals._sequenceIndexes[1] = _scene->_sequences.startCycle(_globals._spriteIndexes[1], false, 2);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[1], Common::Point(165, 76));
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 1);
+
+ _scene->_sequences.setDone(_globals._sequenceIndexes[3]);
+ _globals._sequenceIndexes[3] = _scene->_sequences.startCycle(_globals._spriteIndexes[3], false, 8);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[3]);
+ _scene->_sequences.addTimer(15, 78);
+ break;
+
+ case 78:
+ _scene->_sequences.remove(_globals._sequenceIndexes[1]);
+ _globals._sequenceIndexes[1] = _scene->_sequences.startCycle(_globals._spriteIndexes[1], false, 1);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[1], Common::Point(165, 76));
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 15);
+
+ _scene->_sequences.setDone(_globals._sequenceIndexes[3]);
+ _globals._sequenceIndexes[3] = _scene->_sequences.startCycle(_globals._spriteIndexes[3], false, 9);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[3]);
+ _scene->_sequences.addTimer(15, 79);
+ break;
+
+ case 79:
+ _scene->_sequences.setDone(_globals._sequenceIndexes[3]);
+ _globals._sequenceIndexes[3] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[3], false, 12, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[3], 10, -2);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[3]);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[3], SEQUENCE_TRIGGER_EXPIRE, 0, 80);
+ break;
+
+ case 80:
+ _scene->_sequences.updateTimeout(-1, _globals._sequenceIndexes[3]);
+ _game._player._stepEnabled = true;
+ _game._player._visible = true;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ if (_game._player._moving && (_scene->_rails.getNext() > 0)) {
+ int x = _game._player._prepareWalkPos.x;
+ if (x < 75)
+ x = 75;
+ if (x > 207)
+ x = 207;
+
+ _checkGuardFl = true;
+ _game._player.startWalking(Common::Point(x, 122), FACING_SOUTH);
+ _scene->_rails.resetNext();
+ }
+}
+
+void Scene311::actions() {
+ if (_action._lookFlag)
+ _vm->_dialogs->show(31119);
+ else if (_checkGuardFl) {
+ _checkGuardFl = false;
+ _scene->_kernelMessages.reset();
+ _scene->_kernelMessages.addQuote(0xFA, 120, 0);
+ } else if (_action.isAction(VERB_SIT_AT, NOUN_DESK))
+ _scene->_nextSceneId = 320;
+ else if (_action.isAction(VERB_CLIMB_INTO, NOUN_AIR_VENT)) {
+ switch (_game._trigger) {
+ case 0:
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _scene->_sequences.remove(_globals._sequenceIndexes[1]);
+ _globals._sequenceIndexes[1] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[1], false, 50, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[1], 3, -2);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[1], Common::Point(165, 76));
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 15);
+
+ _globals._sequenceIndexes[2] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[2], false, 15, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[2], -1, 4);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[2]);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[1], SEQUENCE_TRIGGER_EXPIRE, 0, 1);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[2], SEQUENCE_TRIGGER_EXPIRE, 0, 2);
+ break;
+
+ case 1: {
+ int oldIdx = _globals._sequenceIndexes[1];
+ _globals._sequenceIndexes[1] = _scene->_sequences.startCycle(_globals._spriteIndexes[1], false, -2);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[1], Common::Point(165, 76));
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 15);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[1], oldIdx);
+ }
+ break;
+
+ case 2: {
+ int oldIdx = _globals._sequenceIndexes[2];
+ _globals._sequenceIndexes[2] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[2], false, 12, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[2], 4, 10);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[2]);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[2], oldIdx);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[2], SEQUENCE_TRIGGER_EXPIRE, 0, 3);
+ }
+ break;
+
+ case 3: {
+ _scene->_sequences.remove(_globals._sequenceIndexes[1]);
+ _globals._sequenceIndexes[1] = _scene->_sequences.startCycle(_globals._spriteIndexes[1], false, 3);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[1], Common::Point(165, 76));
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 1);
+
+ int oldIdx = _globals._sequenceIndexes[2];
+ _globals._sequenceIndexes[2] = _scene->_sequences.startCycle(_globals._spriteIndexes[2], false, 11);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[2]);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[2], Common::Point(167, 100));
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[2], oldIdx);
+ _scene->_sequences.addTimer(15, 4);
+ }
+ break;
+
+ case 4:
+ _scene->_sequences.remove(_globals._sequenceIndexes[1]);
+ _globals._sequenceIndexes[1] = _scene->_sequences.startCycle(_globals._spriteIndexes[1], false, 2);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[1], Common::Point(165, 76));
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 1);
+
+ _scene->_sequences.remove(_globals._sequenceIndexes[2]);
+ _globals._sequenceIndexes[2] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[2], false, 12, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[2], 12, 14);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[2]);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[2], Common::Point(167, 100));
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[2], SEQUENCE_TRIGGER_EXPIRE, 0, 5);
+ break;
+
+ case 5: {
+ int oldIdx = _globals._sequenceIndexes[2];
+ _globals._sequenceIndexes[2] = _scene->_sequences.startCycle(_globals._spriteIndexes[2], false, 15);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[2]);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[2], Common::Point(167, 100));
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[2], oldIdx);
+ _scene->_sequences.addTimer(15, 6);
+ }
+ break;
+
+ case 6:
+ _scene->_sequences.remove(_globals._sequenceIndexes[2]);
+ _scene->_sequences.remove(_globals._sequenceIndexes[1]);
+ _globals._sequenceIndexes[1] = _scene->_sequences.startCycle(_globals._spriteIndexes[1], false, 1);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[1], Common::Point(165, 76));
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 1);
+ _scene->_sequences.addTimer(15, 7);
+ break;
+
+ case 7:
+ _scene->_nextSceneId = 313;
+ break;
+
+ default:
+ break;
+ }
+ } else if (_action.isAction(VERB_LOOK, NOUN_DESK))
+ _vm->_dialogs->show(31110);
+ else if (_action.isAction(VERB_LOOK, NOUN_WALL))
+ _vm->_dialogs->show(31111);
+ else if (_action.isAction(VERB_LOOK, NOUN_LIGHTING_FIXTURE) || _action.isAction(VERB_STARE_AT, NOUN_LIGHTING_FIXTURE))
+ _vm->_dialogs->show(31112);
+ else if (_action.isAction(VERB_LOOK, NOUN_LIGHTS) || _action.isAction(VERB_STARE_AT, NOUN_LIGHTS))
+ _vm->_dialogs->show(31113);
+ else if (_action.isAction(VERB_TAKE, NOUN_LIGHTS))
+ _vm->_dialogs->show(31114);
+ else if (_action.isAction(VERB_LOOK, NOUN_LIGHT) || _action.isAction(VERB_STARE_AT, NOUN_LIGHT))
+ _vm->_dialogs->show(31115);
+ else if (_action.isAction(VERB_TAKE, NOUN_LIGHT))
+ _vm->_dialogs->show(31116);
+ else if (_action.isAction(VERB_LOOK, NOUN_CORRIDOR_TO_WEST))
+ _vm->_dialogs->show(31117);
+ else if (_action.isAction(VERB_LOOK, NOUN_CORRIDOR_TO_EAST))
+ _vm->_dialogs->show(31118);
+ else if (_action.isAction(VERB_LOOK, NOUN_AIR_VENT))
+ _vm->_dialogs->show(31120);
+ else
+ return;
+
+ _action._inProgress = false;
+}
+
+/*------------------------------------------------------------------------*/
+
+void Scene313::setup() {
+ setPlayerSpritesPrefix();
+ _game._player._spritesPrefix = "RM313A";
+ setAAName();
+}
+
+void Scene313::enter() {
+ _scene->_userInterface.setup(kInputLimitedSentences);
+
+ if ((_scene->_priorSceneId == 366) || (_scene->_priorSceneId == 316)) {
+ _game._player._playerPos = Common::Point(30, 80);
+ _game._player._facing = FACING_NORTH;
+ } else if ((_scene->_priorSceneId == 311) || (_scene->_priorSceneId == 361) || (_scene->_priorSceneId == 391)) {
+ _game._player._playerPos = Common::Point(90, 70);
+ _game._player._facing = FACING_EAST;
+ } else if (_scene->_priorSceneId == 390) {
+ _game._player._playerPos = Common::Point(126, 70);
+ _game._player._facing = FACING_EAST;
+ } else if ((_scene->_priorSceneId == 389) || (_scene->_priorSceneId == 399)) {
+ _game._player._playerPos = Common::Point(163, 70);
+ _game._player._facing = FACING_WEST;
+ } else if (_scene->_priorSceneId == 388) {
+ _game._player._playerPos = Common::Point(199, 70);
+ _game._player._facing = FACING_WEST;
+ } else if (_scene->_priorSceneId != -2) {
+ _game._player._playerPos = Common::Point(234, 70);
+ _game._player._facing = FACING_WEST;
+ }
+
+ if (_globals[kAfterHavoc]) {
+ for (uint16 i = 0; i < _scene->_paletteCycles.size(); i++) {
+ int palIdx = _scene->_paletteCycles[i]._firstColorIndex;
+ int size = _scene->_paletteCycles[i]._colorCount * 3;
+ memset(&_vm->_palette->_cyclingPalette[palIdx], 0, size);
+ memset(&_vm->_palette->_mainPalette[palIdx], 0, size);
+ }
+ }
+
+ sceneEntrySound();
+}
+
+void Scene313::actions() {
+ if (_action.isAction(VERB_CRAWL_TO, NOUN_FOURTH_CELL))
+ _scene->_nextSceneId = 387;
+ else if (_action.isAction(VERB_CRAWL_TO, NOUN_THIRD_CELL))
+ _scene->_nextSceneId = 388;
+ else if (_action.isAction(VERB_CRAWL_TO, NOUN_SECOND_CELL)) {
+ if (_globals[kAfterHavoc])
+ _scene->_nextSceneId = 399;
+ else
+ _scene->_nextSceneId = 389;
+ } else if (_action.isAction(VERB_CRAWL_TO, NOUN_FIRST_CELL))
+ _scene->_nextSceneId = 390;
+ else if (_action.isAction(VERB_CRAWL_TO, NOUN_SECURITY_STATION)) {
+ if (_globals[kSexOfRex] == REX_FEMALE) {
+ _globals[kSexOfRex] = REX_MALE;
+ _vm->_dialogs->show(31301);
+ }
+ _scene->_nextSceneId = 391;
+ } else if (_action.isAction(VERB_CRAWL_TO, NOUN_EQUIPMENT_ROOM)) {
+ if (_globals[kSexOfRex] == REX_FEMALE) {
+ _globals[kSexOfRex] = REX_MALE;
+ _vm->_dialogs->show(31301);
+ }
+ _scene->_nextSceneId = 366;
+ } else if (!_action.isAction(0x301, 0x2D4))
+ return;
+
+ _action._inProgress = false;
+}
+
+/*------------------------------------------------------------------------*/
+
+void Scene316::setup() {
+ if (_scene->_currentSceneId == 366)
+ _globals[kSexOfRex] = REX_MALE;
+
+ setPlayerSpritesPrefix();
+ setAAName();
+}
+
+void Scene316::handleRexInGrate() {
+ switch (_game._trigger) {
+ case 0:
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._sequenceIndexes[4] = _scene->_sequences.startCycle(_globals._spriteIndexes[4], false, 1);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[4]);
+ _scene->_sequences.addTimer(15, 1);
+ break;
+
+ case 1:
+ _scene->_sequences.setDone(_globals._sequenceIndexes[4]);
+ _globals._sequenceIndexes[4] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[4], false, 12, 3, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[4], 2, 3);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[4]);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[4], SEQUENCE_TRIGGER_EXPIRE, 0, 2);
+ break;
+
+ case 2: {
+ int oldIdx = _globals._sequenceIndexes[4];
+ _globals._sequenceIndexes[4] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[4], false, 12, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[4], 4, 8);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[4]);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[4], oldIdx);
+
+ _scene->_sequences.remove(_globals._sequenceIndexes[3]);
+ _globals._sequenceIndexes[3] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[3], false, 12, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[3], 2, -2);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 12);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[3], SEQUENCE_TRIGGER_EXPIRE, 0, 3);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[4], SEQUENCE_TRIGGER_EXPIRE, 0, 4);
+ }
+ break;
+
+ case 3: {
+ int oldIdx = _globals._sequenceIndexes[3];
+ _globals._sequenceIndexes[3] = _scene->_sequences.startCycle(_globals._spriteIndexes[3], false, -2);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 12);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[3], oldIdx);
+ }
+ break;
+
+ case 4: {
+ int oldIdx = _globals._sequenceIndexes[4];
+ _globals._sequenceIndexes[4] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[4], false, 12, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[4], 10, 11);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[4]);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[4], oldIdx);
+
+ _scene->_sequences.remove(_globals._sequenceIndexes[3]);
+ _globals._sequenceIndexes[3] = _scene->_sequences.addReverseSpriteCycle(_globals._spriteIndexes[3], false, 12, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[3], 5, -2);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 3);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[4], SEQUENCE_TRIGGER_EXPIRE, 0, 5);
+ }
+ break;
+
+ case 5: {
+ int oldIdx = _globals._sequenceIndexes[3];
+ _globals._sequenceIndexes[3] = _scene->_sequences.startCycle(_globals._spriteIndexes[3], false, 3);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 3);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[3], oldIdx);
+
+ oldIdx = _globals._sequenceIndexes[4];
+ _globals._sequenceIndexes[4] = _scene->_sequences.startCycle(_globals._spriteIndexes[4], false, 12);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[4]);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[4], oldIdx);
+ _scene->_sequences.addTimer(15, 6);
+ }
+ break;
+
+ case 6:
+ _scene->_sequences.setDone(_globals._sequenceIndexes[4]);
+ _globals._sequenceIndexes[4] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[4], false, 12, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[4], 13, 14);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[4]);
+
+ _scene->_sequences.remove(_globals._sequenceIndexes[3]);
+ _globals._sequenceIndexes[3] = _scene->_sequences.addReverseSpriteCycle(_globals._spriteIndexes[3], false, 12, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[3], 2, 3);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 3);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[4], SEQUENCE_TRIGGER_EXPIRE, 0, 7);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[3], SEQUENCE_TRIGGER_EXPIRE, 0, 8);
+ break;
+
+ case 7:
+ _scene->_sequences.setDone(_globals._sequenceIndexes[4]);
+ _globals._sequenceIndexes[4] = _scene->_sequences.startCycle(_globals._spriteIndexes[4], false, 15);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[4]);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[4], -1);
+ break;
+
+ case 8: {
+ int oldIdx = _globals._sequenceIndexes[3];
+ _globals._sequenceIndexes[3] = _scene->_sequences.startCycle(_globals._spriteIndexes[3], false, 2);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 3);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[3], oldIdx);
+ _scene->_sequences.addTimer(15, 9);
+ }
+ break;
+
+ case 9:
+ _scene->_sequences.setDone(_globals._sequenceIndexes[4]);
+ _globals._sequenceIndexes[3] = _scene->_sequences.startCycle(_globals._spriteIndexes[3], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 3);
+ _scene->_sequences.addTimer(48, 10);
+ break;
+
+ case 10:
+ _scene->_nextSceneId = 313;
+ break;
+
+ default:
+ break;
+ }
+}
+
+void Scene316::handleRoxInGrate() {
+ int temp;
+ int temp1;
+
+ switch (_game._trigger) {
+ case 0:
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._sequenceIndexes[5] = _scene->_sequences.startCycle(_globals._spriteIndexes[5], false, 1);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[5]);
+ _scene->_sequences.addTimer(15, 1);
+ break;
+
+ case 1:
+ _scene->_sequences.setDone(_globals._sequenceIndexes[5]);
+ _globals._sequenceIndexes[5] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[5], false, 17, 3, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[5], 2, 3);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[5]);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[5], SEQUENCE_TRIGGER_EXPIRE, 0, 2);
+ break;
+
+ case 2:
+ _scene->_sequences.remove(_globals._sequenceIndexes[3]);
+ _globals._sequenceIndexes[3] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[3], false, 17, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[3], 2, -2);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 12);
+
+ temp = _globals._sequenceIndexes[5];
+ _globals._sequenceIndexes[5] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[5], false, 17, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[5], 4, 8);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[5]);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[5], temp);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[3], SEQUENCE_TRIGGER_EXPIRE, 0, 3);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[5], SEQUENCE_TRIGGER_EXPIRE, 0, 4);
+ break;
+
+ case 3:
+ temp1 = _globals._sequenceIndexes[3];
+ _globals._sequenceIndexes[3] = _scene->_sequences.startCycle(_globals._spriteIndexes[3], false, -2);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 12);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[3], temp1);
+ break;
+
+ case 4:
+ temp = _globals._sequenceIndexes[5];
+ _globals._sequenceIndexes[5] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[5], false, 17, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[5], 10, 11);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[5]);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[5], temp);
+
+ _scene->_sequences.remove(_globals._sequenceIndexes[3]);
+ _globals._sequenceIndexes[3] = _scene->_sequences.addReverseSpriteCycle(_globals._spriteIndexes[3], false, 17, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[3], 5, -2);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 3);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[5], SEQUENCE_TRIGGER_EXPIRE, 0, 5);
+ break;
+
+ case 5:
+ temp = _globals._sequenceIndexes[3];
+ _globals._sequenceIndexes[3] = _scene->_sequences.startCycle(_globals._spriteIndexes[3], false, 3);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 3);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[3], temp);
+
+ temp = _globals._sequenceIndexes[5];
+ _globals._sequenceIndexes[5] = _scene->_sequences.startCycle(_globals._spriteIndexes[5], false, 12);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[5]);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[5], temp);
+ _scene->_sequences.addTimer(20, 6);
+ break;
+
+ case 6:
+ _scene->_sequences.setDone(_globals._sequenceIndexes[5]);
+ _globals._sequenceIndexes[5] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[5], false, 17, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[5], 13, 15);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[5]);
+
+ _scene->_sequences.remove(_globals._sequenceIndexes[3]);
+ _globals._sequenceIndexes[3] = _scene->_sequences.addReverseSpriteCycle(_globals._spriteIndexes[3], false, 17, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[3], 2, 3);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 3);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[5], SEQUENCE_TRIGGER_EXPIRE, 0, 7);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[3], SEQUENCE_TRIGGER_EXPIRE, 0, 8);
+ break;
+
+ case 7:
+ _scene->_sequences.setDone(_globals._sequenceIndexes[5]);
+ _globals._sequenceIndexes[5] = _scene->_sequences.startCycle(_globals._spriteIndexes[5], false, 16);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[5]);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[5], -1);
+ break;
+
+ case 8:
+ temp = _globals._sequenceIndexes[3];
+ _globals._sequenceIndexes[3] = _scene->_sequences.startCycle(_globals._spriteIndexes[3], false, 2);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 3);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[3], temp);
+ _scene->_sequences.addTimer(20, 9);
+ break;
+
+ case 9:
+ _scene->_sequences.setDone(_globals._sequenceIndexes[5]);
+ _globals._sequenceIndexes[3] = _scene->_sequences.startCycle(_globals._spriteIndexes[3], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 3);
+ _scene->_sequences.addTimer(48, 10);
+ break;
+
+ case 10:
+ _scene->_nextSceneId = 313;
+ break;
+
+ default:
+ break;
+ }
+}
+
+void Scene316::enter() {
+ if (_globals[kSexOfRex] == REX_MALE) {
+ _globals._spriteIndexes[1] = _scene->_sprites.addSprites(formAnimName('g', -1));
+ _globals._spriteIndexes[4] = _scene->_sprites.addSprites("*RXCL_8");
+ _globals._spriteIndexes[6] = _scene->_sprites.addSprites("*RXCL_2");
+ } else {
+ _globals._spriteIndexes[2] = _scene->_sprites.addSprites(formAnimName('g', 0));
+ _globals._spriteIndexes[5] = _scene->_sprites.addSprites("*ROXCL_8");
+ }
+
+ _globals._spriteIndexes[3] = _scene->_sprites.addSprites(formAnimName('v', 0));
+ _globals._sequenceIndexes[3] = _scene->_sequences.startCycle(_globals._spriteIndexes[3], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 12);
+
+ if (_scene->_priorSceneId == 366) {
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _game._player._playerPos = Common::Point(78, 87);
+ _game._player._facing = FACING_SOUTH;
+ _scene->_sequences.addTimer(48, 70);
+ } else if (_scene->_priorSceneId == 321) {
+ _game._player._playerPos = Common::Point(153, 102);
+ _game._player._facing = FACING_SOUTH;
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _vm->_sound->command(44);
+ int spriteIdx = (_globals[kSexOfRex] == REX_MALE) ? 1 : 2;
+ _globals._sequenceIndexes[1] = _scene->_sequences.addReverseSpriteCycle(_globals._spriteIndexes[spriteIdx], false, 6, 1, 0, 0);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 2);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[1], SEQUENCE_TRIGGER_EXPIRE, 0, 60);
+ } else if (_scene->_priorSceneId != -2)
+ _game._player._playerPos = Common::Point(291, 126);
+
+ sceneEntrySound();
+ _game.loadQuoteSet(0xFD, 0);
+}
+
+void Scene316::step() {
+ if (_game._trigger == 60) {
+ _scene->_sequences.updateTimeout(-1, _globals._sequenceIndexes[1]);
+ _game._player._visible = true;
+ _game._player._stepEnabled = true;
+ }
+
+ if (_game._trigger >= 70) {
+ switch (_game._trigger) {
+ case 70:
+ _scene->_sequences.remove(_globals._sequenceIndexes[3]);
+ _globals._sequenceIndexes[3] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[3], false, 12, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[3], 2, 6);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 3);
+
+ _globals._sequenceIndexes[6] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[6], false, 12, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[6], 1, 5);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[6]);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[3], SEQUENCE_TRIGGER_EXPIRE, 0, 71);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[6], SEQUENCE_TRIGGER_EXPIRE, 0, 72);
+ break;
+
+ case 71: {
+ int synxIdx = _globals._sequenceIndexes[3];
+ _globals._sequenceIndexes[3] = _scene->_sequences.startCycle(_globals._spriteIndexes[3], false, -2);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 3);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[3], synxIdx);
+ }
+ break;
+
+ case 72: {
+ int synxIdx = _globals._sequenceIndexes[6];
+ _globals._sequenceIndexes[6] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[6], false, 12, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[6], 6, 9);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[6]);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[6], synxIdx);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[6], SEQUENCE_TRIGGER_EXPIRE, 0, 73);
+ }
+ break;
+
+ case 73:
+ _scene->_sequences.remove(_globals._sequenceIndexes[3]);
+ _globals._sequenceIndexes[3] = _scene->_sequences.addReverseSpriteCycle(_globals._spriteIndexes[3], false, 12, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[3], 1, 5);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 12);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[6]);
+
+ _globals._sequenceIndexes[6] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[6], false, 12, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[6], 10, -2);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[6]);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[3], SEQUENCE_TRIGGER_EXPIRE, 0, 74);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[6], SEQUENCE_TRIGGER_EXPIRE, 0, 75);
+ break;
+
+ case 74: {
+ int synxIdx = _globals._sequenceIndexes[3];
+ _globals._sequenceIndexes[3] = _scene->_sequences.startCycle(_globals._spriteIndexes[3], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 12);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[3], synxIdx);
+ }
+ break;
+
+ case 75:
+ _scene->_sequences.updateTimeout(-1, _globals._sequenceIndexes[6]);
+ _game._player._stepEnabled = true;
+ _game._player._visible = true;
+ break;
+
+ default:
+ break;
+ }
+ }
+}
+
+void Scene316::preActions() {
+ if (_action.isAction(VERB_WALK_DOWN, NOUN_CORRIDOR_TO_EAST)) {
+ if (_globals[kAfterHavoc])
+ _game._player._walkOffScreenSceneId = 354;
+ else
+ _game._player._walkOffScreenSceneId = 304;
+ }
+}
+
+void Scene316::actions() {
+ if (_action.isAction(VERB_CLIMB_INTO, NOUN_AIR_VENT)) {
+ if (_globals[kSexOfRex] == REX_FEMALE)
+ handleRoxInGrate();
+ else
+ handleRexInGrate();
+ } else if (_action.isAction(VERB_WALK_UP, NOUN_RAMP) || _action.isAction(VERB_WALK_ONTO, NOUN_PLATFORM)) {
+ switch (_game._trigger) {
+ case 0:
+ if (_globals[kCityFlooded]) {
+ _vm->_dialogs->show(31623);
+ } else {
+ _vm->_sound->command(45);
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ if (_globals[kSexOfRex] == REX_MALE) {
+ _globals._sequenceIndexes[1] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[1], false, 7, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[1], -1, 7);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 2);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[1], SEQUENCE_TRIGGER_EXPIRE, 0, 1);
+ } else {
+ _globals._sequenceIndexes[2] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[2], false, 7, 1, 0, 0);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 2);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[2], SEQUENCE_TRIGGER_EXPIRE, 0, 3);
+ }
+ }
+ break;
+
+ case 1:
+ _globals._sequenceIndexes[1] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[1], false, 7, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[1], 8, -2);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 2);
+ _scene->_kernelMessages.reset();
+ if (!_game._visitedScenes.exists(321))
+ _scene->_kernelMessages.add(Common::Point(0, 0), 0x1110, 34, 0, 120, _game.getQuote(253));
+
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[1], SEQUENCE_TRIGGER_EXPIRE, 0, 2);
+ break;
+
+ case 2:
+ _globals._sequenceIndexes[1] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[1], false, 7, 0, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[1], -2, -2);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 2);
+ _scene->_sequences.addTimer(48, 4);
+ break;
+
+ case 3:
+ _globals._sequenceIndexes[2] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[2], false, 7, 0, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[2], -2, -2);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 2);
+ _scene->_sequences.addTimer(48, 4);
+ break;
+
+ case 4:
+ _scene->_nextSceneId = 321;
+ break;
+ }
+ } else if (_action.isAction(VERB_LOOK, NOUN_PLATFORM))
+ _vm->_dialogs->show(31610);
+ else if (_action.isAction(VERB_LOOK, NOUN_STRANGE_DEVICE)) {
+ if (_game._visitedScenes.exists(321))
+ _vm->_dialogs->show(31612);
+ else
+ _vm->_dialogs->show(31611);
+ } else if (_action.isAction(VERB_LOOK, NOUN_CONTROLS))
+ _vm->_dialogs->show(31613);
+ else if (_action.isAction(VERB_LOOK, NOUN_EQUIPMENT))
+ _vm->_dialogs->show(31614);
+ else if (_action.isAction(VERB_LOOK, NOUN_PANEL))
+ _vm->_dialogs->show(31615);
+ else if (_action.isAction(VERB_LOOK, NOUN_MONITOR))
+ _vm->_dialogs->show(31616);
+ else if (_action.isAction(VERB_LOOK, NOUN_RAMP))
+ _vm->_dialogs->show(31617);
+ else if (_action.isAction(VERB_LOOK, NOUN_AIR_VENT))
+ _vm->_dialogs->show(31618);
+ else if (_action.isAction(VERB_LOOK, NOUN_CORRIDOR_TO_EAST)) {
+ if (!_globals[kAfterHavoc]) {
+ if (_game._difficulty != DIFFICULTY_EASY)
+ _vm->_dialogs->show(31620);
+ else
+ _vm->_dialogs->show(31619);
+ }
+ } else if (_action.isAction(VERB_LOOK, NOUN_FLOOR))
+ _vm->_dialogs->show(31621);
+ else if (_action.isAction(VERB_LOOK, NOUN_SUPPORT))
+ _vm->_dialogs->show(31622);
+ else
+ return;
+
+ _action._inProgress = false;
+}
+
+
+/*------------------------------------------------------------------------*/
+
+Scene318::Scene318(MADSEngine *vm) : Scene3xx(vm) {
+ _dropTimer = 0;
+
+ _lastFrame = -1;
+ _animMode = -1;
+ _internCounter = -1;
+ _counter = -1;
+
+ _dialogFl = false;
+ _internTalkingFl = false;
+ _internWalkingFl = false;
+ _internVisibleFl = false;
+ _explosionFl = false;
+
+ _lastFrameCounter = 0;
+
+ _subQuote2 = "";
+}
+
+void Scene318::synchronize(Common::Serializer &s) {
+ Scene3xx::synchronize(s);
+
+ s.syncAsUint32LE(_dropTimer);
+
+ s.syncAsSint32LE(_lastFrame);
+ s.syncAsSint32LE(_animMode);
+ s.syncAsSint32LE(_internCounter);
+ s.syncAsSint32LE(_counter);
+
+ s.syncAsByte(_dialogFl);
+ s.syncAsByte(_internTalkingFl);
+ s.syncAsByte(_internWalkingFl);
+ s.syncAsByte(_internVisibleFl);
+ s.syncAsByte(_explosionFl);
+
+ s.syncAsUint32LE(_lastFrameCounter);
+
+ s.syncString(_subQuote2);
+}
+
+void Scene318::setup() {
+ setPlayerSpritesPrefix();
+ setAAName();
+}
+
+void Scene318::handleDialog() {
+ if (!_game._trigger) {
+ _game._player._stepEnabled = false;
+ handleRexDialogs(_action._activeAction._verbId);
+ } else if (_game._trigger == 2) {
+ int synxIdx = _globals._sequenceIndexes[2];
+ _globals._sequenceIndexes[2] = _scene->_sequences.startCycle(_globals._spriteIndexes[2], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 1);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[2], Common::Point(142, 121));
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[2], synxIdx);
+ _vm->_sound->command(3);
+ _scene->_userInterface.setup(kInputLimitedSentences);
+ _game._player._stepEnabled = true;
+ } else {
+ if (_action._activeAction._verbId < 0x19C)
+ _dialog1.write(_action._activeAction._verbId, false);
+
+ switch (_action._activeAction._verbId) {
+ case 0x191:
+ handleInternDialog(0x19E, 2, 9999999);
+ _dialog1.write(0x192, true);
+ break;
+
+ case 0x192:
+ handleInternDialog(0x1A0, 5, 9999999);
+ _dialog1.write(0x193, true);
+ break;
+
+ case 0x193:
+ handleInternDialog(0x1A5, 4, 9999999);
+ _dialog1.write(0x194, true);
+ break;
+
+ case 0x194:
+ handleInternDialog(0x1A9, 6, 9999999);
+ _dialog1.write(0x195, true);
+ _dialog1.write(0x196, true);
+ _dialog1.write(0x19D, false);
+ break;
+
+ case 0x195:
+ handleInternDialog(0x1AF, 7, 9999999);
+ if (!_dialog1.read(0x196))
+ _dialog1.write(0x197, true);
+ break;
+
+ case 0x196:
+ handleInternDialog(0x1B6, 5, 9999999);
+ if (!_dialog1.read(0x195))
+ _dialog1.write(0x197, true);
+ break;
+
+ case 0x197:
+ handleInternDialog(0x1BB, 5, 9999999);
+ break;
+
+ case 0x198:
+ handleInternDialog(0x1C0, 5, 9999999);
+ _dialog1.write(0x19A, true);
+ break;
+
+ case 0x199:
+ handleInternDialog(0x1C5, 3, 9999999);
+ break;
+
+ case 0x19A:
+ handleInternDialog(0x1C8, 5, 9999999);
+ _dialog1.write(0x19B, true);
+ break;
+
+ case 0x19B:
+ handleInternDialog(0x1CD, 3, 9999999);
+ break;
+
+ case 0x19C:
+ case 0x19D:
+ _scene->_sequences.remove(_globals._sequenceIndexes[2]);
+ _globals._sequenceIndexes[2] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[2], false, 8, 1, 0, 0);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 1);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[2], Common::Point(142, 121));
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[2], 6, 8);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[2], SEQUENCE_TRIGGER_EXPIRE, 0, 2);
+
+ _dialogFl = false;
+ handleInternDialog(0x1D0, 1, 120);
+ if (_dialog1.read(0) || (_action._activeAction._verbId == 0x19D)) {
+ _explosionFl = true;
+ _internCounter = 3420;
+ }
+ break;
+ }
+
+ if (_action._activeAction._verbId < 0x19C) {
+ _dialog1.start();
+ _game._player._stepEnabled = true;
+ }
+
+ }
+}
+
+void Scene318::handleRexDialogs(int quote) {
+ _scene->_kernelMessages.reset();
+
+ Common::String curQuote = _game.getQuote(quote);
+ if (_vm->_font->getWidth(curQuote, _scene->_textSpacing) > 200) {
+ Common::String subQuote1;
+ _game.splitQuote(curQuote, subQuote1, _subQuote2);
+ _scene->_kernelMessages.add(Common::Point(138, 59), 0x1110, 32, 0, 240, subQuote1);
+ _scene->_kernelMessages.add(Common::Point(138, 73), 0x1110, 32, 1, 180, _subQuote2);
+ } else
+ _scene->_kernelMessages.add(Common::Point(138, 73), 0x1110, 32, 1, 120, curQuote);
+}
+
+void Scene318::handleInternDialog(int quoteId, int quoteNum, uint32 timeout) {
+ int height = quoteNum * 14;
+ int posY;
+ if (height < 85)
+ posY = 87 - height;
+ else
+ posY = 2;
+
+ int curQuoteId= quoteId;
+
+ int maxWidth = 0;
+ for (int i = 0; i < quoteNum; i++) {
+ maxWidth = MAX(maxWidth, _vm->_font->getWidth(_game.getQuote(curQuoteId), -1));
+ curQuoteId++;
+ }
+
+ int posX = MIN(319 - maxWidth, 178 - (maxWidth >> 1));
+ curQuoteId = quoteId;
+
+ _scene->_kernelMessages.reset();
+ _internTalkingFl = true;
+
+ for (int i = 0; i < quoteNum; i++) {
+ _game._triggerSetupMode = SEQUENCE_TRIGGER_DAEMON;
+ _scene->_sequences.addTimer(180, 63);
+ _scene->_kernelMessages.add(Common::Point(posX, posY), 0xFDFC, 0, 0, timeout, _game.getQuote(curQuoteId));
+ posY += 14;
+ curQuoteId++;
+ }
+}
+
+void Scene318::enter() {
+ _globals._spriteIndexes[1] = _scene->_sprites.addSprites(formAnimName('x', 0));
+ _globals._spriteIndexes[3] = _scene->_sprites.addSprites(formAnimName('k', -1));
+
+ if (_globals[kAfterHavoc]) {
+ _scene->loadAnimation(formAnimName('f', -1));
+ _scene->_activeAnimation->_resetFlag = true;
+ } else if (!_globals[kHasSeenProfPyro]) {
+ _scene->_hotspots.activate(NOUN_PROFESSORS_GURNEY, false);
+ _scene->_hotspots.activate(NOUN_PROFESSOR, false);
+ _scene->_hotspots.activate(NOUN_TAPE_PLAYER, false);
+ }
+
+ if (_game._objects.isInRoom(OBJ_SCALPEL)) {
+ _globals._sequenceIndexes[3] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[3], false, 6, 0, 0, 120);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 4);
+ _scene->_dynamicHotspots.add(NOUN_SCALPEL, VERB_TAKE, _globals._sequenceIndexes[3], Common::Rect(0, 0, 0, 0));
+ }
+
+ if (_scene->_priorSceneId == 357)
+ _game._player._playerPos = Common::Point(15, 110);
+ else if (_scene->_priorSceneId != -2)
+ _game._player._playerPos = Common::Point(214, 152);
+
+ _dialog1.setup(0x47, 0x191, 0x192, 0x193, 0x194, 0x195, 0x196, 0x197, 0x198, 0x199, 0x19A, 0x19B, 0x19C, 0x19D, 0);
+
+ if (!_game._visitedScenes._sceneRevisited) {
+ _dialog1.set(0x191, 0x198, 0x199, 0x19C, 0);
+ if (_game._widepipeCtr >= 2)
+ _dialog1.write(0x19D, true);
+ }
+
+ if (_scene->_priorSceneId == 307) {
+ _game._player._visible = false;
+ _game._player._stepEnabled = false;
+ _scene->loadAnimation(formAnimName('a', -1), 60);
+ _animMode = 1;
+ }
+
+ _lastFrame = 0;
+ _scene->_hotspots.activate(NOUN_INTERN, false);
+
+ if (_scene->_priorSceneId != -2) {
+ _dialogFl = false;
+ _internWalkingFl = false;
+ _counter= 0;
+ _internCounter= 0;
+ _internVisibleFl = true;
+ _explosionFl = false;
+ }
+
+ _game.loadQuoteSet(0x18C, 0x18D, 0x18E, 0x18F, 0x191, 0x192, 0x193, 0x194, 0x195, 0x196,
+ 0x197, 0x198, 0x199, 0x19A, 0x19B, 0x19C, 0x19E, 0x19E, 0x1A0, 0x1A1, 0x1A2, 0x1A3,
+ 0x1A4, 0x1A5, 0x1A6, 0x1A7, 0x1A8, 0x1A9, 0x1AA, 0x1AB, 0x1AC, 0x1AD, 0x1AE, 0x1AF,
+ 0x1B0, 0x1B1, 0x1B2, 0x1B3, 0x1B4, 0x1B5, 0x1B6, 0x1B7, 0x1B8, 0x1B9, 0x1BA, 0x1BB,
+ 0x1BC, 0x1BD, 0x1BE, 0x1BF, 0x1C0, 0x1C1, 0x1C2, 0x1C3, 0x1C4, 0x1C5, 0x1C6, 0x1C7,
+ 0x1C8, 0x1C9, 0x1CA, 0x1CB, 0x1CC, 0x1CD, 0x1CE, 0x1CF, 0x1D0, 0x1D1, 0x1D2, 0x1D3,
+ 0x190, 0x19D, 0);
+
+ if ((_scene->_priorSceneId== -2) || (((_scene->_priorSceneId == 318) || (_scene->_priorSceneId == -1)) && (!_globals[kAfterHavoc]))) {
+ if (!_globals[kAfterHavoc]) {
+ _game._player._visible = false;
+ _globals._spriteIndexes[2] = _scene->_sprites.addSprites(formAnimName('g', -1));
+ _animMode = 2;
+
+ if (_game._visitedScenes.exists(319) || !_internVisibleFl) {
+ _internVisibleFl = false;
+ _dialogFl = false;
+ } else {
+ _scene->loadAnimation(formAnimName('b', -1), 61);
+ _scene->_hotspots.activate(NOUN_INTERN, true);
+ }
+
+ if (_dialogFl) {
+ _dialog1.start();
+ _globals._sequenceIndexes[2] = _scene->_sequences.startCycle(_globals._spriteIndexes[2], false, 8);
+ } else
+ _globals._sequenceIndexes[2] = _scene->_sequences.startCycle(_globals._spriteIndexes[2], false, 1);
+
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[2], Common::Point(142, 121));
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 1);
+ }
+ }
+
+ if (_scene->_priorSceneId == 319) {
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _animMode = 4;
+ if (!_globals[kHasSeenProfPyro]) {
+ _scene->loadAnimation(formAnimName('d', -1), 64);
+ _globals[kHasSeenProfPyro] = true;
+ } else {
+ _scene->loadAnimation(formAnimName('e', -1), 64);
+ }
+ }
+
+ _internTalkingFl = false;
+ _vm->_palette->setEntry(252, 63, 63, 10);
+ _vm->_palette->setEntry(253, 45, 45, 05);
+
+ _dropTimer = _vm->_game->_scene._frameStartTime;
+ sceneEntrySound();
+
+ if (_dialogFl)
+ _vm->_sound->command(15);
+}
+
+void Scene318::step() {
+ if ((_scene->_activeAnimation != nullptr) && (_animMode == 2)) {
+ if (_lastFrame != _scene->_activeAnimation->getCurrentFrame()) {
+ _lastFrame = _scene->_activeAnimation->getCurrentFrame();
+ int nextFrame = -1;
+
+ switch (_lastFrame) {
+ case 20:
+ case 30:
+ case 40:
+ case 50:
+ case 60:
+ case 70:
+ case 80:
+ case 90:
+ case 100:
+ case 110:
+ case 120:
+ case 130:
+ case 140:
+ case 149:
+ if (_internWalkingFl) {
+ nextFrame = 149;
+ } else if (_internTalkingFl) {
+ nextFrame = 149;
+ } else if (_lastFrame == 149) {
+ nextFrame = 4;
+ }
+ break;
+
+ case 151:
+ if (_internWalkingFl)
+ nextFrame = 183;
+ break;
+
+ case 167:
+ case 184:
+ if (_internWalkingFl) {
+ nextFrame = 184;
+ } else if (!_internTalkingFl) {
+ nextFrame = 0;
+ } else if (_vm->getRandomNumber(1, 100) <= 50) {
+ nextFrame = 151;
+ } else {
+ nextFrame = 167;
+ }
+
+ if (nextFrame == 184) {
+ handleInternDialog(0x1D1, 3, 240);
+ _scene->_hotspots.activate(NOUN_INTERN, false);
+ _internVisibleFl = false;
+ }
+ break;
+ }
+
+ if ((nextFrame >= 0) && (nextFrame != _scene->_activeAnimation->getCurrentFrame())) {
+ _scene->_activeAnimation->setCurrentFrame(nextFrame);
+ _lastFrame = nextFrame;
+ }
+ }
+ }
+
+ switch (_game._trigger) {
+ case 60:
+ _vm->_sound->command(3);
+ _animMode = 2;
+ _scene->_reloadSceneFlag = true;
+ break;
+
+ case 61:
+ _counter = 0;
+ break;
+
+ case 62:
+ _scene->_nextSceneId = 319;
+ break;
+
+ case 63:
+ _internTalkingFl = false;
+ break;
+
+ case 64:
+ _vm->_sound->command(3);
+ _scene->_nextSceneId = 307;
+ break;
+ }
+
+ uint32 tmpFrame = _vm->_events->getFrameCounter();
+ long diffFrame = tmpFrame - _lastFrameCounter;
+ _lastFrameCounter = tmpFrame;
+
+ if ((_animMode == 2) && !_internVisibleFl && _game._player._stepEnabled) {
+ if ((diffFrame >= 0) && (diffFrame <= 4))
+ _counter += diffFrame;
+ else
+ _counter++;
+
+ int extraCounter = _game._objects.isInInventory(OBJ_SCALPEL) ? 900 : 0;
+
+ if (_counter + extraCounter >= 1800) {
+ _scene->freeAnimation();
+ _game._player._stepEnabled = false;
+ _scene->loadAnimation(formAnimName('c', -1), 62);
+ _animMode = 3;
+ }
+ } else if ((_animMode == 2) && _explosionFl && _internVisibleFl && !_dialogFl
+ && !_internWalkingFl && (_game._screenObjects._inputMode != 1)) {
+ if ((diffFrame >= 0) && (diffFrame <= 4))
+ _internCounter += diffFrame;
+ else
+ _internCounter++;
+
+ if (_internCounter >= 3600) {
+ _vm->_sound->command(59);
+ _vm->_screen._shakeCountdown = 20;
+ _internWalkingFl = true;
+ }
+ }
+
+ if ((_vm->_game->_scene._frameStartTime - _dropTimer) > 600) {
+ _vm->_sound->command(51);
+ _globals._sequenceIndexes[1] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[1], false, 14, 1, 0, 0);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 10);
+ _dropTimer = _vm->_game->_scene._frameStartTime;
+ }
+}
+
+void Scene318::preActions() {
+ if (_game._player._needToWalk)
+ _game._player._needToWalk = _game._player._visible;
+
+ if (_action.isAction(VERB_WALK_DOWN, NOUN_CORRIDOR_TO_WEST))
+ _game._player._walkOffScreenSceneId = 357;
+}
+
+void Scene318::actions() {
+ if (_game._screenObjects._inputMode == 1) {
+ handleDialog();
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_TALKTO, NOUN_INTERN)) {
+ switch (_game._trigger) {
+ case 0: {
+ _dialogFl = true;
+ _vm->_sound->command(15);
+ _game._player._stepEnabled = false;
+ handleRexDialogs(_vm->getRandomNumber(0x18C, 0x18E));
+
+ _scene->_sequences.remove(_globals._sequenceIndexes[2]);
+ _globals._sequenceIndexes[2] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[2], false, 8, 1, 0, 80);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 1);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[2], Common::Point(142, 121));
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[2], 6, 8);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[2], SEQUENCE_TRIGGER_EXPIRE, 0, 2);
+ }
+ break;
+
+ case 1:
+ _game._player._stepEnabled = true;
+ handleInternDialog(0x18F, 1, 9999999);
+ _dialog1.start();
+ break;
+
+ case 2: {
+ int oldIdx = _globals._sequenceIndexes[2];
+ _globals._sequenceIndexes[2] = _scene->_sequences.startCycle(_globals._spriteIndexes[2], false, 8);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 1);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[2], Common::Point(142, 121));
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[2], oldIdx);
+ }
+ break;
+
+ default:
+ break;
+ }
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_TAKE, NOUN_SCALPEL) && (_game._objects.isInRoom(OBJ_SCALPEL) || _game._trigger)) {
+ switch (_game._trigger) {
+ case 0:
+ _game._player._stepEnabled = false;
+ _scene->_sequences.remove(_globals._sequenceIndexes[2]);
+ _globals._sequenceIndexes[2] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[2], false, 8, 2, 0, 80);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 1);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[2], Common::Point(142, 121));
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[2], 2, 5);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[2], SEQUENCE_TRIGGER_SPRITE, 5, 1);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[2], SEQUENCE_TRIGGER_EXPIRE, 0, 2);
+ break;
+
+ case 1:
+ if (_internVisibleFl)
+ handleInternDialog(0x190, 1, 120);
+ else {
+ _game._objects.addToInventory(OBJ_SCALPEL);
+ _vm->_dialogs->showItem(OBJ_SCALPEL, 0x7C5D);
+ _scene->_sequences.remove(_globals._sequenceIndexes[3]);
+ }
+ break;
+
+ case 2: {
+ int oldIdx = _globals._sequenceIndexes[2];
+ _globals._sequenceIndexes[2] = _scene->_sequences.startCycle(_globals._spriteIndexes[2], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 1);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[2], Common::Point(142, 121));
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[2], oldIdx);
+ _scene->_sequences.addTimer(60, 3);
+ }
+ break;
+
+ case 3:
+ _game._player._stepEnabled = true;
+ break;
+ }
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_game._player._visible) {
+ if (_action.isAction(VERB_WALK_DOWN, NOUN_CORRIDOR_TO_SOUTH)) {
+ _scene->_nextSceneId = 407;
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_TAKE, NOUN_TAPE_PLAYER)) {
+ if (_game._objects.isInRoom(OBJ_AUDIO_TAPE)) {
+ _vm->_dialogs->showItem(OBJ_AUDIO_TAPE, 0x7C5B);
+ _game._objects.addToInventory(OBJ_AUDIO_TAPE);
+ } else
+ _vm->_dialogs->show(31834);
+
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_LOOK, NOUN_TAPE_PLAYER)) {
+ if (_game._objects.isInRoom(OBJ_AUDIO_TAPE))
+ _vm->_dialogs->show(31833);
+ else
+ _vm->_dialogs->show(31834);
+
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_WALK_INTO, NOUN_DOCTORS_OFFICE)) {
+ _vm->_dialogs->show(31831);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_LOOK, NOUN_GURNEY)) {
+ _vm->_dialogs->show(31823);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_LOOK, NOUN_INSTRUMENT_TABLE)) {
+ _vm->_dialogs->show(31825);
+ _action._inProgress = false;
+ return;
+ }
+ } else { // Not visible
+ if (_action.isAction(VERB_LOOK, NOUN_GURNEY)) {
+ _vm->_dialogs->show(31822);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_LOOK, NOUN_INSTRUMENT_TABLE)) {
+ _vm->_dialogs->show(31824);
+ _action._inProgress = false;
+ return;
+ }
+ }
+
+ if (_action.isAction(VERB_LOOK, NOUN_WALL))
+ _vm->_dialogs->show(31810);
+ else if (_action.isAction(VERB_LOOK, NOUN_FLOOR))
+ _vm->_dialogs->show(31811);
+ else if (_action.isAction(VERB_LOOK, NOUN_CORRIDOR_TO_WEST))
+ _vm->_dialogs->show(31812);
+ else if (_action.isAction(VERB_LOOK, NOUN_CORRIDOR_TO_SOUTH))
+ _vm->_dialogs->show(31813);
+ else if (_action.isAction(VERB_LOOK, NOUN_FAUCET))
+ _vm->_dialogs->show(31814);
+ else if (_action.isAction(VERB_LOOK, NOUN_SINK))
+ _vm->_dialogs->show(31815);
+ else if (_action.isAction(VERB_LOOK, NOUN_CONVEYOR_BELT))
+ _vm->_dialogs->show(31816);
+ else if (_action.isAction(VERB_LOOK, NOUN_LARGE_BLADE))
+ _vm->_dialogs->show(31817);
+ else if (_action.isAction(VERB_LOOK, NOUN_MONITOR))
+ _vm->_dialogs->show(31818);
+ else if (_action.isAction(VERB_LOOK, NOUN_CABINETS))
+ _vm->_dialogs->show(31819);
+ else if (_action.isAction(VERB_LOOK, NOUN_EQUIPMENT))
+ _vm->_dialogs->show(31820);
+ else if (_action.isAction(VERB_LOOK, NOUN_SHELF))
+ _vm->_dialogs->show(31821);
+ else if (_action.isAction(VERB_OPEN, NOUN_CABINETS))
+ _vm->_dialogs->show(31829);
+ else if (_action.isAction(VERB_LOOK, NOUN_INTERN))
+ _vm->_dialogs->show(31830);
+ else if (_action.isAction(VERB_LOOK, NOUN_PROFESSOR))
+ _vm->_dialogs->show(31832);
+ else if (_action.isAction(VERB_LOOK, NOUN_PROFESSORS_GURNEY))
+ _vm->_dialogs->show(31836);
+ else if (_action._lookFlag) {
+ if (_game._player._visible || _game._objects.isInInventory(OBJ_SCALPEL))
+ _vm->_dialogs->show(31828);
+ else if (_internVisibleFl)
+ _vm->_dialogs->show(31826);
+ else
+ _vm->_dialogs->show(31827);
+ } else
+ return;
+
+ _action._inProgress = false;
+}
+
+/*------------------------------------------------------------------------*/
+
+Scene319::Scene319(MADSEngine *vm) : Scene3xx(vm) {
+ _animMode = -1;
+ _animFrame = -1;
+ _nextAction1 = -1;
+ _nextAction2 = -1;
+ _slacheMode = -1;
+ _slacheTopic = -1;
+ _slachePosY = -1;
+
+ _slacheTalkingFl = false;
+ _slacheReady = false;
+ _slacheInitFl = false;
+
+ _subQuote2 = "";
+}
+
+void Scene319::synchronize(Common::Serializer &s) {
+ Scene3xx::synchronize(s);
+
+ s.syncAsUint32LE(_animMode);
+ s.syncAsUint32LE(_animFrame);
+ s.syncAsUint32LE(_nextAction1);
+ s.syncAsUint32LE(_nextAction2);
+ s.syncAsUint32LE(_slacheMode);
+ s.syncAsUint32LE(_slacheTopic);
+ s.syncAsUint32LE(_slachePosY);
+
+ s.syncAsByte(_slacheTalkingFl);
+ s.syncAsByte(_slacheReady);
+ s.syncAsByte(_slacheInitFl);
+
+ s.syncString(_subQuote2);
+}
+
+void Scene319::setup() {
+ setPlayerSpritesPrefix();
+ setAAName();
+}
+
+void Scene319::handleRexDialogues(int quote) {
+ _scene->_kernelMessages.reset();
+
+ Common::String curQuote = _game.getQuote(quote);
+ if (_vm->_font->getWidth(curQuote, _scene->_textSpacing) > 200) {
+ Common::String subQuote1;
+ _game.splitQuote(curQuote, subQuote1, _subQuote2);
+ _scene->_kernelMessages.add(Common::Point(160, 106), 0x1110, 32, 0, 120, subQuote1);
+ _scene->_kernelMessages.add(Common::Point(160, 120), 0x1110, 32, 1, 120, _subQuote2);
+ } else
+ _scene->_kernelMessages.add(Common::Point(160, 120), 0x1110, 32, 1, 120, curQuote);
+}
+
+void Scene319::handleSlacheDialogs(int quoteId, int counter, uint32 timer) {
+ int curQuote = quoteId;
+ int posY = 5 + (_slachePosY * 14);
+
+ for (int count = 0; count < counter; count++, curQuote++) {
+ _scene->_kernelMessages.add(Common::Point(8, posY), 0xFDFC, 0, 0, timer, _game.getQuote(curQuote));
+ posY += 14;
+ }
+}
+
+void Scene319::enter() {
+ _globals._spriteIndexes[5] = _scene->_sprites.addSprites(formAnimName('e', 0));
+ _globals._spriteIndexes[0] = _scene->_sprites.addSprites(formAnimName('a', 0));
+ _globals._spriteIndexes[1] = _scene->_sprites.addSprites(formAnimName('a', 1));
+ _globals._spriteIndexes[2] = _scene->_sprites.addSprites(formAnimName('a', 2));
+ _globals._spriteIndexes[3] = _scene->_sprites.addSprites(formAnimName('a', 3));
+ _globals._spriteIndexes[4] = _scene->_sprites.addSprites(formAnimName('k', -1));
+
+ if (!_game._objects.isInInventory(OBJ_SCALPEL)) {
+ _globals._sequenceIndexes[4] = _scene->_sequences.startCycle(_globals._spriteIndexes[4], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[4], 1);
+ }
+
+ _globals._sequenceIndexes[5] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[5], false, 18, 0, 0, 300);
+ _globals._sequenceIndexes[2] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[2], false, 67, 0, 0, 377);
+ _globals._sequenceIndexes[3] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[3], false, 173, 0, 0, 233);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 14);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 14);
+
+ _globals._sequenceIndexes[0] = _scene->_sequences.startCycle(_globals._spriteIndexes[0], false, 1);
+ _globals._sequenceIndexes[1] = _scene->_sequences.startCycle(_globals._spriteIndexes[1], false, 1);
+
+ _dialog1.setup(0x43, 0x165, 0x166, 0x167, 0x168, 0x169, 0x16A, 0);
+ _dialog2.setup(0x44, 0x171, 0x172, 0x173, 0x174, 0x175, 0x176, 0);
+ _dialog3.setup(0x45, 0x17D, 0x17E, 0x17F, 0x180, 0x181, 0x182, 0x183, 0);
+
+ if (_scene->_priorSceneId != -2) {
+ _dialog1.set(0x165, 0x166, 0x167, 0x168, 0);
+ _dialog2.set(0x171, 0x172, 0x173, 0x174, 0);
+ _dialog3.set(0x17D, 0x17E, 0x17F, 0x180, 0);
+ }
+
+ _game.loadQuoteSet(0x15F, 0x160, 0x161, 0x162, 0x163, 0x164, 0x16B, 0x16C, 0x16D,
+ 0x16E, 0x16F, 0x170, 0x177, 0x178, 0x178, 0x17A, 0x17B, 0x17C, 0x165, 0x166,
+ 0x167, 0x168, 0x169, 0x16A, 0x171, 0x172, 0x173, 0x174, 0x175, 0x176, 0x17D,
+ 0x17E, 0x17F, 0x180, 0x181, 0x182, 0x183, 0x184, 0x185, 0x186, 0x187, 0x188,
+ 0x189, 0x18A, 0x18B, 0);
+
+ _vm->_palette->setEntry(252, 63, 30, 2);
+ _vm->_palette->setEntry(253, 45, 15, 1);
+
+ _slachePosY = 0;
+ _slacheInitFl = false;
+ _slacheTalkingFl = false;
+ _slacheReady = false;
+ _animFrame = 0;
+
+ _scene->loadAnimation(formAnimName('b', 0));
+
+ if (_scene->_priorSceneId != -2) {
+ _animMode = 1;
+ _nextAction1 = 2;
+ _nextAction2 = 2;
+ _slacheMode = 1;
+ _slacheTopic = 1;
+ _slacheInitFl = true;
+
+ if (_globals[kRexHasMetSlache]) {
+ handleSlacheDialogs(0x18A, 2, 9999999);
+ _slachePosY = 3;
+ } else {
+ handleSlacheDialogs(0x186, 4, 9999999);
+ _slachePosY = 5;
+ }
+ }
+
+ switch (_slacheTopic) {
+ case 1:
+ handleSlacheDialogs(0x15F, 2, 9999999);
+ _dialog1.start();
+ break;
+
+ case 2:
+ handleSlacheDialogs(0x16B, 2, 9999999);
+ _dialog2.start();
+ break;
+
+ case 3:
+ handleSlacheDialogs(0x177, 2, 9999999);
+ _dialog3.start();
+ break;
+
+ default:
+ break;
+ }
+
+ _slachePosY = 0;
+ sceneEntrySound();
+}
+
+void Scene319::step() {
+ if (_scene->_activeAnimation == nullptr)
+ return;
+
+ if (_animFrame != _scene->_activeAnimation->getCurrentFrame()) {
+ _animFrame = _scene->_activeAnimation->getCurrentFrame();
+ int nextFrame = -1;
+ if (_animMode == 1) {
+ switch (_animFrame) {
+ case 6:
+ _slacheTalkingFl = true;
+ break;
+
+ case 29:
+ _slacheReady = true;
+ break;
+
+ case 39:
+ if (_slacheInitFl) {
+ _slacheInitFl = false;
+ if (_nextAction1 == 2)
+ nextFrame = 0;
+ } else if (_nextAction1 == 2)
+ _nextAction1 = 1;
+ break;
+
+ case 50:
+ case 60:
+ case 70:
+ case 85:
+ if (_nextAction1 == 2)
+ nextFrame = 0;
+ else if (_nextAction1 == 3) {
+ nextFrame = 85;
+ _slacheTalkingFl = true;
+ } else if (_animFrame == 85) {
+ if (!_game._player._stepEnabled)
+ _slacheTalkingFl = true;
+ nextFrame = 40;
+ }
+ break;
+
+ case 115:
+ _slacheReady = true;
+ break;
+
+ case 129:
+ if (_nextAction1 == 3) {
+ nextFrame = 115;
+ if (!_game._player._stepEnabled)
+ _slacheTalkingFl = true;
+ }
+ break;
+
+ case 145:
+ nextFrame = 40;
+ break;
+
+ default:
+ break;
+ }
+
+ if ((_animFrame > 40) && (_animFrame < 85) && (nextFrame < 0)) {
+ switch (_nextAction1) {
+ case 4:
+ _animFrame = 0;
+ _scene->freeAnimation();
+ _animMode = 2;
+ _scene->loadAnimation(formAnimName('b', 3), 70);
+ break;
+
+ case 5:
+ _animFrame = 0;
+ _scene->freeAnimation();
+ _animMode = 3;
+ _scene->loadAnimation(formAnimName('b', 4), 71);
+ break;
+
+ case 6:
+ _animFrame = 0;
+ _scene->freeAnimation();
+ _animMode = 4;
+ _scene->loadAnimation(formAnimName('b', 5), 72);
+ break;
+
+ default:
+ break;
+ }
+
+ if (!_animFrame) {
+ _scene->_sequences.remove(_globals._sequenceIndexes[0]);
+ _scene->_sequences.remove(_globals._sequenceIndexes[1]);
+
+ for (int i = 0; i <= 1; i++) {
+ _globals._sequenceIndexes[i] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[i], false, 8, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[i], 1, 7);
+ }
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[0], SEQUENCE_TRIGGER_EXPIRE, 0, 73);
+ }
+ }
+ }
+
+ if (_animMode == 2) {
+ if (_animFrame == 13)
+ _vm->_screen._shakeCountdown = 40;
+
+ if (_animFrame == 16)
+ _vm->_screen._shakeCountdown = 1;
+ }
+
+ if (_animMode == 3) {
+ if (_animFrame == 11)
+ _vm->_screen._shakeCountdown = 60;
+
+ if (_animFrame == 18)
+ _vm->_screen._shakeCountdown = 1;
+ }
+
+ if ((_animMode == 4) && (_animFrame == 16))
+ _vm->_screen._shakeCountdown = 80;
+
+ if ((nextFrame >= 0) && (nextFrame != _scene->_activeAnimation->getCurrentFrame())) {
+ _scene->_activeAnimation->setCurrentFrame(nextFrame);
+ _animFrame = nextFrame;
+ }
+ }
+
+ switch (_game._trigger) {
+ case 70:
+ case 71:
+ _animMode = 1;
+ _nextAction1 = _nextAction2;
+ _animFrame = 0;
+ _scene->freeAnimation();
+ _scene->loadAnimation(formAnimName('b', 0));
+ if (_nextAction1 == 3)
+ _scene->_activeAnimation->setCurrentFrame(85);
+ else if (_nextAction1 == 1)
+ _scene->_activeAnimation->setCurrentFrame(40);
+
+ _animFrame = _scene->_activeAnimation->getCurrentFrame();
+ _slacheTalkingFl = true;
+ _vm->_screen._shakeCountdown = 1;
+
+ for (int i = 0; i <= 1; i++) {
+ int oldIdx = _globals._sequenceIndexes[i];
+ _scene->_sequences.remove(_globals._sequenceIndexes[i]);
+ _globals._sequenceIndexes[i] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[i], false, 8, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[i], 8, 13);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[i], oldIdx);
+ }
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[0], SEQUENCE_TRIGGER_EXPIRE, 0, 74);
+ break;
+
+ case 72:
+ _vm->_palette->setColorFlags(0xFF, 0, 0);
+ _vm->_palette->setColorValues(0, 0, 0);
+ _vm->_palette->fadeOut(_vm->_palette->_mainPalette, nullptr, 18, 228,
+ 248, 0, 1, 16);
+ _vm->_screen._shakeCountdown = 1;
+ _scene->_reloadSceneFlag = true;
+ break;
+
+ case 73:
+ for (int i = 0; i <= 1; i++) {
+ int oldIdx = _globals._sequenceIndexes[i];
+ _scene->_sequences.remove(_globals._sequenceIndexes[i]);
+ _globals._sequenceIndexes[i] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[i], false, 8, 0, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[i], 6, 7);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[i], oldIdx);
+ }
+ break;
+
+ case 74:
+ for (int i = 0; i <= 1; i++) {
+ int oldIdx = _globals._sequenceIndexes[i];
+ _scene->_sequences.remove(_globals._sequenceIndexes[i]);
+ _globals._sequenceIndexes[i] = _scene->_sequences.startCycle(_globals._spriteIndexes[i], false, 1);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[i], oldIdx);
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+void Scene319::actions() {
+ if (_game._trigger == 0) {
+ _game._player._stepEnabled = false;
+ handleRexDialogues(_action._activeAction._verbId);
+ } else {
+ if ((_action._activeAction._verbId == 0x165) || (_action._activeAction._verbId == 0x166)) {
+ if (_game._trigger == 1) {
+ _nextAction1 = 3;
+ _slacheTalkingFl = false;
+ _slacheMode = 1;
+ _slacheTopic = 2;
+ }
+
+ if (!_slacheTalkingFl) {
+ _scene->_sequences.addTimer(4, 2);
+ } else {
+ handleSlacheDialogs(0x16B, 2, 9999999);
+ _dialog2.start();
+ _game._player._stepEnabled = true;
+ }
+ }
+
+ if ((_action._activeAction._verbId == 0x171) || (_action._activeAction._verbId == 0x172)) {
+ if (_game._trigger == 1) {
+ _nextAction1 = 2;
+ _slacheTalkingFl = false;
+ _slacheMode = 1;
+ _slacheTopic = 3;
+ }
+
+ if (!_slacheTalkingFl) {
+ _scene->_sequences.addTimer(4, 2);
+ } else {
+ handleSlacheDialogs(0x177, 2, 9999999);
+ _dialog3.start();
+ _game._player._stepEnabled = true;
+ }
+ }
+
+ if ((_action._activeAction._verbId == 0x17D) || (_action._activeAction._verbId == 0x17E)) {
+ if (_game._trigger == 1) {
+ _nextAction1 = 3;
+ _slacheTalkingFl = false;
+ _slacheReady = false;
+ _slacheMode = 1;
+ _slacheTopic = 1;
+ }
+
+ if (!_slacheTalkingFl) {
+ _scene->_sequences.addTimer(4, 2);
+ } else {
+ if (_game._trigger == 2)
+ handleSlacheDialogs(0x184, 2, 180);
+
+ if (!_slacheReady) {
+ _scene->_sequences.addTimer(120, 3);
+ } else {
+ _globals[kRexHasMetSlache] = true;
+ _scene->_nextSceneId = 318;
+ }
+ }
+ }
+
+ if ((_action._activeAction._verbId == 0x168) || (_action._activeAction._verbId == 0x174) ||
+ (_action._activeAction._verbId == 0x180) || (_action._activeAction._verbId == 0x169) ||
+ (_action._activeAction._verbId == 0x175) || (_action._activeAction._verbId == 0x181) ||
+ (_action._activeAction._verbId == 0x16A) || (_action._activeAction._verbId == 0x176) ||
+ (_action._activeAction._verbId == 0x182) || (_action._activeAction._verbId == 0x183) ||
+ (_action._activeAction._verbId == 0x167) || (_action._activeAction._verbId == 0x173) ||
+ (_action._activeAction._verbId == 0x17F)) {
+
+ bool addDialogLine = !((_action._activeAction._verbId == 0x167) || (_action._activeAction._verbId == 0x173) ||
+ (_action._activeAction._verbId == 0x17F) || (_action._activeAction._verbId == 0x16A) ||
+ (_action._activeAction._verbId == 0x176) || (_action._activeAction._verbId == 0x182) ||
+ (_action._activeAction._verbId == 0x183));
+
+ int addVerbId = _action._activeAction._verbId + 1;
+ if ((addVerbId == 0x182) && (_game._storyMode != STORYMODE_NAUGHTY))
+ addVerbId = 0x183;
+
+ if (_slacheMode == 1) {
+ if (_game._trigger == 1) {
+ _nextAction2 = _nextAction1;
+ _nextAction1 = 4;
+ }
+
+ if (_nextAction1 != _nextAction2) {
+ _scene->_sequences.addTimer(4, 2);
+ } else {
+ Conversation *curDialog;
+ int nextDocQuote;
+ if ((_action._activeAction._verbId == 0x168) || (_action._activeAction._verbId == 0x167)) {
+ curDialog = &_dialog1;
+ nextDocQuote = 0x161;
+ } else if ((_action._activeAction._verbId == 0x174) || (_action._activeAction._verbId == 0x1753)) {
+ nextDocQuote = 0x16D;
+ curDialog = &_dialog2;
+ } else {
+ nextDocQuote = 0x179;
+ curDialog = &_dialog3;
+ }
+
+ handleSlacheDialogs(nextDocQuote, 2, 9999999);
+ if (addDialogLine) {
+ curDialog->write(_action._activeAction._verbId, false);
+ curDialog->write(addVerbId, true);
+ }
+
+ curDialog->start();
+ _game._player._stepEnabled = true;
+ _slacheMode = 2;
+ }
+ } else if (_slacheMode == 2) {
+ if (_game._trigger == 1) {
+ _nextAction2 = _nextAction1;
+ _nextAction1 = 5;
+ }
+
+ if (_nextAction1 != _nextAction2) {
+ _scene->_sequences.addTimer(4, 2);
+ } else {
+ Conversation *curDialog;
+ int nextDocQuote;
+ if ((_action._activeAction._verbId == 0x168) || (_action._activeAction._verbId == 0x169) || (_action._activeAction._verbId == 0x167)) {
+ curDialog = &_dialog1;
+ nextDocQuote = 0x163;
+ } else if ((_action._activeAction._verbId == 0x174) || (_action._activeAction._verbId == 0x175) || (_action._activeAction._verbId == 0x173)) {
+ nextDocQuote = 0x16F;
+ curDialog = &_dialog2;
+ } else {
+ nextDocQuote = 0x17B;
+ curDialog = &_dialog3;
+ }
+
+ handleSlacheDialogs(nextDocQuote, 2, 9999999);
+ if (addDialogLine) {
+ curDialog->write(_action._activeAction._verbId, false);
+ curDialog->write(addVerbId, true);
+ }
+
+ curDialog->start();
+ _game._player._stepEnabled = true;
+ _slacheMode = 3;
+ }
+ } else {
+ _nextAction2 = _nextAction1;
+ _nextAction1 = 6;
+ }
+ }
+ }
+
+ _action._inProgress = false;
+}
+
+/*------------------------------------------------------------------------*/
+
+Scene320::Scene320(MADSEngine *vm) : Scene300s(vm) {
+ _blinkFl = false;
+ _flippedFl = false;
+
+ _buttonId = -1;
+ _lastFrame = -1;
+ _leftItemId = -1;
+ _posX = -1;
+ _rightItemId = -1;
+}
+
+void Scene320::synchronize(Common::Serializer &s) {
+ Scene3xx::synchronize(s);
+
+ s.syncAsByte(_blinkFl);
+ s.syncAsByte(_flippedFl);
+
+ s.syncAsSint32LE(_buttonId);
+ s.syncAsSint32LE(_lastFrame);
+ s.syncAsSint32LE(_leftItemId);
+ s.syncAsSint32LE(_posX);
+ s.syncAsSint32LE(_rightItemId);
+}
+
+void Scene320::setup() {
+ setPlayerSpritesPrefix();
+ setAAName();
+}
+
+void Scene320::setRightView(int view) {
+ if (_rightItemId < 8) _scene->_sequences.remove(_globals._sequenceIndexes[10]);
+
+ int spriteNum;
+ switch (view) {
+ case 0:
+ spriteNum = 16;
+ break;
+
+ case 1:
+ spriteNum = 14;
+ break;
+
+ case 2:
+ spriteNum = 17;
+ break;
+
+ case 3:
+ spriteNum = 15;
+ break;
+
+ default:
+ spriteNum = view + 6;
+ break;
+ }
+
+ if (view != 8) {
+ _globals._sequenceIndexes[10] = _scene->_sequences.startCycle(_globals._spriteIndexes[spriteNum], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[10], 0);
+ }
+
+ _globals[kRightView320] = _rightItemId = view;
+}
+
+void Scene320::setLeftView(int view) {
+ if (_leftItemId < 10)
+ _scene->_sequences.remove(_globals._sequenceIndexes[0]);
+
+ if (view != 10) {
+ _globals._sequenceIndexes[0] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[view], false, 6, 0, 0, 18);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[0], 0);
+ if (!_blinkFl)
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[0], 2, 2);
+ }
+
+ _leftItemId = view;
+}
+
+void Scene320::handleButtons() {
+ switch(_action._activeAction._objectNameId) {
+ case 0x2DD:
+ _buttonId = 5;
+ break;
+
+ case 0x2DE:
+ _buttonId = 4;
+ break;
+
+ case 0x2E0:
+ _buttonId = 6;
+ break;
+
+ case 0x2E1:
+ _buttonId = 7;
+ break;
+
+ case 0x2E2:
+ _buttonId = 8;
+ break;
+
+ case 0x2E3:
+ _buttonId = 9;
+ break;
+
+ case 0x2E4:
+ _buttonId = 10;
+ break;
+
+ case 0x2E5:
+ _buttonId = 11;
+ break;
+
+ case 0x2E6:
+ _buttonId = 12;
+ break;
+
+ case 0x2E7:
+ _buttonId = 13;
+ break;
+
+ case 0x2E8:
+ _buttonId = 0;
+ break;
+
+ case 0x2E9:
+ _buttonId = 1;
+ break;
+
+ case 0x2EA:
+ _buttonId = 2;
+ break;
+
+ case 0x2EB:
+ _buttonId = 3;
+ break;
+
+ default:
+ break;
+ }
+
+ if (_buttonId <= 3) {
+ _posX = (8 * _buttonId) - 2;
+ _flippedFl = true;
+ } else if (_buttonId <= 5) {
+ _posX = (13 * _buttonId) - 14;
+ _flippedFl = true;
+ } else {
+ _posX = (8 * _buttonId) + 98;
+ _flippedFl = false;
+ }
+}
+
+void Scene320::enter() {
+ _blinkFl = true;
+ _rightItemId = 8;
+ _leftItemId = 10;
+ _lastFrame = 0;
+
+ for (int i = 0; i < 10; i++)
+ _globals._spriteIndexes[i] = _scene->_sprites.addSprites(formAnimName('M', i));
+
+ for (int i = 0; i < 8; i++)
+ _globals._spriteIndexes[10 + i] = _scene->_sprites.addSprites(formAnimName('N', i));
+
+ _globals._spriteIndexes[18] = _scene->_sprites.addSprites("*REXHAND");
+ _game._player._visible = false;
+
+ setRightView(_globals[kRightView320]);
+ setLeftView(0);
+
+ _vm->_palette->setEntry(252, 63, 30, 20);
+ _vm->_palette->setEntry(253, 45, 15, 10);
+
+ sceneEntrySound();
+}
+
+void Scene320::step() {
+ if (_scene->_activeAnimation != nullptr) {
+ if (_lastFrame != _scene->_activeAnimation->getCurrentFrame()) {
+ _lastFrame = _scene->_activeAnimation->getCurrentFrame();
+ switch (_lastFrame) {
+ case 95:
+ _blinkFl = true;
+ setLeftView(9);
+ _vm->_sound->command(41);
+ break;
+
+ case 139:
+ _blinkFl = false;
+ setLeftView(9);
+ break;
+
+ case 191:
+ _scene->_kernelMessages.add(Common::Point(1, 1), 0xFDFC, 0, 0, 60, _game.getQuote(0xFE));
+ break;
+
+ case 417:
+ case 457:
+ _vm->_screen._shakeCountdown = 40;
+ _vm->_sound->command(59);
+ break;
+
+ case 430:
+ _blinkFl = true;
+ setLeftView(4);
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+
+ if (_game._trigger == 70) {
+ _globals[kAfterHavoc] = true;
+ _globals[kTeleporterRoom + 1] = 351;
+ _scene->_nextSceneId = 361;
+ }
+}
+
+void Scene320::actions() {
+ if (_action._lookFlag)
+ _vm->_dialogs->show(32011);
+ else if ((_action.isAction(VERB_PRESS) || _action.isAction(VERB_PUSH)) &&
+ (_action.isObject(NOUN_LEFT_1_KEY) || _action.isObject(NOUN_LEFT_2_KEY) || _action.isObject(NOUN_LEFT_3_KEY) || _action.isObject(NOUN_LEFT_4_KEY) ||
+ _action.isObject(NOUN_GREEN_BUTTON) || _action.isObject(NOUN_RED_BUTTON) || _action.isObject(NOUN_RIGHT_1_KEY) || _action.isObject(NOUN_RIGHT_2_KEY) ||
+ _action.isObject(NOUN_RIGHT_3_KEY) || _action.isObject(NOUN_RIGHT_4_KEY) || _action.isObject(NOUN_RIGHT_5_KEY) || _action.isObject(NOUN_RIGHT_6_KEY) ||
+ _action.isObject(NOUN_RIGHT_7_KEY) || _action.isObject(NOUN_RIGHT_8_KEY)
+ )) {
+ switch (_game._trigger) {
+ case 0:
+ _game._player._stepEnabled = false;
+ handleButtons();
+ _globals._sequenceIndexes[18] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[18], _flippedFl, 4, 2, 0, 0);
+ _scene->_sequences.setScale(_globals._sequenceIndexes[18], 60);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[18], Common::Point(_posX, 170));
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[18], 0);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[18], SEQUENCE_TRIGGER_LOOP, 0, 1);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[18], SEQUENCE_TRIGGER_EXPIRE, 0, 2);
+ break;
+
+ case 1:
+ if (_buttonId >= 6) {
+ _vm->_sound->command(60);
+ setRightView(_buttonId - 6);
+ }
+ if (_buttonId == 4) {
+ _vm->_sound->command(38);
+ if (_leftItemId == 3)
+ setLeftView(0);
+ else
+ setLeftView(3);
+ }
+ if (_buttonId == 5) {
+ _vm->_sound->command(38);
+ if (_leftItemId == 1)
+ setLeftView(2);
+ else
+ setLeftView(1);
+ }
+ if (_buttonId <= 3) {
+ _vm->_sound->command(60);
+ setLeftView(_buttonId + 5);
+ }
+ break;
+
+ case 2:
+ _game._player._stepEnabled = true;
+ if (_buttonId == 5) {
+ if (_leftItemId == 2) {
+ _game._player._stepEnabled = false;
+ setRightView(8);
+ setLeftView(10);
+ _scene->_kernelMessages.reset();
+ _scene->resetScene();
+ _globals._spriteIndexes[2] = _scene->_sprites.addSprites(formAnimName('m', 2));
+ _globals._spriteIndexes[4] = _scene->_sprites.addSprites(formAnimName('m', 4));
+ _globals._spriteIndexes[9] = _scene->_sprites.addSprites(formAnimName('m', 9));
+ _blinkFl = false;
+ setLeftView(2);
+ _game.loadQuoteSet(0xFE, 0);
+ _game._triggerSetupMode = SEQUENCE_TRIGGER_DAEMON;
+ _scene->loadAnimation(formAnimName('a', -1), 70);
+ _vm->_sound->command(17);
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+ } else if (_action.isAction(VERB_LEAVE, NOUN_SECURITY_STATION))
+ _scene->_nextSceneId = 311;
+ else if (_action.isAction(VERB_LOOK, NOUN_RIGHT_MONITOR))
+ _vm->_dialogs->show(32001);
+ else if (_action.isAction(VERB_LOOK, NOUN_LEFT_MONITOR))
+ _vm->_dialogs->show(32002);
+ else if (_action.isAction(VERB_LOOK, NOUN_DESK))
+ _vm->_dialogs->show(32003);
+ else if (_action.isAction(VERB_LOOK, NOUN_SECURITY_STATION))
+ _vm->_dialogs->show(32004);
+ else if (_action.isAction(VERB_LOOK, NOUN_MUG))
+ _vm->_dialogs->show(32005);
+ else if (_action.isAction(VERB_LOOK, NOUN_DOUGHNUT))
+ _vm->_dialogs->show(32006);
+ else if (_action.isAction(VERB_LOOK, NOUN_MAGAZINE))
+ _vm->_dialogs->show(32006);
+ else if (_action.isAction(VERB_LOOK, NOUN_PAPER_FOOTBALL))
+ _vm->_dialogs->show(32008);
+ else if (_action.isAction(VERB_LOOK, NOUN_NEWSPAPER))
+ _vm->_dialogs->show(32009);
+ else if (_action.isAction(VERB_LOOK, NOUN_CLIPBOARD))
+ _vm->_dialogs->show(32010);
+ else if (_action.isAction(VERB_TAKE, NOUN_MUG))
+ _vm->_dialogs->show(32012);
+ else if (_action.isAction(VERB_TAKE, NOUN_CLIPBOARD))
+ _vm->_dialogs->show(32013);
+ else if (_action.isAction(VERB_TAKE, NOUN_DOUGHNUT) || _action.isAction(VERB_EAT, NOUN_DOUGHNUT))
+ _vm->_dialogs->show(32014);
+ else if (_action.isAction(VERB_TAKE, NOUN_PAPER_FOOTBALL))
+ _vm->_dialogs->show(32015);
+ else if (_action.isAction(VERB_TAKE, NOUN_MAGAZINE))
+ _vm->_dialogs->show(32016);
+ else if (_action.isAction(VERB_TAKE, NOUN_NEWSPAPER))
+ _vm->_dialogs->show(32017);
+ else
+ return;
+
+ _action._inProgress = false;
+}
+
+/*------------------------------------------------------------------------*/
+
+void Scene321::setup() {
+ setPlayerSpritesPrefix();
+ setAAName();
+}
+
+void Scene321::enter() {
+ _game._player._visible = false;
+ _game._player._stepEnabled = false;
+
+ _scene->_userInterface.emptyConversationList();
+ _scene->_userInterface.setup(kInputConversation);
+
+ int suffixNum;
+ if (_globals[kSexOfRex] == REX_FEMALE) {
+ _globals[kSexOfRex] = REX_MALE;
+ suffixNum = 1;
+ } else {
+ _globals[kSexOfRex] = REX_FEMALE;
+ suffixNum = _game._visitedScenes._sceneRevisited ? 2 : 0;
+ }
+
+ _scene->loadAnimation(formAnimName('g', suffixNum), 60);
+ sceneEntrySound();
+}
+
+void Scene321::step() {
+ if (_scene->_activeAnimation != nullptr) {
+ if ((_scene->_activeAnimation->getCurrentFrame() >= 260) && (_globals[kSexOfRex] == REX_MALE) && (_game._storyMode >= STORYMODE_NICE))
+ _scene->_nextSceneId = 316;
+ }
+
+ if (_game._trigger == 60)
+ _scene->_nextSceneId = 316;
+}
+
+/*------------------------------------------------------------------------*/
+
+void Scene322::setup() {
+ _game._player._spritesPrefix = "";
+ // The original is calling scene3xx_setAAName()
+ _game._aaName = Resources::formatAAName(4);
+}
+
+void Scene322::enter() {
+ if (_globals[kSexOfRex] == REX_MALE)
+ _handSpriteId = _scene->_sprites.addSprites("*REXHAND");
+ else
+ _handSpriteId = _scene->_sprites.addSprites("*ROXHAND");
+
+ teleporterEnter();
+
+ // The original is using scene3xx_sceneEntrySound()
+ if (!_vm->_musicFlag)
+ _vm->_sound->command(2);
+ else
+ _vm->_sound->command(10);
+}
+
+void Scene322::step() {
+ teleporterStep();
+}
+
+void Scene322::actions() {
+ if (_action._lookFlag) {
+ _vm->_dialogs->show(32214);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (teleporterActions()) {
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_LOOK, NOUN_VIEWPORT) || _action.isAction(VERB_PEER_THROUGH, NOUN_VIEWPORT))
+ _vm->_dialogs->show(32210);
+ else if (_action.isAction(VERB_LOOK, NOUN_KEYPAD))
+ _vm->_dialogs->show(32211);
+ else if (_action.isAction(VERB_LOOK, NOUN_DISPLAY))
+ _vm->_dialogs->show(32212);
+ else if (_action.isAction(VERB_LOOK, NOUN_0_KEY) || _action.isAction(VERB_LOOK, NOUN_1_KEY)
+ || _action.isAction(VERB_LOOK, NOUN_2_KEY) || _action.isAction(VERB_LOOK, NOUN_3_KEY)
+ || _action.isAction(VERB_LOOK, NOUN_4_KEY) || _action.isAction(VERB_LOOK, NOUN_5_KEY)
+ || _action.isAction(VERB_LOOK, NOUN_6_KEY) || _action.isAction(VERB_LOOK, NOUN_7_KEY)
+ || _action.isAction(VERB_LOOK, NOUN_8_KEY) || _action.isAction(VERB_LOOK, NOUN_9_KEY)
+ || _action.isAction(VERB_LOOK, NOUN_SMILE_KEY) || _action.isAction(VERB_LOOK, NOUN_ENTER_KEY)
+ || _action.isAction(VERB_LOOK, NOUN_FROWN_KEY))
+ _vm->_dialogs->show(32213);
+ else if (_action.isAction(VERB_LOOK, NOUN_DEVICE))
+ _vm->_dialogs->show(32214);
+ else
+ return;
+
+ _action._inProgress = false;
+}
+
+/*------------------------------------------------------------------------*/
+
+void Scene351::setup() {
+ if (_scene->_currentSceneId == 391)
+ _globals[kSexOfRex] = REX_MALE;
+
+ setPlayerSpritesPrefix();
+ setAAName();
+ _scene->addActiveVocab(VERB_WALKTO);
+}
+
+void Scene351::enter() {
+ _globals[kAfterHavoc] = -1;
+ _globals[kTeleporterRoom + 1] = 351;
+
+ _globals._spriteIndexes[1] = _scene->_sprites.addSprites(formAnimName('c', -1));
+ _globals._spriteIndexes[2] = _scene->_sprites.addSprites("*ROXRC_7");
+ _globals._spriteIndexes[3] = _scene->_sprites.addSprites("*RXRD_7");
+
+ if (_game._objects.isInRoom(OBJ_CREDIT_CHIP)) {
+ _globals._sequenceIndexes[1] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[1], false, 6, 0, 0, 0);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 4);
+ } else
+ _scene->_hotspots.activate(NOUN_CREDIT_CHIP, false);
+
+ if (_scene->_priorSceneId == 352)
+ _game._player._playerPos = Common::Point(148, 152);
+ else if (_scene->_priorSceneId != -2) {
+ _game._player._playerPos = Common::Point(207, 81);
+ _game._player._facing = FACING_NORTH;
+ }
+
+ if (_globals[kTeleporterCommand]) {
+ _game._player._visible = false;
+ _game._player._stepEnabled = false;
+
+ char sepChar = 'a';
+ if (_globals[kSexOfRex] != REX_MALE)
+ sepChar = 'b';
+
+ int suffixNum = -1;
+ int trigger = 0;
+
+ switch (_globals[kTeleporterCommand]) {
+ case 1:
+ suffixNum = 0;
+ trigger = 60;
+ _globals[kTeleporterCommand] = true;
+ break;
+
+ case 2:
+ suffixNum = 1;
+ trigger = 61;
+ break;
+
+ case 3:
+ case 4:
+ _game._player._visible = true;
+ _game._player._stepEnabled = true;
+ _game._player._turnToFacing = FACING_SOUTH;
+ suffixNum = -1;
+ break;
+
+ default:
+ break;
+ }
+
+ _globals[kTeleporterCommand] = 0;
+
+ if (suffixNum >= 0)
+ _scene->loadAnimation(formAnimName(sepChar, suffixNum), trigger);
+ }
+
+ sceneEntrySound();
+}
+
+void Scene351::step() {
+ if (_game._trigger == 60) {
+ _game._player._stepEnabled = true;
+ _game._player._visible = true;
+ _game._player._priorTimer = _scene->_frameStartTime - _game._player._ticksAmount;
+ _game._player._turnToFacing = FACING_SOUTH;
+ }
+
+ if (_game._trigger == 61) {
+ _globals[kTeleporterCommand] = 1;
+ _scene->_nextSceneId = _globals[kTeleporterDestination];
+ _scene->_reloadSceneFlag = true;
+ }
+}
+
+void Scene351::actions() {
+ if (_action._lookFlag)
+ _vm->_dialogs->show(35121);
+ else if (_action.isAction(VERB_STEP_INTO, NOUN_TELEPORTER))
+ _scene->_nextSceneId = 322;
+ else if (_action.isAction(VERB_WALK_DOWN, NOUN_CORRIDOR_TO_SOUTH))
+ _scene->_nextSceneId = 352;
+ else if (_action.isAction(VERB_TAKE, NOUN_CREDIT_CHIP)) {
+ if (_game._trigger || !_game._objects.isInInventory(0xF)) {
+ switch (_game._trigger) {
+ case 0:
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ if (_globals[kSexOfRex] == REX_FEMALE) {
+ _globals._sequenceIndexes[2] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[2], false, 5, 2, 0, 0);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[2]);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[2], SEQUENCE_TRIGGER_SPRITE, 5, 1);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[2], SEQUENCE_TRIGGER_EXPIRE, 0, 2);
+ } else {
+ _globals._sequenceIndexes[3] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[3], false, 5, 2, 0, 0);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[3]);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[3], SEQUENCE_TRIGGER_SPRITE, 6, 1);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[3], SEQUENCE_TRIGGER_EXPIRE, 0, 2);
+ }
+ break;
+
+ case 1:
+ _scene->_hotspots.activate(NOUN_CREDIT_CHIP, false);
+ _scene->_sequences.remove(_globals._sequenceIndexes[1]);
+ _game._objects.addToInventory(OBJ_CREDIT_CHIP);
+ break;
+
+ case 2:
+ _game._player._visible = true;
+ _game._player._stepEnabled = true;
+ _vm->_dialogs->showItem(OBJ_CREDIT_CHIP, 0x32F);
+ break;
+ }
+ }
+ } else if (_action.isAction(VERB_LOOK, NOUN_VIEW_SCREEN))
+ _vm->_dialogs->show(35110);
+ else if (_action.isAction(VERB_LOOK, NOUN_RIP_IN_FLOOR))
+ _vm->_dialogs->show(35111);
+ else if (_action.isAction(VERB_LOOK, NOUN_FIRE_HYDRANT))
+ _vm->_dialogs->show(35112);
+ else if (_action.isAction(VERB_LOOK, NOUN_GUARD)) {
+ if (_game._objects[0xF]._roomNumber == 351)
+ _vm->_dialogs->show(35114);
+ else
+ _vm->_dialogs->show(35113);
+ } else if (_action.isAction(VERB_LOOK, NOUN_EQUIPMENT))
+ _vm->_dialogs->show(35115);
+ else if (_action.isAction(VERB_LOOK, NOUN_DESK))
+ _vm->_dialogs->show(35116);
+ else if (_action.isAction(VERB_LOOK, NOUN_MACHINE))
+ _vm->_dialogs->show(35117);
+ else if (_action.isAction(VERB_LOOK, NOUN_TELEPORTER))
+ _vm->_dialogs->show(35118);
+ else if (_action.isAction(VERB_LOOK, NOUN_CONTROL_PANEL))
+ _vm->_dialogs->show(35119);
+ else if (_action.isAction(VERB_LOOK, NOUN_CORRIDOR_TO_SOUTH))
+ _vm->_dialogs->show(35120);
+ else if (_action.isAction(VERB_LOOK, NOUN_POLE))
+ _vm->_dialogs->show(35122);
+ else
+ return;
+
+ _action._inProgress = false;
+}
+
+/*------------------------------------------------------------------------*/
+
+Scene352::Scene352(MADSEngine *vm) : Scene3xx(vm) {
+ _vaultOpenFl = false;
+ _mustPutArmDownFl = false;
+ _leaveRoomFl = false;
+
+ _tapePlayerHotspotIdx = -1;
+ _hotspot1Idx = -1;
+ _hotspot2Idx = -1;
+ _lampHostpotIdx = -1;
+ _commonSequenceIdx = -1;
+ _commonSpriteIndex = -1;
+}
+
+void Scene352::synchronize(Common::Serializer &s) {
+ Scene3xx::synchronize(s);
+
+ s.syncAsByte(_vaultOpenFl);
+ s.syncAsByte(_mustPutArmDownFl);
+ s.syncAsByte(_leaveRoomFl);
+
+ s.syncAsSint32LE(_tapePlayerHotspotIdx);
+ s.syncAsSint32LE(_hotspot1Idx);
+ s.syncAsSint32LE(_hotspot2Idx);
+ s.syncAsSint32LE(_lampHostpotIdx);
+ s.syncAsSint32LE(_commonSequenceIdx);
+ s.syncAsSint32LE(_commonSpriteIndex);
+}
+
+void Scene352::setup() {
+ setPlayerSpritesPrefix();
+ setAAName();
+
+ _scene->addActiveVocab(VERB_WALKTO);
+ _scene->addActiveVocab(NOUN_YOUR_STUFF);
+ _scene->addActiveVocab(NOUN_OTHER_STUFF);
+ _scene->addActiveVocab(NOUN_LAMP);
+}
+
+void Scene352::putArmDown(bool corridorExit, bool doorwayExit) {
+ switch (_game._trigger) {
+ case 0:
+ _scene->_kernelMessages.add(Common::Point(0, 0), 0x1110, 34, 0, 60, _game.getQuote(0xFF));
+ _scene->_sequences.addTimer(48, 1);
+ break;
+
+ case 1:
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ if (_globals[kSexOfRex] == REX_FEMALE) {
+ _globals._sequenceIndexes[3] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[3], false, 5, 2, 0, 0);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[3]);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[3], SEQUENCE_TRIGGER_SPRITE, 5, 2);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[3], SEQUENCE_TRIGGER_EXPIRE, 0, 3);
+ } else {
+ _globals._sequenceIndexes[4] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[4], false, 5, 2, 0, 0);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[4]);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[4], SEQUENCE_TRIGGER_SPRITE, 6, 2);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[4], SEQUENCE_TRIGGER_EXPIRE, 0, 3);
+ }
+ break;
+
+ case 2: {
+ _globals._sequenceIndexes[2] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[2], false, 6, 0, 0, 0);
+ int idx = _scene->_dynamicHotspots.add(NOUN_GUARDS_ARM, 0xD, _globals._sequenceIndexes[2], Common::Rect(0, 0, 0, 0));
+ _scene->_dynamicHotspots.setPosition(idx, Common::Point(230, 117), FACING_NORTHWEST);
+ _scene->changeVariant(0);
+ }
+ break;
+
+ case 3:
+ _scene->_kernelMessages.reset();
+ _scene->_kernelMessages.add(Common::Point(0, 0), 0x1110, 34, 0, 120, _game.getQuote(0x100));
+ _game._objects.setRoom(0x2F, _scene->_currentSceneId);
+ _game._player._visible = true;
+ if (corridorExit)
+ _scene->_sequences.addTimer(48, 6);
+ else if (doorwayExit)
+ _scene->_sequences.addTimer(48, 4);
+ else {
+ _mustPutArmDownFl = false;
+ _game._player._stepEnabled = true;
+ }
+ break;
+
+ case 4:
+ _game._player.walk(Common::Point(116, 107), FACING_NORTH);
+ _game._player._stepEnabled = true;
+ _mustPutArmDownFl = false;
+ _scene->_sequences.addTimer(180, 5);
+ _leaveRoomFl = true;
+ break;
+
+ case 5:
+ if (_leaveRoomFl)
+ _scene->_nextSceneId = 351;
+
+ break;
+
+ case 6:
+ _game._player.walk(Common::Point(171, 152), FACING_SOUTH);
+ _game._player._stepEnabled = true;
+ _mustPutArmDownFl = false;
+ _scene->_sequences.addTimer(180, 7);
+ _leaveRoomFl = true;
+ break;
+
+ case 7:
+ if (_leaveRoomFl)
+ _scene->_nextSceneId = 353;
+
+ break;
+
+ default:
+ break;
+ }
+}
+
+void Scene352::enter() {
+ _globals._spriteIndexes[1] = _scene->_sprites.addSprites("*RM302x0");
+ _globals._spriteIndexes[13] = _scene->_sprites.addSprites("*RM302x2");
+ _globals._spriteIndexes[12] = _scene->_sprites.addSprites("*RM302x3");
+ _globals._spriteIndexes[2] = _scene->_sprites.addSprites(formAnimName('g', -1));
+ _globals._spriteIndexes[5] = _scene->_sprites.addSprites(formAnimName('b', -1));
+
+
+ if (_globals[kSexOfRex] == REX_FEMALE) {
+ _globals._spriteIndexes[3] = _scene->_sprites.addSprites("*ROXRC_7");
+ _globals._spriteIndexes[7] = _scene->_sprites.addSprites("*ROXRC_6");
+ _globals._spriteIndexes[15] = _scene->_sprites.addSprites("*ROXRC_9");
+ _globals._spriteIndexes[11] = _scene->_sprites.addSprites(formAnimName('a', 3));
+ _globals._spriteIndexes[9] = _scene->_sprites.addSprites(formAnimName('a', 2));
+ } else {
+ _globals._spriteIndexes[4] = _scene->_sprites.addSprites("*RXRD_7");
+ _globals._spriteIndexes[6] = _scene->_sprites.addSprites("*RXRC_6");
+ _globals._spriteIndexes[14] = _scene->_sprites.addSprites("*RXMRC_9");
+ _globals._spriteIndexes[10] = _scene->_sprites.addSprites(formAnimName('a', 1));
+ _globals._spriteIndexes[8] = _scene->_sprites.addSprites(formAnimName('a', 0));
+ }
+
+ _leaveRoomFl = false;
+
+ if (_game._objects.isInRoom(OBJ_TAPE_PLAYER)) {
+ _globals._sequenceIndexes[5] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[5], false, 12, 0, 0, 0);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[5], 5);
+ int idx = _scene->_dynamicHotspots.add(NOUN_TAPE_PLAYER, 0xD, _globals._sequenceIndexes[5], Common::Rect(0, 0, 0, 0));
+ _tapePlayerHotspotIdx = _scene->_dynamicHotspots.setPosition(idx, Common::Point(84, 145), FACING_WEST);
+ }
+
+ _vaultOpenFl = false;
+
+ if (_scene->_priorSceneId != -2) {
+ _mustPutArmDownFl = false;
+ if (!_game._visitedScenes._sceneRevisited)
+ _globals[kHaveYourStuff] = false;
+ }
+
+ if (_game._objects.isInRoom(OBJ_GUARDS_ARM)) {
+ _globals._sequenceIndexes[2] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[2], false, 6, 0, 0, 0);
+ int idx = _scene->_dynamicHotspots.add(NOUN_GUARDS_ARM, 0xD, _globals._sequenceIndexes[2], Common::Rect(0, 0, 0, 0));
+ _scene->_dynamicHotspots.setPosition(idx, Common::Point(230, 117), FACING_NORTHWEST);
+ } else
+ _mustPutArmDownFl = true;
+
+ if (_scene->_priorSceneId == 353)
+ _game._player._playerPos = Common::Point(171, 155);
+ else if (_scene->_priorSceneId != -2)
+ _game._player._playerPos = Common::Point(116, 107);
+
+ sceneEntrySound();
+
+ _game.loadQuoteSet(0xFF, 0x100, 0x101, 0x102, 0x103, 0);
+}
+
+void Scene352::preActions() {
+ _leaveRoomFl = false;
+
+ if (_action.isAction(VERB_OPEN, NOUN_VAULT))
+ _game._player.walk(Common::Point(266, 111), FACING_NORTHEAST);
+
+ if (_vaultOpenFl && !_action.isAction(0x1F8) && !_action.isAction(0x2F6) && !_action.isAction(0x2F5) && !_action.isAction(0x2F4)) {
+ if (_globals[kHaveYourStuff]) {
+ _commonSpriteIndex = _globals._spriteIndexes[13];
+ _commonSequenceIdx = _globals._sequenceIndexes[13];
+ } else {
+ _commonSpriteIndex = _globals._spriteIndexes[1];
+ _commonSequenceIdx = _globals._sequenceIndexes[1];
+ }
+
+ switch (_game._trigger) {
+ case 0:
+ if (_game._player._needToWalk) {
+ _game._player._stepEnabled = false;
+ _scene->_sequences.remove(_commonSequenceIdx);
+ _vm->_sound->command(20);
+ _commonSequenceIdx = _scene->_sequences.startReverseCycle(_commonSpriteIndex, false, 6, 1, 0, 0);
+ _scene->_sequences.addSubEntry(_commonSequenceIdx, SEQUENCE_TRIGGER_EXPIRE, 0, 1);
+ _scene->_sequences.setDepth(_commonSequenceIdx, 15);
+ }
+ break;
+
+ case 1:
+ if (!_globals[kHaveYourStuff])
+ _scene->_dynamicHotspots.remove(_hotspot2Idx);
+
+ _scene->_dynamicHotspots.remove(_hotspot1Idx);
+ _scene->_dynamicHotspots.remove(_lampHostpotIdx);
+ _vaultOpenFl = false;
+ _game._player._stepEnabled = true;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ if (_action.isAction(VERB_PUT, NOUN_GUARDS_ARM, 0x1F3)) {
+ if (_globals[kSexOfRex] == REX_MALE)
+ _game._player.walk(Common::Point(269, 111), FACING_NORTHEAST);
+ else
+ _game._player.walk(Common::Point(271, 111), FACING_NORTHEAST);
+ }
+
+ if (_action.isAction(VERB_WALK_THROUGH, NOUN_DOORWAY) || _action.isAction(VERB_WALK_DOWN, NOUN_CORRIDOR_TO_SOUTH) || _action.isAction(VERB_PUT, NOUN_GUARDS_ARM, 0x89)) {
+ if (_game._objects.isInInventory(OBJ_GUARDS_ARM))
+ _game._player.walk(Common::Point(230, 117), FACING_NORTHWEST);
+ }
+}
+
+void Scene352::actions() {
+ if (_action._lookFlag) {
+ _vm->_dialogs->show(35225);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_OPEN, NOUN_VAULT)) {
+ if (!_vaultOpenFl) {
+ switch (_game._trigger) {
+ case 0:
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ if (_globals[kSexOfRex] == REX_FEMALE)
+ _commonSpriteIndex = _globals._spriteIndexes[9];
+ else
+ _commonSpriteIndex = _globals._spriteIndexes[8];
+
+ _commonSequenceIdx = _scene->_sequences.addSpriteCycle(_commonSpriteIndex, false, 8, 1, 0, 0);
+ _scene->_sequences.updateTimeout(_commonSequenceIdx, -1);
+ _scene->_sequences.addSubEntry(_commonSequenceIdx, SEQUENCE_TRIGGER_EXPIRE, 0, 1);
+ break;
+
+ case 1: {
+ _vm->_sound->command(21);
+ _globals._sequenceIndexes[12] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[12], false, 7, 2, 20, 0);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[12], FACING_NORTH);
+ int oldIdx = _commonSequenceIdx;
+ _commonSequenceIdx = _scene->_sequences.startCycle(_commonSpriteIndex, false, -2);
+ _scene->_sequences.updateTimeout(_commonSequenceIdx, oldIdx);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[12], SEQUENCE_TRIGGER_EXPIRE, 0, 2);
+ }
+ break;
+
+ case 2:
+ _vm->_sound->command(22);
+ _scene->_sequences.remove(_commonSequenceIdx);
+ _commonSequenceIdx = _scene->_sequences.startReverseCycle(_commonSpriteIndex, false, 8, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_commonSequenceIdx, 1, 3);
+ _scene->_sequences.addSubEntry(_commonSequenceIdx, SEQUENCE_TRIGGER_EXPIRE, 0, 3);
+ break;
+
+ case 3:
+ _scene->_sequences.updateTimeout(-1, _commonSequenceIdx);
+ _game._player._visible = true;
+ _scene->_sequences.addTimer(60, 4);
+ break;
+
+ case 4:
+ _scene->_kernelMessages.add(Common::Point(0, 0), 0x1110, 34, 0, 120, _game.getQuote(0x101));
+ _game._player._stepEnabled = true;
+ break;
+ }
+ }
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_game._objects.isInInventory(OBJ_GUARDS_ARM)) {
+ _mustPutArmDownFl = true;
+ }
+
+ bool exit_corridor = false;
+ bool exit_doorway = false;
+
+ if (_action.isAction(VERB_WALK_DOWN, NOUN_CORRIDOR_TO_SOUTH)) {
+ exit_corridor = true;
+ }
+
+ if (_action.isAction(VERB_WALK_THROUGH, NOUN_DOORWAY)) {
+ exit_doorway = true;
+ }
+
+ if (_action.isAction(VERB_WALK_DOWN, NOUN_CORRIDOR_TO_SOUTH) || _action.isAction(VERB_WALK_THROUGH, NOUN_DOORWAY) || _action.isAction(VERB_PUT, NOUN_GUARDS_ARM, 0x89)) {
+ if (_mustPutArmDownFl)
+ putArmDown(exit_corridor, exit_doorway);
+ else if (exit_corridor)
+ _scene->_nextSceneId = 353;
+ else
+ _scene->_nextSceneId = 351;
+
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_TAKE, NOUN_GUARDS_ARM)) {
+ if (_game._trigger || !_game._objects.isInInventory(OBJ_GUARDS_ARM)) {
+ switch (_game._trigger) {
+ case 0:
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ if (_globals[kSexOfRex] == REX_FEMALE) {
+ _globals._sequenceIndexes[3] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[3], false, 5, 2, 0, 0);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[3]);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[3], SEQUENCE_TRIGGER_SPRITE, 5, 1);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[3], SEQUENCE_TRIGGER_EXPIRE, 0, 2);
+ } else {
+ _globals._sequenceIndexes[4] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[4], false, 5, 2, 0, 0);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[4]);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[4], SEQUENCE_TRIGGER_SPRITE, 6, 1);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[4], SEQUENCE_TRIGGER_EXPIRE, 0, 2);
+ }
+ break;
+
+ case 1:
+ _scene->_sequences.remove(_globals._sequenceIndexes[2]);
+ _game._objects.addToInventory(OBJ_GUARDS_ARM);
+ _scene->changeVariant(1);
+ break;
+
+ case 2:
+ _game._player._visible = true;
+ _game._player._stepEnabled = true;
+ _vm->_dialogs->showItem(0x2F, 0x899C);
+ break;
+ }
+ _action._inProgress = false;
+ return;
+ }
+ }
+
+ if (_action.isAction(VERB_PUT, NOUN_GUARDS_ARM, 0x1F3)) {
+ if (!_vaultOpenFl) {
+ switch (_game._trigger) {
+ case 0:
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ if (_globals[kSexOfRex] == REX_FEMALE)
+ _commonSpriteIndex = _globals._spriteIndexes[11];
+ else
+ _commonSpriteIndex = _globals._spriteIndexes[10];
+
+ _commonSequenceIdx = _scene->_sequences.addSpriteCycle(_commonSpriteIndex, false, 8, 1, 0, 0);
+ _scene->_sequences.updateTimeout(_commonSequenceIdx, -1);
+ _scene->_sequences.addSubEntry(_commonSequenceIdx, SEQUENCE_TRIGGER_EXPIRE, 0, 1);
+ break;
+
+ case 1: {
+ _vm->_sound->command(21);
+ _globals._sequenceIndexes[12] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[12], false, 7, 2, 20, 0);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[12], 8);
+ int oldIdx = _commonSequenceIdx;
+ _commonSequenceIdx = _scene->_sequences.startCycle(_commonSpriteIndex, false, -2);
+ _scene->_sequences.updateTimeout(_commonSequenceIdx, oldIdx);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[12], SEQUENCE_TRIGGER_EXPIRE, 0, 2);
+ }
+ break;
+
+ case 2:
+ _vm->_sound->command(23);
+ _scene->_sequences.remove(_commonSequenceIdx);
+ _commonSequenceIdx = _scene->_sequences.startReverseCycle(_commonSpriteIndex, false, 8, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_commonSequenceIdx, 1, 4);
+ _scene->_sequences.addSubEntry(_commonSequenceIdx, SEQUENCE_TRIGGER_EXPIRE, 0, 3);
+ break;
+
+
+ case 3:
+ _scene->_sequences.updateTimeout(-1, _commonSequenceIdx);
+ _game._player._visible = true;
+ if (_globals[kHaveYourStuff])
+ _commonSpriteIndex = _globals._spriteIndexes[13];
+ else
+ _commonSpriteIndex = _globals._spriteIndexes[1];
+
+ _vm->_sound->command(20);
+ _commonSequenceIdx = _scene->_sequences.addSpriteCycle(_commonSpriteIndex, false, 6, 1, 0, 0);
+ _scene->_sequences.setDepth(_commonSequenceIdx, 15);
+ _scene->_sequences.addSubEntry(_commonSequenceIdx, SEQUENCE_TRIGGER_EXPIRE, 0, 4);
+ break;
+
+ case 4:
+ _commonSequenceIdx = _scene->_sequences.addSpriteCycle(_commonSpriteIndex, false, 6, 0, 0, 0);
+ _scene->_sequences.setAnimRange(_commonSequenceIdx, -2, -2);
+ _scene->_sequences.setDepth(_commonSequenceIdx, 15);
+ _scene->_sequences.addTimer(60, 5);
+ break;
+
+ case 5: {
+ _vaultOpenFl = true;
+ int idx;
+ if (!_globals[kHaveYourStuff]) {
+ idx = _scene->_dynamicHotspots.add(NOUN_YOUR_STUFF, 0xD, -1, Common::Rect(282, 87, 282 + 13, 87 + 7));
+ _hotspot2Idx = _scene->_dynamicHotspots.setPosition(idx, Common::Point(280, 111), FACING_NORTHEAST);
+ _globals._sequenceIndexes[1] = _commonSequenceIdx;
+ _scene->_kernelMessages.add(Common::Point(0, 0), 0x1110, 34, 0, 120, _game.getQuote(0x102));
+ } else {
+ _globals._sequenceIndexes[13] = _commonSequenceIdx;
+ _scene->_kernelMessages.add(Common::Point(0, 0), 0x1110, 34, 0, 120, _game.getQuote(0x103));
+ }
+
+ idx = _scene->_dynamicHotspots.add(NOUN_OTHER_STUFF, 0xD, -1, Common::Rect(282, 48, 282 + 36, 48 + 27));
+ _hotspot1Idx = _scene->_dynamicHotspots.setPosition(idx, Common::Point(287, 115), FACING_NORTHEAST);
+ idx = _scene->_dynamicHotspots.add(NOUN_LAMP, 0xD, -1, Common::Rect(296, 76, 296 + 11, 76 + 17));
+ _lampHostpotIdx = _scene->_dynamicHotspots.setPosition(idx, Common::Point(287, 115), FACING_NORTHEAST);
+ _game._player._stepEnabled = true;
+ }
+ break;
+ }
+ }
+ } else if (_action.isAction(VERB_TAKE, NOUN_YOUR_STUFF)) {
+ switch (_game._trigger) {
+ case 0:
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ if (_globals[kSexOfRex] == REX_MALE) {
+ _globals._sequenceIndexes[14] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[14], false, 8, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[14], 1, 2);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[14]);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[14], SEQUENCE_TRIGGER_SPRITE, 2, 1);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[14], SEQUENCE_TRIGGER_EXPIRE, 0, 2);
+ } else {
+ _globals._sequenceIndexes[15] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[15], false, 8, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[15], 1, 2);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[15]);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[15], SEQUENCE_TRIGGER_SPRITE, 2, 1);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[15], SEQUENCE_TRIGGER_EXPIRE, 0, 2);
+ }
+ break;
+
+ case 1:
+ _scene->_dynamicHotspots.remove(_hotspot2Idx);
+ _globals[kHaveYourStuff] = true;
+
+ for (uint16 i = 0; i < _game._objects.size(); i++) {
+ if (_game._objects[i]._roomNumber == 50)
+ _game._objects.addToInventory(i);
+ }
+
+ _scene->_sequences.remove(_globals._sequenceIndexes[1]);
+ _globals._sequenceIndexes[13] = _scene->_sequences.startCycle(_globals._spriteIndexes[13], false, -2);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[13], 15);
+ break;
+
+ case 2:
+ if (_globals[kSexOfRex] == REX_MALE)
+ _scene->_sequences.updateTimeout(-1, _globals._sequenceIndexes[14]);
+ else
+ _scene->_sequences.updateTimeout(-1, _globals._sequenceIndexes[15]);
+
+ _game._player._visible = true;
+ _game._player._stepEnabled = true;
+ break;
+
+ default:
+ break;
+ }
+ } else if (_action.isAction(VERB_TAKE, NOUN_TAPE_PLAYER) && !_game._objects.isInInventory(OBJ_TAPE_PLAYER)) {
+ switch (_game._trigger) {
+ case 0:
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ if (_globals[kSexOfRex] == REX_MALE) {
+ _globals._sequenceIndexes[6] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[6], true, 6, 2, 0, 0);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[6]);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[6], SEQUENCE_TRIGGER_SPRITE, 6, 1);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[6], SEQUENCE_TRIGGER_EXPIRE, 0, 2);
+ } else {
+ _globals._sequenceIndexes[7] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[7], true, 6, 2, 0, 0);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[7]);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[7], SEQUENCE_TRIGGER_SPRITE, 6, 1);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[7], SEQUENCE_TRIGGER_EXPIRE, 0, 2);
+ }
+ break;
+
+ case 1:
+ _scene->_sequences.remove(_globals._sequenceIndexes[5]);
+ _scene->_dynamicHotspots.remove(_tapePlayerHotspotIdx);
+ break;
+
+ case 2:
+ _game._objects.addToInventory(OBJ_TAPE_PLAYER);
+ if (_globals[kSexOfRex] == REX_MALE)
+ _scene->_sequences.updateTimeout(-1, _globals._sequenceIndexes[6]);
+ else
+ _scene->_sequences.updateTimeout(-1, _globals._sequenceIndexes[7]);
+
+ _game._player._visible = true;
+ _game._player._stepEnabled = true;
+ _vm->_dialogs->showItem(OBJ_TAPE_PLAYER, 0x899B);
+ break;
+
+ default:
+ break;
+ }
+ } else if (_action.isAction(VERB_LOOK, NOUN_SCANNER))
+ _vm->_dialogs->show(35210);
+ else if (_action.isAction(VERB_LOOK, NOUN_MONITOR)) {
+ if (_game._storyMode == STORYMODE_NAUGHTY)
+ _vm->_dialogs->show(35211);
+ else
+ _vm->_dialogs->show(35212);
+ } else if (_action.isAction(VERB_LOOK, NOUN_DISPLAY))
+ _vm->_dialogs->show(35213);
+ else if (_action.isAction(VERB_LOOK, NOUN_STATUE))
+ _vm->_dialogs->show(35214);
+ else if (_action.isAction(VERB_LOOK, NOUN_TAPE_PLAYER) && (_action._savedFields._mainObjectSource == 4))
+ _vm->_dialogs->show(35215);
+ else if (_action.isAction(VERB_LOOK, NOUN_AIR_VENT))
+ _vm->_dialogs->show(35216);
+ else if (_action.isAction(VERB_LOOK, NOUN_GUARDS_ARM) && (_action._savedFields._mainObjectSource == 4))
+ _vm->_dialogs->show(35217);
+ else if (_action.isAction(VERB_LOOK, NOUN_IRONING_BOARD))
+ _vm->_dialogs->show(35218);
+ else if (_action.isAction(VERB_LOOK, NOUN_CLOCK))
+ _vm->_dialogs->show(35219);
+ else if (_action.isAction(VERB_LOOK, NOUN_GAUGE))
+ _vm->_dialogs->show(35220);
+ else if (_action.isAction(VERB_LOOK, NOUN_VAULT)) {
+ if (!_vaultOpenFl)
+ _vm->_dialogs->show(35221);
+ } else if (_action.isAction(VERB_LOOK, NOUN_YOUR_STUFF))
+ _vm->_dialogs->show(35222);
+ else if (_action.isAction(VERB_LOOK, NOUN_OTHER_STUFF))
+ _vm->_dialogs->show(35223);
+ else if (_action.isAction(VERB_LOOK, NOUN_CORRIDOR_TO_SOUTH))
+ _vm->_dialogs->show(35224);
+ else if (_action.isAction(VERB_TAKE, NOUN_OTHER_STUFF))
+ _vm->_dialogs->show(35226);
+ else if (_action.isAction(VERB_LOOK, NOUN_DESK))
+ _vm->_dialogs->show(35229);
+ else if (_action.isAction(VERB_LOOK, NOUN_GUARD))
+ _vm->_dialogs->show(35230);
+ else if (_action.isAction(VERB_LOOK, NOUN_DOORWAY))
+ _vm->_dialogs->show(35231);
+ else if (_action.isAction(VERB_LOOK, NOUN_TABLE))
+ _vm->_dialogs->show(35232);
+ else if (_action.isAction(VERB_LOOK, NOUN_PROJECTOR))
+ _vm->_dialogs->show(35233);
+ else if (_action.isAction(VERB_LOOK, NOUN_SUPPORT))
+ _vm->_dialogs->show(35234);
+ else if (_action.isAction(VERB_LOOK, NOUN_SECURITY_MONITOR))
+ _vm->_dialogs->show(35235);
+ else
+ return;
+}
+
+/*------------------------------------------------------------------------*/
+
+void Scene353::setup() {
+ setPlayerSpritesPrefix();
+ setAAName();
+}
+
+void Scene353::enter() {
+ _globals._spriteIndexes[1] = _scene->_sprites.addSprites(Resources::formatName(303, 'B', 0, EXT_SS, ""));
+ _globals._sequenceIndexes[1] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[1], false, 5, 0, 5, 0);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 1);
+
+ if (_scene->_priorSceneId == 352)
+ _game._player._playerPos = Common::Point(144, 95);
+ else
+ _game._player._playerPos = Common::Point(139, 155);
+
+ sceneEntrySound();
+}
+
+void Scene353::actions() {
+ if (_action._lookFlag)
+ _vm->_dialogs->show(35315);
+ else if (_action.isAction(VERB_WALK_THROUGH, NOUN_DOORWAY))
+ _scene->_nextSceneId = 352;
+ else if (_action.isAction(VERB_WALK_DOWN, NOUN_CORRIDOR_TO_SOUTH))
+ _scene->_nextSceneId = 354;
+ else if (_action.isAction(VERB_LOOK, NOUN_ROCK_CHUNK))
+ _vm->_dialogs->show(35310);
+ else if (_action.isAction(VERB_LOOK, NOUN_PIPES) || _action.isAction(VERB_LOOK, NOUN_PIPE))
+ _vm->_dialogs->show(35311);
+ else if (_action.isAction(VERB_LOOK, NOUN_BROKEN_BEAM))
+ _vm->_dialogs->show(35312);
+ else if (_action.isAction(VERB_LOOK, NOUN_DOORWAY))
+ _vm->_dialogs->show(35313);
+ else if (_action.isAction(VERB_LOOK, NOUN_CORRIDOR_TO_SOUTH))
+ _vm->_dialogs->show(35314);
+ else if (_action.isAction(VERB_LOOK, NOUN_FLOOR))
+ _vm->_dialogs->show(35316);
+ else if (_action.isAction(VERB_LOOK, NOUN_CEILING))
+ _vm->_dialogs->show(35317);
+ else if (_action.isAction(VERB_LOOK, NOUN_WALL))
+ _vm->_dialogs->show(35318);
+ else
+ return;
+
+ _action._inProgress = false;
+}
+
+/*------------------------------------------------------------------------*/
+
+void Scene354::setup() {
+ setPlayerSpritesPrefix();
+ setAAName();
+}
+
+void Scene354::enter() {
+ _globals[kAfterHavoc] = true;
+ _globals[kTeleporterRoom + 1] = 351;
+
+ if (_scene->_priorSceneId == 361)
+ _game._player._playerPos = Common::Point(231, 110);
+ else if (_scene->_priorSceneId == 401) {
+ _game._player._playerPos = Common::Point(106, 152);
+ _game._player._facing = FACING_NORTH;
+ } else if (_scene->_priorSceneId == 316)
+ _game._player._playerPos = Common::Point(71, 107);
+ else if (_scene->_priorSceneId != -2)
+ _game._player._playerPos = Common::Point(167, 57);
+
+ sceneEntrySound();
+}
+
+void Scene354::preActions() {
+ if (_action.isAction(VERB_WALK_DOWN, NOUN_CORRIDOR_TO_SOUTH))
+ _game._player._walkOffScreenSceneId = 401;
+}
+
+void Scene354::actions() {
+ if (_action._lookFlag)
+ _vm->_dialogs->show(35414);
+ else if (_action.isAction(VERB_WALK_DOWN, NOUN_CORRIDOR_TO_NORTH)) {
+ _game._player.startWalking(Common::Point(208, 0), FACING_NORTHEAST);
+ _game._player._walkOffScreenSceneId = 353;
+ } else if (_action.isAction(VERB_WALK_DOWN, NOUN_CORRIDOR_TO_EAST))
+ _scene->_nextSceneId = 361;
+ else if (_action.isAction(VERB_WALK_DOWN, NOUN_CORRIDOR_TO_WEST))
+ _scene->_nextSceneId = 316;
+ else if (_action.isAction(VERB_WALK_DOWN, NOUN_CORRIDOR_TO_SOUTH))
+ _scene->_nextSceneId = 401;
+ else if (_action.isAction(VERB_LOOK, NOUN_CONTROLS))
+ _vm->_dialogs->show(35410);
+ else if (_action.isAction(VERB_LOOK, NOUN_SIGNAL))
+ _vm->_dialogs->show(35411);
+ else if (_action.isAction(VERB_LOOK, NOUN_CATWALK))
+ _vm->_dialogs->show(35412);
+ else if (_action.isAction(VERB_LOOK, NOUN_AIR_DUCT))
+ _vm->_dialogs->show(35413);
+ else if (_action.isAction(VERB_LOOK, NOUN_CORRIDOR_TO_NORTH))
+ _vm->_dialogs->show(35415);
+ else if (_action.isAction(VERB_LOOK, NOUN_CORRIDOR_TO_SOUTH))
+ _vm->_dialogs->show(35416);
+ else if (_action.isAction(VERB_LOOK, NOUN_CORRIDOR_TO_EAST))
+ _vm->_dialogs->show(35417);
+ else if (_action.isAction(VERB_LOOK, NOUN_CORRIDOR_TO_WEST))
+ _vm->_dialogs->show(35418);
+ else if (_action.isAction(VERB_LOOK, NOUN_DEBRIS))
+ _vm->_dialogs->show(35419);
+ else if (_action.isAction(VERB_LOOK, NOUN_GUARD))
+ _vm->_dialogs->show(35420);
+ else
+ return;
+
+ _action._inProgress = false;
+}
+
+/*------------------------------------------------------------------------*/
+
+void Scene357::setup() {
+ setPlayerSpritesPrefix();
+ setAAName();
+}
+
+void Scene357::enter() {
+ _globals[kAfterHavoc] = true;
+ _globals._spriteIndexes[1] = _scene->_sprites.addSprites(Resources::formatName(307, 'X', 0, EXT_SS, ""));
+ _globals._sequenceIndexes[1] = _scene->_sequences.startCycle(_globals._spriteIndexes[1], false, 1);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[1], Common::Point(127, 78));
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 15);
+
+ if (_scene->_priorSceneId == 318)
+ _game._player._playerPos = Common::Point(298, 142);
+ else if (_scene->_priorSceneId == 313)
+ _game._player._playerPos = Common::Point(127, 101);
+ else if (_scene->_priorSceneId != -2)
+ _game._player._playerPos = Common::Point(15, 148);
+
+ sceneEntrySound();
+}
+
+void Scene357::preActions() {
+ if (_action.isAction(VERB_WALK_DOWN, NOUN_CORRIDOR_TO_EAST))
+ _game._player._walkOffScreenSceneId = 318;
+
+ if (_action.isAction(VERB_WALK_DOWN, NOUN_CORRIDOR_TO_WEST))
+ _game._player._walkOffScreenSceneId = 358;
+}
+
+void Scene357::actions() {
+ if (_action._lookFlag)
+ _vm->_dialogs->show(35715);
+ else if (_action.isAction(VERB_LOOK, NOUN_AIR_VENT))
+ _vm->_dialogs->show(35710);
+ else if (_action.isAction(VERB_CLIMB_INTO, NOUN_AIR_VENT))
+ _vm->_dialogs->show(35711);
+ else if (_action.isAction(VERB_LOOK, NOUN_BED))
+ _vm->_dialogs->show(35712);
+ else if (_action.isAction(VERB_LOOK, NOUN_SINK))
+ _vm->_dialogs->show(35713);
+ else if (_action.isAction(VERB_LOOK, NOUN_TOILET))
+ _vm->_dialogs->show(35714);
+ else if (_action.isAction(VERB_LOOK, NOUN_CELL_WALL))
+ _vm->_dialogs->show(35716);
+ else if (_action.isAction(VERB_LOOK, NOUN_LIGHT))
+ _vm->_dialogs->show(35717);
+ else if (_action.isAction(VERB_LOOK, NOUN_RIP_IN_FLOOR))
+ _vm->_dialogs->show(35718);
+ else if (_action.isAction(VERB_LOOK, NOUN_DEBRIS))
+ _vm->_dialogs->show(35719);
+ else if (_action.isAction(VERB_TAKE, NOUN_DEBRIS))
+ _vm->_dialogs->show(35720);
+ else if (_action.isAction(VERB_LOOK, NOUN_WALL))
+ _vm->_dialogs->show(35721);
+ else if (_action.isAction(VERB_LOOK, NOUN_CORRIDOR_TO_EAST))
+ _vm->_dialogs->show(35722);
+ else if (_action.isAction(VERB_LOOK, NOUN_CORRIDOR_TO_WEST))
+ _vm->_dialogs->show(35723);
+ else
+ return;
+
+ _action._inProgress = false;
+}
+
+/*------------------------------------------------------------------------*/
+
+void Scene358::setup() {
+ setPlayerSpritesPrefix();
+ setAAName();
+}
+
+void Scene358::enter() {
+ _globals._spriteIndexes[1] = _scene->_sprites.addSprites(Resources::formatName(307, 'X', 0, EXT_SS, ""));
+ _globals._sequenceIndexes[1] = _scene->_sequences.startCycle(_globals._spriteIndexes[1], false, 1);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[1], Common::Point(127, 78));
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 15);
+
+ if (_scene->_priorSceneId == 357)
+ _game._player._playerPos = Common::Point(305, 142);
+ else if (_scene->_priorSceneId != -2)
+ _game._player._playerPos = Common::Point(12, 141);
+
+ sceneEntrySound();
+}
+
+void Scene358::preActions() {
+ if (_action.isAction(VERB_WALK_DOWN, NOUN_CORRIDOR_TO_EAST))
+ _game._player._walkOffScreenSceneId = 357;
+
+ if (_action.isAction(VERB_WALK_DOWN, NOUN_CORRIDOR_TO_WEST))
+ _game._player._walkOffScreenSceneId = 359;
+}
+
+void Scene358::actions() {
+ if (_action._lookFlag)
+ _vm->_dialogs->show(35815);
+ else if (_action.isAction(VERB_LOOK, NOUN_CORRIDOR_TO_WEST))
+ _vm->_dialogs->show(35810);
+ else if (_action.isAction(VERB_LOOK, NOUN_CORRIDOR_TO_EAST))
+ _vm->_dialogs->show(35811);
+ else if (_action.isAction(VERB_LOOK, NOUN_BED))
+ _vm->_dialogs->show(35812);
+ else if (_action.isAction(VERB_LOOK, NOUN_SINK))
+ _vm->_dialogs->show(35813);
+ else if (_action.isAction(VERB_LOOK, NOUN_TOILET))
+ _vm->_dialogs->show(35814);
+ else if (_action.isAction(VERB_LOOK, NOUN_CORRIDOR) || _action.isAction(VERB_LOOK, NOUN_WALL))
+ _vm->_dialogs->show(35816);
+ else if (_action.isAction(VERB_LOOK, NOUN_AIR_VENT))
+ _vm->_dialogs->show(35817);
+ else
+ return;
+
+ _action._inProgress = false;
+}
+
+/*------------------------------------------------------------------------*/
+
+Scene359::Scene359(MADSEngine *vm) : Scene3xx(vm) {
+ _cardHotspotId = -1;
+}
+
+void Scene359::synchronize(Common::Serializer &s) {
+ Scene3xx::synchronize(s);
+
+ s.syncAsSint32LE(_cardHotspotId);
+}
+
+void Scene359::setup() {
+ setPlayerSpritesPrefix();
+ setAAName();
+ _scene->addActiveVocab(VERB_WALKTO);
+}
+
+void Scene359::enter() {
+ _globals._spriteIndexes[1] = _scene->_sprites.addSprites(formAnimName('b', -1));
+ _globals._spriteIndexes[3] = _scene->_sprites.addSprites(Resources::formatName(307, 'X', 0, EXT_SS, ""));
+
+ if (_globals[kSexOfRex] == REX_MALE)
+ _globals._spriteIndexes[2] = _scene->_sprites.addSprites("*RXMBD_2");
+ else
+ _globals._spriteIndexes[4] = _scene->_sprites.addSprites("*ROXBD_2");
+
+ _globals._sequenceIndexes[3] = _scene->_sequences.startCycle(_globals._spriteIndexes[3], false, 1);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[3], Common::Point(127, 78));
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 15);
+
+ if (_game._objects.isInRoom(OBJ_SECURITY_CARD)) {
+ _globals._sequenceIndexes[1] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[1], false, 9, 0, 0, 0);
+ _cardHotspotId = _scene->_dynamicHotspots.add(NOUN_SECURITY_CARD, 0xD, _globals._sequenceIndexes[1], Common::Rect(0, 0, 0, 0));
+ _scene->_dynamicHotspots.setPosition(_cardHotspotId, Common::Point(107, 107), FACING_SOUTH);
+ }
+
+ if (_scene->_priorSceneId == 358)
+ _game._player._playerPos = Common::Point(301, 141);
+ else if (_scene->_priorSceneId != -2)
+ _game._player._playerPos = Common::Point(15, 148);
+
+ sceneEntrySound();
+}
+
+void Scene359::preActions() {
+ if (_action.isAction(VERB_WALK_DOWN, NOUN_CORRIDOR_TO_EAST))
+ _game._player._walkOffScreenSceneId = 358;
+
+ if (_action.isAction(VERB_WALK_DOWN, NOUN_CORRIDOR_TO_WEST))
+ _game._player._walkOffScreenSceneId = 360;
+}
+
+void Scene359::actions() {
+ if (_action._lookFlag) {
+ if ((_game._difficulty != DIFFICULTY_HARD) && (_game._objects[OBJ_SECURITY_CARD]._roomNumber == 359))
+ _vm->_dialogs->show(35914);
+ else
+ _vm->_dialogs->show(35915);
+ } else if (_action.isAction(VERB_TAKE, NOUN_SECURITY_CARD)) {
+ if (_game._trigger || !_game._objects.isInInventory(OBJ_SECURITY_CARD)) {
+ switch (_game._trigger) {
+ case 0:
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _vm->_dialogs->show(35920);
+ if (_globals[kSexOfRex] == REX_MALE) {
+ _globals._sequenceIndexes[2] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[2], false, 4, 2, 0, 0);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[2]);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[2], SEQUENCE_TRIGGER_SPRITE, 6, 1);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[2], SEQUENCE_TRIGGER_EXPIRE, 0, 2);
+ } else {
+ _globals._sequenceIndexes[4] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[4], true, 7, 2, 0, 0);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[4]);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[4], Common::Point(106, 110));
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[4], SEQUENCE_TRIGGER_SPRITE, 6, 1);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[4], SEQUENCE_TRIGGER_EXPIRE, 0, 2);
+ }
+ break;
+
+ case 1:
+ _scene->_sequences.remove(_globals._sequenceIndexes[1]);
+ _scene->_dynamicHotspots.remove(_cardHotspotId);
+ _vm->_sound->command(57);
+ _game._objects.addToInventory(OBJ_SECURITY_CARD);
+ _vm->_dialogs->showItem(OBJ_SECURITY_CARD, 0x330);
+ _scene->changeVariant(1);
+ break;
+
+ case 2:
+ if (_globals[kSexOfRex] == REX_MALE)
+ _scene->_sequences.updateTimeout(-1, _globals._sequenceIndexes[2]);
+ else
+ _scene->_sequences.updateTimeout(-1, _globals._sequenceIndexes[4]);
+
+ _game._player._visible = true;
+ _game._player._stepEnabled = true;
+ break;
+
+ default:
+ break;
+ }
+ }
+ } else if (_action.isAction(VERB_LOOK, NOUN_BLOODY_CELL_WALL))
+ _vm->_dialogs->show(35910);
+ else if (_action.isAction(VERB_LOOK, NOUN_BED))
+ _vm->_dialogs->show(35911);
+ else if (_action.isAction(VERB_LOOK, NOUN_SINK))
+ _vm->_dialogs->show(35912);
+ else if (_action.isAction(VERB_LOOK, NOUN_TOILET))
+ _vm->_dialogs->show(35913);
+ else if (_action.isAction(VERB_LOOK, NOUN_CORRIDOR_TO_EAST))
+ _vm->_dialogs->show(35916);
+ else if (_action.isAction(VERB_LOOK, NOUN_CORRIDOR_TO_WEST))
+ _vm->_dialogs->show(35917);
+ else if (_action.isAction(VERB_LOOK, NOUN_LIMB))
+ _vm->_dialogs->show(35918);
+ else if (_action.isAction(VERB_TAKE, NOUN_LIMB))
+ _vm->_dialogs->show(35919);
+ else if (_action.isAction(VERB_LOOK, NOUN_SECURITY_CARD) && (_action._mainObjectSource == 4))
+ _vm->_dialogs->show(35921);
+ else if (_action.isAction(VERB_LOOK, NOUN_BLOOD_STAIN)) {
+ if ((_game._difficulty != DIFFICULTY_HARD) && (_game._objects[OBJ_SECURITY_CARD]._roomNumber == 359))
+ _vm->_dialogs->show(35922);
+ else
+ _vm->_dialogs->show(35923);
+ } else if (_action.isAction(VERB_LOOK, NOUN_WALL_BOARD))
+ _vm->_dialogs->show(35924);
+ else if (_action.isAction(VERB_TAKE, NOUN_WALL_BOARD))
+ _vm->_dialogs->show(35925);
+ else if (_action.isAction(VERB_LOOK, NOUN_RIP_IN_FLOOR))
+ _vm->_dialogs->show(35926);
+ else if (_action.isAction(VERB_LOOK, NOUN_CORRIDOR))
+ _vm->_dialogs->show(35927);
+ else if (_action.isAction(VERB_LOOK, NOUN_FLOOR)) {
+ if ((_game._difficulty != DIFFICULTY_HARD) && (_game._objects[OBJ_SECURITY_CARD]._roomNumber == 359))
+ _vm->_dialogs->show(35928);
+ else
+ _vm->_dialogs->show(35929);
+ } else if (_action.isAction(VERB_OPEN, NOUN_AIR_VENT) || _action.isAction(VERB_LOOK, NOUN_AIR_VENT))
+ _vm->_dialogs->show(36016);
+ else
+ return;
+
+ _action._inProgress = false;
+}
+
+/*------------------------------------------------------------------------*/
+
+void Scene360::setup() {
+ setPlayerSpritesPrefix();
+ setAAName();
+}
+
+void Scene360::enter() {
+ _globals._spriteIndexes[1] = _scene->_sprites.addSprites(Resources::formatName(307, 'X', 0, EXT_SS, ""));
+ _globals._sequenceIndexes[1] = _scene->_sequences.startCycle(_globals._spriteIndexes[1], false, 1);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[1], Common::Point(127, 78));
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 15);
+
+ if (_scene->_priorSceneId == 359)
+ _game._player._playerPos = Common::Point(304, 143);
+ else if (_scene->_priorSceneId != -2)
+ _game._player._playerPos = Common::Point(13, 141);
+
+ sceneEntrySound();
+}
+
+void Scene360::preActions() {
+ if (_action.isAction(VERB_WALK_DOWN, NOUN_CORRIDOR_TO_EAST))
+ _game._player._walkOffScreenSceneId = 359;
+
+ if (_action.isAction(VERB_WALK_DOWN, NOUN_CORRIDOR_TO_WEST))
+ _game._player._walkOffScreenSceneId = 361;
+}
+
+void Scene360::actions() {
+ if (_action._lookFlag)
+ _vm->_dialogs->show(36015);
+ else if (_action.isAction(VERB_LOOK, NOUN_CORRIDOR_TO_WEST))
+ _vm->_dialogs->show(36010);
+ else if (_action.isAction(VERB_LOOK, NOUN_CORRIDOR_TO_EAST))
+ _vm->_dialogs->show(36011);
+ else if (_action.isAction(VERB_LOOK, NOUN_BED))
+ _vm->_dialogs->show(36012);
+ else if (_action.isAction(VERB_LOOK, NOUN_SINK))
+ _vm->_dialogs->show(36013);
+ else if (_action.isAction(VERB_LOOK, NOUN_TOILET))
+ _vm->_dialogs->show(36014);
+ else if (_action.isAction(VERB_LOOK, NOUN_AIR_VENT))
+ _vm->_dialogs->show(36016);
+ else if (_action.isAction(VERB_LOOK, NOUN_CORRIDOR))
+ _vm->_dialogs->show(36017);
+ else if (_action.isAction(VERB_LOOK, NOUN_WALL))
+ _vm->_dialogs->show(36018);
+ else
+ return;
+
+ _action._inProgress = false;
+}
+
+/*------------------------------------------------------------------------*/
+
+void Scene361::setup() {
+ if (_scene->_currentSceneId == 391)
+ _globals[kSexOfRex] = REX_MALE;
+
+ setPlayerSpritesPrefix();
+ setAAName();
+}
+
+void Scene361::handleRexAction() {
+ switch (_game._trigger) {
+ case 0:
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _scene->_sequences.remove(_globals._sequenceIndexes[1]);
+ _globals._sequenceIndexes[1] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[1], false, 50, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[1], 3, -2);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[1], Common::Point(165, 76));
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 15);
+
+ _globals._sequenceIndexes[2] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[2], false, 15, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[2], -1, 4);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[2]);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[1], SEQUENCE_TRIGGER_EXPIRE, 0, 1);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[2], SEQUENCE_TRIGGER_EXPIRE, 0, 2);
+ break;
+
+ case 1: {
+ int seqIdx = _globals._sequenceIndexes[1];
+ _globals._sequenceIndexes[1] = _scene->_sequences.startCycle(_globals._spriteIndexes[1], false, 4);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[1], Common::Point(165, 76));
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 15);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[1], seqIdx);
+ }
+ break;
+
+ case 2: {
+ int seqIdx = _globals._sequenceIndexes[2];
+ _globals._sequenceIndexes[2] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[2], false, 12, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[2], 4, 10);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[2]);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[2], seqIdx);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[2], SEQUENCE_TRIGGER_EXPIRE, 0, 3);
+ }
+ break;
+
+ case 3: {
+ _scene->_sequences.remove(_globals._sequenceIndexes[1]);
+ _globals._sequenceIndexes[1] = _scene->_sequences.startCycle(_globals._spriteIndexes[1], false, 3);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[1], Common::Point(165, 76));
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 1);
+
+ int seqIdx = _globals._sequenceIndexes[2];
+ _globals._sequenceIndexes[2] = _scene->_sequences.startCycle(_globals._spriteIndexes[2], false, 11);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[2]);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[2], Common::Point(167, 100));
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[2], seqIdx);
+ _scene->_sequences.addTimer(15, 4);
+ }
+ break;
+
+ case 4:
+ _scene->_sequences.remove(_globals._sequenceIndexes[1]);
+ _globals._sequenceIndexes[1] = _scene->_sequences.startCycle(_globals._spriteIndexes[1], false, 2);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[1], Common::Point(165, 76));
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 1);
+
+ _scene->_sequences.setDone(_globals._sequenceIndexes[2]);
+ _globals._sequenceIndexes[2] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[2], false, 12, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[2], 12, 14);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[2]);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[2], Common::Point(167, 100));
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[2], SEQUENCE_TRIGGER_EXPIRE, 0, 5);
+ break;
+
+ case 5: {
+ int seqIdx = _globals._sequenceIndexes[2];
+ _globals._sequenceIndexes[2] = _scene->_sequences.startCycle(_globals._spriteIndexes[2], false, 15);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[2]);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[2], Common::Point(167, 100));
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[2], seqIdx);
+ _scene->_sequences.addTimer(15, 6);
+ }
+ break;
+
+ case 6:
+ _scene->_sequences.setDone(_globals._sequenceIndexes[2]);
+ _scene->_sequences.remove(_globals._sequenceIndexes[1]);
+ _globals._sequenceIndexes[1] = _scene->_sequences.startCycle(_globals._spriteIndexes[1], false, 1);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[1], Common::Point(165, 76));
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 1);
+ _scene->_sequences.addTimer(48, 7);
+ break;
+
+ case 7:
+ _scene->_nextSceneId = 313;
+ break;
+
+ default:
+ break;
+ }
+}
+
+void Scene361::handleRoxAction() {
+ switch (_game._trigger) {
+ case 0:
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _scene->_sequences.remove(_globals._sequenceIndexes[1]);
+ _globals._sequenceIndexes[1] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[1], false, 18, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[1], 2, 4);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[1], Common::Point(165, 76));
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 15);
+
+ _globals._sequenceIndexes[4] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[4], false, 18, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[4], -1, 3);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[4]);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[1], SEQUENCE_TRIGGER_EXPIRE, 0, 1);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[4], SEQUENCE_TRIGGER_EXPIRE, 0, 2);
+ break;
+
+ case 1: {
+ int tmpIdx = _globals._sequenceIndexes[1];
+ _globals._sequenceIndexes[1] = _scene->_sequences.startCycle(_globals._spriteIndexes[1], false, 4);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[1], Common::Point(165, 76));
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 15);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[1], tmpIdx);
+ }
+ break;
+
+ case 2: {
+ int tmpIdx = _globals._sequenceIndexes[4];
+ _globals._sequenceIndexes[4] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[4], false, 12, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[4], 4, 8);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[4]);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[4], tmpIdx);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[4], SEQUENCE_TRIGGER_EXPIRE, 0, 3);
+ }
+ break;
+
+ case 3: {
+ _scene->_sequences.remove(_globals._sequenceIndexes[1]);
+ _globals._sequenceIndexes[1] = _scene->_sequences.startCycle(_globals._spriteIndexes[1], false, 3);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[1], Common::Point(165, 76));
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 1);
+
+ int tmpIdx = _globals._sequenceIndexes[4];
+ _globals._sequenceIndexes[4] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[4], false, 12, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[4], 9, 10);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[4]);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[4], Common::Point(167, 100));
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[4], tmpIdx);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[4], SEQUENCE_TRIGGER_EXPIRE, 0, 4);
+ }
+ break;
+
+ case 4: {
+ _scene->_sequences.remove(_globals._sequenceIndexes[1]);
+ _globals._sequenceIndexes[1] = _scene->_sequences.startCycle(_globals._spriteIndexes[1], false, 2);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[1], Common::Point(165, 76));
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 1);
+
+ int tmpIdx = _globals._sequenceIndexes[4];
+ _globals._sequenceIndexes[4] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[4], false, 12, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[4], 11, 15);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[4]);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[4], Common::Point(167, 100));
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[4], tmpIdx);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[4], SEQUENCE_TRIGGER_EXPIRE, 0, 5);
+ }
+ break;
+
+ case 5: {
+ int tmpIdx = _globals._sequenceIndexes[4];
+ _globals._sequenceIndexes[4] = _scene->_sequences.startCycle(_globals._spriteIndexes[4], false, 16);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[4]);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[4], Common::Point(167, 100));
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[4], tmpIdx);
+ _scene->_sequences.addTimer(48, 6);
+ }
+ break;
+
+ case 6:
+ _scene->_sequences.setDone(_globals._sequenceIndexes[4]);
+
+ _scene->_sequences.remove(_globals._sequenceIndexes[1]);
+ _globals._sequenceIndexes[1] = _scene->_sequences.startCycle(_globals._spriteIndexes[1], false, 1);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[1], Common::Point(165, 76));
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 1);
+ _scene->_sequences.addTimer(48, 7);
+ break;
+
+ case 7:
+ _scene->_nextSceneId = 313;
+ break;
+
+ default:
+ break;
+ }
+}
+
+void Scene361::enter() {
+ _globals._spriteIndexes[1] = _scene->_sprites.addSprites(Resources::formatName(307, 'X', 0, EXT_SS, ""));
+
+ if (_globals[kSexOfRex] == REX_MALE) {
+ _globals._spriteIndexes[2] = _scene->_sprites.addSprites("*RXCL_8");
+ _globals._spriteIndexes[3] = _scene->_sprites.addSprites("*RXCL_2");
+ } else
+ _globals._spriteIndexes[4] = _scene->_sprites.addSprites("*ROXCL_8");
+
+ _globals._sequenceIndexes[1] = _scene->_sequences.startCycle(_globals._spriteIndexes[1], false, 1);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[1], Common::Point(165, 76));
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 15);
+
+ if (_scene->_priorSceneId == 391) {
+ _globals[kSexOfRex] = REX_MALE;
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _game._player._facing = FACING_SOUTH;
+ _game._player._playerPos = Common::Point(166, 101);
+ _scene->_sequences.addTimer(120, 70);
+ } else if (_scene->_priorSceneId == 360)
+ _game._player._playerPos = Common::Point(302, 145);
+ else if (_scene->_priorSceneId == 320) {
+ _game._player._playerPos = Common::Point(129, 113);
+ _game._player._facing = FACING_SOUTH;
+ } else if (_scene->_priorSceneId != -2)
+ _game._player._playerPos = Common::Point(13, 145);
+
+ _game.loadQuoteSet(0xFB, 0xFC, 0);
+
+ if (_scene->_priorSceneId == 320)
+ _scene->_kernelMessages.setQuoted(_scene->_kernelMessages.addQuote(0xFB, 0, 0x78), 4, true);
+
+ sceneEntrySound();
+}
+
+void Scene361::step() {
+ if (_game._trigger >= 70) {
+ switch (_game._trigger) {
+ case 70:
+ _scene->_sequences.remove(_globals._sequenceIndexes[1]);
+ _globals._sequenceIndexes[1] = _scene->_sequences.startCycle(_globals._spriteIndexes[1], false, 2);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[1], Common::Point(165, 76));
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 1);
+
+ _globals._sequenceIndexes[3] = _scene->_sequences.startCycle(_globals._spriteIndexes[3], false, 1);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[3]);
+ _scene->_sequences.addTimer(15, 71);
+ break;
+
+ case 71:
+ _scene->_sequences.setDone(_globals._sequenceIndexes[3]);
+ _globals._sequenceIndexes[3] = _scene->_sequences.startCycle(_globals._spriteIndexes[3], false, 2);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[3]);
+ _scene->_sequences.addTimer(15, 72);
+ break;
+
+ case 72:
+ _scene->_sequences.remove(_globals._sequenceIndexes[1]);
+ _globals._sequenceIndexes[1] = _scene->_sequences.startCycle(_globals._spriteIndexes[1], false, 3);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[1], Common::Point(165, 76));
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 1);
+
+ _scene->_sequences.setDone(_globals._sequenceIndexes[3]);
+ _globals._sequenceIndexes[3] = _scene->_sequences.startCycle(_globals._spriteIndexes[3], false, 3);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[3]);
+ _scene->_sequences.addTimer(15, 73);
+ break;
+
+ case 73:
+ _scene->_sequences.setDone(_globals._sequenceIndexes[3]);
+ _globals._sequenceIndexes[3] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[3], false, 12, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[3], 4, 5);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[3]);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[3], SEQUENCE_TRIGGER_EXPIRE, 0, 74);
+ break;
+
+ case 74: {
+ int seqIdx = _globals._sequenceIndexes[3];
+ _globals._sequenceIndexes[3] = _scene->_sequences.startCycle(_globals._spriteIndexes[3], false, 6);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[3]);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[3], seqIdx);
+ _scene->_sequences.addTimer(15, 75);
+ }
+ break;
+
+ case 75:
+ _scene->_sequences.setDone(_globals._sequenceIndexes[3]);
+ _globals._sequenceIndexes[3] = _scene->_sequences.startCycle(_globals._spriteIndexes[3], false, 7);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[3]);
+ _scene->_sequences.addTimer(15, 76);
+ break;
+
+ case 76:
+ _scene->_sequences.remove(_globals._sequenceIndexes[1]);
+ _globals._sequenceIndexes[1] = _scene->_sequences.startCycle(_globals._spriteIndexes[1], false, 2);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[1], Common::Point(165, 76));
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 1);
+
+ _scene->_sequences.setDone(_globals._sequenceIndexes[3]);
+ _globals._sequenceIndexes[3] = _scene->_sequences.startCycle(_globals._spriteIndexes[3], false, 8);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[3]);
+ _scene->_sequences.addTimer(15, 77);
+ break;
+
+ case 77:
+ _scene->_sequences.remove(_globals._sequenceIndexes[1]);
+ _globals._sequenceIndexes[1] = _scene->_sequences.startCycle(_globals._spriteIndexes[1], false, 1);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[1], Common::Point(165, 76));
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 15);
+
+ _scene->_sequences.setDone(_globals._sequenceIndexes[3]);
+ _globals._sequenceIndexes[3] = _scene->_sequences.startCycle(_globals._spriteIndexes[3], false, 9);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[3]);
+ _scene->_sequences.addTimer(15, 78);
+ break;
+
+ case 78:
+ _scene->_sequences.setDone(_globals._sequenceIndexes[3]);
+ _globals._sequenceIndexes[3] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[3], false, 12, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[3], 10, -2);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[3]);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[3], SEQUENCE_TRIGGER_EXPIRE, 0, 79);
+ break;
+
+ case 79:
+ _scene->_sequences.updateTimeout(-1, _globals._sequenceIndexes[3]);
+ _game._player._stepEnabled = true;
+ _game._player._visible = true;
+ break;
+
+ default:
+ break;
+ }
+ }
+}
+
+void Scene361::preActions() {
+ if (_action.isAction(VERB_WALK_DOWN, NOUN_CORRIDOR_TO_EAST))
+ _game._player._walkOffScreenSceneId = 360;
+
+ if (_action.isAction(VERB_WALK_DOWN, NOUN_CORRIDOR_TO_WEST))
+ _game._player._walkOffScreenSceneId = 354;
+}
+
+void Scene361::actions() {
+ if (_action._lookFlag)
+ _vm->_dialogs->show(36119);
+ else if (_action.isAction(VERB_SIT_AT, NOUN_DESK)) {
+ _scene->_kernelMessages.reset();
+ _scene->_kernelMessages.addQuote(0xFC, 120, 0);
+ } else if (_action.isAction(VERB_CLIMB_INTO, NOUN_AIR_VENT)) {
+ if (_globals[kSexOfRex] == REX_FEMALE)
+ handleRoxAction();
+ else
+ handleRexAction();
+ } else if (_action.isAction(VERB_LOOK, NOUN_DESK))
+ _vm->_dialogs->show(36110);
+ else if (_action.isAction(VERB_LOOK, NOUN_WALL))
+ _vm->_dialogs->show(36111);
+ else if (_action.isAction(VERB_LOOK, NOUN_LIGHTING_FIXTURE) || _action.isAction(VERB_STARE_AT, NOUN_LIGHTING_FIXTURE))
+ _vm->_dialogs->show(36112);
+ else if (_action.isAction(VERB_LOOK, NOUN_LIGHTS) || _action.isAction(VERB_STARE_AT, NOUN_LIGHTS))
+ _vm->_dialogs->show(36113);
+ else if (_action.isAction(VERB_TAKE, NOUN_LIGHTS))
+ _vm->_dialogs->show(36114);
+ else if (_action.isAction(VERB_LOOK, NOUN_LIGHT_BULB) || _action.isAction(VERB_STARE_AT, NOUN_LIGHT_BULB))
+ _vm->_dialogs->show(36115);
+ else if (_action.isAction(VERB_TAKE, NOUN_LIGHT_BULB))
+ _vm->_dialogs->show(36116);
+ else if (_action.isAction(VERB_LOOK, NOUN_CORRIDOR_TO_WEST))
+ _vm->_dialogs->show(36117);
+ else if (_action.isAction(VERB_LOOK, NOUN_CORRIDOR_TO_EAST))
+ _vm->_dialogs->show(36118);
+ else if (_action.isAction(VERB_LOOK, NOUN_AIR_VENT))
+ _vm->_dialogs->show(36120);
+ else
+ return;
+
+ _action._inProgress = false;
+}
+
+/*------------------------------------------------------------------------*/
+
+void Scene366::setup() {
+ setPlayerSpritesPrefix();
+ setAAName();
+}
+
+void Scene366::enter() {
+ _scene->_userInterface.setup(kInputLimitedSentences);
+ _game._player._visible = false;
+ sceneEntrySound();
+}
+
+void Scene366::actions() {
+ if (_action.isAction(VERB_RETURN_TO, NOUN_AIR_SHAFT))
+ _scene->_nextSceneId = 302;
+ else if (_action.isAction(VERB_OPEN, NOUN_GRATE)) {
+ if (_game._visitedScenes.exists(316))
+ _vm->_dialogs->show(36612);
+ else
+ _vm->_dialogs->show(36613);
+ _scene->_nextSceneId = 316;
+ } else if (_action.isAction(VERB_LOOK_THROUGH, NOUN_GRATE)) {
+ if (_game._visitedScenes.exists(321))
+ _vm->_dialogs->show(36611);
+ else
+ _vm->_dialogs->show(36610);
+ } else {
+ return;
+ }
+
+ _action._inProgress = false;
+}
+
+/*------------------------------------------------------------------------*/
+
+void Scene387::setup() {
+ setPlayerSpritesPrefix();
+ setAAName();
+}
+
+void Scene387::enter() {
+ _scene->_userInterface.setup(kInputLimitedSentences);
+ _game._player._visible = false;
+
+ sceneEntrySound();
+}
+
+void Scene387::actions() {
+ if (_action.isAction(VERB_RETURN_TO, NOUN_AIR_SHAFT))
+ _scene->_nextSceneId = 313;
+ else if (_action.isAction(VERB_LOOK_THROUGH, NOUN_GRATE))
+ _vm->_dialogs->show(38710);
+ else if (_action.isAction(VERB_OPEN, NOUN_GRATE))
+ _vm->_dialogs->show(38711);
+ else
+ return;
+
+ _action._inProgress = false;
+}
+
+/*------------------------------------------------------------------------*/
+
+void Scene388::setup() {
+ setPlayerSpritesPrefix();
+ setAAName();
+}
+
+void Scene388::enter() {
+ _scene->_userInterface.setup(kInputLimitedSentences);
+
+ if (_globals[kAfterHavoc])
+ _scene->_hotspots.activate(NOUN_SAUROPOD, false);
+ else {
+ _globals._spriteIndexes[0] = _scene->_sprites.addSprites(formAnimName('b', 0));
+ _globals._sequenceIndexes[0] = _scene->_sequences.startCycle(_globals._spriteIndexes[0], false, 1);
+ }
+
+ _game._player._visible = false;
+ _vm->_palette->setEntry(252, 63, 30, 20);
+ _vm->_palette->setEntry(253, 45, 15, 12);
+ _game.loadQuoteSet(0x154, 0x155, 0x156, 0x157, 0x158, 0);
+
+ sceneEntrySound();
+}
+
+void Scene388::actions() {
+ if (_action.isAction(VERB_RETURN_TO, NOUN_AIR_SHAFT))
+ _scene->_nextSceneId = 313;
+ else if (_action.isAction(VERB_TALKTO, NOUN_SAUROPOD)) {
+ switch (_game._trigger) {
+ case 0:
+ _game._player._stepEnabled = false;
+ _scene->_kernelMessages.reset();
+ _scene->_kernelMessages.add(Common::Point(160, 136), 0x1110, 32, 1, 120, _game.getQuote(0x154));
+ break;
+
+ case 1:
+ _scene->_kernelMessages.add(Common::Point(82, 38), 0xFDFC, 0, 0, 300, _game.getQuote(0x156));
+ _scene->_kernelMessages.add(Common::Point(82, 52), 0xFDFC, 0, 0, 300, _game.getQuote(0x157));
+ _scene->_kernelMessages.add(Common::Point(82, 66), 0xFDFC, 0, 2, 300, _game.getQuote(0x158));
+ break;
+
+ case 2:
+ _game._player._stepEnabled = true;
+ _scene->_kernelMessages.add(Common::Point(160, 136), 0x1110, 32, 0, 120, _game.getQuote(0x155));
+ break;
+
+ default:
+ break;
+ }
+ } else if (_action.isAction(VERB_LOOK_THROUGH, NOUN_GRATE)) {
+ if (_globals[kAfterHavoc])
+ _vm->_dialogs->show(38811);
+ else
+ _vm->_dialogs->show(38810);
+ } else if (_action.isAction(VERB_OPEN, NOUN_GRATE))
+ _vm->_dialogs->show(38812);
+ else
+ return;
+
+ _action._inProgress = false;
+}
+
+/*------------------------------------------------------------------------*/
+
+Scene389::Scene389(MADSEngine *vm) : Scene300s(vm) {
+ _monsterTime = 0;
+ _circularQuoteId = -1;
+}
+
+void Scene389::synchronize(Common::Serializer &s) {
+ Scene3xx::synchronize(s);
+
+ s.syncAsUint32LE(_monsterTime);
+ s.syncAsSint32LE(_circularQuoteId);
+}
+
+void Scene389::setup() {
+ setPlayerSpritesPrefix();
+ setAAName();
+}
+
+void Scene389::enter() {
+ _scene->_userInterface.setup(kInputLimitedSentences);
+ _monsterTime = 0;
+ _circularQuoteId = 0x159;
+
+ if (_globals[kAfterHavoc])
+ _scene->_hotspots.activate(NOUN_MONSTER, false);
+ else {
+ _globals._spriteIndexes[0] = _scene->_sprites.addSprites(formAnimName('m', -1));
+ _globals._sequenceIndexes[0] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[0], false, 6, 0, 0, 0);
+ _scene->_kernelMessages.initRandomMessages(1,
+ Common::Rect(88, 19, 177, 77), 13, 2, 0xFDFC, 60,
+ 247, 248, 249, 0);
+ }
+
+ _vm->_palette->setEntry(252, 63, 37, 26);
+ _vm->_palette->setEntry(253, 45, 24, 17);
+ _game._player._visible = false;
+ _game.loadQuoteSet(0xF7, 0xF8, 0xF9, 0x159, 0x15A, 0x15B, 0);
+
+ sceneEntrySound();
+}
+
+void Scene389::step() {
+ _scene->_kernelMessages.randomServer();
+ if (_scene->_frameStartTime >= _monsterTime) {
+ int chanceMinor = _scene->_kernelMessages.checkRandom() * 4 + 1;
+ _scene->_kernelMessages.generateRandom(20, chanceMinor);
+ _monsterTime = _scene->_frameStartTime + 2;
+ }
+}
+
+void Scene389::actions() {
+ if (_action.isAction(VERB_RETURN_TO, NOUN_AIR_SHAFT))
+ _scene->_nextSceneId = 313;
+ else if (_action.isAction(VERB_TALKTO, NOUN_MONSTER)) {
+ switch (_game._trigger) {
+ case 0:
+ _game._player._stepEnabled = false;
+ _scene->_kernelMessages.add(Common::Point(160, 136), 0x1110, 32, 1, 120, _game.getQuote(_circularQuoteId));
+ _circularQuoteId++;
+ if (_circularQuoteId > 0x15B)
+ _circularQuoteId = 0x159;
+
+ break;
+
+ case 1:
+ _game._player._stepEnabled = true;
+ break;
+
+ default:
+ break;
+ }
+ } else if (_action.isAction(VERB_LOOK_THROUGH, NOUN_GRATE)) {
+ if (_globals[kAfterHavoc]) {
+ if ((_game._difficulty != DIFFICULTY_HARD) && (_game._objects[OBJ_SECURITY_CARD]._roomNumber == 359))
+ _vm->_dialogs->show(38911);
+ else
+ _vm->_dialogs->show(38912);
+ } else
+ _vm->_dialogs->show(38910);
+ } else if (_action.isAction(VERB_OPEN, NOUN_GRATE)) {
+ if (_globals[kAfterHavoc])
+ _vm->_dialogs->show(38914);
+ else
+ _vm->_dialogs->show(38913);
+ } else
+ return;
+
+ _action._inProgress = false;
+}
+
+/*------------------------------------------------------------------------*/
+
+void Scene390::setup() {
+ setPlayerSpritesPrefix();
+ setAAName();
+}
+
+void Scene390::enter() {
+ _scene->_userInterface.setup(kInputLimitedSentences);
+ _game._player._visible = false;
+
+ sceneEntrySound();
+}
+
+void Scene390::actions() {
+ if (_action.isAction(VERB_RETURN_TO, NOUN_AIR_SHAFT))
+ _scene->_nextSceneId = 313;
+ else if (_action.isAction(VERB_LOOK_THROUGH, NOUN_GRATE))
+ _vm->_dialogs->show(39010);
+ else if (_action.isAction(VERB_OPEN, NOUN_GRATE))
+ _vm->_dialogs->show(39011);
+ else
+ return;
+
+ _action._inProgress = false;
+}
+
+/*------------------------------------------------------------------------*/
+
+void Scene391::setup() {
+ setPlayerSpritesPrefix();
+ setAAName();
+}
+
+void Scene391::enter() {
+ _scene->_userInterface.setup(kInputLimitedSentences);
+ _game._player._visible = false;
+ sceneEntrySound();
+}
+
+void Scene391::actions() {
+ if (_action.isAction(VERB_RETURN_TO, NOUN_AIR_SHAFT))
+ _scene->_nextSceneId = 313;
+ else if (_action.isAction(VERB_OPEN, NOUN_GRATE)) {
+ if (_globals[kKickedIn391Grate])
+ _vm->_dialogs->show(39113);
+ else {
+ _vm->_dialogs->show(39112);
+ _globals[kKickedIn391Grate] = true;
+ }
+
+ if (_globals[kAfterHavoc])
+ _scene->_nextSceneId = 361;
+ else
+ _scene->_nextSceneId = 311;
+ } else if (_action.isAction(VERB_LOOK_THROUGH, NOUN_GRATE)) {
+ if (_globals[kAfterHavoc])
+ _vm->_dialogs->show(39111);
+ else
+ _vm->_dialogs->show(39110);
+ } else
+ return;
+
+ _action._inProgress = false;
+}
+
+/*------------------------------------------------------------------------*/
+
+void Scene399::setup() {
+ setPlayerSpritesPrefix();
+ setAAName();
+}
+
+void Scene399::enter() {
+ _scene->_userInterface.setup(kInputLimitedSentences);
+ _game._player._visible = false;
+ sceneEntrySound();
+}
+
+void Scene399::actions() {
+ if (_action.isAction(VERB_RETURN_TO, NOUN_AIR_SHAFT))
+ _scene->_nextSceneId = 313;
+ else if (_action.isAction(VERB_LOOK_THROUGH, NOUN_GRATE)) {
+ if (_globals[kAfterHavoc]) {
+ if ((_game._difficulty != DIFFICULTY_HARD) && (_game._objects[OBJ_SECURITY_CARD]._roomNumber == 359))
+ _vm->_dialogs->show(38911);
+ else
+ _vm->_dialogs->show(38912);
+ } else
+ _vm->_dialogs->show(38910);
+ } else if (_action.isAction(VERB_OPEN, NOUN_GRATE)) {
+ if (_globals[kAfterHavoc])
+ _vm->_dialogs->show(38914);
+ else
+ _vm->_dialogs->show(38913);
+ } else
+ return;
+
+ _action._inProgress = false;
+}
+
+/*------------------------------------------------------------------------*/
+
+} // End of namespace Nebular
+} // End of namespace MADS
diff --git a/engines/mads/nebular/nebular_scenes3.h b/engines/mads/nebular/nebular_scenes3.h
new file mode 100644
index 0000000000..30ab333e53
--- /dev/null
+++ b/engines/mads/nebular/nebular_scenes3.h
@@ -0,0 +1,540 @@
+/* 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.
+ *
+ */
+
+#ifndef MADS_NEBULAR_SCENES3_H
+#define MADS_NEBULAR_SCENES3_H
+
+#include "common/scummsys.h"
+#include "mads/game.h"
+#include "mads/scene.h"
+#include "mads/nebular/nebular_scenes.h"
+
+namespace MADS {
+
+namespace Nebular {
+
+typedef struct {
+ bool _flag;
+ int _vertical;
+ int _horizontal;
+ int _seqId[40];
+ uint32 _timer;
+
+ void synchronize(Common::Serializer &s) {
+ s.syncAsByte(_flag);
+ s.syncAsSint32LE(_vertical);
+ s.syncAsSint32LE(_horizontal);
+ for (int i = 0; i < 40; ++i)
+ s.syncAsSint32LE(_seqId[i]);
+ s.syncAsUint32LE(_timer);
+ };
+} ForceField;
+
+class Scene3xx : public NebularScene {
+protected:
+ /**
+ * Plays an appropriate sound when entering a scene
+ */
+ void setAAName();
+
+ /**
+ * Updates the prefix used for getting player sprites for the scene
+ */
+ void setPlayerSpritesPrefix();
+
+ void sceneEntrySound();
+
+ void initForceField(ForceField *force, bool flag);
+ void handleForceField(ForceField *force, int *sprites);
+ int computeScale(int low, int high, int id);
+
+public:
+ Scene3xx(MADSEngine *vm) : NebularScene(vm) {}
+
+ virtual void actions() {}
+};
+
+class Scene300s : public Scene3xx {
+public:
+ Scene300s(MADSEngine *vm) : Scene3xx(vm) {}
+
+ virtual void preActions();
+};
+
+class Scene301: public Scene3xx {
+public:
+ Scene301(MADSEngine *vm) : Scene3xx(vm) {}
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+};
+
+class Scene302: public Scene3xx {
+private:
+ int _oldFrame;
+
+public:
+ Scene302(MADSEngine *vm);
+ virtual void synchronize(Common::Serializer &s);
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+};
+
+class Scene303: public Scene3xx {
+public:
+ Scene303(MADSEngine *vm) : Scene3xx(vm) {}
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+};
+
+class Scene304: public Scene3xx {
+private:
+ int _explosionSpriteId;
+
+public:
+ Scene304(MADSEngine *vm);
+ virtual void synchronize(Common::Serializer &s);
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+};
+
+class Scene307: public Scene3xx {
+private:
+ ForceField _forceField;
+
+ bool _afterPeeingFl;
+ bool _duringPeeingFl;
+ bool _grateOpenedFl;
+ bool _activePrisonerFl;
+
+ int _animationMode;
+ int _prisonerMessageId;
+ int _fieldCollisionCounter;
+
+ uint32 _lastFrameTime;
+ uint32 _guardTime;
+ uint32 _prisonerTimer;
+
+ Common::String _subQuote2;
+
+ Conversation _dialog1, _dialog2;
+
+ void handleDialog();
+ void handleRexDialog(int quote);
+ void handlePrisonerDialog();
+ void handlePrisonerEncounter();
+ void setDialogNode(int node);
+ void handlePrisonerSpeech(int firstQuoteId, int number, long timeout);
+
+public:
+ Scene307(MADSEngine *vm);
+ virtual void synchronize(Common::Serializer &s);
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+ virtual void actions();
+};
+
+class Scene308: public Scene3xx {
+private:
+ ForceField _forceField;
+
+public:
+ Scene308(MADSEngine *vm) : Scene3xx(vm) {}
+ virtual void synchronize(Common::Serializer &s);
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+};
+
+class Scene309: public Scene3xx {
+private:
+ ForceField _forceField;
+ int _characterSpriteIndexes[3];
+ int _messagesIndexes[3];
+ int _lastFrame;
+
+public:
+ Scene309(MADSEngine *vm);
+ virtual void synchronize(Common::Serializer &s);
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+};
+
+class Scene310: public Scene3xx {
+private:
+ ForceField _forceField;
+
+public:
+ Scene310(MADSEngine *vm) : Scene3xx(vm) {}
+ virtual void synchronize(Common::Serializer &s);
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+};
+
+class Scene311: public Scene3xx {
+private:
+ bool _checkGuardFl;
+
+public:
+ Scene311(MADSEngine *vm);
+ virtual void synchronize(Common::Serializer &s);
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+ virtual void actions();
+};
+
+class Scene313: public Scene3xx {
+public:
+ Scene313(MADSEngine *vm) : Scene3xx(vm) {}
+
+ virtual void setup();
+ virtual void enter();
+ virtual void actions();
+};
+
+class Scene316: public Scene3xx {
+private:
+ void handleRexInGrate();
+ void handleRoxInGrate();
+
+public:
+ Scene316(MADSEngine *vm) : Scene3xx(vm) {}
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+ virtual void preActions();
+ virtual void actions();
+};
+
+class Scene318: public Scene3xx {
+private:
+ uint32 _dropTimer;
+
+ int _lastFrame;
+ int _animMode;
+ int _internCounter;
+ int _counter;
+
+ bool _dialogFl;
+ bool _internTalkingFl;
+ bool _internWalkingFl;
+ bool _internVisibleFl;
+ bool _explosionFl;
+
+ uint32 _lastFrameCounter;
+
+ Common::String _subQuote2;
+
+ Conversation _dialog1;
+
+ void handleDialog();
+ void handleRexDialogs(int quote);
+ void handleInternDialog(int quoteId, int quoteNum, uint32 timeout);
+
+public:
+ Scene318(MADSEngine *vm);
+ virtual void synchronize(Common::Serializer &s);
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+ virtual void preActions();
+ virtual void actions();
+};
+
+class Scene319: public Scene3xx {
+private:
+ Conversation _dialog1, _dialog2, _dialog3;
+
+ int _animMode, _animFrame;
+ int _nextAction1, _nextAction2;
+ int _slacheMode;
+ int _slacheTopic;
+ int _slachePosY;
+
+ bool _slacheTalkingFl;
+ bool _slacheReady;
+ bool _slacheInitFl;
+
+ Common::String _subQuote2;
+
+ void handleRexDialogues(int quote);
+ void handleSlacheDialogs(int quoteId, int counter, uint32 timer);
+public:
+ Scene319(MADSEngine *vm);
+ virtual void synchronize(Common::Serializer &s);
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+ virtual void actions();
+};
+
+class Scene320: public Scene300s {
+private:
+ void setRightView(int view);
+ void setLeftView(int view);
+ void handleButtons();
+
+ bool _blinkFl;
+ bool _flippedFl;
+
+ int _buttonId;
+ int _lastFrame;
+ int _leftItemId;
+ int _posX;
+ int _rightItemId;
+
+public:
+ Scene320(MADSEngine *vm);
+ virtual void synchronize(Common::Serializer &s);
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+ virtual void actions();
+};
+
+class Scene321: public Scene3xx {
+public:
+ Scene321(MADSEngine *vm) : Scene3xx(vm) {}
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+};
+
+class Scene322: public SceneTeleporter {
+public:
+ Scene322(MADSEngine *vm) : SceneTeleporter(vm) {}
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+ virtual void actions();
+};
+
+class Scene351: public Scene3xx {
+public:
+ Scene351(MADSEngine *vm) : Scene3xx(vm) {}
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+ virtual void actions();
+};
+
+class Scene352: public Scene3xx {
+private:
+ bool _vaultOpenFl;
+ bool _mustPutArmDownFl;
+ bool _leaveRoomFl;
+
+ int _tapePlayerHotspotIdx;
+ int _hotspot1Idx;
+ int _hotspot2Idx;
+ int _lampHostpotIdx;
+ int _commonSequenceIdx;
+ int _commonSpriteIndex;
+
+ void putArmDown(bool corridorExit, bool doorwayExit);
+
+public:
+ Scene352(MADSEngine *vm);
+ virtual void synchronize(Common::Serializer &s);
+
+ virtual void setup();
+ virtual void enter();
+ virtual void preActions();
+ virtual void actions();
+};
+
+class Scene353: public Scene3xx {
+public:
+ Scene353(MADSEngine *vm) : Scene3xx(vm) {}
+
+ virtual void setup();
+ virtual void enter();
+ virtual void actions();
+};
+
+class Scene354: public Scene3xx {
+public:
+ Scene354(MADSEngine *vm) : Scene3xx(vm) {}
+
+ virtual void setup();
+ virtual void enter();
+ virtual void preActions();
+ virtual void actions();
+};
+
+class Scene357: public Scene3xx {
+public:
+ Scene357(MADSEngine *vm) : Scene3xx(vm) {}
+
+ virtual void setup();
+ virtual void enter();
+ virtual void preActions();
+ virtual void actions();
+};
+
+class Scene358: public Scene3xx {
+public:
+ Scene358(MADSEngine *vm) : Scene3xx(vm) {}
+
+ virtual void setup();
+ virtual void enter();
+ virtual void preActions();
+ virtual void actions();
+};
+
+class Scene359: public Scene3xx {
+private:
+ int _cardHotspotId;
+
+public:
+ Scene359(MADSEngine *vm);
+ virtual void synchronize(Common::Serializer &s);
+
+ virtual void setup();
+ virtual void enter();
+ virtual void preActions();
+ virtual void actions();
+};
+
+class Scene360: public Scene3xx {
+public:
+ Scene360(MADSEngine *vm) : Scene3xx(vm) {}
+
+ virtual void setup();
+ virtual void enter();
+ virtual void preActions();
+ virtual void actions();
+};
+
+class Scene361: public Scene3xx {
+private:
+ void handleRexAction();
+ void handleRoxAction();
+
+public:
+ Scene361(MADSEngine *vm) : Scene3xx(vm) {}
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+ virtual void preActions();
+ virtual void actions();
+};
+
+class Scene366: public Scene300s {
+public:
+ Scene366(MADSEngine *vm) : Scene300s(vm) {}
+
+ virtual void setup();
+ virtual void enter();
+ virtual void actions();
+};
+
+class Scene387: public Scene300s {
+public:
+ Scene387(MADSEngine *vm) : Scene300s(vm) {}
+
+ virtual void setup();
+ virtual void enter();
+ virtual void actions();
+};
+
+class Scene388: public Scene300s {
+public:
+ Scene388(MADSEngine *vm) : Scene300s(vm) {}
+
+ virtual void setup();
+ virtual void enter();
+ virtual void actions();
+};
+
+class Scene389: public Scene300s {
+private:
+ uint32 _monsterTime;
+
+ int _circularQuoteId;
+
+public:
+ Scene389(MADSEngine *vm);
+ virtual void synchronize(Common::Serializer &s);
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+ virtual void actions();
+};
+
+class Scene390: public Scene300s {
+public:
+ Scene390(MADSEngine *vm) : Scene300s(vm) {}
+
+ virtual void setup();
+ virtual void enter();
+ virtual void actions();
+};
+
+class Scene391: public Scene300s {
+public:
+ Scene391(MADSEngine *vm) : Scene300s(vm) {}
+
+ virtual void setup();
+ virtual void enter();
+ virtual void actions();
+};
+
+class Scene399: public Scene300s {
+public:
+ Scene399(MADSEngine *vm) : Scene300s(vm) {}
+
+ virtual void setup();
+ virtual void enter();
+ virtual void actions();
+};
+
+} // End of namespace Nebular
+
+} // End of namespace MADS
+
+#endif /* MADS_NEBULAR_SCENES3_H */
diff --git a/engines/mads/nebular/nebular_scenes4.cpp b/engines/mads/nebular/nebular_scenes4.cpp
new file mode 100644
index 0000000000..b1b2b098af
--- /dev/null
+++ b/engines/mads/nebular/nebular_scenes4.cpp
@@ -0,0 +1,4191 @@
+/* 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 "mads/mads.h"
+#include "mads/scene.h"
+#include "mads/nebular/nebular_scenes.h"
+#include "mads/nebular/nebular_scenes4.h"
+
+namespace MADS {
+
+namespace Nebular {
+
+void Scene4xx::setAAName() {
+ _game._aaName = Resources::formatAAName(4);
+}
+
+void Scene4xx::setPlayerSpritesPrefix() {
+ _vm->_sound->command(5);
+ Common::String oldName = _game._player._spritesPrefix;
+
+ if ((_scene->_nextSceneId == 403) || (_scene->_nextSceneId == 409))
+ _game._player._spritesPrefix = "";
+ else if (_globals[kSexOfRex] == REX_FEMALE)
+ _game._player._spritesPrefix = "ROX";
+ else
+ _game._player._spritesPrefix = "RXM";
+
+ _game._player._scalingVelocity = true;
+
+ if (oldName != _game._player._spritesPrefix)
+ _game._player._spritesChanged = true;
+
+ _vm->_palette->setEntry(16, 10, 63, 63);
+ _vm->_palette->setEntry(17, 10, 45, 45);
+}
+
+void Scene4xx::sceneEntrySound() {
+ if (!_vm->_musicFlag) {
+ _vm->_sound->command(2);
+ return;
+ }
+
+ switch (_scene->_nextSceneId) {
+ case 401:
+ _vm->_sound->startQueuedCommands();
+ if (_scene->_priorSceneId == 402)
+ _vm->_sound->command(12, 64);
+ else
+ _vm->_sound->command(12, 1);
+ break;
+
+ case 402:
+ _vm->_sound->startQueuedCommands();
+ _vm->_sound->command(12, 127);
+ break;
+
+ case 405:
+ case 407:
+ case 409:
+ case 410:
+ case 413:
+ _vm->_sound->command(10);
+ break;
+
+ case 408:
+ _vm->_sound->command(52);
+ break;
+
+ default:
+ break;
+ }
+}
+
+/*------------------------------------------------------------------------*/
+
+Scene401::Scene401(MADSEngine *vm) : Scene4xx(vm), _destPos(0, 0) {
+ _northFl = false;
+ _timer = 0;
+}
+
+void Scene401::synchronize(Common::Serializer &s) {
+ Scene4xx::synchronize(s);
+
+ s.syncAsByte(_northFl);
+ s.syncAsSint16LE(_destPos.x);
+ s.syncAsSint16LE(_destPos.y);
+ s.syncAsUint32LE(_timer);
+}
+
+void Scene401::setup() {
+ setPlayerSpritesPrefix();
+ setAAName();
+}
+
+void Scene401::enter() {
+ if (_scene->_priorSceneId != -2)
+ _northFl = false;
+
+ _timer = 0;
+
+ if (_scene->_priorSceneId == 402) {
+ _game._player._playerPos = Common::Point(203, 115);
+ _game._player._facing = FACING_WEST;
+ } else if (_scene->_priorSceneId == 354) {
+ _game._player._playerPos = Common::Point(149, 90);
+ _game._player._facing = FACING_SOUTH;
+ _northFl = true;
+ } else if (_scene->_priorSceneId != -2) {
+ _game._player._playerPos = Common::Point(142, 131);
+ _game._player._facing = FACING_NORTH;
+ }
+
+ _game.loadQuoteSet(0x1D4, 0);
+ sceneEntrySound();
+}
+
+void Scene401::step() {
+ if (_game._trigger == 70) {
+ _scene->_nextSceneId = 354;
+ _scene->_reloadSceneFlag = true;
+ }
+
+ if (_game._trigger == 80) {
+ _game._player._priorTimer = _scene->_frameStartTime - _game._player._ticksAmount;
+ _game._player._stepEnabled = true;
+ _game._player._visible = true;
+ _northFl = false;
+ _game._player.walk(Common::Point(149, 110), FACING_SOUTH);
+ }
+
+ if (_scene->_frameStartTime >= _timer) {
+ int dist = 64 - ((_vm->hypotenuse(_game._player._playerPos.x - 219, _game._player._playerPos.y - 115) * 64) / 120);
+
+ if (dist > 64)
+ dist = 64;
+ else if (dist < 1)
+ dist = 1;
+
+ _vm->_sound->command(12, dist);
+ _timer = _scene->_frameStartTime + _game._player._ticksAmount;
+ }
+
+}
+
+void Scene401::preActions() {
+ if (_action.isAction(VERB_WALK_DOWN, NOUN_CORRIDOR_TO_NORTH)) {
+ _game._player.walk(Common::Point(149, 89), FACING_NORTH);
+ _northFl = false;
+ }
+
+ if (_action.isAction(VERB_WALK_DOWN, NOUN_CORRIDOR_TO_SOUTH) && !_northFl)
+ _game._player._walkOffScreenSceneId = 405;
+
+ if (_action.isAction(VERB_TAKE))
+ _game._player._needToWalk = false;
+
+ if (_game._player._needToWalk && _northFl) {
+ if (_globals[kSexOfRex] == REX_MALE)
+ _destPos = Common::Point(148, 94);
+ else
+ _destPos = Common::Point(149, 99);
+
+ _game._player.walk(_destPos, FACING_SOUTH);
+ }
+}
+
+void Scene401::actions() {
+ if ((_game._player._playerPos == _destPos) && _northFl) {
+ if (_globals[kSexOfRex] == REX_MALE) {
+ _game._triggerSetupMode = SEQUENCE_TRIGGER_DAEMON;
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _vm->_sound->command(21);
+ _scene->loadAnimation(formAnimName('s', 1), 70);
+ _globals[kHasBeenScanned] = true;
+ _vm->_sound->command(22);
+ int idx = _scene->_kernelMessages.add(Common::Point(153, 46), 0x1110, 32, 0, 60, _game.getQuote(0x1D4));
+ _scene->_kernelMessages.setQuoted(idx, 4, true);
+ }
+
+ if (_globals[kSexOfRex] == REX_FEMALE) {
+ _game._triggerSetupMode = SEQUENCE_TRIGGER_DAEMON;
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _vm->_sound->command(21);
+ _scene->loadAnimation(formAnimName('s', 2), 80);
+ _vm->_sound->command(23);
+ _globals[kHasBeenScanned] = true;
+ }
+ }
+
+ if (_action.isAction(VERB_WALK_INTO, NOUN_BAR)) {
+ if (!_northFl)
+ _scene->_nextSceneId = 402;
+ } else if (_action.isAction(VERB_WALK_DOWN, NOUN_CORRIDOR_TO_NORTH))
+ _scene->_nextSceneId = 354;
+ else if (_action.isAction(VERB_LOOK, NOUN_SCANNER)) {
+ if (_globals[kHasBeenScanned])
+ _vm->_dialogs->show(40111);
+ else
+ _vm->_dialogs->show(40110);
+ } else if (_action.isAction(VERB_LOOK, NOUN_BAR))
+ _vm->_dialogs->show(40112);
+ else if (_action.isAction(VERB_LOOK, NOUN_SIGN))
+ _vm->_dialogs->show(40113);
+ else if (_action.isAction(VERB_LOOK, NOUN_CORRIDOR_TO_SOUTH))
+ _vm->_dialogs->show(40114);
+ else if (_action.isAction(VERB_LOOK, NOUN_CORRIDOR_TO_NORTH))
+ _vm->_dialogs->show(40115);
+ else if (_action._lookFlag)
+ _vm->_dialogs->show(40116);
+ else
+ return;
+
+ _action._inProgress = false;
+}
+
+/*------------------------------------------------------------------------*/
+
+Scene402::Scene402(MADSEngine *vm) : Scene4xx(vm) {
+ _lightOn = false;
+ _blowingSmoke = false;
+ _leftWomanMoving = false;
+ _rightWomanMoving = false;
+ _firstTalkToGirlInChair = false;
+ _waitingGinnyMove = false;
+ _ginnyLooking = false;
+ _bigBeatFl = false;
+ _roxOnStool = false;
+ _bartenderSteady = false;
+ _bartenderHandsHips = false;
+ _bartenderLooksLeft = false;
+ _bartenderReady = false;
+ _bartenderTalking = false;
+ _bartenderCalled = false;
+ _conversationFl = false;
+ _activeTeleporter = false;
+ _activeArrows = false;
+ _activeArrow1 = false;
+ _activeArrow2 = false;
+ _activeArrow3 = false;
+ _cutSceneReady = false;
+ _cutSceneNeeded = false;
+ _helgaReady = false;
+ _refuseAlienLiquor = false;
+
+ _drinkTimer = -1;
+ _beatCounter = -1;
+ _bartenderMode = -1;
+ _bartenderDialogNode = -1;
+ _bartenderCurrentQuestion = -1;
+ _helgaTalkMode = -1;
+ _roxMode = -1;
+ _rexMode = -1;
+ _talkTimer = -1;
+}
+
+void Scene402::synchronize(Common::Serializer &s) {
+ Scene4xx::synchronize(s);
+
+ s.syncAsByte(_lightOn);
+ s.syncAsByte(_blowingSmoke);
+ s.syncAsByte(_leftWomanMoving);
+ s.syncAsByte(_rightWomanMoving);
+ s.syncAsByte(_firstTalkToGirlInChair);
+ s.syncAsByte(_waitingGinnyMove);
+ s.syncAsByte(_ginnyLooking);
+ s.syncAsByte(_bigBeatFl);
+ s.syncAsByte(_roxOnStool);
+ s.syncAsByte(_bartenderSteady);
+ s.syncAsByte(_bartenderHandsHips);
+ s.syncAsByte(_bartenderLooksLeft);
+ s.syncAsByte(_bartenderReady);
+ s.syncAsByte(_bartenderTalking);
+ s.syncAsByte(_bartenderCalled);
+ s.syncAsByte(_conversationFl);
+ s.syncAsByte(_activeTeleporter);
+ s.syncAsByte(_activeArrows);
+ s.syncAsByte(_activeArrow1);
+ s.syncAsByte(_activeArrow2);
+ s.syncAsByte(_activeArrow3);
+ s.syncAsByte(_cutSceneReady);
+ s.syncAsByte(_cutSceneNeeded);
+ s.syncAsByte(_helgaReady);
+ s.syncAsByte(_refuseAlienLiquor);
+
+ s.syncAsSint16LE(_drinkTimer);
+ s.syncAsSint16LE(_beatCounter);
+ s.syncAsSint16LE(_bartenderMode);
+ s.syncAsSint16LE(_bartenderDialogNode);
+ s.syncAsSint16LE(_bartenderCurrentQuestion);
+ s.syncAsSint16LE(_helgaTalkMode);
+ s.syncAsSint16LE(_roxMode);
+ s.syncAsSint16LE(_rexMode);
+ s.syncAsSint16LE(_talkTimer);
+}
+
+void Scene402::setup() {
+ setPlayerSpritesPrefix();
+ setAAName();
+
+ _scene->addActiveVocab(NOUN_BARTENDER);
+ _scene->addActiveVocab(NOUN_ALIEN_LIQUOR);
+ _scene->addActiveVocab(VERB_DRINK);
+ _scene->addActiveVocab(NOUN_BINOCULARS);
+ _scene->addActiveVocab(VERB_WALKTO);
+ _scene->addActiveVocab(NOUN_CREDIT_CHIP);
+ _scene->addActiveVocab(VERB_TAKE);
+ _scene->addActiveVocab(NOUN_REPAIR_LIST);
+ _scene->addActiveVocab(VERB_LOOK_AT);
+}
+
+void Scene402::setDialogNode(int node) {
+ if (node > 0)
+ _bartenderDialogNode = node;
+
+ _game._player._stepEnabled = true;
+
+ switch (node) {
+ case 0:
+ _scene->_userInterface.setup(kInputBuildingSentences);
+ _conversationFl = false;
+ _bartenderDialogNode = 0;
+ break;
+
+ case 1:
+ _dialog1.start();
+ _bartenderDialogNode = 1;
+ break;
+
+ case 2:
+ _dialog2.start();
+ _bartenderDialogNode = 2;
+ break;
+
+ case 3:
+ _dialog3.start();
+ _bartenderDialogNode = 3;
+ break;
+
+ case 4:
+ _dialog4.start();
+ _bartenderDialogNode = 4;
+ break;
+
+ default:
+ break;
+ }
+}
+
+void Scene402::handleConversation1() {
+ switch (_action._activeAction._verbId) {
+ case 0x214: {
+ int quoteId = 0;
+ int quotePosX = 0;
+ switch (_vm->getRandomNumber(1, 3)) {
+ case 1:
+ quoteId = 0x1E4;
+ _bartenderCurrentQuestion = 4;
+ quotePosX = 205;
+ break;
+
+ case 2:
+ quoteId = 0x1E5;
+ _bartenderCurrentQuestion = 5;
+ quotePosX = 203;
+ break;
+
+ case 3:
+ quoteId = 0x1E6;
+ _bartenderCurrentQuestion = 6;
+ quotePosX = 260;
+ break;
+
+ default:
+ break;
+ }
+ _scene->_kernelMessages.reset();
+ _scene->_kernelMessages.add(Common::Point(quotePosX, 41), 0xFDFC, 0, 0, 9999999, _game.getQuote(quoteId));
+ _game._triggerSetupMode = SEQUENCE_TRIGGER_DAEMON;
+ _scene->_sequences.addTimer(1, 100);
+ _talkTimer = 120;
+ setDialogNode(2);
+ }
+ break;
+
+ case 0x215:
+ _scene->_kernelMessages.reset();
+ _scene->_kernelMessages.add(Common::Point(260, 41), 0xFDFC, 0, 0, 9999999, _game.getQuote(0x1EC));
+ _game._triggerSetupMode = SEQUENCE_TRIGGER_DAEMON;
+ _scene->_sequences.addTimer(1, 100);
+ _talkTimer = 120;
+ _bartenderCurrentQuestion = 1;
+ setDialogNode(3);
+ break;
+
+ case 0x237:
+ _scene->_kernelMessages.reset();
+ _scene->_kernelMessages.add(Common::Point(208, 41), 0xFDFC, 0, 0, 100, _game.getQuote(0x1FD));
+ setDialogNode(0);
+ _game._triggerSetupMode = SEQUENCE_TRIGGER_DAEMON;
+ _scene->_sequences.addTimer(1, 100);
+ _talkTimer = 1120;
+ break;
+
+ default:
+ break;
+ }
+}
+
+void Scene402::handleConversation2() {
+ switch (_action._activeAction._verbId) {
+ case 0x216:
+ _dialog2.write(0x216, false);
+ _dialog2.write(0x21D, true);
+ break;
+
+ case 0x219:
+ _dialog2.write(0x219, false);
+ _dialog2.write(0x220, true);
+ break;
+
+ case 0x21A:
+ _dialog2.write(0x21A, false);
+ _dialog2.write(0x223, true);
+ break;
+
+ case 0x21B:
+ _dialog2.write(0x21B, false);
+ _dialog2.write(0x224, true);
+ break;
+
+ case 0x21D:
+ _dialog2.write(0x21D, false);
+ _dialog2.write(0x227, true);
+ break;
+
+ case 0x220:
+ _dialog2.write(0x220, false);
+ _dialog2.write(0x22A, true);
+ break;
+
+ case 0x223:
+ _dialog2.write(0x223, false);
+ _dialog2.write(0x22D, true);
+ break;
+
+ case 0x224:
+ _dialog2.write(0x224, false);
+ _dialog2.write(0x230, true);
+ break;
+
+ case 0x227:
+ _dialog2.write(0x227, false);
+ break;
+
+ case 0x22A:
+ _dialog2.write(0x22A, false);
+ break;
+
+ case 0x22D:
+ _dialog2.write(0x22D, false);
+ break;
+
+ case 0x230:
+ _dialog2.write(0x230, false);
+ break;
+
+ case 0x21C:
+ setDialogNode(0);
+ break;
+
+ default:
+ break;
+
+ }
+
+ if (_action._activeAction._verbId != 0x21C) {
+ switch (_vm->getRandomNumber(1, 3)) {
+ case 1:
+ _game._triggerSetupMode = SEQUENCE_TRIGGER_DAEMON;
+ _scene->_sequences.addTimer(1, 100);
+ _talkTimer = 180;
+ _scene->_kernelMessages.reset();
+ _scene->_kernelMessages.add(Common::Point(198, 27), 0xFDFC, 0, 0, 9999999, _game.getQuote(0x1E7));
+ _scene->_kernelMessages.add(Common::Point(201, 41), 0xFDFC, 0, 0, 9999999, _game.getQuote(0x1E8));
+ _bartenderCurrentQuestion = 7;
+ break;
+
+ case 2:
+ _game._triggerSetupMode = SEQUENCE_TRIGGER_DAEMON;
+ _scene->_sequences.addTimer(1, 100);
+ _talkTimer = 180;
+ _scene->_kernelMessages.reset();
+ _scene->_kernelMessages.add(Common::Point(220, 27), 0xFDFC, 0, 0, 9999999, _game.getQuote(0x1E9));
+ _scene->_kernelMessages.add(Common::Point(190, 41), 0xFDFC, 0, 0, 9999999, _game.getQuote(0x1EA));
+ _bartenderCurrentQuestion = 8;
+ break;
+
+ case 3:
+ _game._triggerSetupMode = SEQUENCE_TRIGGER_DAEMON;
+ _scene->_sequences.addTimer(1, 100);
+ _talkTimer = 150;
+ _scene->_kernelMessages.reset();
+ _scene->_kernelMessages.add(Common::Point(196, 41), 0xFDFC, 0, 0, 9999999, _game.getQuote(0x1EB));
+ _bartenderCurrentQuestion = 9;
+ break;
+
+ default:
+ break;
+ }
+ _dialog2.start();
+ } else {
+ _scene->_kernelMessages.reset();
+ _scene->_kernelMessages.add(Common::Point(208, 41), 0xFDFC, 0, 0, 100, _game.getQuote(0x1FD));
+ _game._triggerSetupMode = SEQUENCE_TRIGGER_DAEMON;
+ _scene->_sequences.addTimer(1, 100);
+ _talkTimer = 1120;
+ }
+}
+
+void Scene402::handleConversation3() {
+ switch (_action._activeAction._verbId) {
+ case 0x233:
+ case 0x234:
+ case 0x235:
+ case 0x236:
+ _game._triggerSetupMode = SEQUENCE_TRIGGER_DAEMON;
+ _scene->_sequences.addTimer(1, 86);
+ _scene->_kernelMessages.reset();
+ _scene->_kernelMessages.add(Common::Point(188, 27), 0xFDFC, 0, 0, 9999999, _game.getQuote(0x1ED));
+ _scene->_kernelMessages.add(Common::Point(199, 41), 0xFDFC, 0, 0, 9999999, _game.getQuote(0x1EE));
+ setDialogNode(4);
+ _bartenderCurrentQuestion = 2;
+ break;
+
+ case 0x237:
+ _scene->_kernelMessages.reset();
+ _scene->_kernelMessages.add(Common::Point(208, 41), 0xFDFC, 0, 0, 100, _game.getQuote(0x1FD));
+ _game._triggerSetupMode = SEQUENCE_TRIGGER_DAEMON;
+ _scene->_sequences.addTimer(1, 100);
+ _talkTimer = 1120;
+ setDialogNode(0);
+ break;
+
+ default:
+ break;
+ }
+}
+
+void Scene402::handleConversation4() {
+ switch (_action._activeAction._verbId) {
+ case 0x238:
+ _scene->_kernelMessages.reset();
+ setDialogNode(0);
+ _game._player._stepEnabled = false;
+ _scene->_kernelMessages.add(Common::Point(196, 13), 0xFDFC, 0, 0, 180, _game.getQuote(0x1F0));
+ _scene->_kernelMessages.add(Common::Point(184, 27), 0xFDFC, 0, 0, 180, _game.getQuote(0x1F1));
+ _scene->_kernelMessages.add(Common::Point(200, 41), 0xFDFC, 0, 0, 180, _game.getQuote(0x1F2));
+ _game._triggerSetupMode = SEQUENCE_TRIGGER_DAEMON;
+ _scene->_sequences.addTimer(1, 100);
+ _talkTimer = 1100;
+ _dialog4.write(0x238, false);
+ _bartenderMode = 22;
+ _game._triggerSetupMode = SEQUENCE_TRIGGER_DAEMON;
+ _scene->_sequences.addTimer(100, 95);
+ _refuseAlienLiquor = true;
+ break;
+
+ case 0x239:
+ _game._player._stepEnabled = false;
+ _roxMode = 21;
+ _game._triggerSetupMode = SEQUENCE_TRIGGER_DAEMON;
+ _scene->_sequences.addTimer(1, 92);
+ _scene->_userInterface.setup(kInputBuildingSentences);
+ _conversationFl = false;
+ break;
+
+ case 0x23A:
+ setDialogNode(0);
+ _game._player._stepEnabled = false;
+ _scene->_kernelMessages.add(Common::Point(193, 27), 0xFDFC, 0, 0, 150, _game.getQuote(0x1F4));
+ _scene->_kernelMessages.add(Common::Point(230, 41), 0xFDFC, 0, 0, 150, _game.getQuote(0x1F5));
+ _dialog4.write(0x23A, false);
+ _globals[kHasSaidTimer] = true;
+ _game._triggerSetupMode = SEQUENCE_TRIGGER_DAEMON;
+ _scene->_sequences.addTimer(1, 100);
+ _talkTimer = 1100;
+ _bartenderMode = 22;
+ _game._triggerSetupMode = SEQUENCE_TRIGGER_DAEMON;
+ _scene->_sequences.addTimer(100, 95);
+ _refuseAlienLiquor = true;
+ break;
+
+ case 0x23D:
+ setDialogNode(0);
+ _game._player._stepEnabled = false;
+ _scene->_kernelMessages.add(Common::Point(153, 27), 0xFDFC, 0, 0, 150, _game.getQuote(0x1F6));
+ _scene->_kernelMessages.add(Common::Point(230, 41), 0xFDFC, 0, 0, 150, _game.getQuote(0x1F7));
+ _dialog4.write(0x23D, false);
+ _globals[kHasSaidBinocs] = true;
+ _game._triggerSetupMode = SEQUENCE_TRIGGER_DAEMON;
+ _scene->_sequences.addTimer(1, 100);
+ _talkTimer = 1100;
+ _bartenderMode = 22;
+ _game._triggerSetupMode = SEQUENCE_TRIGGER_DAEMON;
+ _scene->_sequences.addTimer(100, 95);
+ _refuseAlienLiquor = true;
+ break;
+
+ case 0x23E:
+ _scene->_kernelMessages.reset();
+ setDialogNode(0);
+ _game._player._stepEnabled = false;
+ _scene->_kernelMessages.add(Common::Point(205, 41), 0xFDFC, 0, 0, 100, _game.getQuote(0x1F8));
+ _bartenderMode = 22;
+ _game._triggerSetupMode = SEQUENCE_TRIGGER_DAEMON;
+ _scene->_sequences.addTimer(1, 100);
+ _talkTimer = 1050;
+ _game._triggerSetupMode = SEQUENCE_TRIGGER_DAEMON;
+ _scene->_sequences.addTimer(50, 95);
+ _refuseAlienLiquor = true;
+ break;
+
+ default:
+ break;
+ }
+}
+
+void Scene402::handleDialogs() {
+ if (_game._trigger == 0) {
+ _scene->_kernelMessages.reset();
+ _game._player._stepEnabled = false;
+ Common::String curQuote = _game.getQuote(_action._activeAction._verbId);
+ if (_vm->_font->getWidth(curQuote, _scene->_textSpacing) > 200) {
+ Common::String subQuote1, subQuote2;
+ _game.splitQuote(curQuote, subQuote1, subQuote2);
+ _scene->_kernelMessages.add(Common::Point(230, 42), 0x1110, 32, 0, 140, subQuote1);
+ _scene->_kernelMessages.add(Common::Point(230, 56), 0x1110, 32, 0, 140, subQuote2);
+ _scene->_sequences.addTimer(160, 120);
+ } else {
+ _scene->_kernelMessages.add(Common::Point(230, 56), 0x1110, 32, 1, 140, curQuote);
+ _scene->_sequences.addTimer(160, 120);
+ }
+ } else if (_game._trigger == 120) {
+ _game._player._stepEnabled = true;
+ switch (_bartenderDialogNode) {
+ case 1:
+ handleConversation1();
+ break;
+
+ case 2:
+ handleConversation2();
+ break;
+
+ case 3:
+ handleConversation3();
+ break;
+
+ case 4:
+ handleConversation4();
+ break;
+
+ default:
+ break;
+ }
+ }
+}
+
+void Scene402::enter() {
+ _globals._spriteIndexes[0] = _scene->_sprites.addSprites(formAnimName('n', -1));
+ _globals._spriteIndexes[1] = _scene->_sprites.addSprites(formAnimName('x', 2));
+ _globals._spriteIndexes[3] = _scene->_sprites.addSprites(formAnimName('x', 0));
+ _globals._spriteIndexes[2] = _scene->_sprites.addSprites(formAnimName('x', 1));
+ _globals._spriteIndexes[4] = _scene->_sprites.addSprites(formAnimName('g', 0));
+ _globals._spriteIndexes[5] = _scene->_sprites.addSprites(formAnimName('g', 1));
+ _globals._spriteIndexes[6] = _scene->_sprites.addSprites(formAnimName('a', 0));
+ _globals._spriteIndexes[7] = _scene->_sprites.addSprites(formAnimName('a', 1));
+ _globals._spriteIndexes[15] = _scene->_sprites.addSprites(formAnimName('x', 5));
+ _globals._spriteIndexes[8] = _scene->_sprites.addSprites(formAnimName('x', 4));
+ _globals._spriteIndexes[9] = _scene->_sprites.addSprites(formAnimName('b', 0));
+ _globals._spriteIndexes[10] = _scene->_sprites.addSprites(formAnimName('b', 1));
+ _globals._spriteIndexes[11] = _scene->_sprites.addSprites(formAnimName('b', 2));
+ _globals._spriteIndexes[12] = _scene->_sprites.addSprites(formAnimName('b', 3));
+ _globals._spriteIndexes[13] = _scene->_sprites.addSprites(formAnimName('c', 0));
+ _globals._spriteIndexes[14] = _scene->_sprites.addSprites(formAnimName('l', 0));
+ _globals._spriteIndexes[16] = _scene->_sprites.addSprites(formAnimName('h', 0));
+ _globals._spriteIndexes[17] = _scene->_sprites.addSprites(formAnimName('z', 0));
+ _globals._spriteIndexes[18] = _scene->_sprites.addSprites(formAnimName('z', 1));
+ _globals._spriteIndexes[19] = _scene->_sprites.addSprites(formAnimName('z', 2));
+ _globals._spriteIndexes[20] = _scene->_sprites.addSprites(formAnimName('x', 6));
+ _globals._spriteIndexes[21] = _scene->_sprites.addSprites("*ROXRC_9");
+ _globals._spriteIndexes[22] = _scene->_sprites.addSprites("*ROXCL_8");
+
+ if (_scene->_priorSceneId == 401) {
+ _game._player._playerPos = Common::Point(160, 150);
+ _game._player._facing = FACING_NORTH;
+ _roxOnStool = false;
+ _bartenderDialogNode = 1;
+ _conversationFl = false;
+ } else if (_scene->_priorSceneId != -2) {
+ _game._player._playerPos = Common::Point(160, 150);
+ _game._player._facing = FACING_NORTH;
+ _game._objects.addToInventory(OBJ_CREDIT_CHIP);
+ _game._objects.addToInventory(OBJ_BINOCULARS);
+ _game._objects.addToInventory(OBJ_TIMER_MODULE);
+ _roxOnStool = false;
+ _bartenderDialogNode = 1;
+ _conversationFl = false;
+ }
+
+ _game.loadQuoteSet(0x1D7, 0x1D8, 0x1D9, 0x1DA, 0x1DB, 0x1DC, 0x1DD, 0x1DE, 0x1DF, 0x1E2, 0x1E3, 0x1E6, 0x1E5, 0x1E7,
+ 0x1E8, 0x1E9, 0x1EA, 0x1EF, 0x1F0, 0x1F1, 0x1F2, 0x1F3, 0x1F4, 0x1F5, 0x1F6, 0x1F7, 0x1F8, 0x1F9, 0x1FA, 0x1FB,
+ 0x1FC, 0x1EB, 0x1EC, 0x1ED, 0x1EE, 0x1E4, 0x1FD, 0x1E0, 0x1E1, 0x1FE, 0x1FF, 0x200, 0x201, 0x202, 0x203, 0x204,
+ 0x205, 0x206, 0x207, 0x208, 0x209, 0x20A, 0x20B, 0x20C, 0x20F, 0x20D, 0x20E, 0x210, 0x211, 0x212, 0x213, 0x214,
+ 0x215, 0x237, 0x216, 0x219, 0x21A, 0x21B, 0x21C, 0x21D, 0x220, 0x223, 0x224, 0x227, 0x22A, 0x22D, 0x230, 0x233,
+ 0x234, 0x235, 0x236, 0x238, 0x239, 0x23A, 0x23D, 0x23E, 0x23F, 0);
+
+ _vm->_palette->setEntry(250, 47, 41, 40);
+ _vm->_palette->setEntry(251, 50, 63, 55);
+ _vm->_palette->setEntry(252, 38, 34, 25);
+ _vm->_palette->setEntry(253, 45, 41, 35);
+
+ _dialog1.setup(0x60, 0x214, 0x215, 0x237, 0);
+ _dialog2.setup(0x61, 0x216, 0x219, 0x21A, 0x21B, 0x21D, 0x220, 0x223, 0x224, 0x227, 0x22A, 0x22D, 0x230, 0x21C, 0);
+ _dialog3.setup(0x62, 0x233, 0x234, 0x235, 0x236, 0x237, -1);
+ _dialog4.setup(0x63, 0x238, 0x239, 0x23A, 0x23D, 0x23E, 0);
+
+ if (!_game._visitedScenes._sceneRevisited) {
+ _dialog2.set(0x61, 0x216, 0x219, 0x21A, 0x21B, 0x21C, 0);
+ _dialog4.set(0x63, 0x238, 0x23E, 0);
+ _dialog1.set(0x60, 0x214, 0x215, 0x237, 0);
+ }
+
+ if (_game._objects.isInInventory(OBJ_CREDIT_CHIP))
+ _dialog4.write(0x239, true);
+ else
+ _dialog4.write(0x239, false);
+
+ if (_game._objects.isInInventory(OBJ_BINOCULARS) && !_globals[kHasSaidBinocs])
+ _dialog4.write(0x23D, true);
+ else
+ _dialog4.write(0x23D, false);
+
+ if (_game._objects.isInInventory(OBJ_TIMER_MODULE) && !_globals[kHasSaidTimer])
+ _dialog4.write(0x23A, true);
+ else
+ _dialog4.write(0x23A, false);
+
+ if (_dialog2.read(0) <= 1)
+ _dialog1.write(0x214, false);
+
+ if (_conversationFl) {
+ switch (_bartenderDialogNode) {
+ case 0:
+ _scene->_userInterface.setup(kInputBuildingSentences);
+ _bartenderDialogNode = 1;
+ break;
+
+ case 1:
+ _dialog1.start();
+ break;
+
+ case 2:
+ _dialog2.start();
+ break;
+
+ case 3:
+ _dialog3.start();
+ break;
+
+ case 4:
+ _dialog4.start();
+ break;
+
+ default:
+ break;
+ }
+
+ switch (_bartenderCurrentQuestion) {
+ case 1:
+ _scene->_kernelMessages.add(Common::Point(260, 41), 0xFDFC, 0, 0, 9999999, _game.getQuote(0x1EC));
+ break;
+
+ case 2:
+ _scene->_kernelMessages.add(Common::Point(188, 27), 0xFDFC, 0, 0, 9999999, _game.getQuote(0x1ED));
+ _scene->_kernelMessages.add(Common::Point(199, 41), 0xFDFC, 0, 0, 9999999, _game.getQuote(0x1EE));
+ break;
+
+ case 3:
+ _scene->_kernelMessages.add(Common::Point(177, 41), 0xFDFC, 0, 0, 9999999, _game.getQuote(0x1EF));
+ break;
+
+ case 4:
+ _scene->_kernelMessages.add(Common::Point(205, 41), 0xFDFC, 0, 0, 9999999, _game.getQuote(0x1E4));
+ break;
+
+ case 5:
+ _scene->_kernelMessages.add(Common::Point(203, 41), 0xFDFC, 0, 0, 9999999, _game.getQuote(0x1E5));
+ break;
+
+ case 6:
+ _scene->_kernelMessages.add(Common::Point(260, 41), 0xFDFC, 0, 0, 9999999, _game.getQuote(0x1E6));
+ break;
+
+ case 7:
+ _scene->_kernelMessages.add(Common::Point(198, 27), 0xFDFC, 0, 0, 9999999, _game.getQuote(0x1E7));
+ _scene->_kernelMessages.add(Common::Point(201, 41), 0xFDFC, 0, 0, 9999999, _game.getQuote(0x1E8));
+ break;
+
+ case 8:
+ _scene->_kernelMessages.add(Common::Point(220, 27), 0xFDFC, 0, 0, 9999999, _game.getQuote(0x1E9));
+ _scene->_kernelMessages.add(Common::Point(190, 41), 0xFDFC, 0, 0, 9999999, _game.getQuote(0x1EA));
+ break;
+
+ case 9:
+ _scene->_kernelMessages.add(Common::Point(196, 41), 0xFDFC, 0, 0, 9999999, _game.getQuote(0x1EB));
+ break;
+
+ case 10:
+ _scene->_kernelMessages.add(Common::Point(198, 27), 0xFDFC, 0, 0, 9999999, _game.getQuote(0x1E2));
+ _scene->_kernelMessages.add(Common::Point(199, 41), 0xFDFC, 0, 0, 9999999, _game.getQuote(0x1E3));
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ _firstTalkToGirlInChair = false;
+ _lightOn = false;
+ _blowingSmoke = false;
+ _leftWomanMoving = false;
+ _rightWomanMoving = false;
+ _ginnyLooking = false;
+ _beatCounter = 0;
+ _waitingGinnyMove = false;
+ _bigBeatFl = true;
+ _bartenderHandsHips = false;
+ _bartenderSteady = true;
+ _bartenderLooksLeft = false;
+ _activeTeleporter = false;
+ _activeArrows = false;
+ _activeArrow1 = false;
+ _activeArrow2 = false;
+ _activeArrow3 = false;
+ _cutSceneReady = false;
+ _cutSceneNeeded = false;
+ _helgaReady = true;
+ _bartenderReady = true;
+ _drinkTimer = 0;
+ _bartenderTalking = false;
+ _bartenderCalled = false;
+ _helgaTalkMode = 0;
+ _rexMode = 0;
+ _refuseAlienLiquor = false;
+
+ _scene->loadAnimation(Resources::formatName(402, 'd', 1, EXT_AA, ""));
+ _scene->_activeAnimation->_resetFlag = true;
+
+ _globals._sequenceIndexes[5] = _scene->_sequences.startCycle(_globals._spriteIndexes[5], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[5], 1);
+
+ _globals._sequenceIndexes[13] = _scene->_sequences.startCycle(_globals._spriteIndexes[13], false, 2);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[13], 8);
+
+ if (!_game._objects.isInInventory(OBJ_REPAIR_LIST)) {
+ _globals._sequenceIndexes[14] = _scene->_sequences.startCycle(_globals._spriteIndexes[14], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[14], 7);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[14], Common::Point(210, 80));
+ int idx = _scene->_dynamicHotspots.add(NOUN_REPAIR_LIST, 0xD1, _globals._sequenceIndexes[14], Common::Rect(0, 0, 0, 0));
+ _scene->_dynamicHotspots.setPosition(idx, Common::Point(0, 0), FACING_NONE);
+ }
+
+ {
+ _globals._sequenceIndexes[9] = _scene->_sequences.startCycle(_globals._spriteIndexes[9], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[9], 8);
+ int idx = _scene->_dynamicHotspots.add(NOUN_BARTENDER, 0xD, _globals._sequenceIndexes[9], Common::Rect(0, 0, 0, 0));
+ _scene->_dynamicHotspots.setPosition(idx, Common::Point(228, 83), FACING_SOUTH);
+ }
+
+ if (!_game._objects.isInRoom(OBJ_ALIEN_LIQUOR) && !_game._objects.isInInventory(OBJ_CREDIT_CHIP)) {
+ _globals._sequenceIndexes[15] = _scene->_sequences.startCycle(_globals._spriteIndexes[15], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[15], 8);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[15], Common::Point(250, 80));
+ int idx = _scene->_dynamicHotspots.add(NOUN_CREDIT_CHIP, 0x4, _globals._sequenceIndexes[15], Common::Rect(0, 0, 0, 0));
+ _scene->_dynamicHotspots.setPosition(idx, Common::Point(0, 0), FACING_NONE);
+ }
+
+ _globals._sequenceIndexes[20] = _scene->_sequences.startCycle(_globals._spriteIndexes[20], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[20], 7);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[20], Common::Point(234, 72));
+
+ if (_globals[kBottleDisplayed]) {
+ _globals._sequenceIndexes[8] = _scene->_sequences.startCycle(_globals._spriteIndexes[8], false, 4);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[8], 7);
+ }
+
+ if (_roxOnStool) {
+ _globals._sequenceIndexes[6] = _scene->_sequences.startCycle(_globals._spriteIndexes[6], false, 11);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[6], 5);
+ _game._player._visible = false;
+ }
+
+ sceneEntrySound();
+}
+
+void Scene402::step() {
+ if (_game._trigger == 104) {
+ _game._player._priorTimer = _scene->_frameStartTime + _game._player._ticksAmount;
+ _game._player._visible = true;
+ _scene->_sequences.remove(_globals._sequenceIndexes[15]);
+ _game._objects.addToInventory(OBJ_CREDIT_CHIP);
+ _vm->_dialogs->showItem(OBJ_CREDIT_CHIP, 40242);
+ _game._player._stepEnabled = true;
+ }
+
+ if ((_vm->getRandomNumber(1, 1500) == 1) && (!_activeTeleporter) && (_game._player._playerPos.x < 150)) {
+ _vm->_sound->command(30);
+ _globals._sequenceIndexes[4] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[4], false, 13, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[4], 1, 11);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[4], 14);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[4], SEQUENCE_TRIGGER_EXPIRE, 0, 48);
+ _activeTeleporter = true;
+ _globals[kSomeoneHasExploded] = true;
+ }
+
+ if (_game._trigger == 48)
+ _activeTeleporter = false;
+
+ if (_game._trigger == 100) {
+ _bartenderReady = false;
+ if (_bartenderHandsHips) {
+ _scene->_sequences.remove(_globals._sequenceIndexes[10]);
+ _bartenderHandsHips = false;
+ } else if (_bartenderLooksLeft) {
+ _scene->_sequences.remove(_globals._sequenceIndexes[11]);
+ _bartenderLooksLeft = false;
+ } else if (_bartenderSteady) {
+ _scene->_sequences.remove(_globals._sequenceIndexes[9]);
+ _bartenderSteady = false;
+ }
+
+ if (!_bartenderTalking) {
+ _globals._sequenceIndexes[10] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[10], false, 7, 0, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[10], 3, 4);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[10], 8);
+ int idx = _scene->_dynamicHotspots.add(NOUN_BARTENDER, 0xD, _globals._sequenceIndexes[10], Common::Rect(0, 0, 0, 0));
+ _scene->_dynamicHotspots.setPosition(idx, Common::Point(228, 83), FACING_SOUTH);
+ _bartenderTalking = true;
+ if (_talkTimer > 1000)
+ _scene->_sequences.addTimer(_talkTimer - 1000, 101);
+ else
+ _scene->_sequences.addTimer(_talkTimer, 101);
+ }
+ }
+
+ if ((_game._trigger == 101) && _bartenderTalking) {
+ _scene->_sequences.remove(_globals._sequenceIndexes[10]);
+ _globals._sequenceIndexes[9] = _scene->_sequences.startCycle(_globals._spriteIndexes[9], false, 1);
+ int idx = _scene->_dynamicHotspots.add(NOUN_BARTENDER, 0xD, _globals._sequenceIndexes[9], Common::Rect(0, 0, 0, 0));
+ _scene->_dynamicHotspots.setPosition(idx, Common::Point(228, 83), FACING_SOUTH);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[9], 8);
+ _bartenderSteady = true;
+ _bartenderTalking = false;
+ if (_talkTimer < 1000)
+ _bartenderReady = true;
+ }
+
+ if (_game._trigger == 28)
+ _game._player._stepEnabled = true;
+
+ switch (_game._trigger) {
+ case 92:
+ _game._player._stepEnabled = false;
+ _scene->_sequences.remove(_globals._sequenceIndexes[6]);
+ _globals._sequenceIndexes[7] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[7], false, 10, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[7], 1, 2);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[7], 5);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[7], SEQUENCE_TRIGGER_EXPIRE, 0, 93);
+ break;
+
+ case 93: {
+ int seqIdx = _globals._sequenceIndexes[7];
+ switch (_roxMode) {
+ case 20:
+ _vm->_sound->command(57);
+ _scene->_sequences.remove(_globals._sequenceIndexes[15]);
+ _game._objects.addToInventory(OBJ_CREDIT_CHIP);
+ _vm->_dialogs->showItem(OBJ_CREDIT_CHIP, 40242);
+ break;
+
+ case 22:
+ _vm->_sound->command(57);
+ _scene->_sequences.remove(_globals._sequenceIndexes[8]);
+ _game._objects.addToInventory(OBJ_ALIEN_LIQUOR);
+ _globals[kBottleDisplayed] = false;
+ _vm->_dialogs->showItem(OBJ_ALIEN_LIQUOR, 40241);
+ break;
+
+ case 21:
+ _globals._sequenceIndexes[15] = _scene->_sequences.startCycle(_globals._spriteIndexes[15], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[15], 8);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[15], Common::Point(250, 80));
+ break;
+
+ default:
+ break;
+ }
+ _globals._sequenceIndexes[7] = _scene->_sequences.addReverseSpriteCycle(_globals._spriteIndexes[7], false, 10, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[7], 1, 3);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[7], 5);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[7], seqIdx);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[7], SEQUENCE_TRIGGER_EXPIRE, 0, 94);
+
+ if (_roxMode == 21) {
+ if (_game._objects.isInInventory(OBJ_CREDIT_CHIP))
+ _game._objects.setRoom (OBJ_CREDIT_CHIP, NOWHERE);
+
+ _bartenderMode = 20;
+ _scene->_sequences.addTimer(60, 95);
+ }
+ }
+ break;
+
+ case 94: {
+ int seqIdx = _globals._sequenceIndexes[7];
+ _globals._sequenceIndexes[6] = _scene->_sequences.startCycle(_globals._spriteIndexes[6], false, 11);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[6], 5);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[6], seqIdx);
+ if (_roxMode == 22) {
+ _scene->_kernelMessages.reset();
+ _scene->_kernelMessages.add(Common::Point(230, 56), 0x1110, 32, 0, 120, _game.getQuote(0x23F));
+ _bartenderMode = 21;
+ _globals[kHasPurchased] = true;
+ _scene->_sequences.addTimer(140, 95);
+ } else if (_roxMode == 20)
+ _game._player._stepEnabled = true;
+
+ }
+ break;
+ }
+
+ switch (_game._trigger) {
+ case 95:
+ _bartenderReady = false;
+ _game._player._stepEnabled = false;
+ if (_bartenderHandsHips || _bartenderTalking) {
+ _scene->_sequences.remove(_globals._sequenceIndexes[10]);
+ _bartenderHandsHips = false;
+ _bartenderTalking = false;
+ }
+
+ if (_bartenderLooksLeft) {
+ _scene->_sequences.remove(_globals._sequenceIndexes[11]);
+ _bartenderLooksLeft = false;
+ }
+
+ if (_bartenderSteady) {
+ _scene->_sequences.remove(_globals._sequenceIndexes[9]);
+ _bartenderSteady = false;
+ }
+ _globals._sequenceIndexes[12] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[12], false, 10, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[12], 1, 4);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[12], 8);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[12], SEQUENCE_TRIGGER_EXPIRE, 0, 96);
+ break;
+
+ case 96: {
+ int seqIdx = _globals._sequenceIndexes[12];
+ _globals._sequenceIndexes[12] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[12], false, 10, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[12], 6, 7);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[12], 8);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[12], seqIdx);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[12], SEQUENCE_TRIGGER_EXPIRE, 0, 97);
+ }
+ break;
+
+ case 97: {
+ int seqIdx = _globals._sequenceIndexes[12];
+ switch (_bartenderMode) {
+ case 20:
+ _scene->_sequences.remove(_globals._sequenceIndexes[15]);
+ break;
+
+ case 21: {
+ _globals._sequenceIndexes[15] = _scene->_sequences.startCycle(_globals._spriteIndexes[15], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[15], 8);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[15], Common::Point(250, 80));
+ int idx = _scene->_dynamicHotspots.add(NOUN_CREDIT_CHIP, 0x4, _globals._sequenceIndexes[15], Common::Rect(0, 0, 0, 0));
+ _scene->_dynamicHotspots.setPosition(idx, Common::Point(0, 0), FACING_NONE);
+ }
+ break;
+
+ case 22:
+ _scene->_sequences.remove(_globals._sequenceIndexes[8]);
+ _globals[kBottleDisplayed] = false;
+ break;
+
+ default:
+ break;
+ }
+
+ _globals._sequenceIndexes[12] = _scene->_sequences.startCycle(_globals._spriteIndexes[12], false, 6);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[12], seqIdx);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[12], 8);
+ _scene->_sequences.addTimer(10, 98);
+ }
+ break;
+
+ case 98:
+ _scene->_sequences.remove(_globals._sequenceIndexes[12]);
+ _globals._sequenceIndexes[12] = _scene->_sequences.addReverseSpriteCycle(_globals._spriteIndexes[12], false, 10, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[12], 1, 4);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[12], 8);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[12], SEQUENCE_TRIGGER_EXPIRE, 0, 99);
+ break;
+
+ case 99: {
+ int seqIdx = _globals._sequenceIndexes[12];
+ _globals._sequenceIndexes[9] = _scene->_sequences.startCycle(_globals._spriteIndexes[9], false, 1);
+ _bartenderSteady = true;
+ int idx = _scene->_dynamicHotspots.add(NOUN_BARTENDER, 0xD, _globals._sequenceIndexes[9], Common::Rect(0, 0, 0, 0));
+ _scene->_dynamicHotspots.setPosition(idx, Common::Point(228, 83), FACING_SOUTH);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[9], seqIdx);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[9], 8);
+ if (_bartenderMode == 20) {
+ _scene->_kernelMessages.reset();
+ _scene->_kernelMessages.add(Common::Point(210, 41), 0xFDFC, 0, 0, 100, _game.getQuote(0x1F3));
+ _scene->_sequences.addTimer(5, 100);
+ _talkTimer = 180;
+ _roxMode = 22;
+ _scene->_sequences.addTimer(65, 92);
+ } else if ((_bartenderMode == 21) || (_bartenderMode == 22)) {
+ _game._player._stepEnabled = true;
+ _bartenderReady = true;
+ }
+
+ }
+ break;
+ }
+
+ switch (_game._trigger) {
+ case 86:
+ _bartenderReady = false;
+ _game._player._stepEnabled = false;
+ if ((_bartenderHandsHips) || (_bartenderTalking)) {
+ _scene->_sequences.remove(_globals._sequenceIndexes[10]);
+ _bartenderHandsHips = false;
+ _bartenderTalking = false;
+ } else if (_bartenderLooksLeft) {
+ _scene->_sequences.remove(_globals._sequenceIndexes[11]);
+ _bartenderLooksLeft = false;
+ } else if (_bartenderSteady) {
+ _scene->_sequences.remove(_globals._sequenceIndexes[9]);
+ _bartenderSteady = false;
+ }
+ _globals._sequenceIndexes[9] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[9], false, 10, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[9], 1, 9);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[9], 8);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[9], SEQUENCE_TRIGGER_EXPIRE, 0, 87);
+ break;
+
+ case 87: {
+ int seqIdx = _globals._sequenceIndexes[9];
+ _globals._sequenceIndexes[9] = _scene->_sequences.startCycle(_globals._spriteIndexes[9], false, 9);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[9], 8);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[9], seqIdx);
+ _scene->_sequences.addTimer(10, 89);
+
+ _globals._sequenceIndexes[8] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[8], false, 10, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[8], 1, 4);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[8], 7);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[8], SEQUENCE_TRIGGER_EXPIRE, 0, 88);
+ }
+ break;
+
+ case 88:
+ _globals._sequenceIndexes[8] = _scene->_sequences.startCycle(_globals._spriteIndexes[8], false, 4);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[8], 7);
+ _globals[kBottleDisplayed] = true;
+ break;
+
+ case 89:
+ _scene->_sequences.remove(_globals._sequenceIndexes[9]);
+ _globals._sequenceIndexes[9] = _scene->_sequences.startCycle(_globals._spriteIndexes[9], false, 6);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[9], 8);
+ _scene->_sequences.addTimer(10, 90);
+ break;
+
+ case 90:
+ _scene->_sequences.remove(_globals._sequenceIndexes[9]);
+ _globals._sequenceIndexes[9] = _scene->_sequences.startCycle(_globals._spriteIndexes[9], false, 5);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[9], 8);
+ _scene->_sequences.addTimer(10, 91);
+ break;
+
+ case 91: {
+ _scene->_sequences.remove(_globals._sequenceIndexes[9]);
+ _globals._sequenceIndexes[9] = _scene->_sequences.startCycle(_globals._spriteIndexes[9], false, 1);
+ int idx = _scene->_dynamicHotspots.add(NOUN_BARTENDER, 0xD, _globals._sequenceIndexes[9], Common::Rect(0, 0, 0, 0));
+ _scene->_dynamicHotspots.setPosition(idx, Common::Point(228, 83), FACING_SOUTH);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[9], 8);
+ _bartenderSteady = true;
+ _game._player._stepEnabled = true;
+ _bartenderReady = true;
+ }
+ break;
+ }
+
+ if (!_waitingGinnyMove && !_ginnyLooking) {
+ _waitingGinnyMove = true;
+ ++ _beatCounter;
+ if (_beatCounter >= 20) {
+ _ginnyLooking = true;
+ _beatCounter = 0;
+ _scene->_sequences.addTimer(60, 54);
+ } else {
+ _scene->_sequences.addTimer(30, 75);
+ }
+ }
+
+ switch (_game._trigger) {
+ case 75:
+ _scene->_sequences.remove(_globals._sequenceIndexes[5]);
+ _bigBeatFl = !_bigBeatFl;
+
+ if (_bigBeatFl) {
+ _globals._sequenceIndexes[5] = _scene->_sequences.startCycle(_globals._spriteIndexes[5], false, 5);
+ _scene->_sequences.addTimer(8, 130);
+ } else {
+ _globals._sequenceIndexes[5] = _scene->_sequences.startCycle(_globals._spriteIndexes[5], false, 5);
+ _scene->_sequences.addTimer(8, 53);
+ }
+
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[5], 1);
+ break;
+
+ case 130:
+ _scene->_sequences.remove(_globals._sequenceIndexes[5]);
+ _globals._sequenceIndexes[5] = _scene->_sequences.startCycle(_globals._spriteIndexes[5], false, 6);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[5], 1);
+ _scene->_sequences.addTimer(8, 131);
+ break;
+
+ case 131:
+ _scene->_sequences.remove(_globals._sequenceIndexes[5]);
+ _globals._sequenceIndexes[5] = _scene->_sequences.startCycle(_globals._spriteIndexes[5], false, 5);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[5], 1);
+ _scene->_sequences.addTimer(8, 53);
+ break;
+
+ case 53:
+ _scene->_sequences.remove(_globals._sequenceIndexes[5]);
+ _globals._sequenceIndexes[5] = _scene->_sequences.startCycle(_globals._spriteIndexes[5], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[5], 1);
+ _waitingGinnyMove = false;
+ break;
+ }
+
+ if ((_game._trigger == 54) && _ginnyLooking) {
+ ++_beatCounter;
+ if (_beatCounter >= 10) {
+ _ginnyLooking = false;
+ _waitingGinnyMove = false;
+ _beatCounter = 0;
+ _bigBeatFl = true;
+ } else {
+ _scene->_sequences.remove(_globals._sequenceIndexes[5]);
+ _globals._sequenceIndexes[5] = _scene->_sequences.startCycle(_globals._spriteIndexes[5], false, _vm->getRandomNumber(1, 4));
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[5], 1);
+ _scene->_sequences.addTimer(60, 54);
+ }
+ }
+
+ if (_bartenderReady) {
+ if (_vm->getRandomNumber(1, 250) == 1) {
+ if (_bartenderLooksLeft) {
+ _scene->_sequences.remove(_globals._sequenceIndexes[11]);
+ _bartenderLooksLeft = false;
+ } else if (_bartenderHandsHips) {
+ _scene->_sequences.remove(_globals._sequenceIndexes[10]);
+ _bartenderHandsHips = false;
+ } else if (_bartenderSteady) {
+ _scene->_sequences.remove(_globals._sequenceIndexes[9]);
+ _bartenderSteady = false;
+ }
+
+ switch (_vm->getRandomNumber(1, 3)) {
+ case 1: {
+ _globals._sequenceIndexes[10] = _scene->_sequences.startCycle(_globals._spriteIndexes[10], false, 4);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[10], 8);
+ int idx = _scene->_dynamicHotspots.add(NOUN_BARTENDER, 0xD, _globals._sequenceIndexes[10], Common::Rect(0, 0, 0, 0));
+ _scene->_dynamicHotspots.setPosition(idx, Common::Point(228, 83), FACING_SOUTH);
+ _bartenderHandsHips = true;
+ }
+ break;
+
+ case 2: {
+ _globals._sequenceIndexes[11] = _scene->_sequences.startCycle(_globals._spriteIndexes[11], false, 2);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[11], 8);
+ int idx = _scene->_dynamicHotspots.add(NOUN_BARTENDER, 0xD, _globals._sequenceIndexes[11], Common::Rect(0, 0, 0, 0));
+ _scene->_dynamicHotspots.setPosition(idx, Common::Point(228, 83), FACING_SOUTH);
+ _bartenderLooksLeft = true;
+ }
+ break;
+
+ case 3: {
+ _globals._sequenceIndexes[9] = _scene->_sequences.startCycle(_globals._spriteIndexes[9], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[9], 8);
+ int idx = _scene->_dynamicHotspots.add(NOUN_BARTENDER, 0xD, _globals._sequenceIndexes[9], Common::Rect(0, 0, 0, 0));
+ _scene->_dynamicHotspots.setPosition(idx, Common::Point(228, 83), FACING_SOUTH);
+ _bartenderSteady = true;
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+
+ if (_game._trigger == 76) {
+ int seqIdx = _globals._sequenceIndexes[6];
+ _globals._sequenceIndexes[6] = _scene->_sequences.startCycle(_globals._spriteIndexes[6], false, 11);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[6], 5);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[6], seqIdx);
+ if (!_globals[kBeenThruHelgaScene]) {
+ _game._player._stepEnabled = false;
+ _cutSceneNeeded = true;
+ } else {
+ _game._player._stepEnabled = true;
+ }
+ _roxOnStool = true;
+ }
+
+ switch (_game._trigger) {
+ case 77:
+ _game._player._stepEnabled = false;
+ _scene->_sequences.remove(_globals._sequenceIndexes[6]);
+ _globals._sequenceIndexes[7] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[7], false, 10, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[7], 10, 12);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[7], 5);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[7], SEQUENCE_TRIGGER_EXPIRE, 0, 78);
+ break;
+
+ case 78: {
+ _vm->_sound->command(57);
+ int seqIdx = _globals._sequenceIndexes[7];
+ _game._objects.addToInventory(OBJ_REPAIR_LIST);
+ _scene->_sequences.remove(_globals._sequenceIndexes[14]);
+ _globals._sequenceIndexes[7] = _scene->_sequences.addReverseSpriteCycle(_globals._spriteIndexes[7], false, 10, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[7], 10, 12);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[7], 5);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[7], seqIdx);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[7], SEQUENCE_TRIGGER_EXPIRE, 0, 79);
+ }
+ break;
+
+ case 79: {
+ int seqIdx = _globals._sequenceIndexes[7];
+ _globals._sequenceIndexes[6] = _scene->_sequences.startCycle(_globals._spriteIndexes[6], false, 11);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[6], 5);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[6], seqIdx);
+ _scene->_sequences.addTimer(20, 180);
+ }
+ break;
+
+ case 180:
+ _vm->_dialogs->showItem(OBJ_REPAIR_LIST, 40240);
+ _game._player._stepEnabled = true;
+ break;
+
+ default:
+ break;
+ }
+
+ if (_cutSceneNeeded && _cutSceneReady) {
+ _cutSceneNeeded = false;
+ _scene->_sequences.addTimer(20, 55);
+ _helgaReady = false;
+ _bartenderReady = false;
+ }
+
+ if (_vm->getRandomNumber(1, 25) == 1) {
+ if (_lightOn) {
+ _scene->_sequences.remove(_globals._sequenceIndexes[0]);
+ _lightOn = false;
+ } else {
+ _globals._sequenceIndexes[0] = _scene->_sequences.startCycle(_globals._spriteIndexes[0], false, 1);
+ _lightOn = true;
+ }
+ }
+
+ if (!_blowingSmoke && (_vm->getRandomNumber(1, 300) == 1)) {
+ _globals._sequenceIndexes[1] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[1], false, 8, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[1], 1, 14);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 14);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[1], SEQUENCE_TRIGGER_EXPIRE, 0, 30);
+ _blowingSmoke = true;
+ }
+
+ switch (_game._trigger) {
+ case 30:
+ _globals._sequenceIndexes[1] = _scene->_sequences.addReverseSpriteCycle(_globals._spriteIndexes[1], false, 8, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[1], 1, 5);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 14);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[1],SEQUENCE_TRIGGER_EXPIRE, 0, 31);
+ break;
+
+ case 31:
+ _blowingSmoke = false;
+ break;
+ }
+
+ if (!_leftWomanMoving) {
+ if (_vm->getRandomNumber(1, 1000) == 1) {
+ switch (_vm->getRandomNumber(1, 2)) {
+ case 1:
+ _globals._sequenceIndexes[2] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[2], false, 12, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[2], 1, 8);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[2], SEQUENCE_TRIGGER_EXPIRE, 0, 33);
+ _leftWomanMoving = true;
+ break;
+
+ case 2:
+ _globals._sequenceIndexes[2] = _scene->_sequences.startCycle(_globals._spriteIndexes[2], false, 1);
+ _scene->_sequences.addTimer(12, 35);
+ _leftWomanMoving = true;
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+
+ switch (_game._trigger) {
+ case 33: {
+ int seqIdx = _globals._sequenceIndexes[2];
+ _globals._sequenceIndexes[2] = _scene->_sequences.startCycle(_globals._spriteIndexes[2], false, 9);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[2], seqIdx);
+ _scene->_sequences.addTimer(_vm->getRandomNumber(60, 250), 34);
+ }
+ break;
+
+ case 34:
+ _scene->_sequences.remove(_globals._sequenceIndexes[2]);
+ _globals._sequenceIndexes[2] = _scene->_sequences.addReverseSpriteCycle(_globals._spriteIndexes[2], false, 12, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[2], 1, 8);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[2], SEQUENCE_TRIGGER_EXPIRE, 0, 38);
+ break;
+
+ case 35:
+ _scene->_sequences.remove(_globals._sequenceIndexes[2]);
+ _globals._sequenceIndexes[2] = _scene->_sequences.startCycle(_globals._spriteIndexes[2], false, 2);
+ _scene->_sequences.addTimer(_vm->getRandomNumber(60, 300), 36);
+ break;
+
+ case 36:
+ _scene->_sequences.remove(_globals._sequenceIndexes[2]);
+ _globals._sequenceIndexes[2] = _scene->_sequences.startCycle(_globals._spriteIndexes[2], false, 1);
+ _scene->_sequences.addTimer(12, 37);
+ break;
+
+ case 37:
+ _scene->_sequences.remove(_globals._sequenceIndexes[2]);
+ _leftWomanMoving = false;
+ break;
+
+ case 38:
+ _leftWomanMoving = false;
+ break;
+
+ default:
+ break;
+ }
+
+ if (!_rightWomanMoving) {
+ if (_vm->getRandomNumber(1, 300) == 1) {
+ switch (_vm->getRandomNumber(1, 4)) {
+ case 1:
+ _globals._sequenceIndexes[3] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[3], false, 12, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[3], 1, 4);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[3], SEQUENCE_TRIGGER_EXPIRE, 0, 32);
+ _rightWomanMoving = true;
+ break;
+
+ case 2:
+ _globals._sequenceIndexes[3] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[3], false, 12, 2, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[3], 4, 5);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[3], SEQUENCE_TRIGGER_EXPIRE, 0, 32);
+ _rightWomanMoving = true;
+ break;
+
+ case 3:
+ _globals._sequenceIndexes[3] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[3], false, 12, 2, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[3], 4, 5);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[3], SEQUENCE_TRIGGER_EXPIRE, 0, 32);
+ _rightWomanMoving = true;
+ break;
+
+ case 4:
+ _globals._sequenceIndexes[3] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[3], false, 12, 2, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[3], 3, 4);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[3], SEQUENCE_TRIGGER_EXPIRE, 0, 32);
+ _rightWomanMoving = true;
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+
+ if (_game._trigger == 32)
+ _rightWomanMoving = false;
+
+ if (_scene->_activeAnimation->getCurrentFrame() == 1) {
+ switch (_vm->getRandomNumber(1, 50)) {
+ case 1:
+ _scene->_activeAnimation->setCurrentFrame(2);
+ break;
+
+ case 2:
+ _scene->_activeAnimation->setCurrentFrame(7);
+ break;
+
+ case 3:
+ _scene->_activeAnimation->setCurrentFrame(11);
+ break;
+
+ default:
+ _scene->_activeAnimation->setCurrentFrame(0);
+ break;
+ }
+ }
+
+ if ((_scene->_activeAnimation->getCurrentFrame() == 4) && (_drinkTimer < 10)) {
+ ++ _drinkTimer;
+ _scene->_activeAnimation->setCurrentFrame(3);
+ }
+
+ if (_drinkTimer == 10) {
+ _drinkTimer = 0;
+ _scene->_activeAnimation->setCurrentFrame(4);
+ _scene->_activeAnimation->_currentFrame = 5;
+ }
+
+
+ switch (_scene->_activeAnimation->getCurrentFrame()) {
+ case 6:
+ case 10:
+ case 14:
+ _scene->_activeAnimation->setCurrentFrame(0);
+ break;
+
+ default:
+ break;
+ }
+
+ switch (_game._trigger) {
+ case 39:
+ _scene->_kernelMessages.reset();
+ _scene->_kernelMessages.add(Common::Point(89, 67), 0xFDFC, 32, 0, 120, _game.getQuote(0x1D8));
+ _scene->_sequences.addTimer(150, 40);
+ break;
+
+ case 40:
+ _scene->_kernelMessages.add(Common::Point(89, 67), 0xFDFC, 32, 0, 120, _game.getQuote(0x1D9));
+ _scene->_sequences.addTimer(150, 41);
+ break;
+
+ case 41:
+ _scene->_kernelMessages.add(Common::Point(89, 67), 0xFDFC, 32, 0, 120, _game.getQuote(0x1DA));
+ _game._player._stepEnabled = true;
+ break;
+
+ case 42:
+ _scene->_kernelMessages.reset();
+ _scene->_kernelMessages.add(Common::Point(89, 67), 0xFDFC, 32, 0, 120, _game.getQuote(0x1DC));
+ _scene->_sequences.addTimer(150, 43);
+ break;
+
+ case 43:
+ _scene->_kernelMessages.add(Common::Point(89, 67), 0xFDFC, 32, 0, 120, _game.getQuote(0x1DD));
+ _game._player._stepEnabled = true;
+ break;
+
+ case 44:
+ _game._player._stepEnabled = true;
+ break;
+
+ default:
+ break;
+ }
+
+ switch (_game._trigger) {
+ case 55:
+ if (_bartenderHandsHips) {
+ _scene->_sequences.remove(_globals._sequenceIndexes[10]);
+ _bartenderHandsHips = false;
+ _globals._sequenceIndexes[9] = _scene->_sequences.startCycle(_globals._spriteIndexes[9], false, 1);
+ int idx = _scene->_dynamicHotspots.add(NOUN_BARTENDER, 0xD, _globals._sequenceIndexes[9], Common::Rect(0, 0, 0, 0));
+ _scene->_dynamicHotspots.setPosition(idx, Common::Point(228, 83), FACING_SOUTH);
+ _bartenderSteady = true;
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[9], 8);
+ } else if (_bartenderLooksLeft) {
+ _scene->_sequences.remove(_globals._sequenceIndexes[11]);
+ _bartenderLooksLeft = false;
+ _globals._sequenceIndexes[9] = _scene->_sequences.startCycle(_globals._spriteIndexes[9], false, 1);
+ int idx = _scene->_dynamicHotspots.add(NOUN_BARTENDER, 0xD, _globals._sequenceIndexes[9], Common::Rect(0, 0, 0, 0));
+ _scene->_dynamicHotspots.setPosition(idx, Common::Point(228, 83), FACING_SOUTH);
+ _bartenderSteady = true;
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[9], 8);
+ }
+ _game._player._stepEnabled = false;
+ _scene->_kernelMessages.reset();
+ _scene->_kernelMessages.add(Common::Point(180, 47), 0xFBFA, 0, 0, 100, _game.getQuote(0x1FE));
+ _scene->_sequences.addTimer(120, 56);
+ break;
+
+ case 56:
+ _scene->_sequences.remove(_globals._sequenceIndexes[13]);
+ _globals._sequenceIndexes[13] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[13], false, 10, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[13], 2, 5);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[13], 8);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[13], SEQUENCE_TRIGGER_EXPIRE, 0, 57);
+ break;
+
+ case 57: {
+ int seqIdx = _globals._sequenceIndexes[13];
+ _scene->_sequences.remove(_globals._sequenceIndexes[20]);
+ _globals._sequenceIndexes[13] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[13], false, 10, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[13], 6, 9);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[13], 8);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[13], seqIdx);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[13], SEQUENCE_TRIGGER_EXPIRE, 0, 58);
+ }
+ break;
+
+ case 58: {
+ int seqIdx = _globals._sequenceIndexes[13];
+ _globals._sequenceIndexes[13] = _scene->_sequences.addReverseSpriteCycle(_globals._spriteIndexes[13], false, 10, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[13], 5, 9);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[13], 8);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[13], seqIdx);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[13], SEQUENCE_TRIGGER_EXPIRE, 0, 59);
+ }
+ break;
+
+ case 59: {
+ int seqIdx = _globals._sequenceIndexes[13];
+ _globals._sequenceIndexes[13] = _scene->_sequences.addReverseSpriteCycle(_globals._spriteIndexes[13], false, 10, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[13], 1, 4);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[13], 8);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[13], seqIdx);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[13], SEQUENCE_TRIGGER_EXPIRE, 0, 60);
+ _globals._sequenceIndexes[20] = _scene->_sequences.startCycle(_globals._spriteIndexes[20], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[20], 8);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[20], Common::Point(234, 72));
+ }
+ break;
+
+ case 60: {
+ int seqIdx = _globals._sequenceIndexes[13];
+ _globals._sequenceIndexes[13] = _scene->_sequences.startCycle(_globals._spriteIndexes[13], false, 2);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[13], seqIdx);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[13], 8);
+ _scene->_sequences.addTimer(10, 61);
+ }
+ break;
+
+ case 61:
+ _scene->_kernelMessages.reset();
+ _scene->_kernelMessages.add(Common::Point(181, 33), 0xFBFA, 0, 0, 130, _game.getQuote(0x1FF));
+ _scene->_kernelMessages.add(Common::Point(171, 47), 0xFBFA, 0, 0, 130, _game.getQuote(0x200));
+ _scene->_sequences.addTimer(150, 63);
+ _scene->_sequences.remove(_globals._sequenceIndexes[13]);
+ _globals._sequenceIndexes[13] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[13], false, 30, 4, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[13], 10, 11);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[13], 8);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[13], SEQUENCE_TRIGGER_EXPIRE, 0, 62);
+ break;
+
+ case 62: {
+ int seqIdx = _globals._sequenceIndexes[13];
+ _globals._sequenceIndexes[13] = _scene->_sequences.startCycle(_globals._spriteIndexes[13], false, 2);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[13], seqIdx);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[13], 8);
+ }
+ break;
+
+ case 63:
+ _scene->_kernelMessages.reset();
+ _scene->_kernelMessages.add(Common::Point(160, 33), 0xFBFA, 0, 0, 130, _game.getQuote(0x201));
+ _scene->_kernelMessages.add(Common::Point(165, 47), 0xFBFA, 0, 0, 130, _game.getQuote(0x202));
+ _scene->_sequences.addTimer(150, 64);
+ break;
+
+ case 64:
+ _scene->_kernelMessages.reset();
+ _scene->_kernelMessages.add(Common::Point(210, 27), 0xFDFC, 0, 0, 130, _game.getQuote(0x1E0));
+ _scene->_kernelMessages.add(Common::Point(198, 41), 0xFDFC, 0, 0, 130, _game.getQuote(0x1E1));
+ _scene->_sequences.addTimer(150, 65);
+ _scene->_sequences.addTimer(1, 100);
+ _talkTimer = 1130;
+ break;
+
+ case 65:
+ _vm->_sound->command(30);
+ _globals._sequenceIndexes[16] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[16], false, 10, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[16], 1, 6);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[16], 9);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[16], SEQUENCE_TRIGGER_EXPIRE, 0, 66);
+ break;
+
+ case 66: {
+ int seqIdx = _globals._sequenceIndexes[16];
+ _globals._sequenceIndexes[16] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[16], false, 10, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[16], 7, 37);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[16], 9);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[16], seqIdx);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[16], SEQUENCE_TRIGGER_EXPIRE, 0, 68);
+
+ _scene->_sequences.remove(_globals._sequenceIndexes[13]);
+ _globals._sequenceIndexes[13] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[13], false, 10, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[13], 12, 13);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[13], 8);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[13], SEQUENCE_TRIGGER_EXPIRE, 0, 67);
+ }
+ break;
+
+ case 67: {
+ int seqIdx = _globals._sequenceIndexes[13];
+ _globals._sequenceIndexes[13] = _scene->_sequences.startCycle(_globals._spriteIndexes[13], false, 13);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[13], seqIdx);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[13], 8);
+ }
+ break;
+
+ case 68:
+ _scene->_sequences.remove(_globals._sequenceIndexes[13]);
+ _globals._sequenceIndexes[13] = _scene->_sequences.addReverseSpriteCycle(_globals._spriteIndexes[13], false, 10, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[13], 12, 13);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[13], 8);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[13], SEQUENCE_TRIGGER_EXPIRE, 0, 69);
+ break;
+
+ case 69: {
+ int seqIdx = _globals._sequenceIndexes[13];
+ _globals._sequenceIndexes[13] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[13], false, 25, 4, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[13], 10, 11);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[13], 8);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[13], seqIdx);
+
+ _scene->_kernelMessages.reset();
+ _scene->_kernelMessages.add(Common::Point(179, 33), 0xFBFA, 0, 0, 130, _game.getQuote(0x203));
+ _scene->_kernelMessages.add(Common::Point(167, 47), 0xFBFA, 0, 0, 130, _game.getQuote(0x204));
+ _scene->_sequences.addTimer(150, 71);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[13], SEQUENCE_TRIGGER_EXPIRE, 0, 70);
+ }
+ break;
+
+ case 70:
+ _globals._sequenceIndexes[13] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[13], false, 25, 4, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[13], 10, 12);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[13], 8);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[13], SEQUENCE_TRIGGER_EXPIRE, 0, 72);
+ break;
+
+ case 71:
+ _scene->_sequences.addTimer(210, 73);
+ _scene->_kernelMessages.reset();
+ _scene->_kernelMessages.add(Common::Point(168, 33), 0xFBFA, 0, 0, 180, _game.getQuote(0x205));
+ _scene->_kernelMessages.add(Common::Point(151, 47), 0xFBFA, 0, 0, 180, _game.getQuote(0x206));
+ if (!_game._objects.isInInventory(OBJ_REPAIR_LIST))
+ _activeArrows = true;
+ break;
+
+ case 72: {
+ int seqIdx = _globals._sequenceIndexes[13];
+ _globals._sequenceIndexes[13] = _scene->_sequences.startCycle(_globals._spriteIndexes[13], false, 2);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[13], seqIdx);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[13], 8);
+ }
+ break;
+
+ case 73:
+ _scene->_kernelMessages.reset();
+ _scene->_kernelMessages.add(Common::Point(177, 33), 0xFBFA, 0, 0, 150, _game.getQuote(0x207));
+ _scene->_kernelMessages.add(Common::Point(172, 47), 0xFBFA, 0, 0, 150, _game.getQuote(0x208));
+ _bartenderSteady = true;
+ _game._player._stepEnabled = true;
+ _helgaReady = true;
+ _bartenderReady = true;
+ _globals[kBeenThruHelgaScene] = true;
+ _activeArrows = false;
+ break;
+
+ default:
+ break;
+ }
+
+ if (_helgaReady) {
+ int rndVal = _vm->getRandomNumber(1, 1000);
+ if (rndVal < 6)
+ switch (rndVal) {
+ case 1:
+ _cutSceneReady = false;
+ _helgaReady = false;
+ _scene->_sequences.remove(_globals._sequenceIndexes[13]);
+ _globals._sequenceIndexes[13] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[13], false, 10, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[13], 2, 5);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[13], 8);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[13], SEQUENCE_TRIGGER_EXPIRE, 0, 82);
+ break;
+
+ case 2:
+ _cutSceneReady = false;
+ _helgaReady = false;
+ _scene->_sequences.remove(_globals._sequenceIndexes[13]);
+ _globals._sequenceIndexes[13] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[13], false, 15, 2, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[13], 11, 13);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[13], 8);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[13], SEQUENCE_TRIGGER_EXPIRE, 0, 26);
+ break;
+
+ case 3:
+ _cutSceneReady = false;
+ _helgaReady = false;
+ _scene->_sequences.remove(_globals._sequenceIndexes[13]);
+ _globals._sequenceIndexes[13] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[13], false, 10, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[13], 10, 11);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[13], 8);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[13], SEQUENCE_TRIGGER_EXPIRE, 0, 26);
+ break;
+
+ case 4:
+ _cutSceneReady = false;
+ _helgaReady = false;
+ _scene->_sequences.remove(_globals._sequenceIndexes[13]);
+ _globals._sequenceIndexes[13] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[13], false, 15, 2, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[13], 14, 15);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[13], 8);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[13], SEQUENCE_TRIGGER_EXPIRE, 0, 26);
+ break;
+
+ case 5:
+ _cutSceneReady = false;
+ _helgaReady = false;
+ _scene->_sequences.remove(_globals._sequenceIndexes[13]);
+ _globals._sequenceIndexes[13] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[13], false, 10, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[13], 16, 19);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[13], 8);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[13], SEQUENCE_TRIGGER_EXPIRE, 0, 80);
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ if (_game._trigger == 80) {
+ int seqIdx = _globals._sequenceIndexes[13];
+ _globals._sequenceIndexes[13] = _scene->_sequences.startCycle(_globals._spriteIndexes[13], false, 19);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[13], seqIdx);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[13], 8);
+ _scene->_sequences.addTimer(_vm->getRandomNumber(60, 120), 81);
+ }
+
+ if (_game._trigger == 81) {
+ _scene->_sequences.remove(_globals._sequenceIndexes[13]);
+ _globals._sequenceIndexes[13] = _scene->_sequences.addReverseSpriteCycle(_globals._spriteIndexes[13], false, 10, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[13], 16, 19);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[13], 8);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[13], SEQUENCE_TRIGGER_EXPIRE, 0, 26);
+ }
+
+ if (_game._trigger == 26) {
+ int seqIdx = _globals._sequenceIndexes[13];
+ _globals._sequenceIndexes[13] = _scene->_sequences.startCycle(_globals._spriteIndexes[13], false, 2);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[13], seqIdx);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[13], 8);
+ _cutSceneReady = true;
+
+ if (!_cutSceneNeeded)
+ _helgaReady = true;
+ }
+
+ if (_game._trigger == 82) {
+ _scene->_sequences.remove(_globals._sequenceIndexes[20]);
+ int seqIdx = _globals._sequenceIndexes[13];
+ _globals._sequenceIndexes[13] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[13], false, 10, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[13], 6, 9);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[13], 8);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[13], seqIdx);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[13], SEQUENCE_TRIGGER_EXPIRE, 0, 83);
+ }
+
+ if (_game._trigger == 83) {
+ int seqIdx = _globals._sequenceIndexes[13];
+ _globals._sequenceIndexes[13] = _scene->_sequences.addReverseSpriteCycle(_globals._spriteIndexes[13], false, 10, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[13], 5, 9);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[13], 8);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[13], seqIdx);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[13], SEQUENCE_TRIGGER_EXPIRE, 0, 84);
+ }
+
+ if (_game._trigger == 84) {
+ int seqIdx = _globals._sequenceIndexes[13];
+ _globals._sequenceIndexes[13] = _scene->_sequences.addReverseSpriteCycle(_globals._spriteIndexes[13], false, 10, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[13], 1, 4);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[13], 8);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[13], seqIdx);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[13], SEQUENCE_TRIGGER_EXPIRE, 0, 85);
+
+ _globals._sequenceIndexes[20] = _scene->_sequences.startCycle(_globals._spriteIndexes[20], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[20], 8);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[20], Common::Point(234, 72));
+ }
+
+ if (_game._trigger == 85) {
+ int seqIdx = _globals._sequenceIndexes[13];
+ _globals._sequenceIndexes[13] = _scene->_sequences.startCycle(_globals._spriteIndexes[13], false, 2);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[13], seqIdx);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[13], 8);
+ _cutSceneReady = true;
+ if (!_cutSceneNeeded)
+ _helgaReady = true;
+ }
+
+ if (_game._trigger == 102) {
+ _scene->_sequences.remove(_globals._sequenceIndexes[6]);
+ _game._player._priorTimer = _scene->_frameStartTime - _game._player._ticksAmount;
+ _globals._sequenceIndexes[7] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[7], false, 8, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[7], 14, 18);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[7], 5);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[7], SEQUENCE_TRIGGER_EXPIRE, 0, 103);
+ } else if (_game._trigger == 103) {
+ _game._player._priorTimer = _scene->_frameStartTime + _game._player._ticksAmount;
+ _roxOnStool = false;
+ _game._player._facing = FACING_SOUTH;
+ _game._player.selectSeries();
+ _game._player._visible = true;
+ _game._player._stepEnabled = true;
+ _game._player._readyToWalk = true;
+ }
+
+ if (_activeArrows) {
+ if (!_activeArrow1) {
+ _globals._sequenceIndexes[17] = _scene->_sequences.startCycle(_globals._spriteIndexes[17], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[17], 1);
+ _scene->_sequences.addTimer(_vm->getRandomNumber(10, 15), 49);
+ _activeArrow1 = true;
+ }
+
+ if (!_activeArrow2) {
+ _globals._sequenceIndexes[18] = _scene->_sequences.startCycle(_globals._spriteIndexes[18], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[18], 1);
+ _scene->_sequences.addTimer(_vm->getRandomNumber(10, 15), 50);
+ _activeArrow2 = true;
+ }
+
+ if (!_activeArrow3) {
+ _globals._sequenceIndexes[19] = _scene->_sequences.startCycle(_globals._spriteIndexes[19], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[19], 1);
+ _scene->_sequences.addTimer(_vm->getRandomNumber(10, 15), 51);
+ _activeArrow3 = true;
+ }
+ }
+
+ if (_game._trigger == 49) {
+ _scene->_sequences.remove(_globals._sequenceIndexes[17]);
+ _scene->_sequences.addTimer(_vm->getRandomNumber(10, 15), 45);
+ }
+
+ if (_game._trigger == 45)
+ _activeArrow1 = false;
+
+ if (_game._trigger == 50) {
+ _scene->_sequences.remove(_globals._sequenceIndexes[18]);
+ _scene->_sequences.addTimer(_vm->getRandomNumber(10, 15), 46);
+ }
+
+ if (_game._trigger == 46)
+ _activeArrow2 = false;
+
+ if (_game._trigger == 51) {
+ _scene->_sequences.remove(_globals._sequenceIndexes[19]);
+ _scene->_sequences.addTimer(_vm->getRandomNumber(10, 15), 47);
+ }
+
+ if (_game._trigger == 47)
+ _activeArrow3 = false;
+}
+
+void Scene402::preActions() {
+ if (_action.isAction(VERB_SIT_ON, NOUN_BAR_STOOL) && (_game._player._prepareWalkPos.x != 248))
+ _game._player.walk(Common::Point(232, 112), FACING_EAST);
+
+ if (_action.isAction(VERB_WALKTO, NOUN_WOMAN_ON_BALCONY))
+ _game._player._needToWalk = _game._player._readyToWalk;
+
+ if (!_roxOnStool && _action.isAction(VERB_TAKE, NOUN_CREDIT_CHIP) && !_game._objects.isInInventory(OBJ_CREDIT_CHIP))
+ _game._player.walk(Common::Point(246, 108), FACING_NORTH);
+
+ if (_action.isAction(VERB_TAKE))
+ _game._player._needToWalk = false;
+
+ if (_action.isAction(VERB_TAKE, NOUN_CREDIT_CHIP) && !_roxOnStool)
+ _game._player._needToWalk = true;
+
+ if (_roxOnStool) {
+ if (_action.isAction(VERB_LOOK) || _action.isAction(0x24A) || _action.isAction(VERB_TALKTO))
+ _game._player._needToWalk = false;
+
+ if (_action.isAction(VERB_TAKE, NOUN_REPAIR_LIST) || _action.isAction(VERB_TAKE, NOUN_CREDIT_CHIP))
+ _game._player._needToWalk = false;
+
+ if (_action.isAction(VERB_TALKTO, NOUN_WOMAN_IN_CHAIR) || _action.isAction(VERB_TALKTO, NOUN_WOMAN_IN_ALCOVE))
+ _game._player._needToWalk = _game._player._readyToWalk;
+
+ if (_game._player._needToWalk) {
+ _game._player._facing = FACING_SOUTH;
+ _game._player._readyToWalk = false;
+ _game._player._stepEnabled = false;
+ _game._triggerSetupMode = SEQUENCE_TRIGGER_DAEMON;
+ _scene->_sequences.addTimer(1, 102);
+ }
+ }
+
+ if (_action.isAction(VERB_TAKE, NOUN_REPAIR_LIST) && !_roxOnStool && !_game._objects.isInInventory(OBJ_REPAIR_LIST))
+ _game._player.walk(Common::Point(191, 99), FACING_NORTHEAST);
+
+ if (_action.isAction(VERB_TALKTO, NOUN_BARTENDER) && !_roxOnStool)
+ _game._player.walk(Common::Point(228, 83), FACING_SOUTH);
+
+ if (_action.isAction(VERB_TALKTO, NOUN_REPAIR_WOMAN) && !_roxOnStool)
+ _game._player.walk(Common::Point(208, 102), FACING_NORTHEAST);
+}
+
+void Scene402::actions() {
+ if (_action.isAction(VERB_TAKE, NOUN_REPAIR_LIST) && _game._objects.isInRoom(OBJ_REPAIR_LIST) && _roxOnStool) {
+ _game._triggerSetupMode = SEQUENCE_TRIGGER_DAEMON;
+ _scene->_sequences.addTimer(1, 77);
+ _game._player._needToWalk = false;
+ } else if (_action.isAction(VERB_TAKE, NOUN_REPAIR_LIST) && _game._objects.isInRoom(OBJ_REPAIR_LIST) && !_roxOnStool) {
+ if (_game._trigger == 0) {
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._sequenceIndexes[21] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[21], false, 7, 2, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[21], 1, 2);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[21]);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[21], SEQUENCE_TRIGGER_SPRITE, 2, 165);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[21], SEQUENCE_TRIGGER_EXPIRE, 0, 166);
+ } else if (_game._trigger == 165) {
+ _scene->_sequences.remove(_globals._sequenceIndexes[14]);
+ _game._objects.addToInventory(OBJ_REPAIR_LIST);
+ }
+ } else if (_game._trigger == 166) {
+ _game._player._priorTimer = _scene->_frameStartTime + _game._player._ticksAmount;
+ _game._player._visible = true;
+ _scene->_sequences.addTimer(20, 167);
+ } else if (_game._trigger == 167) {
+ _vm->_dialogs->showItem(OBJ_REPAIR_LIST, 40240);
+ _game._player._stepEnabled = true;
+ } else if (_game._screenObjects._inputMode == 1)
+ handleDialogs();
+ else if (_action.isAction(VERB_WALK_INTO, NOUN_CORRIDOR_TO_SOUTH))
+ _scene->_nextSceneId = 401;
+ else if (_action.isAction(VERB_WALK_ONTO, NOUN_DANCE_FLOOR))
+ ; // just... nothing
+ else if (_action.isAction(VERB_TALKTO, NOUN_REPAIR_WOMAN)) {
+ switch (_game._trigger) {
+ case 0: {
+ _game._player._stepEnabled = false;
+ int random = _vm->getRandomNumber(1, 3);
+ if (_helgaTalkMode == 0)
+ random = 1;
+
+ int centerFlag;
+ Common::Point centerPos;
+ if (_roxOnStool) {
+ centerFlag = 0;
+ centerPos = Common::Point(230, 56);
+ } else {
+ centerFlag = 2;
+ centerPos = Common::Point(0, 0);
+ }
+
+ switch (random) {
+ case 1:
+ _scene->_kernelMessages.add(centerPos, 0x1110, 32 | centerFlag, 0, 90, _game.getQuote(0x211));
+ _scene->_sequences.addTimer(110, 25);
+ break;
+
+ case 2:
+ _scene->_kernelMessages.add(centerPos, 0x1110, 32 | centerFlag, 0, 90, _game.getQuote(0x212));
+ _scene->_sequences.addTimer(110, 25);
+ break;
+
+ case 3:
+ _scene->_kernelMessages.add(centerPos, 0x1110, 32 | centerFlag, 0, 90, _game.getQuote(0x213));
+ _scene->_sequences.addTimer(110, 25);
+ break;
+
+ default:
+ break;
+ }
+ }
+ break;
+
+ case 25:
+ switch (_helgaTalkMode) {
+ case 0:
+ _game._player._stepEnabled = false;
+ _helgaTalkMode = 1;
+ _scene->_kernelMessages.add(Common::Point(177, 33), 0xFBFA, 0, 0, 130, _game.getQuote(0x209));
+ _scene->_kernelMessages.add(Common::Point(182, 47), 0xFBFA, 0, 0, 130, _game.getQuote(0x20A));
+ _game._triggerSetupMode = SEQUENCE_TRIGGER_DAEMON;
+ _scene->_sequences.addTimer(130, 28);
+ break;
+
+ case 1:
+ _game._player._stepEnabled = false;
+ _helgaTalkMode = 2;
+ _scene->_kernelMessages.add(Common::Point(157, 47), 0xFBFA, 0, 0, 100, _game.getQuote(0x20B));
+ _game._triggerSetupMode = SEQUENCE_TRIGGER_DAEMON;
+ _scene->_sequences.addTimer(100, 28);
+ break;
+
+ case 2:
+ _game._player._stepEnabled = false;
+ _helgaTalkMode = 3;
+ _scene->_kernelMessages.add(Common::Point(172, 47), 0xFBFA, 0, 0, 100, _game.getQuote(0x20C));
+ _game._triggerSetupMode = SEQUENCE_TRIGGER_DAEMON;
+ _scene->_sequences.addTimer(100, 28);
+ break;
+
+ case 3:
+ _game._player._stepEnabled = true;
+ break;
+
+ default:
+ break;
+ }
+ break;
+ }
+ } else if (_action.isAction(VERB_TALKTO, NOUN_WOMAN_IN_CHAIR) && !_firstTalkToGirlInChair) {
+ _scene->_kernelMessages.add(Common::Point(0, 0), 0x1110, 34, 0, 120, _game.getQuote(0x1D7));
+ _game._triggerSetupMode = SEQUENCE_TRIGGER_DAEMON;
+ _scene->_sequences.addTimer(150, 39);
+ _game._player._stepEnabled = false;
+ _firstTalkToGirlInChair = true;
+ } else if (_action.isAction(VERB_TALKTO, NOUN_WOMAN_IN_CHAIR) && _firstTalkToGirlInChair) {
+ _scene->_kernelMessages.add(Common::Point(0, 0), 0x1110, 34, 0, 120, _game.getQuote(0x1DB));
+ _game._triggerSetupMode = SEQUENCE_TRIGGER_DAEMON;
+ _scene->_sequences.addTimer(150, 42);
+ _game._player._stepEnabled = false;
+ } else if (_action.isAction(VERB_TALKTO, NOUN_WOMAN_IN_ALCOVE) || _action.isAction(VERB_WALKTO, NOUN_WOMAN_IN_ALCOVE)) {
+ _scene->_kernelMessages.add(Common::Point(102, 48), 0xFBFA, 0, 0, 120, _game.getQuote(0x1DE));
+ _game._triggerSetupMode = SEQUENCE_TRIGGER_DAEMON;
+ _scene->_sequences.addTimer(120, 44);
+ _game._player._stepEnabled = false;
+ } else if (_action.isAction(VERB_WALK_ALONG, NOUN_BAR_STOOL) && (_game._player._targetPos.x == 248)){
+ _scene->_kernelMessages.add(Common::Point(0, -14), 0x1110, 34, 0, 120, _game.getQuote(0x20D));
+ _scene->_kernelMessages.add(Common::Point(0, 0), 0x1110, 34, 0, 120, _game.getQuote(0x20E));
+ } else if (_action.isAction(VERB_WALK_ALONG, NOUN_BAR_STOOL) && !_roxOnStool && (_game._player._targetPos.x != 248)) {
+ _game._player._visible = false;
+ _game._triggerSetupMode = SEQUENCE_TRIGGER_DAEMON;
+ _globals._sequenceIndexes[6] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[6], false, 7, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[6], 1, 11);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[6], 5);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[6], SEQUENCE_TRIGGER_EXPIRE, 0, 76);
+ _game._player._stepEnabled = false;
+ } else if (_action.isAction(VERB_TAKE, NOUN_CREDIT_CHIP) && !_game._objects.isInInventory(OBJ_CREDIT_CHIP) && _roxOnStool) {
+ _roxMode = 20;
+ _game._triggerSetupMode = SEQUENCE_TRIGGER_DAEMON;
+ _scene->_sequences.addTimer(1, 92);
+ } else if (_action.isAction(VERB_TAKE, NOUN_CREDIT_CHIP) && !_game._objects.isInInventory(OBJ_CREDIT_CHIP) && !_roxOnStool) {
+ _game._triggerSetupMode = SEQUENCE_TRIGGER_DAEMON;
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._sequenceIndexes[22] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[22], false, 7, 2, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[22], 1, 2);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[22], Common::Point(_game._player._playerPos.x, _game._player._playerPos.y + 1));
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[22], 5);
+ _scene->_sequences.setScale(_globals._sequenceIndexes[22], 88);
+ _game._triggerSetupMode = SEQUENCE_TRIGGER_DAEMON;
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[22], SEQUENCE_TRIGGER_EXPIRE, 0, 104);
+ } else if (_action.isAction(VERB_TALKTO, NOUN_BARTENDER)) {
+ switch (_game._trigger) {
+ case 0: {
+ int centerFlag;
+ Common::Point centerPos;
+ if (_roxOnStool) {
+ centerFlag = 0;
+ centerPos = Common::Point(230, 56);
+ } else {
+ centerFlag = 2;
+ centerPos = Common::Point(0, 0);
+ }
+
+ _game._player._stepEnabled = false;
+ int quoteId;
+ if (_bartenderCalled) {
+ quoteId = 0x210;
+ } else {
+ quoteId = 0x20F;
+ _bartenderCalled = true;
+ }
+ _scene->_kernelMessages.reset();
+ _scene->_kernelMessages.add(centerPos, 0x1110, 32 | centerFlag, 0, 90, _game.getQuote(quoteId));
+ _scene->_sequences.addTimer(110, 29);
+ _game._triggerSetupMode = SEQUENCE_TRIGGER_DAEMON;
+ _scene->_sequences.addTimer(90, 28);
+ }
+ break;
+
+ case 29:
+ _scene->_kernelMessages.reset();
+ if (!_roxOnStool) {
+ if (_game._objects.isInRoom(OBJ_ALIEN_LIQUOR)) {
+ _scene->_kernelMessages.add(Common::Point(177, 41), 0xFDFC, 0, 0, 120, _game.getQuote(0x1DF));
+ _game._triggerSetupMode = SEQUENCE_TRIGGER_DAEMON;
+ _scene->_sequences.addTimer(1, 100);
+ _talkTimer = 120;
+ } else if (_rexMode == 0) {
+ _scene->_kernelMessages.add(Common::Point(175, 13), 0xFDFC, 0, 0, 180, _game.getQuote(0x1F9));
+ _scene->_kernelMessages.add(Common::Point(184, 27), 0xFDFC, 0, 0, 180, _game.getQuote(0x1FA));
+ _scene->_kernelMessages.add(Common::Point(200, 41), 0xFDFC, 0, 0, 180, _game.getQuote(0x1FB));
+ _game._triggerSetupMode = SEQUENCE_TRIGGER_DAEMON;
+ _scene->_sequences.addTimer(1, 100);
+ _talkTimer = 180;
+ _rexMode = 1;
+ } else if (_rexMode == 1) {
+ _scene->_kernelMessages.add(Common::Point(205, 41), 0xFDFC, 0, 0, 120, _game.getQuote(0x1FC));
+ _game._player._stepEnabled = true;
+ _game._triggerSetupMode = SEQUENCE_TRIGGER_DAEMON;
+ _scene->_sequences.addTimer(1, 100);
+ _talkTimer = 120;
+ _rexMode = 3;
+ } else {
+ _game._player._stepEnabled = true;
+ }
+ } else {
+ if (_game._objects.isInRoom(OBJ_ALIEN_LIQUOR)) {
+ if (!_refuseAlienLiquor) {
+ _scene->_kernelMessages.reset();
+ _scene->_kernelMessages.add(Common::Point(198, 27), 0xFDFC, 0, 0, 9999999, _game.getQuote(0x1E2));
+ _scene->_kernelMessages.add(Common::Point(199, 41), 0xFDFC, 0, 0, 9999999, _game.getQuote(0x1E3));
+ _bartenderCurrentQuestion = 10;
+ _game._triggerSetupMode = SEQUENCE_TRIGGER_DAEMON;
+ _scene->_sequences.addTimer(1, 100);
+ _talkTimer = 120;
+ _conversationFl = true;
+ _bartenderDialogNode = 1;
+ if (_dialog2.read(0) <= 1)
+ _dialog1.write(0x214, false);
+
+ _dialog1.start();
+ } else {
+ _scene->_kernelMessages.add(Common::Point(177, 41), 0xFDFC, 0, 0, 9999999, _game.getQuote(0x1EF));
+ _game._triggerSetupMode = SEQUENCE_TRIGGER_DAEMON;
+ _scene->_sequences.addTimer(1, 100);
+ _talkTimer = 120;
+ _bartenderCurrentQuestion = 3;
+ _conversationFl = true;
+ _bartenderDialogNode = 1;
+ if (_dialog2.read(0) <= 1)
+ _dialog1.write(0x214, false);
+
+ _dialog1.start();
+ _game._player._stepEnabled = true;
+ }
+ } else {
+ if (_rexMode == 0) {
+ _scene->_kernelMessages.add(Common::Point(175, 13), 0xFDFC, 0, 0, 180, _game.getQuote(0x1F9));
+ _scene->_kernelMessages.add(Common::Point(184, 27), 0xFDFC, 0, 0, 180, _game.getQuote(0x1FA));
+ _scene->_kernelMessages.add(Common::Point(200, 41), 0xFDFC, 0, 0, 180, _game.getQuote(0x1FB));
+ _game._triggerSetupMode = SEQUENCE_TRIGGER_DAEMON;
+ _scene->_sequences.addTimer(1, 100);
+ _talkTimer = 180;
+ _rexMode = 1;
+ } else if (_rexMode == 1) {
+ _scene->_kernelMessages.add(Common::Point(205, 41), 0xFDFC, 0, 0, 120, _game.getQuote(0x1FC));
+ _game._player._stepEnabled = true;
+ _game._triggerSetupMode = SEQUENCE_TRIGGER_DAEMON;
+ _scene->_sequences.addTimer(1, 100);
+ _talkTimer = 120;
+ _rexMode = 3;
+ } else {
+ _game._player._stepEnabled = true;
+ }
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+ } else if (_action.isAction(VERB_LOOK, NOUN_DANCE_FLOOR))
+ _vm->_dialogs->show(40210);
+ else if (_action.isAction(VERB_LOOK, NOUN_TELEPORTER)) {
+ if (_globals[kSomeoneHasExploded])
+ _vm->_dialogs->show(40212);
+ else
+ _vm->_dialogs->show(40211);
+ } else if (_action.isAction(VERB_LOOK, NOUN_BAR))
+ _vm->_dialogs->show(40213);
+ else if (_action.isAction(VERB_LOOK, NOUN_BARTENDER))
+ _vm->_dialogs->show(40214);
+ else if (_action.isAction(VERB_LOOK, NOUN_WOMAN_IN_ALCOVE))
+ _vm->_dialogs->show(40215);
+ else if (_action.isAction(VERB_LOOK, NOUN_WOMAN_ON_BALCONY))
+ _vm->_dialogs->show(40216);
+ else if (_action.isAction(VERB_LOOK, NOUN_WOMAN_IN_CHAIR))
+ _vm->_dialogs->show(40217);
+ else if (_action.isAction(VERB_LOOK, NOUN_REPAIR_WOMAN))
+ _vm->_dialogs->show(40218);
+ else if (_action.isAction(VERB_LOOK, NOUN_CORRIDOR_TO_SOUTH))
+ _vm->_dialogs->show(40219);
+ else if (_action._lookFlag)
+ _vm->_dialogs->show(40220);
+ else if (_action.isAction(VERB_LOOK, NOUN_WOMEN))
+ _vm->_dialogs->show(40221);
+ else if (_action.isAction(VERB_PUSH, NOUN_REPAIR_WOMAN) || _action.isAction(VERB_PULL, NOUN_REPAIR_WOMAN))
+ _vm->_dialogs->show(40222);
+ else if (_action.isAction(VERB_TALKTO, NOUN_WOMEN))
+ _vm->_dialogs->show(40223);
+ else if (_action.isAction(VERB_TALKTO, NOUN_WOMAN_ON_BALCONY))
+ _vm->_dialogs->show(40224);
+ else if (_action.isAction(VERB_LOOK, NOUN_RAILING))
+ _vm->_dialogs->show(40225);
+ else if (_action.isAction(VERB_LOOK, NOUN_TABLE))
+ _vm->_dialogs->show(40226);
+ else if (_action.isAction(VERB_TAKE, NOUN_TABLE))
+ _vm->_dialogs->show(40227);
+ else if (_action.isAction(VERB_LOOK, NOUN_SIGN))
+ _vm->_dialogs->show(40228);
+ else if (_action.isAction(VERB_TAKE, NOUN_SIGN))
+ _vm->_dialogs->show(40229);
+ else if (_action.isAction(VERB_LOOK, NOUN_BAR_STOOL))
+ _vm->_dialogs->show(40230);
+ else if (_action.isAction(VERB_TAKE, NOUN_BAR_STOOL))
+ _vm->_dialogs->show(40231);
+ else if (_action.isAction(VERB_LOOK, NOUN_CACTUS))
+ _vm->_dialogs->show(40232);
+ else if (_action.isAction(VERB_TAKE, NOUN_CACTUS))
+ _vm->_dialogs->show(40233);
+ else if (_action.isAction(VERB_LOOK, NOUN_DISCO_BALL))
+ _vm->_dialogs->show(40234);
+ else if (_action.isAction(VERB_LOOK, NOUN_UPPER_DANCE_FLOOR))
+ _vm->_dialogs->show(40235);
+ else if (_action.isAction(VERB_LOOK, NOUN_TREE))
+ _vm->_dialogs->show(40236);
+ else if (_action.isAction(VERB_LOOK, NOUN_PLANT))
+ _vm->_dialogs->show(40237);
+ else if (_action.isAction(VERB_TAKE, NOUN_PLANT))
+ _vm->_dialogs->show(40238);
+ else if (_action.isAction(VERB_LOOK, NOUN_REPAIR_LIST) && _game._objects.isInRoom(OBJ_REPAIR_LIST))
+ _vm->_dialogs->show(40239);
+ else
+ return;
+
+ _action._inProgress = false;
+}
+
+/*------------------------------------------------------------------------*/
+
+void Scene405::setup() {
+ setPlayerSpritesPrefix();
+ setAAName();
+}
+
+void Scene405::enter() {
+ _globals._spriteIndexes[1] = _scene->_sprites.addSprites(formAnimName('x', 0));
+ _globals._spriteIndexes[2] = _scene->_sprites.addSprites(formAnimName('x', 1));
+ _globals._spriteIndexes[3] = _scene->_sprites.addSprites("*ROXCL_8");
+
+ if (_scene->_priorSceneId == 401) {
+ _game._player._playerPos = Common::Point(23, 123);
+ _game._player._facing = FACING_EAST;
+ } else if (_scene->_priorSceneId == 406) {
+ _game._player._playerPos = Common::Point(300, 128);
+ _game._player._facing = FACING_WEST;
+ } else if (_scene->_priorSceneId == 408) {
+ _game._player._playerPos = Common::Point(154, 109);
+ _game._player._facing = FACING_SOUTH;
+ } else if (_scene->_priorSceneId == 413) {
+ _game._player._playerPos = Common::Point(284, 109);
+ _game._player._facing = FACING_SOUTH;
+ } else if (_scene->_priorSceneId != -2) {
+ _game._player._playerPos = Common::Point(23, 123);
+ _game._player._facing = FACING_EAST;
+ }
+
+ if (_globals[kArmoryDoorOpen])
+ _globals._sequenceIndexes[2] = _scene->_sequences.startCycle(_globals._spriteIndexes[2], false, 1);
+ else
+ _globals._sequenceIndexes[1] = _scene->_sequences.startCycle(_globals._spriteIndexes[1], false, 1);
+
+ if (_scene->_roomChanged) {
+ _globals[kArmoryDoorOpen] = false;
+ _game._objects.addToInventory(OBJ_SECURITY_CARD);
+ }
+
+ _game.loadQuoteSet(0x24F, 0);
+ sceneEntrySound();
+}
+
+void Scene405::step() {
+ if (_game._trigger == 80) {
+ _scene->_sequences.addTimer(20, 81);
+ _game._player._priorTimer = _scene->_frameStartTime + _game._player._ticksAmount;
+ _game._player._visible = true;
+ }
+
+ if (_game._trigger == 81) {
+ _game._player._stepEnabled = true;
+ _vm->_dialogs->show(40525);
+ }
+
+ if (_game._trigger == 70) {
+ _game._player._priorTimer = _scene->_frameStartTime + _game._player._ticksAmount ;
+ _game._player._visible = true;
+ _globals._sequenceIndexes[1] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[1], false, 6, 1, 0, 0);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[1], SEQUENCE_TRIGGER_EXPIRE, 0, 71);
+ _vm->_sound->command(19);
+ }
+
+ if (_game._trigger == 71) {
+ _globals._sequenceIndexes[1] = _scene->_sequences.startCycle(_globals._spriteIndexes[1], false, 1);
+ _globals[kArmoryDoorOpen] = false;
+ _scene->_sequences.remove(_globals._sequenceIndexes[2]);
+ _game._player._stepEnabled = true;
+ }
+
+ if (_game._trigger == 75) {
+ _game._player._priorTimer = _scene->_frameStartTime + _game._player._ticksAmount ;
+ _game._player._visible = true;
+ _scene->_sequences.remove(_globals._sequenceIndexes[1]);
+ _globals._sequenceIndexes[1] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[1], false, 6, 1, 0, 0);
+ _globals[kArmoryDoorOpen] = true;
+ _game._player._stepEnabled = true;
+ _globals._sequenceIndexes[2] = _scene->_sequences.startCycle (_globals._spriteIndexes[2],
+ false, 1);
+ _vm->_sound->command(19);
+ }
+}
+
+void Scene405::preActions() {
+ if (_action.isAction(VERB_TAKE))
+ _game._player._needToWalk = false;
+
+ if (_action.isAction(VERB_WALK_DOWN, NOUN_CORRIDOR_TO_WEST))
+ _game._player._walkOffScreenSceneId = 401;
+
+ if (_action.isAction(VERB_WALK_DOWN, NOUN_CORRIDOR_TO_EAST))
+ _game._player._walkOffScreenSceneId = 406;
+
+ if (_action.isAction(VERB_CLOSE, NOUN_WIDE_DOOR) && _globals[kArmoryDoorOpen])
+ _game._player.walk(Common::Point(212, 113), FACING_NORTH);
+}
+
+void Scene405::actions() {
+ if (_action.isAction(VERB_WALK_THROUGH, NOUN_DOOR))
+ _scene->_nextSceneId = 413;
+ else if (_action.isAction(VERB_WALK_THROUGH, NOUN_WIDE_DOOR) && _globals[kArmoryDoorOpen])
+ _scene->_nextSceneId = 408;
+ else if (_action.isAction(VERB_WALK_THROUGH, NOUN_WIDE_DOOR) && !_globals[kArmoryDoorOpen])
+ _scene->_kernelMessages.add(Common::Point(0, 0), 0x1110, 34, 0, 60, _game.getQuote(0x24F));
+ else if (_action.isAction(VERB_PUT, NOUN_SECURITY_CARD, 0x251) && !_globals[kArmoryDoorOpen]) {
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _game._triggerSetupMode = SEQUENCE_TRIGGER_DAEMON;
+ _globals._sequenceIndexes[3] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[3], false, 7, 2, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[3], 1, 2);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[3], SEQUENCE_TRIGGER_EXPIRE, 0, 75);
+ Common::Point msgPos = Common::Point(_game._player._playerPos.x, _game._player._playerPos.y + 1);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[3], msgPos);
+ _scene->_sequences.setScale(_globals._sequenceIndexes[3], 87);
+ } else if ((_action.isAction(VERB_PUT, NOUN_SECURITY_CARD, 0x251) || _action.isAction(VERB_CLOSE, NOUN_WIDE_DOOR)) && _globals[kArmoryDoorOpen]) {
+ _game._triggerSetupMode = SEQUENCE_TRIGGER_DAEMON;
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._sequenceIndexes[3] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[3], false, 7, 2, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[3], 1, 2);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[3], SEQUENCE_TRIGGER_EXPIRE, 0, 70);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[3], _game._player._playerPos);
+ _scene->_sequences.setScale(_globals._sequenceIndexes[3], 87);
+ } else if (_action.isAction(VERB_PUT, NOUN_CARD_SLOT)) {
+ _game._triggerSetupMode = SEQUENCE_TRIGGER_DAEMON;
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._sequenceIndexes[3] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[3], false, 7, 2, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[3], 1, 2);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[3], SEQUENCE_TRIGGER_EXPIRE, 0, 80);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[3], _game._player._playerPos);
+ _scene->_sequences.setScale(_globals._sequenceIndexes[3], 87);
+ } else if (_action.isAction(VERB_LOOK, NOUN_CANNON_BALLS))
+ _vm->_dialogs->show(40510);
+ else if (_action.isAction(VERB_TAKE, NOUN_CANNON_BALLS))
+ _vm->_dialogs->show(40511);
+ else if (_action.isAction(VERB_LOOK, NOUN_WATER_FOUNTAIN))
+ _vm->_dialogs->show(40512);
+ else if (_action.isAction(VERB_LOOK, NOUN_BACKBOARD) || _action.isAction(VERB_LOOK, NOUN_HOOP))
+ _vm->_dialogs->show(40513);
+ else if (_action.isAction(VERB_LOOK, NOUN_LIGHT))
+ _vm->_dialogs->show(40514);
+ else if (_action.isAction(VERB_LOOK, NOUN_CARD_SLOT))
+ _vm->_dialogs->show(40515);
+ else if (_action.isAction(VERB_LOOK, NOUN_CORRIDOR_TO_EAST))
+ _vm->_dialogs->show(40516);
+ else if (_action.isAction(VERB_LOOK, NOUN_CORRIDOR_TO_WEST))
+ _vm->_dialogs->show(40517);
+ else if (_action.isAction(VERB_LOOK, NOUN_MONITOR))
+ _vm->_dialogs->show(40518);
+ else if (_action.isAction(VERB_LOOK, NOUN_CORRIDOR) || _action._lookFlag)
+ _vm->_dialogs->show(40519);
+ else if (_action.isAction(VERB_LOOK, NOUN_WIDE_DOOR)) {
+ if (_globals[kArmoryDoorOpen])
+ _vm->_dialogs->show(40521);
+ else
+ _vm->_dialogs->show(40520);
+ } else if (_action.isAction(VERB_LOOK, NOUN_DOOR))
+ _vm->_dialogs->show(40522);
+ else if (_action.isAction(VERB_LOOK, NOUN_COACH_LAMP))
+ _vm->_dialogs->show(40523);
+ else if (_action.isAction(VERB_LOOK, NOUN_SUPPORT))
+ _vm->_dialogs->show(40524);
+ else
+ return;
+
+ _action._inProgress = false;
+}
+
+/*------------------------------------------------------------------------*/
+
+Scene406::Scene406(MADSEngine *vm) : Scene4xx(vm) {
+ _hitStorageDoor = false;
+}
+
+void Scene406::synchronize(Common::Serializer &s) {
+ Scene4xx::synchronize(s);
+
+ s.syncAsByte(_hitStorageDoor);
+}
+
+void Scene406::setup() {
+ setPlayerSpritesPrefix();
+ setAAName();
+}
+
+void Scene406::enter() {
+ _game._player._visible = true;
+ if (_scene->_priorSceneId == 405) {
+ _game._player._playerPos = Common::Point(15, 129);
+ _game._player._facing = FACING_EAST;
+ } else if (_scene->_priorSceneId == 407) {
+ _game._player._playerPos = Common::Point(270, 127);
+ _game._player._facing = FACING_WEST;
+ } else if (_scene->_priorSceneId == 410) {
+ _game._player._playerPos = Common::Point(30, 108);
+ _game._player._facing = FACING_SOUTH;
+ } else if (_scene->_priorSceneId == 411) {
+ _game._player._playerPos = Common::Point(153, 108);
+ _game._player._facing = FACING_SOUTH;
+ } else if (_scene->_priorSceneId != -2) {
+ _game._player._playerPos = Common::Point(15, 129);
+ _game._player._facing = FACING_EAST;
+ }
+
+ _globals._spriteIndexes[2] = _scene->_sprites.addSprites("*ROXCL_8");
+ _globals._spriteIndexes[1] = _scene->_sprites.addSprites(formAnimName('x', 0));
+ _globals._spriteIndexes[3] = _scene->_sprites.addSprites(formAnimName('x', 1));
+
+ if (_scene->_roomChanged) {
+ _globals[kStorageDoorOpen] = false;
+ _game._objects.addToInventory(OBJ_SECURITY_CARD);
+ }
+
+ if (!_globals[kStorageDoorOpen])
+ _globals._sequenceIndexes[1] = _scene->_sequences.startCycle(_globals._spriteIndexes[1], false, 1);
+
+ if (_scene->_priorSceneId != 411)
+ _globals._sequenceIndexes[3] = _scene->_sequences.startCycle(_globals._spriteIndexes[3], false, 1);
+ else {
+ _game._player._stepEnabled = false;
+ _game._triggerSetupMode = SEQUENCE_TRIGGER_DAEMON;
+ _globals._sequenceIndexes[3] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[3], false, 3, 1, 0, 0);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[3], SEQUENCE_TRIGGER_EXPIRE, 0, 90);
+ _vm->_sound->command(19);
+ }
+
+ _game.loadQuoteSet(0x24F, 0);
+ _hitStorageDoor = false;
+ sceneEntrySound();
+}
+
+void Scene406::step() {
+ if (_game._trigger == 90) {
+ _game._player._stepEnabled = true;
+ _globals._sequenceIndexes[3] = _scene->_sequences.startCycle(_globals._spriteIndexes[3], false, 1);
+ }
+
+ if (_game._trigger == 80)
+ _scene->_nextSceneId = 411;
+
+ if (_game._trigger == 100) {
+ _vm->_dialogs->show(40622);
+ _hitStorageDoor = true;
+ }
+
+ if (_game._trigger == 110) {
+ _scene->_sequences.addTimer(20, 111);
+ _game._player._priorTimer = _scene->_frameStartTime + _game._player._ticksAmount;
+ _game._player._visible = true;
+ }
+
+ if (_game._trigger == 111) {
+ _game._player._stepEnabled = true;
+ _vm->_dialogs->show(40613);
+ }
+
+ if (_game._trigger == 70) {
+ _game._player._priorTimer = _scene->_frameStartTime + _game._player._ticksAmount;
+ _game._player._visible = true;
+ _globals._sequenceIndexes[1] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[1], false, 4, 1, 0, 0);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[1], SEQUENCE_TRIGGER_EXPIRE, 0, 71);
+ _vm->_sound->command(19);
+ }
+
+ if (_game._trigger == 71) {
+ _globals._sequenceIndexes[1] = _scene->_sequences.startCycle(_globals._spriteIndexes[1], false, 1);
+ _globals[kStorageDoorOpen] = false;
+ _game._player._stepEnabled = true;
+ }
+
+ if (_game._trigger == 75) {
+ _scene->_sequences.remove(_globals._sequenceIndexes[1]);
+ _globals._sequenceIndexes[1] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[1], false, 4, 1, 0, 0);
+ _globals[kStorageDoorOpen] = true;
+ _game._player._stepEnabled = true;
+ _game._player._priorTimer = _scene->_frameStartTime + _game._player._ticksAmount;
+ _game._player._visible = true;
+ _vm->_sound->command(19);
+ }
+}
+
+void Scene406::preActions() {
+ if (_action.isAction(VERB_WALK_DOWN, NOUN_CORRIDOR_TO_WEST))
+ _game._player._walkOffScreenSceneId = 405;
+
+ if (_action.isAction(VERB_WALK_DOWN, NOUN_CORRIDOR_TO_EAST))
+ _game._player._walkOffScreenSceneId = 407;
+
+ if (_action.isAction(VERB_TAKE))
+ _game._player._needToWalk = false;
+
+ if (_action.isAction(VERB_LOOK, NOUN_SIGN) || _action.isAction(VERB_LOOK, NOUN_TRASH))
+ _game._player._needToWalk = true;
+}
+
+void Scene406::actions() {
+ if (_action.isAction(VERB_WALK_THROUGH, NOUN_DOOR) && (_game._player._targetPos.x> 100)) {
+ _game._player._stepEnabled = false;
+ _game._triggerSetupMode = SEQUENCE_TRIGGER_DAEMON;
+ _scene->_sequences.remove(_globals._sequenceIndexes[3]);
+ _globals._sequenceIndexes[3] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[3], false, 3, 1, 0, 0);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[3], SEQUENCE_TRIGGER_EXPIRE, 0, 80);
+ _vm->_sound->command(19);
+ } else if (_action.isAction(VERB_WALK_THROUGH, NOUN_DOOR) && _globals[kStorageDoorOpen] && (_game._player._targetPos.x < 100))
+ _scene->_nextSceneId = 410;
+ else if (_action.isAction(VERB_WALK_THROUGH, NOUN_DOOR) && !_globals[kStorageDoorOpen] && (_game._player._targetPos.x < 100)) {
+ _scene->_kernelMessages.add(Common::Point(0, 0), 0x1110, 34, 0, 60, _game.getQuote(0x24F));
+ if (!_hitStorageDoor) {
+ _game._triggerSetupMode = SEQUENCE_TRIGGER_DAEMON;
+ _scene->_sequences.addTimer(80, 100);
+ }
+ } else if (_action.isAction(VERB_PUT, NOUN_SECURITY_CARD, 0x251) && !_globals[kStorageDoorOpen]) {
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _game._triggerSetupMode = SEQUENCE_TRIGGER_DAEMON;
+ _globals._sequenceIndexes[2] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[2], false, 7, 2, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[2], 1, 2);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[2], SEQUENCE_TRIGGER_EXPIRE, 0, 75);
+ Common::Point msgPos = Common::Point(_game._player._playerPos.x, _game._player._playerPos.y + 1);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[2], msgPos);
+ _scene->_sequences.setScale(_globals._sequenceIndexes[2], 87);
+ } else if (_action.isAction(VERB_PUT, NOUN_SECURITY_CARD, 0x251) && _globals[kStorageDoorOpen]) {
+ _game._triggerSetupMode = SEQUENCE_TRIGGER_DAEMON;
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._sequenceIndexes[2] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[2], false, 7, 2, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[2], 1, 2);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[2], SEQUENCE_TRIGGER_EXPIRE, 0, 70);
+ Common::Point msgPos = Common::Point(_game._player._playerPos.x, _game._player._playerPos.y + 1);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[2], msgPos);
+ _scene->_sequences.setScale(_globals._sequenceIndexes[2], 87);
+ } else if (_action.isAction(VERB_PUT, NOUN_CARD_SLOT)) {
+ _game._triggerSetupMode = SEQUENCE_TRIGGER_DAEMON;
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._sequenceIndexes[2] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[2], false, 7, 2, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[2], 1, 2);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[2], SEQUENCE_TRIGGER_EXPIRE, 0, 110);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[2], _game._player._playerPos);
+ _scene->_sequences.setScale(_globals._sequenceIndexes[2], 87);
+ } else if (_action.isAction(VERB_LOOK, NOUN_TRASH))
+ _vm->_dialogs->show(40610);
+ else if (_action.isAction(VERB_TAKE, NOUN_TRASH))
+ _vm->_dialogs->show(40611);
+ else if (_action.isAction(VERB_LOOK, NOUN_CARD_SLOT))
+ _vm->_dialogs->show(40612);
+ else if (_action.isAction(VERB_LOOK, NOUN_FIRE_EXTINGUISHER))
+ _vm->_dialogs->show(40614);
+ else if (_action.isAction(VERB_TAKE, NOUN_FIRE_EXTINGUISHER))
+ _vm->_dialogs->show(40615);
+ else if (_action.isAction(VERB_LOOK, NOUN_CORRIDOR_TO_EAST))
+ _vm->_dialogs->show(40616);
+ else if (_action.isAction(VERB_LOOK, NOUN_CORRIDOR_TO_WEST))
+ _vm->_dialogs->show(40617);
+ else if (_action.isAction(VERB_LOOK, NOUN_CORRIDOR) || _action._lookFlag)
+ _vm->_dialogs->show(40618);
+ else if (_action.isAction(VERB_LOOK, NOUN_WALL))
+ _vm->_dialogs->show(40619);
+ else if (_action.isAction(VERB_LOOK, NOUN_DOOR)) {
+ if (_globals[kStorageDoorOpen])
+ _vm->_dialogs->show(40621);
+ else
+ _vm->_dialogs->show(40620);
+ } else if (_action.isAction(VERB_LOOK, NOUN_MONITOR))
+ _vm->_dialogs->show(40623);
+ else if (_action.isAction(VERB_LOOK, NOUN_SIGNPOST))
+ _vm->_dialogs->show(40624);
+ else if (_action.isAction(VERB_TAKE, NOUN_SIGNPOST))
+ _vm->_dialogs->show(40625);
+ else if (_action.isAction(VERB_LOOK, NOUN_BOULDER))
+ _vm->_dialogs->show(40626);
+ else if (_action.isAction(VERB_TAKE, NOUN_BOULDER))
+ _vm->_dialogs->show(40627);
+ else if (_action.isAction(VERB_LOOK, NOUN_SIGN))
+ _vm->_dialogs->show(40628);
+ else if (_action.isAction(VERB_TAKE, NOUN_SIGN))
+ _vm->_dialogs->show(40629);
+ else
+ return;
+
+ _action._inProgress = false;
+}
+
+/*------------------------------------------------------------------------*/
+
+Scene407::Scene407(MADSEngine *vm) : Scene4xx(vm), _destPos(0, 0) {
+ _fromNorth = false;
+}
+
+void Scene407::synchronize(Common::Serializer &s) {
+ Scene4xx::synchronize(s);
+
+ s.syncAsByte(_fromNorth);
+ s.syncAsSint16LE(_destPos.x);
+ s.syncAsSint16LE(_destPos.y);
+}
+
+void Scene407::setup() {
+ setPlayerSpritesPrefix();
+ setAAName();
+}
+
+void Scene407::enter() {
+ if (_scene->_priorSceneId != -2)
+ _fromNorth = false;
+
+ if (_scene->_priorSceneId == 318) {
+ _game._player._playerPos = Common::Point(172, 92);
+ _game._player._facing = FACING_SOUTH;
+ _fromNorth = true;
+ } else if (_scene->_priorSceneId != -2) {
+ _game._player._playerPos = Common::Point(172, 132);
+ _game._player._facing = FACING_NORTH;
+ }
+
+ _game.loadQuoteSet(0x250, 0);
+ sceneEntrySound();
+}
+
+void Scene407::step() {
+ if (_game._trigger == 70) {
+ _scene->_nextSceneId = 318;
+ _scene->_reloadSceneFlag = true;
+ }
+
+ if (_game._trigger == 80) {
+ _game._player._priorTimer = _scene->_frameStartTime - _game._player._ticksAmount;
+ _game._player._stepEnabled = true;
+ _game._player._visible = true;
+ _fromNorth = false;
+ _game._player.walk(Common::Point(173, 104), FACING_SOUTH);
+ }
+}
+
+void Scene407::preActions() {
+ if (_action.isAction(VERB_TAKE))
+ _game._player._needToWalk = false;
+
+ if (_action.isAction(VERB_LOOK, NOUN_DOOR))
+ _game._player._needToWalk = true;
+
+ if (_action.isAction(VERB_WALK_DOWN, NOUN_CORRIDOR_TO_NORTH)) {
+ _game._player.walk(Common::Point(172, 91), FACING_NORTH);
+ _fromNorth = false;
+ }
+
+ if (_game._player._needToWalk && _fromNorth) {
+ if (_globals[kSexOfRex] == REX_MALE)
+ _destPos = Common::Point(171, 95);
+ else
+ _destPos = Common::Point(173, 96);
+
+ _game._player.walk(_destPos, FACING_SOUTH);
+ }
+}
+
+void Scene407::actions() {
+ if ((_game._player._playerPos == _destPos) && _fromNorth) {
+ if (_globals[kSexOfRex] == REX_MALE) {
+ _game._triggerSetupMode = SEQUENCE_TRIGGER_DAEMON;
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _vm->_sound->command(21);
+ _scene->loadAnimation(formAnimName('s', 1), 70);
+ _globals[kHasBeenScanned] = true;
+ _scene->_kernelMessages.add(Common::Point(0, 0), 0x1110, 34, 0, 60, _game.getQuote(60));
+ _vm->_sound->command(22);
+ }
+
+ if (_globals[kSexOfRex] == REX_FEMALE) {
+ _game._triggerSetupMode = SEQUENCE_TRIGGER_DAEMON;
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _vm->_sound->command(21);
+ _scene->loadAnimation(formAnimName('s', 2), 80);
+ _vm->_sound->command(23);
+ _globals[kHasBeenScanned] = true;
+ }
+ }
+
+ if (_action.isAction(VERB_WALK_DOWN, NOUN_CORRIDOR_TO_SOUTH) && !_fromNorth)
+ _scene->_nextSceneId = 406;
+ else if (_action.isAction(VERB_WALK_DOWN, NOUN_CORRIDOR_TO_NORTH))
+ _scene->_nextSceneId = 318;
+ else if (_action.isAction(VERB_LOOK, NOUN_SCANNER)) {
+ if (_globals[kHasBeenScanned])
+ _vm->_dialogs->show(40711);
+ else
+ _vm->_dialogs->show(40710);
+ } else if (_action.isAction(VERB_LOOK, NOUN_DOOR))
+ _vm->_dialogs->show(40712);
+ else if (_action.isAction(VERB_LOOK, NOUN_CORRIDOR_TO_SOUTH))
+ _vm->_dialogs->show(40713);
+ else if (_action.isAction(VERB_LOOK, NOUN_CORRIDOR_TO_NORTH))
+ _vm->_dialogs->show(40714);
+ else if (_action._lookFlag)
+ _vm->_dialogs->show(40715);
+ else
+ return;
+
+ _action._inProgress = false;
+}
+
+/*------------------------------------------------------------------------*/
+
+void Scene408::setup() {
+ setPlayerSpritesPrefix();
+ setAAName();
+ _scene->addActiveVocab(NOUN_TARGET_MODULE);
+ _scene->addActiveVocab(VERB_WALKTO);
+}
+
+void Scene408::enter() {
+ _game._player._playerPos = Common::Point(137, 150);
+ _game._player._facing = FACING_NORTH;
+
+ _globals._spriteIndexes[1] = _scene->_sprites.addSprites("*ROXRC_7");
+ _globals._spriteIndexes[2] = _scene->_sprites.addSprites(formAnimName('m', -1));
+
+ if (_game._objects.isInRoom(OBJ_TARGET_MODULE)) {
+ _globals._sequenceIndexes[2] = _scene->_sequences.startCycle(_globals._spriteIndexes[2], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 3);
+ int idx = _scene->_dynamicHotspots.add(NOUN_TARGET_MODULE, 0xD, _globals._sequenceIndexes[2], Common::Rect(0, 0, 0, 0));
+ _scene->_dynamicHotspots.setPosition(idx, Common::Point(283, 128), FACING_NORTHEAST);
+ }
+ sceneEntrySound();
+}
+
+void Scene408::preActions() {
+ if ((_action.isAction(VERB_TAKE) && !_action.isAction(0x167)) || _action.isAction(VERB_PULL, NOUN_PIN) || _action.isAction(VERB_OPEN, NOUN_CARTON))
+ _game._player._needToWalk = false;
+
+ if ((_action.isAction(VERB_LOOK, NOUN_TARGET_MODULE) && _game._objects.isInRoom(OBJ_TARGET_MODULE)) || _action.isAction(VERB_LOOK, NOUN_CHEST))
+ _game._player._needToWalk = true;
+}
+
+void Scene408::actions() {
+ if (_action.isAction(VERB_WALK_INTO, NOUN_CORRIDOR_TO_SOUTH)) {
+ _scene->_nextSceneId = 405;
+ _vm->_sound->command(58);
+ } else if (_action.isAction(VERB_TAKE, NOUN_TARGET_MODULE) && (_game._objects.isInRoom(OBJ_TARGET_MODULE) || _game._trigger)) {
+ switch (_game._trigger) {
+ case (0):
+ _vm->_sound->command(57);
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._sequenceIndexes[1] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[1], true, 7, 2, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[1], 1, 2);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[1]);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[1], SEQUENCE_TRIGGER_SPRITE, 2, 1);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[1], SEQUENCE_TRIGGER_EXPIRE, 0, 2);
+ break;
+
+ case 1:
+ _scene->_sequences.remove(_globals._sequenceIndexes[2]);
+ _game._objects.addToInventory(OBJ_TARGET_MODULE);
+ _vm->_dialogs->showItem(OBJ_TARGET_MODULE, 40847);
+ break;
+
+ case 2:
+ _game._player._priorTimer = _game._player._ticksAmount + _scene->_frameStartTime;
+ _game._player._visible = true;
+ _scene->_sequences.addTimer(20, 3);
+ break;
+
+ case 3:
+ _game._player._stepEnabled = true;
+ break;
+
+ default:
+ break;
+ }
+ } else if (_action.isAction(VERB_LOOK, NOUN_ARMORED_VEHICLE))
+ _vm->_dialogs->show(40810);
+ else if (_action.isAction(VERB_TAKE, NOUN_ARMORED_VEHICLE) || _action.isAction(VERB_TAKE, NOUN_ANVIL) || _action.isAction(VERB_TAKE, NOUN_TWO_TON_WEIGHT))
+ _vm->_dialogs->show(40811);
+ else if (_action.isAction(VERB_LOOK, NOUN_MISSILE))
+ _vm->_dialogs->show(40812);
+ else if (_action.isAction(VERB_TAKE, NOUN_MISSILE))
+ _vm->_dialogs->show(40813);
+ else if (_action.isAction(VERB_LOOK, NOUN_GRENADE))
+ _vm->_dialogs->show(40814);
+ else if (_action.isAction(VERB_TAKE, NOUN_GRENADE))
+ _vm->_dialogs->show(40815);
+ else if (_action.isAction(VERB_TAKE, NOUN_PIN) || _action.isAction(VERB_PULL, NOUN_PIN))
+ _vm->_dialogs->show(40816);
+ else if (_action.isAction(VERB_LOOK, NOUN_BLIMP))
+ _vm->_dialogs->show(40817);
+ else if (_action.isAction(VERB_TAKE, NOUN_BLIMP))
+ _vm->_dialogs->show(40818);
+ else if (_action.isAction(VERB_LOOK, NOUN_AMMUNITION))
+ _vm->_dialogs->show(40819);
+ else if (_action.isAction(VERB_TAKE, NOUN_AMMUNITION))
+ _vm->_dialogs->show(40820);
+ else if (_action.isAction(VERB_LOOK, NOUN_CATAPULT))
+ _vm->_dialogs->show(40821);
+ else if (_action.isAction(VERB_TAKE, NOUN_CATAPULT))
+ _vm->_dialogs->show(40822);
+ else if (_action.isAction(VERB_LOOK, NOUN_CHEST)) {
+ if (_game._objects.isInRoom(OBJ_TARGET_MODULE))
+ _vm->_dialogs->show(40823);
+ else
+ _vm->_dialogs->show(40824);
+ } else if (_action.isAction(VERB_TAKE, NOUN_CHEST))
+ _vm->_dialogs->show(40825);
+ else if (_action.isAction(VERB_LOOK, NOUN_SUIT_OF_ARMOR))
+ _vm->_dialogs->show(40826);
+ else if (_action.isAction(VERB_TAKE, NOUN_SUIT_OF_ARMOR))
+ _vm->_dialogs->show(40827);
+ else if (_action.isAction(VERB_LOOK, NOUN_ESCAPE_HATCH))
+ _vm->_dialogs->show(40828);
+ else if (_action.isAction(VERB_OPEN, NOUN_ESCAPE_HATCH) || _action.isAction(VERB_PULL, NOUN_ESCAPE_HATCH))
+ _vm->_dialogs->show(40829);
+ else if (_action.isAction(VERB_LOOK, NOUN_BARRELS))
+ _vm->_dialogs->show(40830);
+ else if (_action.isAction(VERB_TAKE, NOUN_BARRELS))
+ _vm->_dialogs->show(40831);
+ else if (_action.isAction(VERB_LOOK, NOUN_INFLATABLE_RAFT))
+ _vm->_dialogs->show(40832);
+ else if (_action.isAction(VERB_TAKE, NOUN_INFLATABLE_RAFT))
+ _vm->_dialogs->show(40833);
+ else if (_action.isAction(VERB_LOOK, NOUN_TOMATO))
+ _vm->_dialogs->show(40834);
+ else if (_action.isAction(VERB_TAKE, NOUN_TOMATO))
+ _vm->_dialogs->show(40835);
+ else if (_action.isAction(VERB_LOOK, NOUN_ANVIL))
+ _vm->_dialogs->show(40836);
+ else if (_action.isAction(VERB_LOOK, NOUN_TWO_TON_WEIGHT))
+ _vm->_dialogs->show(40837);
+ else if (_action.isAction(VERB_LOOK, NOUN_POWDER_CONTAINER))
+ _vm->_dialogs->show(40838);
+ else if (_action.isAction(VERB_LOOK, NOUN_POWDER_PUFF))
+ _vm->_dialogs->show(40839);
+ else if (_action.isAction(VERB_TAKE, NOUN_POWDER_PUFF))
+ _vm->_dialogs->show(40840);
+ else if (_action.isAction(VERB_LOOK, NOUN_CARTON))
+ _vm->_dialogs->show(40841);
+ else if (_action.isAction(VERB_TAKE, NOUN_CARTON))
+ _vm->_dialogs->show(40842);
+ else if (_action.isAction(VERB_OPEN, NOUN_CARTON))
+ _vm->_dialogs->show(40843);
+ else if (_action.isAction(VERB_LOOK, NOUN_CORRIDOR_TO_SOUTH))
+ _vm->_dialogs->show(40844);
+ else if (_action._lookFlag)
+ _vm->_dialogs->show(40845);
+ else if (_action.isAction(VERB_LOOK, NOUN_TARGET_MODULE) && _game._objects.isInRoom(OBJ_TARGET_MODULE))
+ _vm->_dialogs->show(40846);
+ else if (_action.isAction(VERB_LOOK, NOUN_LOADING_RAMP))
+ _vm->_dialogs->show(40848);
+ else if (_action.isAction(VERB_OPEN, NOUN_CHEST))
+ _vm->_dialogs->show(40849);
+ else
+ return;
+
+ _action._inProgress = false;
+}
+
+/*------------------------------------------------------------------------*/
+
+void Scene409::setup() {
+ _game._player._spritesPrefix = "";
+
+ // The original is calling Scene4xx::setAAName()
+ _game._aaName = Resources::formatAAName(4);
+}
+
+void Scene409::enter() {
+ _handSpriteId = _scene->_sprites.addSprites("*ROXHAND");
+ teleporterEnter();
+
+ // The original is calling Scene4xx::sceneEntrySound()
+ if (!_vm->_musicFlag)
+ _vm->_sound->command(2);
+ else
+ _vm->_sound->command(10);
+}
+
+void Scene409::step() {
+ teleporterStep();
+}
+
+void Scene409::actions() {
+ if (teleporterActions()) {
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_LOOK, NOUN_VIEWPORT))
+ _vm->_dialogs->show(40910);
+ else if (_action.isAction(VERB_PEER_THROUGH, NOUN_VIEWPORT))
+ _vm->_dialogs->show(40910);
+ else if (_action.isAction(VERB_LOOK, NOUN_KEYPAD))
+ _vm->_dialogs->show(40911);
+ else if (_action.isAction(VERB_INSPECT, NOUN_KEYPAD))
+ _vm->_dialogs->show(40911);
+ else if (_action.isAction(VERB_LOOK, NOUN_DISPLAY))
+ _vm->_dialogs->show(40912);
+ else if (_action.isAction(VERB_LOOK, NOUN_1_KEY) || _action.isAction(VERB_LOOK, NOUN_2_KEY)
+ || _action.isAction(VERB_LOOK, NOUN_3_KEY) || _action.isAction(VERB_LOOK, NOUN_4_KEY)
+ || _action.isAction(VERB_LOOK, NOUN_5_KEY) || _action.isAction(VERB_LOOK, NOUN_6_KEY)
+ || _action.isAction(VERB_LOOK, NOUN_7_KEY) || _action.isAction(VERB_LOOK, NOUN_8_KEY)
+ || _action.isAction(VERB_LOOK, NOUN_9_KEY) || _action.isAction(VERB_LOOK, NOUN_0_KEY)
+ || _action.isAction(VERB_LOOK, NOUN_SMILE_KEY) || _action.isAction(VERB_LOOK, NOUN_FROWN_KEY))
+ _vm->_dialogs->show(40913);
+ else if (_action.isAction(VERB_LOOK, NOUN_DEVICE))
+ _vm->_dialogs->show(40914);
+ else if (_action._lookFlag)
+ _vm->_dialogs->show(40914);
+ else
+ return;
+
+ _action._inProgress = false;
+}
+
+/*------------------------------------------------------------------------*/
+
+void Scene410::setup() {
+ setPlayerSpritesPrefix();
+ setAAName();
+}
+
+void Scene410::enter() {
+ _globals._spriteIndexes[1] = _scene->_sprites.addSprites(formAnimName('y', -1));
+ _globals._spriteIndexes[2] = _scene->_sprites.addSprites("*ROXRC_7");
+
+ if (_game._objects.isInRoom(OBJ_CHARGE_CASES))
+ _globals._sequenceIndexes[1] = _scene->_sequences.startCycle(_globals._spriteIndexes[1], false, 1);
+ else
+ _scene->_hotspots.activate(NOUN_CHARGE_CASES, false);
+
+ if (_scene->_priorSceneId != -2) {
+ _game._player._playerPos = Common::Point(155, 150);
+ _game._player._facing = FACING_NORTH;
+ }
+
+ sceneEntrySound();
+
+ _scene->loadAnimation(Resources::formatName(410, 'r', -1, EXT_AA, ""));
+ _scene->_activeAnimation->_resetFlag = true;
+}
+
+void Scene410::step() {
+ if (_scene->_activeAnimation->getCurrentFrame() == 1) {
+ if (_vm->getRandomNumber(1, 30) == 1)
+ _scene->_activeAnimation->setCurrentFrame(2);
+ else
+ _scene->_activeAnimation->setCurrentFrame(0);
+ }
+
+ if (_scene->_activeAnimation->getCurrentFrame() == 9) {
+ if (_vm->getRandomNumber(1, 30) == 1)
+ _scene->_activeAnimation->setCurrentFrame(10);
+ else
+ _scene->_activeAnimation->setCurrentFrame(8);
+ }
+
+ if (_scene->_activeAnimation->getCurrentFrame() == 5) {
+ if (_vm->getRandomNumber(1, 30) == 1)
+ _scene->_activeAnimation->setCurrentFrame(6);
+ else
+ _scene->_activeAnimation->setCurrentFrame(4);
+ }
+
+ if (_scene->_activeAnimation->getCurrentFrame() == 3) {
+ if (_vm->getRandomNumber(1, 2) == 1)
+ _scene->_activeAnimation->setCurrentFrame(4);
+ else // == 2
+ _scene->_activeAnimation->setCurrentFrame(8);
+ }
+}
+
+void Scene410::preActions() {
+ if (_action.isAction(VERB_TAKE) && !_action.isAction(0x48))
+ _game._player._needToWalk = false;
+
+ if (_action.isAction(VERB_LOOK, NOUN_CHARGE_CASES) && _game._objects.isInRoom(OBJ_CHARGE_CASES))
+ _game._player._needToWalk = true;
+
+ if (_action.isAction(VERB_OPEN, NOUN_SACKS) || _action.isAction(VERB_OPEN, NOUN_SACK))
+ _game._player._needToWalk = false;
+
+ if (_action.isAction(VERB_LOOK, NOUN_CAN))
+ _game._player._needToWalk = true;
+}
+
+void Scene410::actions() {
+ if (_action.isAction(VERB_WALK_INTO, NOUN_CORRIDOR_TO_SOUTH))
+ _scene->_nextSceneId = 406;
+ else if (_action.isAction(VERB_TAKE, NOUN_CHARGE_CASES) && (_game._objects.isInRoom(OBJ_CHARGE_CASES) || _game._trigger)) {
+ switch (_game._trigger) {
+ case (0):
+ _vm->_sound->command(57);
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._sequenceIndexes[2] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[2], false, 7, 2, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[2], 1, 3);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[2]);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[2], SEQUENCE_TRIGGER_SPRITE, 3, 1);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[2], SEQUENCE_TRIGGER_EXPIRE, 0, 2);
+ break;
+
+ case 1:
+ _scene->_sequences.remove(_globals._sequenceIndexes[1]);
+ _scene->_hotspots.activate(NOUN_CHARGE_CASES, false);
+ _game._objects.addToInventory(OBJ_CHARGE_CASES);
+ _vm->_dialogs->showItem(OBJ_CHARGE_CASES, 41032);
+ break;
+
+ case 2:
+ _game._player._priorTimer = _game._player._ticksAmount + _scene->_frameStartTime;
+ _game._player._visible = true;
+ _scene->_sequences.addTimer(20, 3);
+ break;
+
+ case 3:
+ _game._player._stepEnabled = true;
+ break;
+
+ default:
+ break;
+ }
+ } else if (_action.isAction(VERB_LOOK, NOUN_BARREL))
+ _vm->_dialogs->show(41010);
+ else if (_action.isAction(VERB_TAKE, NOUN_BARREL))
+ _vm->_dialogs->show(41011);
+ else if (_action.isAction(VERB_OPEN, NOUN_BARREL))
+ _vm->_dialogs->show(41012);
+ else if (_action.isAction(VERB_LOOK, NOUN_RUG))
+ _vm->_dialogs->show(41013);
+ else if (_action.isAction(VERB_TAKE, NOUN_RUG))
+ _vm->_dialogs->show(41014);
+ else if (_action.isAction(VERB_LOOK, NOUN_CARTON) || _action.isAction(VERB_OPEN, NOUN_CARTON)) {
+ if (_game._objects.isInRoom(OBJ_CHARGE_CASES))
+ _vm->_dialogs->show(41015);
+ else
+ _vm->_dialogs->show(41016);
+ } else if (_action.isAction(VERB_LOOK, NOUN_FLOUR))
+ _vm->_dialogs->show(41017);
+ else if (_action.isAction(VERB_TAKE, NOUN_FLOUR))
+ _vm->_dialogs->show(41018);
+ else if (_action.isAction(VERB_LOOK, NOUN_SACKS))
+ _vm->_dialogs->show(41019);
+ else if (_action.isAction(VERB_LOOK, NOUN_SACK))
+ _vm->_dialogs->show(41019);
+ else if (_action.isAction(VERB_OPEN, NOUN_SACKS))
+ _vm->_dialogs->show(41020);
+ else if (_action.isAction(VERB_OPEN, NOUN_SACK))
+ _vm->_dialogs->show(41020);
+ else if (_action.isAction(VERB_LOOK, NOUN_BUCKET_OF_TAR))
+ _vm->_dialogs->show(41021);
+ else if (_action.isAction(VERB_TAKE, NOUN_BUCKET_OF_TAR))
+ _vm->_dialogs->show(41022);
+ else if (_action.isAction(VERB_LOOK, NOUN_CAN))
+ _vm->_dialogs->show(41023);
+ else if (_action.isAction(VERB_TAKE, NOUN_CAN))
+ _vm->_dialogs->show(41024);
+ else if (_action.isAction(VERB_LOOK, NOUN_CHARGE_CASES) && _game._objects.isInRoom(OBJ_CHARGE_CASES))
+ _vm->_dialogs->show(41025);
+ else if (_action.isAction(VERB_LOOK, NOUN_FENCE))
+ _vm->_dialogs->show(41027);
+ else if (_action.isAction(VERB_LOOK, NOUN_SHELVES))
+ _vm->_dialogs->show(41028);
+ else if (_action.isAction(VERB_LOOK, NOUN_RAT))
+ _vm->_dialogs->show(41029);
+ else if (_action.isAction(VERB_TAKE, NOUN_RAT))
+ _vm->_dialogs->show(41030);
+ else if (_action.isAction(VERB_THROW, NOUN_RAT))
+ _vm->_dialogs->show(41031);
+ else if (_action._lookFlag)
+ _vm->_dialogs->show(41033);
+ else
+ return;
+
+ _action._inProgress = false;
+}
+
+/*------------------------------------------------------------------------*/
+
+Scene411::Scene411(MADSEngine *vm) : Scene4xx(vm) {
+ _curAnimationFrame = -1;
+ _newIngredient = -1;
+ _newQuantity = -1;
+ _resetFrame = -1;
+ _badThreshold = -1;
+
+ _killRox = false;
+ _makeMushroomCloud = false;
+}
+
+void Scene411::synchronize(Common::Serializer &s) {
+ Scene4xx::synchronize(s);
+
+ s.syncAsSint32LE(_curAnimationFrame);
+ s.syncAsSint32LE(_newIngredient);
+ s.syncAsSint32LE(_newQuantity);
+ s.syncAsSint32LE(_resetFrame);
+ s.syncAsSint32LE(_badThreshold);
+
+ s.syncAsByte(_killRox);
+ s.syncAsByte(_makeMushroomCloud);
+}
+
+bool Scene411::addIngredient() {
+ bool retVal = false;
+
+ switch (_newIngredient) {
+ case OBJ_LECITHIN:
+ if (_globals[kIngredientList + _globals[kNextIngredient]] == 1)
+ retVal = true;
+
+ _badThreshold = 1;
+ break;
+
+ case OBJ_ALIEN_LIQUOR:
+ if (_globals[kIngredientList + _globals[kNextIngredient]] == 0)
+ retVal = true;
+
+ _badThreshold = 0;
+ break;
+
+ case OBJ_FORMALDEHYDE:
+ if (_globals[kIngredientList + _globals[kNextIngredient]] == 3)
+ retVal = true;
+
+ _badThreshold = 3;
+ break;
+
+ case OBJ_PETROX:
+ if (_globals[kIngredientList + _globals[kNextIngredient]] == 2)
+ retVal = true;
+
+ _badThreshold = 2;
+ break;
+
+ default:
+ break;
+ }
+
+ if (!retVal && (_globals[kNextIngredient] == 0))
+ _globals[kBadFirstIngredient] = _badThreshold;
+
+ if (_globals[kNextIngredient] == 0)
+ retVal = true;
+
+ return(retVal);
+}
+
+bool Scene411::addQuantity() {
+ bool retVal = false;
+
+ if (_globals[kIngredientQuantity + _globals[kNextIngredient]] == _newQuantity)
+ retVal = true;
+
+ if (!retVal && (_globals[kNextIngredient] == 0))
+ _globals[kBadFirstIngredient] = _badThreshold;
+
+ if (_globals[kNextIngredient] == 0)
+ retVal = true;
+
+ return(retVal);
+}
+
+int Scene411::computeQuoteAndQuantity() {
+ int quoteId;
+ int quantity;
+
+ switch (_action._activeAction._verbId) {
+ case 0x252:
+ quoteId = 0x26F;
+ quantity = 0;
+ break;
+
+ case 0x253:
+ quoteId = 0x271;
+ quantity = 0;
+ break;
+
+ case 0x254:
+ quoteId = 0x270;
+ quantity = 0;
+ break;
+
+ case 0x255:
+ quoteId = 0x272;
+ quantity = 0;
+ break;
+
+ case 0x256:
+ quoteId = 0x267;
+ quantity = 2;
+ break;
+
+ case 0x257:
+ quoteId = 0x269;
+ quantity = 2;
+ break;
+
+ case 0x258:
+ quoteId = 0x268;
+ quantity = 2;
+ break;
+
+ case 0x259:
+ quoteId = 0x26A;
+ quantity = 2;
+ break;
+
+ case 0x25A:
+ quoteId = 0x26B;
+ quantity = 3;
+ break;
+
+ case 0x25B:
+ quoteId = 0x26D;
+ quantity = 3;
+ break;
+
+ case 0x25C:
+ quoteId = 0x26C;
+ quantity = 3;
+ break;
+
+ case 0x25D:
+ quoteId = 0x26E;
+ quantity = 3;
+ break;
+
+ case 0x25E:
+ quoteId = 0x263;
+ quantity = 1;
+ break;
+
+ case 0x25F:
+ quoteId = 0x265;
+ quantity = 1;
+ break;
+
+ case 0x260:
+ quoteId = 0x264;
+ quantity = 1;
+ break;
+
+ case 0x261:
+ quoteId = 0x266;
+ quantity = 1;
+ break;
+
+ default:
+ quoteId = 0;
+ quantity = 0;
+ break;
+ }
+
+ _scene->_kernelMessages.add(Common::Point(202, 82), 0x1110, 32, 0, 120, _game.getQuote(quoteId));
+ return quantity;
+}
+
+void Scene411::handleKettleAction() {
+ switch (_globals[kNextIngredient]) {
+ case (1):
+ _globals._sequenceIndexes[4] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[4],
+ false, 15, 0, 0, 0);
+ break;
+
+ case (2):
+ _scene->_sequences.remove(_globals._sequenceIndexes[4]);
+ _globals._sequenceIndexes[4] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[4],
+ false, 6, 0, 0, 0);
+ break;
+
+ case (3):
+ _makeMushroomCloud = true;
+ break;
+
+ default:
+ break;
+ }
+}
+
+void Scene411::handleDialog() {
+ if ((_action._activeAction._verbId != 0x262) && (_game._trigger == 0)) {
+ if (_game._objects.isInInventory(_newIngredient)) {
+ switch (_newIngredient) {
+ case OBJ_FORMALDEHYDE:
+ _resetFrame = 17;
+ break;
+
+ case OBJ_PETROX:
+ _resetFrame = 55;
+ break;
+
+ case OBJ_LECITHIN:
+ _resetFrame = 36;
+ break;
+
+ default:
+ _resetFrame = 112;
+ break;
+ }
+
+ _game._player._priorTimer = _scene->_frameStartTime + _game._player._ticksAmount;
+ _game._player._visible = false;
+ _game._player._stepEnabled = false;
+ _scene->_activeAnimation->setCurrentFrame(_resetFrame);
+ }
+ _scene->_kernelMessages.reset();
+ _newQuantity = computeQuoteAndQuantity ();
+
+ if ((_globals[kNextIngredient] == 1) && (_globals[kBadFirstIngredient] > -1))
+ _killRox = true;
+ else if (addIngredient() && addQuantity()) {
+ handleKettleAction();
+ _globals[kNextIngredient]++;
+ } else
+ _killRox = true;
+
+ _scene->_userInterface.setup(kInputBuildingSentences);
+ } else if (_action._activeAction._verbId == 0x262)
+ _scene->_userInterface.setup(kInputBuildingSentences);
+}
+
+void Scene411::giveToRex(int object) {
+ switch (object) {
+ case (0):
+ _game._objects.addToInventory(OBJ_ALIEN_LIQUOR);
+ break;
+
+ case (1):
+ _game._objects.addToInventory(OBJ_LECITHIN);
+ break;
+
+ case (2):
+ _game._objects.addToInventory(OBJ_PETROX);
+ break;
+
+ case (3):
+ _game._objects.addToInventory(OBJ_FORMALDEHYDE);
+ break;
+
+ default:
+ break;
+ }
+}
+
+void Scene411::setup() {
+ setPlayerSpritesPrefix();
+ setAAName();
+ _scene->addActiveVocab(VERB_WALKTO);
+ _scene->addActiveVocab(NOUN_ALIEN_LIQUOR);
+ _scene->addActiveVocab(NOUN_FORMALDEHYDE);
+ _scene->addActiveVocab(NOUN_PETROX);
+ _scene->addActiveVocab(NOUN_LECITHIN);
+}
+
+void Scene411::enter() {
+ if (_scene->_priorSceneId == 411) {
+ if ((_globals[kNextIngredient] == 1) && (_globals[kBadFirstIngredient] > -1))
+ giveToRex(_globals[kBadFirstIngredient]);
+ else if (_globals[kNextIngredient] > 0) {
+ for (int i = 0; i < _globals[kNextIngredient]; i ++)
+ giveToRex(_globals[kIngredientList + i]);
+ }
+ _globals[kNextIngredient] = 0;
+ _globals[kBadFirstIngredient] = -1;
+ }
+
+ _globals._spriteIndexes[1] = _scene->_sprites.addSprites(formAnimName('x', 0));
+ _globals._spriteIndexes[2] = _scene->_sprites.addSprites(formAnimName('x', 1));
+ _globals._spriteIndexes[4] = _scene->_sprites.addSprites(formAnimName('c', 0));
+ _globals._spriteIndexes[5] = _scene->_sprites.addSprites(formAnimName('f', 0));
+ _globals._spriteIndexes[6] = _scene->_sprites.addSprites(formAnimName('f', 1));
+ _globals._spriteIndexes[7] = _scene->_sprites.addSprites(formAnimName('f', 2));
+ _globals._spriteIndexes[9] = _scene->_sprites.addSprites(formAnimName('c', 1));
+ _globals._spriteIndexes[10] = _scene->_sprites.addSprites(formAnimName('a', 6));
+ _globals._spriteIndexes[11] = _scene->_sprites.addSprites(formAnimName('a', 1));
+ _globals._spriteIndexes[8] = _scene->_sprites.addSprites("*ROXRC_9");
+
+ _globals._sequenceIndexes[1] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[1], false, 5, 0, 0, 0);
+ _globals._sequenceIndexes[2] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[2], false, 50, 0, 0, 0);
+
+ _game.loadQuoteSet(0x252, 0x25E, 0x25A, 0x256, 0x253, 0x25F, 0x25B, 0x257, 0x254, 0x260, 0x25C, 0x258, 0x255,
+ 0x261, 0x25D, 0x259, 0x262, 0x267, 0x263, 0x26B, 0x26F, 0x268, 0x264, 0x26C, 0x270, 0x26A, 0x266, 0x26E,
+ 0x272, 0x269, 0x265, 0x26D, 0x271, 0);
+
+ _dialog1.setup(0x5B, 0x252, 0x25E, 0x25A, 0x256, 0x262, -1);
+ _dialog2.setup(0x5C, 0x253, 0x25F, 0x25B, 0x257, 0x262, -1);
+ _dialog3.setup(0x5D, 0x254, 0x260, 0x25C, 0x258, 0x262, -1);
+ _dialog4.setup(0x5E, 0x255, 0x261, 0x25D, 0x259, 0x262, -1);
+
+ if (_globals[kNextIngredient] >= 4 && _game._objects[OBJ_CHARGE_CASES].getQuality(3)) {
+ _scene->_hotspots.activate(NOUN_EXPLOSIVES, false);
+ _scene->_hotspots.activate(NOUN_KETTLE, true);
+ } else {
+ _scene->_hotspots.activate(NOUN_KETTLE, false);
+ _scene->_hotspots.activate(NOUN_EXPLOSIVES, true);
+ }
+
+ if (_globals[kNextIngredient] >= 4 && _game._objects[OBJ_CHARGE_CASES].getQuality(3)) {
+ _globals._sequenceIndexes[4] = _scene->_sequences.startCycle(_globals._spriteIndexes[4], true, 6);
+ } else if (!_game._objects[OBJ_CHARGE_CASES].getQuality(3)) {
+ switch (_globals[kNextIngredient]) {
+ case 1:
+ _vm->_sound->command(53);
+ break;
+
+ case 2:
+ _vm->_sound->command(53);
+ _vm->_sound->command(54);
+ _globals._sequenceIndexes[4] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[4], false, 15, 0, 0, 0);
+ break;
+
+ case 3:
+ _vm->_sound->command(53);
+ _vm->_sound->command(54);
+ _vm->_sound->command(55);
+ _globals._sequenceIndexes[4] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[4], false, 6, 0, 0, 0);
+ break;
+
+ case (4):
+ _vm->_sound->command(53);
+ _vm->_sound->command(54);
+ _vm->_sound->command(55);
+ _vm->_sound->command(56);
+ _globals._sequenceIndexes[4] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[4], false, 6, 0, 0, 0);
+ break;
+
+ default:
+ _vm->_sound->command(10);
+ break;
+ }
+ }
+
+ if (_globals[kNextIngredient] >= 4 && _game._objects[OBJ_CHARGE_CASES].getQuality(3)) {
+ _globals._sequenceIndexes[4] = _scene->_sequences.startCycle(_globals._spriteIndexes[4], true, 6);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[4], 1);
+ }
+
+ if (_game._objects.isInRoom(OBJ_FORMALDEHYDE)) {
+ _globals._sequenceIndexes[7] = _scene->_sequences.startCycle(_globals._spriteIndexes[7], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[7], 1);
+ int idx = _scene->_dynamicHotspots.add(NOUN_FORMALDEHYDE, VERB_WALKTO, _globals._sequenceIndexes[7], Common::Rect(0, 0, 0, 0));
+ _scene->_dynamicHotspots.setPosition(idx, Common::Point(206, 145), FACING_SOUTHEAST);
+ }
+
+ if (_game._objects.isInRoom(OBJ_PETROX)) {
+ _globals._sequenceIndexes[5] = _scene->_sequences.startCycle(_globals._spriteIndexes[5], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[5], 8);
+ int idx = _scene->_dynamicHotspots.add(NOUN_PETROX, VERB_WALKTO, _globals._sequenceIndexes[5], Common::Rect(0, 0, 0, 0));
+ _scene->_dynamicHotspots.setPosition(idx, Common::Point(186, 112), FACING_NORTHEAST);
+ }
+
+ if (_game._objects.isInRoom(OBJ_LECITHIN)) {
+ _globals._sequenceIndexes[6] = _scene->_sequences.startCycle(_globals._spriteIndexes[6], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[6], 8);
+ int idx = _scene->_dynamicHotspots.add(NOUN_LECITHIN, VERB_WALKTO, _globals._sequenceIndexes[6], Common::Rect(0, 0, 0, 0));
+ _scene->_dynamicHotspots.setPosition(idx, Common::Point(220, 121), FACING_NORTHEAST);
+ }
+
+ if (_scene->_priorSceneId != -2) {
+ _game._player._playerPos = Common::Point(60, 146);
+ _game._player._facing = FACING_NORTHEAST;
+ }
+
+ sceneEntrySound();
+
+ if (_scene->_roomChanged) {
+ _game._objects.addToInventory(OBJ_ALIEN_LIQUOR);
+ _game._objects.addToInventory(OBJ_CHARGE_CASES);
+ _game._objects.addToInventory(OBJ_TAPE_PLAYER);
+ _game._objects.addToInventory(OBJ_AUDIO_TAPE);
+ }
+
+ _scene->loadAnimation(formAnimName('a', -1));
+ _scene->_activeAnimation->setCurrentFrame(128);
+
+ _makeMushroomCloud = false;
+ _killRox = false;
+}
+
+void Scene411::step() {
+ if (_scene->_activeAnimation != nullptr) {
+ if (_curAnimationFrame != _scene->_activeAnimation->getCurrentFrame()) {
+ _curAnimationFrame = _scene->_activeAnimation->getCurrentFrame();
+ _resetFrame = -1;
+
+ switch (_curAnimationFrame) {
+ case 16:
+ _game._player._stepEnabled = true;
+ _game._player._priorTimer = _scene->_frameStartTime + _game._player._ticksAmount;
+ _game._player._visible = true;
+ _resetFrame = 128;
+ break;
+
+ case 35:
+ case 54:
+ case 71:
+ case 127:
+ if (_killRox) {
+ _resetFrame = 72;
+ } else {
+ _resetFrame = 0;
+ _game._objects.removeFromInventory(_newIngredient, NOWHERE);
+ switch (_globals[kNextIngredient]) {
+ case 1:
+ _vm->_sound->command(53);
+ break;
+
+ case 2:
+ _vm->_sound->command(54);
+ break;
+
+ case 3:
+ _vm->_sound->command(55);
+ break;
+
+ case 4:
+ _vm->_sound->command(56);
+ break;
+
+ default:
+ break;
+ }
+ }
+ break;
+
+ case (22):
+ case (41):
+ case (59):
+ case (115):
+ if (_makeMushroomCloud) {
+ _globals._sequenceIndexes[9] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[9], false, 5, 1, 0, 0);
+ _makeMushroomCloud = false;
+ _scene->_hotspots.activate(NOUN_EXPLOSIVES, false);
+ _scene->_hotspots.activate(NOUN_KETTLE, true);
+ }
+ break;
+
+ case 111:
+ _resetFrame = 111;
+ _scene->_reloadSceneFlag = true;
+ break;
+
+ case 129:
+ _resetFrame = 128;
+ break;
+
+ default:
+ break;
+ }
+
+ if ((_resetFrame >= 0) && (_resetFrame != _scene->_activeAnimation->getCurrentFrame())) {
+ _scene->_activeAnimation->setCurrentFrame(_resetFrame);
+ _curAnimationFrame = _resetFrame;
+ }
+ }
+ }
+
+ if (_scene->_activeAnimation->getCurrentFrame() == 86)
+ _vm->_sound->command(59);
+}
+
+void Scene411::preActions() {
+ if (_action.isAction(VERB_LOOK, NOUN_PETROX) && (_game._objects.isInRoom(OBJ_PETROX)))
+ _game._player._needToWalk = true;
+
+ if (_action.isAction(VERB_LOOK, NOUN_LECITHIN) && (_game._objects.isInRoom(OBJ_LECITHIN)))
+ _game._player._needToWalk = true;
+
+ if (_action.isAction(VERB_LOOK, NOUN_FORMALDEHYDE) && (_game._objects.isInRoom(OBJ_FORMALDEHYDE)))
+ _game._player._needToWalk = true;
+
+ if (_action.isAction(VERB_LOOK, NOUN_EXPLOSIVES) || _action.isAction(VERB_LOOK, NOUN_KETTLE) || _action.isAction(VERB_LOOK, NOUN_MISHAP) ||
+ _action.isAction(VERB_LOOK, NOUN_ALCOVE) || _action.isAction(VERB_LOOK, NOUN_SINK) || _action.isAction(VERB_PUT, NOUN_SINK) ||
+ _action.isAction(VERB_LOOK, NOUN_EXPERIMENT) || _action.isAction(VERB_LOOK, NOUN_DRAWING_BOARD))
+ _game._player._needToWalk = true;
+
+ if (_action.isAction(VERB_PULL, NOUN_KNIFE_SWITCH) || _action.isAction(VERB_PUSH, NOUN_KNIFE_SWITCH))
+ _game._player._needToWalk = false;
+}
+
+void Scene411::actions() {
+ if (_game._screenObjects._inputMode != 1) {
+ handleDialog();
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_WALK_INTO, NOUN_CORRIDOR_TO_SOUTH)) {
+ _scene->_nextSceneId = 406;
+ _vm->_sound->command(10);
+ _action._inProgress = false;
+ return;
+ }
+
+ if ((_globals[kNextIngredient] >= 4) && (_action.isAction(VERB_TAKE, NOUN_EXPLOSIVES) || _action.isAction(VERB_PUT, NOUN_CHARGE_CASES, 0x3AB))
+ && !_game._objects[OBJ_CHARGE_CASES].getQuality(3)
+ && _game._objects.isInInventory(OBJ_CHARGE_CASES)) {
+ switch (_game._trigger) {
+ case 0:
+ _vm->_sound->command(10);
+ _vm->_sound->command(57);
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._sequenceIndexes[10] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[10], false, 8, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[10], 1, 6);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[10], 3);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[10], SEQUENCE_TRIGGER_EXPIRE, 0, 110);
+ break;
+
+ case 110: {
+ int idx = _globals._sequenceIndexes[10];
+ _globals._sequenceIndexes[10] = _scene->_sequences.startCycle(_globals._spriteIndexes[10], false, 6);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[10], 3);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[10], idx);
+ _scene->_sequences.addTimer(180, 111);
+ }
+ break;
+
+ case 111:
+ _scene->_hotspots.activate(NOUN_KETTLE, true);
+ _scene->_hotspots.activate(NOUN_EXPLOSIVES, false);
+ _scene->_sequences.remove(_globals._sequenceIndexes[4]);
+ _scene->_sequences.remove(_globals._sequenceIndexes[10]);
+
+ _globals._sequenceIndexes[4] = _scene->_sequences.startCycle(_globals._spriteIndexes[4], true, 6);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[4], 1);
+
+ _globals._sequenceIndexes[10] = _scene->_sequences.addReverseSpriteCycle(_globals._spriteIndexes[10], false, 8, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[10], 1, 6);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[10], 3);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[10], SEQUENCE_TRIGGER_EXPIRE, 0, 112);
+ // No break on purpose
+ case 112:
+ _game._player._priorTimer = _scene->_frameStartTime - _game._player._ticksAmount;
+ _game._player._visible = true;
+ _game._player._stepEnabled = true;
+ _game._objects[OBJ_CHARGE_CASES].setQuality(3, 1);
+ _vm->_dialogs->showItem(OBJ_CHARGE_CASES, 41142);
+ break;
+ }
+ _action._inProgress = false;
+ return;
+ } else if (!_game._objects.isInInventory(OBJ_CHARGE_CASES) && _action.isAction(VERB_TAKE, NOUN_EXPLOSIVES)) {
+ _vm->_dialogs->show(41143);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_TAKE, NOUN_PETROX) && (_game._objects.isInRoom(OBJ_PETROX) || _game._trigger)) {
+ switch (_game._trigger) {
+ case (0):
+ _vm->_sound->command(57);
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._sequenceIndexes[8] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[8], false, 7, 2, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[8], 1, 2);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[8]);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[8], SEQUENCE_TRIGGER_SPRITE, 2, 1);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[8], SEQUENCE_TRIGGER_EXPIRE, 0, 2);
+ break;
+
+ case 1:
+ _scene->_sequences.remove(_globals._sequenceIndexes[5]);
+ _game._objects.addToInventory(OBJ_PETROX);
+ _vm->_dialogs->showItem(OBJ_PETROX, 41120);
+ break;
+
+ case 2:
+ _game._player._priorTimer = _scene->_frameStartTime + _game._player._ticksAmount;
+ _game._player._priorTimer = _scene->_frameStartTime + _game._player._ticksAmount;
+ _game._player._visible = true;
+ _scene->_sequences.addTimer(20, 3);
+ break;
+
+ case 3:
+ _game._player._stepEnabled = true;
+ break;
+
+ default:
+ break;
+ }
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_TAKE, NOUN_LECITHIN) && (_game._objects.isInRoom(OBJ_LECITHIN) || _game._trigger)) {
+ switch (_game._trigger) {
+ case (0):
+ _vm->_sound->command(57);
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._sequenceIndexes[8] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[8], false, 7, 2, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[8], 1, 2);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[8]);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[8], SEQUENCE_TRIGGER_SPRITE, 2, 1);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[8], SEQUENCE_TRIGGER_EXPIRE, 0, 2);
+ break;
+
+ case 1:
+ _scene->_sequences.remove(_globals._sequenceIndexes[6]);
+ _game._objects.addToInventory(OBJ_LECITHIN);
+ _vm->_dialogs->showItem(OBJ_LECITHIN, 41124);
+ break;
+
+ case 2:
+ _game._player._priorTimer = _scene->_frameStartTime + _game._player._ticksAmount;
+ _game._player._visible = true;
+ _scene->_sequences.addTimer(20, 3);
+ break;
+
+ case 3:
+ _game._player._stepEnabled = true;
+ break;
+
+ default:
+ break;
+ }
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_TAKE, NOUN_FORMALDEHYDE) && _game._objects.isInRoom(OBJ_FORMALDEHYDE) && (_game._trigger == 0)) {
+ _vm->_sound->command(57);
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._sequenceIndexes[11] = _scene->_sequences.startCycle(_globals._spriteIndexes[11], false, 2);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[11], 1);
+ _scene->_sequences.addTimer(20, 100);
+ _scene->_sequences.remove(_globals._sequenceIndexes[7]);
+ _game._objects.addToInventory(OBJ_FORMALDEHYDE);
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_game._trigger == 100) {
+ _scene->_sequences.remove(_globals._sequenceIndexes[11]);
+ _game._player._priorTimer = _scene->_frameStartTime - _game._player._ticksAmount;
+ _game._player._visible = true;
+ _game._player._stepEnabled = true;
+ _scene->_sequences.addTimer(20, 10);
+ }
+
+ if (_game._trigger == 10)
+ _vm->_dialogs->showItem(OBJ_FORMALDEHYDE, 41124);
+
+ if (_action.isAction(VERB_PUT, NOUN_KETTLE)) {
+ if (_action.isAction(0x2D7) || _action.isAction(0x2D6) || _action.isAction(0x3A9) || _action.isAction(0x306)) {
+ _newIngredient = _game._objects.getIdFromDesc(_action._activeAction._objectNameId);
+ switch (_newIngredient) {
+ case (OBJ_ALIEN_LIQUOR):
+ _dialog1.start();
+ break;
+
+ case (OBJ_FORMALDEHYDE):
+ _dialog3.start();
+ break;
+
+ case (OBJ_PETROX):
+ _dialog4.start();
+ break;
+
+ case (OBJ_LECITHIN):
+ _dialog2.start();
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+
+
+ if (_action.isAction(VERB_LOOK, NOUN_MONITOR))
+ _vm->_dialogs->show(41110);
+ else if (_action.isAction(VERB_LOOK, NOUN_AIR_PURIFIER))
+ _vm->_dialogs->show(41111);
+ else if (_action.isAction(VERB_LOOK, NOUN_LAB_EQUIPMENT))
+ _vm->_dialogs->show(41112);
+ else if (_action.isAction(VERB_LOOK, NOUN_KNIFE_SWITCH))
+ _vm->_dialogs->show(41113);
+ else if (_action.isAction(VERB_PUSH, NOUN_KNIFE_SWITCH) || _action.isAction(VERB_PULL, NOUN_KNIFE_SWITCH))
+ _vm->_dialogs->show(41114);
+ else if (_action.isAction(VERB_LOOK, NOUN_TOXIC_WASTE))
+ _vm->_dialogs->show(41115);
+ else if (_action.isAction(VERB_TAKE, NOUN_TOXIC_WASTE))
+ _vm->_dialogs->show(41116);
+ else if (_action.isAction(VERB_LOOK, NOUN_DRAWING_BOARD))
+ _vm->_dialogs->show(41117);
+ else if (_action.isAction(VERB_LOOK, NOUN_EXPERIMENT))
+ _vm->_dialogs->show(41118);
+ else if (_action.isAction(VERB_LOOK, NOUN_PETROX) && _game._objects.isInRoom(OBJ_PETROX))
+ _vm->_dialogs->show(41119);
+ else if (_action.isAction(VERB_LOOK, NOUN_ALCOVE))
+ _vm->_dialogs->show(41121);
+ else if ((_action.isAction(VERB_LOOK, NOUN_FORMALDEHYDE)) && (_game._objects.isInRoom(OBJ_FORMALDEHYDE)))
+ _vm->_dialogs->show(41122);
+ else if ((_action.isAction(VERB_LOOK, NOUN_LECITHIN)) && (_game._objects.isInRoom(OBJ_LECITHIN)))
+ _vm->_dialogs->show(41123);
+ else if (_action.isAction(VERB_LOOK, NOUN_KETTLE)) {
+ if (_globals[kNextIngredient] > 0 && !_game._objects[OBJ_CHARGE_CASES].getQuality(3)) {
+ _vm->_dialogs->show(41126);
+ } else if (_globals[kNextIngredient] == 0 || _game._objects[OBJ_CHARGE_CASES].getQuality(3)) {
+ _vm->_dialogs->show(41125);
+ }
+ } else if (_action.isAction(VERB_LOOK, NOUN_EXPLOSIVES) && _game._objects[OBJ_CHARGE_CASES].getQuality(3) == 0) {
+ _vm->_dialogs->show(41127);
+ } else if (_action.isAction(VERB_TAKE, NOUN_KETTLE))
+ _vm->_dialogs->show(41128);
+ else if (_action.isAction(VERB_LOOK, NOUN_CONTROL_PANEL))
+ _vm->_dialogs->show(41129);
+ else if (_action.isAction(VERB_LOOK, NOUN_MISHAP))
+ _vm->_dialogs->show(41130);
+ else if (_action.isAction(VERB_LOOK, NOUN_CORRIDOR_TO_SOUTH))
+ _vm->_dialogs->show(41131);
+ else if (_action._lookFlag)
+ _vm->_dialogs->show(41132);
+ else if (_action.isAction(VERB_LOOK, NOUN_AIR_HORN))
+ _vm->_dialogs->show(41133);
+ else if (_action.isAction(VERB_LOOK, NOUN_DEBRIS))
+ _vm->_dialogs->show(41134);
+ else if (_action.isAction(VERB_LOOK, NOUN_HEATER))
+ _vm->_dialogs->show(41135);
+ else if (_action.isAction(VERB_LOOK, NOUN_PIPE))
+ _vm->_dialogs->show(41136);
+ else if (_action.isAction(VERB_LOOK, NOUN_SINK))
+ _vm->_dialogs->show(41137);
+ else if (_action.isAction(VERB_PUT, NOUN_SINK))
+ _vm->_dialogs->show(41138);
+ else if (_action.isAction(VERB_TAKE, NOUN_EXPERIMENT))
+ _vm->_dialogs->show(41139);
+ else if (_action.isAction(VERB_LOOK, NOUN_ELECTRODES))
+ _vm->_dialogs->show(41140);
+ else if (_action.isAction(VERB_TAKE, NOUN_ELECTRODES))
+ _vm->_dialogs->show(41141);
+ else
+ return;
+
+ _action._inProgress = false;
+}
+
+/*------------------------------------------------------------------------*/
+
+Scene413::Scene413(MADSEngine *vm) : Scene4xx(vm) {
+ _rexDeath = -1;
+ _canMove = -1;
+}
+
+void Scene413::synchronize(Common::Serializer &s) {
+ Scene4xx::synchronize(s);
+
+ s.syncAsSint32LE(_rexDeath);
+ s.syncAsSint32LE(_canMove);
+}
+
+void Scene413::setup() {
+ setPlayerSpritesPrefix();
+ setAAName();
+}
+
+void Scene413::enter() {
+ _globals._spriteIndexes[1] = _scene->_sprites.addSprites(formAnimName('a', 2));
+ _rexDeath = false;
+
+ if (_scene->_priorSceneId == 405) {
+ _game._player._playerPos = Common::Point(142, 146);
+ _game._player._facing = FACING_NORTH;
+ _game._player._visible = true;
+ } else if (_scene->_priorSceneId != -2) {
+ if (_globals[kSexOfRex] == REX_MALE) {
+ _scene->loadAnimation(Resources::formatName(413, 'd', 1, EXT_AA, ""), 78);
+ _vm->_sound->command(30);
+ _game._player._visible = false;
+ _game._player._stepEnabled = false;
+ _rexDeath = true;
+ } else if (!_globals[kTeleporterCommand]) {
+ _game._player._playerPos = Common::Point(136, 117);
+ _game._player.walk(Common::Point(141, 130), FACING_SOUTH);
+ _game._player._facing = FACING_SOUTH;
+ _game._player._visible = true;
+ }
+ }
+
+ if ((_globals[kTeleporterCommand]) && (!_rexDeath)) {
+ switch (_globals[kTeleporterCommand]) {
+ case 1:
+ _vm->_sound->command(30);
+ _game._player._visible = false;
+ _globals._sequenceIndexes[1] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[1], false, 7, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[1], 1, 19);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 8);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[1], SEQUENCE_TRIGGER_EXPIRE, 0, 76);
+ break;
+
+ case 2:
+ _game._player._visible = false;
+ _vm->_sound->command(30);
+ _globals._sequenceIndexes[1] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[1], false, 7, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[1], 1, 20);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 8);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[1], SEQUENCE_TRIGGER_EXPIRE, 0, 77);
+ break;
+
+ case 3:
+ case 4:
+ _game._player._playerPos = Common::Point(136, 117);
+ _game._player._facing = FACING_SOUTH;
+ _game._player.walk(Common::Point(141, 130), FACING_SOUTH);
+ _game._player._visible = true;
+ _game._player._stepEnabled = true;
+ break;
+
+ default:
+ break;
+ }
+ _globals[kTeleporterCommand] = 0;
+ }
+
+ _canMove = true;
+ sceneEntrySound();
+}
+
+void Scene413::step() {
+ if (_scene->_activeAnimation && _scene->_activeAnimation->getCurrentFrame() == 38)
+ _scene->_activeAnimation->setCurrentFrame(37);
+
+ if (_scene->_activeAnimation && _scene->_activeAnimation->getCurrentFrame() == 21 && _canMove) {
+ _vm->_sound->command(27);
+ _canMove = false;
+ }
+
+ if (_game._trigger == 76) {
+ _game._player._playerPos = Common::Point(136, 117);
+ _game._player.walk(Common::Point(141, 130), FACING_SOUTH);
+ _game._player._facing = FACING_SOUTH;
+ _game._player.selectSeries();
+ _game._player._visible = true;
+ _game._player._stepEnabled = true;
+ }
+
+ if (_game._trigger == 77) {
+ _globals[kTeleporterCommand] = TELEPORTER_BEAM_IN;
+ _scene->_nextSceneId = _globals[kTeleporterDestination];
+ _scene->_reloadSceneFlag = true;
+ }
+
+ if (_game._trigger == 78) {
+ _scene->_reloadSceneFlag = true;
+ _scene->_nextSceneId = _scene->_priorSceneId;
+ _globals[kTeleporterCommand] = TELEPORTER_NONE;
+ }
+}
+
+void Scene413::preActions() {
+ if (_action.isAction(VERB_TAKE) || _action.isAction(VERB_PUT, NOUN_CONVEYOR_BELT))
+ _game._player._needToWalk = false;
+
+ if (_action.isAction(VERB_LOOK, NOUN_WOODEN_STATUE) || _action.isAction(VERB_LOOK, NOUN_DISPLAY)
+ || _action.isAction(VERB_LOOK, NOUN_PICTURE) || _action.isAction(VERB_LOOK, NOUN_PLANT)) {
+ _game._player._needToWalk = true;
+ }
+}
+
+void Scene413::actions() {
+ if (_action.isAction(VERB_WALK_INSIDE, NOUN_TELEPORTER)) {
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _scene->_nextSceneId = 409;
+ } else if (_action.isAction(VERB_WALK_INSIDE, NOUN_CORRIDOR_TO_SOUTH))
+ _scene->_nextSceneId = 405;
+ else if (_action.isAction(VERB_LOOK, NOUN_WOODEN_STATUE))
+ _vm->_dialogs->show(41310);
+ else if (_action.isAction(VERB_TAKE, NOUN_WOODEN_STATUE))
+ _vm->_dialogs->show(41311);
+ else if (_action.isAction(VERB_LOOK, NOUN_CONVEYOR_BELT))
+ _vm->_dialogs->show(41312);
+ else if (_action.isAction(VERB_PUT, NOUN_CONVEYOR_BELT))
+ _vm->_dialogs->show(41313);
+ else if (_action.isAction(VERB_LOOK, NOUN_TELEPORTER))
+ _vm->_dialogs->show(41314);
+ else if (_action.isAction(VERB_LOOK, NOUN_DISPLAY))
+ _vm->_dialogs->show(41315);
+ else if (_action.isAction(VERB_LOOK, NOUN_CORRIDOR_TO_SOUTH))
+ _vm->_dialogs->show(41316);
+ else if (_action.isAction(VERB_LOOK, NOUN_PICTURE))
+ _vm->_dialogs->show(41317);
+ else if (_action.isAction(VERB_LOOK, NOUN_PLANT))
+ _vm->_dialogs->show(41318);
+ else if (_action.isAction(VERB_TAKE, NOUN_PLANT))
+ _vm->_dialogs->show(41319);
+ else if (_action._lookFlag)
+ _vm->_dialogs->show(41320);
+ else
+ return;
+
+ _action._inProgress = false;
+}
+
+/*------------------------------------------------------------------------*/
+
+} // End of namespace Nebular
+} // End of namespace MADS
diff --git a/engines/mads/nebular/nebular_scenes4.h b/engines/mads/nebular/nebular_scenes4.h
new file mode 100644
index 0000000000..4544e0887f
--- /dev/null
+++ b/engines/mads/nebular/nebular_scenes4.h
@@ -0,0 +1,258 @@
+/* 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.
+ *
+ */
+
+#ifndef MADS_NEBULAR_SCENES4_H
+#define MADS_NEBULAR_SCENES4_H
+
+#include "common/scummsys.h"
+#include "mads/game.h"
+#include "mads/scene.h"
+#include "mads/nebular/nebular_scenes.h"
+
+namespace MADS {
+
+namespace Nebular {
+
+class Scene4xx : public NebularScene {
+protected:
+ /**
+ * Plays an appropriate sound when entering a scene
+ */
+ void setAAName();
+
+ /**
+ * Updates the prefix used for getting player sprites for the scene
+ */
+ void setPlayerSpritesPrefix();
+
+ void sceneEntrySound();
+
+public:
+ Scene4xx(MADSEngine *vm) : NebularScene(vm) {}
+};
+
+class Scene401: public Scene4xx {
+private:
+ bool _northFl;
+ Common::Point _destPos;
+ uint32 _timer;
+
+public:
+ Scene401(MADSEngine *vm);
+ void synchronize(Common::Serializer &s);
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+ virtual void preActions();
+ virtual void actions();
+};
+
+class Scene402: public Scene4xx {
+private:
+ bool _lightOn;
+ bool _blowingSmoke;
+ bool _leftWomanMoving;
+ bool _rightWomanMoving;
+ bool _firstTalkToGirlInChair;
+ bool _waitingGinnyMove;
+ bool _ginnyLooking;
+ bool _bigBeatFl;
+ bool _roxOnStool;
+ bool _bartenderSteady;
+ bool _bartenderHandsHips;
+ bool _bartenderLooksLeft;
+ bool _bartenderReady;
+ bool _bartenderTalking;
+ bool _bartenderCalled;
+ bool _conversationFl;
+ bool _activeTeleporter;
+ bool _activeArrows;
+ bool _activeArrow1;
+ bool _activeArrow2;
+ bool _activeArrow3;
+ bool _cutSceneReady;
+ bool _cutSceneNeeded;
+ bool _helgaReady;
+ bool _refuseAlienLiquor;
+
+ int _drinkTimer;
+ int _beatCounter;
+ int _bartenderMode;
+ int _bartenderDialogNode;
+ int _bartenderCurrentQuestion;
+ int _helgaTalkMode;
+ int _roxMode;
+ int _rexMode;
+ int _talkTimer;
+
+ Conversation _dialog1;
+ Conversation _dialog2;
+ Conversation _dialog3;
+ Conversation _dialog4;
+
+ void setDialogNode(int node);
+ void handleConversation1();
+ void handleConversation2();
+ void handleConversation3();
+ void handleConversation4();
+ void handleDialogs();
+
+public:
+ Scene402(MADSEngine *vm);
+ void synchronize(Common::Serializer &s);
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+ virtual void preActions();
+ virtual void actions();
+};
+
+class Scene405: public Scene4xx {
+public:
+ Scene405(MADSEngine *vm) : Scene4xx(vm) {}
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+ virtual void preActions();
+ virtual void actions();
+};
+
+class Scene406: public Scene4xx {
+private:
+ bool _hitStorageDoor;
+
+public:
+ Scene406(MADSEngine *vm);
+ void synchronize(Common::Serializer &s);
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+ virtual void preActions();
+ virtual void actions();
+};
+
+class Scene407: public Scene4xx {
+private:
+ bool _fromNorth;
+ Common::Point _destPos;
+
+public:
+ Scene407(MADSEngine *vm);
+ void synchronize(Common::Serializer &s);
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+ virtual void preActions();
+ virtual void actions();
+};
+
+class Scene408: public Scene4xx {
+public:
+ Scene408(MADSEngine *vm) : Scene4xx(vm) {}
+
+ virtual void setup();
+ virtual void enter();
+ virtual void preActions();
+ virtual void actions();
+};
+
+class Scene409: public SceneTeleporter {
+public:
+ Scene409(MADSEngine *vm) : SceneTeleporter(vm) {}
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+ virtual void actions();
+};
+
+class Scene410: public Scene4xx {
+public:
+ Scene410(MADSEngine *vm) : Scene4xx(vm) {}
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+ virtual void preActions();
+ virtual void actions();
+};
+
+class Scene411: public Scene4xx {
+private:
+ int _curAnimationFrame;
+ int _newIngredient;
+ int _newQuantity;
+ int _resetFrame;
+ int _badThreshold;
+
+ bool _killRox;
+ bool _makeMushroomCloud;
+
+ Conversation _dialog1;
+ Conversation _dialog2;
+ Conversation _dialog3;
+ Conversation _dialog4;
+
+ void giveToRex(int object);
+ void handleDialog();
+ void handleKettleAction();
+
+ int computeQuoteAndQuantity();
+
+ bool addQuantity();
+ bool addIngredient();
+
+public:
+ Scene411(MADSEngine *vm);
+ void synchronize(Common::Serializer &s);
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+ virtual void preActions();
+ virtual void actions();
+};
+
+class Scene413: public Scene4xx {
+private:
+ int _rexDeath;
+ int _canMove;
+
+public:
+ Scene413(MADSEngine *vm);
+ void synchronize(Common::Serializer &s);
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+ virtual void preActions();
+ virtual void actions();
+};
+} // End of namespace Nebular
+} // End of namespace MADS
+
+#endif /* MADS_NEBULAR_SCENES4_H */
diff --git a/engines/mads/nebular/nebular_scenes5.cpp b/engines/mads/nebular/nebular_scenes5.cpp
new file mode 100644
index 0000000000..a8c6b22591
--- /dev/null
+++ b/engines/mads/nebular/nebular_scenes5.cpp
@@ -0,0 +1,2871 @@
+/* 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 "mads/mads.h"
+#include "mads/scene.h"
+#include "mads/nebular/nebular_scenes.h"
+#include "mads/nebular/nebular_scenes5.h"
+
+namespace MADS {
+
+namespace Nebular {
+
+void Scene5xx::setAAName() {
+ _game._aaName = Resources::formatAAName(5);
+}
+
+void Scene5xx::setPlayerSpritesPrefix() {
+ _vm->_sound->command(5);
+
+ Common::String oldName = _game._player._spritesPrefix;
+
+ if ((_scene->_nextSceneId == 502) || (_scene->_nextSceneId == 504) || (_scene->_nextSceneId == 505) || (_scene->_nextSceneId == 515))
+ _game._player._spritesPrefix = "";
+ else if (_globals[kSexOfRex] == REX_MALE)
+ _game._player._spritesPrefix = "RXM";
+ else if ((_scene->_nextSceneId == 501) || (_scene->_nextSceneId == 503) || (_scene->_nextSceneId == 551))
+ _game._player._spritesPrefix = "ROX";
+
+ _game._player._scalingVelocity = true;
+
+ if ((_scene->_nextSceneId == 512) || (_scene->_nextSceneId == 507))
+ _game._player._scalingVelocity = false;
+
+ if (oldName != _game._player._spritesPrefix)
+ _game._player._spritesChanged = true;
+
+ _vm->_palette->setEntry(16, 10, 63, 63);
+ _vm->_palette->setEntry(17, 10, 45, 45);
+}
+
+void Scene5xx::sceneEntrySound() {
+ if (!_vm->_musicFlag) {
+ _vm->_sound->command(2);
+ return;
+ }
+
+ switch (_scene->_nextSceneId) {
+ case 501:
+ case 502:
+ case 504:
+ case 505:
+ case 506:
+ case 507:
+ case 508:
+ case 511:
+ case 512:
+ case 513:
+ case 515:
+ case 551:
+ if (_scene->_priorSceneId == 503)
+ _vm->_sound->command(38);
+ else
+ _vm->_sound->command(29);
+ break;
+ case 503:
+ _vm->_sound->command(41);
+ break;
+ default:
+ break;
+ }
+}
+
+/*------------------------------------------------------------------------*/
+
+Scene501::Scene501(MADSEngine *vm) : Scene5xx(vm) {
+ _mainSequenceId = -1;
+ _mainSpriteId = -1;
+ _doorHotspotid = -1;
+
+ _rexPunched = false;
+}
+
+void Scene501::synchronize(Common::Serializer &s) {
+ Scene5xx::synchronize(s);
+
+ s.syncAsSint16LE(_mainSequenceId);
+ s.syncAsSint16LE(_mainSpriteId);
+ s.syncAsSint16LE(_doorHotspotid);
+ s.syncAsByte(_rexPunched);
+}
+
+void Scene501::setup() {
+ setPlayerSpritesPrefix();
+ setAAName();
+ _scene->addActiveVocab(NOUN_DOOR);
+ _scene->addActiveVocab(VERB_WALK_THROUGH);
+}
+
+void Scene501::handleSlotActions() {
+ switch (_game._trigger) {
+ case 0:
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ int numTicks, frameIndex;
+ if (_globals[kSexOfRex] == REX_MALE) {
+ _mainSpriteId = _globals._spriteIndexes[4];
+ numTicks = 8;
+ frameIndex = 3;
+ } else {
+ _mainSpriteId = _globals._spriteIndexes[5];
+ numTicks = 10;
+ frameIndex = 2;
+ }
+
+ _mainSequenceId = _scene->_sequences.startReverseCycle(_mainSpriteId, false, numTicks, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_mainSequenceId, 1, frameIndex);
+ _scene->_sequences.setMsgLayout(_mainSequenceId);
+ _vm->_sound->command(10);
+ _scene->_sequences.addSubEntry(_mainSequenceId, SEQUENCE_TRIGGER_SPRITE, frameIndex, 1);
+ _scene->_sequences.addSubEntry(_mainSequenceId, SEQUENCE_TRIGGER_EXPIRE, 0, 2);
+ break;
+
+ case 1:
+ _globals._sequenceIndexes[1] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[1], false, 12, 6, 0, 0);
+ break;
+
+ case 2:
+ _scene->_sequences.updateTimeout(-1, _mainSequenceId);
+ _game._player._visible = true;
+ _scene->_sequences.addTimer(15, 3);
+ break;
+
+ case 3:
+ _game._player.walk(Common::Point(282, 110), FACING_NORTH);
+ _scene->_sequences.addTimer(60, 4);
+ break;
+
+ default:
+ break;
+ }
+}
+
+void Scene501::enter() {
+ _globals._spriteIndexes[1] = _scene->_sprites.addSprites(formAnimName('x', 1));
+ _globals._spriteIndexes[2] = _scene->_sprites.addSprites(formAnimName('c', 0));
+ _globals._spriteIndexes[3] = _scene->_sprites.addSprites(formAnimName('x', 0));
+
+ if (_globals[kSexOfRex] == REX_MALE) {
+ _globals._spriteIndexes[4] = _scene->_sprites.addSprites("*RXMRC_9");
+ _globals._spriteIndexes[6] = _scene->_sprites.addSprites("*RXCD_7");
+ } else {
+ _globals._spriteIndexes[5] = _scene->_sprites.addSprites("*ROXRC_9");
+ _globals._spriteIndexes[7] = _scene->_sprites.addSprites("*ROXCD_7");
+ }
+
+ _globals._sequenceIndexes[3] = _scene->_sequences.startCycle(_globals._spriteIndexes[3], false, 1);
+ int idx = _scene->_dynamicHotspots.add(NOUN_DOOR, 0x18B, _globals._sequenceIndexes[3], Common::Rect(0, 0, 0, 0));
+ _doorHotspotid = _scene->_dynamicHotspots.setPosition(idx,Common::Point(282, 110), FACING_NORTH);
+ _scene->_dynamicHotspots.setCursor(_doorHotspotid, CURSOR_GO_UP);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 7);
+ _globals._sequenceIndexes[2] = _scene->_sequences.startCycle(_globals._spriteIndexes[2], false, -1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 4);
+ _rexPunched = true;
+
+ if (_scene->_priorSceneId == 504) {
+ _game._player._stepEnabled = false;
+ _game._player._playerPos = Common::Point(74, 121);
+ _game._player._facing = FACING_NORTHWEST;
+ _game._player._visible = false;
+ _game._player._stepEnabled = false;
+ _scene->_sequences.remove(_globals._sequenceIndexes[2]);
+ _globals._sequenceIndexes[2] = _scene->_sequences.startCycle(_globals._spriteIndexes[2], false, -2);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 4);
+ if (_globals[kSexOfRex] == REX_MALE)
+ _scene->loadAnimation(formAnimName('G', 2), 70);
+ else
+ _scene->loadAnimation(formAnimName('R', 2), 70);
+ } else if (_scene->_priorSceneId == 503) {
+ _game._player._playerPos = Common::Point(317, 102);
+ _game._player._facing = FACING_SOUTHWEST;
+ _scene->_sequences.addTimer(15, 80);
+ } else if (_scene->_priorSceneId != -2)
+ _game._player._playerPos = Common::Point(299, 131);
+
+ if (_scene->_roomChanged) {
+ _game._objects.addToInventory(OBJ_FAKE_ID);
+ _game._objects.addToInventory(OBJ_SECURITY_CARD);
+ _game._objects.addToInventory(OBJ_ID_CARD);
+ }
+
+ sceneEntrySound();
+ _game.loadQuoteSet(0x275, 0x276, 0x277, 0);
+
+ if (!_game._visitedScenes._sceneRevisited)
+ _scene->_sequences.addTimer(2, 90);
+}
+
+void Scene501::step() {
+ if (_game._trigger == 90)
+ _vm->_dialogs->show(50127);
+
+ if (_game._trigger >= 80) {
+ switch (_game._trigger) {
+ case 80:
+ _game._player._stepEnabled = false;
+ _scene->_sequences.remove(_globals._sequenceIndexes[3]);
+ _globals._sequenceIndexes[1] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[1], false, 12, 6, 0, 0);
+ _globals._sequenceIndexes[3] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[3], false, 9, 1, 0, 0);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 7);
+ _vm->_sound->command(11);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[3], SEQUENCE_TRIGGER_EXPIRE, 0, 81);
+ break;
+
+ case 81:
+ _scene->_dynamicHotspots.remove(_doorHotspotid);
+ _game._player.walk(Common::Point(276, 110), FACING_SOUTHWEST);
+ _scene->_sequences.addTimer(120, 82);
+ break;
+
+ case 82:
+ _globals._sequenceIndexes[3] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[3], false, 9, 1, 0, 0);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 7);
+ _vm->_sound->command(12);
+ _doorHotspotid = _scene->_dynamicHotspots.add(NOUN_DOOR, 0x18B, _globals._sequenceIndexes[3], Common::Rect(0, 0, 0, 0));
+ _scene->_dynamicHotspots.setPosition(_globals._sequenceIndexes[3], Common::Point(282, 110), FACING_NORTH);
+ _scene->_dynamicHotspots.setCursor(_doorHotspotid, CURSOR_GO_UP);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[3], SEQUENCE_TRIGGER_EXPIRE, 0, 83);
+ break;
+
+ case 83:
+ _game._player._stepEnabled = true;
+ _globals._sequenceIndexes[3] = _scene->_sequences.startCycle(_globals._spriteIndexes[3], false, -1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 7);
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ if (_game._trigger >= 70 && _game._trigger <= 73) {
+ switch (_game._trigger) {
+ case 70:
+ _game._player._visible = true;
+ _game._player._priorTimer = _scene->_frameStartTime - _game._player._ticksAmount;
+ _scene->_sequences.addTimer(15, 71);
+ break;
+
+ case 71:
+ _game._player.walk(Common::Point(92, 130), FACING_SOUTH);
+ _scene->_sequences.addTimer(30, 72);
+ break;
+
+ case 72:
+ _scene->_sequences.remove(_globals._sequenceIndexes[2]);
+ _globals._sequenceIndexes[2] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[2], false, 6, 1, 0, 0);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 4);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[2], SEQUENCE_TRIGGER_EXPIRE, 0, 73);
+ break;
+
+ case 73:
+ _game._player._stepEnabled = true;
+ _globals._sequenceIndexes[2] = _scene->_sequences.startCycle(_globals._spriteIndexes[2], false, -1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 4);
+ break;
+
+ default:
+ break;
+ }
+ }
+}
+
+void Scene501::preActions() {
+ if (_action.isAction(VERB_WALK_DOWN) && (_action.isObject(NOUN_STREET_TO_EAST) || _action.isObject(NOUN_SIDEWALK_TO_EAST)))
+ _game._player._walkOffScreenSceneId = 551;
+}
+
+void Scene501::actions() {
+ if (_action.isAction(VERB_GET_INTO, NOUN_CAR)) {
+ switch (_game._trigger) {
+ case 0:
+ _game._player._stepEnabled = false;
+ _scene->_sequences.remove(_globals._sequenceIndexes[2]);
+ _globals._sequenceIndexes[2] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[2], false, 6, 1, 0, 0);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 4);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[2], SEQUENCE_TRIGGER_EXPIRE, 0, 1);
+ break;
+
+ case 1: {
+ int syncIdx = _globals._sequenceIndexes[2];
+ _globals._sequenceIndexes[2] = _scene->_sequences.startCycle(_globals._spriteIndexes[2], false, -2);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 4);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[2], syncIdx);
+ _scene->_sequences.addTimer(15, 2);
+ }
+ break;
+
+ case 2:
+ _game._player._visible = false;
+ if (_globals[kSexOfRex] == REX_MALE)
+ _mainSpriteId = _globals._spriteIndexes[6];
+ else
+ _mainSpriteId = _globals._spriteIndexes[7];
+
+ _mainSequenceId = _scene->_sequences.addSpriteCycle(_mainSpriteId, false, 8, 1, 0, 0);
+ _scene->_sequences.setMsgLayout(_mainSequenceId);
+ _scene->_sequences.addSubEntry(_mainSequenceId, SEQUENCE_TRIGGER_EXPIRE, 0, 3);
+ break;
+
+ case 3: {
+ int syncIdx = _mainSequenceId;
+ _mainSequenceId = _scene->_sequences.startCycle(_mainSpriteId, false, -2);
+ _scene->_sequences.setMsgLayout(_mainSequenceId);
+ _scene->_sequences.updateTimeout(_mainSequenceId, syncIdx);
+ _scene->_sequences.addTimer(30, 4);
+ }
+ break;
+
+ case 4:
+ _scene->_nextSceneId = 504;
+ break;
+
+ default:
+ break;
+ }
+ } else if (_action.isAction(VERB_PUT, NOUN_SECURITY_CARD, 0x251))
+ _vm->_dialogs->show(50113);
+ else if (_action.isAction(VERB_PUT, NOUN_FAKE_ID, 0x251)) {
+ switch (_game._trigger) {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ handleSlotActions();
+ break;
+
+ case 4:
+ if (_globals[kSexOfRex] == REX_MALE) {
+ _game._player._visible = false;
+ _vm->_sound->command(13);
+ _scene->loadAnimation(formAnimName('G', 1), 5);
+ } else {
+ _rexPunched = false;
+ _scene->_kernelMessages.reset();
+ _scene->_kernelMessages.add(Common::Point(0, 0), 0x1110, 34, 6, 120, _game.getQuote(0x277));
+ }
+ break;
+
+ case 5:
+ _game._player._visible = true;
+ _game._player._priorTimer = _scene->_frameStartTime - _game._player._ticksAmount;
+ _scene->_sequences.addTimer(30, 6);
+ break;
+
+ case 6:
+ if (_globals[kSexOfRex] == REX_MALE) {
+ if (_rexPunched) {
+ _scene->_kernelMessages.reset();
+ _scene->_kernelMessages.add(Common::Point(0, 0), 0x1110, 34, 0, 120, _game.getQuote(0x275));
+ _rexPunched = false;
+ } else {
+ _scene->_kernelMessages.reset();
+ _scene->_kernelMessages.add(Common::Point(0, 0), 0x1110, 34, 0, 120, _game.getQuote(0x276));
+ }
+ }
+ _game._player._stepEnabled = true;
+ break;
+
+ default:
+ break;
+ }
+ } else if (_action.isAction(VERB_PUT, NOUN_ID_CARD, 0x251)) {
+ switch (_game._trigger) {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ handleSlotActions();
+
+ case 4:
+ _scene->_sequences.remove(_globals._sequenceIndexes[3]);
+ _scene->_dynamicHotspots.remove(_doorHotspotid);
+ _globals._sequenceIndexes[3] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[3], false, 9, 1, 0, 0);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 7);
+ _vm->_sound->command(11);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[3], SEQUENCE_TRIGGER_EXPIRE, 0, 6);
+ break;
+
+ case 6:
+ _game._player.walk(Common::Point(317, 102), FACING_NORTHEAST);
+ _scene->_sequences.addTimer(120, 7);
+ break;
+
+ case 7: {
+ _vm->_sound->command(12);
+ int syncIdx = _globals._sequenceIndexes[3];
+ _globals._sequenceIndexes[3] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[3], false, 9, 1, 0, 0);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 7);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[3], syncIdx);
+ _vm->_sound->command(12);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[3], SEQUENCE_TRIGGER_EXPIRE, 0, 8);
+ }
+ break;
+
+ case 8: {
+ int syncIdx = _globals._sequenceIndexes[3];
+ _globals._sequenceIndexes[3] = _scene->_sequences.startCycle(_globals._spriteIndexes[3], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 7);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[3], syncIdx);
+ _scene->_nextSceneId = 503;
+ }
+ break;
+
+ default:
+ break;
+ }
+ } else if (_action._lookFlag || _action.isAction(VERB_LOOK, NOUN_STREET))
+ _vm->_dialogs->show(50121);
+ else if (_action.isAction(VERB_LOOK, NOUN_DOOR))
+ _vm->_dialogs->show(50110);
+ else if (_action.isAction(VERB_LOOK, NOUN_CARD_SLOT))
+ _vm->_dialogs->show(50112);
+ else if (_action.isAction(VERB_LOOK, NOUN_SIGN))
+ _vm->_dialogs->show(50114);
+ else if (_action.isAction(VERB_TAKE, NOUN_SIGN))
+ _vm->_dialogs->show(50115);
+ else if (_action.isAction(VERB_LOOK, NOUN_SIDEWALK_TO_EAST))
+ _vm->_dialogs->show(50118);
+ else if (_action.isAction(VERB_LOOK, NOUN_SIDEWALK_TO_WEST) || _action.isAction(VERB_LOOK, NOUN_STREET_TO_WEST)
+ || _action.isAction(VERB_WALK_DOWN, NOUN_SIDEWALK_TO_WEST) || _action.isAction(VERB_WALK_DOWN, NOUN_STREET_TO_WEST))
+ _vm->_dialogs->show(50119);
+ else if (_action.isAction(VERB_LOOK, NOUN_BUILDING))
+ _vm->_dialogs->show(50120);
+ else if (_action.isAction(VERB_OPEN, NOUN_DOOR))
+ _vm->_dialogs->show(50122);
+ else if (_action.isAction(VERB_LOOK, NOUN_FIRE_HYDRANT))
+ _vm->_dialogs->show(50123);
+ else if (_action.isAction(VERB_OPEN, NOUN_FIRE_HYDRANT))
+ _vm->_dialogs->show(50124);
+ else if (_action.isAction(VERB_LOOK, NOUN_EQUIPMENT_OVERHEAD))
+ _vm->_dialogs->show(50125);
+ else if (_action.isAction(VERB_LOOK, NOUN_PIPES) || _action.isAction(VERB_LOOK, NOUN_PIPE))
+ _vm->_dialogs->show(50126);
+ else if (_action.isAction(VERB_LOOK, NOUN_CAR)) {
+ if (!_game._visitedScenes.exists(504))
+ _vm->_dialogs->show(50116);
+ else
+ _vm->_dialogs->show(50117);
+ } else
+ return;
+
+ _action._inProgress = false;
+}
+
+/*------------------------------------------------------------------------*/
+
+void Scene502::setup() {
+ _game._player._spritesPrefix = "";
+ // The original is using Scene5xx_setAAName()
+ _game._aaName = Resources::formatAAName(5);
+}
+
+void Scene502::enter() {
+ if (_globals[kSexOfRex] == REX_MALE)
+ _handSpriteId = _scene->_sprites.addSprites("*REXHAND");
+ else
+ _handSpriteId = _scene->_sprites.addSprites("*ROXHAND");
+
+ teleporterEnter();
+
+ // The original uses scene5xx_sceneEntrySound
+ if (!_vm->_musicFlag)
+ _vm->_sound->command(2);
+ else if (_scene->_priorSceneId == 503)
+ _vm->_sound->command(38);
+ else
+ _vm->_sound->command(29);
+}
+
+void Scene502::step() {
+ teleporterStep();
+}
+
+void Scene502::actions() {
+ if (teleporterActions()) {
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_LOOK, NOUN_VIEWPORT) || _action.isAction(VERB_PEER_THROUGH, NOUN_VIEWPORT))
+ _vm->_dialogs->show(50210);
+ else if (_action.isAction(VERB_LOOK, NOUN_KEYPAD))
+ _vm->_dialogs->show(50211);
+ else if (_action.isAction(VERB_LOOK, NOUN_DISPLAY))
+ _vm->_dialogs->show(50212);
+ else if (_action.isAction(VERB_LOOK, NOUN_0_KEY) || _action.isAction(VERB_LOOK, NOUN_1_KEY)
+ || _action.isAction(VERB_LOOK, NOUN_2_KEY) || _action.isAction(VERB_LOOK, NOUN_3_KEY)
+ || _action.isAction(VERB_LOOK, NOUN_4_KEY) || _action.isAction(VERB_LOOK, NOUN_5_KEY)
+ || _action.isAction(VERB_LOOK, NOUN_6_KEY) || _action.isAction(VERB_LOOK, NOUN_7_KEY)
+ || _action.isAction(VERB_LOOK, NOUN_8_KEY) || _action.isAction(VERB_LOOK, NOUN_9_KEY)
+ || _action.isAction(VERB_LOOK, NOUN_SMILE_KEY) || _action.isAction(VERB_LOOK, NOUN_ENTER_KEY)
+ || _action.isAction(VERB_LOOK, NOUN_FROWN_KEY))
+ _vm->_dialogs->show(50213);
+ else if (_action.isAction(VERB_LOOK, NOUN_DEVICE) || _action._lookFlag)
+ _vm->_dialogs->show(50214);
+ else
+ return;
+
+ _action._inProgress = false;
+}
+
+/*------------------------------------------------------------------------*/
+
+Scene503::Scene503(MADSEngine *vm) : Scene5xx(vm) {
+ _detonatorHotspotId = -1;
+}
+
+void Scene503::synchronize(Common::Serializer &s) {
+ Scene5xx::synchronize(s);
+
+ s.syncAsSint16LE(_detonatorHotspotId);
+}
+
+void Scene503::setup() {
+ setPlayerSpritesPrefix();
+ setAAName();
+ _scene->addActiveVocab(NOUN_DETONATORS);
+ _scene->addActiveVocab(VERB_WALKTO);
+}
+
+void Scene503::enter() {
+ _globals._spriteIndexes[1] = _scene->_sprites.addSprites(formAnimName('c', -1));
+
+ if (_globals[kSexOfRex] == REX_MALE)
+ _globals._spriteIndexes[2] = _scene->_sprites.addSprites("*RXMBD_2");
+ else
+ _globals._spriteIndexes[3] = _scene->_sprites.addSprites("*ROXBD_2");
+
+ if (_game._objects[OBJ_DETONATORS]._roomNumber == _scene->_currentSceneId) {
+ _globals._sequenceIndexes[1] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[1], false, 9, 0, 0, 0);
+ _detonatorHotspotId = _scene->_dynamicHotspots.add(NOUN_DETONATORS, 0xD, _globals._sequenceIndexes[1], Common::Rect(0, 0, 0, 0));
+ _scene->_dynamicHotspots.setPosition(_detonatorHotspotId, Common::Point(254, 135), FACING_SOUTH);
+ }
+
+ if (_scene->_priorSceneId != -2) {
+ _game._player._playerPos = Common::Point(191, 152);
+ _game._player._facing = FACING_NORTHWEST;
+ }
+
+ sceneEntrySound();
+}
+
+void Scene503::actions() {
+ if (_action.isAction(VERB_WALK, NOUN_OUTSIDE))
+ _scene->_nextSceneId = 501;
+ else if (_action.isAction(VERB_TAKE, NOUN_DETONATORS)) {
+ if ( _game._trigger || !_game._objects.isInInventory(OBJ_DETONATORS)) {
+ switch (_game._trigger) {
+ case 0:
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ if (_globals[kSexOfRex] == REX_MALE) {
+ _globals._sequenceIndexes[2] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[2], false, 8, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[2], 1, 3);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[2]);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[2], SEQUENCE_TRIGGER_SPRITE, 3, 1);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[2], SEQUENCE_TRIGGER_EXPIRE, 0, 2);
+ } else {
+ _globals._sequenceIndexes[3] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[3], true, 8, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[3], 1, 4);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[3]);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[3], SEQUENCE_TRIGGER_SPRITE, 4, 1);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[3], SEQUENCE_TRIGGER_EXPIRE, 0, 2);
+ }
+ break;
+
+ case 1:
+ _vm->_sound->command(9);
+ _scene->_sequences.remove(_globals._sequenceIndexes[1]);
+ _scene->_dynamicHotspots.remove(_detonatorHotspotId);
+ _game._objects.addToInventory(OBJ_DETONATORS);
+ _vm->_dialogs->showItem(OBJ_DETONATORS, 50326);
+ break;
+
+ case 2:
+ if (_globals[kSexOfRex] == REX_MALE)
+ _scene->_sequences.updateTimeout(-1, _globals._sequenceIndexes[2]);
+ else
+ _scene->_sequences.updateTimeout(-1, _globals._sequenceIndexes[3]);
+
+ _game._player._visible = true;
+ _game._player._stepEnabled = true;
+ break;
+
+ default:
+ break;
+ }
+ }
+ } else if (_action._lookFlag)
+ _vm->_dialogs->show(50328);
+ else if (_action.isAction(VERB_LOOK, NOUN_MONITORING_EQUIPMENT))
+ _vm->_dialogs->show(50310);
+ else if (_action.isAction(VERB_LOOK, NOUN_PHOTON_RIFLES))
+ _vm->_dialogs->show(50311);
+ else if (_action.isAction(VERB_TAKE, NOUN_PHOTON_RIFLES) || _action.isAction(VERB_TAKE, NOUN_NUCLEAR_SLINGSHOT))
+ _vm->_dialogs->show(50312);
+ else if (_action.isAction(VERB_LOOK, NOUN_DISPLAY_CASE))
+ _vm->_dialogs->show(50313);
+ else if (_action.isAction(VERB_LOOK, NOUN_NUCLEAR_SLINGSHOT))
+ _vm->_dialogs->show(50314);
+ else if (_action.isAction(VERB_LOOK, NOUN_WATER_COOLER))
+ _vm->_dialogs->show(50315);
+ else if (_action.isAction(VERB_LOOK, NOUN_STORAGE_BOX))
+ _vm->_dialogs->show(50316);
+ else if (_action.isAction(VERB_OPEN, NOUN_STORAGE_BOX))
+ _vm->_dialogs->show(50317);
+ else if (_action.isAction(VERB_LOOK, NOUN_WARNING_LABEL))
+ _vm->_dialogs->show(50318);
+ else if (_action.isAction(VERB_LOOK, NOUN_DESK))
+ _vm->_dialogs->show(50319);
+ else if (_action.isAction(VERB_LOOK, NOUN_MONITOR))
+ _vm->_dialogs->show(50320);
+ else if (_action.isAction(VERB_LOOK, NOUN_FILE_CABINETS))
+ _vm->_dialogs->show(50322);
+ else if (_action.isAction(VERB_LOOK, NOUN_BOX)) {
+ if (_game._objects.isInRoom(OBJ_DETONATORS))
+ _vm->_dialogs->show(50323);
+ else
+ _vm->_dialogs->show(50324);
+ } else if (_action.isAction(VERB_LOOK, NOUN_DETONATORS) && (_action._savedFields._mainObjectSource == 4))
+ _vm->_dialogs->show(50325);
+ else if (_action.isAction(VERB_LOOK, NOUN_WINDOWS))
+ _vm->_dialogs->show(50327);
+ else if (_action.isAction(VERB_OPEN, NOUN_DISPLAY_CASE))
+ _vm->_dialogs->show(50329);
+ else if (_action.isAction(VERB_THROW, NOUN_DISPLAY_CASE) && _game._objects.isInInventory(_game._objects.getIdFromDesc(_action._activeAction._objectNameId)))
+ _vm->_dialogs->show(50330);
+ else
+ return;
+
+ _action._inProgress = false;
+}
+
+/*------------------------------------------------------------------------*/
+
+Scene504::Scene504(MADSEngine *vm) : Scene5xx(vm) {
+ _carAnimationMode = -1;
+ _carFrame = -1;
+}
+
+void Scene504::synchronize(Common::Serializer &s) {
+ Scene5xx::synchronize(s);
+
+ s.syncAsSint16LE(_carAnimationMode);
+ s.syncAsSint16LE(_carFrame);
+}
+
+void Scene504::setup() {
+ _game._player._spritesPrefix = "";
+ setAAName();
+}
+
+void Scene504::enter() {
+ _globals._spriteIndexes[2] = _scene->_sprites.addSprites(formAnimName('a', 2));
+
+ for (int i = 0; i < 4; i++)
+ _globals._spriteIndexes[5 + i] = _scene->_sprites.addSprites(formAnimName('m', i));
+
+ if (_globals[kSexOfRex] == REX_MALE)
+ _globals._spriteIndexes[1] = _scene->_sprites.addSprites(formAnimName('a', 0));
+ else {
+ _globals._spriteIndexes[1] = _scene->_sprites.addSprites(formAnimName('a', 1));
+ _scene->changeVariant(1);
+ }
+
+ _globals._sequenceIndexes[1] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[1], false, 6, 1, 0, 0);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 0);
+ _globals._sequenceIndexes[2] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[2], false, 6, 0, 0, 0);
+ _carFrame = -1;
+
+ if ((_scene->_priorSceneId == 505) && (_globals[kHoverCarDestination] != _globals[kHoverCarLocation])){
+ _carAnimationMode = 1;
+ _scene->loadAnimation(formAnimName('A', -1));
+ _vm->_sound->command(14);
+ _scene->_sequences.addTimer(1, 70);
+ _game._player._stepEnabled = false;
+ } else {
+ _globals._spriteIndexes[3] = _scene->_sprites.addSprites(formAnimName('a', 3));
+ _carAnimationMode = 1;
+ _scene->loadAnimation(formAnimName('A', -1));
+ if ((_scene->_priorSceneId != -2) && (_scene->_priorSceneId != 505))
+ _globals[kHoverCarLocation] = _scene->_priorSceneId;
+
+ _globals._sequenceIndexes[7] = _scene->_sequences.startCycle(_globals._spriteIndexes[7], false, 1);
+ }
+
+ if (_globals[kTimebombTimer] > 10500)
+ _globals[kTimebombTimer] = 10500;
+
+ sceneEntrySound();
+}
+
+void Scene504::step() {
+ if ((_carAnimationMode == 1) && (_scene->_activeAnimation != nullptr)) {
+ if (_scene->_activeAnimation->getCurrentFrame() != _carFrame) {
+ _carFrame = _scene->_activeAnimation->getCurrentFrame();
+ int nextFrame;
+
+ if (_carFrame == 1)
+ nextFrame = 0;
+ else
+ nextFrame = -1;
+
+ if ((nextFrame >= 0) && (nextFrame != _scene->_activeAnimation->getCurrentFrame())) {
+ _scene->_activeAnimation->setCurrentFrame(nextFrame);
+ _carFrame = nextFrame;
+ }
+ }
+ }
+
+
+ if (_game._trigger >= 70) {
+ switch (_game._trigger) {
+ case 70:
+ if (_globals[kHoverCarDestination] != -1) {
+ _game._player._stepEnabled = false;
+ _scene->freeAnimation();
+ _carAnimationMode = 2;
+ if (((_globals[kHoverCarLocation] >= 500 && _globals[kHoverCarLocation] <= 599) &&
+ (_globals[kHoverCarDestination] >= 500 && _globals[kHoverCarDestination] <= 599)) ||
+ ((_globals[kHoverCarLocation] >= 600 && _globals[kHoverCarLocation] <= 699) &&
+ (_globals[kHoverCarDestination] >= 600 && _globals[kHoverCarDestination] <= 699))) {
+ _scene->loadAnimation(formAnimName('A', -1), 71);
+ } else if (_globals[kHoverCarLocation] > _globals[kHoverCarDestination])
+ _scene->loadAnimation(formAnimName('C', -1), 71);
+ else
+ _scene->loadAnimation(formAnimName('B', -1), 71);
+ }
+ break;
+
+ case 71:
+ _vm->_sound->command(15);
+ _scene->_nextSceneId = _globals[kHoverCarDestination];
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ if ((_globals[kTimebombTimer] >= 10800) && (_globals[kTimebombStatus] == TIMEBOMB_ACTIVATED) && (_game._difficulty != 3)) {
+ _globals[kTimebombStatus] = TIMEBOMB_DEAD;
+ _globals[kTimebombTimer] = 0;
+ _globals[kCheckDaemonTimebomb] = false;
+ _scene->_nextSceneId = 620;
+ }
+}
+
+void Scene504::preActions() {
+ _game._player._needToWalk = false;
+}
+
+void Scene504::actions() {
+ if (_action.isAction(VERB_EXIT_FROM, NOUN_CAR)) {
+ _vm->_sound->command(15);
+ _scene->_nextSceneId = _globals[kHoverCarLocation];
+ } else if (_action.isAction(VERB_ACTIVATE, NOUN_CAR_CONTROLS)) {
+ switch (_game._trigger) {
+ case 0:
+ _game._player._stepEnabled = false;
+ _vm->_sound->command(39);
+ _globals._sequenceIndexes[3] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[3], false, 6, 1, 0, 0);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 13);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[3], SEQUENCE_TRIGGER_EXPIRE, 0, 1);
+ _scene->_sequences.remove(_globals._sequenceIndexes[7]);
+ _globals._sequenceIndexes[5] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[5], false, 18, 0, 0, 0);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[5], 14);
+ break;
+
+ case 1: {
+ int syncIdx = _globals._sequenceIndexes[3];
+ _globals._sequenceIndexes[3] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[3], false, 6, 1, 0, 0);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 13);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[3], 1, 6);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[3], SEQUENCE_TRIGGER_EXPIRE, 0, 2);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[3], syncIdx);
+ }
+ break;
+
+ case 2:
+ _scene->_sequences.addTimer(10, 3);
+ break;
+
+ case 3:
+ _scene->_sequences.remove(_globals._sequenceIndexes[5]);
+ if (_globals[kSexOfRex] == REX_MALE) {
+ _vm->_sound->command(34);
+ _scene->_sequences.addTimer(60, 4);
+ _globals._sequenceIndexes[6] = _scene->_sequences.startCycle(_globals._spriteIndexes[6], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[6], 14);
+ } else {
+ _vm->_sound->command(40);
+ _globals._sequenceIndexes[8] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[8], false, 18, 0, 0, 0);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[8], 14);
+ _scene->_sequences.addTimer(120, 5);
+ }
+ break;
+
+ case 4:
+ _game._player._stepEnabled = true;
+ _globals[kHoverCarDestination] = _globals[kHoverCarLocation];
+ _scene->_nextSceneId = 505;
+ break;
+
+ case 5:
+ _game._player._stepEnabled = true;
+ _scene->_sequences.remove(_globals._sequenceIndexes[8]);
+ _globals._sequenceIndexes[7] = _scene->_sequences.startCycle(_globals._spriteIndexes[7], false, 1);
+ _vm->_dialogs->show(50421);
+ break;
+
+ default:
+ break;
+ }
+ } else if (_action._lookFlag || _action.isAction(VERB_LOOK, NOUN_INTERIOR_OF_CAR))
+ _vm->_dialogs->show(50412);
+ else if (_action.isAction(VERB_LOOK, NOUN_GLOVE_COMPARTMENT))
+ _vm->_dialogs->show(50410);
+ else if (_action.isAction(VERB_LOOK, NOUN_CAR_CONTROLS) || _action.isAction(VERB_LOOK, NOUN_DASHBOARD))
+ _vm->_dialogs->show(50411);
+ else if (_action.isAction(VERB_LOOK, NOUN_SCENT_PACKET))
+ _vm->_dialogs->show(50413);
+ else if (_action.isAction(VERB_LOOK, NOUN_SODA_CANS))
+ _vm->_dialogs->show(50414);
+ else if (_action.isAction(VERB_LOOK, NOUN_KITTY))
+ _vm->_dialogs->show(50415);
+ else if (_action.isAction(VERB_LOOK, NOUN_WINDSHIELD) || _action.isAction(VERB_LOOK_THROUGH, NOUN_WINDSHIELD))
+ _vm->_dialogs->show(50416);
+ else if (_action.isAction(VERB_LOOK, NOUN_REARVIEW_MIRROR))
+ _vm->_dialogs->show(50417);
+ else if (_action.isAction(VERB_TAKE, NOUN_REARVIEW_MIRROR))
+ _vm->_dialogs->show(50418);
+ else if (_action.isAction(VERB_LOOK, NOUN_MOLDY_SOCK))
+ _vm->_dialogs->show(50419);
+ else if (_action.isAction(VERB_TAKE, NOUN_MOLDY_SOCK))
+ _vm->_dialogs->show(50420);
+ else
+ return;
+
+ _action._inProgress = false;
+}
+
+/*------------------------------------------------------------------------*/
+
+Scene505::Scene505(MADSEngine *vm) : Scene5xx(vm) {
+ _frame = -1;
+ _nextButtonId = -1;
+ _homeSelectedId = -1;
+ _selectedId = -1;
+ _activeCars = -1;
+
+ for (int i = 0; i < 9; i++)
+ _carLocations[i] = -1;
+}
+
+void Scene505::synchronize(Common::Serializer &s) {
+ Scene5xx::synchronize(s);
+
+ s.syncAsSint16LE(_frame);
+ s.syncAsSint16LE(_nextButtonId);
+ s.syncAsSint16LE(_homeSelectedId);
+ s.syncAsSint16LE(_selectedId);
+ s.syncAsSint16LE(_activeCars);
+
+ for (int i = 0; i < 9; i++)
+ s.syncAsSint16LE(_carLocations[i]);
+}
+
+void Scene505::setup() {
+ _game._player._spritesPrefix = "";
+ setAAName();
+}
+
+void Scene505::enter() {
+ for (int i = 0; i < 9; i++)
+ _globals._spriteIndexes[i] = _scene->_sprites.addSprites(formAnimName('a', i + 1));
+
+ _globals._spriteIndexes[13] = _scene->_sprites.addSprites(formAnimName('b', 1));
+ _globals._spriteIndexes[9] = _scene->_sprites.addSprites(formAnimName('g', 1));
+ _globals._spriteIndexes[10] = _scene->_sprites.addSprites(formAnimName('g', 0));
+ _globals._spriteIndexes[11] = _scene->_sprites.addSprites(formAnimName('t', -1));
+ _globals._spriteIndexes[12] = _scene->_sprites.addSprites(formAnimName('e', -1));
+
+ if (_scene->_priorSceneId != -2)
+ _globals._sequenceIndexes[12] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[12], false, 6, 1, 0, 0);
+
+ _globals._sequenceIndexes[13] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[13], false, 6, 1, 120, 0);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[13], SEQUENCE_TRIGGER_EXPIRE, 0, 60);
+ _scene->_sequences.addTimer(30, 62);
+
+ _carLocations[0] = 501;
+ _carLocations[1] = 506;
+ _carLocations[2] = 511;
+ _carLocations[3] = 513;
+ _carLocations[4] = 601;
+ _carLocations[5] = 604;
+ _carLocations[6] = 607;
+ _carLocations[7] = 609;
+ _carLocations[8] = 612;
+
+ _activeCars = false;
+
+ for (int i = 0; i < 9; i++) {
+ if (_globals[kHoverCarLocation] == _carLocations[i]) {
+ _homeSelectedId = i;
+ if (_scene->_priorSceneId != -2)
+ _selectedId = i;
+ }
+ }
+
+ _game._player._visible = false;
+ _game._player._stepEnabled = false;
+ _frame = -1;
+ _scene->loadAnimation(formAnimName('a', -1));
+ _scene->_activeAnimation->setCurrentFrame(86);
+
+ sceneEntrySound();
+ _vm->_sound->command(16);
+}
+
+void Scene505::step() {
+ if (_frame != _scene->_activeAnimation->getCurrentFrame()) {
+ _frame = _scene->_activeAnimation->getCurrentFrame();
+ int resetFrame = -1;
+
+ switch (_frame) {
+ case 4:
+ case 24:
+ case 33:
+ case 53:
+ case 62:
+ case 82:
+ if (_nextButtonId == 0x38A)
+ resetFrame = 4;
+ else if (_nextButtonId == 0x38B)
+ resetFrame = 33;
+ else if (_nextButtonId == 0x2DE)
+ resetFrame = 62;
+
+ break;
+
+ case 15:
+ case 44:
+ case 73: {
+ int this_button;
+ int old_select;
+ _vm->_sound->command(17);
+ old_select = _selectedId;
+ if (_frame == 15) {
+ this_button = 0x38A;
+ _selectedId = (_selectedId + 1) % 9;
+ } else if (_frame == 44) {
+ this_button = 0x38B;
+ _selectedId--;
+ if (_selectedId < 0)
+ _selectedId = 8;
+ } else {
+ this_button = 0x2DE;
+ if ((_globals[kTimebombStatus] == TIMEBOMB_ACTIVATED) && (_carLocations[_selectedId] == 501))
+ _vm->_dialogs->show(431);
+ else if (_selectedId != _homeSelectedId) {
+ _nextButtonId = 0;
+ _activeCars = true;
+ _game._player._stepEnabled = false;
+ _scene->_sequences.remove(_globals._sequenceIndexes[1]);
+ _scene->_sequences.remove(_globals._sequenceIndexes[0]);
+ _scene->_sequences.remove(_globals._sequenceIndexes[13]);
+ _globals._sequenceIndexes[13] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[13], false, 6, 1, 0, 0);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[13], SEQUENCE_TRIGGER_EXPIRE, 0, 63);
+ _vm->_sound->command(18);
+ }
+ }
+
+ if (_nextButtonId == this_button)
+ _nextButtonId = 0;
+
+ if (old_select != _selectedId) {
+ _scene->_sequences.remove(_globals._sequenceIndexes[11]);
+ _globals._sequenceIndexes[11] = _scene->_sequences.startCycle(_globals._spriteIndexes[11], false, _selectedId + 1);
+ if (old_select != _homeSelectedId)
+ _scene->_sequences.remove(_globals._sequenceIndexes[0]);
+
+ if (_selectedId != _homeSelectedId) {
+ _globals._sequenceIndexes[0] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[0 + _selectedId], false, 24, 0, 0, 0);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[0], 1);
+ }
+ }
+ break;
+ }
+
+ case 18:
+ case 19:
+ case 20:
+ case 21:
+ case 22:
+ case 23:
+ if (_nextButtonId == 0x38A)
+ resetFrame = 29 - _frame;
+
+ break;
+
+ case 26:
+ case 55:
+ case 84:
+ if (_nextButtonId != 0)
+ resetFrame = 3;
+
+ break;
+
+ case 27:
+ case 56:
+ case 85:
+ if (_nextButtonId != 0)
+ resetFrame = 2;
+
+ break;
+
+ case 29:
+ case 58:
+ case 87:
+ if (_activeCars)
+ _globals[kHoverCarDestination] = _carLocations[_selectedId];
+
+ if (_nextButtonId == 0x38A)
+ resetFrame = 0;
+ else if (_nextButtonId == 0x38B)
+ resetFrame = 29;
+ else if (_nextButtonId == 0x2DE)
+ resetFrame = 58;
+ else
+ resetFrame = 86;
+ break;
+
+ case 47:
+ case 48:
+ case 49:
+ case 50:
+ case 51:
+ case 52:
+ if (_nextButtonId == 0x38B)
+ resetFrame = 87 - _frame;
+
+ break;
+
+ case 76:
+ case 77:
+ case 78:
+ case 79:
+ case 80:
+ case 81:
+ if (_nextButtonId == 0x2DE)
+ resetFrame = 145 - _frame;
+
+ break;
+
+ default:
+ break;
+ }
+
+ if ((resetFrame >= 0) && (resetFrame != _scene->_activeAnimation->getCurrentFrame())) {
+ _scene->_activeAnimation->setCurrentFrame(resetFrame);
+ _frame = resetFrame;
+ }
+ }
+
+ switch (_game._trigger) {
+ case 60: {
+ _game._player._stepEnabled = true;
+ int syncIdx = _globals._sequenceIndexes[13];
+ _globals._sequenceIndexes[13] = _scene->_sequences.startCycle(_globals._spriteIndexes[13], false, -2);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[13], 8);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[13], syncIdx);
+ _globals._sequenceIndexes[1] = _scene->_sequences.startCycle(_globals._spriteIndexes[_homeSelectedId], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 1);
+ _globals._sequenceIndexes[11] = _scene->_sequences.startCycle(_globals._spriteIndexes[11], false, _selectedId + 1);
+
+ if (_selectedId != _homeSelectedId) {
+ _globals._sequenceIndexes[0] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[0 + _selectedId], false, 24, 0, 0, 0);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[0], 1);
+ }
+ break;
+ }
+
+ case 61:
+ _globals._sequenceIndexes[10] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[10], false, 8, 0, 0, 0);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[10], 8);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[10], _globals._sequenceIndexes[9]);
+ break;
+
+ case 62:
+ _globals._sequenceIndexes[9] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[9], false, 8, 1, 0, 0);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[9], 8);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[9], SEQUENCE_TRIGGER_EXPIRE, 0, 61);
+ break;
+
+ case 63:
+ _globals[kHoverCarDestination] = _carLocations[_selectedId];
+ _scene->_nextSceneId = 504;
+ break;
+
+ default:
+ break;
+ }
+}
+
+void Scene505::actions() {
+ if (_action.isAction(VERB_PRESS))
+ _nextButtonId = _action._activeAction._objectNameId;
+ else if (_action.isAction(VERB_RETURN_TO, NOUN_INSIDE_OF_CAR))
+ _scene->_nextSceneId = 504;
+ else if (_action.isAction(VERB_LOOK, NOUN_VIEW_SCREEN))
+ _vm->_dialogs->show(50510);
+ else if (_action.isAction(VERB_LOOK, NOUN_CONTROL_PANEL))
+ _vm->_dialogs->show(50511);
+ else
+ return;
+
+ _action._inProgress = false;
+}
+
+/*------------------------------------------------------------------------*/
+
+Scene506::Scene506(MADSEngine *vm) : Scene5xx(vm), _doorPos(0, 0) {
+ _heroFacing = FACING_DUMMY;
+
+ _doorDepth = -1;
+ _doorSpriteIdx = -1;
+ _doorSequenceIdx = -1;
+ _doorWord = -1;
+
+ _labDoorFl = false;
+ _firstDoorFl = false;
+ _actionFl = false;
+}
+
+void Scene506::synchronize(Common::Serializer &s) {
+ Scene5xx::synchronize(s);
+
+ s.syncAsSint16LE(_doorPos.x);
+ s.syncAsSint16LE(_doorPos.y);
+
+ s.syncAsByte(_heroFacing);
+
+ s.syncAsSint16LE(_doorDepth);
+ s.syncAsSint16LE(_doorSpriteIdx);
+ s.syncAsSint16LE(_doorSequenceIdx);
+ s.syncAsSint16LE(_doorWord);
+
+ s.syncAsByte(_labDoorFl);
+ s.syncAsByte(_firstDoorFl);
+ s.syncAsByte(_actionFl);
+}
+
+void Scene506::setup() {
+ setPlayerSpritesPrefix();
+ setAAName();
+ _scene->addActiveVocab(VERB_WALK_INTO);
+ _scene->addActiveVocab(NOUN_SOFTWARE_STORE);
+ _scene->addActiveVocab(NOUN_LABORATORY);
+}
+
+void Scene506::enter() {
+ _globals._spriteIndexes[1] = _scene->_sprites.addSprites(formAnimName('q', 0));
+ _globals._spriteIndexes[2] = _scene->_sprites.addSprites(formAnimName('q', 1));
+ _globals._spriteIndexes[3] = _scene->_sprites.addSprites(formAnimName('c', -1));
+ _globals._spriteIndexes[4] = _scene->_sprites.addSprites("*RXCD_3");
+
+ _globals._sequenceIndexes[1] = _scene->_sequences.startCycle(_globals._spriteIndexes[1], false, 1);
+ int idx = _scene->_dynamicHotspots.add(NOUN_LABORATORY, 0x242, _globals._sequenceIndexes[1], Common::Rect(0, 0, 0, 0));
+ int hotspotId = _scene->_dynamicHotspots.setPosition(idx, Common::Point(65, 125), FACING_NORTHWEST);
+ _scene->_dynamicHotspots.setCursor(hotspotId, CURSOR_GO_LEFT);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 10);
+ _globals._sequenceIndexes[2] = _scene->_sequences.startCycle(_globals._spriteIndexes[2], false, 1);
+ idx = _scene->_dynamicHotspots.add(NOUN_SOFTWARE_STORE, 0x242, _globals._sequenceIndexes[2], Common::Rect(0, 0, 0, 0));
+ hotspotId = _scene->_dynamicHotspots.setPosition(idx, Common::Point(112, 102), FACING_NORTHWEST);
+ _scene->_dynamicHotspots.setCursor(hotspotId, CURSOR_GO_LEFT);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 13);
+
+ _globals._sequenceIndexes[3] = _scene->_sequences.startCycle(_globals._spriteIndexes[3], false, -1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 5);
+ _firstDoorFl = true;
+ _actionFl = false;
+
+ if (_scene->_priorSceneId == 508) {
+ _game._player._playerPos = Common::Point(16, 111);
+ _game._player._facing = FACING_SOUTHEAST;
+ _scene->_sequences.addTimer(15, 80);
+ _game._player._stepEnabled = false;
+ } else if (_scene->_priorSceneId == 507) {
+ _game._player._playerPos = Common::Point(80, 102);
+ _game._player._facing = FACING_SOUTHEAST;
+ _scene->_sequences.addTimer(60, 80);
+ _game._player._stepEnabled = false;
+ } else if (_scene->_priorSceneId != -2) {
+ _game._player._playerPos = Common::Point(138, 116);
+ _game._player._facing = FACING_NORTHEAST;
+ _game._player._visible = false;
+ _game._player._stepEnabled = false;
+ _scene->_sequences.remove(_globals._sequenceIndexes[3]);
+ _globals._sequenceIndexes[3] = _scene->_sequences.startCycle(_globals._spriteIndexes[3], false, -2);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 5);
+ _scene->loadAnimation(formAnimName('R', 1), 70);
+ }
+ sceneEntrySound();
+}
+
+void Scene506::step() {
+ if (_game._trigger >= 80) {
+ if (_firstDoorFl) {
+ _heroFacing = FACING_SOUTHEAST;
+ if (_scene->_priorSceneId == 507) {
+ _doorPos = Common::Point(112, 102);
+ _doorWord = 0x336;
+ } else {
+ _doorPos = Common::Point(65, 125);
+ _doorWord = 0x37D;
+ }
+ }
+ handleDoorSequences();
+ }
+
+ if (_game._trigger >= 70) {
+ switch (_game._trigger) {
+ case 70:
+ _game._player._visible = true;
+ _game._player._priorTimer = _scene->_activeAnimation->getNextFrameTimer() - _game._player._ticksAmount;
+ _scene->_sequences.addTimer(6, 71);
+ break;
+
+ case 71:
+ _scene->_sequences.remove(_globals._sequenceIndexes[3]);
+ _globals._sequenceIndexes[3] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[3], false, 6, 1, 0, 0);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 5);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[3], SEQUENCE_TRIGGER_EXPIRE, 0, 72);
+ break;
+
+ case 72:
+ _globals._sequenceIndexes[3] = _scene->_sequences.startCycle(_globals._spriteIndexes[3], false, -1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 5);
+ _game._player._stepEnabled = true;
+ break;
+
+ default:
+ break;
+ }
+ }
+}
+
+void Scene506::handleDoorSequences() {
+ _game._triggerSetupMode = SEQUENCE_TRIGGER_DAEMON;
+
+ if (_firstDoorFl) {
+ if (_action.isAction(VERB_WALK_INTO, NOUN_SOFTWARE_STORE) || ((_scene->_priorSceneId == 507) && !_actionFl)) {
+ _doorDepth = 13;
+ _doorSpriteIdx = _globals._spriteIndexes[2];
+ _doorSequenceIdx = _globals._sequenceIndexes[2];
+ _labDoorFl = false;
+ } else {
+ _doorDepth = 10;
+ _doorSpriteIdx = _globals._spriteIndexes[1];
+ _doorSequenceIdx = _globals._sequenceIndexes[1];
+ _labDoorFl = true;
+ }
+ _firstDoorFl = false;
+ }
+
+ switch (_game._trigger) {
+ case 0:
+ case 80:
+ _game._player._stepEnabled = false;
+ _scene->_sequences.remove(_doorSequenceIdx);
+ _doorSequenceIdx = _scene->_sequences.addSpriteCycle(_doorSpriteIdx, false, 7, 1, 0, 0);
+ _scene->_sequences.setDepth(_doorSequenceIdx, _doorDepth);
+ _scene->changeVariant(1);
+ _scene->_sequences.addSubEntry(_doorSequenceIdx, SEQUENCE_TRIGGER_EXPIRE, 0, 81);
+ break;
+
+
+ case 81:
+ _doorSequenceIdx = _scene->_sequences.startCycle(_doorSpriteIdx, false, -2);
+ _scene->_sequences.setDepth(_doorSequenceIdx, _doorDepth);
+ _game._player._walkAnywhere = true;
+ _game._player.walk(_doorPos, _heroFacing);
+ _scene->_sequences.addTimer(120, 82);
+ break;
+
+ case 82:
+ _scene->_sequences.remove(_doorSequenceIdx);
+ _doorSequenceIdx = _scene->_sequences.startReverseCycle(_doorSpriteIdx, false, 7, 1, 0, 0);
+ _scene->_sequences.setDepth(_doorSequenceIdx, _doorDepth);
+ if (_actionFl)
+ _scene->_sequences.addSubEntry(_doorSequenceIdx, SEQUENCE_TRIGGER_EXPIRE, 0, 84);
+ else
+ _scene->_sequences.addSubEntry(_doorSequenceIdx, SEQUENCE_TRIGGER_EXPIRE, 0, 83);
+
+ break;
+
+ case 83: {
+ _doorSequenceIdx = _scene->_sequences.startCycle(_doorSpriteIdx, false, 1);
+ int idx = _scene->_dynamicHotspots.add(_doorWord, 0x242, _doorSequenceIdx, Common::Rect(0, 0, 0, 0));
+ int hotspotId = _scene->_dynamicHotspots.setPosition(idx, _doorPos, FACING_NORTHWEST);
+ _scene->_dynamicHotspots.setCursor(hotspotId, CURSOR_GO_LEFT);
+ _scene->_sequences.setDepth(_doorSequenceIdx, _doorDepth);
+ _firstDoorFl = true;
+ if (_labDoorFl) {
+ _globals._spriteIndexes[1] = _doorSpriteIdx;
+ _globals._sequenceIndexes[1] = _doorSequenceIdx;
+ } else {
+ _globals._spriteIndexes[2] = _doorSpriteIdx;
+ _globals._sequenceIndexes[2] = _doorSequenceIdx;
+ }
+ _game._player._stepEnabled = true;
+
+ }
+ break;
+
+ case 84:
+ _actionFl = false;
+ _game._player._stepEnabled = true;
+ if (_labDoorFl)
+ _scene->_nextSceneId = 508;
+ else
+ _scene->_nextSceneId = 507;
+
+ break;
+
+ default:
+ break;
+ }
+}
+
+void Scene506::actions() {
+ if (_action.isAction(VERB_WALK_INTO, NOUN_LABORATORY)) {
+ if (_firstDoorFl) {
+ _heroFacing = FACING_NORTHWEST;
+ _doorPos = Common::Point(16, 111);
+ }
+ _actionFl = true;
+ handleDoorSequences();
+ } else if (_action.isAction(VERB_WALK_INTO, NOUN_SOFTWARE_STORE)) {
+ if (_firstDoorFl) {
+ _heroFacing = FACING_NORTHWEST;
+ _doorPos = Common::Point(80, 102);
+ }
+ _actionFl = true;
+ handleDoorSequences();
+ } else if (_action.isAction(VERB_GET_INTO, NOUN_CAR)) {
+ switch (_game._trigger) {
+ case 0:
+ _game._player._stepEnabled = false;
+ _scene->_sequences.remove(_globals._sequenceIndexes[3]);
+ _globals._sequenceIndexes[3] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[3], false, 6, 1, 0, 0);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 5);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[3], SEQUENCE_TRIGGER_EXPIRE, 0, 1);
+ break;
+
+ case 1: {
+ int syncIdx = _globals._sequenceIndexes[3];
+ _globals._sequenceIndexes[3] = _scene->_sequences.startCycle(_globals._spriteIndexes[3], false, -2);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[3], syncIdx);
+ _scene->_sequences.addTimer(6, 2);
+ }
+ break;
+
+ case 2:
+ _game._player._visible = false;
+ _globals._sequenceIndexes[4] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[4], false, 10, 1, 0, 0);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[4]);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[4], SEQUENCE_TRIGGER_EXPIRE, 0, 3);
+ break;
+
+ case 3: {
+ int syncIdx = _globals._sequenceIndexes[4];
+ _globals._sequenceIndexes[4] = _scene->_sequences.startCycle(_globals._spriteIndexes[4], false, -2);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[4]);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[4], syncIdx);
+ _scene->_nextSceneId = 504;
+ }
+ break;
+
+ default:
+ break;
+ }
+ } else if (_action._lookFlag || _action.isAction(VERB_LOOK, NOUN_STREET))
+ _vm->_dialogs->show(50618);
+ else if (_action.isAction(VERB_LOOK, NOUN_RESTAURANT))
+ _vm->_dialogs->show(50610);
+ else if (_action.isAction(VERB_LOOK, NOUN_MOTEL))
+ _vm->_dialogs->show(50611);
+ else if (_action.isAction(VERB_LOOK, NOUN_CYCLE_SHOP))
+ _vm->_dialogs->show(50612);
+ else if (_action.isAction(VERB_LOOK, NOUN_AIR_BIKE))
+ _vm->_dialogs->show(50613);
+ else if (_action.isAction(VERB_TAKE, NOUN_AIR_BIKE))
+ _vm->_dialogs->show(50614);
+ else if (_action.isAction(VERB_LOOK, NOUN_SOFTWARE_STORE))
+ _vm->_dialogs->show(50615);
+ else if (_action.isAction(VERB_LOOK, NOUN_LABORATORY))
+ _vm->_dialogs->show(50616);
+ else if (_action.isAction(VERB_LOOK, NOUN_STREET_TO_WEST) || _action.isAction(VERB_WALK_DOWN, NOUN_STREET_TO_WEST))
+ _vm->_dialogs->show(50617);
+ else if (_action.isAction(VERB_LOOK, NOUN_SOFTWARE_STORE_SIGN))
+ _vm->_dialogs->show(50619);
+ else if (_action.isAction(VERB_LOOK, NOUN_CAR))
+ _vm->_dialogs->show(50620);
+ else if (_action.isAction(VERB_LOOK, NOUN_SKY))
+ _vm->_dialogs->show(50621);
+ else
+ return;
+
+ _action._inProgress = false;
+}
+
+/*------------------------------------------------------------------------*/
+
+Scene507::Scene507(MADSEngine *vm) : Scene5xx(vm) {
+ _penlightHotspotId = -1;
+}
+
+void Scene507::synchronize(Common::Serializer &s) {
+ Scene5xx::synchronize(s);
+
+ s.syncAsSint16LE(_penlightHotspotId);
+}
+
+void Scene507::setup() {
+ setPlayerSpritesPrefix();
+ setAAName();
+ _scene->addActiveVocab(NOUN_PENLIGHT);
+ _scene->addActiveVocab(VERB_WALKTO);
+}
+
+void Scene507::enter() {
+ _globals._spriteIndexes[1] = _scene->_sprites.addSprites(formAnimName('p', -1));
+ _globals._spriteIndexes[2] = _scene->_sprites.addSprites("*RXMRD_3");
+
+ if ((_game._difficulty != DIFFICULTY_EASY) && (_game._objects[OBJ_PENLIGHT]._roomNumber == _scene->_currentSceneId)) {
+ _globals._sequenceIndexes[1] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[1], false, 9, 0, 0, 0);
+ _penlightHotspotId = _scene->_dynamicHotspots.add(NOUN_PENLIGHT, VERB_WALKTO, _globals._sequenceIndexes[1], Common::Rect(0, 0, 0, 0));
+ _scene->_dynamicHotspots.setPosition(_penlightHotspotId, Common::Point(233, 152), FACING_SOUTHEAST);
+ }
+
+ if (_scene->_priorSceneId != -2) {
+ _game._player._playerPos = Common::Point(121, 147);
+ _game._player._facing = FACING_NORTH;
+ }
+
+ sceneEntrySound();
+}
+void Scene507::actions() {
+ if (_action.isAction(VERB_WALK_THROUGH, NOUN_ENTRANCE))
+ _scene->_nextSceneId = 506;
+ else if (_action.isAction(VERB_TAKE, NOUN_PENLIGHT)) {
+ if (_game._trigger || !_game._objects.isInInventory(OBJ_PENLIGHT)) {
+ switch (_game._trigger) {
+ case 0:
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._sequenceIndexes[2] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[2], false, 6, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[2], 1, 5);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[2]);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[2], SEQUENCE_TRIGGER_SPRITE, 5, 1);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[2], SEQUENCE_TRIGGER_EXPIRE, 0, 2);
+ break;
+
+ case 1:
+ _scene->_sequences.remove(_globals._sequenceIndexes[1]);
+ _scene->_dynamicHotspots.remove(_penlightHotspotId);
+ _vm->_sound->command(27);
+ _game._objects.addToInventory(OBJ_PENLIGHT);
+ _vm->_dialogs->showItem(OBJ_PENLIGHT, 50730);
+ break;
+
+ case 2:
+ _scene->_sequences.updateTimeout(-1, _globals._sequenceIndexes[2]);
+ _game._player._visible = true;
+ _game._player._stepEnabled = true;
+ break;
+
+ default:
+ break;
+ }
+ }
+ } else if (_action._lookFlag)
+ _vm->_dialogs->show(50722);
+ else if (_action.isAction(VERB_LOOK, NOUN_SWIRLING_LIGHT))
+ _vm->_dialogs->show(50710);
+ else if (_action.isAction(VERB_TAKE, NOUN_SWIRLING_LIGHT))
+ _vm->_dialogs->show(50711);
+ else if (_action.isAction(VERB_LOOK, NOUN_OLD_SOFTWARE))
+ _vm->_dialogs->show(50712);
+ else if (_action.isAction(VERB_TAKE, NOUN_OLD_SOFTWARE))
+ _vm->_dialogs->show(50713);
+ else if (_action.isAction(VERB_LOOK, NOUN_ADVERTISEMENT))
+ _vm->_dialogs->show(50714);
+ else if (_action.isAction(VERB_LOOK, NOUN_ADVERTISING_POSTER))
+ _vm->_dialogs->show(50715);
+ else if (_action.isAction(VERB_LOOK, NOUN_SIGN)) {
+ if (_scene->_customDest.x < 100)
+ _vm->_dialogs->show(50726);
+ else
+ _vm->_dialogs->show(50716);
+ } else if (_action.isAction(VERB_LOOK, NOUN_HOTTEST_SOFTWARE))
+ _vm->_dialogs->show(50717);
+ else if (_action.isAction(VERB_LOOK, NOUN_SOFTWARE_SHELF))
+ _vm->_dialogs->show(50718);
+ else if (_action.isAction(VERB_LOOK, NOUN_SENSOR))
+ _vm->_dialogs->show(50719);
+ else if (_action.isAction(VERB_LOOK, NOUN_CASH_REGISTER))
+ _vm->_dialogs->show(50720);
+ else if (_action.isAction(VERB_LOOK, NOUN_PAD_OF_PAPER))
+ _vm->_dialogs->show(50721);
+ else if (_action.isAction(VERB_OPEN, NOUN_CASH_REGISTER))
+ _vm->_dialogs->show(50723);
+ else if (_action.isAction(VERB_LOOK, NOUN_BARGAIN_VAT))
+ _vm->_dialogs->show(50724);
+ else if (_action.isAction(VERB_LOOK, NOUN_WINDOW))
+ _vm->_dialogs->show(50725);
+ else if (_action.isAction(VERB_LOOK, NOUN_COUNTER)) {
+ if (_game._objects.isInRoom(OBJ_PENLIGHT))
+ _vm->_dialogs->show(50728);
+ else
+ _vm->_dialogs->show(50727);
+ } else if (_action.isAction(VERB_LOOK, NOUN_PENLIGHT) && !_game._objects.isInInventory(OBJ_PENLIGHT)) {
+ if (_game._objects.isInRoom(OBJ_PENLIGHT))
+ _vm->_dialogs->show(50729);
+ } else if (_action.isAction(VERB_LOOK, NOUN_EMERGENCY_LIGHT))
+ _vm->_dialogs->show(50731);
+ else
+ return;
+
+ _action._inProgress = false;
+}
+
+/*------------------------------------------------------------------------*/
+
+Scene508::Scene508(MADSEngine *vm) : Scene5xx(vm) {
+ _chosenObject = -1;
+}
+
+void Scene508::synchronize(Common::Serializer &s) {
+ Scene5xx::synchronize(s);
+
+ s.syncAsSint16LE(_chosenObject);
+}
+
+void Scene508::setup() {
+ setPlayerSpritesPrefix();
+ setAAName();
+ _scene->addActiveVocab(NOUN_SPINACH_PATCH_DOLL);
+ _scene->addActiveVocab(VERB_WALKTO);
+ _scene->addActiveVocab(NOUN_LASER_BEAM);
+}
+
+void Scene508::enter() {
+ _globals._spriteIndexes[1] = _scene->_sprites.addSprites(formAnimName('a', 0));
+ _globals._spriteIndexes[2] = _scene->_sprites.addSprites(formAnimName('m', 0));
+ _globals._spriteIndexes[3] = _scene->_sprites.addSprites(formAnimName('h', 0));
+ _globals._spriteIndexes[4] = _scene->_sprites.addSprites(formAnimName('l', 2));
+ _globals._spriteIndexes[5] = _scene->_sprites.addSprites(formAnimName('t', 0));
+ _globals._spriteIndexes[6] = _scene->_sprites.addSprites("*RXMRC_9");
+ _globals._spriteIndexes[7] = _scene->_sprites.addSprites(formAnimName('l', 3));
+
+ if (!_game._visitedScenes._sceneRevisited) {
+ _globals[kLaserOn] = false;
+ _chosenObject = 0;
+ }
+
+ if (!_globals[kLaserOn]) {
+ _globals._sequenceIndexes[3] = _scene->_sequences.startCycle(_globals._spriteIndexes[3], false, -2);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 8);
+ _globals._sequenceIndexes[5] = _scene->_sequences.startCycle(_globals._spriteIndexes[5], false, -2);
+ int idx = _scene->_dynamicHotspots.add(NOUN_LASER_BEAM, VERB_WALKTO, _globals._sequenceIndexes[5], Common::Rect(0, 0, 0, 0));
+ _scene->_dynamicHotspots.setPosition(idx, Common::Point(57, 116), FACING_NORTHEAST);
+ _scene->_hotspots.activate(NOUN_HOLE, false);
+ _scene->_hotspots.activate(NOUN_LASER_BEAM, false);
+ } else {
+ _scene->changeVariant(1);
+ _globals._sequenceIndexes[3] = _scene->_sequences.startCycle(_globals._spriteIndexes[3], false, -2);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 8);
+ _globals._sequenceIndexes[4] = _scene->_sequences.startCycle(_globals._spriteIndexes[4], false, -2);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[4], 11);
+ int idx = _scene->_dynamicHotspots.add(NOUN_LASER_BEAM, VERB_WALKTO, _globals._sequenceIndexes[4], Common::Rect(0, 0, 0, 0));
+ _scene->_dynamicHotspots.setPosition(idx, Common::Point(57, 116), FACING_NORTHEAST);
+ _globals._sequenceIndexes[2] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[2], false, 15, 0, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[2], 6, 8);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 6);
+ if (_globals[kLaserHoleIsThere]) {
+ _globals._sequenceIndexes[7] = _scene->_sequences.startCycle(_globals._spriteIndexes[7], false, -2);
+ _scene->_hotspots.activate(NOUN_HOLE, true);
+ _scene->_hotspots.activate(NOUN_LASER_BEAM, true);
+ }
+ _vm->_sound->command(21);
+ }
+ _vm->_sound->command(20);
+
+ if (_scene->_priorSceneId == 515) {
+ _game._player._playerPos = Common::Point(57, 116);
+ _game._player._facing = FACING_NORTHEAST;
+ } else if (_scene->_priorSceneId != -2) {
+ _game._player._playerPos = Common::Point(289, 139);
+ _game._player._facing = FACING_WEST;
+ }
+
+ sceneEntrySound();
+ _game.loadQuoteSet(0x273, 0);
+
+ if (_scene->_roomChanged) {
+ _game._objects.addToInventory(OBJ_COMPACT_CASE);
+ _game._objects.addToInventory(OBJ_REARVIEW_MIRROR);
+ }
+}
+
+void Scene508::preActions() {
+ if (_action.isAction(VERB_WALK, NOUN_OUTSIDE))
+ _game._player._walkOffScreenSceneId = 506;
+}
+
+void Scene508::handlePedestral() {
+ if (!_globals[kLaserOn])
+ _vm->_dialogs->show(50835);
+
+ if (_globals[kLaserHoleIsThere])
+ _vm->_dialogs->show(50836);
+
+ if (_globals[kLaserOn] && !_globals[kLaserHoleIsThere]) {
+ switch (_game._trigger) {
+ case 0:
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._sequenceIndexes[6] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[6], false, 9, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[6], 1, 4);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[6]);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[6], SEQUENCE_TRIGGER_SPRITE, 4, 1);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[6], SEQUENCE_TRIGGER_EXPIRE, 0, 3);
+ break;
+
+ case 1:
+ if (_chosenObject == 2)
+ _game._objects.removeFromInventory(OBJ_COMPACT_CASE, 1);
+ else
+ _game._objects.removeFromInventory(OBJ_REARVIEW_MIRROR, 1);
+
+ _globals._sequenceIndexes[7] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[7], false, 6, 1, 0, 0);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[7], SEQUENCE_TRIGGER_EXPIRE, 0, 2);
+ break;
+
+ case 2:
+ _globals._sequenceIndexes[7] = _scene->_sequences.startCycle(_globals._spriteIndexes[7], false, -2);
+ _scene->_hotspots.activate(NOUN_HOLE, true);
+ _scene->_hotspots.activate(NOUN_LASER_BEAM, true);
+ break;
+
+ case 3:
+ _scene->_sequences.updateTimeout(-1, _globals._sequenceIndexes[6]);
+ _game._player._visible = true;
+ _scene->_sequences.addTimer(120, 4);
+ break;
+
+ case 4:
+ _vm->_dialogs->show(50834);
+ _globals[kLaserHoleIsThere] = true;
+ _scene->_nextSceneId = 515;
+ break;
+
+ default:
+ break;
+ }
+ }
+}
+
+void Scene508::actions() {
+ if (_action.isAction(VERB_PULL, NOUN_LEVER)) {
+ if (!_globals[kLaserOn]) {
+ switch (_game._trigger) {
+ case 0:
+ _game._player._stepEnabled = false;
+ _scene->_kernelMessages.reset();
+ _scene->_kernelMessages.add(Common::Point(0, 0), 0x1110, 34, 2, 120, _game.getQuote(0x273));
+ break;
+
+ case 2:
+ _game._player._visible = false;
+ _scene->_sequences.remove(_globals._sequenceIndexes[3]);
+ _globals._sequenceIndexes[1] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[1], false, 10, 1, 0, 0);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 7);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[1], -1);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[1], SEQUENCE_TRIGGER_EXPIRE, 0, 3);
+ break;
+
+ case 3:
+ _vm->_sound->command(19);
+ _globals._sequenceIndexes[2] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[2], false, 15, 1, 0, 0);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 6);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[2], SEQUENCE_TRIGGER_EXPIRE, 0, 4);
+ _globals._sequenceIndexes[3] = _scene->_sequences.startCycle(_globals._spriteIndexes[3], false, -2);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 8);
+ _scene->_sequences.updateTimeout(-1, _globals._sequenceIndexes[1]);
+ _game._player._visible = true;
+ _scene->_sequences.addTimer(15, 5);
+ break;
+
+ case 4:
+ _globals._sequenceIndexes[2] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[2], false, 15, 0, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[2], 6, 8);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 6);
+ break;
+
+ case 5:
+ _scene->_sequences.remove(_globals._sequenceIndexes[5]);
+ _scene->loadAnimation(formAnimName('B', 1), 6);
+ break;
+
+ case 6: {
+ _vm->_sound->command(22);
+ _globals._sequenceIndexes[4] = _scene->_sequences.startCycle(_globals._spriteIndexes[4], false, -2);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[4], 11);
+ int idx = _scene->_dynamicHotspots.add(NOUN_LASER_BEAM, VERB_WALKTO, _globals._sequenceIndexes[4], Common::Rect(0, 0, 0, 0));
+ _scene->_dynamicHotspots.setPosition(idx, Common::Point(57, 116), FACING_NORTHEAST);
+ _scene->_kernelMessages.reset();
+ _scene->changeVariant(1);
+ _scene->_sequences.addTimer(30, 7);
+ }
+ break;
+
+ case 7:
+ _globals[kLaserOn] = true;
+ _vm->_dialogs->show(50833);
+ _game._player._stepEnabled = true;
+ break;
+
+ default:
+ break;
+ }
+ } else {
+ _vm->_dialogs->show(50837);
+ }
+ } else if (_action.isAction(VERB_REFLECT, 0x120, 0x343) || _action.isAction(VERB_PUT, NOUN_REARVIEW_MIRROR, 0x344) || _action.isAction(VERB_PUT, NOUN_REARVIEW_MIRROR, 0x343)) {
+ _chosenObject = 1;
+ handlePedestral();
+ } else if (_action.isAction(VERB_PUT, NOUN_COMPACT_CASE, 0x344) || _action.isAction(VERB_PUT, NOUN_COMPACT_CASE, 0x343) || _action.isAction(VERB_REFLECT, 0x57, 0x343)) {
+ _chosenObject = 2;
+ handlePedestral();
+ } else if (_action._lookFlag)
+ _vm->_dialogs->show(50822);
+ else if (_action.isAction(VERB_LOOK, NOUN_TARGET_AREA))
+ _vm->_dialogs->show(50810);
+ else if (_action.isAction(VERB_LOOK, NOUN_SPINACH_PATCH_DOLL))
+ _vm->_dialogs->show(50811);
+ else if (_action.isAction(VERB_TAKE, NOUN_SPINACH_PATCH_DOLL))
+ _vm->_dialogs->show(50812);
+ else if (_action.isAction(VERB_LOOK, NOUN_SAND_BAGS))
+ _vm->_dialogs->show(50816);
+ else if (_action.isAction(VERB_TAKE, NOUN_SAND_BAGS))
+ _vm->_dialogs->show(50817);
+ else if (_action.isAction(VERB_LOOK, NOUN_CONTROL_STATION))
+ _vm->_dialogs->show(50818);
+ else if (_action.isAction(VERB_LOOK, NOUN_MONITOR)) {
+ if (_globals[kLaserOn])
+ _vm->_dialogs->show(50820);
+ else
+ _vm->_dialogs->show(50819);
+ } else if (_action.isAction(VERB_LOOK, NOUN_LASER_CANNON)) {
+ if (_globals[kLaserOn])
+ _vm->_dialogs->show(50822);
+ else
+ _vm->_dialogs->show(50821);
+ } else if (_action.isAction(VERB_TAKE, NOUN_LASER_CANNON))
+ _vm->_dialogs->show(50823);
+ else if (_action.isAction(VERB_LOOK, NOUN_LEVER)) {
+ if (_globals[kLaserOn])
+ _vm->_dialogs->show(50825);
+ else
+ _vm->_dialogs->show(50824);
+ } else if (_action.isAction(VERB_PUSH, NOUN_LEVER))
+ _vm->_dialogs->show(50826);
+ else if (_action.isAction(VERB_LOOK, NOUN_LASER_BEAM)) {
+ if (_globals[kLaserHoleIsThere])
+ _vm->_dialogs->show(50828);
+ else
+ _vm->_dialogs->show(50827);
+ } else if (_action.isAction(VERB_TAKE, NOUN_LASER_BEAM))
+ _vm->_dialogs->show(50829);
+ else if (_action.isAction(VERB_LOOK, NOUN_CEILING)) {
+ if (_globals[kLaserHoleIsThere])
+ _vm->_dialogs->show(50831);
+ else
+ _vm->_dialogs->show(50830);
+ } else if (_action.isAction(VERB_LOOK, NOUN_WALL))
+ _vm->_dialogs->show(50832);
+ else if (_action.isAction(VERB_LOOK, NOUN_PEDESTAL)) {
+ if (!_globals[kLaserOn])
+ _vm->_dialogs->show(50813);
+ else if (!_globals[kLaserHoleIsThere])
+ _vm->_dialogs->show(50814);
+ else
+ _vm->_dialogs->show(50815);
+ } else
+ return;
+
+ _action._inProgress = false;
+}
+
+/*------------------------------------------------------------------------*/
+
+Scene511::Scene511(MADSEngine *vm) : Scene5xx(vm) {
+ _handingLine = false;
+ _lineMoving = false;
+
+ _lineAnimationMode = -1;
+ _lineFrame = -1;
+ _lineAnimationPosition = -1;
+}
+
+void Scene511::synchronize(Common::Serializer &s) {
+ Scene5xx::synchronize(s);
+
+ s.syncAsByte(_handingLine);
+ s.syncAsByte(_lineMoving);
+
+ s.syncAsSint16LE(_lineAnimationMode);
+ s.syncAsSint16LE(_lineFrame);
+ s.syncAsSint16LE(_lineAnimationPosition);
+}
+
+void Scene511::setup() {
+ setPlayerSpritesPrefix();
+ setAAName();
+ _scene->addActiveVocab(NOUN_BOAT);
+ _scene->addActiveVocab(NOUN_FISHING_LINE);
+ _scene->addActiveVocab(VERB_WALKTO);
+}
+
+void Scene511::enter() {
+ _globals._spriteIndexes[1] = _scene->_sprites.addSprites(formAnimName('c', 0));
+ _globals._spriteIndexes[4] = _scene->_sprites.addSprites("*RXCD_6");
+
+ if (_scene->_priorSceneId != -2)
+ _handingLine = false;
+
+ if (_globals[kBoatRaised]) {
+ _globals._spriteIndexes[2] = _scene->_sprites.addSprites(formAnimName('b', 0));
+ _globals._sequenceIndexes[2] = _scene->_sequences.startCycle(_globals._spriteIndexes[2], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 3);
+ _scene->_hotspots.activate(NOUN_BOAT, false);
+ int idx = _scene->_dynamicHotspots.add(NOUN_BOAT, VERB_WALKTO, _globals._sequenceIndexes[2], Common::Rect(0, 0, 0, 0));
+ _scene->_dynamicHotspots.setPosition(idx, Common::Point(75, 124), FACING_NORTH);
+ _scene->_hotspots.activate(NOUN_ROPE, false);
+ } else {
+ _globals._spriteIndexes[5] = _scene->_sprites.addSprites(formAnimName('b', 2));
+ _globals._spriteIndexes[6] = _scene->_sprites.addSprites(formAnimName('b', 3));
+ _globals._spriteIndexes[3] = _scene->_sprites.addSprites(formAnimName('b', 1));
+
+ _globals._sequenceIndexes[3] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[3], false, 1, 1, 0, 0);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 5);
+
+ _globals._sequenceIndexes[5] = _scene->_sequences.startCycle(_globals._spriteIndexes[5], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[5], 4);
+
+ _globals._sequenceIndexes[6] = _scene->_sequences.startCycle(_globals._spriteIndexes[6], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[6],5);
+
+ _scene->_hotspots.activate(NOUN_ROPE, true);
+ _scene->_hotspots.activate(NOUN_BOAT, true);
+ _scene->changeVariant(1);
+ }
+
+ int frame = 0;
+ if (_globals[kLineStatus] == 2)
+ frame = -1;
+ else if (_globals[kLineStatus] == 3)
+ frame = -2;
+
+ if (_globals[kLineStatus] == 2 || _globals[kLineStatus] == 3) {
+ _globals._spriteIndexes[7] = _scene->_sprites.addSprites(formAnimName('b', 4));
+ _globals._sequenceIndexes[7] = _scene->_sequences.startCycle(_globals._spriteIndexes[7], false, frame);
+ int idx = _scene->_dynamicHotspots.add(NOUN_FISHING_LINE, VERB_WALKTO, _globals._sequenceIndexes[7], Common::Rect(0, 0, 0, 0));
+ _scene->_dynamicHotspots.setPosition(idx, Common::Point(26, 153), FACING_NORTHEAST);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[7], 3);
+ if (_globals[kBoatRaised])
+ _scene->changeVariant(2);
+ }
+
+ _lineFrame = -1;
+ _lineMoving = false;
+
+ _globals._sequenceIndexes[1] = _scene->_sequences.startCycle(_globals._spriteIndexes[1], false, -2);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 1);
+
+ if (_scene->_priorSceneId == 512) {
+ _game._player._playerPos = Common::Point(60, 112);
+ _game._player._facing = FACING_SOUTHEAST;
+ } else if (_scene->_priorSceneId != -2) {
+ _game._player._playerPos = Common::Point(55, 152);
+ _game._player._facing = FACING_NORTHWEST;
+ _game._player._visible = false;
+ _game._player._stepEnabled = false;
+ _scene->_sequences.remove(_globals._sequenceIndexes[1]);
+ _globals._sequenceIndexes[1] = _scene->_sequences.startCycle(_globals._spriteIndexes[1], false, -1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 1);
+ _scene->loadAnimation(formAnimName('R', 1), 70);
+ } else if (_handingLine) {
+ _game._player._visible = false;
+ _lineAnimationMode = 1;
+ _lineAnimationPosition = 1;
+ _scene->loadAnimation(formAnimName('R', -1));
+ _lineFrame = 2;
+ }
+ sceneEntrySound();
+}
+
+void Scene511::step() {
+ if ((_lineAnimationMode == 1) && _scene->_activeAnimation) {
+ if (_lineFrame != _scene->_activeAnimation->getCurrentFrame()) {
+ _lineFrame = _scene->_activeAnimation->getCurrentFrame();
+ int resetFrame = -1;
+
+ if ((_lineAnimationPosition == 2) && (_lineFrame == 14))
+ _lineMoving = false;
+
+ if (_lineAnimationPosition == 1) {
+ if (_lineFrame == 3) {
+ _lineMoving = false;
+ resetFrame = 2;
+ }
+
+ if (_handingLine)
+ resetFrame = 2;
+ }
+
+ if ((resetFrame >= 0) && (resetFrame != _scene->_activeAnimation->getCurrentFrame())) {
+ _scene->_activeAnimation->setCurrentFrame(resetFrame);
+ _lineFrame = resetFrame;
+ }
+ }
+ }
+
+ switch (_game._trigger) {
+ case 70:
+ _game._player._visible = true;
+ _game._player._priorTimer = _scene->_activeAnimation->getNextFrameTimer() - _game._player._ticksAmount;
+ _scene->_sequences.addTimer(6, 71);
+ break;
+
+ case 71:
+ _scene->_sequences.remove(_globals._sequenceIndexes[1]);
+ _globals._sequenceIndexes[1] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[1], false, 6, 1, 0, 0);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 1);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[1], SEQUENCE_TRIGGER_EXPIRE, 0, 72);
+ break;
+
+ case 72:
+ _globals._sequenceIndexes[1] = _scene->_sequences.startCycle(_globals._spriteIndexes[1], false, -2);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 1);
+ _game._player._stepEnabled = true;
+ break;
+
+ default:
+ break;
+ }
+}
+
+void Scene511::preActions() {
+ if (!_handingLine)
+ return;
+
+ if (_action.isAction(VERB_LOOK) || _action.isAction(0x87) || _action.isAction(VERB_TALKTO))
+ _game._player._needToWalk = false;
+
+ if ((!_action.isAction(0x170, 0x87, 0x345) || !_action.isAction(0x19, 0x87, 0x345)) && _game._player._needToWalk) {
+ if (_game._trigger == 0) {
+ _game._player._readyToWalk = false;
+ _game._player._stepEnabled = false;
+ _scene->freeAnimation ();
+ _lineAnimationMode = 2;
+ _scene->loadAnimation(formAnimName('R',2), 1);
+ } else if (_game._trigger == 1) {
+ _game._player._visible = true;
+ _game._player._priorTimer = _scene->_activeAnimation->getNextFrameTimer() - _game._player._ticksAmount;
+ _game._objects.setRoom(OBJ_FISHING_LINE, 1);
+ _handingLine = false;
+ _game._player._stepEnabled = true;
+ _game._player._readyToWalk = true;
+ }
+ }
+}
+
+void Scene511::actions() {
+ if (_action.isAction(VERB_WALK_INTO, NOUN_RESTAURANT))
+ _scene->_nextSceneId = 512;
+ else if (_action.isAction(VERB_GET_INTO, NOUN_CAR)) {
+ switch (_game._trigger) {
+ case 0:
+ _game._player._stepEnabled = false;
+ _scene->_sequences.remove(_globals._sequenceIndexes[1]);
+ _globals._sequenceIndexes[1] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[1], false, 6, 1, 0, 0);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 1);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[1], SEQUENCE_TRIGGER_EXPIRE, 0, 1);
+ break;
+
+ case 1: {
+ int syncIdx = _globals._sequenceIndexes[1];
+ _globals._sequenceIndexes[1] = _scene->_sequences.startCycle(_globals._spriteIndexes[1], false, -1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 1);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[1], syncIdx);
+ _scene->_sequences.addTimer(6, 2);
+ }
+ break;
+
+ case 2:
+ _game._player._visible = false;
+ _globals._sequenceIndexes[4] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[4], false, 8, 1, 0, 0);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[4]);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[4], SEQUENCE_TRIGGER_EXPIRE, 0, 3);
+ break;
+
+ case 3: {
+ int syncIdx = _globals._sequenceIndexes[4];
+ _globals._sequenceIndexes[4] = _scene->_sequences.startCycle(_globals._spriteIndexes[4], false, -2);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[4]);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[4], syncIdx);
+ _scene->_nextSceneId = 504;
+ }
+ break;
+
+ default:
+ break;
+ }
+ } else if (_action.isAction(VERB_TAKE, NOUN_FISHING_LINE)) {
+ if (!_globals[kBoatRaised]) {
+ if (_globals[kLineStatus] == 2) {
+ if (_globals[kLineStatus] != 3) {
+ if (_game._trigger == 0) {
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _lineAnimationMode = 1;
+ _lineAnimationPosition = 1;
+ _lineMoving = true;
+ _scene->loadAnimation(formAnimName('R', -1));
+ _scene->_sequences.addTimer(1, 1);
+ } else if (_game._trigger == 1) {
+ if (_lineMoving) {
+ _scene->_sequences.addTimer(1, 1);
+ } else {
+ _game._objects.addToInventory(OBJ_FISHING_LINE);
+ _lineMoving = true;
+ _handingLine = true;
+ _game._player._stepEnabled = true;
+ }
+ }
+ } else
+ _vm->_dialogs->show(51129);
+ } else
+ return;
+ } else {
+ _vm->_dialogs->show(51130);
+ }
+ } else if (_action.isAction(0x170, 0x87, 0x345) || _action.isAction(0x19, 0x87, 0x345)) {
+ if (_globals[kBoatRaised])
+ _vm->_dialogs->show(51131);
+ else if (_globals[kLineStatus] == 1)
+ _vm->_dialogs->show(51130);
+ else if (!_globals[kBoatRaised] && _handingLine) {
+ if (_globals[kLineStatus] != 3) {
+ if (_game._trigger == 0) {
+ _game._player._stepEnabled = false;
+ _scene->_sequences.remove(_globals._sequenceIndexes[7]);
+ _lineMoving = true;
+ _lineAnimationPosition = 2;
+ _scene->_sequences.addTimer(1, 1);
+ } else if (_game._trigger == 1) {
+ if (_lineMoving)
+ _scene->_sequences.addTimer(1, 1);
+ else {
+ _game._player._visible = true;
+ _game._player._priorTimer = _scene->_frameStartTime - _game._player._ticksAmount;
+ _globals._sequenceIndexes[7] = _scene->_sequences.startCycle(_globals._spriteIndexes[7], false, -2);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[7], 4);
+ int idx = _scene->_dynamicHotspots.add(NOUN_FISHING_LINE, VERB_WALKTO, _globals._sequenceIndexes[7], Common::Rect(0, 0, 0, 0));
+ _scene->_dynamicHotspots.setPosition(idx, Common::Point(26, 153), FACING_NORTHEAST);
+ _game._objects.removeFromInventory(OBJ_FISHING_LINE, 1);
+ _handingLine = false;
+ _lineMoving = true;
+ _globals[kLineStatus] = 3;
+ _game._player._stepEnabled = true;
+ }
+ }
+ }
+ }
+ } else if (_action.isAction(VERB_LOOK, NOUN_STREET) || _action._lookFlag) {
+ if (_globals[kLineStatus] == 2)
+ _vm->_dialogs->show(51110);
+ else {
+ if (_globals[kLineStatus] == 3)
+ _vm->_dialogs->show(51111);
+ else
+ _vm->_dialogs->show(51112);
+ }
+ } else if (_action.isAction(VERB_LOOK, NOUN_CAR))
+ _vm->_dialogs->show(51113);
+ else if (_action.isAction(VERB_LOOK, NOUN_SIDEWALK))
+ _vm->_dialogs->show(51114);
+ else if (_action.isAction(VERB_WALK_DOWN, NOUN_SIDEWALK_TO_EAST) || _action.isAction(VERB_WALK_DOWN, NOUN_SIDEWALK_TO_WEST) || _action.isAction(VERB_WALK_DOWN, NOUN_STREET_TO_EAST))
+ _vm->_dialogs->show(51115);
+ else if (_action.isAction(VERB_LOOK, NOUN_PLEASURE_DOME))
+ _vm->_dialogs->show(51116);
+ else if (_action.isAction(VERB_LOOK, NOUN_TICKET_BOOTH))
+ _vm->_dialogs->show(51117);
+ else if (_action.isAction(VERB_LOOK, NOUN_DOME_ENTRANCE))
+ _vm->_dialogs->show(51118);
+ else if (_action.isAction(VERB_UNLOCK, 0xFF, 0x37C) || _action.isAction(VERB_UNLOCK, 0x6F, 0x37C))
+ _vm->_dialogs->show(51119);
+ else if ( (_action.isAction(VERB_PUT) || _action.isAction(VERB_THROW))
+ && (_action.isAction(0x171) || _action.isAction(0x2A) || _action.isAction(0x2B))
+ && _action.isAction(0x37C))
+ _vm->_dialogs->show(51120);
+ else if (_action.isAction(VERB_LOOK, NOUN_RESTAURANT)) {
+ if (_globals[kBoatRaised])
+ _vm->_dialogs->show(51121);
+ else
+ _vm->_dialogs->show(51128);
+ } else if (_action.isAction(VERB_LOOK, NOUN_PORTHOLE))
+ _vm->_dialogs->show(51122);
+ else if (_action.isAction(VERB_LOOK, NOUN_FISHING_LINE) && (_action._mainObjectSource == 4) && (_globals[kLineStatus] == 2))
+ _vm->_dialogs->show(51126);
+ else if (_action.isAction(VERB_LOOK, NOUN_FISHING_LINE) && (_action._mainObjectSource == 4) && (_globals[kLineStatus] == 3))
+ _vm->_dialogs->show(51133);
+ else if (_action.isAction(VERB_LOOK, NOUN_STATUE))
+ _vm->_dialogs->show(51127);
+ else if (_action.isAction(VERB_LOOK, NOUN_BOAT))
+ if (_globals[kBoatRaised])
+ _vm->_dialogs->show(51123);
+ else if (_globals[kLineStatus] != 3)
+ _vm->_dialogs->show(51124);
+ else
+ _vm->_dialogs->show(51125);
+ else if (_action.isAction(VERB_LOOK, NOUN_FISHING_LINE) && (_globals[kLineStatus] == 3))
+ _vm->_dialogs->show(51125);
+ else
+ return;
+
+ _action._inProgress = false;
+}
+
+/*------------------------------------------------------------------------*/
+
+Scene512::Scene512(MADSEngine *vm) : Scene5xx(vm) {
+ _fishingRodHotspotId = -1;
+ _keyHotspotId = -1;
+}
+
+void Scene512::synchronize(Common::Serializer &s) {
+ Scene5xx::synchronize(s);
+
+ s.syncAsSint16LE(_fishingRodHotspotId);
+ s.syncAsSint16LE(_keyHotspotId);
+}
+
+void Scene512::setup() {
+ setPlayerSpritesPrefix();
+ setAAName();
+ _scene->addActiveVocab(NOUN_FISHING_ROD);
+ _scene->addActiveVocab(VERB_WALKTO);
+ _scene->addActiveVocab(NOUN_PADLOCK_KEY);
+ _scene->addActiveVocab(NOUN_REGISTER_DRAWER);
+}
+
+void Scene512::enter() {
+ _globals._spriteIndexes[1] = _scene->_sprites.addSprites(formAnimName('r', -1));
+ _globals._spriteIndexes[2] = _scene->_sprites.addSprites("*RXMRC_9");
+ _globals._spriteIndexes[8] = _scene->_sprites.addSprites("*RXMRC_8");
+ _globals._spriteIndexes[3] = _scene->_sprites.addSprites(formAnimName('x', 0));
+ _globals._spriteIndexes[4] = _scene->_sprites.addSprites(formAnimName('x', 1));
+ _globals._spriteIndexes[5] = _scene->_sprites.addSprites(formAnimName('x', 2));
+ _globals._spriteIndexes[6] = _scene->_sprites.addSprites(formAnimName('x', 3));
+
+ if (_game._objects[OBJ_FISHING_ROD]._roomNumber == _scene->_currentSceneId) {
+ _globals._sequenceIndexes[1] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[1], false, 9, 0, 0, 0);
+ _fishingRodHotspotId = _scene->_dynamicHotspots.add(NOUN_FISHING_ROD, VERB_WALKTO, _globals._sequenceIndexes[1], Common::Rect(0, 0, 0, 0));
+ _scene->_dynamicHotspots.setPosition(_fishingRodHotspotId, Common::Point(199, 101), FACING_NORTHEAST);
+ }
+
+ if (!_game._visitedScenes._sceneRevisited)
+ _globals[kRegisterOpen] = false;
+
+ _scene->_hotspots.activate(NOUN_PADLOCK_KEY, false);
+ if (_game._difficulty == DIFFICULTY_EASY) {
+ if (_game._objects[OBJ_PADLOCK_KEY]._roomNumber == _scene->_currentSceneId) {
+ _globals._sequenceIndexes[6] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[6], false, 10, 0, 0, 0);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[6], 3);
+ _keyHotspotId = _scene->_dynamicHotspots.add(NOUN_PADLOCK_KEY, VERB_WALKTO, _globals._sequenceIndexes[6], Common::Rect(0, 0, 0, 0));
+ _scene->_dynamicHotspots.setPosition(_keyHotspotId, Common::Point(218, 152), FACING_NORTHEAST);
+ }
+ if (_globals[kRegisterOpen]) {
+ _globals._sequenceIndexes[3] = _scene->_sequences.startCycle(_globals._spriteIndexes[3], false, -2);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 3);
+ _scene->_hotspots.activate(NOUN_PADLOCK_KEY, false);
+ }
+ } else if (_globals[kRegisterOpen]) {
+ if (_game._objects[OBJ_PADLOCK_KEY]._roomNumber == _scene->_currentSceneId) {
+ _scene->_hotspots.activate(NOUN_PADLOCK_KEY, true);
+ _globals._sequenceIndexes[5] = _scene->_sequences.startCycle(_globals._spriteIndexes[5], false, -2);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[5], 3);
+ } else {
+ _scene->_hotspots.activate(NOUN_PADLOCK_KEY, false);
+ _globals._sequenceIndexes[3] = _scene->_sequences.startCycle(_globals._spriteIndexes[3], false, -2);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 3);
+ }
+ } else
+ _scene->_hotspots.activate(NOUN_PADLOCK_KEY, false);
+
+ if (_scene->_priorSceneId != -2) {
+ _game._player._playerPos = Common::Point(144, 152);
+ _game._player._facing = FACING_NORTHEAST;
+ }
+
+ sceneEntrySound();
+}
+
+void Scene512::actions() {
+ if (_action.isAction(VERB_WALK, NOUN_OUTSIDE))
+ _scene->_nextSceneId = 511;
+ else if (_action.isAction(VERB_TAKE, NOUN_FISHING_ROD)) {
+ if (_game._trigger || !_game._objects.isInInventory(OBJ_FISHING_ROD)) {
+ switch (_game._trigger) {
+ case 0:
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._sequenceIndexes[2] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[2], false, 8, 1, 0, 0);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[2]);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[2], SEQUENCE_TRIGGER_SPRITE, 5, 1);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[2], SEQUENCE_TRIGGER_EXPIRE, 0, 2);
+ break;
+
+ case 1:
+ _vm->_sound->command(9);
+ _scene->_sequences.remove(_globals._sequenceIndexes[1]);
+ _scene->_dynamicHotspots.remove(_fishingRodHotspotId);
+ _game._objects.addToInventory(OBJ_FISHING_ROD);
+ _vm->_dialogs->showItem(OBJ_FISHING_ROD, 51217);
+ break;
+
+ case 2:
+ _scene->_sequences.updateTimeout(-1, _globals._sequenceIndexes[2]);
+ _game._player._visible = true;
+ _game._player._stepEnabled = true;
+ break;
+
+ default:
+ break;
+ }
+ }
+ } else if (_action.isAction(VERB_OPEN, NOUN_CASH_REGISTER)) {
+ if (!_globals[kRegisterOpen]) {
+ switch (_game._trigger) {
+ case 0:
+ _vm->_dialogs->show(51236);
+ _game._player._stepEnabled = false;
+ _game._player._facing = FACING_NORTH;
+ _scene->_sequences.addTimer(15, 1);
+ break;
+
+ case 1:
+ _game._player._visible = false;
+ _globals._sequenceIndexes[8] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[8], false, 9, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[8], 1, 3);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[8]);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[8], SEQUENCE_TRIGGER_EXPIRE, 0, 2);
+ break;
+
+ case 2:
+ _scene->_sequences.updateTimeout(-1, _globals._sequenceIndexes[8]);
+ _game._player._visible = true;
+ _scene->_sequences.addTimer(30, 3);
+ break;
+
+ case 3:
+ _game._player._facing = FACING_NORTHEAST;
+ if (!_game._objects.isInRoom(OBJ_PADLOCK_KEY) || (_game._difficulty == DIFFICULTY_EASY)) {
+ _globals._sequenceIndexes[3] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[3], false, 12, 1, 0, 0);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 3);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[3], SEQUENCE_TRIGGER_EXPIRE, 0, 4);
+ } else {
+ _globals._sequenceIndexes[4] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[4], false, 12, 1, 0, 0);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[4], 3);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[4], SEQUENCE_TRIGGER_EXPIRE, 0, 5);
+ }
+ _vm->_sound->command(23);
+ break;
+
+ case 4:
+ _globals._sequenceIndexes[3] = _scene->_sequences.startCycle(_globals._spriteIndexes[3], false, -2);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 3);
+ _scene->_sequences.addTimer(60, 6);
+ break;
+
+ case 5:
+ _globals._sequenceIndexes[5] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[5], false, 14, 0, 0, 0);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[5], 3);
+ _scene->_hotspots.activate(NOUN_PADLOCK_KEY, true);
+ _scene->_sequences.addTimer(60, 6);
+ break;
+
+ case 6:
+ _globals[kRegisterOpen] = true;
+ _game._player._stepEnabled = true;
+ break;
+
+ default:
+ break;
+ }
+ } else
+ _vm->_dialogs->show(51239);
+ } else if (_action.isAction(VERB_CLOSE, NOUN_CASH_REGISTER) && _globals[kRegisterOpen]) {
+ switch (_game._trigger) {
+ case 0:
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._sequenceIndexes[2] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[2], false, 10, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[2], 1, 2);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[2]);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[2], SEQUENCE_TRIGGER_EXPIRE, 0, 1);
+ break;
+
+ case 1:
+ _scene->_sequences.updateTimeout(-1, _globals._sequenceIndexes[2]);
+ _game._player._visible = true;
+ if (!_game._objects.isInRoom(OBJ_PADLOCK_KEY) || _game._difficulty == DIFFICULTY_EASY) {
+ _scene->_sequences.remove(_globals._sequenceIndexes[3]);
+ _globals._sequenceIndexes[3] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[3], false, 12, 1, 0, 0);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 3);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[3], SEQUENCE_TRIGGER_EXPIRE, 0, 2);
+ } else {
+ _scene->_sequences.remove(_globals._sequenceIndexes[5]);
+ _globals._sequenceIndexes[4] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[4], false, 12, 1, 0, 0);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[4], 3);
+ _scene->_hotspots.activate(NOUN_PADLOCK_KEY, false);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[4], SEQUENCE_TRIGGER_EXPIRE, 0, 2);
+ }
+ break;
+
+ case 2:
+ _globals[kRegisterOpen] = false;
+ _game._player._stepEnabled = true;
+ break;
+
+ default:
+ break;
+ }
+ } else if (_action.isAction(VERB_TAKE, NOUN_PADLOCK_KEY)) {
+ if (_game._trigger || !_game._objects.isInInventory(OBJ_PADLOCK_KEY)) {
+ switch (_game._trigger) {
+ case 0:
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+
+ int endVal;
+ if (_game._player._playerPos == Common::Point(218, 152))
+ endVal = 3;
+ else
+ endVal = 2;
+
+ _globals._sequenceIndexes[2] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[2], false, 10, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[2], 1, endVal);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[2]);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[2], SEQUENCE_TRIGGER_SPRITE, endVal, 1);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[2], SEQUENCE_TRIGGER_EXPIRE, 0, 2);
+ break;
+
+ case 1:
+ if (_game._player._playerPos == Common::Point(218, 152)) {
+ _scene->_sequences.remove(_globals._sequenceIndexes[6]);
+ _scene->_dynamicHotspots.remove(_keyHotspotId);
+ } else {
+ _scene->_sequences.remove(_globals._sequenceIndexes[5]);
+ _globals._sequenceIndexes[3] = _scene->_sequences.startCycle(_globals._spriteIndexes[3], false, -2);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 3);
+ _scene->_hotspots.activate(NOUN_PADLOCK_KEY, false);
+ }
+ _vm->_sound->command(9);
+ _game._objects.addToInventory(OBJ_PADLOCK_KEY);
+ _vm->_dialogs->showItem(OBJ_PADLOCK_KEY, 51226);
+ break;
+
+ case 2:
+ _scene->_sequences.updateTimeout(-1, _globals._sequenceIndexes[2]);
+ _game._player._visible = true;
+ _game._player._stepEnabled = true;
+ break;
+
+ default:
+ break;
+ }
+ }
+ } else if (_action._lookFlag)
+ _vm->_dialogs->show(51225);
+ else if (_action.isAction(VERB_LOOK, NOUN_PADLOCK_KEY) && _game._objects.isInRoom(OBJ_PADLOCK_KEY))
+ _vm->_dialogs->show(51215);
+ else if (_action.isAction(VERB_LOOK, NOUN_FISHING_ROD) && (_scene->_activeAnimation->getCurrentFrame() == 4))
+ _vm->_dialogs->show(51216);
+ else if (_action.isAction(VERB_LOOK, NOUN_SHIPS_WHEEL))
+ _vm->_dialogs->show(51218);
+ else if (_action.isAction(VERB_TAKE, NOUN_SHIPS_WHEEL))
+ _vm->_dialogs->show(51219);
+ else if (_action.isAction(VERB_LOOK, NOUN_PORTHOLE) || _action.isAction(VERB_PEER_THROUGH, NOUN_PORTHOLE))
+ _vm->_dialogs->show(51220);
+ else if (_action.isAction(VERB_LOOK, NOUN_TABLE))
+ _vm->_dialogs->show(51221);
+ else if (_action.isAction(VERB_LOOK, NOUN_STARFISH))
+ _vm->_dialogs->show(51222);
+ else if (_action.isAction(VERB_TAKE, NOUN_STARFISH))
+ _vm->_dialogs->show(51223);
+ else if (_action.isAction(VERB_LOOK, NOUN_OUTSIDE))
+ _vm->_dialogs->show(51224);
+ else if (_action.isAction(VERB_LOOK, NOUN_POSTER))
+ _vm->_dialogs->show(51227);
+ else if (_action.isAction(VERB_TAKE, NOUN_POSTER))
+ _vm->_dialogs->show(51228);
+ else if (_action.isAction(VERB_LOOK, NOUN_TROPHY)) {
+ if (_game._visitedScenes.exists(604))
+ _vm->_dialogs->show(51229);
+ else
+ _vm->_dialogs->show(51230);
+ } if (_action.isAction(VERB_LOOK, NOUN_CHAIR))
+ _vm->_dialogs->show(51231);
+ else if (_action.isAction(VERB_LOOK, NOUN_ROPE))
+ _vm->_dialogs->show(51232);
+ else if (_action.isAction(VERB_TAKE, NOUN_ROPE))
+ _vm->_dialogs->show(51233);
+ else if (_action.isAction(VERB_LOOK, NOUN_LAMP))
+ _vm->_dialogs->show(51234);
+ else if (_action.isAction(VERB_LOOK, NOUN_COUNTER))
+ _vm->_dialogs->show(51235);
+ else if (_action.isAction(VERB_LOOK, NOUN_ICE_CHESTS))
+ _vm->_dialogs->show(51237);
+ else if (_action.isAction(VERB_OPEN, NOUN_ICE_CHESTS))
+ _vm->_dialogs->show(51238);
+ else if (_action.isAction(VERB_LOOK, NOUN_CASH_REGISTER)) {
+ if (!_globals[kRegisterOpen])
+ _vm->_dialogs->show(51212);
+ else if (_game._objects.isInRoom(OBJ_PADLOCK_KEY))
+ _vm->_dialogs->show(51214);
+ else
+ _vm->_dialogs->show(51213);
+ } else
+ return;
+
+ _action._inProgress = false;
+}
+
+/*------------------------------------------------------------------------*/
+
+void Scene513::setup() {
+ setPlayerSpritesPrefix();
+ setAAName();
+ _scene->addActiveVocab(NOUN_ELEVATOR_DOOR);
+ _scene->addActiveVocab(VERB_WALKTO);
+}
+
+void Scene513::enter() {
+ _globals._spriteIndexes[1] = _scene->_sprites.addSprites(formAnimName('c', 0));
+ _globals._spriteIndexes[2] = _scene->_sprites.addSprites(formAnimName('x', 0));
+ _globals._spriteIndexes[3] = _scene->_sprites.addSprites("*RXCD_9");
+ _globals._spriteIndexes[4] = _scene->_sprites.addSprites("*RXMRC_9");
+
+ _globals._sequenceIndexes[2] = _scene->_sequences.startCycle(_globals._spriteIndexes[2], false, -2);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 2);
+
+ _globals._sequenceIndexes[1] = _scene->_sequences.startCycle(_globals._spriteIndexes[1], false, -2);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 1);
+
+ if ((_scene->_priorSceneId == 751) || (_scene->_priorSceneId == 701)) {
+ _game._player._playerPos = Common::Point(296, 147);
+ _game._player._facing = FACING_WEST;
+ _game._player._stepEnabled = false;
+ _scene->_sequences.addTimer(15, 80);
+ } else if (_scene->_priorSceneId != -2) {
+ _game._player._playerPos = Common::Point(63, 149);
+ _game._player._facing = FACING_NORTHEAST;
+ _game._player._visible = false;
+ _game._player._stepEnabled = false;
+ _scene->_sequences.remove(_globals._sequenceIndexes[1]);
+ _globals._sequenceIndexes[1] = _scene->_sequences.startCycle(_globals._spriteIndexes[1], false, -1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 1);
+ _scene->loadAnimation(formAnimName('R', 1), 70);
+ }
+
+ sceneEntrySound();
+
+ if (_scene->_roomChanged)
+ _game._objects.addToInventory(OBJ_SECURITY_CARD);
+
+ _game.loadQuoteSet(0x278, 0);
+}
+
+void Scene513::step() {
+ switch (_game._trigger) {
+ case 80:
+ _game._player._stepEnabled = false;
+ _scene->_sequences.remove(_globals._sequenceIndexes[2]);
+ _globals._sequenceIndexes[2] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[2], false, 7, 1, 0, 0);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 2);
+ _vm->_sound->command(24);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[2], SEQUENCE_TRIGGER_EXPIRE, 0, 81);
+ break;
+
+ case 81:
+ _game._player.walk(Common::Point(265, 152), FACING_WEST);
+ _scene->_sequences.addTimer(120, 82);
+ break;
+
+ case 82:
+ _globals._sequenceIndexes[2] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[2], false, 7, 1, 0, 0);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 2);
+ _vm->_sound->command(25);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[2], SEQUENCE_TRIGGER_EXPIRE, 0, 83);
+ break;
+
+ case 83:
+ _globals._sequenceIndexes[2] = _scene->_sequences.startCycle(_globals._spriteIndexes[2], false, -2);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 2);
+ _game._player._stepEnabled = true;
+ break;
+
+ default:
+ break;
+ }
+
+ switch (_game._trigger) {
+ case 70:
+ _game._player._visible = true;
+ _game._player._priorTimer = _scene->_activeAnimation->getNextFrameTimer() - _game._player._ticksAmount;
+ _scene->_sequences.addTimer(6, 71);
+ break;
+
+ case 71:
+ _scene->_sequences.remove(_globals._sequenceIndexes[1]);
+ _globals._sequenceIndexes[1] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[1], false, 6, 1, 0, 0);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 1);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[1], SEQUENCE_TRIGGER_EXPIRE, 0, 72);
+ break;
+
+ case 72:
+ _globals._sequenceIndexes[1] = _scene->_sequences.startCycle(_globals._spriteIndexes[1], false, -2);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 1);
+ _game._player._stepEnabled = true;
+ break;
+
+ default:
+ break;
+ }
+}
+
+void Scene513::actions() {
+ if (_action.isAction(VERB_GET_INTO, NOUN_CAR)) {
+ switch (_game._trigger) {
+ case 0:
+ _game._player._stepEnabled = false;
+ _scene->_sequences.remove(_globals._sequenceIndexes[1]);
+ _globals._sequenceIndexes[1] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[1], false, 6, 1, 0, 0);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 1);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[1], SEQUENCE_TRIGGER_EXPIRE, 0, 1);
+ break;
+
+ case 1: {
+ int syncIdx = _globals._sequenceIndexes[1];
+ _globals._sequenceIndexes[1] = _scene->_sequences.startCycle(_globals._spriteIndexes[1], false, -1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 1);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[1], syncIdx);
+ _scene->_sequences.addTimer(6, 2);
+ }
+ break;
+
+ case 2:
+ _game._player._visible = false;
+ _globals._sequenceIndexes[3] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[3], false, 10, 1, 0, 0);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[3]);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[3], SEQUENCE_TRIGGER_EXPIRE, 0, 3);
+ break;
+
+ case 3: {
+ int syncIdx = _globals._sequenceIndexes[3];
+ _globals._sequenceIndexes[3] = _scene->_sequences.startCycle(_globals._spriteIndexes[3], false, -2);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[3]);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[3], syncIdx);
+ _scene->_nextSceneId = 504;
+ }
+ break;
+
+ default:
+ break;
+ }
+ } else if (_action.isAction(VERB_PUT, NOUN_ID_CARD, 0x251) || _action.isAction(VERB_PUT, NOUN_FAKE_ID, 0x251)) {
+ switch (_game._trigger) {
+ case 0:
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._sequenceIndexes[4] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[4], false, 7, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[4], 1, 2);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[4]);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[4], SEQUENCE_TRIGGER_EXPIRE, 0, 1);
+ break;
+
+ case 1:
+ _scene->_sequences.updateTimeout(-1, _globals._sequenceIndexes[4]);
+ _game._player._visible = true;
+ _scene->_sequences.remove(_globals._sequenceIndexes[2]);
+ _globals._sequenceIndexes[2] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[2], false, 7, 1, 0, 0);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 2);
+ _vm->_sound->command(24);
+ _scene->_kernelMessages.reset();
+ _scene->_kernelMessages.add(Common::Point(0, 0), 0x1110, 34, 0, 120, _game.getQuote(0x278));
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[2], SEQUENCE_TRIGGER_EXPIRE, 0, 2);
+ break;
+
+ case 2:
+ _game._player.walk(Common::Point(296, 147), FACING_WEST);
+ _scene->_sequences.addTimer(120, 3);
+ break;
+
+ case 3:
+ _globals._sequenceIndexes[2] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[2], false, 7, 1, 0, 0);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 2);
+ _vm->_sound->command(25);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[2], SEQUENCE_TRIGGER_EXPIRE, 0, 4);
+ break;
+
+ case 4:
+ _globals._sequenceIndexes[2] = _scene->_sequences.startCycle(_globals._spriteIndexes[2], false, -2);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 2);
+ _game._player._stepEnabled = true;
+ if (_globals[kCityFlooded])
+ _scene->_nextSceneId = 701;
+ else
+ _scene->_nextSceneId = 751;
+
+ break;
+
+ default:
+ break;
+ }
+ } else if ((_action._lookFlag) || _action.isAction(VERB_LOOK, NOUN_STREET))
+ _vm->_dialogs->show(51318);
+ else if (_action.isAction(VERB_LOOK, NOUN_ELEVATOR))
+ _vm->_dialogs->show(51310);
+ else if (_action.isAction(VERB_LOOK, NOUN_ELEVATOR_DOOR))
+ _vm->_dialogs->show(51311);
+ else if (_action.isAction(VERB_LOOK, NOUN_CARD_SLOT))
+ _vm->_dialogs->show(51312);
+ else if (_action.isAction(VERB_LOOK, NOUN_HANDICAP_SIGN))
+ _vm->_dialogs->show(51313);
+ else if (_action.isAction(VERB_LOOK, NOUN_BIKE_RACK))
+ _vm->_dialogs->show(51314);
+ else if (_action.isAction(VERB_LOOK, NOUN_BUILDING))
+ _vm->_dialogs->show(51315);
+ else if (_action.isAction(VERB_LOOK, NOUN_SIGN))
+ _vm->_dialogs->show(51316);
+ else if (_action.isAction(VERB_LOOK, NOUN_STREET_TO_WEST) || _action.isAction(VERB_WALK_DOWN, NOUN_STREET_TO_WEST))
+ _vm->_dialogs->show(51317);
+ else if (_action.isAction(VERB_OPEN, NOUN_ELEVATOR_DOOR) || _action.isAction(VERB_OPEN, NOUN_ELEVATOR))
+ _vm->_dialogs->show(51319);
+ else if (_action.isAction(VERB_LOOK, NOUN_CAR))
+ _vm->_dialogs->show(51321);
+ else if (_action.isAction(VERB_LOOK, NOUN_BRICK_WALL))
+ _vm->_dialogs->show(51322);
+ else if (_action.isAction(VERB_PUT, NOUN_SECURITY_CARD, 0x251))
+ _vm->_dialogs->show(51320);
+ else
+ return;
+
+ _action._inProgress = false;
+}
+
+/*------------------------------------------------------------------------*/
+
+void Scene515::setup() {
+ _game._player._spritesPrefix = "";
+ setAAName();
+}
+
+void Scene515::enter() {
+ _game._player._visible = false;
+ _game._player._stepEnabled = false;
+ _scene->_sequences.addTimer(30, 70);
+
+ sceneEntrySound();
+}
+
+void Scene515::step() {
+ if (_game._trigger == 70)
+ _scene->loadAnimation(formAnimName('A', -1), 71);
+ else if (_game._trigger == 71)
+ _scene->_nextSceneId = 508;
+}
+
+/*------------------------------------------------------------------------*/
+
+void Scene551::setup() {
+ setPlayerSpritesPrefix();
+ setAAName();
+}
+
+void Scene551::enter() {
+ if (_globals[kSexOfRex] == REX_MALE)
+ _globals._spriteIndexes[2] = _scene->_sprites.addSprites(formAnimName('a', 0));
+ else
+ _globals._spriteIndexes[3] = _scene->_sprites.addSprites(formAnimName('a', 1));
+
+ if (_scene->_priorSceneId == 501)
+ _game._player._playerPos = Common::Point(18, 130);
+ else if (_scene->_priorSceneId != -2) {
+ _game._player._playerPos = Common::Point(124, 119);
+ _game._player._facing = FACING_NORTH;
+ }
+
+ if (_globals[kTeleporterCommand]) {
+ _game._player._visible = false;
+ _game._player._stepEnabled = false;
+
+ char sepChar;
+ if (_globals[kSexOfRex] == REX_MALE)
+ sepChar = 'e';
+ else
+ sepChar = 'u';
+
+ int suffixNum;
+ int trigger;
+
+ switch (_globals[kTeleporterCommand]) {
+ case 1:
+ suffixNum = 3;
+ trigger = 75;
+ _globals[kTeleporterUnderstood] = true;
+ break;
+
+ case 2:
+ suffixNum = 1;
+ trigger = 80;
+ break;
+
+ case 4:
+ suffixNum = 2;
+ trigger = 90;
+ break;
+
+ default:
+ trigger = 0;
+ suffixNum = 0;
+ }
+
+ _globals[kTeleporterCommand] = 0;
+
+ if (suffixNum > 0)
+ _scene->loadAnimation(formAnimName(sepChar, suffixNum), trigger);
+ else {
+ _game._player._visible = true;
+ _game._player._stepEnabled = true;
+ }
+ }
+
+ sceneEntrySound();
+}
+
+void Scene551::step() {
+ switch (_game._trigger) {
+ case 75:
+ _game._player._stepEnabled = true;
+ _game._player._visible = true;
+ _game._player._priorTimer = _scene->_frameStartTime - _game._player._ticksAmount;
+ break;
+
+ case 80:
+ _globals[kTeleporterCommand] = 1;
+ _scene->_nextSceneId = _globals[kTeleporterDestination];
+ _scene->_reloadSceneFlag = true;
+ break;
+
+ case 90:
+ if (_globals[kSexOfRex] == REX_MALE) {
+ _globals._sequenceIndexes[2] = _scene->_sequences.startCycle(_globals._spriteIndexes[2], false, -2);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 8);
+ } else {
+ _globals._sequenceIndexes[3] = _scene->_sequences.startCycle(_globals._spriteIndexes[3], false, -2);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 8);
+ }
+ _vm->_sound->command(28);
+ _scene->_sequences.addTimer(60, 91);
+ break;
+
+ case 91:
+ _scene->_reloadSceneFlag = true;
+ break;
+
+ default:
+ break;
+ }
+}
+
+void Scene551::preActions() {
+ if (_action.isAction(VERB_WALK_DOWN) && (_action.isObject(NOUN_STREET_TO_WEST) || _action.isObject(NOUN_SIDEWALK_TO_WEST)))
+ _game._player._walkOffScreenSceneId = 501;
+}
+
+void Scene551::actions() {
+ if (_action.isAction(VERB_STEP_INTO, NOUN_TELEPORTER))
+ _scene->_nextSceneId = 502;
+ else if ((_action._lookFlag))
+ _vm->_dialogs->show(55117);
+ else if (_action.isAction(VERB_LOOK, NOUN_SKELETON))
+ _vm->_dialogs->show(55110);
+ else if (_action.isAction(VERB_LOOK, NOUN_ELEVATOR_SHAFT))
+ _vm->_dialogs->show(55111);
+ else if (_action.isAction(VERB_WALKTO, NOUN_ELEVATOR_SHAFT))
+ _vm->_dialogs->show(55112);
+ else if (_action.isAction(VERB_LOOK, NOUN_BUILDING))
+ _vm->_dialogs->show(55113);
+ else if (_action.isAction(VERB_LOOK, NOUN_TELEPORTER))
+ _vm->_dialogs->show(55114);
+ else if (_action.isAction(VERB_LOOK, NOUN_BUILDING))
+ _vm->_dialogs->show(55115);
+ else if (_action.isAction(VERB_LOOK, NOUN_SIDEWALK_TO_WEST)) {
+ if (_game._visitedScenes.exists(505))
+ _vm->_dialogs->show(55116);
+ else
+ _vm->_dialogs->show(55115);
+ } else if (_action.isAction(VERB_LOOK, NOUN_SIDEWALK))
+ _vm->_dialogs->show(55118);
+ else if (_action.isAction(VERB_LOOK, NOUN_EQUIPMENT_OVERHEAD))
+ _vm->_dialogs->show(55119);
+ else if (_action.isAction(VERB_LOOK, NOUN_RAILING))
+ _vm->_dialogs->show(55120);
+ else
+ return;
+
+ _action._inProgress = false;
+}
+
+/*------------------------------------------------------------------------*/
+
+} // End of namespace Nebular
+} // End of namespace MADS
diff --git a/engines/mads/nebular/nebular_scenes5.h b/engines/mads/nebular/nebular_scenes5.h
new file mode 100644
index 0000000000..4022f1c85b
--- /dev/null
+++ b/engines/mads/nebular/nebular_scenes5.h
@@ -0,0 +1,254 @@
+/* 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.
+ *
+ */
+
+#ifndef MADS_NEBULAR_SCENES5_H
+#define MADS_NEBULAR_SCENES5_H
+
+#include "common/scummsys.h"
+#include "mads/game.h"
+#include "mads/scene.h"
+#include "mads/nebular/nebular_scenes.h"
+
+namespace MADS {
+
+namespace Nebular {
+
+class Scene5xx : public NebularScene {
+protected:
+ /**
+ * Plays an appropriate sound when entering a scene
+ */
+ void setAAName();
+
+ /**
+ * Updates the prefix used for getting player sprites for the scene
+ */
+ void setPlayerSpritesPrefix();
+
+ void sceneEntrySound();
+
+public:
+ Scene5xx(MADSEngine *vm) : NebularScene(vm) {}
+};
+
+class Scene501: public Scene5xx{
+private:
+ int _mainSequenceId;
+ int _mainSpriteId;
+ int _doorHotspotid;
+ bool _rexPunched;
+
+ void handleSlotActions();
+
+public:
+ Scene501(MADSEngine *vm);
+ void synchronize(Common::Serializer &s);
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+ virtual void preActions();
+ virtual void actions();
+};
+
+class Scene502: public SceneTeleporter {
+public:
+ Scene502(MADSEngine *vm) : SceneTeleporter(vm) {}
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+ virtual void actions();
+};
+
+class Scene503: public Scene5xx{
+private:
+ int _detonatorHotspotId;
+
+public:
+ Scene503(MADSEngine *vm);
+ void synchronize(Common::Serializer &s);
+
+ virtual void setup();
+ virtual void enter();
+ virtual void actions();
+};
+
+class Scene504: public Scene5xx{
+private:
+ int _carAnimationMode;
+ int _carFrame;
+
+public:
+ Scene504(MADSEngine *vm);
+ void synchronize(Common::Serializer &s);
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+ virtual void preActions();
+ virtual void actions();
+};
+
+class Scene505: public Scene5xx{
+private:
+ int _frame;
+ int _nextButtonId;
+ int _homeSelectedId;
+ int _selectedId;
+ int _activeCars;
+
+ int _carLocations[9];
+
+public:
+ Scene505(MADSEngine *vm);
+ void synchronize(Common::Serializer &s);
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+ virtual void actions();
+};
+
+class Scene506: public Scene5xx{
+private:
+ Common::Point _doorPos;
+ Facing _heroFacing;
+
+ int _doorDepth;
+ int _doorSpriteIdx;
+ int _doorSequenceIdx;
+ int _doorWord;
+
+ bool _labDoorFl;
+ bool _firstDoorFl;
+ bool _actionFl;
+
+ void handleDoorSequences();
+
+public:
+ Scene506(MADSEngine *vm);
+ void synchronize(Common::Serializer &s);
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+ virtual void actions();
+};
+
+class Scene507: public Scene5xx{
+private:
+ int _penlightHotspotId;
+
+public:
+ Scene507(MADSEngine *vm);
+ void synchronize(Common::Serializer &s);
+
+ virtual void setup();
+ virtual void enter();
+ virtual void actions();
+};
+
+class Scene508: public Scene5xx{
+private:
+ int _chosenObject;
+
+ void handlePedestral();
+
+public:
+ Scene508(MADSEngine *vm);
+ void synchronize(Common::Serializer &s);
+
+ virtual void setup();
+ virtual void enter();
+ virtual void preActions();
+ virtual void actions();
+};
+
+class Scene511: public Scene5xx{
+private:
+ bool _handingLine;
+ bool _lineMoving;
+
+ int _lineAnimationMode;
+ int _lineFrame;
+ int _lineAnimationPosition;
+
+public:
+ Scene511(MADSEngine *vm);
+ void synchronize(Common::Serializer &s);
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+ virtual void preActions();
+ virtual void actions();
+};
+
+class Scene512: public Scene5xx{
+private:
+ int _fishingRodHotspotId;
+ int _keyHotspotId;
+
+public:
+ Scene512(MADSEngine *vm);
+ void synchronize(Common::Serializer &s);
+
+ virtual void setup();
+ virtual void enter();
+ virtual void actions();
+};
+
+class Scene513: public Scene5xx{
+public:
+ Scene513(MADSEngine *vm) : Scene5xx(vm) {}
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+ virtual void actions();
+};
+
+class Scene515: public Scene5xx{
+public:
+ Scene515(MADSEngine *vm) : Scene5xx(vm) {}
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+ virtual void actions() {};
+};
+
+class Scene551: public Scene5xx{
+public:
+ Scene551(MADSEngine *vm) : Scene5xx(vm) {}
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+ virtual void preActions();
+ virtual void actions();
+};
+} // End of namespace Nebular
+} // End of namespace MADS
+
+#endif /* MADS_NEBULAR_SCENES5_H */
diff --git a/engines/mads/nebular/nebular_scenes6.cpp b/engines/mads/nebular/nebular_scenes6.cpp
new file mode 100644
index 0000000000..1821a72c16
--- /dev/null
+++ b/engines/mads/nebular/nebular_scenes6.cpp
@@ -0,0 +1,4771 @@
+/* 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 "mads/mads.h"
+#include "mads/scene.h"
+#include "mads/nebular/nebular_scenes.h"
+#include "mads/nebular/nebular_scenes6.h"
+
+namespace MADS {
+
+namespace Nebular {
+
+void Scene6xx::setAAName() {
+ _game._aaName = Resources::formatAAName(5);
+}
+
+void Scene6xx::setPlayerSpritesPrefix() {
+ _vm->_sound->command(5);
+ Common::String oldName = _game._player._spritesPrefix;
+
+ if ((_scene->_nextSceneId == 605) || (_scene->_nextSceneId == 620))
+ _game._player._spritesPrefix = "";
+ else if (_globals[kSexOfRex] == REX_MALE)
+ _game._player._spritesPrefix = "RXM";
+ else
+ _game._player._spritesPrefix = "ROX";
+
+ if (oldName != _game._player._spritesPrefix)
+ _game._player._spritesChanged = true;
+
+ _game._player._scalingVelocity = true;
+ _vm->_palette->setEntry(16, 10, 63, 63);
+ _vm->_palette->setEntry(17, 10, 45, 45);
+}
+
+void Scene6xx::sceneEntrySound() {
+ if (!_vm->_musicFlag) {
+ _vm->_sound->command(2);
+ return;
+ }
+
+ switch (_scene->_nextSceneId) {
+ case 601:
+ case 602:
+ case 603:
+ case 604:
+ case 605:
+ case 607:
+ case 608:
+ case 609:
+ case 610:
+ case 612:
+ case 620:
+ _vm->_sound->command(29);
+ break;
+ case 611:
+ _vm->_sound->command(24);
+ break;
+ default:
+ break;
+ }
+}
+
+/*------------------------------------------------------------------------*/
+
+void Scene601::setup() {
+ setPlayerSpritesPrefix();
+ setAAName();
+ _scene->addActiveVocab(NOUN_LASER_BEAM);
+ _scene->addActiveVocab(VERB_LOOK_AT);
+}
+
+void Scene601::enter() {
+ _globals._spriteIndexes[1] = _scene->_sprites.addSprites(formAnimName('x', 0));
+ _globals._spriteIndexes[2] = _scene->_sprites.addSprites(formAnimName('c', 0));
+ _globals._spriteIndexes[3] = _scene->_sprites.addSprites("*RXCD_4");
+
+ if (_globals[kLaserHoleIsThere]) {
+ _globals._sequenceIndexes[1] = _scene->_sequences.startCycle(_globals._spriteIndexes[1], false, -2);
+ _scene->_dynamicHotspots.add(NOUN_LASER_BEAM, 0xD1, _globals._sequenceIndexes[1], Common::Rect(0, 0, 0, 0));
+ }
+
+ _globals._sequenceIndexes[2] = _scene->_sequences.startCycle(_globals._spriteIndexes[2], false, -1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 3);
+
+ if (_scene->_priorSceneId == 504) {
+ _game._player._playerPos = Common::Point(73, 148);
+ _game._player._facing = FACING_WEST;
+ _game._player._visible = false;
+ _game._player._stepEnabled = false;
+ _scene->_sequences.remove(_globals._sequenceIndexes[2]);
+ _globals._sequenceIndexes[2] = _scene->_sequences.startCycle(_globals._spriteIndexes[2], false, -2);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 3);
+ _scene->loadAnimation(formAnimName('R', 1), 70);
+ } else if (_scene->_priorSceneId != -2) {
+ _game._player._playerPos = Common::Point(229, 129);
+ _game._player._facing = FACING_SOUTHWEST;
+ }
+
+ sceneEntrySound();
+}
+
+void Scene601::step() {
+ switch (_game._trigger) {
+ case 70:
+ _game._player._visible = true;
+ _game._player._priorTimer = _scene->_activeAnimation->getNextFrameTimer() - _game._player._ticksAmount;
+ _scene->_sequences.addTimer(30, 71);
+ break;
+
+ case 71:
+ _scene->_sequences.remove(_globals._sequenceIndexes[2]);
+ _globals._sequenceIndexes[2] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[2], false, 6, 1, 0, 0);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 3);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[2], SEQUENCE_TRIGGER_EXPIRE, 0, 72);
+ break;
+
+ case 72:
+ _globals._sequenceIndexes[2] = _scene->_sequences.startCycle(_globals._spriteIndexes[2], false, -1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 3);
+ _game._player._stepEnabled = true;
+ break;
+
+ default:
+ break;
+ }
+}
+
+void Scene601::actions() {
+ if (_action.isAction(VERB_WALK_THROUGH, NOUN_ENTRANCE))
+ _scene->_nextSceneId = 602;
+ else if (_action.isAction(0x325, 0x324)) {
+ switch (_game._trigger) {
+ case 0:
+ _game._player._stepEnabled = false;
+ _scene->_sequences.remove(_globals._sequenceIndexes[2]);
+ _globals._sequenceIndexes[2] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[2], false, 6, 1, 0, 0);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 3);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[2], SEQUENCE_TRIGGER_EXPIRE, 0, 1);
+ break;
+
+ case 1: {
+ int syncIdx = _globals._sequenceIndexes[2];
+ _globals._sequenceIndexes[2] = _scene->_sequences.startCycle(_globals._spriteIndexes[2], false, -2);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[2], syncIdx);
+ _scene->_sequences.addTimer(6, 2);
+ }
+ break;
+
+ case 2:
+ _game._player._visible = false;
+ _globals._sequenceIndexes[3] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[3], false, 10, 1, 0, 0);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[3]);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[3], SEQUENCE_TRIGGER_EXPIRE, 0, 3);
+ break;
+
+ case 3: {
+ int syncIdx = _globals._sequenceIndexes[3];
+ _globals._sequenceIndexes[3] = _scene->_sequences.startCycle(_globals._spriteIndexes[3], false, -2);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[3]);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[3], syncIdx);
+ _scene->_nextSceneId = 504;
+ }
+ break;
+
+ default:
+ break;
+ }
+ } else if (_action._lookFlag || _action.isAction(VERB_LOOK, NOUN_STREET)) {
+ if (!_globals[kLaserHoleIsThere])
+ _vm->_dialogs->show(60110);
+ else
+ _vm->_dialogs->show(60111);
+ } else if (_action.isAction(VERB_LOOK, NOUN_CAR))
+ _vm->_dialogs->show(60112);
+ else if (_action.isAction(VERB_LOOK, NOUN_PAPERS))
+ _vm->_dialogs->show(60113);
+ else if (_action.isAction(VERB_LOOK, NOUN_BUILDING))
+ _vm->_dialogs->show(60114);
+ else if (_action.isAction(VERB_WALK_DOWN, NOUN_STREET))
+ _vm->_dialogs->show(60115);
+ else if (_action.isAction(VERB_LOOK, NOUN_BALCONY))
+ _vm->_dialogs->show(60116);
+ else if (_action.isAction(VERB_LOOK, NOUN_ENTRANCE))
+ _vm->_dialogs->show(60117);
+ else if (_action.isAction(VERB_LOOK, NOUN_WALL))
+ _vm->_dialogs->show(60118);
+ else if (_action.isAction(VERB_LOOK, NOUN_CITY))
+ _vm->_dialogs->show(60119);
+ else if (_action.isAction(VERB_LOOK, NOUN_FOUNTAIN))
+ _vm->_dialogs->show(60120);
+ else
+ return;
+
+ _action._inProgress = false;
+}
+
+/*------------------------------------------------------------------------*/
+
+Scene602::Scene602(MADSEngine *vm) : Scene6xx(vm) {
+ _lastSpriteIdx = -1;
+ _lastSequenceIdx = -1;
+ _cycleIndex = -1;
+ _safeMode = -1;
+}
+
+void Scene602::synchronize(Common::Serializer &s) {
+ Scene6xx::synchronize(s);
+
+ s.syncAsSint16LE(_lastSpriteIdx);
+ s.syncAsSint16LE(_lastSequenceIdx);
+ s.syncAsSint16LE(_cycleIndex);
+ s.syncAsSint16LE(_safeMode);
+}
+
+void Scene602::setup() {
+ setPlayerSpritesPrefix();
+ setAAName();
+ _scene->addActiveVocab(VERB_WALKTO);
+ _scene->addActiveVocab(NOUN_SAFE);
+ _scene->addActiveVocab(NOUN_LASER_BEAM);
+}
+
+void Scene602::enter() {
+ _globals._spriteIndexes[1] = _scene->_sprites.addSprites(formAnimName('h', -1));
+ _globals._spriteIndexes[2] = _scene->_sprites.addSprites(formAnimName('x', 0));
+ _globals._spriteIndexes[3] = _scene->_sprites.addSprites(formAnimName('x', 1));
+ _globals._spriteIndexes[4] = _scene->_sprites.addSprites(formAnimName('l', 0));
+ _globals._spriteIndexes[5] = _scene->_sprites.addSprites("*RXMRC_9");
+
+ if (!_game._visitedScenes._sceneRevisited)
+ _globals[kSafeStatus] = 0;
+
+ if (_globals[kLaserHoleIsThere]) {
+ _globals._sequenceIndexes[1] = _scene->_sequences.startCycle(_globals._spriteIndexes[1], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 9);
+ _globals._sequenceIndexes[4] = _scene->_sequences.startCycle(_globals._spriteIndexes[4], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[4], 9);
+ int idx = _scene->_dynamicHotspots.add(NOUN_LASER_BEAM, VERB_WALKTO, _globals._sequenceIndexes[4], Common::Rect(0, 0, 0, 0));
+ _scene->_dynamicHotspots.setPosition(idx, Common::Point(80, 134), FACING_NORTHEAST);
+ _scene->changeVariant(1);
+ } else
+ _scene->_hotspots.activate(NOUN_HOLE, false);
+
+ if (_globals[kSafeStatus] == 0) {
+ _lastSpriteIdx = _globals._spriteIndexes[2];
+ _cycleIndex = -1;
+ } else if (_globals[kSafeStatus] == 1) {
+ _lastSpriteIdx = _globals._spriteIndexes[2];
+ _cycleIndex = -2;
+ } else if (_globals[kSafeStatus] == 3) {
+ _lastSpriteIdx = _globals._spriteIndexes[3];
+ _cycleIndex = -2;
+ } else {
+ _lastSpriteIdx = _globals._spriteIndexes[3];
+ _cycleIndex = -1;
+ }
+
+ _lastSequenceIdx = _scene->_sequences.startCycle(_lastSpriteIdx, false, _cycleIndex);
+ _scene->_sequences.setDepth(_lastSequenceIdx, 14);
+ int idx = _scene->_dynamicHotspots.add(NOUN_SAFE, VERB_WALKTO, _lastSequenceIdx, Common::Rect(0, 0, 0, 0));
+ _scene->_dynamicHotspots.setPosition(idx, Common::Point(185, 113), FACING_NORTHWEST);
+
+ if (_game._objects.isInRoom(OBJ_DOOR_KEY)) {
+ _globals._spriteIndexes[6] = _scene->_sprites.addSprites(formAnimName('k', -1));
+ _globals._sequenceIndexes[6] = _scene->_sequences.startCycle(_globals._spriteIndexes[6], false, -1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[6], 15);
+ if (_globals[kSafeStatus] == 0 || _globals[kSafeStatus] == 2)
+ _scene->_hotspots.activate(NOUN_DOOR_KEY, false);
+ } else
+ _scene->_hotspots.activate(NOUN_DOOR_KEY, false);
+
+ if (_scene->_priorSceneId == 603) {
+ _game._player._playerPos = Common::Point(228, 126);
+ _game._player._facing = FACING_WEST;
+ } else if (_scene->_priorSceneId != -2) {
+ _game._player._playerPos = Common::Point(50, 127);
+ _game._player._facing = FACING_EAST;
+ }
+
+ sceneEntrySound();
+ _game.loadQuoteSet(0x2F1, 0x2F2, 0x2F3, 0);
+
+ if (_scene->_roomChanged) {
+ _game._objects.addToInventory(OBJ_NOTE);
+ _game._objects.addToInventory(OBJ_REARVIEW_MIRROR);
+ _game._objects.addToInventory(OBJ_COMPACT_CASE);
+ }
+}
+
+void Scene602::handleSafeActions() {
+ switch (_game._trigger) {
+ case 0:
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._sequenceIndexes[5] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[5], true, 12, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[5], 1, 3);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[5]);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[5], SEQUENCE_TRIGGER_SPRITE, 3, 1);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[5], SEQUENCE_TRIGGER_EXPIRE, 0, 3);
+ break;
+
+ case 1:
+ if (_safeMode == 1 || _safeMode == 3) {
+ if (_globals[kSafeStatus] == 0 && _safeMode == 1) {
+ _scene->_kernelMessages.reset();
+ _scene->_kernelMessages.add(Common::Point(0, 0), 0x1110, 34, 0, 120, _game.getQuote(0x2F1));
+ _scene->_sequences.addTimer(120, 4);
+ } else {
+ _scene->_sequences.remove(_lastSequenceIdx);
+ if (_safeMode == 3)
+ _lastSpriteIdx = _globals._spriteIndexes[2];
+ else
+ _lastSpriteIdx = _globals._spriteIndexes[3];
+
+ _lastSequenceIdx = _scene->_sequences.addSpriteCycle(_lastSpriteIdx, false, 12, 1, 0, 0);
+ _scene->_sequences.setDepth(_lastSequenceIdx, 14);
+ if (_game._objects[OBJ_DOOR_KEY]._roomNumber == _scene->_currentSceneId)
+ _scene->_hotspots.activate(NOUN_DOOR_KEY, true);
+
+ _scene->_sequences.addSubEntry(_lastSequenceIdx,
+ SEQUENCE_TRIGGER_EXPIRE, 0, 2);
+ }
+ } else {
+ _scene->_sequences.remove(_lastSequenceIdx);
+ if (_globals[kSafeStatus] == 1)
+ _lastSpriteIdx = _globals._spriteIndexes[2];
+ else
+ _lastSpriteIdx = _globals._spriteIndexes[3];
+
+ _lastSequenceIdx = _scene->_sequences.startReverseCycle(_lastSpriteIdx, false, 12, 1, 0, 0);
+ _scene->_sequences.setDepth(_lastSequenceIdx, 14);
+ if (_game._objects[OBJ_DOOR_KEY]._roomNumber == _scene->_currentSceneId)
+ _scene->_hotspots.activate(NOUN_DOOR_KEY, false);
+
+ _scene->_sequences.addSubEntry(_lastSequenceIdx, SEQUENCE_TRIGGER_EXPIRE, 0, 2);
+ }
+ break;
+
+ case 2: {
+ int synxIdx = _lastSequenceIdx;
+ _lastSequenceIdx = _scene->_sequences.startCycle(_lastSpriteIdx, false, _cycleIndex);
+ _scene->_sequences.setDepth(_lastSequenceIdx, 14);
+ _scene->_sequences.updateTimeout(_lastSequenceIdx, synxIdx);
+ int idx = _scene->_dynamicHotspots.add(NOUN_SAFE, VERB_WALKTO, _lastSequenceIdx, Common::Rect(0, 0, 0, 0));
+ _scene->_dynamicHotspots.setPosition(idx, Common::Point(185, 113), FACING_NORTHWEST);
+ if (_safeMode == 3) {
+ _scene->_kernelMessages.reset();
+ _scene->_kernelMessages.add(Common::Point(0, 0), 0x1110, 34, 0, 120, _game.getQuote(0x2F3));
+ _scene->_sequences.addTimer(120, 4);
+ } else
+ _scene->_sequences.addTimer(60, 4);
+ break;
+ }
+
+ case 3:
+ _scene->_sequences.updateTimeout(-1, _globals._sequenceIndexes[5]);
+ _game._player._visible = true;
+ break;
+
+ case 4:
+ if (_safeMode == 1) {
+ if (_globals[kSafeStatus] == 2)
+ _globals[kSafeStatus] = 3;
+ } else if (_safeMode == 2) {
+ if (_globals[kSafeStatus] == 3)
+ _globals[kSafeStatus] = 2;
+ else
+ _globals[kSafeStatus] = 0;
+ } else
+ _globals[kSafeStatus] = 1;
+
+ _game._player._stepEnabled = true;
+ break;
+
+ default:
+ break;
+ }
+}
+
+void Scene602::actions() {
+ if (_action.isAction(VERB_WALK_THROUGH, NOUN_HALLWAY))
+ _scene->_nextSceneId = 601;
+ else if (_action.isAction(VERB_WALK_THROUGH, NOUN_DOORWAY))
+ _scene->_nextSceneId = 603;
+ else if (_action.isAction(VERB_OPEN, NOUN_SAFE) && ((_globals[kSafeStatus] == 0) || (_globals[kSafeStatus] == 2))) {
+ _safeMode = 1;
+ _cycleIndex = -2;
+ handleSafeActions();
+ } else if (_action.isAction(VERB_CLOSE, NOUN_SAFE) && ((_globals[kSafeStatus] == 1) || (_globals[kSafeStatus] == 3))) {
+ _safeMode = 2;
+ _cycleIndex = -1;
+ handleSafeActions();
+ } else if (_action.isAction(VERB_UNLOCK, 0x3A7, 0x3D3)) {
+ if ((_globals[kSafeStatus] == 0) && (_game._difficulty != DIFFICULTY_HARD)) {
+ _safeMode = 3;
+ _cycleIndex = -2;
+ handleSafeActions();
+ }
+ } else if ((_action.isAction(VERB_PUT, NOUN_REARVIEW_MIRROR, 0x343) || _action.isAction(VERB_PUT, NOUN_COMPACT_CASE, 0x343)
+ || _action.isAction(VERB_REFLECT, 0x57, 0x343) || _action.isAction(VERB_REFLECT, 0x120, 0x343)) && (_globals[kSafeStatus] == 0)) {
+ switch (_game._trigger) {
+ case 0:
+ _vm->_dialogs->show(60230);
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _scene->_sequences.remove(_globals._sequenceIndexes[4]);
+ _scene->_sequences.remove(_lastSequenceIdx);
+ _scene->loadAnimation(formAnimName('L', 1), 1);
+ break;
+
+ case 1: {
+ _game._player._visible = true;
+ _game._player._priorTimer = _scene->_activeAnimation->getNextFrameTimer() - _game._player._ticksAmount;
+ _lastSpriteIdx = _globals._spriteIndexes[3];
+ _lastSequenceIdx = _scene->_sequences.startCycle(_lastSpriteIdx, false, -1);
+ _scene->_sequences.setDepth(_lastSequenceIdx, 14);
+ int idx = _scene->_dynamicHotspots.add(NOUN_SAFE, VERB_WALKTO, _lastSequenceIdx, Common::Rect(0, 0, 0, 0));
+ _scene->_dynamicHotspots.setPosition(idx, Common::Point(185, 113), FACING_NORTHWEST);
+ _globals._sequenceIndexes[4] = _scene->_sequences.startCycle(_globals._spriteIndexes[4], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[4], 9);
+ idx = _scene->_dynamicHotspots.add(NOUN_LASER_BEAM, VERB_WALKTO, _globals._sequenceIndexes[4], Common::Rect(0, 0, 0, 0));
+ _scene->_dynamicHotspots.setPosition(idx, Common::Point(80, 134), FACING_NORTHEAST);
+ _scene->_sequences.addTimer(60, 2);
+ }
+ break;
+
+ case 2:
+ _scene->_kernelMessages.reset();
+ _scene->_kernelMessages.add(Common::Point(0, 0), 0x1110, 34, 0, 120, _game.getQuote(0x2F2));
+ _globals[kSafeStatus] = 2;
+ _game._player._stepEnabled = true;
+ break;
+
+ default:
+ break;
+ }
+ } else if (_action.isAction(VERB_TAKE, NOUN_DOOR_KEY) && (_game._trigger || _game._objects.isInRoom(OBJ_DOOR_KEY))) {
+ switch (_game._trigger) {
+ case 0:
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._sequenceIndexes[5] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[5], true, 8, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[5], 1, 3);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[5]);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[5], SEQUENCE_TRIGGER_SPRITE, 3, 1);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[5], SEQUENCE_TRIGGER_EXPIRE, 0, 2);
+ break;
+
+ case 1:
+ _scene->_sequences.remove(_globals._sequenceIndexes[6]);
+ _scene->_hotspots.activate(NOUN_DOOR_KEY, false);
+ _vm->_sound->command(9);
+ _game._objects.addToInventory(OBJ_DOOR_KEY);
+ break;
+
+ case 2:
+ _scene->_sequences.updateTimeout(-1, _globals._sequenceIndexes[5]);
+ _game._player._visible = true;
+ _game._player._stepEnabled = true;
+ _vm->_dialogs->showItem(OBJ_DOOR_KEY, 835);
+ break;
+
+ default:
+ break;
+ }
+ } else if (_action._lookFlag)
+ _vm->_dialogs->show(60210);
+ else if (_action.isAction(VERB_LOOK, NOUN_FLOOR))
+ _vm->_dialogs->show(60211);
+ else if (_action.isAction(VERB_LOOK, NOUN_HALLWAY))
+ _vm->_dialogs->show(60212);
+ else if (_action.isAction(VERB_LOOK, NOUN_TABLE))
+ _vm->_dialogs->show(60213);
+ else if (_action.isAction(VERB_LOOK, NOUN_CHAIR) || _action.isAction(VERB_LOOK, NOUN_LOUNGE_CHAIR))
+ _vm->_dialogs->show(60214);
+ else if (_action.isAction(VERB_LOOK, NOUN_NEON_LIGHTS))
+ _vm->_dialogs->show(60215);
+ else if (_action.isAction(VERB_LOOK, NOUN_FIREPLACE))
+ _vm->_dialogs->show(60216);
+ else if (_action.isAction(VERB_LOOK, NOUN_PICTURE))
+ _vm->_dialogs->show(60217);
+ else if (_action.isAction(VERB_LOOK, NOUN_LAMP))
+ _vm->_dialogs->show(60218);
+ else if (_action.isAction(VERB_LOOK, NOUN_MASKS))
+ _vm->_dialogs->show(60219);
+ else if (_action.isAction(VERB_LOOK, NOUN_GLASS_BLOCK_WALL))
+ _vm->_dialogs->show(60220);
+ else if (_action.isAction(VERB_LOOK, NOUN_DOORWAY))
+ _vm->_dialogs->show(60221);
+ else if (_action.isAction(VERB_LOOK, NOUN_SAFE)) {
+ if (_globals[kSafeStatus] == 0)
+ _vm->_dialogs->show(60222);
+ else if (_globals[kSafeStatus] == 1) {
+ if (!_game._objects.isInRoom(OBJ_DOOR_KEY))
+ _vm->_dialogs->show(60223);
+ else
+ _vm->_dialogs->show(60224);
+ } else if (_globals[kSafeStatus] == 2)
+ _vm->_dialogs->show(60234);
+ else if (_game._objects.isInRoom(OBJ_DOOR_KEY))
+ _vm->_dialogs->show(60235);
+ else
+ _vm->_dialogs->show(60236);
+ } else if (_action.isAction(VERB_UNLOCK, 0x6F, 0x3D3) || _action.isAction(VERB_UNLOCK, 0xFF, 0x3D3))
+ _vm->_dialogs->show(60225);
+ else if (_action.isAction(VERB_PULL, NOUN_SAFE))
+ _vm->_dialogs->show(60226);
+ else if (_action.isAction(VERB_PUT, NOUN_FIREPLACE) && _game._objects.isInInventory(_game._objects.getIdFromDesc(_action._activeAction._objectNameId)))
+ _vm->_dialogs->show(60227);
+ else if (_action.isAction(VERB_LOOK, NOUN_HOLE))
+ _vm->_dialogs->show(60228);
+ else if (_action.isAction(VERB_LOOK, NOUN_LASER_BEAM))
+ _vm->_dialogs->show(60229);
+ else if (_action.isAction(VERB_LOOK, NOUN_FLOWER_BOX))
+ _vm->_dialogs->show(60231);
+ else if (_action.isAction(VERB_THROW, NOUN_BOMB, 0x3D3) || _action.isAction(VERB_THROW, NOUN_BOMBS, 0x3D3))
+ _vm->_dialogs->show(60232);
+ else if (_action.isAction(VERB_PUT, NOUN_TIMEBOMB))
+ _vm->_dialogs->show(60233);
+ else
+ return;
+
+ _action._inProgress = false;
+}
+
+/*------------------------------------------------------------------------*/
+
+Scene603::Scene603(MADSEngine *vm) : Scene6xx(vm) {
+ _compactCaseHotspotId = -1;
+ _noteHotspotId = -1;
+}
+
+void Scene603::synchronize(Common::Serializer &s) {
+ Scene6xx::synchronize(s);
+
+ s.syncAsSint16LE(_compactCaseHotspotId);
+ s.syncAsSint16LE(_noteHotspotId);
+}
+
+void Scene603::setup() {
+ setPlayerSpritesPrefix();
+ setAAName();
+ _scene->addActiveVocab(VERB_WALKTO);
+ _scene->addActiveVocab(NOUN_COMPACT_CASE);
+ _scene->addActiveVocab(NOUN_NOTE);
+}
+
+void Scene603::enter() {
+ if (_game._objects[OBJ_COMPACT_CASE]._roomNumber == _scene->_currentSceneId) {
+ _globals._spriteIndexes[4] = _scene->_sprites.addSprites("*RXMRD_3");
+ _globals._spriteIndexes[1] = _scene->_sprites.addSprites(formAnimName('c', -1));
+ _globals._sequenceIndexes[1] = _scene->_sequences.startCycle(_globals._spriteIndexes[1], false, -1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 1);
+ _compactCaseHotspotId = _scene->_dynamicHotspots.add(NOUN_COMPACT_CASE, VERB_WALKTO, _globals._sequenceIndexes[1], Common::Rect(0, 0, 0, 0));
+ _scene->_dynamicHotspots.setPosition(_compactCaseHotspotId, Common::Point(250, 152), FACING_SOUTHEAST);
+ }
+
+ if ((_game._difficulty != DIFFICULTY_HARD) && (_game._objects[OBJ_NOTE]._roomNumber == _scene->_currentSceneId)) {
+ _globals._spriteIndexes[3] = _scene->_sprites.addSprites("*RXMRC_9");
+ _globals._spriteIndexes[2] = _scene->_sprites.addSprites(formAnimName('p', -1));
+ _globals._sequenceIndexes[2] = _scene->_sequences.startCycle(_globals._spriteIndexes[2], false, -1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 14);
+ _noteHotspotId = _scene->_dynamicHotspots.add(NOUN_NOTE, VERB_WALKTO, _globals._sequenceIndexes[2], Common::Rect(0, 0, 0, 0));
+ _scene->_dynamicHotspots.setPosition(_noteHotspotId, Common::Point(242, 118), FACING_NORTHEAST);
+ }
+
+ if (_scene->_priorSceneId != -2)
+ _game._player._playerPos = Common::Point(113, 134);
+
+ sceneEntrySound();
+}
+
+void Scene603::actions() {
+ if (_action.isAction(VERB_WALK_TOWARDS, NOUN_LIVINGROOM))
+ _scene->_nextSceneId = 602;
+ else if (_action.isAction(VERB_TAKE, NOUN_COMPACT_CASE)) {
+ if ( _game._trigger || !_game._objects.isInInventory(OBJ_COMPACT_CASE)) {
+ switch (_game._trigger) {
+ case 0:
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._sequenceIndexes[4] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[4], false, 8, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[4], 1, 5);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[4]);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[4], SEQUENCE_TRIGGER_SPRITE, 5, 1);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[4], SEQUENCE_TRIGGER_EXPIRE, 0, 2);
+ break;
+
+ case 1:
+ _vm->_sound->command(9);
+ _scene->_sequences.remove(_globals._sequenceIndexes[1]);
+ _scene->_dynamicHotspots.remove(_compactCaseHotspotId);
+ _game._objects.addToInventory(OBJ_COMPACT_CASE);
+ _vm->_dialogs->showItem(OBJ_COMPACT_CASE, 60330);
+ break;
+
+ case 2:
+ _scene->_sequences.updateTimeout(-1, _globals._sequenceIndexes[4]);
+ _game._player._visible = true;
+ _game._player._stepEnabled = true;
+ break;
+
+ default:
+ break;
+ }
+ }
+ } else if (_action.isAction(VERB_TAKE, NOUN_NOTE)) {
+ if ( _game._trigger || !_game._objects.isInInventory(OBJ_NOTE)) {
+ if (_game._trigger == 0) {
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._sequenceIndexes[3] = _scene->_sequences.startCycle(_globals._spriteIndexes[3], false, 1);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[3]);
+ _scene->_sequences.addTimer(15, 1);
+ } else if (_game._trigger == 1) {
+ _vm->_sound->command(9);
+ _scene->_sequences.remove(_globals._sequenceIndexes[2]);
+ _scene->_dynamicHotspots.remove(_noteHotspotId);
+ _game._objects.addToInventory(OBJ_NOTE);
+ _scene->_sequences.remove(_globals._sequenceIndexes[3]);
+ _game._player._priorTimer = _scene->_frameStartTime - _game._player._ticksAmount;
+ _game._player._visible = true;
+ _game._player._stepEnabled = true;
+ }
+ }
+ } else if (_action._lookFlag)
+ _vm->_dialogs->show(60310);
+ else if (_action.isAction(VERB_LOOK, NOUN_BED))
+ _vm->_dialogs->show(60311);
+ else if (_action.isAction(VERB_LOOK, NOUN_WIG_STAND))
+ _vm->_dialogs->show(60312);
+ else if (_action.isAction(VERB_TAKE, NOUN_WIG_STAND))
+ _vm->_dialogs->show(60313);
+ else if (_action.isAction(VERB_LOOK, NOUN_REVIEW))
+ _vm->_dialogs->show(60314);
+ else if (_action.isAction(VERB_LOOK, NOUN_SOUVENIR_TICKETS))
+ _vm->_dialogs->show(60315);
+ else if (_action.isAction(VERB_LOOK, NOUN_PHOTOGRAPH))
+ _vm->_dialogs->show(60316);
+ else if (_action.isAction(VERB_LOOK, NOUN_LAMP))
+ _vm->_dialogs->show(60317);
+ else if (_action.isAction(VERB_LOOK, NOUN_DIRECTORS_SLATE) || _action.isAction(VERB_LOOK, NOUN_CROP) || _action.isAction(VERB_LOOK, NOUN_MEGAPHONE))
+ _vm->_dialogs->show(60318);
+ else if (_action.isAction(VERB_LOOK, NOUN_SNAPSHOT))
+ _vm->_dialogs->show(60319);
+ else if (_action.isAction(VERB_TAKE, NOUN_SNAPSHOT))
+ _vm->_dialogs->show(60320);
+ else if (_action.isAction(VERB_LOOK, NOUN_PERFUME))
+ _vm->_dialogs->show(60321);
+ else if (_action.isAction(VERB_TAKE, NOUN_PERFUME))
+ _vm->_dialogs->show(60322);
+ else if (_action.isAction(VERB_TAKE, NOUN_NOTE))
+ _vm->_dialogs->show(60323);
+ else if (_action.isAction(VERB_LOOK, NOUN_NOTE)) {
+ if (_game._objects[OBJ_NOTE]._roomNumber == _scene->_currentSceneId)
+ _vm->_dialogs->show(60324);
+ } else if (_action.isAction(VERB_LOOK, NOUN_CORNER_TABLE)) {
+ if (_game._objects[OBJ_NOTE]._roomNumber == _scene->_currentSceneId)
+ _vm->_dialogs->show(60326);
+ else
+ _vm->_dialogs->show(60325);
+ } else if (_action.isAction(VERB_LOOK, NOUN_VANITY)) {
+ if (_game._objects[OBJ_COMPACT_CASE]._roomNumber == _scene->_currentSceneId)
+ _vm->_dialogs->show(60327);
+ else
+ _vm->_dialogs->show(60328);
+ } else if (_action.isAction(VERB_LOOK, NOUN_COMPACT_CASE) && (_action._mainObjectSource == 4))
+ _vm->_dialogs->show(60329);
+ // For the next two checks, the second part of the check wasn't surrounded par parenthesis, which was obviously wrong
+ else if (_action.isAction(VERB_LOOK) && (_action.isAction(0x31) || _action.isAction(0x3EA) || _action.isAction(0x3E8)))
+ _vm->_dialogs->show(60331);
+ else if (_action.isAction(VERB_TAKE) && (_action.isAction(0x31) || _action.isAction(0x3EA) || _action.isAction(0x3E8)))
+ _vm->_dialogs->show(60332);
+ else
+ return;
+
+ _action._inProgress = false;
+}
+
+/*------------------------------------------------------------------------*/
+
+Scene604::Scene604(MADSEngine *vm) : Scene6xx(vm) {
+ _timebombHotspotId = -1;
+ _bombMode = -1;
+ _monsterFrame = -1;
+
+ _monsterTimer = 0;
+
+ _monsterActive = false;
+ _animationActiveFl = false;
+}
+
+void Scene604::synchronize(Common::Serializer &s) {
+ Scene6xx::synchronize(s);
+
+ s.syncAsSint16LE(_timebombHotspotId);
+ s.syncAsSint16LE(_bombMode);
+ s.syncAsSint16LE(_monsterFrame);
+
+ s.syncAsUint32LE(_monsterTimer);
+
+ s.syncAsByte(_monsterActive);
+ s.syncAsByte(_animationActiveFl);
+}
+
+void Scene604::setup() {
+ setPlayerSpritesPrefix();
+ setAAName();
+ _scene->addActiveVocab(NOUN_SEA_MONSTER);
+ _scene->addActiveVocab(VERB_WALKTO);
+ _scene->addActiveVocab(NOUN_TIMEBOMB);
+}
+
+void Scene604::enter() {
+ _globals._spriteIndexes[2] = _scene->_sprites.addSprites(formAnimName('c', 0));
+ _globals._spriteIndexes[4] = _scene->_sprites.addSprites("*RXCD_9");
+ _globals._spriteIndexes[6] = _scene->_sprites.addSprites(Resources::formatName(620, 'b', 0, EXT_SS, ""));
+ _globals._spriteIndexes[5] = _scene->_sprites.addSprites("*RXMRC_9");
+
+ if (_globals[kTimebombStatus] == 1) {
+ _globals._sequenceIndexes[6] = _scene->_sequences.startCycle(_globals._spriteIndexes[6], false, -1);
+ _timebombHotspotId = _scene->_dynamicHotspots.add(NOUN_TIMEBOMB, VERB_WALKTO, _globals._sequenceIndexes[6], Common::Rect(0, 0, 0, 0));
+ _scene->_dynamicHotspots.setPosition(_timebombHotspotId, Common::Point(166, 118), FACING_NORTHEAST);
+ }
+
+ if (_scene->_roomChanged)
+ _game._objects.addToInventory(OBJ_TIMEBOMB);
+
+ _vm->_palette->setEntry(252, 63, 37, 26);
+ _vm->_palette->setEntry(253, 45, 24, 17);
+ _animationActiveFl = false;
+
+ if (_scene->_priorSceneId != -2) {
+ _game._player._playerPos = Common::Point(72, 149);
+ _game._player._facing = FACING_NORTHEAST;
+ _game._player._visible = false;
+ _game._player._stepEnabled = false;
+ _globals._sequenceIndexes[2] = _scene->_sequences.startCycle(_globals._spriteIndexes[2], false, -1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 1);
+ _scene->loadAnimation(formAnimName('R', 1), 70);
+ _animationActiveFl = true;
+ } else {
+ _globals._sequenceIndexes[2] = _scene->_sequences.startCycle(_globals._spriteIndexes[2], false, -2);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 1);
+ }
+
+ _monsterTimer = _scene->_frameStartTime;
+ _monsterActive = false;
+
+ sceneEntrySound();
+ _game.loadQuoteSet(0x2E7, 0x2E8, 0x2E9, 0x2EA, 0x2EB, 0x2EC, 0x2ED, 0x2EE, 0x2EF, 0x2F0, 0);
+}
+
+void Scene604::step() {
+ switch (_game._trigger) {
+ case 70:
+ _game._player._visible = true;
+ _game._player._priorTimer = _scene->_activeAnimation->getNextFrameTimer() - _game._player._ticksAmount;
+ _scene->_sequences.addTimer(30, 71);
+ break;
+
+ case 71:
+ _scene->_sequences.remove(_globals._sequenceIndexes[2]);
+ _globals._sequenceIndexes[2] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[2], false, 6, 1, 0, 0);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 1);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[2], SEQUENCE_TRIGGER_EXPIRE, 0, 72);
+ break;
+
+ case 72:
+ _globals._sequenceIndexes[2] = _scene->_sequences.startCycle(_globals._spriteIndexes[2], false, -2);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 1);
+ _game._player._stepEnabled = true;
+ _animationActiveFl = false;
+ break;
+
+ default:
+ break;
+ }
+
+ if (_monsterActive && (_scene->_activeAnimation != nullptr)) {
+ if (_scene->_activeAnimation->getCurrentFrame() != _monsterFrame) {
+ _monsterFrame = _scene->_activeAnimation->getCurrentFrame();
+ int nextMonsterFrame = -1;
+
+ switch (_monsterFrame) {
+ case 50:
+ case 137:
+ case 174: {
+ int randVal = _vm->getRandomNumber(1, 1000);
+ if ((randVal <= 450) && (_game._player._special)) {
+ if (_game._player._special == 1)
+ nextMonsterFrame = 50;
+ else if (_game._player._special == 2)
+ nextMonsterFrame = 84;
+ else
+ nextMonsterFrame = 137;
+ } else if (randVal <= 150)
+ nextMonsterFrame = 50;
+ else if (randVal <= 300)
+ nextMonsterFrame = 84;
+ else if (randVal <= 450)
+ nextMonsterFrame = 137;
+ else if (randVal < 750)
+ nextMonsterFrame = 13;
+ else
+ nextMonsterFrame = 114;
+
+ }
+ break;
+
+ case 84:
+ nextMonsterFrame = 14;
+ break;
+
+ default:
+ break;
+ }
+
+ if ((nextMonsterFrame >= 0) && (nextMonsterFrame != _monsterFrame)) {
+ _scene->_activeAnimation->setCurrentFrame(nextMonsterFrame);
+ _monsterFrame = nextMonsterFrame;
+ }
+ }
+ }
+
+ if ((!_monsterActive && !_animationActiveFl) && (_scene->_frameStartTime > (_monsterTimer + 4))) {
+ _monsterTimer = _scene->_frameStartTime;
+ if ((_vm->getRandomNumber(1, 1000) < 25) || !_game._visitedScenes._sceneRevisited) {
+ _monsterActive = true;
+ _scene->freeAnimation();
+ _scene->loadAnimation(formAnimName('m', -1));
+ }
+ }
+}
+
+void Scene604::handleBombActions() {
+ switch (_game._trigger) {
+ case 0:
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._sequenceIndexes[5] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[5], false, 9, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[5], 1, 3);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[5]);
+ if (_bombMode == 1)
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[5], SEQUENCE_TRIGGER_SPRITE, 3, 1);
+ else
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[5], SEQUENCE_TRIGGER_SPRITE, 3, 2);
+
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[5], SEQUENCE_TRIGGER_EXPIRE, 0, 3);
+ break;
+
+ case 1:
+ _globals._sequenceIndexes[6] = _scene->_sequences.startCycle(_globals._spriteIndexes[6], false, -1);
+ _timebombHotspotId = _scene->_dynamicHotspots.add(NOUN_TIMEBOMB, VERB_WALKTO, _globals._sequenceIndexes[6], Common::Rect(0, 0, 0, 0));
+ _scene->_dynamicHotspots.setPosition(_timebombHotspotId, Common::Point(166, 118), FACING_NORTHEAST);
+ _game._objects.setRoom(OBJ_TIMEBOMB, _scene->_currentSceneId);
+ break;
+
+ case 2:
+ _scene->_sequences.remove(_globals._sequenceIndexes[6]);
+ _scene->_dynamicHotspots.remove(_timebombHotspotId);
+ _game._objects.addToInventory(OBJ_TIMEBOMB);
+ break;
+
+ case 3:
+ _scene->_sequences.updateTimeout(-1, _globals._sequenceIndexes[5]);
+ _game._player._visible = true;
+ _game._player._stepEnabled = true;
+ if (_bombMode == 1) {
+ _vm->_dialogs->show(60421);
+ _globals[kTimebombStatus] = TIMEBOMB_ACTIVATED;
+ _globals[kTimebombTimer] = 0;
+ } else {
+ _vm->_dialogs->show(60423);
+ _globals[kTimebombStatus] = TIMEBOMB_DEACTIVATED;
+ _globals[kTimebombTimer] = 0;
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+void Scene604::actions() {
+ if (_action.isAction(0x325, 0x324)) {
+ switch (_game._trigger) {
+ case 0:
+ _game._player._stepEnabled = false;
+ _scene->_sequences.remove(_globals._sequenceIndexes[2]);
+ _globals._sequenceIndexes[2] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[2], false, 6, 1, 0, 0);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 1);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[2], SEQUENCE_TRIGGER_EXPIRE, 0, 1);
+ break;
+
+ case 1: {
+ int syncIdx = _globals._sequenceIndexes[2];
+ _globals._sequenceIndexes[2] = _scene->_sequences.startCycle(_globals._spriteIndexes[2], false, -1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 1);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[2], syncIdx);
+ _scene->_sequences.addTimer(6, 2);
+ }
+ break;
+
+ case 2:
+ _game._player._visible = false;
+ _globals._sequenceIndexes[4] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[4], false, 10, 1, 0, 0);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[4]);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[4], SEQUENCE_TRIGGER_EXPIRE, 0, 3);
+ break;
+
+ case 3: {
+ int syncIdx = _globals._sequenceIndexes[4];
+ _globals._sequenceIndexes[4] = _scene->_sequences.startCycle(_globals._spriteIndexes[4], false, -2);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[4]);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[4], syncIdx);
+ _scene->_nextSceneId = 504;
+ }
+ break;
+
+ default:
+ break;
+ }
+ } else if ((_action.isAction(VERB_PUT, NOUN_LEDGE) || _action.isAction(VERB_PUT, NOUN_VIEWPORT) || _action.isAction(VERB_THROW, NOUN_VIEWPORT))
+ && (_action.isAction(0x2A) || _action.isAction(0x2B)))
+ _vm->_dialogs->show(60420);
+ else if (_action.isAction(VERB_PUT, NOUN_TIMEBOMB, 0x3F6) || _action.isAction(VERB_PUT, NOUN_TIMEBOMB, 0x181)) {
+ _bombMode = 1;
+ if ((_game._difficulty == DIFFICULTY_HARD) || _globals[kWarnedFloodCity])
+ handleBombActions();
+ else if ((_game._objects.isInInventory(OBJ_POLYCEMENT) && _game._objects.isInInventory(OBJ_CHICKEN))
+ && ((_globals[kLineStatus] == LINE_TIED) || ((_game._difficulty == DIFFICULTY_EASY) && (!_globals[kBoatRaised]))))
+ handleBombActions();
+ else if (_game._difficulty == DIFFICULTY_EASY)
+ _vm->_dialogs->show(60424);
+ else {
+ _vm->_dialogs->show(60425);
+ _globals[kWarnedFloodCity] = true;
+ }
+ } else if (_action.isAction(VERB_TAKE, NOUN_TIMEBOMB)) {
+ if (_game._trigger || !_game._objects.isInInventory(OBJ_TIMEBOMB)) {
+ _bombMode = 2;
+ handleBombActions();
+ }
+ } else if (_action._lookFlag)
+ _vm->_dialogs->show(60411);
+ else if (_action.isAction(VERB_LOOK, NOUN_VIEWPORT)) {
+ if (_monsterActive) {
+ _vm->_dialogs->show(60413);
+ } else {
+ _vm->_dialogs->show(60412);
+ }
+ } else if (_action.isAction(VERB_LOOK, NOUN_WALL))
+ _vm->_dialogs->show(60414);
+ else if (_action.isAction(VERB_LOOK, NOUN_VENT))
+ _vm->_dialogs->show(60415);
+ else if (_action.isAction(VERB_LOOK, NOUN_INDICATOR))
+ _vm->_dialogs->show(60416);
+ else if (_action.isAction(VERB_LOOK, NOUN_SCULPTURE))
+ _vm->_dialogs->show(60417);
+ else if (_action.isAction(VERB_LOOK, NOUN_CAR))
+ _vm->_dialogs->show(60418);
+ else if (_action.isAction(VERB_LOOK, NOUN_FOUNTAIN))
+ _vm->_dialogs->show(60419);
+ else
+ return;
+
+ _action._inProgress = false;
+}
+
+/*------------------------------------------------------------------------*/
+
+void Scene605::setup() {
+ _game._player._spritesPrefix = "";
+ setAAName();
+}
+
+void Scene605::enter() {
+ _globals._spriteIndexes[1] = _scene->_sprites.addSprites(formAnimName('r', -1));
+ _globals._spriteIndexes[2] = _scene->_sprites.addSprites(formAnimName('b', -1));
+ _globals._spriteIndexes[3] = _scene->_sprites.addSprites(formAnimName('l', -1));
+ _globals._spriteIndexes[4] = _scene->_sprites.addSprites(formAnimName('p', -1));
+ _globals._spriteIndexes[5] = _scene->_sprites.addSprites(formAnimName('n', -1));
+ _globals._spriteIndexes[6] = _scene->_sprites.addSprites(formAnimName('f', -1));
+
+ _globals._sequenceIndexes[1] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[1], false, 15, 0, 0, 0);
+ _globals._sequenceIndexes[2] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[2], false, 17, 0, 0, 0);
+ _globals._sequenceIndexes[3] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[3], false, 14, 0, 0, 0);
+ _globals._sequenceIndexes[4] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[4], false, 13, 0, 0, 0);
+ _globals._sequenceIndexes[5] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[5], false, 17, 0, 0, 0);
+ _globals._sequenceIndexes[6] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[6], false, 18, 0, 0, 0);
+
+ _game._player._visible = false;
+ _game._player._stepEnabled = false;
+ _scene->_sequences.addTimer(600, 70);
+ _scene->_userInterface.setup(kInputLimitedSentences);
+ sceneEntrySound();
+ _vm->_sound->command(22);
+}
+
+void Scene605::step() {
+ if (_game._trigger == 70) {
+ _vm->_sound->command(23);
+ if (_globals[kResurrectRoom] >= 700)
+ _vm->_dialogs->show(60598);
+ else
+ _vm->_dialogs->show(60599);
+
+ _scene->_nextSceneId = _globals[kResurrectRoom];
+ }
+}
+
+void Scene605::actions() {
+ return;
+}
+
+/*------------------------------------------------------------------------*/
+
+Scene607::Scene607(MADSEngine *vm) : Scene6xx(vm) {
+ _dogTimer = 0;
+ _lastFrameTime = 0;
+
+ _dogLoop = false;
+ _dogEatsRex = false;
+ _dogBarking = false;
+ _shopAvailable = false;
+
+ _animationMode = -1;
+ _animationActive = -1;
+ _counter = -1;
+}
+
+void Scene607::synchronize(Common::Serializer &s) {
+ Scene6xx::synchronize(s);
+
+ s.syncAsUint32LE(_dogTimer);
+ s.syncAsUint32LE(_lastFrameTime);
+
+ s.syncAsByte(_dogLoop);
+ s.syncAsByte(_dogEatsRex);
+ s.syncAsByte(_dogBarking);
+ s.syncAsByte(_shopAvailable);
+
+ s.syncAsSint16LE(_animationMode);
+ s.syncAsSint16LE(_animationActive);
+ s.syncAsSint16LE(_counter);
+}
+
+void Scene607::setup() {
+ setPlayerSpritesPrefix();
+ setAAName();
+ _scene->addActiveVocab(NOUN_OBNOXIOUS_DOG);
+ _scene->addActiveVocab(VERB_WALKTO);
+}
+
+void Scene607::enter() {
+ _globals._spriteIndexes[2] = _scene->_sprites.addSprites(formAnimName('c', 0));
+ _globals._spriteIndexes[3] = _scene->_sprites.addSprites("*RXCD_3");
+
+ if (!_game._visitedScenes._sceneRevisited && (_scene->_priorSceneId != 608))
+ _globals[kDogStatus] = 1;
+
+ if ((_scene->_priorSceneId == 608) && (_globals[kDogStatus] < 3))
+ _globals[kDogStatus] = 3;
+
+ _animationActive = 0;
+
+ if ((_globals[kDogStatus] == 1) && (_game._difficulty != DIFFICULTY_EASY)) {
+ _globals._spriteIndexes[4] = _scene->_sprites.addSprites(formAnimName('g', 3));
+ _globals._spriteIndexes[5] = _scene->_sprites.addSprites(formAnimName('g', 7));
+ _globals._spriteIndexes[1] = _scene->_sprites.addSprites(formAnimName('g', 0));
+
+ _globals._sequenceIndexes[1] = _scene->_sequences.startCycle(_globals._spriteIndexes[1], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 6);
+ _dogBarking = false;
+ _dogLoop = false;
+ _shopAvailable = false;
+ _dogEatsRex = false;
+ _dogTimer = 0;
+ } else
+ _scene->_hotspots.activate(NOUN_OBNOXIOUS_DOG, false);
+
+ _globals._sequenceIndexes[2] = _scene->_sequences.startCycle(_globals._spriteIndexes[2], false, -2);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 4);
+
+ if (_scene->_priorSceneId == 608) {
+ _game._player._playerPos = Common::Point(297, 50);
+ _game._player._facing = FACING_SOUTHEAST;
+ } else if (_scene->_priorSceneId != -2) {
+ _game._player._playerPos = Common::Point(40, 104);
+ _game._player._facing = FACING_SOUTHEAST;
+ _game._player._visible = false;
+ _game._player._stepEnabled = false;
+ _scene->_sequences.remove(_globals._sequenceIndexes[2]);
+ _globals._sequenceIndexes[2] = _scene->_sequences.startCycle(_globals._spriteIndexes[2], false, -1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 4);
+ _scene->loadAnimation(formAnimName('R', 1), 80);
+ } else if (_globals[kDogStatus] == 2) {
+ _globals._spriteIndexes[4] = _scene->_sprites.addSprites(formAnimName('g', 3));
+ _globals._spriteIndexes[5] = _scene->_sprites.addSprites(formAnimName('g', 7));
+ _globals._spriteIndexes[1] = _scene->_sprites.addSprites(formAnimName('g', 0));
+ }
+
+ sceneEntrySound();
+
+ if (_scene->_roomChanged)
+ _game._objects.addToInventory(OBJ_BONES);
+
+ _vm->_palette->setEntry(252, 63, 44, 30);
+ _vm->_palette->setEntry(253, 63, 20, 22);
+ _game.loadQuoteSet(0x2F8, 0x2F7, 0x2F6, 0x2F9, 0x2FA, 0);
+}
+
+void Scene607::step() {
+ if (_globals[kDogStatus] == 2) {
+ int32 diff = _scene->_frameStartTime - _lastFrameTime;
+ if ((diff >= 0) && (diff <= 4))
+ _dogTimer += diff;
+ else
+ _dogTimer++;
+
+ _lastFrameTime = _scene->_frameStartTime;
+ }
+
+ if ((_dogTimer >= 480) && !_dogLoop && !_shopAvailable && (_globals[kDogStatus] == 2) && !_game._player._special) {
+ _vm->_sound->command(14);
+ _dogLoop = true;
+ _globals._sequenceIndexes[5] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[5], false, 10, 1, 0, 0);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[5], 1);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[5], SEQUENCE_TRIGGER_EXPIRE, 0, 91);
+ _dogLoop = false;
+ _dogTimer = 0;
+ }
+
+ if (_game._trigger == 91) {
+ _globals._sequenceIndexes[1] = _scene->_sequences.startCycle(_globals._spriteIndexes[1], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 6);
+ _dogBarking = false;
+ _globals[kDogStatus] = 1;
+ _scene->_hotspots.activate(NOUN_OBNOXIOUS_DOG, true);
+ }
+
+ if (!_dogEatsRex && (_game._difficulty != DIFFICULTY_EASY) && !_animationActive && (_globals[kDogStatus] == 1)
+ && !_dogBarking && (_vm->getRandomNumber(1, 50) == 10)) {
+ _dogBarking = true;
+ _scene->_sequences.remove(_globals._sequenceIndexes[1]);
+ _globals._sequenceIndexes[1] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[1], false, 5, 8, 0, 0);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 6);
+ _scene->_kernelMessages.reset();
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[1], SEQUENCE_TRIGGER_SPRITE, 2, 100);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[1], SEQUENCE_TRIGGER_EXPIRE, 0, 70);
+ _counter = 0;
+ }
+
+ if ((_game._trigger == 70) && !_dogEatsRex && (_globals[kDogStatus] == 1) && !_animationActive) {
+ int syncIdx = _globals._sequenceIndexes[1];
+ _globals._sequenceIndexes[1] = _scene->_sequences.startCycle(_globals._spriteIndexes[1], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 6);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[1], syncIdx);
+ _scene->_kernelMessages.reset();
+ _dogBarking = false;
+ }
+
+ if (_game._trigger == 100) {
+ _counter++;
+ _vm->_sound->command(12);
+
+ if ((_counter >= 1) && (_counter <= 4)) {
+ Common::Point pos(0, 0);
+ switch (_counter) {
+ case 1:
+ pos = Common::Point(237, 5);
+ break;
+
+ case 2:
+ pos = Common::Point(270, 15);
+ break;
+
+ case 3:
+ pos = Common::Point(237, 25);
+ break;
+
+ case 4:
+ pos = Common::Point(270, 36);
+ break;
+
+ default:
+ break;
+ }
+ _scene->_kernelMessages.add(pos, 0xFDFC, 0, 0, 120, _game.getQuote(0x2F9));
+ }
+ }
+
+ if (_game._player._moving && (_game._difficulty != DIFFICULTY_EASY) && !_shopAvailable && (_globals[kDogStatus] == 1) && (_scene->_rails.getNext() > 0)) {
+ _game._player.cancelCommand();
+ _game._player.startWalking(Common::Point(268, 72), FACING_NORTHEAST);
+ _scene->_rails.resetNext();
+ }
+
+ if ((_game._player._special > 0) && (_game._difficulty != DIFFICULTY_EASY) && (_globals[kDogStatus] == 1) && _game._player._stepEnabled)
+ _game._player._stepEnabled = false;
+
+ if ((_game._difficulty != DIFFICULTY_EASY) && (_globals[kDogStatus] == 1) && (_game._player._playerPos == Common::Point(268, 72))
+ && (_game._trigger || !_dogEatsRex)) {
+ _dogEatsRex = true;
+ switch (_game._trigger) {
+ case 91:
+ case 0:
+ _animationActive = 1;
+ _game._player._visible = false;
+ _scene->_sequences.remove(_globals._sequenceIndexes[1]);
+ _globals._sequenceIndexes[4] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[4], false, 10, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[4], -1, 7);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[4], 1);
+ _scene->_kernelMessages.reset();
+ _scene->_kernelMessages.add(Common::Point(0, 0), 0x1110, 34, 0, 120, _game.getQuote(0x2FA));
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[4], SEQUENCE_TRIGGER_EXPIRE, 0, 60);
+ _scene->_sequences.addTimer(10, 64);
+ break;
+
+ case 60: {
+ int syncIdx = _globals._sequenceIndexes[4];
+ _globals._sequenceIndexes[4] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[4], false, 5, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[4], 8, 45);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[4], 1);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[4], syncIdx);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[4], SEQUENCE_TRIGGER_EXPIRE, 0, 61);
+ }
+ break;
+
+ case 61: {
+ int syncIdx = _globals._sequenceIndexes[4];
+ _globals._sequenceIndexes[4] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[4], false, 15, 3, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[4], 46, -2);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[4], 1);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[4], syncIdx);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[4], SEQUENCE_TRIGGER_EXPIRE, 0, 62);
+ }
+ break;
+
+ case 62: {
+ int syncIdx = _globals._sequenceIndexes[4];
+ _animationActive = 2;
+ _globals._sequenceIndexes[4] = _scene->_sequences.startCycle(_globals._spriteIndexes[4], false, -2);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[4], 1);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[4], syncIdx);
+ _scene->_sequences.addTimer(60, 63);
+ }
+ break;
+
+ case 63:
+ _vm->_dialogs->show(60729);
+ _animationActive = 0;
+ _dogEatsRex = false;
+ _scene->_reloadSceneFlag = true;
+ _game._player._stepEnabled = true;
+ break;
+
+ case 64:
+ if (_dogEatsRex && (_animationActive == 1)) {
+ _vm->_sound->command(12);
+ _scene->_sequences.addTimer(10, 64);
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ switch (_game._trigger) {
+ case 80:
+ _game._player._visible = true;
+ _game._player._priorTimer = _scene->_activeAnimation->getNextFrameTimer() - _game._player._ticksAmount;
+ _scene->_sequences.addTimer(6, 81);
+ break;
+
+ case 81:
+ _scene->_sequences.remove(_globals._sequenceIndexes[2]);
+ _globals._sequenceIndexes[2] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[2], false, 6, 1, 0, 0);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 4);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[2], SEQUENCE_TRIGGER_EXPIRE, 0, 82);
+ break;
+
+ case 82:
+ _globals._sequenceIndexes[2] = _scene->_sequences.startCycle(_globals._spriteIndexes[2], false, -2);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 4);
+ _game._player._stepEnabled = true;
+ break;
+
+ default:
+ break;
+ }
+}
+
+void Scene607::handleThrowingBone() {
+ _animationActive = -1;
+ switch (_game._trigger) {
+ case 0:
+ _game._player._stepEnabled = false;
+ _scene->_sequences.remove(_globals._sequenceIndexes[1]);
+ _game._player._visible = false;
+ _scene->loadAnimation(formAnimName('D', _animationMode), 1);
+ break;
+
+ case 1:
+ _game._player._visible = true;
+ _game._player._priorTimer = _scene->_activeAnimation->getNextFrameTimer() - _game._player._ticksAmount;
+
+ if (_animationMode != 1)
+ _scene->_hotspots.activate(NOUN_OBNOXIOUS_DOG, false);
+ else {
+ _globals._sequenceIndexes[1] = _scene->_sequences.startCycle(_globals._spriteIndexes[1], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 6);
+ }
+
+ _dogBarking = false;
+ if (_game._objects.isInInventory(OBJ_BONE)) {
+ _game._objects.setRoom(OBJ_BONE, 1);
+ if (_animationMode == 1)
+ _globals[kBone202Status] = 0;
+ } else {
+ _game._objects.setRoom(OBJ_BONES, 1);
+ _game._objects.addToInventory(OBJ_BONE);
+ }
+
+ _scene->_sequences.addTimer(60, 2);
+ break;
+
+ case 2: {
+ int quoteId = 0x2F8;
+ if (_animationMode == 1)
+ quoteId = 0x2F7;
+
+ if (_animationMode == 2) {
+ _globals[kDogStatus] = 2;
+ _dogTimer = 0;
+ }
+
+ _scene->_kernelMessages.reset();
+ _scene->_kernelMessages.add(Common::Point(0, 0), 0x1110, 34, 0, 120, _game.getQuote(quoteId));
+ _scene->_sequences.addTimer(60, 3);
+ }
+ break;
+
+ case 3:
+ _game._player._stepEnabled = true;
+ _animationActive = 0;
+ break;
+
+ default:
+ break;
+ }
+}
+
+void Scene607::preActions() {
+ if (_action.isAction(VERB_TALKTO, NOUN_OBNOXIOUS_DOG))
+ _game._player._needToWalk = false;
+
+ if (_action.isAction(VERB_WALK_THROUGH, NOUN_SIDE_ENTRANCE) && (_globals[kDogStatus] == 2) && (_game._difficulty != DIFFICULTY_EASY)) {
+ _shopAvailable = true;
+ _dogTimer = 0;
+ }
+
+ if (_action.isAction(VERB_THROW, NOUN_BONES, 0x471) || _action.isAction(VERB_THROW, NOUN_BONE, 0x471))
+ _game._player.walk(Common::Point(193, 100), FACING_NORTHEAST);
+
+ if (_action.isAction(VERB_THROW, NOUN_BONES, 0x2C3) || _action.isAction(VERB_THROW, NOUN_BONE, 0x2C3))
+ _game._player.walk(Common::Point(201, 107), FACING_SOUTHEAST);
+}
+
+void Scene607::actions() {
+ if (_action.isAction(VERB_WALK_THROUGH, NOUN_SIDE_ENTRANCE))
+ _scene->_nextSceneId = 608;
+ else if (_action.isAction(0x325, 0x324)) {
+ switch (_game._trigger) {
+ case 0:
+ _game._player._stepEnabled = false;
+ _scene->_sequences.remove(_globals._sequenceIndexes[2]);
+ _globals._sequenceIndexes[2] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[2], false, 6, 1, 0, 0);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 4);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[2], SEQUENCE_TRIGGER_EXPIRE, 0, 1);
+ break;
+
+ case 1: {
+ int syncIdx = _globals._sequenceIndexes[2];
+ _globals._sequenceIndexes[2] = _scene->_sequences.startCycle(_globals._spriteIndexes[2], false, -1);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[2], syncIdx);
+ _scene->_sequences.addTimer(6, 2);
+ }
+ break;
+
+ case 2:
+ _game._player._visible = false;
+ _globals._sequenceIndexes[3] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[3], false, 10, 1, 0, 0);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[3]);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[3], SEQUENCE_TRIGGER_EXPIRE, 0, 3);
+ break;
+
+ case 3: {
+ int syncIdx = _globals._sequenceIndexes[3];
+ _globals._sequenceIndexes[3] = _scene->_sequences.startCycle(_globals._spriteIndexes[3], false, -2);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[3]);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[3], syncIdx);
+ _scene->_nextSceneId = 504;
+ }
+ break;
+
+ default:
+ break;
+ }
+ } else if (_action.isAction(VERB_THROW, NOUN_BONES, 0x471) || _action.isAction(VERB_THROW, NOUN_BONE, 0x471)) {
+ if (_game._difficulty != DIFFICULTY_EASY) {
+ _animationMode = 1;
+ _scene->_kernelMessages.reset();
+ if (_game._trigger == 0)
+ _scene->_kernelMessages.add(Common::Point(0, 0), 0x1110, 34, 0, 120, _game.getQuote(0x2F6));
+
+ handleThrowingBone();
+ }
+ } else if ((_action.isAction(VERB_THROW, NOUN_BONES, 0x2C3) || _action.isAction(VERB_THROW, NOUN_BONE, 0x2C3)) && (_game._difficulty != DIFFICULTY_EASY)
+ && ((_globals[kDogStatus] == 1) || _game._trigger)) {
+ _animationMode = 2;
+ if (_game._trigger == 0) {
+ _scene->_kernelMessages.reset();
+ _scene->_kernelMessages.add(Common::Point(0, 0), 0x1110, 34, 0, 120, _game.getQuote(0x2F6));
+ }
+ handleThrowingBone();
+ } else if (_action._lookFlag || _action.isAction(VERB_LOOK, NOUN_STREET)) {
+ if ((_globals[kDogStatus] == 1) || (_game._difficulty == DIFFICULTY_EASY))
+ _vm->_dialogs->show(60710);
+ else
+ _vm->_dialogs->show(60711);
+ } else if (_action.isAction(VERB_LOOK, NOUN_WALL))
+ _vm->_dialogs->show(60712);
+ else if (_action.isAction(VERB_LOOK, NOUN_FENCE))
+ _vm->_dialogs->show(60713);
+ else if (_action.isAction(VERB_LOOK, NOUN_CAR))
+ _vm->_dialogs->show(60714);
+ else if (_action.isAction(VERB_LOOK, NOUN_MANHOLE))
+ _vm->_dialogs->show(60715);
+ else if (_action.isAction(VERB_LOOK, NOUN_FIRE_HYDRANT) && (_globals[kDogStatus] == 1))
+ _vm->_dialogs->show(60716);
+ else if (_action.isAction(VERB_LOOK, NOUN_SIGN))
+ _vm->_dialogs->show(60717);
+ else if (_action.isAction(VERB_LOOK, NOUN_BROKEN_WINDOW))
+ _vm->_dialogs->show(60718);
+ else if (_action.isAction(VERB_LOOK, NOUN_GARAGE_DOOR))
+ _vm->_dialogs->show(60719);
+ else if (_action.isAction(VERB_LOOK, NOUN_SIDEWALK))
+ _vm->_dialogs->show(60720);
+ else if (_action.isAction(VERB_LOOK, NOUN_AIR_HOSE))
+ _vm->_dialogs->show(60721);
+ else if (_action.isAction(VERB_LOOK, NOUN_AUTO_SHOP)) {
+ if (_globals[kDogStatus] == 1)
+ _vm->_dialogs->show(60723);
+ else
+ _vm->_dialogs->show(60722);
+ } else if (_action.isAction(VERB_LOOK, NOUN_SIDE_ENTRANCE)) {
+ if (_globals[kDogStatus] == 1)
+ _vm->_dialogs->show(60725);
+ else
+ _vm->_dialogs->show(60724);
+ } else if (_action.isAction(VERB_LOOK, NOUN_OBNOXIOUS_DOG))
+ _vm->_dialogs->show(60726);
+ else if (_action.isAction(VERB_TALKTO, NOUN_OBNOXIOUS_DOG))
+ _vm->_dialogs->show(60727);
+ else if (_action.isAction(VERB_LOOK, NOUN_BARRICADE))
+ _vm->_dialogs->show(60728);
+ else if (_action.isAction(VERB_WALK_DOWN, NOUN_STREET))
+ _vm->_dialogs->show(60730);
+ else if (_action.isAction(0x3FF) && (_action.isAction(VERB_OPEN) || _action.isAction(VERB_PUSH) || _action.isAction(VERB_PULL)))
+ _vm->_dialogs->show(60731);
+ else
+ return;
+
+ _action._inProgress = false;
+}
+
+/*------------------------------------------------------------------------*/
+
+Scene608::Scene608(MADSEngine *vm) : Scene6xx(vm) {
+ _carMode = -1;
+ _carFrame = -1;
+ _carMoveMode = -1;
+ _dogDeathMode = -1;
+ _carHotspotId = -1;
+ _barkCount = -1;
+ _polycementHotspotId = -1;
+ _animationMode = -1;
+ _nextTrigger = -1;
+ _throwMode = -1;
+
+ _resetPositionsFl = false;
+ _dogActiveFl = false;
+ _dogBarkingFl = false;
+ _dogFirstEncounter = false;
+ _rexBeingEaten = false;
+ _dogHitWindow = false;
+ _checkFl = false;
+ _dogSquashFl = false;
+ _dogSafeFl = false;
+ _buttonPressedonTimeFl = false;
+ _dogUnderCar = false;
+ _dogYelping = false;
+
+ _dogWindowTimer = -1;
+ _dogRunTimer = -1;
+
+ _dogTimer1 = 0;
+ _dogTimer2 = 0;
+}
+
+void Scene608::synchronize(Common::Serializer &s) {
+ Scene6xx::synchronize(s);
+
+ s.syncAsSint16LE(_carMode);
+ s.syncAsSint16LE(_carFrame);
+ s.syncAsSint16LE(_carMoveMode);
+ s.syncAsSint16LE(_dogDeathMode);
+ s.syncAsSint16LE(_carHotspotId);
+ s.syncAsSint16LE(_barkCount);
+ s.syncAsSint16LE(_polycementHotspotId);
+ s.syncAsSint16LE(_animationMode);
+ s.syncAsSint16LE(_nextTrigger);
+ s.syncAsSint16LE(_throwMode);
+
+ s.syncAsByte(_resetPositionsFl);
+ s.syncAsByte(_dogActiveFl);
+ s.syncAsByte(_dogBarkingFl);
+ s.syncAsByte(_dogFirstEncounter);
+ s.syncAsByte(_rexBeingEaten);
+ s.syncAsByte(_dogHitWindow);
+ s.syncAsByte(_checkFl);
+ s.syncAsByte(_dogSquashFl);
+ s.syncAsByte(_dogSafeFl);
+ s.syncAsByte(_buttonPressedonTimeFl);
+ s.syncAsByte(_dogUnderCar);
+ s.syncAsByte(_dogYelping);
+
+ s.syncAsSint32LE(_dogWindowTimer);
+ s.syncAsSint32LE(_dogRunTimer);
+
+ s.syncAsUint32LE(_dogTimer1);
+ s.syncAsUint32LE(_dogTimer2);
+}
+
+void Scene608::setup() {
+ setPlayerSpritesPrefix();
+ setAAName();
+ _scene->addActiveVocab(VERB_WALKTO);
+ _scene->addActiveVocab(NOUN_POLYCEMENT);
+ _scene->addActiveVocab(NOUN_CAR);
+ _scene->addActiveVocab(NOUN_OBNOXIOUS_DOG);
+}
+
+void Scene608::resetDogVariables() {
+ _globals._sequenceIndexes[5] = _scene->_sequences.startCycle(_globals._spriteIndexes[5], false, 1);
+ int idx = _scene->_dynamicHotspots.add(NOUN_OBNOXIOUS_DOG, VERB_WALKTO, _globals._sequenceIndexes[5], Common::Rect(0, 0, 0, 0));
+ _scene->_dynamicHotspots.setPosition(idx, Common::Point(194, 142), FACING_EAST);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[5], 4);
+ _dogBarkingFl = false;
+ _dogFirstEncounter = false;
+}
+
+void Scene608::restoreAnimations() {
+ _scene->freeAnimation();
+ _carMode = 0;
+ _game._player._stepEnabled = true;
+ if (_throwMode == 6)
+ _dogSquashFl = true;
+
+ if (_globals[kCarStatus] == 0) {
+ _scene->_sequences.remove(_globals._sequenceIndexes[6]);
+ _scene->_sequences.remove(_globals._sequenceIndexes[7]);
+ _scene->loadAnimation(formAnimName('A', -1));
+ } else {
+ _scene->_sequences.remove(_globals._sequenceIndexes[8]);
+ _scene->_sequences.remove(_globals._sequenceIndexes[6]);
+ _scene->_sequences.remove(_globals._sequenceIndexes[7]);
+ _scene->loadAnimation(formAnimName('A', -1));
+ _scene->_activeAnimation->setCurrentFrame(6);
+ }
+}
+
+void Scene608::setCarAnimations() {
+ _scene->freeAnimation();
+ if (_globals[kCarStatus] == 0) {
+ _globals._sequenceIndexes[6] = _scene->_sequences.startCycle(_globals._spriteIndexes[6], false, 1);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[6], Common::Point(143, 98));
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[6], 6);
+ _globals._sequenceIndexes[7] = _scene->_sequences.startCycle(_globals._spriteIndexes[7], false, 1);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[7], Common::Point(141, 67));
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[7], 15);
+ } else {
+ _globals._sequenceIndexes[6] = _scene->_sequences.startCycle(_globals._spriteIndexes[6], false, 1);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[6], Common::Point(143, 128));
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[6], 6);
+ _globals._sequenceIndexes[7] = _scene->_sequences.startCycle(_globals._spriteIndexes[7], false, 1);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[7], Common::Point(141, 97));
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[7], 15);
+ _globals._sequenceIndexes[8] = _scene->_sequences.startCycle(_globals._spriteIndexes[8], false, 1);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[8], Common::Point(144, 126));
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[8], 5);
+ }
+}
+
+void Scene608::handleThrowingBone() {
+ switch (_game._trigger) {
+ case 0:
+ _game._player._stepEnabled = false;
+ setCarAnimations();
+ _scene->_sequences.remove(_globals._sequenceIndexes[5]);
+ _animationMode = -1;
+ _game._player._visible = false;
+ _carMode = _throwMode;
+ if (_throwMode == 4)
+ _scene->loadAnimation(formAnimName('X', 2), 1);
+ else if (_throwMode == 5)
+ _scene->loadAnimation(formAnimName('X', 1), 1);
+ else
+ _scene->loadAnimation(formAnimName('X', 3), 1);
+ break;
+
+ case 1:
+ _nextTrigger = 1;
+ _scene->_sequences.addTimer(1, 2);
+ break;
+
+ case 2:
+ if (_nextTrigger != 2)
+ _scene->_sequences.addTimer(1, 2);
+ else {
+ if (_game._objects.isInInventory(OBJ_BONE))
+ _game._objects.setRoom(OBJ_BONE, 1);
+ else {
+ _game._objects.setRoom(OBJ_BONES, 1);
+ _game._objects.addToInventory(OBJ_BONE);
+ }
+ _scene->_sequences.addTimer(60, 3);
+ }
+ break;
+
+ case 3:
+ if (_throwMode != 6) {
+ _scene->_kernelMessages.reset();
+ _scene->_kernelMessages.add(Common::Point(0, 0), 0x1110, 34, 0, 120, _game.getQuote(0x304));
+ _scene->_sequences.addTimer(120, 4);
+ } else
+ restoreAnimations();
+ break;
+
+ case 4:
+ restoreAnimations();
+ break;
+
+ default:
+ break;
+ }
+}
+
+void Scene608::enter() {
+ _globals._spriteIndexes[2] = _scene->_sprites.addSprites("*RXMRD_7");
+ _globals._spriteIndexes[3] = _scene->_sprites.addSprites("*RXMRC_9");
+ _globals._spriteIndexes[6] = _scene->_sprites.addSprites(formAnimName('c', 2));
+ _globals._spriteIndexes[7] = _scene->_sprites.addSprites(formAnimName('c', 0));
+ _globals._spriteIndexes[8] = _scene->_sprites.addSprites(formAnimName('c', 1));
+
+ if (_game._objects.isInRoom(OBJ_POLYCEMENT)) {
+ _globals._spriteIndexes[1] = _scene->_sprites.addSprites(formAnimName('g', -1));
+ _globals._sequenceIndexes[1] = _scene->_sequences.startCycle(_globals._spriteIndexes[1], false, 1);
+ int idx = _scene->_dynamicHotspots.add(NOUN_POLYCEMENT, VERB_WALKTO, _globals._sequenceIndexes[1], Common::Rect(0, 0, 0, 0));
+ _polycementHotspotId = _scene->_dynamicHotspots.setPosition(idx, Common::Point(249, 129), FACING_NORTHEAST);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 6);
+ }
+
+ if (_game._objects.isInRoom(OBJ_REARVIEW_MIRROR)) {
+ _globals._spriteIndexes[12] = _scene->_sprites.addSprites(formAnimName('m', -1));
+ _globals._sequenceIndexes[12] = _scene->_sequences.startCycle(_globals._spriteIndexes[12], false, 1);
+ int idx = _scene->_dynamicHotspots.add(NOUN_REARVIEW_MIRROR, VERB_WALKTO, _globals._sequenceIndexes[12], Common::Rect(0, 0, 0, 0));
+ _scene->_dynamicHotspots.setPosition(idx, Common::Point(71, 113), FACING_NORTHEAST);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[12], 15);
+ }
+
+ if (_game._difficulty == DIFFICULTY_HARD) {
+ _globals._spriteIndexes[9] = _scene->_sprites.addSprites(formAnimName('g', 0));
+ _globals._spriteIndexes[4] = _scene->_sprites.addSprites(formAnimName('g', 1));
+ _globals._spriteIndexes[5] = _scene->_sprites.addSprites(formAnimName('g', 2));
+ _globals._spriteIndexes[10] = _scene->_sprites.addSprites(formAnimName('h', 2));
+ _globals._spriteIndexes[11] = _scene->_sprites.addSprites(formAnimName('h', 3));
+ _rexBeingEaten = false;
+
+ if (!_game._visitedScenes._sceneRevisited) {
+ _globals[kDogStatus] = 3;
+ _dogActiveFl = true;
+ } else
+ _dogActiveFl = (_globals[kDogStatus] != 4);
+ } else {
+ _globals[kDogStatus] = 4;
+ _dogActiveFl = false;
+ }
+
+ _dogSquashFl = false;
+ _buttonPressedonTimeFl = false;
+ _dogWindowTimer = 0;
+ _dogRunTimer = 0;
+ _dogHitWindow = false;
+ _checkFl = false;
+ _dogUnderCar = false;
+ _dogYelping = false;
+
+
+ if (!_game._visitedScenes._sceneRevisited)
+ _globals[kCarStatus] = 0;
+
+ _animationMode = 0;
+ _carMoveMode = 0;
+ _carFrame = -1;
+
+ if (_globals[kCarStatus] == 0) {
+ _carMode = 0;
+ _dogDeathMode = 0;
+ _resetPositionsFl = false;
+ int idx = _scene->_dynamicHotspots.add(NOUN_CAR, VERB_WALKTO, -1, Common::Rect(99, 69, 99 + 82, 69 + 25));
+ _carHotspotId = _scene->_dynamicHotspots.setPosition(idx, Common::Point(96, 132), FACING_NORTHEAST);
+ _scene->loadAnimation(formAnimName('A', -1));
+ } else if (_globals[kCarStatus] == 3) {
+ _carMode = 0;
+ _dogDeathMode = 0;
+ _resetPositionsFl = false;
+ int idx = _scene->_dynamicHotspots.add(NOUN_CAR, VERB_WALKTO, -1, Common::Rect(100, 100, 100 + 82, 100 + 25));
+ _carHotspotId = _scene->_dynamicHotspots.setPosition(idx, Common::Point(96, 132), FACING_NORTHEAST);
+ _scene->loadAnimation(formAnimName('A', -1));
+ _scene->_activeAnimation->setCurrentFrame(6);
+ } else if (_globals[kCarStatus] == 1) {
+ _carMode = 2;
+ _dogDeathMode = 0;
+ _resetPositionsFl = false;
+ int idx = _scene->_dynamicHotspots.add(NOUN_CAR, VERB_WALKTO, -1, Common::Rect(99, 69, 99 + 82, 69 + 25));
+ _carHotspotId = _scene->_dynamicHotspots.setPosition(idx, Common::Point(96, 132), FACING_NORTHEAST);
+ _scene->loadAnimation(formAnimName('C', -1));
+ } else if (_globals[kCarStatus] == 2) {
+ _carMode = 1;
+ _dogDeathMode = 2;
+ _resetPositionsFl = true;
+ int idx = _scene->_dynamicHotspots.add(NOUN_CAR, VERB_WALKTO, -1, Common::Rect(99, 69, 99 + 82, 69 + 25));
+ _carHotspotId = _scene->_dynamicHotspots.setPosition(idx, Common::Point(96, 132), FACING_NORTHEAST);
+ _scene->loadAnimation(formAnimName('B', -1));
+ } else {
+ _carMode = 3;
+ _dogDeathMode = 2;
+ _resetPositionsFl = true;
+ int idx = _scene->_dynamicHotspots.add(NOUN_CAR, VERB_WALKTO, -1, Common::Rect(100, 100, 100 + 82, 100 + 25));
+ _carHotspotId = _scene->_dynamicHotspots.setPosition(idx, Common::Point(96, 132), FACING_NORTHEAST);
+ _scene->loadAnimation(formAnimName('D', -1));
+ }
+
+ _vm->_palette->setEntry(252, 63, 44, 30);
+ _vm->_palette->setEntry(253, 63, 20, 22);
+
+ if (_scene->_priorSceneId != -2) {
+ _game._player._playerPos = Common::Point(46, 132);
+ _game._player._facing = FACING_EAST;
+ if (_game._difficulty == DIFFICULTY_HARD) {
+ if (!_game._visitedScenes._sceneRevisited)
+ _dogFirstEncounter = true;
+ else if (_dogActiveFl)
+ resetDogVariables();
+ }
+ } else if ((_game._difficulty == DIFFICULTY_HARD) && !_dogFirstEncounter && _dogActiveFl) {
+ if (!_dogUnderCar)
+ resetDogVariables();
+ else {
+ _globals._sequenceIndexes[10] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[10], false, 9, 0, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[10], 10, 11);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[10], 6);
+ }
+ }
+
+ sceneEntrySound();
+
+ if (_scene->_roomChanged)
+ _game._objects.addToInventory(OBJ_BONES);
+
+ _game.loadQuoteSet(0x2FB, 0x2FC, 0x2FE, 0x2FD, 0x2FF, 0x300, 0x301, 0x302, 0x303, 0x304, 0);
+}
+
+void Scene608::step() {
+ if (_dogFirstEncounter) {
+ long diff = _scene->_frameStartTime - _dogTimer1;
+ if ((diff >= 0) && (diff <= 1))
+ _dogWindowTimer += diff;
+ else
+ _dogWindowTimer++;
+
+ _dogTimer1 = _scene->_frameStartTime;
+ }
+
+ if (_dogActiveFl && (_dogWindowTimer >= 2) && !_dogHitWindow) {
+ _dogHitWindow = true;
+ _globals._sequenceIndexes[4] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[4], false, 11, 1, 0, 0);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[4], 1);
+ _vm->_sound->command(14);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[4], SEQUENCE_TRIGGER_EXPIRE, 0, 70);
+ _dogWindowTimer = 0;
+ }
+
+ if (_game._trigger == 70)
+ resetDogVariables();
+
+ if ((_game._difficulty == DIFFICULTY_HARD) && !_animationMode && _dogActiveFl && !_dogFirstEncounter && !_dogUnderCar) {
+ if (!_dogBarkingFl) {
+ if (_vm->getRandomNumber(1, 50) == 10) {
+ _dogBarkingFl = true;
+ _scene->_sequences.remove(_globals._sequenceIndexes[5]);
+ _globals._sequenceIndexes[5] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[5], false, 5, 8, 0, 0);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[5], 4);
+ int idx = _scene->_dynamicHotspots.add(NOUN_OBNOXIOUS_DOG, VERB_WALKTO, _globals._sequenceIndexes[5], Common::Rect(0, 0, 0, 0));
+ _scene->_dynamicHotspots.setPosition(idx, Common::Point(194, 142), FACING_EAST);
+ _barkCount = 0;
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[5], SEQUENCE_TRIGGER_SPRITE, 2, 100);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[5], SEQUENCE_TRIGGER_EXPIRE, 0, 60);
+ }
+ } else if (_game._trigger == 60) {
+ int syncIdx = _globals._sequenceIndexes[5];
+ _globals._sequenceIndexes[5] = _scene->_sequences.startCycle(_globals._spriteIndexes[5], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[5], 6);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[5], syncIdx);
+ _scene->_kernelMessages.reset();
+ _dogBarkingFl = false;
+ }
+ }
+
+ if ((_game._trigger == 100) && _dogBarkingFl) {
+ _vm->_sound->command(12);
+ _barkCount++;
+
+ if ((_barkCount >= 1) && (_barkCount <= 4)) {
+ Common::Point _barkPos(0, 0);
+ switch (_barkCount) {
+ case 1:
+ _barkPos = Common::Point(197, 66);
+ break;
+
+ case 2:
+ _barkPos = Common::Point(230, 76);
+ break;
+
+ case 3:
+ _barkPos = Common::Point(197, 86);
+ break;
+
+ case 4:
+ _barkPos = Common::Point(230, 97);
+ break;
+
+ default:
+ break;
+ }
+ _scene->_kernelMessages.add(_barkPos, 0xFDFC, 0, 0, 120, _game.getQuote(0x2FB));
+ }
+ }
+
+ if (_dogSquashFl && !_dogFirstEncounter && _dogUnderCar && _dogActiveFl) {
+ long diff = _scene->_frameStartTime - _dogTimer2;
+ if ((diff >= 0) && (diff <= 4))
+ _dogRunTimer += diff;
+ else
+ _dogRunTimer++;
+
+ _dogTimer2 = _scene->_frameStartTime;
+ }
+
+ // CHECKME: _checkFl is always false?
+ if (_dogRunTimer >= 480 && !_checkFl && !_buttonPressedonTimeFl && !_dogFirstEncounter && _dogUnderCar && _dogActiveFl) {
+ _checkFl = true;
+ _dogSquashFl = false;
+ _dogSafeFl = true;
+ _checkFl = false;
+ _dogRunTimer = 0;
+ } else {
+ _dogSafeFl = false;
+ if (_game._player._moving && (_game._difficulty == DIFFICULTY_HARD) && _dogActiveFl && (_scene->_rails.getNext() > 0) && _dogUnderCar)
+ _dogSafeFl = true;
+ }
+
+ if (_dogActiveFl && _dogSafeFl && !_buttonPressedonTimeFl) {
+ _dogDeathMode = 0;
+ _globals[kCarStatus] = 0;
+ _carMode = 0;
+ _scene->_sequences.remove(_globals._sequenceIndexes[10]);
+ _dogUnderCar = false;
+ _dogYelping = false;
+ _scene->_kernelMessages.reset();
+ _globals._sequenceIndexes[11] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[11], false, 6, 1, 0, 0);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[11], SEQUENCE_TRIGGER_EXPIRE, 0, 92);
+ _scene->_kernelMessages.add(Common::Point(0, 0), 0x1110, 34, 0, 120, _game.getQuote(0x2FF));
+ }
+
+ if (_game._trigger == 92) {
+ resetDogVariables();
+ _animationMode = 0;
+ }
+
+ if ((_carMode == 4) && (_scene->_activeAnimation != nullptr)) {
+ if (_scene->_activeAnimation->getCurrentFrame() != _carFrame) {
+ _carFrame = _scene->_activeAnimation->getCurrentFrame();
+ int nextFrame = -1;
+
+ if (_carFrame == 10) {
+ _game._player._visible = true;
+ _game._player._priorTimer = _scene->_activeAnimation->getNextFrameTimer() - _game._player._ticksAmount;
+ }
+
+ if (_carFrame == 56) {
+ resetDogVariables();
+ _animationMode = 0;
+ _nextTrigger = 2;
+ }
+
+ if ((nextFrame >= 0) && (nextFrame != _scene->_activeAnimation->getCurrentFrame())) {
+ _scene->_activeAnimation->setCurrentFrame(nextFrame);
+ _carFrame = nextFrame;
+ }
+ }
+ }
+
+ if ((_carMode == 5) && (_scene->_activeAnimation != nullptr)) {
+ if (_scene->_activeAnimation->getCurrentFrame() != _carFrame) {
+ _carFrame = _scene->_activeAnimation->getCurrentFrame();
+ int nextFrame = -1;
+
+ if (_carFrame == 10) {
+ _game._player._visible = true;
+ _game._player._priorTimer = _scene->_activeAnimation->getNextFrameTimer() - _game._player._ticksAmount;
+ }
+
+ if (_carFrame == 52) {
+ resetDogVariables();
+ _animationMode = 0;
+ _nextTrigger = 2;
+ }
+
+ if ((nextFrame >= 0) && (nextFrame != _scene->_activeAnimation->getCurrentFrame())) {
+ _scene->_activeAnimation->setCurrentFrame(nextFrame);
+ _carFrame = nextFrame;
+ }
+ }
+ }
+
+
+ if ((_carMode == 6) && (_scene->_activeAnimation != nullptr)) {
+ if (_scene->_activeAnimation->getCurrentFrame() != _carFrame) {
+ _carFrame = _scene->_activeAnimation->getCurrentFrame();
+ int nextFrame = -1;
+
+ if (_carFrame == 11) {
+ _game._player._visible = true;
+ _game._player._priorTimer = _scene->_activeAnimation->getNextFrameTimer() - _game._player._ticksAmount;
+ }
+
+ if (_carFrame == 41) {
+ _globals._sequenceIndexes[10] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[10], false, 9, 0, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[10], 10, 11);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[10], 6);
+ _dogUnderCar = true;
+ _nextTrigger = 2;
+ }
+
+
+ if ((nextFrame >= 0) && (nextFrame != _scene->_activeAnimation->getCurrentFrame())) {
+ _scene->_activeAnimation->setCurrentFrame(nextFrame);
+ _carFrame = nextFrame;
+ }
+ }
+ }
+
+ if (_dogUnderCar) {
+ if (!_dogYelping) {
+ if (_vm->getRandomNumber(1, 50) == 10) {
+ _dogYelping = true;
+ _barkCount = 0;
+ _scene->_sequences.addTimer(12, 110);
+ _scene->_sequences.addTimer(22, 111);
+ _scene->_sequences.addTimer(120, 112);
+ }
+ _scene->_kernelMessages.reset();
+ }
+ } else
+ _dogYelping = false;
+
+ if (_game._trigger == 110) {
+ _vm->_sound->command(12);
+ _scene->_kernelMessages.add(Common::Point(150, 97), 0xFDFC, 0, 0, 60, _game.getQuote(0x303));
+ }
+
+ if (_game._trigger == 111) {
+ _vm->_sound->command(12);
+ _scene->_kernelMessages.add(Common::Point(183, 93), 0xFDFC, 0, 0, 60, _game.getQuote(0x303));
+ }
+
+ if (_game._trigger == 112)
+ _dogYelping = false;
+
+ if ((_carMode == 0) && (_scene->_activeAnimation != nullptr)) {
+ if (_scene->_activeAnimation->getCurrentFrame() != _carFrame) {
+ _carFrame = _scene->_activeAnimation->getCurrentFrame();
+ int nextFrame = -1;
+
+ if ((_globals[kCarStatus] == 0) || (_globals[kCarStatus] == 3)) {
+ switch (_carMoveMode) {
+ case 0:
+ if (_globals[kCarStatus] == 0)
+ nextFrame = 0;
+ else
+ nextFrame = 6;
+ break;
+
+ case 1:
+ if (_scene->_activeAnimation->getCurrentFrame() >= 12) {
+ nextFrame = 0;
+ _carMoveMode = 0;
+ _globals[kCarStatus] = 0;
+ }
+ break;
+
+ case 2:
+ if (_scene->_activeAnimation->getCurrentFrame() >= 6) {
+ nextFrame = 6;
+ _carMoveMode = 0;
+ _globals[kCarStatus] = 3;
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ if ((nextFrame >= 0) && (nextFrame != _scene->_activeAnimation->getCurrentFrame())) {
+ _scene->_activeAnimation->setCurrentFrame(nextFrame);
+ _carFrame = nextFrame;
+ }
+ }
+ }
+
+ if ((_carMode == 2) && (_scene->_activeAnimation != nullptr)) {
+ if (_scene->_activeAnimation->getCurrentFrame() != _carFrame) {
+ _carFrame = _scene->_activeAnimation->getCurrentFrame();
+ int nextFrame = -1;
+
+ if (_carMoveMode == 0)
+ nextFrame = 28;
+ else if (_scene->_activeAnimation->getCurrentFrame() >= 28) {
+ nextFrame = 28;
+ _carMoveMode = 0;
+ }
+
+ if ((nextFrame >= 0) && (nextFrame != _scene->_activeAnimation->getCurrentFrame())) {
+ _scene->_activeAnimation->setCurrentFrame(nextFrame);
+ _carFrame = nextFrame;
+ }
+ }
+ }
+
+ if ((_carMode == 3) && (_scene->_activeAnimation != nullptr)) {
+ if (_scene->_activeAnimation->getCurrentFrame() != _carFrame) {
+ _carFrame = _scene->_activeAnimation->getCurrentFrame();
+ int nextFrame = -1;
+
+ if (_resetPositionsFl) {
+ nextFrame = 0;
+ _carMoveMode = 0;
+ } else if (_carMoveMode == 0)
+ nextFrame = 6;
+ else if (_scene->_activeAnimation->getCurrentFrame() >= 6) {
+ nextFrame = 6;
+ _carMoveMode = 0;
+ }
+
+ if ((nextFrame >= 0) && (nextFrame != _scene->_activeAnimation->getCurrentFrame())) {
+ _scene->_activeAnimation->setCurrentFrame(nextFrame);
+ _carFrame = nextFrame;
+ }
+ }
+ }
+
+
+ if ((_carMode == 1) && (_scene->_activeAnimation != nullptr)) {
+ if (_scene->_activeAnimation->getCurrentFrame() != _carFrame) {
+ _carFrame = _scene->_activeAnimation->getCurrentFrame();
+ int nextFrame = -1;
+
+ if (_resetPositionsFl) {
+ nextFrame = 0;
+ _carMoveMode = 0;
+ } else if (_carMoveMode == 0)
+ nextFrame = 6;
+ else if (_scene->_activeAnimation->getCurrentFrame() >= 6) {
+ nextFrame = 6;
+ _carMoveMode = 0;
+ }
+
+ if ((nextFrame >= 0) && (nextFrame != _scene->_activeAnimation->getCurrentFrame())) {
+ _scene->_activeAnimation->setCurrentFrame(nextFrame);
+ _carFrame = nextFrame;
+ }
+ }
+ }
+
+ if (_game._player._moving && (_game._difficulty == DIFFICULTY_HARD) && _dogActiveFl && (_scene->_rails.getNext() > 0)) {
+ _game._player.cancelCommand();
+ _game._player.startWalking(Common::Point(194, 142), FACING_EAST);
+ _scene->_rails.resetNext();
+ if (_dogUnderCar)
+ _dogSafeFl = true;
+ }
+
+ if (_game._player._special > 0 && (_game._difficulty == DIFFICULTY_HARD) && _dogActiveFl && _game._player._stepEnabled)
+ _game._player._stepEnabled = false;
+
+ if ((_game._difficulty == DIFFICULTY_HARD) && _dogActiveFl && (_game._player._playerPos == Common::Point(194, 142))
+ && (_game._trigger || !_rexBeingEaten)) {
+ _rexBeingEaten = true;
+ switch (_game._trigger) {
+ case 0:
+ _scene->_sequences.remove(_globals._sequenceIndexes[5]);
+ _animationMode = 1;
+ _globals._sequenceIndexes[9] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[9], false, 10, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[9], 1, 2);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[9], 5);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[9], SEQUENCE_TRIGGER_EXPIRE, 0, 80);
+ _scene->_sequences.addTimer(10, 85);
+ break;
+
+ case 80:
+ _game._player._visible = false;
+ _globals._sequenceIndexes[9] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[9], false, 10, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[9], 3, 5);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[9], 5);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[9], -1);
+ _scene->_kernelMessages.reset();
+ _scene->_kernelMessages.add(Common::Point(0, 0), 0x1110, 34, 0, 120, _game.getQuote(0x2FC));
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[9], SEQUENCE_TRIGGER_EXPIRE, 0, 81);
+ break;
+
+ case 81: {
+ int syncIdx = _globals._sequenceIndexes[9];
+ _globals._sequenceIndexes[9] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[9], false, 5, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[9], 6, 38);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[9], 5);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[9], syncIdx);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[9], SEQUENCE_TRIGGER_EXPIRE, 0, 82);
+ }
+ break;
+
+ case 82: {
+ int syncIdx = _globals._sequenceIndexes[9];
+ _globals._sequenceIndexes[9] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[9], false, 15, 5, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[9], 39, 40);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[9], 5);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[9], syncIdx);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[9], SEQUENCE_TRIGGER_EXPIRE, 0, 83);
+ }
+ break;
+
+ case 83: {
+ _animationMode = 2;
+ int syncIdx = _globals._sequenceIndexes[9];
+ _globals._sequenceIndexes[9] = _scene->_sequences.startCycle(_globals._spriteIndexes[9], false, -2);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[9], 5);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[9], syncIdx);
+ _scene->_sequences.addTimer(60, 84);
+ }
+ break;
+
+ case 84:
+ _rexBeingEaten = false;
+ _animationMode = 0;
+ _scene->_reloadSceneFlag = true;
+ _game._player._stepEnabled = true;
+ break;
+
+ case 85:
+ if (_rexBeingEaten && (_animationMode == 1)) {
+ _vm->_sound->command(12);
+ _scene->_sequences.addTimer(10, 85);
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+}
+
+void Scene608::preActions() {
+ _game._triggerSetupMode = SEQUENCE_TRIGGER_DAEMON;
+
+ if ((_action.isAction(VERB_THROW, NOUN_BONE, 0x410) || _action.isAction(VERB_THROW, NOUN_BONES, 0x410)
+ || _action.isAction(VERB_THROW, NOUN_BONE, 0x411) || _action.isAction(VERB_THROW, NOUN_BONES, 0x411)
+ || _action.isAction(VERB_THROW, NOUN_BONES, 0x471) || _action.isAction(VERB_THROW, NOUN_BONE, 0x471)) && _dogActiveFl) {
+ _game._player._stepEnabled = false;
+ _game._player.walk(Common::Point(56, 146), FACING_EAST);
+ }
+
+ if ((_action.isAction(VERB_THROW, NOUN_BONES, 0x41D) || _action.isAction(VERB_THROW, NOUN_BONE, 0x41D)
+ || _action.isAction(VERB_THROW, NOUN_BONES, 0x41E) || _action.isAction(VERB_THROW, NOUN_BONE, 0x41E)) && _dogActiveFl) {
+ _game._player._stepEnabled = false;
+ _game._player.walk(Common::Point(75, 136), FACING_EAST);
+ }
+
+ if (_action.isAction(VERB_PUSH, NOUN_DOWN_BUTTON) && _dogUnderCar) {
+ _buttonPressedonTimeFl = true;
+ _dogDeathMode = 1;
+ } else
+ _buttonPressedonTimeFl = false;
+}
+
+void Scene608::actions() {
+ if (_action.isAction(VERB_WALK_THROUGH, NOUN_DOORWAY))
+ _scene->_nextSceneId = 607;
+ else if (_action.isAction(VERB_PUSH, NOUN_DOWN_BUTTON)) {
+ _game._player._stepEnabled = true;
+ switch (_game._trigger) {
+ case 0:
+ if ((_globals[kCarStatus] == 0) || (_globals[kCarStatus] == 1) || (_globals[kCarStatus] == 2)) {
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._sequenceIndexes[3] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[3], true, 6, 2, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[3], 1, 2);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[3]);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[3], SEQUENCE_TRIGGER_EXPIRE, 0, 1);
+ } else
+ _vm->_dialogs->show(60839);
+ break;
+
+ case 1:
+ _scene->_sequences.updateTimeout(-1, _globals._sequenceIndexes[3]);
+ _game._player._visible = true;
+ if (_dogDeathMode == 0)
+ _carMode = 0;
+ else if (_dogDeathMode == 1) {
+ _scene->_kernelMessages.reset();
+ _scene->_kernelMessages.add(Common::Point(0, 0), 0x1110, 34, 0, 120, _game.getQuote(0x300));
+ _globals[kCarStatus] = 1;
+ _carMode = 2;
+ _globals[kDogStatus] = 4;
+ _dogActiveFl = false;
+ _dogUnderCar = false;
+ _scene->_sequences.remove(_globals._sequenceIndexes[10]);
+ _scene->freeAnimation();
+ _scene->loadAnimation(formAnimName('C', -1));
+ } else {
+ _resetPositionsFl = false;
+ _carMode = 1;
+ _scene->freeAnimation();
+ _scene->loadAnimation(formAnimName('B', -1));
+ }
+
+ _carMoveMode = 2;
+ _scene->_sequences.addTimer(1, 2);
+ break;
+
+ case 2:
+ if (_carMoveMode != 0)
+ _scene->_sequences.addTimer(1, 2);
+ else {
+ _scene->_dynamicHotspots.remove(_carHotspotId);
+ int idx = _scene->_dynamicHotspots.add(NOUN_CAR, VERB_WALKTO, -1, Common::Rect(100, 100, 100 + 82, 100 + 25));
+ _carHotspotId = _scene->_dynamicHotspots.setPosition(idx, Common::Point(96, 132), FACING_NORTHEAST);
+ if (_globals[kCarStatus] == 1)
+ _scene->_sequences.addTimer(120, 3);
+ else {
+ if (_dogDeathMode == 0)
+ _globals[kCarStatus] = 3;
+ else {
+ _globals[kCarStatus] = 4;
+ _carMode = 3;
+ _dogDeathMode = 2;
+ }
+ _game._player._stepEnabled = true;
+ }
+ }
+ break;
+
+ case 3:
+ _scene->_kernelMessages.add(Common::Point(0, 0), 0x1110, 34, 0, 120, _game.getQuote(0x302));
+ _globals[kCarStatus] = 4;
+ _carMode = 3;
+ _dogDeathMode = 2;
+ _game._player._stepEnabled = true;
+ break;
+
+ default:
+ break;
+ }
+ } else if (_action.isAction(VERB_PUSH, NOUN_UP_BUTTON)) {
+ switch (_game._trigger) {
+ case 0:
+ if ((_globals[kCarStatus] == 3) || (_globals[kCarStatus] == 4)) {
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._sequenceIndexes[3] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[3], true, 6, 2, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[3], 1, 3);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[3]);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[3], SEQUENCE_TRIGGER_EXPIRE, 0, 1);
+ } else
+ _vm->_dialogs->show(60840);
+ break;
+
+ case 1:
+ _scene->_sequences.updateTimeout(-1, _globals._sequenceIndexes[3]);
+ _game._player._visible = true;
+ if (_dogDeathMode == 0)
+ _carMode = 0;
+ else {
+ _carMode = 3;
+ _resetPositionsFl = false;
+ _scene->freeAnimation();
+ _scene->loadAnimation(formAnimName('D', -1));
+ }
+ _carMoveMode = 1;
+ _scene->_sequences.addTimer(1, 2);
+ break;
+
+ case 2: {
+ if (_carMoveMode != 0)
+ _scene->_sequences.addTimer(1, 2);
+ else if (_dogDeathMode == 0)
+ _globals[kCarStatus] = 0;
+ else if (_dogDeathMode == 2) {
+ _globals[kCarStatus] = 2;
+ _carMode = 3;
+ _dogDeathMode = 2;
+ }
+ _scene->_dynamicHotspots.remove(_carHotspotId);
+ int idx = _scene->_dynamicHotspots.add(NOUN_CAR, VERB_WALKTO, -1, Common::Rect(99, 69, 99 + 82, 69 + 25));
+ _carHotspotId = _scene->_dynamicHotspots.setPosition(idx, Common::Point(96, 132), FACING_NORTHEAST);
+ _game._player._stepEnabled = true;
+ }
+ break;
+
+ default:
+ break;
+ }
+ } else if (_action.isAction(VERB_THROW, NOUN_BONE, 0x410) || _action.isAction(VERB_THROW, NOUN_BONES, 0x410)
+ || _action.isAction(VERB_THROW, NOUN_BONES, 0x471) || _action.isAction(VERB_THROW, NOUN_BONE, 0x471)) {
+ _game._player._stepEnabled = true;
+ if (_dogActiveFl) {
+ if (_game._trigger == 0) {
+ _scene->_kernelMessages.reset();
+ _scene->_kernelMessages.add(Common::Point(0, 0), 0x1110, 34, 0, 120, _game.getQuote(0x2FE));
+ }
+ _throwMode = 4;
+ handleThrowingBone();
+ } else
+ _vm->_dialogs->show(60841);
+ } else if (_action.isAction(VERB_THROW, NOUN_BONE, 0x411) || _action.isAction(VERB_THROW, NOUN_BONES, 0x411)) {
+ _game._player._stepEnabled = true;
+ if (_dogActiveFl) {
+ if (_game._trigger == 0) {
+ _scene->_kernelMessages.reset();
+ _scene->_kernelMessages.add(Common::Point(0, 0), 0x1110, 34, 0, 120, _game.getQuote(0x2FD));
+ }
+ _throwMode = 5;
+ handleThrowingBone();
+ } else
+ _vm->_dialogs->show(60841);
+ } else if (_action.isAction(VERB_THROW, NOUN_BONES, 0x41D) || _action.isAction(VERB_THROW, NOUN_BONE, 0x41D)
+ || _action.isAction(VERB_THROW, NOUN_BONES, 0x41E) || _action.isAction(VERB_THROW, NOUN_BONE, 0x41E)) {
+ _game._player._stepEnabled = true;
+ if ((_globals[kCarStatus] == 0) && _dogActiveFl) {
+ if (_dogActiveFl) {
+ if (_game._trigger == 0) {
+ _scene->_kernelMessages.reset();
+ _scene->_kernelMessages.add(Common::Point(0, 0), 0x1110, 34, 0, 120, _game.getQuote(0x301));
+ }
+ _throwMode = 6;
+ handleThrowingBone();
+ } else
+ _vm->_dialogs->show(60841);
+ } else
+ _vm->_dialogs->show(60842);
+ } else if (_action.isAction(VERB_TAKE, NOUN_POLYCEMENT) && (_game._trigger || !_game._objects.isInInventory(OBJ_POLYCEMENT))) {
+ switch (_game._trigger) {
+ case 0:
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._sequenceIndexes[2] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[2], true, 6, 2, 0, 0);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[2]);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[2], SEQUENCE_TRIGGER_SPRITE, 4, 1);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[2], SEQUENCE_TRIGGER_EXPIRE, 0, 2);
+ break;
+
+ case 1:
+ _vm->_sound->command(9);
+ _scene->_sequences.remove(_globals._sequenceIndexes[1]);
+ _scene->_dynamicHotspots.remove(_polycementHotspotId);
+ break;
+
+ case 2:
+ _game._objects.addToInventory(OBJ_POLYCEMENT);
+ _scene->_sequences.updateTimeout(-1, _globals._sequenceIndexes[2]);
+ _game._player._visible = true;
+ _game._player._stepEnabled = true;
+ _vm->_dialogs->showItem(OBJ_POLYCEMENT, 60833);
+ break;
+
+ default:
+ break;
+ }
+ } else if (_action.isAction(VERB_TAKE, NOUN_REARVIEW_MIRROR) && (_game._trigger || !_game._objects.isInInventory(OBJ_REARVIEW_MIRROR))) {
+ switch (_game._trigger) {
+ case 0:
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._sequenceIndexes[2] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[2], true, 6, 2, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[2], 1, 2);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[2]);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[2], SEQUENCE_TRIGGER_SPRITE, 2, 1);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[2], SEQUENCE_TRIGGER_EXPIRE, 0, 2);
+ break;
+
+ case 1:
+ _vm->_sound->command(9);
+ _scene->_sequences.remove(_globals._sequenceIndexes[12]);
+ _game._objects.addToInventory(OBJ_REARVIEW_MIRROR);
+ _vm->_dialogs->showItem(OBJ_REARVIEW_MIRROR, 60827);
+ break;
+
+ case 2:
+ _scene->_sequences.updateTimeout(-1, _globals._sequenceIndexes[2]);
+ _game._player._visible = true;
+ _game._player._stepEnabled = true;
+ break;
+
+ default:
+ break;
+ }
+ } else if (_action._lookFlag) {
+ if (_game._difficulty != DIFFICULTY_HARD)
+ _vm->_dialogs->show(60810);
+ else if (_globals[kDogStatus] == 4)
+ _vm->_dialogs->show(60812);
+ else
+ _vm->_dialogs->show(60811);
+ } else if (_action.isAction(VERB_LOOK) && (_action.isAction(0x412) || _action.isAction(0x408) || _action.isAction(0x414)
+ || _action.isAction(0x40D) || _action.isAction(0x41C)))
+ _vm->_dialogs->show(60813);
+ else if (_action.isAction(VERB_TAKE) && (_action.isAction(0x412) || _action.isAction(0x408) || _action.isAction(0x414)
+ || _action.isAction(0x40D) || _action.isAction(0x41C)))
+ _vm->_dialogs->show(60814);
+ else if (_action.isAction(VERB_LOOK, NOUN_GARAGE_FLOOR) || _action.isAction(VERB_LOOK, NOUN_FRONT_OF_GARAGE) || _action.isAction(VERB_LOOK, NOUN_REAR_OF_GARAGE)) {
+ if (_dogActiveFl)
+ _vm->_dialogs->show(60815);
+ else
+ _vm->_dialogs->show(60816);
+ } else if (_action.isAction(VERB_LOOK, NOUN_SPARE_RIBS))
+ _vm->_dialogs->show(60817);
+ else if (_action.isAction(VERB_TAKE, NOUN_SPARE_RIBS)) {
+ if (_game._difficulty == DIFFICULTY_HARD)
+ _vm->_dialogs->show(60818);
+ else
+ _vm->_dialogs->show(60819);
+ } else if (_action.isAction(VERB_LOOK, NOUN_UP_BUTTON))
+ _vm->_dialogs->show(60820);
+ else if (_action.isAction(VERB_LOOK, NOUN_DOWN_BUTTON))
+ _vm->_dialogs->show(60821);
+ else if (_action.isAction(VERB_LOOK, NOUN_TRASH_CAN))
+ _vm->_dialogs->show(60822);
+ else if (_action.isAction(VERB_LOOK, NOUN_CALENDAR))
+ _vm->_dialogs->show(60823);
+ else if (_action.isAction(VERB_LOOK, NOUN_STORAGE_BOX)) {
+ if (_game._objects[OBJ_REARVIEW_MIRROR]._roomNumber == _scene->_currentSceneId)
+ _vm->_dialogs->show(60825);
+ else
+ _vm->_dialogs->show(60824);
+ } else if (_action.isAction(VERB_OPEN, NOUN_STORAGE_BOX))
+ _vm->_dialogs->show(60826);
+ else if (_action.isAction(VERB_LOOK, NOUN_REARVIEW_MIRROR) && (_action._mainObjectSource == 4))
+ _vm->_dialogs->show(60828);
+ else if (_action.isAction(VERB_LOOK, NOUN_TOOL_BOX)) {
+ if (_game._objects[OBJ_POLYCEMENT]._roomNumber == _scene->_currentSceneId)
+ _vm->_dialogs->show(60829);
+ else
+ _vm->_dialogs->show(60830);
+ } else if (_action.isAction(VERB_OPEN, NOUN_TOOL_BOX))
+ _vm->_dialogs->show(60831);
+ else if ((_action.isAction(VERB_LOOK, NOUN_POLYCEMENT)) && (_game._objects.isInRoom(OBJ_POLYCEMENT)))
+ _vm->_dialogs->show(60832);
+ else if (_action.isAction(VERB_LOOK, NOUN_GREASE_CAN) || _action.isAction(VERB_LOOK, NOUN_OIL_CAN))
+ _vm->_dialogs->show(60834);
+ else if (_action.isAction(VERB_LOOK, NOUN_CAR_LIFT))
+ _vm->_dialogs->show(60835);
+ else if (_action.isAction(VERB_LOOK, NOUN_CHAIR) || _action.isAction(VERB_LOOK, NOUN_HAT))
+ _vm->_dialogs->show(60836);
+ else if (_action.isAction(VERB_LOOK, NOUN_DANGER_ZONE))
+ _vm->_dialogs->show(60838);
+ else
+ return;
+
+ _action._inProgress = false;
+}
+
+/*------------------------------------------------------------------------*/
+
+Scene609::Scene609(MADSEngine *vm) : Scene6xx(vm) {
+ _videoDoorMode = -1;
+}
+
+void Scene609::synchronize(Common::Serializer &s) {
+ Scene6xx::synchronize(s);
+
+ s.syncAsSint16LE(_videoDoorMode);
+}
+
+void Scene609::setup() {
+ setPlayerSpritesPrefix();
+ setAAName();
+}
+
+void Scene609::enter() {
+ _globals._spriteIndexes[1] = _scene->_sprites.addSprites(formAnimName('c', 0));
+ _globals._spriteIndexes[2] = _scene->_sprites.addSprites(formAnimName('x', 0));
+ _globals._spriteIndexes[3] = _scene->_sprites.addSprites(formAnimName('h', 0));
+ _globals._spriteIndexes[4] = _scene->_sprites.addSprites("*RXCD_9");
+ _globals._spriteIndexes[5] = _scene->_sprites.addSprites("*RXMRC_9");
+
+ _globals._sequenceIndexes[1] = _scene->_sequences.startCycle(_globals._spriteIndexes[1], false, -2);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 5);
+ _globals._sequenceIndexes[2] = _scene->_sequences.startCycle(_globals._spriteIndexes[2], false, -1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 9);
+
+ if (!_game._visitedScenes._sceneRevisited)
+ _globals[kBeenInVideoStore] = false;
+
+ if (_scene->_priorSceneId == 611) {
+ _game._player._playerPos = Common::Point(264, 69);
+ _game._player._facing = FACING_SOUTHWEST;
+ } else if (_scene->_priorSceneId == 610) {
+ _game._player._playerPos = Common::Point(23, 90);
+ _game._player._facing = FACING_EAST;
+ _scene->_sequences.addTimer(60, 60);
+ _game._player._stepEnabled = false;
+ } else if (_scene->_priorSceneId != -2) {
+ _game._player._playerPos = Common::Point(86, 136);
+ _game._player._facing = FACING_NORTHEAST;
+ _game._player._visible = false;
+ _game._player._stepEnabled = false;
+ _scene->_sequences.remove(_globals._sequenceIndexes[1]);
+ _globals._sequenceIndexes[1] = _scene->_sequences.startCycle(_globals._spriteIndexes[1], false, -1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 5);
+ _scene->loadAnimation(formAnimName('R', 1), 70);
+ }
+
+ if (_scene->_roomChanged) {
+ _game._objects.addToInventory(OBJ_DOOR_KEY);
+ if (_game._difficulty != DIFFICULTY_EASY)
+ _game._objects.addToInventory(OBJ_PENLIGHT);
+ }
+
+ sceneEntrySound();
+ _game.loadQuoteSet(0x305, 0x306, 0x307, 0x308, 0x309, 0);
+}
+
+void Scene609::step() {
+ switch (_game._trigger) {
+ case 60:
+ _game._player._stepEnabled = false;
+ _scene->_sequences.remove(_globals._sequenceIndexes[2]);
+ _globals._sequenceIndexes[2] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[2], false, 7, 1, 0, 0);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 9);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[2], SEQUENCE_TRIGGER_EXPIRE, 0, 61);
+ break;
+
+ case 61:
+ _scene->_hotspots.activate(NOUN_VIDEO_STORE_DOOR, false);
+ _game._player.walk(Common::Point(101, 100), FACING_EAST);
+ _scene->_sequences.addTimer(180, 62);
+ break;
+
+ case 62:
+ _scene->_sequences.remove( _globals._sequenceIndexes[2]);
+ _globals._sequenceIndexes[2] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[2], false, 7, 1, 0, 0);
+ _scene->_hotspots.activate(NOUN_VIDEO_STORE_DOOR, true);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 9);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[2], SEQUENCE_TRIGGER_EXPIRE, 0, 63);
+ break;
+
+ case 63:
+ if (!_globals[kHasTalkedToHermit] && (_game._difficulty != DIFFICULTY_HARD)) {
+ _globals._sequenceIndexes[3] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[3], false, 26, 2, 0, 0);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 7);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[3], Common::Point(287, 73));
+ _scene->_sequences.setScale(_globals._sequenceIndexes[3], 47);
+ }
+ _globals._sequenceIndexes[2] = _scene->_sequences.startCycle(_globals._spriteIndexes[2], false, -1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 9);
+ _game._player._stepEnabled = true;
+ break;
+
+ default:
+ break;
+ }
+
+ switch (_game._trigger) {
+ case 70:
+ _game._player._visible = true;
+ _game._player._priorTimer = _scene->_activeAnimation->getNextFrameTimer() - _game._player._ticksAmount;
+ _scene->_sequences.addTimer(6, 71);
+ break;
+
+ case 71:
+ if (!_globals[kHasTalkedToHermit]) {
+ _globals._sequenceIndexes[3] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[3], false, 26, 2, 0, 0);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 7);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[3], Common::Point(287, 73));
+ _scene->_sequences.setScale(_globals._sequenceIndexes[3], 47);
+ }
+ _scene->_sequences.remove(_globals._sequenceIndexes[1]);
+ _globals._sequenceIndexes[1] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[1], false, 6, 1, 0, 0);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 5);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[1], SEQUENCE_TRIGGER_EXPIRE, 0, 72);
+ break;
+
+ case 72:
+ _globals._sequenceIndexes[1] = _scene->_sequences.startCycle(_globals._spriteIndexes[1], false, -2);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 5);
+ _game._player._stepEnabled = true;
+ break;
+
+ default:
+ break;
+ }
+}
+
+void Scene609::enterStore() {
+ switch (_game._trigger) {
+ case 0:
+ _game._player._stepEnabled = false;
+ if (_videoDoorMode == 2)
+ _scene->_sequences.addTimer(1, 4);
+ else {
+ _scene->_kernelMessages.reset();
+ _scene->_kernelMessages.add(Common::Point(0, 0), 0x1110, 34, 0, 120, _game.getQuote(0x305));
+ _scene->_sequences.addTimer(120, 1);
+ }
+ break;
+
+ case 1:
+ _scene->_kernelMessages.reset();
+ _scene->_kernelMessages.add(Common::Point(0, 0), 0x1110, 34, 0, 120, _game.getQuote(0x306));
+ _scene->_sequences.addTimer(60, 2);
+ break;
+
+ case 2:
+ _game._player._visible = false;
+ _globals._sequenceIndexes[5] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[5], true, 11, 2, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[5], 1, 2);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[5]);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[5], SEQUENCE_TRIGGER_EXPIRE, 0, 3);
+ break;
+
+ case 3:
+ _scene->_sequences.updateTimeout(-1, _globals._sequenceIndexes[5]);
+ _game._player._visible = true;
+ _game._objects.setRoom(OBJ_DOOR_KEY, 1);
+ _scene->_sequences.addTimer(15, 4);
+ break;
+
+ case 4:
+ _game._player._visible = false;
+ _globals._sequenceIndexes[5] = _scene->_sequences.startCycle(_globals._spriteIndexes[5], true, 1);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[5]);
+ _scene->_sequences.addTimer(15, 5);
+ break;
+
+ case 5:
+ _scene->_sequences.remove(_globals._sequenceIndexes[5]);
+ _game._player._priorTimer = _scene->_frameStartTime - _game._player._ticksAmount;
+ _game._player._visible = true;
+ _scene->_sequences.remove(_globals._sequenceIndexes[2]);
+ _globals._sequenceIndexes[2] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[2], false, 7, 1, 0, 0);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 9);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[2], SEQUENCE_TRIGGER_EXPIRE, 0, 6);
+ break;
+
+ case 6:
+ _scene->_hotspots.activate(NOUN_VIDEO_STORE_DOOR, false);
+ if (_videoDoorMode == 1) {
+ _scene->_kernelMessages.reset();
+ _scene->_kernelMessages.add(Common::Point(0, 0), 0x1110, 34, 0, 180, _game.getQuote(0x307));
+ }
+ _game._player.walk(Common::Point(23, 90), FACING_WEST);
+ _scene->_sequences.addTimer(180, 7);
+ break;
+
+ case 7:
+ _scene->_sequences.remove(_globals._sequenceIndexes[2]);
+ _globals._sequenceIndexes[2] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[2], false, 7, 1, 0, 0);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 9);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[2], SEQUENCE_TRIGGER_EXPIRE, 0, 8);
+ break;
+
+ case 8:
+ _scene->_hotspots.activate(NOUN_VIDEO_STORE_DOOR, true);
+ _globals._sequenceIndexes[2] = _scene->_sequences.startCycle(_globals._spriteIndexes[2], false, -1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 9);
+ _globals[kBeenInVideoStore] = true;
+ _game._player._stepEnabled = true;
+ _scene->_nextSceneId = 610;
+ break;
+
+ default:
+ break;
+ }
+}
+
+void Scene609::preActions() {
+ if (_action.isAction(VERB_UNLOCK, 0x6F, 0x425))
+ _game._player.walk(Common::Point(78, 99), FACING_NORTHWEST);
+}
+
+void Scene609::actions() {
+ if (_action.isAction(VERB_WALK_TOWARDS, NOUN_ALLEY))
+ _scene->_nextSceneId = 611;
+ else if (_action.isAction(VERB_WALK_THROUGH, NOUN_VIDEO_STORE_DOOR)) {
+ if (!_globals[kBeenInVideoStore]) {
+ switch (_game._trigger) {
+ case 0:
+ _game._player._stepEnabled = false;
+ _scene->_kernelMessages.reset();
+ _scene->_kernelMessages.add(Common::Point(0, 0), 0x1110, 34, 0, 120, _game.getQuote(0x308));
+ _scene->_sequences.addTimer(120, 1);
+ break;
+
+ case 1:
+ _game._player._visible = false;
+ _globals._sequenceIndexes[5] = _scene->_sequences.startCycle(_globals._spriteIndexes[5], true, 1);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[5]);
+ _scene->_sequences.addTimer(30, 2);
+ break;
+
+ case 2:
+ _scene->_sequences.remove(_globals._sequenceIndexes[5]);
+ _game._player._priorTimer = _scene->_frameStartTime - _game._player._ticksAmount;
+ _game._player._visible = true;
+ _scene->_sequences.addTimer(60, 3);
+ break;
+
+ case 3:
+ _scene->_kernelMessages.reset();
+ _scene->_kernelMessages.add(Common::Point(0, 0), 0x1110, 34, 0, 120, _game.getQuote(0x309));
+ _scene->_sequences.addTimer(120, 4);
+ break;
+
+ case 4:
+ _game._player._stepEnabled = true;
+ break;
+
+ default:
+ break;
+ }
+ } else {
+ _videoDoorMode = 2;
+ enterStore();
+ }
+ } else if (_action.isAction(VERB_UNLOCK, 0x6F, 0x425)) {
+ _videoDoorMode = 1;
+ enterStore();
+ } else if (_action.isAction(0x325, 0x324)) {
+ switch (_game._trigger) {
+ case 0:
+ _game._player._stepEnabled = false;
+ _scene->_sequences.remove(_globals._sequenceIndexes[1]);
+ _globals._sequenceIndexes[1] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[1], false, 6, 1, 0, 0);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 5);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[1], SEQUENCE_TRIGGER_EXPIRE, 0, 1);
+ break;
+
+ case 1: {
+ int syncIdx = _globals._sequenceIndexes[1];
+ _globals._sequenceIndexes[1] = _scene->_sequences.startCycle(_globals._spriteIndexes[1], false, -1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 5);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[1], syncIdx);
+ _scene->_sequences.addTimer(6, 2);
+ }
+ break;
+
+ case 2:
+ _game._player._visible = false;
+ _globals._sequenceIndexes[4] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[4], false, 10, 1, 0, 0);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[4]);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[4], SEQUENCE_TRIGGER_EXPIRE, 0, 3);
+ break;
+
+ case 3: {
+ int syncIdx = _globals._sequenceIndexes[4];
+ _globals._sequenceIndexes[4] = _scene->_sequences.startCycle(_globals._spriteIndexes[4], false, -2);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[4]);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[4], syncIdx);
+ _scene->_nextSceneId = 504;
+ }
+ break;
+
+ default:
+ break;
+ }
+ } else if (_action._lookFlag)
+ _vm->_dialogs->show(60910);
+ else if (_action.isAction(VERB_LOOK, NOUN_STREET))
+ _vm->_dialogs->show(60911);
+ else if (_action.isAction(VERB_LOOK, NOUN_SPOT_A_POT))
+ _vm->_dialogs->show(60912);
+ else if (_action.isAction(VERB_LOOK, NOUN_VIDEO_STORE))
+ _vm->_dialogs->show(60913);
+ else if (_action.isAction(VERB_LOOK, NOUN_BILLBOARD))
+ _vm->_dialogs->show(60914);
+ else if (_action.isAction(VERB_LOOK, NOUN_STATUE))
+ _vm->_dialogs->show(60915);
+ else if (_action.isAction(VERB_LOOK, NOUN_CAR))
+ _vm->_dialogs->show(60916);
+ else if (_action.isAction(VERB_LOOK, NOUN_NEWSSTAND))
+ _vm->_dialogs->show(60917);
+ else if (_action.isAction(VERB_LOOK, NOUN_VIDEO_STORE_DOOR)) {
+ if (!_globals[kBeenInVideoStore])
+ _vm->_dialogs->show(60918);
+ else
+ _vm->_dialogs->show(60919);
+ } else if (_action.isAction(VERB_WALK_DOWN, NOUN_STREET))
+ _vm->_dialogs->show(60730);
+ else
+ return;
+
+ _action._inProgress = false;
+}
+
+/*------------------------------------------------------------------------*/
+
+Scene610::Scene610(MADSEngine *vm) : Scene6xx(vm) {
+ _handsetHotspotId = -1;
+ _checkVal = -1;
+
+ _cellCharging = false;
+
+ _cellChargingTimer = -1;
+ _lastFrameTimer = 0;
+}
+
+void Scene610::synchronize(Common::Serializer &s) {
+ Scene6xx::synchronize(s);
+
+ s.syncAsSint16LE(_handsetHotspotId);
+ s.syncAsSint16LE(_checkVal);
+
+ s.syncAsByte(_cellCharging);
+
+ s.syncAsSint32LE(_cellChargingTimer);
+ s.syncAsUint32LE(_lastFrameTimer);
+}
+
+void Scene610::setup() {
+ setPlayerSpritesPrefix();
+ setAAName();
+ _scene->addActiveVocab(NOUN_PHONE_HANDSET);
+ _scene->addActiveVocab(VERB_WALKTO);
+}
+
+void Scene610::enter() {
+ _globals._spriteIndexes[1] = _scene->_sprites.addSprites(formAnimName('p', -1));
+ _globals._spriteIndexes[2] = _scene->_sprites.addSprites("*RXMRC_9");
+ _globals._spriteIndexes[3] = _scene->_sprites.addSprites(formAnimName('x', 0));
+ _globals._spriteIndexes[4] = _scene->_sprites.addSprites(formAnimName('x', 1));
+
+ _globals._sequenceIndexes[4] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[4], false, 60, 0, 0, 0);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[4], 13);
+ _globals._sequenceIndexes[3] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[3], false, 30, 0, 0, 0);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 9);
+
+ if (!_game._visitedScenes._sceneRevisited)
+ _cellCharging = false;
+
+ if (_game._objects[OBJ_PHONE_HANDSET]._roomNumber == _scene->_currentSceneId) {
+ _globals._sequenceIndexes[1] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[1], false, 9, 0, 0, 0);
+ _handsetHotspotId = _scene->_dynamicHotspots.add(NOUN_PHONE_HANDSET, VERB_WALKTO, _globals._sequenceIndexes[1], Common::Rect(0, 0, 0, 0));
+ _scene->_dynamicHotspots.setPosition(_handsetHotspotId, Common::Point(132, 121), FACING_NORTHWEST);
+ if ((_globals[kHandsetCellStatus] == 2) && (_game._difficulty == DIFFICULTY_HARD) && !_globals[kDurafailRecharged])
+ _globals[kHandsetCellStatus] = 1;
+ }
+
+ if (_scene->_roomChanged && _game._difficulty != DIFFICULTY_EASY)
+ _game._objects.addToInventory(OBJ_PENLIGHT);
+
+ if (_scene->_priorSceneId != -2) {
+ _game._player._playerPos = Common::Point(175, 152);
+ _game._player._facing = FACING_NORTHWEST;
+ }
+
+ sceneEntrySound();
+}
+
+void Scene610::step() {
+ if (_cellCharging) {
+ long diff = _scene->_frameStartTime - _lastFrameTimer;
+ if ((diff >= 0) && (diff <= 60))
+ _cellChargingTimer += diff;
+ else
+ _cellChargingTimer++;
+
+ _lastFrameTimer = _scene->_frameStartTime;
+ }
+
+ // CHECKME: _checkVal is always false, could be removed
+ if ((_cellChargingTimer >= 60) && !_checkVal) {
+ _checkVal = true;
+ _globals[kHandsetCellStatus] = 1;
+ _cellCharging = false;
+ _checkVal = false;
+ _cellChargingTimer = 0;
+ }
+}
+
+void Scene610::actions() {
+ if (_action.isAction(VERB_EXIT_FROM, NOUN_VIDEO_STORE))
+ _scene->_nextSceneId = 609;
+ else if (_action.isAction(VERB_TAKE, NOUN_PHONE_HANDSET)) {
+ if ( _game._trigger || !_game._objects.isInInventory(OBJ_PHONE_HANDSET)) {
+ switch (_game._trigger) {
+ case 0:
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._sequenceIndexes[2] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[2], true, 8, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[2], 1, 2);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[2]);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[2], SEQUENCE_TRIGGER_SPRITE, 2, 1);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[2], SEQUENCE_TRIGGER_EXPIRE, 0, 2);
+ break;
+
+ case 1:
+ _vm->_sound->command(9);
+ _scene->_sequences.remove(_globals._sequenceIndexes[1]);
+ _scene->_dynamicHotspots.remove(_handsetHotspotId);
+ _game._objects.addToInventory(OBJ_PHONE_HANDSET);
+ _vm->_dialogs->showItem(OBJ_PHONE_HANDSET, 61017);
+ break;
+
+ case 2:
+ _scene->_sequences.updateTimeout(-1, _globals._sequenceIndexes[2]);
+ _game._player._visible = true;
+ _game._player._stepEnabled = true;
+ break;
+
+ default:
+ break;
+ }
+ }
+ } else if (_action.isAction(VERB_PUT, NOUN_PHONE_HANDSET, 0x42F)) {
+ switch (_game._trigger) {
+ case 0:
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._sequenceIndexes[2] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[2], true, 8, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[2], 1, 2);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[2]);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[2], SEQUENCE_TRIGGER_SPRITE, 2, 1);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[2], SEQUENCE_TRIGGER_EXPIRE, 0, 2);
+ break;
+
+ case 1:
+ _globals._sequenceIndexes[1] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[1], false, 9, 0, 0, 0);
+ _handsetHotspotId = _scene->_dynamicHotspots.add(NOUN_PHONE_HANDSET, VERB_WALKTO, _globals._sequenceIndexes[1], Common::Rect(0, 0, 0, 0));
+ _scene->_dynamicHotspots.setPosition(_handsetHotspotId, Common::Point(132, 121), FACING_NORTHWEST);
+ _game._objects.setRoom(OBJ_PHONE_HANDSET, _scene->_currentSceneId);
+ break;
+
+ case 2:
+ _scene->_sequences.updateTimeout(-1, _globals._sequenceIndexes[2]);
+ _game._player._visible = true;
+ _game._player._stepEnabled = true;
+ if ((_globals[kHandsetCellStatus] == 2) && (_game._difficulty == DIFFICULTY_HARD) && !_globals[kDurafailRecharged])
+ _cellCharging = true;
+
+ _vm->_dialogs->show(61032);
+ break;
+
+ default:
+ break;
+ }
+ } else if (_action.isAction(VERB_LOOK, NOUN_PIPPY_BILLBOARD))
+ _vm->_dialogs->show(61010);
+ else if (_action.isAction(VERB_LOOK, NOUN_CIVILIZATION_AD))
+ _vm->_dialogs->show(61011);
+ else if (_action.isAction(VERB_LOOK, NOUN_MARX_BROS_POSTER))
+ _vm->_dialogs->show(61012);
+ else if (_action.isAction(VERB_LOOK, NOUN_VIDEO_MONITOR))
+ _vm->_dialogs->show(61013);
+ else if (_action.isAction(VERB_LOOK, NOUN_VIDEO_STORE))
+ _vm->_dialogs->show(61014);
+ else if (_action._lookFlag)
+ _vm->_dialogs->show(61015);
+ else if (_action.isAction(VERB_LOOK, NOUN_LOGO))
+ _vm->_dialogs->show(61018);
+ else if (_action.isAction(VERB_LOOK, NOUN_CEMENT)) {
+ if (_game._visitedScenes.exists(601))
+ _vm->_dialogs->show(61020);
+ else
+ _vm->_dialogs->show(61019);
+ } else if (_action.isAction(VERB_LOOK, NOUN_COUNTER))
+ _vm->_dialogs->show(61021);
+ else if (_action.isAction(VERB_LOOK, NOUN_PHONE_ANTENNA))
+ _vm->_dialogs->show(61022);
+ else if (_action.isAction(VERB_LOOK, NOUN_SMELLY_SNEAKER))
+ _vm->_dialogs->show(61023);
+ else if (_action.isAction(VERB_TAKE, NOUN_SMELLY_SNEAKER))
+ _vm->_dialogs->show(61024);
+ else if (_action.isAction(VERB_LOOK, NOUN_SPOTLIGHT))
+ _vm->_dialogs->show(61025);
+ else if (_action.isAction(VERB_LOOK, NOUN_PHONE_HANDSET) && (_action._mainObjectSource == 4))
+ _vm->_dialogs->show(61026);
+ else if (_action.isAction(VERB_LOOK, NOUN_PHONE_CRADLE))
+ _vm->_dialogs->show(61027);
+ else if (_action.isAction(VERB_LOOK, NOUN_RETURN_SLOT))
+ _vm->_dialogs->show(61028);
+ else if (_action.isAction(VERB_PUT, NOUN_RETURN_SLOT)
+ && _game._objects.isInInventory(_game._objects.getIdFromDesc(_action._activeAction._objectNameId)))
+ _vm->_dialogs->show(61029);
+ else if ( _action.isAction(0x44F) || _action.isAction(0x444) || _action.isAction(0x430)
+ || _action.isAction(0x44C) || _action.isAction(0x44D) || _action.isAction(0x446)
+ || _action.isAction(0x497) || _action.isAction(0x449) || _action.isAction(0x44E)
+ || _action.isAction(0x450) || _action.isAction(0x42C)) {
+ if (_action.isAction(VERB_LOOK))
+ _vm->_dialogs->show(61030);
+ else if (_action.isAction(VERB_TAKE))
+ _vm->_dialogs->show(61031);
+ else
+ return;
+ } else
+ return;
+
+ _action._inProgress = false;
+}
+
+/*------------------------------------------------------------------------*/
+
+Scene611::Scene611(MADSEngine *vm) : Scene6xx(vm), _defaultDialogPos(0, 0) {
+ _seenRatFl = false;
+ _eyesRunningFl = false;
+ _shouldRemoveEyes = false;
+ _ratPresentFl = false;
+ _duringDialogFl = false;
+ _resetBatterieText = false;
+ _hermitTalkingFl = false;
+ _hermitMovingFl = false;
+ _alreadyTalkingFl = false;
+ _giveBatteriesFl = false;
+ _startTradingFl = false;
+ _check1Fl = false;
+ _stickFingerFl = false;
+
+ _randVal = -1;
+ _ratHotspotId = -1;
+ _hermitDialogNode = -1;
+ _hermitDisplayedQuestion = -1;
+ _nextFrame = -1;
+ _hermitMode = -1;
+
+ _ratTimer = 0;
+}
+
+void Scene611::synchronize(Common::Serializer &s) {
+ Scene6xx::synchronize(s);
+
+ s.syncAsByte(_seenRatFl);
+ s.syncAsByte(_eyesRunningFl);
+ s.syncAsByte(_shouldRemoveEyes);
+ s.syncAsByte(_ratPresentFl);
+ s.syncAsByte(_duringDialogFl);
+ s.syncAsByte(_resetBatterieText);
+ s.syncAsByte(_hermitTalkingFl);
+ s.syncAsByte(_hermitMovingFl);
+ s.syncAsByte(_alreadyTalkingFl);
+ s.syncAsByte(_giveBatteriesFl);
+ s.syncAsByte(_startTradingFl);
+ s.syncAsByte(_check1Fl);
+ s.syncAsByte(_stickFingerFl);
+
+ s.syncAsSint16LE(_randVal);
+ s.syncAsSint16LE(_ratHotspotId);
+ s.syncAsSint16LE(_hermitDialogNode);
+ s.syncAsSint16LE(_hermitDisplayedQuestion);
+ s.syncAsSint16LE(_nextFrame);
+ s.syncAsSint16LE(_hermitMode);
+
+ s.syncAsUint32LE(_ratTimer);
+
+ s.syncAsSint16LE(_defaultDialogPos.x);
+ s.syncAsSint16LE(_defaultDialogPos.y);
+}
+
+void Scene611::setup() {
+ setPlayerSpritesPrefix();
+ setAAName();
+ _scene->addActiveVocab(NOUN_RAT);
+ _scene->addActiveVocab(VERB_WALKTO);
+}
+
+void Scene611::handleRatMoves() {
+ _ratPresentFl = false;
+ _scene->_sequences.remove(_globals._sequenceIndexes[1]);
+ _globals._sequenceIndexes[1] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[1], false, 12, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[1], 11, -2);
+ _ratTimer = _game._player._priorTimer;
+ _scene->_dynamicHotspots.remove(_ratHotspotId);
+}
+
+void Scene611::handleTrading() {
+ if (_game._objects.isInInventory(OBJ_DURAFAIL_CELLS))
+ _game._objects.setRoom(OBJ_DURAFAIL_CELLS, 1);
+
+ if (_game._objects.isInInventory(OBJ_PHONE_CELLS))
+ _game._objects.setRoom(OBJ_PHONE_CELLS, 1);
+
+ _game._objects.addToInventory(OBJ_FAKE_ID);
+}
+
+void Scene611::setDialogNode(int node) {
+ if (node > 0)
+ _hermitDialogNode = node;
+
+ _game._player._stepEnabled = true;
+
+ switch (node) {
+ case 0:
+ _scene->_userInterface.setup(kInputBuildingSentences);
+ _duringDialogFl = false;
+ _hermitDialogNode = 0;
+ break;
+
+ case 1:
+ _dialog1.start();
+ _duringDialogFl = true;
+ _hermitDialogNode = 1;
+ break;
+
+ case 2:
+ _dialog2.start();
+ _duringDialogFl = true;
+ _hermitDialogNode = 2;
+ break;
+
+ default:
+ break;
+ }
+}
+
+bool Scene611::check2ChargedBatteries() {
+ if ((_game._objects.isInInventory(OBJ_DURAFAIL_CELLS) && !_game._objects.isInInventory(OBJ_PHONE_CELLS))
+ || (!_game._objects.isInInventory(OBJ_DURAFAIL_CELLS) && _game._objects.isInInventory(OBJ_PHONE_CELLS)))
+ return true;
+
+ return false;
+}
+
+bool Scene611::check4ChargedBatteries() {
+ if (_game._objects.isInInventory(OBJ_DURAFAIL_CELLS) && _game._objects.isInInventory(OBJ_PHONE_CELLS) && _globals[136])
+ return true;
+
+ return false;
+}
+
+void Scene611::handleTalking(int delay) {
+ if (_hermitTalkingFl)
+ _alreadyTalkingFl = true;
+
+ _hermitTalkingFl = true;
+ _game._triggerSetupMode = SEQUENCE_TRIGGER_DAEMON;
+ _scene->_sequences.addTimer(delay, 100);
+}
+
+void Scene611::handleSubDialog1() {
+ switch (_action._activeAction._verbId) {
+ case 0x287:
+ _stickFingerFl = true;
+ _nextFrame = 34;
+ _hermitMovingFl = false;
+ _hermitMode = 5;
+ displayHermitQuestions(5);
+ _dialog1.write(0x287, false);
+ if (!_dialog1.read(0x288))
+ _dialog1.write(0x28E, true);
+
+ _dialog2.write(0x29C, true);
+ _dialog2.write(0x29D, true);
+ _dialog2.write(0x29E, true);
+ setDialogNode(2);
+ break;
+
+ case 0x288:
+ handleTalking(500);
+ displayHermitQuestions(6);
+ _dialog1.write(0x288, false);
+ _dialog1.write(0x289, true);
+ if (!_dialog1.read(0x287))
+ _dialog1.write(0x28E, true);
+
+ setDialogNode(1);
+ break;
+
+ case 0x289:
+ handleTalking(500);
+ displayHermitQuestions(10);
+ _dialog1.write(0x289, false);
+ _dialog1.write(0x28A, true);
+ _dialog1.write(0x28B, true);
+ setDialogNode(1);
+ break;
+
+ case 0x28A:
+ handleTalking(500);
+ displayHermitQuestions(11);
+ _dialog1.write(0x28A, false);
+ setDialogNode(1);
+ break;
+
+ case 0x28B:
+ handleTalking(500);
+ displayHermitQuestions(12);
+ _dialog1.write(0x28C, true);
+ _dialog1.write(0x28D, true);
+ _dialog1.write(0x28B, false);
+ setDialogNode(1);
+ break;
+
+ case 0x28C:
+ handleTalking(500);
+ displayHermitQuestions(13);
+ _dialog1.write(0x28C, false);
+ setDialogNode(1);
+ break;
+
+ case 0x28D:
+ handleTalking(500);
+ displayHermitQuestions(14);
+ _dialog1.write(0x290, true);
+ _dialog1.write(0x28D, false);
+ _dialog1.write(0x28F, true);
+ setDialogNode(1);
+ break;
+
+ case 0x28E:
+ handleTalking(500);
+ displayHermitQuestions(15);
+ _dialog1.write(0x295, true);
+ _dialog1.write(0x28E, false);
+ setDialogNode(1);
+ break;
+
+ case 0x290:
+ handleTalking(500);
+ displayHermitQuestions(17);
+ _dialog1.write(0x290, false);
+ _dialog1.write(0x28E, false);
+ if (!_dialog1.read(0x28F))
+ _dialog1.write(0x291, true);
+
+ setDialogNode(1);
+ break;
+
+ case 0x291:
+ handleTalking(500);
+ displayHermitQuestions(18);
+ _dialog1.write(0x291, false);
+ if ((!_game._objects.isInInventory(OBJ_DURAFAIL_CELLS)) && (!_game._objects.isInInventory(OBJ_PHONE_CELLS))) {
+ _dialog1.write(0x292, true);
+ _dialog1.write(0x293, true);
+ }
+
+ if ((_game._objects.isInInventory(OBJ_DURAFAIL_CELLS)) || (_game._objects.isInInventory(OBJ_PHONE_CELLS)))
+ _dialog1.write(0x294, true);
+
+ if (!_game._objects.isInInventory(OBJ_DURAFAIL_CELLS) && !_game._objects.isInInventory(OBJ_PHONE_CELLS))
+ _globals[kExecuted_1_11] = true;
+
+ setDialogNode(1);
+ break;
+
+ case 0x28F:
+ handleTalking(500);
+ displayHermitQuestions(16);
+ _dialog1.write(0x28F, false);
+ if (!_dialog1.read(0x290))
+ _dialog1.write(0x291, true);
+
+ setDialogNode(1);
+ break;
+
+ case 0x295:
+ handleTalking(500);
+ displayHermitQuestions(20);
+ _dialog1.write(0x295, false);
+ setDialogNode(1);
+ break;
+
+ case 0x292:
+ handleTalking(500);
+ displayHermitQuestions(19);
+ _dialog1.write(0x292, false);
+ _dialog1.write(0x293, false);
+ setDialogNode(1);
+ break;
+
+ case 0x293: {
+ handleTalking(200);
+ _scene->_kernelMessages.reset();
+
+ Common::String curQuote = _game.getQuote(0x2D1);
+ int width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
+ int quotePosX = _defaultDialogPos.x - (width / 2);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y), 0xFDFC, 0, 0, 120, curQuote);
+
+ curQuote = _game.getQuote(0x2D2);
+ width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
+ quotePosX = _defaultDialogPos.x - (width / 2);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 14), 0xFDFC, 0, 0, 120, curQuote);
+
+ _dialog1.write(0x293, false);
+ setDialogNode(0);
+ }
+ break;
+
+ case 0x294: {
+ bool hermitPleasedFl = false;
+
+ switch (_game._difficulty) {
+ case DIFFICULTY_EASY:
+ hermitPleasedFl = _game._objects.isInInventory(OBJ_DURAFAIL_CELLS) || _game._objects.isInInventory(OBJ_PHONE_CELLS);
+ break;
+
+ case DIFFICULTY_MEDIUM:
+ hermitPleasedFl = _game._objects.isInInventory(OBJ_DURAFAIL_CELLS) && _game._objects.isInInventory(OBJ_PHONE_CELLS);
+ break;
+
+ default: // HARD
+ hermitPleasedFl = check4ChargedBatteries();
+ break;
+ }
+
+ if (hermitPleasedFl) {
+ _hermitDisplayedQuestion = 21;
+ if (!_giveBatteriesFl)
+ setDialogNode(0);
+ else
+ _giveBatteriesFl = false;
+ } else if (((_game._difficulty == DIFFICULTY_MEDIUM) || (_game._difficulty == DIFFICULTY_HARD)) && check2ChargedBatteries()) {
+ _hermitDisplayedQuestion = 22;
+ if (!_giveBatteriesFl)
+ setDialogNode(0);
+ else
+ _giveBatteriesFl = false;
+ } else {
+ _hermitDisplayedQuestion = 23;
+ if (!_giveBatteriesFl)
+ setDialogNode(0);
+ else
+ _giveBatteriesFl = false;
+ }
+ _startTradingFl = true;
+ }
+ break;
+
+ case 0x296: {
+ _scene->_kernelMessages.reset();
+
+ Common::String curQuote = _game.getQuote(0x2E6);
+ int width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
+ int quotePosX = _defaultDialogPos.x - (width / 2);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 14), 0xFDFC, 0, 0, 120, curQuote);
+
+ setDialogNode(0);
+ handleTalking(200);
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+void Scene611::handleSubDialog2() {
+ switch (_action._activeAction._verbId) {
+ case 0x29C:
+ displayHermitQuestions(7);
+ setDialogNode(1);
+ handleTalking(500);
+ break;
+
+ case 0x29D:
+ displayHermitQuestions(8);
+ setDialogNode(1);
+ handleTalking(500);
+ break;
+
+ case 0x29E:
+ displayHermitQuestions(9);
+ setDialogNode(1);
+ handleTalking(500);
+ break;
+
+ case 0x29F: {
+ _scene->_kernelMessages.reset();
+ Common::String curQuote = _game.getQuote(0x2A7);
+ int width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
+ int quotePosX = _defaultDialogPos.x - (width / 2);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 14), 0xFDFC, 0, 0, 120, curQuote);
+ setDialogNode(0);
+ _dialog2.write(0x29F, false);
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+void Scene611::handleDialog() {
+ if (_game._trigger == 0) {
+ _scene->_kernelMessages.reset();
+ _game._player._stepEnabled = false;
+
+ Common::String curQuote = _game.getQuote(_action._activeAction._verbId);
+ int width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
+
+ if (width > 200) {
+ Common::String subQuote1, subQuote2;
+ _game.splitQuote(curQuote, subQuote1, subQuote2);
+ _scene->_kernelMessages.add(Common::Point(0, -14), 0x1110, 34, 0, 150, subQuote1);
+
+ if (_action._activeAction._verbId == 0x29D)
+ _scene->_kernelMessages.add(Common::Point(-18, 0), 0x1110, 34, 1, 150, subQuote2);
+ else if (_action._activeAction._verbId == 0x28A)
+ _scene->_kernelMessages.add(Common::Point(-10, 0), 0x1110, 34, 1, 150, subQuote2);
+ else
+ _scene->_kernelMessages.add(Common::Point(0, 0), 0x1110, 34, 1, 150, subQuote2);
+
+ _scene->_sequences.addTimer(170, 50);
+ } else {
+ _scene->_kernelMessages.add(Common::Point(0, 0), 0x1110, 34, 1, 120, curQuote);
+ _scene->_sequences.addTimer(140, 50);
+ }
+ } else if (_game._trigger == 50) {
+ if (_hermitDialogNode == 1)
+ handleSubDialog1();
+ else if (_hermitDialogNode == 2)
+ handleSubDialog2();
+ }
+}
+
+void Scene611::displayHermitQuestions(int question) {
+ _scene->_kernelMessages.reset();
+ _hermitDisplayedQuestion = question;
+
+ switch (question) {
+ case 1: {
+ Common::String curQuote = _game.getQuote(0x281);
+ int width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
+ int quotePosX = _defaultDialogPos.x - (width / 2);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y), 0xFDFC, 0, 0, 9999999, curQuote);
+
+ curQuote = _game.getQuote(0x282);
+ width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
+ quotePosX = _defaultDialogPos.x - (width / 2);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 14), 0xFDFC, 0, 0, 9999999, curQuote);
+ }
+ break;
+
+ case 2: {
+ Common::String curQuote = _game.getQuote(0x283);
+ int width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
+ int quotePosX = _defaultDialogPos.x - (width / 2);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y), 0xFDFC, 0, 0, 9999999, curQuote);
+
+ curQuote = _game.getQuote(0x284);
+ width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
+ quotePosX = _defaultDialogPos.x - (width / 2);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 14), 0xFDFC, 0, 0, 9999999, curQuote);
+ }
+ break;
+
+ case 3: {
+ Common::String curQuote = _game.getQuote(0x285);
+ int width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
+ int quotePosX = _defaultDialogPos.x - (width / 2);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 14), 0xFDFC, 0, 0, 9999999, curQuote);
+ }
+ break;
+
+ case 4: {
+ Common::String curQuote = _game.getQuote(0x286);
+ int width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
+ int quotePosX = _defaultDialogPos.x - (width / 2);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 14), 0xFDFC, 0, 0, 9999999, curQuote);
+ }
+ break;
+
+ case 5: {
+ Common::String curQuote = _game.getQuote(0x297);
+ int width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
+ int quotePosX = _defaultDialogPos.x - (width / 2);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y - 14), 0xFDFC, 0, 0, 9999999, curQuote);
+
+ curQuote = _game.getQuote(0x298);
+ width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
+ quotePosX = _defaultDialogPos.x - (width / 2);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y), 0xFDFC, 0, 0, 9999999, curQuote);
+
+ curQuote = _game.getQuote(0x299);
+ width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
+ quotePosX = _defaultDialogPos.x - (width / 2);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 14), 0xFDFC, 0, 0, 9999999, curQuote);
+ }
+ break;
+
+ case 6: {
+ Common::String curQuote = _game.getQuote(0x29A);
+ int width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
+ int quotePosX = _defaultDialogPos.x - (width / 2);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y), 0xFDFC, 0, 0, 9999999, curQuote);
+
+ curQuote = _game.getQuote(0x29B);
+ width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
+ quotePosX = _defaultDialogPos.x - (width / 2);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 14), 0xFDFC, 0, 0, 9999999, curQuote);
+ }
+ break;
+
+ case 7: {
+ Common::String curQuote = _game.getQuote(0x2A0);
+ int width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
+ int quotePosX = _defaultDialogPos.x - (width / 2);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 45), 0xFDFC, 0, 0, 9999999, curQuote);
+
+ curQuote = _game.getQuote(0x2A1);
+ width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
+ quotePosX = _defaultDialogPos.x - (width / 2);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 59), 0xFDFC, 0, 0, 9999999, curQuote);
+ }
+ break;
+
+ case 8: {
+ Common::String curQuote = _game.getQuote(0x2A2);
+ int width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
+ int quotePosX = _defaultDialogPos.x - (width / 2);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 31), 0xFDFC, 0, 0, 9999999, curQuote);
+
+ curQuote = _game.getQuote(0x2A3);
+ width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
+ quotePosX = _defaultDialogPos.x - (width / 2);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 45), 0xFDFC, 0, 0, 9999999, curQuote);
+
+ curQuote = _game.getQuote(0x2A4);
+ width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
+ quotePosX = _defaultDialogPos.x - (width / 2);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 59), 0xFDFC, 0, 0, 9999999, curQuote);
+ }
+ break;
+
+ case 9: {
+ Common::String curQuote = _game.getQuote(0x2A5);
+ int width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
+ int quotePosX = _defaultDialogPos.x - (width / 2);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 45), 0xFDFC, 0, 0, 9999999, curQuote);
+
+ curQuote = _game.getQuote(0x2A6);
+ width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
+ quotePosX = _defaultDialogPos.x - (width / 2);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 59), 0xFDFC, 0, 0, 9999999, curQuote);
+ }
+ break;
+
+ case 10: {
+ Common::String curQuote = _game.getQuote(0x2A8);
+ int width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
+ int quotePosX = _defaultDialogPos.x - (width / 2);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 31), 0xFDFC, 0, 0, 9999999, curQuote);
+
+ curQuote = _game.getQuote(0x2A9);
+ width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
+ quotePosX = _defaultDialogPos.x - (width / 2);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 45), 0xFDFC, 0, 0, 9999999, curQuote);
+
+ curQuote = _game.getQuote(0x2AA);
+ width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
+ quotePosX = _defaultDialogPos.x - (width / 2);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 59), 0xFDFC, 0, 0, 9999999, curQuote);
+ }
+ break;
+
+ case 11: {
+ Common::String curQuote = _game.getQuote(0x2AB);
+ int width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
+ int quotePosX = _defaultDialogPos.x - (width / 2);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 17), 0xFDFC, 0, 0, 9999999, curQuote);
+
+ curQuote = _game.getQuote(0x2AC);
+ width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
+ quotePosX = _defaultDialogPos.x - (width / 2);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 31), 0xFDFC, 0, 0, 9999999, curQuote);
+
+ curQuote = _game.getQuote(0x2AD);
+ width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
+ quotePosX = _defaultDialogPos.x - (width / 2);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 45), 0xFDFC, 0, 0, 9999999, curQuote);
+
+ curQuote = _game.getQuote(0x2AE);
+ width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
+ quotePosX = _defaultDialogPos.x - (width / 2);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 59), 0xFDFC, 0, 0, 9999999, curQuote);
+ }
+ break;
+
+ case 12: {
+ Common::String curQuote = _game.getQuote(0x2AF);
+ int width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
+ int quotePosX = _defaultDialogPos.x - (width / 2);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 17), 0xFDFC, 0, 0, 9999999, curQuote);
+
+ curQuote = _game.getQuote(0x2B0);
+ width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
+ quotePosX = _defaultDialogPos.x - (width / 2);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 31), 0xFDFC, 0, 0, 9999999, curQuote);
+
+ curQuote = _game.getQuote(0x2B1);
+ width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
+ quotePosX = _defaultDialogPos.x - (width / 2);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 45), 0xFDFC, 0, 0, 9999999, curQuote);
+
+ curQuote = _game.getQuote(0x2B2);
+ width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
+ quotePosX = _defaultDialogPos.x - (width / 2);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 59), 0xFDFC, 0, 0, 9999999, curQuote);
+ }
+ break;
+
+ case 13: {
+ Common::String curQuote = _game.getQuote(0x2B3);
+ int width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
+ int quotePosX = _defaultDialogPos.x - (width / 2);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 3), 0xFDFC, 0, 0, 9999999, curQuote);
+
+ curQuote = _game.getQuote(0x2B4);
+ width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
+ quotePosX = _defaultDialogPos.x - (width / 2);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 17), 0xFDFC, 0, 0, 9999999, curQuote);
+
+ curQuote = _game.getQuote(0x2B5);
+ width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
+ quotePosX = _defaultDialogPos.x - (width / 2);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 31), 0xFDFC, 0, 0, 9999999, curQuote);
+
+ curQuote = _game.getQuote(0x2B6);
+ width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
+ quotePosX = _defaultDialogPos.x - (width / 2);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 45), 0xFDFC, 0, 0, 9999999, curQuote);
+
+ _scene->_kernelMessages.add(Common::Point(11, _defaultDialogPos.y + 59), 0xFDFC, 0, 0, 9999999, _game.getQuote(0x2B7));
+ _scene->_kernelMessages.add(Common::Point(11, _defaultDialogPos.y + 73), 0xFDFC, 0, 0, 9999999, _game.getQuote(0x2B8));
+ _scene->_kernelMessages.add(Common::Point(11, _defaultDialogPos.y + 87), 0xFDFC, 0, 0, 9999999, _game.getQuote(0x2B9));
+ }
+ break;
+
+ case 14: {
+ Common::String curQuote = _game.getQuote(0x2BA);
+ int width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
+ int quotePosX = _defaultDialogPos.x - (width / 2);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 17), 0xFDFC, 0, 0, 9999999, curQuote);
+
+ curQuote = _game.getQuote(0x2BB);
+ width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
+ quotePosX = _defaultDialogPos.x - (width / 2);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 31), 0xFDFC, 0, 0, 9999999, curQuote);
+
+ curQuote = _game.getQuote(0x2BC);
+ width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
+ quotePosX = _defaultDialogPos.x - (width / 2);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 45), 0xFDFC, 0, 0, 9999999, curQuote);
+
+ curQuote = _game.getQuote(0x2BD);
+ width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
+ quotePosX = _defaultDialogPos.x - (width / 2);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 59), 0xFDFC, 0, 0, 9999999, curQuote);
+ }
+ break;
+
+ case 15: {
+ Common::String curQuote = _game.getQuote(0x2BE);
+ int width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
+ int quotePosX = _defaultDialogPos.x - (width / 2);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 17), 0xFDFC, 0, 0, 9999999, curQuote);
+
+ curQuote = _game.getQuote(0x2BF);
+ width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
+ quotePosX = _defaultDialogPos.x - (width / 2);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 31), 0xFDFC, 0, 0, 9999999, curQuote);
+
+ curQuote = _game.getQuote(0x2C0);
+ width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
+ quotePosX = _defaultDialogPos.x - (width / 2);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 45), 0xFDFC, 0, 0, 9999999, curQuote);
+
+ curQuote = _game.getQuote(0x2C1);
+ width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
+ quotePosX = _defaultDialogPos.x - (width / 2);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 59), 0xFDFC, 0, 0, 9999999, curQuote);
+ }
+ break;
+
+ case 16: {
+ Common::String curQuote = _game.getQuote(0x2C2);
+ int width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
+ int quotePosX = _defaultDialogPos.x - (width / 2);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 3), 0xFDFC, 0, 0, 9999999, curQuote);
+
+ curQuote = _game.getQuote(0x2C3);
+ width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
+ quotePosX = _defaultDialogPos.x - (width / 2);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 17), 0xFDFC, 0, 0, 9999999, curQuote);
+
+ curQuote = _game.getQuote(0x2C4);
+ width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
+ quotePosX = _defaultDialogPos.x - (width / 2);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 31), 0xFDFC, 0, 0, 9999999, curQuote);
+
+ curQuote = _game.getQuote(0x2C5);
+ width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
+ quotePosX = _defaultDialogPos.x - (width / 2);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 45), 0xFDFC, 0, 0, 9999999, curQuote);
+
+ curQuote = _game.getQuote(0x2C6);
+ width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
+ quotePosX = _defaultDialogPos.x - (width / 2);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 59), 0xFDFC, 0, 0, 9999999, curQuote);
+ }
+ break;
+
+ case 17: {
+ Common::String curQuote = _game.getQuote(0x2C7);
+ int width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
+ int quotePosX = _defaultDialogPos.x - (width / 2);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 17), 0xFDFC, 0, 0, 9999999, curQuote);
+
+ curQuote = _game.getQuote(0x2C8);
+ width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
+ quotePosX = _defaultDialogPos.x - (width / 2);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 31), 0xFDFC, 0, 0, 9999999, curQuote);
+
+ curQuote = _game.getQuote(0x2C0);
+ width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
+ quotePosX = _defaultDialogPos.x - (width / 2);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 45), 0xFDFC, 0, 0, 9999999, curQuote);
+
+ curQuote = _game.getQuote(0x2CA);
+ width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
+ quotePosX = _defaultDialogPos.x - (width / 2);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 59), 0xFDFC, 0, 0, 9999999, curQuote);
+ }
+ break;
+
+ case 18: {
+ Common::String curQuote = _game.getQuote(0x2CB);
+ int width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
+ int quotePosX = _defaultDialogPos.x - (width / 2);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 31), 0xFDFC, 0, 0, 9999999, curQuote);
+
+ curQuote = _game.getQuote(0x2CC);
+ width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
+ quotePosX = _defaultDialogPos.x - (width / 2);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 45), 0xFDFC, 0, 0, 9999999, curQuote);
+
+ curQuote = _game.getQuote(0x2CD);
+ width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
+ quotePosX = _defaultDialogPos.x - (width / 2);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 59), 0xFDFC, 0, 0, 9999999, curQuote);
+ }
+ break;
+
+ case 19: {
+ Common::String curQuote = _game.getQuote(0x2CE);
+ int width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
+ int quotePosX = _defaultDialogPos.x - (width / 2);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 31), 0xFDFC, 0, 0, 9999999, curQuote);
+
+ curQuote = _game.getQuote(0x2CF);
+ width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
+ quotePosX = _defaultDialogPos.x - (width / 2);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 45), 0xFDFC, 0, 0, 9999999, curQuote);
+
+ curQuote = _game.getQuote(0x2D0);
+ width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
+ quotePosX = _defaultDialogPos.x - (width / 2);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 59), 0xFDFC, 0, 0, 9999999, curQuote);
+ }
+ break;
+
+ case 20: {
+ Common::String curQuote = _game.getQuote(0x2E1);
+ int width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
+ int quotePosX = _defaultDialogPos.x - (width / 2);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 3), 0xFDFC, 0, 0, 9999999, curQuote);
+
+ curQuote = _game.getQuote(0x2E2);
+ width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
+ quotePosX = _defaultDialogPos.x - (width / 2);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 17), 0xFDFC, 0, 0, 9999999, curQuote);
+
+ curQuote = _game.getQuote(0x2E3);
+ width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
+ quotePosX = _defaultDialogPos.x - (width / 2);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 31), 0xFDFC, 0, 0, 9999999, curQuote);
+
+ curQuote = _game.getQuote(0x2E4);
+ width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
+ quotePosX = _defaultDialogPos.x - (width / 2);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 45), 0xFDFC, 0, 0, 9999999, curQuote);
+
+ curQuote = _game.getQuote(0x2E5);
+ width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
+ quotePosX = _defaultDialogPos.x - (width / 2);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 59), 0xFDFC, 0, 0, 9999999, curQuote);
+ }
+ break;
+
+ case 21: {
+ Common::String curQuote = _game.getQuote(0x2D3);
+ int width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
+ int quotePosX = _defaultDialogPos.x - (width / 2);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 3), 0xFDFC, 0, 0, 9999999, curQuote);
+
+ curQuote = _game.getQuote(0x2D4);
+ width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
+ quotePosX = _defaultDialogPos.x - (width / 2);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 17), 0xFDFC, 0, 0, 9999999, curQuote);
+
+ curQuote = _game.getQuote(0x2D5);
+ width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
+ quotePosX = _defaultDialogPos.x - (width / 2);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 31), 0xFDFC, 0, 0, 9999999, curQuote);
+
+ curQuote = _game.getQuote(0x2D6);
+ width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
+ quotePosX = _defaultDialogPos.x - (width / 2);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 45), 0xFDFC, 0, 0, 9999999, curQuote);
+
+ curQuote = _game.getQuote(0x2D7);
+ width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
+ quotePosX = _defaultDialogPos.x - (width / 2);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 59), 0xFDFC, 0, 0, 9999999, curQuote);
+ }
+ break;
+
+ case 22: {
+ Common::String curQuote = _game.getQuote(0x2D8);
+ int width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
+ int quotePosX = _defaultDialogPos.x - (width / 2);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 17), 0xFDFC, 0, 0, 700, curQuote);
+
+ curQuote = _game.getQuote(0x2D9);
+ width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
+ quotePosX = _defaultDialogPos.x - (width / 2);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 31), 0xFDFC, 0, 0, 700, curQuote);
+
+ curQuote = _game.getQuote(0x2DA);
+ width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
+ quotePosX = _defaultDialogPos.x - (width / 2);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 45), 0xFDFC, 0, 0, 700, curQuote);
+
+ curQuote = _game.getQuote(0x2DB);
+ width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
+ quotePosX = _defaultDialogPos.x - (width / 2);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 59), 0xFDFC, 0, 0, 700, curQuote);
+ }
+ break;
+
+ case 23: {
+ Common::String curQuote = _game.getQuote(0x2DC);
+ int width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
+ int quotePosX = _defaultDialogPos.x - (width / 2);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 3), 0xFDFC, 0, 0, 700, curQuote);
+
+ curQuote = _game.getQuote(0x2DD);
+ width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
+ quotePosX = _defaultDialogPos.x - (width / 2);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 17), 0xFDFC, 0, 0, 700, curQuote);
+
+ curQuote = _game.getQuote(0x2DE);
+ width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
+ quotePosX = _defaultDialogPos.x - (width / 2);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 31), 0xFDFC, 0, 0, 700, curQuote);
+
+ curQuote = _game.getQuote(0x2DF);
+ width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
+ quotePosX = _defaultDialogPos.x - (width / 2);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 45), 0xFDFC, 0, 0, 700, curQuote);
+
+ curQuote = _game.getQuote(0x2E0);
+ width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
+ quotePosX = _defaultDialogPos.x - (width / 2);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 59), 0xFDFC, 0, 0, 700, curQuote);
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+void Scene611::enter() {
+ _globals._spriteIndexes[1] = _scene->_sprites.addSprites(formAnimName('x', 0));
+ _globals._spriteIndexes[2] = _scene->_sprites.addSprites(formAnimName('x', 1));
+ _globals._spriteIndexes[3] = _scene->_sprites.addSprites("*RXMRC_9");
+
+ _game.loadQuoteSet(0x279, 0x27A, 0x27B, 0x27C, 0x27D, 0x27E, 0x27F, 0x280, 0x281, 0x282, 0x283, 0x284,
+ 0x285, 0x286, 0x287, 0x288, 0x289, 0x28A, 0x28B, 0x28C, 0x28D, 0x28E, 0x28F, 0x290, 0x291, 0x292,
+ 0x293, 0x294, 0x295, 0x296, 0x297, 0x298, 0x299, 0x29A, 0x29B, 0x29C, 0x29D, 0x29E, 0x29F, 0x2A0,
+ 0x2A1, 0x2A2, 0x2A3, 0x2A4, 0x2A5, 0x2A6, 0x2A7, 0x2A8, 0x2A9, 0x2AA, 0x2AB, 0x2AC, 0x2AD, 0x2AE,
+ 0x2AF, 0x2B0, 0x2B1, 0x2B2, 0x2B3, 0x2B4, 0x2B5, 0x2B6, 0x2B7, 0x2B8, 0x2B9, 0x2BA, 0x2BB, 0x2BC,
+ 0x2BD, 0x2BE, 0x2BF, 0x2C0, 0x2C1, 0x2C2, 0x2C3, 0x2C4, 0x2C5, 0x2C6, 0x2C7, 0x2C8, 0x2C9, 0x2CA,
+ 0x2CB, 0x2CC, 0x2CD, 0x2CE, 0x2CF, 0x2D0, 0x2D1, 0x2D2, 0x2D3, 0x2D4, 0x2D5, 0x2D6, 0x2D7, 0x2D8,
+ 0x2D9, 0x2DA, 0x2DB, 0x2DC, 0x2DD, 0x2DE, 0x2DF, 0x2E0, 0x2E1, 0x2E2, 0x2E3, 0x2E4, 0x2E5, 0x2E6,
+ 0x323, 0x324, 0);
+
+ _dialog1.setup(0x82, 0x287, 0x288, 0x289, 0x28A, 0x28B, 0x28C, 0x28D, 0x28E, 0x28F, 0x290,
+ 0x291, 0x292, 0x293, 0x294, 0x295, 0x296, 0);
+
+ _dialog2.setup(0x83, 0x29C, 0x29D, 0x29E, 0x29F, 0);
+
+ if (!_game._visitedScenes._sceneRevisited) {
+ _dialog1.set(0x82, 0x287, 0x288, 0x296, 0);
+ _dialog2.set(0x83, 0x29F, 0);
+ }
+
+ _vm->_palette->setEntry(252, 51, 51, 47);
+ _vm->_palette->setEntry(253, 37, 37, 37);
+
+ _ratPresentFl = false;
+ _seenRatFl = true;
+ _eyesRunningFl = false;
+ _shouldRemoveEyes = false;
+ _randVal = 0;
+ _defaultDialogPos = Common::Point(264, 43);
+ _giveBatteriesFl = false;
+ _resetBatterieText = false;
+ _alreadyTalkingFl = false;
+ _startTradingFl = false;
+
+ if (_scene->_priorSceneId != -2) {
+ _game._player._playerPos = Common::Point(22, 132);
+ _game._player._facing = FACING_EAST;
+ _duringDialogFl = false;
+ }
+
+ if (!_globals[kHasTalkedToHermit]) {
+ _scene->loadAnimation(Resources::formatName(611, 'h', -1, EXT_AA, ""), 0);
+ _scene->loadAnimation(Resources::formatName(203, 'a', -1, EXT_AA, ""), 81);
+ _nextFrame = 47;
+ _hermitMode = 1;
+ _hermitTalkingFl = false;
+ _hermitMovingFl = true;
+ _check1Fl = true;
+ _stickFingerFl = false;
+ } else {
+ _hermitMode = 0;
+ _scene->_hotspots.activate(NOUN_HERMIT, false);
+ }
+
+ // CHECKME: The last line of the block looks extremely useless
+ if (_globals[kExecuted_1_11]) {
+ _dialog1.write(0x294, true);
+ _dialog1.write(0x292, false);
+ _globals[kExecuted_1_11] = true;
+ }
+
+ if (_duringDialogFl) {
+ _game._player._playerPos = Common::Point(237, 129);
+ _game._player._facing = FACING_NORTHEAST;
+
+ switch (_hermitDialogNode) {
+ case 0:
+ _scene->_userInterface.setup(kInputBuildingSentences);
+ _hermitDialogNode = 1;
+ break;
+
+ case 1:
+ _dialog1.start();
+ break;
+
+ case 2:
+ _dialog2.start();
+ break;
+
+ default:
+ break;
+ }
+ displayHermitQuestions(_hermitDisplayedQuestion);
+ }
+
+ sceneEntrySound();
+}
+
+void Scene611::step() {
+ if (_seenRatFl && (_vm->getRandomNumber(1, 100) == 10)) {
+ _seenRatFl = false;
+ _scene->_sequences.addTimer(1, 80);
+ }
+
+ if (_game._trigger == 80) {
+ _globals._sequenceIndexes[1] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[1], false, 12, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[1], 1, 8);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 1);
+ _ratPresentFl = true;
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[1], SEQUENCE_TRIGGER_EXPIRE, 0, 81);
+ } else if (_game._trigger == 81) {
+ int syncId = _globals._sequenceIndexes[1];
+ _globals._sequenceIndexes[1] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[1], false, 20, 0, 0, 0);
+ int idx = _scene->_dynamicHotspots.add(NOUN_RAT, VERB_WALKTO, _globals._sequenceIndexes[1], Common::Rect(0, 0, 0, 0));
+ _ratHotspotId = _scene->_dynamicHotspots.setPosition(idx, Common::Point(272, 154), FACING_SOUTHEAST);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[1], 9, 10);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[1], syncId);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 1);
+ _ratTimer = _game._player._priorTimer;
+ }
+
+ if (_ratPresentFl && ((_game._player._priorTimer - _ratTimer) > 1200))
+ handleRatMoves();
+
+ if (!_eyesRunningFl) {
+ _randVal = _vm->getRandomNumber(1, 30);
+ _eyesRunningFl = true;
+ _scene->_sequences.addTimer(1, 70);
+ }
+
+ if (_game._trigger == 70) {
+ switch (_randVal) {
+ case 2:
+ _globals._sequenceIndexes[2] = _scene->_sequences.startCycle(_globals._spriteIndexes[2], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 1);
+ _shouldRemoveEyes = true;
+ _scene->_sequences.addTimer(60, 71);
+ break;
+
+ case 6:
+ _globals._sequenceIndexes[2] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[2], false, 12, 3, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[2], 2, 4);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 1);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[2], SEQUENCE_TRIGGER_EXPIRE, 0, 71);
+ break;
+
+ case 7:
+ _globals._sequenceIndexes[2] = _scene->_sequences.startCycle(_globals._spriteIndexes[2], false, 5);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 1);
+ _shouldRemoveEyes = true;
+ _scene->_sequences.addTimer(60, 71);
+ break;
+
+ case 9:
+ _globals._sequenceIndexes[2] = _scene->_sequences.startCycle(_globals._spriteIndexes[2], false, 6);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 1);
+ _shouldRemoveEyes = true;
+ _scene->_sequences.addTimer(60, 71);
+ break;
+
+ case 13:
+ _globals._sequenceIndexes[2] = _scene->_sequences.startCycle(_globals._spriteIndexes[2], false, 7);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 1);
+ _shouldRemoveEyes = true;
+ _scene->_sequences.addTimer(60, 71);
+ break;
+
+ case 14:
+ _globals._sequenceIndexes[2] = _scene->_sequences.startCycle(_globals._spriteIndexes[2], false, 8);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 1);
+ _shouldRemoveEyes = true;
+ _scene->_sequences.addTimer(60, 71);
+ break;
+
+ case 15:
+ _globals._sequenceIndexes[2] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[2], false, 24, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[2], 5, 8);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 1);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[2], SEQUENCE_TRIGGER_EXPIRE, 0, 71);
+ break;
+
+ case 17:
+ _globals._sequenceIndexes[2] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[2], false, 20, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[2], 9, 11);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 1);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[2], SEQUENCE_TRIGGER_EXPIRE, 0, 71);
+ break;
+
+ case 21:
+ _globals._sequenceIndexes[2] = _scene->_sequences.startCycle(_globals._spriteIndexes[2], false, 9);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 1);
+ _shouldRemoveEyes = true;
+ _scene->_sequences.addTimer(60, 71);
+ break;
+
+ case 25:
+ _globals._sequenceIndexes[2] = _scene->_sequences.startCycle(_globals._spriteIndexes[2], false, 10);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 1);
+ _shouldRemoveEyes = true;
+ _scene->_sequences.addTimer(60, 71);
+ break;
+
+ case 27:
+ _globals._sequenceIndexes[2] = _scene->_sequences.startCycle(_globals._spriteIndexes[2], false, 11);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 1);
+ _shouldRemoveEyes = true;
+ _scene->_sequences.addTimer(60, 71);
+ break;
+
+ case 29:
+ _globals._sequenceIndexes[2] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[2], false, 20, 1, 0, 0);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 1);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[2], SEQUENCE_TRIGGER_EXPIRE, 0, 71);
+ break;
+
+ default:
+ _scene->_sequences.addTimer(1, 71);
+ break;
+ }
+ }
+
+ if (_game._trigger == 71) {
+ if (_shouldRemoveEyes) {
+ _scene->_sequences.remove(_globals._sequenceIndexes[2]);
+ _shouldRemoveEyes = false;
+ }
+ _eyesRunningFl = false;
+ _randVal = 0;
+ }
+
+ if (_game._trigger == 100) {
+ if (_alreadyTalkingFl)
+ _alreadyTalkingFl = false;
+ else
+ _hermitMovingFl = true;
+ }
+
+ if (_stickFingerFl && (_scene->_activeAnimation->getCurrentFrame() == 47)) {
+ _stickFingerFl = false;
+ _hermitMovingFl = true;
+ _hermitMode = 1;
+ }
+
+ if ((_scene->_activeAnimation->getCurrentFrame() == 240) && _check1Fl) {
+ _check1Fl = false;
+ _scene->_kernelMessages.add(Common::Point(33, 88), 0xFDFC, 0, 0, 90, _game.getQuote(0x27E));
+ _scene->_sequences.addTimer(120, 120);
+ }
+
+ if (_game._trigger == 120) {
+ int msgIdx = _scene->_kernelMessages.add(Common::Point(28, 102), 0xFDFC, 0, 0, 90, _game.getQuote(0x27F));
+ _scene->_kernelMessages.setQuoted(msgIdx, 4, true);
+ _scene->_sequences.addTimer(100, 121);
+ }
+
+ if (_game._trigger == 121) {
+ int msgIdx = _scene->_kernelMessages.add(Common::Point(23, 116), 0xFDFC, 0, 0, 90, _game.getQuote(0x280));
+ _scene->_kernelMessages.setQuoted(msgIdx, 4, true);
+ }
+
+ if (_hermitMode == 1) {
+ if (_startTradingFl) {
+ _hermitMode = 6;
+ _hermitMovingFl = false;
+ _hermitTalkingFl = false;
+ _scene->_sequences.addTimer(1, 110);
+ } else if (_hermitTalkingFl) {
+ _hermitMode = 2;
+ _nextFrame = 18;
+ _hermitMovingFl = false;
+ } else {
+ switch (_vm->getRandomNumber(1, 5)) {
+ case 1:
+ _nextFrame = 46;
+ break;
+
+ case 2:
+ _nextFrame = 47;
+ break;
+
+ case 3:
+ _nextFrame = 48;
+ break;
+
+ case 4:
+ _nextFrame = 49;
+ break;
+
+ case 5:
+ _nextFrame = 50;
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+
+ if (_hermitMode == 2) {
+ if (_startTradingFl) {
+ _hermitMode = 6;
+ _hermitMovingFl = false;
+ _hermitTalkingFl = false;
+ _scene->_sequences.addTimer(1, 110);
+ } else if (_hermitMovingFl) {
+ _hermitMode = 1;
+ _nextFrame = 47;
+ _hermitTalkingFl = false;
+ } else {
+ switch (_vm->getRandomNumber(1, 4)) {
+ case 1:
+ _nextFrame = 18;
+ break;
+
+ case 2:
+ _nextFrame = 20;
+ break;
+
+ case 3:
+ _nextFrame = 22;
+ break;
+
+ case 4:
+ _nextFrame = 24;
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+
+ if (_scene->_activeAnimation->getCurrentFrame() == 254)
+ _game._player._stepEnabled = true;
+
+ if (_game._trigger == 110) {
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._sequenceIndexes[3] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[3], false, 7, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[3], 1, 2);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[3]);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[3], SEQUENCE_TRIGGER_EXPIRE, 0, 111);
+ }
+
+ if (_game._trigger == 111) {
+ int syncIdx = _globals._sequenceIndexes[3];
+ _globals._sequenceIndexes[3] = _scene->_sequences.startCycle(_globals._spriteIndexes[3], false, 2);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[3]);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[3], syncIdx);
+ _nextFrame = 1;
+ }
+
+ if (_game._trigger == 112) {
+ _game._player._priorTimer = _scene->_frameStartTime - _game._player._ticksAmount;
+ _game._player._visible = true;
+ }
+
+ if (_hermitMode == 6) {
+ if ((_scene->_activeAnimation->getCurrentFrame() == 9) && _check1Fl) {
+ _scene->_sequences.remove(_globals._sequenceIndexes[3]);
+ _globals._sequenceIndexes[3] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[3], false, 7, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[3], 1, 2);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[3]);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[3], SEQUENCE_TRIGGER_EXPIRE, 0, 112);
+ _check1Fl = false;
+ }
+
+ if ((_scene->_activeAnimation->getCurrentFrame() == 17) && !_check1Fl) {
+ _nextFrame = 26;
+ _hermitMode = 4;
+ _check1Fl = true;
+ }
+ }
+
+ if (_hermitMode == 4) {
+ if ((_scene->_activeAnimation->getCurrentFrame() == 33) && _check1Fl) {
+ displayHermitQuestions(_hermitDisplayedQuestion);
+ _nextFrame = 1;
+ _check1Fl = false;
+ }
+
+ if ((_scene->_activeAnimation->getCurrentFrame() == 9) && !_check1Fl) {
+ _nextFrame = 8;
+ _scene->_sequences.addTimer(1, 113);
+ _check1Fl = true;
+ }
+ }
+
+ if (_game._trigger == 113) {
+ _game._player._visible = false;
+ _globals._sequenceIndexes[3] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[3], false, 7, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[3], 1, 2);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[3]);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[3], SEQUENCE_TRIGGER_EXPIRE, 0, 114);
+ }
+
+ if (_game._trigger == 114) {
+ _resetBatterieText = true;
+ int syncIdx = _globals._sequenceIndexes[3];
+ _nextFrame = 10;
+ _globals._sequenceIndexes[3] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[3], false, 7, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[3], 1, 2);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[3], syncIdx);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[3]);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[3], SEQUENCE_TRIGGER_EXPIRE, 0, 115);
+ }
+
+ if ((_nextFrame >= 0) && (_nextFrame != _scene->_activeAnimation->getCurrentFrame())) {
+ _scene->_activeAnimation->setCurrentFrame(_nextFrame);
+ _nextFrame = -1;
+ }
+
+ if (_game._trigger == 115) {
+ _game._player._priorTimer = _scene->_frameStartTime - _game._player._ticksAmount;
+ _game._player._visible = true;
+ if (_hermitDisplayedQuestion == 21) {
+ _game._player._stepEnabled = false;
+ handleTrading();
+ _hermitMode = 0;
+ _startTradingFl = false;
+ _nextFrame = 52;
+ _globals[kHasTalkedToHermit] = true;
+ _scene->_hotspots.activate(NOUN_HERMIT, false);
+ } else {
+ _game._player._stepEnabled = true;
+ _hermitMode = 1;
+ _nextFrame = 47;
+ _hermitTalkingFl = false;
+ _startTradingFl = false;
+ _check1Fl = true;
+ }
+ }
+}
+
+void Scene611::preActions() {
+ if (_action.isAction(VERB_WALK_DOWN, NOUN_ALLEY))
+ _game._player._walkOffScreenSceneId = 609;
+
+ if (_resetBatterieText)
+ _scene->_kernelMessages.reset();
+}
+
+void Scene611::actions() {
+ if (_game._screenObjects._inputMode == 1)
+ handleDialog();
+ else if ((_action.isAction(VERB_GIVE, NOUN_PHONE_CELLS, 0x45A)) || (_action.isAction(VERB_GIVE, NOUN_DURAFAIL_CELLS, 0x45A))) {
+ _action._activeAction._verbId = 0x294;
+ _giveBatteriesFl = true;
+ handleSubDialog1();
+ } else if (_action.isAction(VERB_GIVE, NOUN_HERMIT)) {
+ _scene->_kernelMessages.reset();
+
+ Common::String curQuote = _game.getQuote(0x323);
+ int width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
+ int quotePosX = _defaultDialogPos.x - (width / 2);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y), 0xFDFC, 0, 0, 120, curQuote);
+
+ curQuote = _game.getQuote(0x324);
+ width = _vm->_font->getWidth(curQuote, _scene->_textSpacing);
+ quotePosX = _defaultDialogPos.x - (width / 2);
+ _scene->_kernelMessages.add(Common::Point(quotePosX, _defaultDialogPos.y + 14), 0xFDFC, 0, 0, 120, curQuote);
+ } else if (_game._trigger == 90) {
+ if (_dialog2.read(0x29C) && _dialog2.read(0x29D) && _dialog2.read(0x29E)) {
+ handleTalking(180);
+ if (_vm->getRandomNumber(1, 2) == 1)
+ displayHermitQuestions(1);
+ else
+ displayHermitQuestions(2);
+ } else {
+ handleTalking(180);
+ if (_vm->getRandomNumber(1, 2) == 1)
+ displayHermitQuestions(3);
+ else
+ displayHermitQuestions(4);
+ }
+
+ _duringDialogFl = true;
+ if (_dialog2.read(0x29F)) {
+ _hermitDialogNode = 1;
+ _dialog1.start();
+ _duringDialogFl = true;
+ } else {
+ _hermitDialogNode = 2;
+ _dialog2.write(0x29F, true);
+ _dialog2.start();
+ _duringDialogFl = true;
+ }
+ } else if (_action.isAction(VERB_TALKTO, NOUN_HERMIT)) {
+ if (!_dialog1.read(0x287)) {
+ _scene->_kernelMessages.reset();
+ _scene->_kernelMessages.add(Common::Point(0, 0), 0x1110, 34, 0, 120, _game.getQuote(0x27A));
+ _scene->_sequences.addTimer(120, 90);
+ } else {
+ int nextQuote = 0;
+ switch (_vm->getRandomNumber(1, 3)) {
+ case 1:
+ nextQuote = 0x27B;
+ break;
+
+ case 2:
+ nextQuote = 0x27C;
+ break;
+
+ case 3:
+ nextQuote = 0x27D;
+ break;
+ }
+ _scene->_kernelMessages.reset();
+ _scene->_kernelMessages.add(Common::Point(0, 0), 0x1110, 34, 0, 120, _game.getQuote(nextQuote));
+ _scene->_sequences.addTimer(120, 90);
+ }
+ } else if ((_action.isAction(VERB_WALKTO) || _action.isAction(VERB_LOOK)) && _action.isAction(0x275)) {
+ switch (_game._trigger) {
+ case 0:
+ _scene->_kernelMessages.reset();
+ _scene->_kernelMessages.add(Common::Point(0, 0), 0x1110, 34, 0, 120, _game.getQuote(0x279));
+ _scene->_sequences.addTimer(60, 1);
+ break;
+
+ case 1:
+ handleRatMoves();
+ _game._player._stepEnabled = true;
+ break;
+
+ default:
+ break;
+ }
+ } else if (_action._lookFlag) {
+ if (_globals[kHasTalkedToHermit])
+ _vm->_dialogs->show(61111);
+ else
+ _vm->_dialogs->show(61110);
+ } else if (_action.isAction(VERB_LOOK, NOUN_HERMIT))
+ _vm->_dialogs->show(61112);
+ else if (_action.isAction(VERB_LOOK, NOUN_TRASH))
+ _vm->_dialogs->show(61113);
+ else if (_action.isAction(VERB_TAKE, NOUN_TRASH))
+ _vm->_dialogs->show(61114);
+ else if (_action.isAction(VERB_LOOK, NOUN_CARDBOARD_BOX))
+ _vm->_dialogs->show(61115);
+ else if (_action.isAction(VERB_TAKE, NOUN_CARDBOARD_BOX))
+ _vm->_dialogs->show(61116);
+ else if (_action.isAction(VERB_OPEN, NOUN_CARDBOARD_BOX))
+ _vm->_dialogs->show(61117);
+ else if (_action.isAction(VERB_LOOK, NOUN_REFRIGERATOR))
+ _vm->_dialogs->show(61118);
+ else if (_action.isAction(VERB_OPEN, NOUN_REFRIGERATOR))
+ _vm->_dialogs->show(61119);
+ else if (_action.isAction(VERB_TAKE, NOUN_REFRIGERATOR))
+ _vm->_dialogs->show(61120);
+ else if (_action.isAction(VERB_LOOK, NOUN_BUILDING))
+ _vm->_dialogs->show(61121);
+ else if (_action.isAction(VERB_LOOK, NOUN_GRAFFITI))
+ _vm->_dialogs->show(61122);
+ else if (_action.isAction(VERB_LOOK, NOUN_METAL_PIPE))
+ _vm->_dialogs->show(61123);
+ else
+ return;
+
+ _action._inProgress = false;
+}
+
+/*------------------------------------------------------------------------*/
+
+Scene612::Scene612(MADSEngine *vm) : Scene6xx(vm) {
+ _actionMode = -1;
+ _cycleIndex = -1;
+}
+
+void Scene612::synchronize(Common::Serializer &s) {
+ Scene6xx::synchronize(s);
+
+ s.syncAsSint16LE(_actionMode);
+ s.syncAsSint16LE(_cycleIndex);
+}
+
+void Scene612::setup() {
+ setPlayerSpritesPrefix();
+ setAAName();
+ _scene->addActiveVocab(NOUN_FISHING_LINE);
+ _scene->addActiveVocab(VERB_WALKTO);
+}
+
+void Scene612::handleWinchMovement() {
+ switch (_game._trigger) {
+ case 0:
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._sequenceIndexes[4] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[4], false, 10, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[4], 1, 5);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[4]);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[4], SEQUENCE_TRIGGER_SPRITE, 5, 1);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[4], SEQUENCE_TRIGGER_EXPIRE, 0, 2);
+ break;
+
+ case 1:
+ // CHECKME: Is the "else" block useful as action is always equal to 1 at this point?
+ // Or is it a missing bit of code we could fix?
+ if (_actionMode == 1) {
+ _scene->_sequences.remove(_globals._sequenceIndexes[2]);
+ _globals._sequenceIndexes[2] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[2], false, 17, 7, 0, 0);
+ _vm->_sound->command(19);
+ _game._objects.setRoom(OBJ_PADLOCK_KEY, 1);
+ _globals[kBoatRaised] = false;
+ } else {
+ _scene->_sequences.remove(_globals._sequenceIndexes[2]);
+ _globals._sequenceIndexes[2] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[2], false, 17, 9, 0, 0);
+ _vm->_sound->command(18);
+ }
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 1);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[2], SEQUENCE_TRIGGER_EXPIRE, 0, 3);
+ break;
+
+ case 2:
+ _scene->_sequences.updateTimeout(-1, _globals._sequenceIndexes[4]);
+ _game._player._visible = true;
+ break;
+
+ case 3: {
+ int syncIdx = _globals._sequenceIndexes[2];
+ _globals._sequenceIndexes[2] = _scene->_sequences.startCycle(_globals._spriteIndexes[2], false, _cycleIndex);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 1);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[2], syncIdx);
+ _scene->_kernelMessages.reset();
+ _scene->_kernelMessages.add(Common::Point(0, 0), 0x1110, 34, 0, 120, _game.getQuote(0x2F4));
+ _game._player._stepEnabled = true;
+
+ _vm->_dialogs->show(61217);
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+void Scene612::enter() {
+ _globals._spriteIndexes[1] = _scene->_sprites.addSprites(formAnimName('c', -1));
+ _globals._spriteIndexes[2] = _scene->_sprites.addSprites(formAnimName('p', -1));
+ _globals._spriteIndexes[3] = _scene->_sprites.addSprites("*RXCD_3");
+ _globals._spriteIndexes[4] = _scene->_sprites.addSprites("*RXRC_6");
+
+ if ((_globals[kLineStatus] == 2) || (_globals[kLineStatus] == 3)) {
+ _globals._spriteIndexes[5] = _scene->_sprites.addSprites(formAnimName('f', -1));
+ _globals._sequenceIndexes[5] = _scene->_sequences.startCycle(_globals._spriteIndexes[5], false, -1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[5], 1);
+ int idx = _scene->_dynamicHotspots.add(NOUN_FISHING_LINE, VERB_WALKTO, _globals._sequenceIndexes[5], Common::Rect(0, 0, 0, 0));
+ _scene->_dynamicHotspots.setPosition(idx, Common::Point(34, 117), FACING_SOUTHEAST);
+ }
+
+ if (_globals[kBoatRaised])
+ _cycleIndex = -2;
+ else
+ _cycleIndex = -1;
+
+ _globals._sequenceIndexes[2] = _scene->_sequences.startCycle(_globals._spriteIndexes[2], false, _cycleIndex);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 1);
+
+ if (_scene->_priorSceneId != -2) {
+ _game._player._playerPos = Common::Point(280, 75);
+ _game._player._facing = FACING_SOUTHWEST;
+ _game._player._visible = false;
+ _game._player._stepEnabled = false;
+ _globals._sequenceIndexes[1] = _scene->_sequences.startCycle(_globals._spriteIndexes[1], false, -1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 3);
+ _scene->loadAnimation(formAnimName('R', 1), 70);
+ }
+
+ sceneEntrySound();
+
+ if (_scene->_roomChanged)
+ _game._objects.addToInventory(OBJ_PADLOCK_KEY);
+
+ _game.loadQuoteSet(0x2F5, 0x2F4, 0);
+}
+
+void Scene612::step() {
+ switch (_game._trigger) {
+ case 70:
+ _game._player._visible = true;
+ _game._player._priorTimer = _scene->_activeAnimation->getNextFrameTimer() - _game._player._ticksAmount;
+ _scene->_sequences.addTimer(6, 71);
+ break;
+
+ case 71:
+ _scene->_sequences.remove(_globals._sequenceIndexes[1]);
+ _globals._sequenceIndexes[1] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[1], false, 6, 1, 0, 0);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 2);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[1], SEQUENCE_TRIGGER_EXPIRE, 0, 72);
+ break;
+
+ case 72:
+ _globals._sequenceIndexes[1] = _scene->_sequences.startCycle(_globals._spriteIndexes[1], false, -2);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 2);
+ _game._player._stepEnabled = true;
+ break;
+
+ default:
+ break;
+ }
+}
+
+void Scene612::actions() {
+ if (_action.isAction(0x325, 0x324)) {
+ switch (_game._trigger) {
+ case 0:
+ _game._player._stepEnabled = false;
+ _scene->_sequences.remove(_globals._sequenceIndexes[1]);
+ _globals._sequenceIndexes[1] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[1], false, 6, 1, 0, 0);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 2);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[1], SEQUENCE_TRIGGER_EXPIRE, 0, 1);
+ break;
+
+ case 1: {
+ int syncIdx = _globals._sequenceIndexes[1];
+ _globals._sequenceIndexes[1] = _scene->_sequences.startCycle(_globals._spriteIndexes[1], false, -1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 3);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[1], syncIdx);
+ _scene->_sequences.addTimer(6, 2);
+ }
+ break;
+
+ case 2:
+ _game._player._visible = false;
+ _globals._sequenceIndexes[3] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[3], true, 10, 1, 0, 0);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[3]);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[3], SEQUENCE_TRIGGER_EXPIRE, 0, 3);
+ break;
+
+ case 3: {
+ int syncIdx = _globals._sequenceIndexes[3];
+ _globals._sequenceIndexes[3] = _scene->_sequences.startCycle(_globals._spriteIndexes[3], true, -2);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[3]);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[3], syncIdx);
+ _scene->_nextSceneId = 504;
+ }
+ break;
+
+ default:
+ break;
+ }
+ } else if (_action.isAction(VERB_UNLOCK, 0xFF, 0x45F)) {
+ _cycleIndex = -2;
+ _actionMode = 1;
+ handleWinchMovement();
+ } else if (_action._lookFlag || _action.isAction(VERB_LOOK, NOUN_EXPRESSWAY))
+ _vm->_dialogs->show(61210);
+ else if (_action.isAction(VERB_LOOK, NOUN_ROPE) || _action.isAction(VERB_LOOK, NOUN_ARMATURE)) {
+ if (_globals[kBoatRaised])
+ _vm->_dialogs->show(61211);
+ else
+ _vm->_dialogs->show(61212);
+ } else if (_action.isAction(VERB_TAKE, NOUN_ROPE))
+ _vm->_dialogs->show(61213);
+ else if (_action.isAction(VERB_LOOK, NOUN_CONTROL_BOX)) {
+ if (_globals[kBoatRaised])
+ _vm->_dialogs->show(61214);
+ else
+ _vm->_dialogs->show(61216);
+ } else if (_action.isAction(VERB_OPEN, NOUN_CONTROL_BOX))
+ _vm->_dialogs->show(61215);
+ else if (_action.isAction(VERB_LOOK, NOUN_BUILDINGS))
+ _vm->_dialogs->show(61218);
+ else if (_action.isAction(VERB_LOOK, NOUN_DOME))
+ _vm->_dialogs->show(61219);
+ else if (_action.isAction(VERB_LOOK, NOUN_STATUE))
+ _vm->_dialogs->show(61220);
+ else if (_action.isAction(VERB_LOOK, NOUN_MAINTENANCE_BUILDING))
+ _vm->_dialogs->show(61221);
+ else if (_action.isAction(VERB_OPEN, NOUN_MAINTENANCE_BUILDING))
+ _vm->_dialogs->show(61222);
+ else if (_action.isAction(VERB_LOOK, NOUN_WALL))
+ _vm->_dialogs->show(61223);
+ else if (_action.isAction(VERB_LOOK, NOUN_SUPPORT))
+ _vm->_dialogs->show(61224);
+ else if (_action.isAction(VERB_WALK_DOWN, NOUN_EXPRESSWAY_TO_EAST) || _action.isAction(VERB_WALK_DOWN, NOUN_EXPRESSWAY_TO_WEST))
+ _vm->_dialogs->show(61225);
+ else
+ return;
+
+ _action._inProgress = false;
+}
+
+/*------------------------------------------------------------------------*/
+
+void Scene620::setup() {
+ _game._player._spritesPrefix = "";
+ setAAName();
+}
+
+void Scene620::enter() {
+ _globals._spriteIndexes[1] = _scene->_sprites.addSprites(formAnimName('b', 0));
+ _globals._sequenceIndexes[1] = _scene->_sequences.startCycle(_globals._spriteIndexes[1], false, -1);
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _scene->_sequences.addTimer(30, 70);
+ _scene->_userInterface.setup(kInputLimitedSentences);
+ sceneEntrySound();
+}
+
+void Scene620::step() {
+ switch (_game._trigger) {
+ case 70:
+ _scene->_sequences.remove(_globals._sequenceIndexes[1]);
+ _scene->loadAnimation(formAnimName('E', -1), 71);
+ break;
+
+ case 71:
+ if (_scene->_priorSceneId == 751) {
+ _globals[kCityFlooded] = true;
+ _globals[kTeleporterRoom + 5] = 0;
+ _scene->_nextSceneId = 701;
+ } else if (_scene->_priorSceneId == 752) {
+ _globals[kCityFlooded] = true;
+ _globals[kTeleporterRoom + 5] = 0;
+ _scene->_nextSceneId = 702;
+ } else if (_scene->_priorSceneId < 501 || _scene->_priorSceneId > 752) {
+ _globals[kCityFlooded] = true;
+ _globals[kTeleporterRoom + 5] = 0;
+ _scene->_nextSceneId = _scene->_priorSceneId;
+ } else if (_scene->_priorSceneId >= 501 && _scene->_priorSceneId <= 612) {
+ _globals[kResurrectRoom] = _globals[kHoverCarLocation];
+ _game._objects.addToInventory(OBJ_TIMEBOMB);
+ _globals[kTimebombStatus] = 0;
+ _globals[kTimebombTimer] = 0;
+ _scene->_nextSceneId = 605;
+ }
+ _game._player._stepEnabled = true;
+ break;
+
+ default:
+ break;
+ }
+}
+
+/*------------------------------------------------------------------------*/
+
+} // End of namespace Nebular
+} // End of namespace MADS
diff --git a/engines/mads/nebular/nebular_scenes6.h b/engines/mads/nebular/nebular_scenes6.h
new file mode 100644
index 0000000000..74467858bd
--- /dev/null
+++ b/engines/mads/nebular/nebular_scenes6.h
@@ -0,0 +1,322 @@
+/* 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.
+ *
+ */
+
+#ifndef MADS_NEBULAR_SCENES6_H
+#define MADS_NEBULAR_SCENES6_H
+
+#include "common/scummsys.h"
+#include "mads/game.h"
+#include "mads/scene.h"
+#include "mads/nebular/nebular_scenes.h"
+
+namespace MADS {
+
+namespace Nebular {
+
+class Scene6xx : public NebularScene {
+protected:
+ /**
+ * Plays an appropriate sound when entering a scene
+ */
+ void setAAName();
+
+ /**
+ * Updates the prefix used for getting player sprites for the scene
+ */
+ void setPlayerSpritesPrefix();
+
+ void sceneEntrySound();
+
+public:
+ Scene6xx(MADSEngine *vm) : NebularScene(vm) {}
+};
+
+class Scene601: public Scene6xx{
+public:
+ Scene601(MADSEngine *vm) : Scene6xx(vm) {}
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+ virtual void actions();
+};
+
+class Scene602: public Scene6xx{
+private:
+ int _lastSpriteIdx;
+ int _lastSequenceIdx;
+ int _cycleIndex;
+ int _safeMode;
+
+ void handleSafeActions();
+
+public:
+ Scene602(MADSEngine *vm);
+ void synchronize(Common::Serializer &s);
+
+ virtual void setup();
+ virtual void enter();
+ virtual void actions();
+};
+
+class Scene603: public Scene6xx{
+private:
+ int _compactCaseHotspotId;
+ int _noteHotspotId;
+
+public:
+ Scene603(MADSEngine *vm);
+ void synchronize(Common::Serializer &s);
+
+ virtual void setup();
+ virtual void enter();
+ virtual void actions();
+};
+
+class Scene604: public Scene6xx{
+private:
+ int _timebombHotspotId;
+ int _bombMode;
+ int _monsterFrame;
+
+ uint32 _monsterTimer;
+
+ bool _monsterActive;
+ bool _animationActiveFl;
+
+ void handleBombActions();
+
+public:
+ Scene604(MADSEngine *vm);
+ void synchronize(Common::Serializer &s);
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+ virtual void actions();
+};
+
+class Scene605: public Scene6xx{
+public:
+ Scene605(MADSEngine *vm) : Scene6xx(vm) {}
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+ virtual void actions();
+};
+
+class Scene607: public Scene6xx{
+private:
+ uint32 _dogTimer;
+ uint32 _lastFrameTime;
+
+ bool _dogLoop;
+ bool _dogEatsRex;
+ bool _dogBarking;
+ bool _shopAvailable;
+
+ int _animationMode;
+ int _animationActive;
+ int _counter;
+
+ void handleThrowingBone();
+
+public:
+ Scene607(MADSEngine *vm);
+ void synchronize(Common::Serializer &s);
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+ virtual void preActions();
+ virtual void actions();
+};
+
+class Scene608: public Scene6xx{
+private:
+ int _carMode;
+ int _carFrame;
+ int _carMoveMode;
+ int _dogDeathMode;
+ int _carHotspotId;
+ int _barkCount;
+ int _polycementHotspotId;
+ int _animationMode;
+ int _nextTrigger;
+ int _throwMode;
+
+ bool _resetPositionsFl;
+ bool _dogActiveFl;
+ bool _dogBarkingFl;
+ bool _dogFirstEncounter;
+ bool _rexBeingEaten;
+ bool _dogHitWindow;
+ bool _checkFl;
+ bool _dogSquashFl;
+ bool _dogSafeFl;
+ bool _buttonPressedonTimeFl;
+ bool _dogUnderCar;
+ bool _dogYelping;
+
+ long _dogWindowTimer;
+ long _dogRunTimer;
+
+ uint32 _dogTimer1;
+ uint32 _dogTimer2;
+
+ void resetDogVariables();
+ void restoreAnimations();
+ void setCarAnimations();
+ void handleThrowingBone();
+
+public:
+ Scene608(MADSEngine *vm);
+ void synchronize(Common::Serializer &s);
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+ virtual void preActions();
+ virtual void actions();
+};
+
+class Scene609: public Scene6xx{
+private:
+ int _videoDoorMode;
+
+ void enterStore();
+
+public:
+ Scene609(MADSEngine *vm);
+ void synchronize(Common::Serializer &s);
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+ virtual void preActions();
+ virtual void actions();
+};
+
+class Scene610: public Scene6xx{
+private:
+ int _handsetHotspotId;
+ int _checkVal;
+
+ bool _cellCharging;
+
+ long _cellChargingTimer;
+ uint32 _lastFrameTimer;
+
+public:
+ Scene610(MADSEngine *vm);
+ void synchronize(Common::Serializer &s);
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+ virtual void actions();
+};
+
+class Scene611: public Scene6xx{
+private:
+ bool _seenRatFl;
+ bool _eyesRunningFl;
+ bool _shouldRemoveEyes;
+ bool _ratPresentFl;
+ bool _duringDialogFl;
+ bool _resetBatterieText;
+ bool _hermitTalkingFl;
+ bool _hermitMovingFl;
+ bool _alreadyTalkingFl;
+ bool _giveBatteriesFl;
+ bool _startTradingFl;
+ bool _check1Fl;
+ bool _stickFingerFl;
+
+ int _randVal;
+ int _ratHotspotId;
+ int _hermitDialogNode;
+ int _hermitDisplayedQuestion;
+ int _nextFrame;
+ int _hermitMode;
+
+ uint32 _ratTimer;
+
+ Conversation _dialog1;
+ Conversation _dialog2;
+
+ Common::Point _defaultDialogPos;
+
+ void handleTrading();
+ void handleRatMoves();
+ void handleDialog();
+ void handleSubDialog1();
+ void handleSubDialog2();
+ void handleTalking(int delay);
+ void setDialogNode(int node);
+ void displayHermitQuestions(int question);
+
+ bool check2ChargedBatteries();
+ bool check4ChargedBatteries();
+
+public:
+ Scene611(MADSEngine *vm);
+ void synchronize(Common::Serializer &s);
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+ virtual void preActions();
+ virtual void actions();
+};
+
+class Scene612: public Scene6xx{
+private:
+ int _actionMode;
+ int _cycleIndex;
+
+ void handleWinchMovement();
+
+public:
+ Scene612(MADSEngine *vm);
+ void synchronize(Common::Serializer &s);
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+ virtual void actions();
+};
+
+class Scene620: public Scene6xx{
+public:
+ Scene620(MADSEngine *vm) : Scene6xx(vm) {}
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+ virtual void actions() {};
+};
+} // End of namespace Nebular
+} // End of namespace MADS
+
+#endif /* MADS_NEBULAR_SCENES6_H */
diff --git a/engines/mads/nebular/nebular_scenes7.cpp b/engines/mads/nebular/nebular_scenes7.cpp
new file mode 100644
index 0000000000..08b85bfbd4
--- /dev/null
+++ b/engines/mads/nebular/nebular_scenes7.cpp
@@ -0,0 +1,2678 @@
+/* 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 "mads/mads.h"
+#include "mads/scene.h"
+#include "mads/nebular/nebular_scenes.h"
+#include "mads/nebular/nebular_scenes7.h"
+
+namespace MADS {
+
+namespace Nebular {
+
+void Scene7xx::setAAName() {
+ _game._aaName = Resources::formatAAName(5);
+}
+
+void Scene7xx::setPlayerSpritesPrefix() {
+ _vm->_sound->command(5);
+
+ Common::String oldName = _game._player._spritesPrefix;
+
+ if ((_scene->_nextSceneId == 703) || (_scene->_nextSceneId == 704) || (_scene->_nextSceneId == 705)
+ || (_scene->_nextSceneId == 707) || (_scene->_nextSceneId == 710) || (_scene->_nextSceneId == 711))
+ _game._player._spritesPrefix = "";
+ else if (_globals[kSexOfRex] == REX_MALE)
+ _game._player._spritesPrefix = "RXM";
+ else
+ _game._player._spritesPrefix = "ROX";
+
+ _game._player._scalingVelocity = true;
+
+ if (oldName != _game._player._spritesPrefix)
+ _game._player._spritesChanged = true;
+
+ _vm->_palette->setEntry(16, 10, 63, 63);
+ _vm->_palette->setEntry(17, 10, 45, 45);
+}
+
+void Scene7xx::sceneEntrySound() {
+ if (!_vm->_musicFlag) {
+ _vm->_sound->command(2);
+ return;
+ }
+
+ switch (_scene->_nextSceneId) {
+ case 701:
+ case 702:
+ case 704:
+ case 705:
+ case 751:
+ _vm->_sound->command(38);
+ break;
+ case 703:
+ if (_globals[kMonsterAlive] == 0)
+ _vm->_sound->command(24);
+ else
+ _vm->_sound->command(27);
+ break;
+ case 706:
+ case 707:
+ case 710:
+ case 711:
+ _vm->_sound->command(25);
+ break;
+ default:
+ break;
+ }
+}
+
+/*------------------------------------------------------------------------*/
+
+Scene701::Scene701(MADSEngine *vm) : Scene7xx(vm) {
+ _fishingLineId = -1;
+}
+
+void Scene701::synchronize(Common::Serializer &s) {
+ Scene7xx::synchronize(s);
+
+ s.syncAsSint16LE(_fishingLineId);
+}
+
+void Scene701::setup() {
+ setPlayerSpritesPrefix();
+ setAAName();
+
+ _scene->addActiveVocab(NOUN_BOAT);
+ _scene->addActiveVocab(VERB_CLIMB_INTO);
+ _scene->addActiveVocab(NOUN_FISHING_LINE);
+ _scene->addActiveVocab(VERB_WALKTO);
+}
+
+void Scene701::enter() {
+ _globals._spriteIndexes[1] = _scene->_sprites.addSprites(formAnimName('x', 0));
+ _globals._spriteIndexes[2] = _scene->_sprites.addSprites(formAnimName('b', 5));
+ _globals._spriteIndexes[4] = _scene->_sprites.addSprites(formAnimName('b', 0));
+ _globals._spriteIndexes[3] = _scene->_sprites.addSprites(formAnimName('b', 1));
+ _globals._spriteIndexes[5] = _scene->_sprites.addSprites("*RM202A1");
+ _globals._spriteIndexes[6] = _scene->_sprites.addSprites(formAnimName('b', 8));
+
+ if (_scene->_roomChanged) {
+ _game._objects.addToInventory(OBJ_BINOCULARS);
+ _game._objects.addToInventory(OBJ_TWINKIFRUIT);
+ _game._objects.addToInventory(OBJ_BOMB);
+ _game._objects.addToInventory(OBJ_CHICKEN);
+ _game._objects.addToInventory(OBJ_BONES);
+
+ _globals[kCityFlooded] = true;
+ _globals[kLineStatus] = LINE_TIED;
+ _globals[kBoatRaised] = false;
+ }
+
+ if (_globals[kBoatStatus] == BOAT_UNFLOODED) {
+ if (_globals[kBoatRaised])
+ _globals[kBoatStatus] = BOAT_GONE;
+ else if (_globals[kLineStatus] == LINE_TIED)
+ _globals[kBoatStatus] = BOAT_TIED_FLOATING;
+ else if (_game._difficulty == DIFFICULTY_HARD)
+ _globals[kBoatStatus] = BOAT_ADRIFT;
+ else
+ _globals[kBoatStatus] = BOAT_TIED;
+ }
+
+ _globals._sequenceIndexes[1] = _scene->_sequences.startCycle(_globals._spriteIndexes[1], false, 1);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[1], Common::Point(48, 136));
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 10);
+
+ int boatStatus = (_scene->_priorSceneId == 703) ? BOAT_GONE : _globals[kBoatStatus];
+
+ switch (boatStatus) {
+ case BOAT_TIED_FLOATING:
+ _globals._sequenceIndexes[4] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[4], false, 20, 0, 0, 0);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[4], 10);
+ break;
+ case BOAT_ADRIFT:
+ _globals._sequenceIndexes[6] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[6], false, 20, 0, 0, 0);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[6], 10);
+ break;
+ case BOAT_TIED:
+ _globals._sequenceIndexes[2] = _scene->_sequences.startCycle(_globals._spriteIndexes[2], false, -1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 9);
+ break;
+ case BOAT_GONE:
+ _scene->_hotspots.activate(NOUN_BOAT, false);
+ break;
+ default:
+ break;
+ }
+
+ if (_globals[kLineStatus] == LINE_DROPPED || _globals[kLineStatus] == LINE_TIED) {
+ _globals._sequenceIndexes[3] = _scene->_sequences.startCycle(_globals._spriteIndexes[3], false, -1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 8);
+ int idx = _scene->_dynamicHotspots.add(NOUN_FISHING_LINE, VERB_WALKTO, _globals._sequenceIndexes[3], Common::Rect(0, 0, 0, 0));
+ _fishingLineId = _scene->_dynamicHotspots.setPosition(idx, Common::Point(234, 129), FACING_NORTHEAST);
+ }
+
+ if (_scene->_priorSceneId == 702) {
+ _game._player._playerPos = Common::Point(309, 138);
+ _game._player._facing = FACING_WEST;
+ } else if (_scene->_priorSceneId == 710) {
+ _game._player._playerPos = Common::Point(154, 129);
+ _game._player._facing = FACING_NORTH;
+ _game._player._visible = false;
+ _game._player._stepEnabled = false;
+ _globals._sequenceIndexes[5] = _scene->_sequences.startCycle(_globals._spriteIndexes[5], false, 1);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[5], Common::Point(155, 129));
+ _scene->_sequences.addTimer(15, 60);
+ } else if (_scene->_priorSceneId == 703) {
+ _game._player._playerPos = Common::Point(231, 127);
+ _game._player._facing = FACING_SOUTH;
+ _game._player._visible = false;
+ _game._player._stepEnabled = false;
+ _scene->loadAnimation(formAnimName('B', 1), 80);
+ _vm->_sound->command(28);
+ } else if (_scene->_priorSceneId != -2 && _scene->_priorSceneId != 620) {
+ _game._player._playerPos = Common::Point(22, 131);
+ _game._player._facing = FACING_EAST;
+ _game._player._stepEnabled = false;
+ _scene->_sequences.addTimer(60, 70);
+ }
+
+ _game.loadQuoteSet(0x310, 0x30F, 0);
+ sceneEntrySound();
+}
+
+void Scene701::step() {
+ switch(_game._trigger) {
+ case 60:
+ _scene->_sequences.remove(_globals._sequenceIndexes[5]);
+ _globals._sequenceIndexes[5] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[5], false, 6, 1, 0, 0);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[5], Common::Point(155, 129));
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[5], SEQUENCE_TRIGGER_EXPIRE, 0, 61);
+ break;
+
+ case 61:
+ _scene->_sequences.updateTimeout(-1, _globals._sequenceIndexes[5]);
+ _game._player._visible = true;
+ _game._player._stepEnabled = true;
+ break;
+
+ case 70:
+ _vm->_sound->command(16);
+ _scene->_sequences.remove(_globals._sequenceIndexes[1]);
+ _globals._sequenceIndexes[1] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[1], false, 5, 1, 0, 0);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[1], Common::Point(48, 136));
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 10);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[1], SEQUENCE_TRIGGER_EXPIRE, 0, 71);
+ break;
+
+ case 71:
+ _game._player.walk(Common::Point(61, 131), FACING_EAST);
+ _scene->_sequences.addTimer(120, 72);
+ break;
+
+ case 72:
+ _vm->_sound->command(17);
+ _globals._sequenceIndexes[1] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[1], false, 5, 1, 0, 0);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[1], Common::Point(48, 136));
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 10);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[1], SEQUENCE_TRIGGER_EXPIRE, 0, 73);
+ break;
+
+ case 73:
+ _game._player._stepEnabled = true;
+ _globals._sequenceIndexes[1] = _scene->_sequences.startCycle(_globals._spriteIndexes[1], false, -1);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[1], Common::Point(48, 136));
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 10);
+ _scene->_kernelMessages.reset();
+ break;
+
+ case 80: {
+ _game._player._visible = true;
+ _game._player._priorTimer = _scene->_frameStartTime - _game._player._ticksAmount;
+ _globals._sequenceIndexes[2] = _scene->_sequences.startCycle(_globals._spriteIndexes[2], false, -1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 9);
+ int idx = _scene->_dynamicHotspots.add(NOUN_BOAT, VERB_CLIMB_INTO, _globals._sequenceIndexes[2], Common::Rect(0, 0, 0, 0));
+ _scene->_dynamicHotspots.setPosition(idx, Common::Point(234, 129), FACING_NORTH);
+ _globals[kBoatStatus] = BOAT_TIED;
+ _game._player._stepEnabled = true;
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+void Scene701::preActions() {
+ if (_action.isAction(VERB_WALKTO, NOUN_EAST_END_OF_PLATFORM))
+ _game._player._walkOffScreenSceneId = 702;
+
+ if (_action.isAction(VERB_LOOK, NOUN_BUILDING))
+ _game._player.walk(Common::Point(154, 129), FACING_NORTHEAST);
+
+ if (_action.isAction(VERB_LOOK, NOUN_BINOCULARS, NOUN_BUILDING))
+ _game._player.walk(Common::Point(154, 129), FACING_NORTH);
+}
+
+void Scene701::actions() {
+ if (_action.isAction(VERB_WALK_ALONG, NOUN_PLATFORM))
+ return;
+
+ if (_action.isAction(VERB_LOOK, NOUN_BINOCULARS, NOUN_BUILDING) && _game._objects[OBJ_VASE]._roomNumber == 706) {
+ switch (_game._trigger) {
+ case 0:
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._sequenceIndexes[5] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[5], false, 6, 1, 0, 0);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[5], Common::Point(155, 129));
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[5], SEQUENCE_TRIGGER_EXPIRE, 0, 1);
+ break;
+
+ case 1: {
+ int temp = _globals._sequenceIndexes[5];
+ _globals._sequenceIndexes[5] = _scene->_sequences.startCycle(_globals._spriteIndexes[5], false, -2);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[5], Common::Point(155, 129));
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[5], temp);
+ _scene->_sequences.addTimer(15, 2);
+ }
+ break;
+
+ case 2:
+ _scene->_nextSceneId = 710;
+ break;
+
+ default:
+ break;
+ }
+ } else if (_action.isAction(VERB_STEP_INTO, NOUN_ELEVATOR)) {
+ switch (_game._trigger) {
+ case 0:
+ _game._player._stepEnabled = false;
+ _scene->_sequences.remove(_globals._sequenceIndexes[1]);
+ _vm->_sound->command(16);
+ _globals._sequenceIndexes[1] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[1], false, 5, 1, 0, 0);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[1], Common::Point(48, 136));
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 10);
+ _scene->_kernelMessages.reset();
+ _scene->_kernelMessages.add(Common::Point(0, 0), 0x310, 34, 0, 120, _game.getQuote(0x30D));
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[1], SEQUENCE_TRIGGER_EXPIRE, 0, 1);
+ break;
+
+ case 1:
+ _game._player.walk(Common::Point(22, 131), FACING_EAST);
+ _scene->_sequences.addTimer(120, 3);
+ break;
+
+ case 3:
+ _vm->_sound->command(17);
+ _globals._sequenceIndexes[1] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[1], false, 5, 1, 0, 0);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[1], Common::Point(48, 136));
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 10);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[1], SEQUENCE_TRIGGER_EXPIRE, 0, 4);
+ break;
+
+ case 4:
+ _globals._sequenceIndexes[1] = _scene->_sequences.startCycle(_globals._spriteIndexes[1], false, -1);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[1], Common::Point(48, 136));
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 10);
+ _globals[kResurrectRoom] = 701;
+ _scene->_nextSceneId = 605;
+ break;
+
+ default:
+ break;
+ }
+ } else if ((_action.isAction(VERB_PULL, NOUN_BOAT) || _action.isAction(VERB_TAKE, NOUN_BOAT) ||
+ _action.isAction(VERB_PULL, NOUN_FISHING_LINE) || _action.isAction(VERB_TAKE, NOUN_FISHING_LINE)) &&
+ !_game._objects.isInInventory(OBJ_FISHING_LINE)) {
+ if (_globals[kBoatStatus] == BOAT_TIED_FLOATING) {
+ switch (_game._trigger) {
+ case 0:
+ _game._player._stepEnabled = false;
+ _scene->_sequences.remove(_globals._sequenceIndexes[4]);
+ _scene->_sequences.remove(_globals._sequenceIndexes[3]);
+ _scene->_dynamicHotspots.remove(_fishingLineId);
+ _scene->_hotspots.activate(NOUN_BOAT, false);
+ _game._player._visible = false;
+ _scene->loadAnimation(formAnimName('E', -1), 1);
+ break;
+
+ case 1: {
+ _game._player._visible = true;
+ _game._player._priorTimer = _scene->_activeAnimation->getNextFrameTimer() - _game._player._ticksAmount;
+ _globals._sequenceIndexes[2] = _scene->_sequences.startCycle(_globals._spriteIndexes[2], false, -1);
+ _scene->_sequences.setDepth (_globals._sequenceIndexes[2], 9);
+ int idx = _scene->_dynamicHotspots.add(NOUN_BOAT, VERB_CLIMB_INTO, _globals._sequenceIndexes[2], Common::Rect(0, 0, 0, 0));
+ _scene->_dynamicHotspots.setPosition(idx, Common::Point(231, 127), FACING_NORTH);
+ _scene->_sequences.addTimer(15, 2);
+ }
+ break;
+
+ case 2:
+ _globals[kBoatStatus] = BOAT_TIED;
+ _globals[kLineStatus] = LINE_NOW_UNTIED;
+ _game._player._stepEnabled = true;
+ break;
+
+ default:
+ break;
+ }
+ } else if (_globals[kBoatStatus] == BOAT_TIED) {
+ _vm->_dialogs->show(70125);
+ } else if (_globals[kLineStatus] == LINE_DROPPED) {
+ _globals[kLineStatus] = LINE_NOW_UNTIED;
+ _game._objects.addToInventory(OBJ_FISHING_LINE);
+ _vm->_sound->command(15);
+ _scene->_sequences.remove(_globals._sequenceIndexes[3]);
+ _vm->_dialogs->showItem(OBJ_FISHING_LINE, 70126);
+ } else {
+ _vm->_dialogs->show(70127);
+ }
+ } else if (_action.isAction(VERB_CLIMB_INTO, NOUN_BOAT) && _globals[kBoatStatus] == BOAT_TIED) {
+ switch (_game._trigger) {
+ case 0:
+ _game._player._stepEnabled = false;
+ _scene->_sequences.remove(_globals._sequenceIndexes[2]);
+ _game._player._visible = false;
+ _scene->loadAnimation(formAnimName('B', 0), 1);
+ break;
+
+ case 1:
+ _scene->_nextSceneId = 703;
+ break;
+
+ default:
+ break;
+ }
+ } else if (_action._lookFlag) {
+ if (_globals[kBoatStatus] != BOAT_GONE) {
+ if (_globals[kBoatStatus] == BOAT_TIED)
+ _vm->_dialogs->show(70128);
+ else
+ _vm->_dialogs->show(70110);
+ } else
+ _vm->_dialogs->show(70111);
+ } else if (_action.isAction(VERB_LOOK, NOUN_SUBMERGED_CITY))
+ _vm->_dialogs->show(70112);
+ else if (_action.isAction(VERB_LOOK, 0))
+ _vm->_dialogs->show(70113);
+ else if (_action.isAction(VERB_LOOK, NOUN_PLATFORM))
+ _vm->_dialogs->show(70114);
+ else if (_action.isAction(VERB_LOOK, NOUN_CEMENT_PYLON))
+ _vm->_dialogs->show(70115);
+ else if (_action.isAction(VERB_LOOK, NOUN_HOOK)) {
+ if (_globals[kLineStatus] == LINE_NOT_DROPPED || _globals[kLineStatus] == LINE_NOW_UNTIED)
+ _vm->_dialogs->show(70116);
+ else
+ _vm->_dialogs->show(70117);
+ } else if (_action.isAction(VERB_LOOK, NOUN_ROCK))
+ _vm->_dialogs->show(70118);
+ else if (_action.isAction(VERB_TAKE, NOUN_ROCK))
+ _vm->_dialogs->show(70119);
+ else if (_action.isAction(VERB_LOOK, NOUN_EAST_END_OF_PLATFORM))
+ _vm->_dialogs->show(70120);
+ else if (_action.isAction(VERB_LOOK, NOUN_BUILDING))
+ _vm->_dialogs->show(70121);
+ else if (_action.isAction(VERB_LOOK, NOUN_BOAT)) {
+ if (_globals[kBoatStatus] == BOAT_ADRIFT || _globals[kBoatStatus] == BOAT_TIED_FLOATING)
+ _vm->_dialogs->show(70122);
+ else
+ _vm->_dialogs->show(70123);
+ } else if (_action.isAction(VERB_CAST, NOUN_FISHING_ROD, NOUN_BOAT) && _game._objects.isInInventory(OBJ_FISHING_LINE))
+ _vm->_dialogs->show(70124);
+ else
+ return;
+
+ _action._inProgress = false;
+}
+
+/*------------------------------------------------------------------------*/
+
+void Scene702::setup() {
+ setPlayerSpritesPrefix();
+ setAAName();
+}
+
+void Scene702::enter() {
+ _globals._spriteIndexes[12] = _scene->_sprites.addSprites("*RXMBD_8");
+
+ if (_scene->_priorSceneId == 701) {
+ _game._player._playerPos = Common::Point(13, 145);
+ _game._player._facing = FACING_EAST;
+ } else if (_scene->_priorSceneId != -2 && _scene->_priorSceneId != 620) {
+ _game._player._playerPos = Common::Point(289, 138);
+ _game._player.walk(Common::Point(262, 148), FACING_WEST);
+ _game._player._facing = FACING_WEST;
+ _game._player._visible = true;
+ }
+
+ if (_game._globals[kTeleporterCommand]) {
+ switch(_game._globals[kTeleporterCommand]) {
+ case TELEPORTER_BEAM_OUT:
+ case TELEPORTER_WRONG:
+ case TELEPORTER_STEP_OUT:
+ _game._player._visible = true;
+ _game._player._stepEnabled = true;
+ break;
+ default:
+ break;
+ }
+
+ _game._globals[kTeleporterCommand] = TELEPORTER_NONE;
+ }
+
+ sceneEntrySound();
+}
+
+void Scene702::preActions() {
+ if (_action.isAction(VERB_WALKTO, NOUN_WEST_END_OF_PLATFORM))
+ _game._player._walkOffScreenSceneId = 701;
+}
+
+void Scene702::actions() {
+ if (_action.isAction(VERB_WALK_ALONG, NOUN_PLATFORM))
+ ; // Only set the action as finished
+ else if (_action.isAction(VERB_STEP_INTO, NOUN_TELEPORTER)) {
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _scene->_nextSceneId = 711;
+ } else if (_action.isAction(VERB_TAKE, NOUN_BONES) && (_action._mainObjectSource == 4) && (!_game._objects.isInInventory(OBJ_BONES) || _game._trigger)) {
+ switch (_game._trigger) {
+ case 0:
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._sequenceIndexes[12] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[12], false, 5, 2, 0, 0);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[12]);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[12], SEQUENCE_TRIGGER_SPRITE, 4, 1);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[12], SEQUENCE_TRIGGER_EXPIRE, 0, 2);
+ break;
+ case 1:
+ _vm->_sound->command(0xF);
+ if (_game._objects.isInInventory(OBJ_BONE))
+ _game._objects.setRoom(OBJ_BONE, 1);
+ _game._objects.addToInventory(OBJ_BONES);
+ _vm->_dialogs->show(OBJ_BONES, 70218);
+ break;
+ case 2:
+ _scene->_sequences.updateTimeout(-1, _globals._sequenceIndexes[12]);
+ _game._player._visible = true;
+ _game._player._stepEnabled = true;
+ break;
+ default:
+ break;
+ }
+ } else if (_action._lookFlag)
+ _vm->_dialogs->show(70210);
+ else if (_action.isAction(VERB_LOOK, NOUN_PLATFORM))
+ _vm->_dialogs->show(70211);
+ else if (_action.isAction(VERB_LOOK, NOUN_CEMENT_BLOCK))
+ _vm->_dialogs->show(70212);
+ else if (_action.isAction(VERB_LOOK, NOUN_ROCK))
+ _vm->_dialogs->show(70213);
+ else if (_action.isAction(VERB_TAKE, NOUN_ROCK))
+ _vm->_dialogs->show(70214);
+ else if (_action.isAction(VERB_LOOK, NOUN_WEST_END_OF_PLATFORM))
+ _vm->_dialogs->show(70215);
+ else if (_action.isAction(VERB_LOOK, NOUN_TELEPORTER))
+ _vm->_dialogs->show(70216);
+ else if (_action.isAction(VERB_LOOK, NOUN_BONES) && (_action._mainObjectSource == 4))
+ _vm->_dialogs->show(70217);
+ else if (_action.isAction(VERB_TAKE, NOUN_BONES) && (_action._mainObjectSource == 4)) {
+ if (_game._objects.isInInventory(OBJ_BONES))
+ _vm->_dialogs->show(70219);
+ } else if (_action.isAction(VERB_LOOK, NOUN_SUBMERGED_CITY))
+ _vm->_dialogs->show(70220);
+ else
+ return;
+
+ _action._inProgress = false;
+}
+
+/*------------------------------------------------------------------------*/
+
+Scene703::Scene703(MADSEngine *vm) : Scene7xx(vm) {
+ _monsterMode = -1;
+ _boatFrame = -1;
+ _curSequence = -1;
+ _boatDir = -1;
+
+ _useBomb = false;
+ _startMonsterTimer = false;
+ _rexDeathFl = false;
+ _restartTrigger70Fl = false;
+
+ _lastFrameTime = 0;
+ _monsterTime = 0;
+}
+
+void Scene703::synchronize(Common::Serializer &s) {
+ Scene7xx::synchronize(s);
+
+ s.syncAsSint16LE(_monsterMode);
+ s.syncAsSint16LE(_boatFrame);
+ s.syncAsSint16LE(_curSequence);
+ s.syncAsSint16LE(_boatDir);
+
+ s.syncAsByte(_useBomb);
+ s.syncAsByte(_startMonsterTimer);
+ s.syncAsByte(_rexDeathFl);
+ s.syncAsByte(_restartTrigger70Fl);
+
+ s.syncAsUint32LE(_lastFrameTime);
+ s.syncAsUint32LE(_monsterTime);
+}
+
+void Scene703::setup() {
+ _game._player._spritesPrefix = "";
+ setAAName();
+}
+
+void Scene703::handleBottleInterface() {
+ switch (_globals[kBottleStatus]) {
+ case 0:
+ _dialog1.write(0x311, true);
+ _dialog1.write(0x312, true);
+ _dialog1.write(0x313, true);
+ _dialog1.write(0x314, true);
+ _dialog1.write(0x315, true);
+ break;
+
+ case 1:
+ _dialog1.write(0x311, false);
+ _dialog1.write(0x312, true);
+ _dialog1.write(0x313, true);
+ _dialog1.write(0x314, true);
+ _dialog1.write(0x315, true);
+ break;
+
+ case 2:
+ _dialog1.write(0x311, false);
+ _dialog1.write(0x312, false);
+ _dialog1.write(0x313, true);
+ _dialog1.write(0x314, true);
+ _dialog1.write(0x315, true);
+ break;
+
+ case 3:
+ _dialog1.write(0x311, false);
+ _dialog1.write(0x312, false);
+ _dialog1.write(0x313, false);
+ _dialog1.write(0x314, true);
+ _dialog1.write(0x315, true);
+ break;
+
+ default:
+ break;
+ }
+}
+
+void Scene703::setBottleSequence() {
+ _scene->_userInterface.setup(kInputBuildingSentences);
+ _game._player._stepEnabled = false;
+ if (_boatDir == 2)
+ _curSequence = 6;
+ else
+ _curSequence = 7;
+}
+
+void Scene703::handleFillBottle(int quote) {
+ switch (quote) {
+ case 0x311:
+ _globals[kBottleStatus] = 1;
+ setBottleSequence();
+ break;
+
+ case 0x312:
+ _globals[kBottleStatus] = 2;
+ setBottleSequence();
+ break;
+
+ case 0x313:
+ _globals[kBottleStatus] = 3;
+ setBottleSequence();
+ break;
+
+ case 0x314:
+ _globals[kBottleStatus] = 4;
+ setBottleSequence();
+ break;
+
+ case 0x315:
+ _scene->_userInterface.setup(kInputBuildingSentences);
+ break;
+
+ default:
+ break;
+ }
+}
+
+void Scene703::enter() {
+ _game._player._visible = false;
+
+ if (!_game._visitedScenes._sceneRevisited) {
+ if (_scene->_priorSceneId == 704)
+ _globals[kMonsterAlive] = false;
+ else
+ _globals[kMonsterAlive] = true;
+ }
+
+ _startMonsterTimer = true;
+ _rexDeathFl = true;
+ _monsterTime = 0;
+ _restartTrigger70Fl = true;
+ _useBomb = false;
+ _boatFrame = -1;
+
+ if (!_globals[kMonsterAlive])
+ _scene->_hotspots.activate(NOUN_SEA_MONSTER, false);
+
+ if (_scene->_priorSceneId == 704) {
+ _game._player._stepEnabled = false;
+ _curSequence = 2;
+ _boatDir = 2;
+ _monsterMode = 0;
+ _scene->loadAnimation(formAnimName('A', -1));
+ _scene->_activeAnimation->setCurrentFrame(34);
+ } else if (_scene->_priorSceneId != -2) {
+ _game._player._stepEnabled = false;
+ _boatDir = 1;
+ if (_globals[kMonsterAlive]) {
+ _monsterMode = 1;
+ _curSequence = 0;
+ _scene->loadAnimation(formAnimName('B', -1));
+ } else {
+ _curSequence = 0;
+ _monsterMode = 0;
+ _scene->loadAnimation(formAnimName('A', -1));
+ }
+ } else if (_globals[kMonsterAlive]) {
+ _curSequence = 0;
+ _boatDir = 1;
+ _monsterMode = 1;
+ _scene->loadAnimation(formAnimName('B', -1));
+ _scene->_activeAnimation->setCurrentFrame(39);
+ } else if (_boatDir == 1) {
+ _curSequence = 0;
+ _monsterMode = 0;
+ _scene->loadAnimation(formAnimName('A', -1));
+ _scene->_activeAnimation->setCurrentFrame(9);
+ } else if (_boatDir == 2) {
+ _curSequence = 0;
+ _monsterMode = 0;
+ _scene->loadAnimation(formAnimName('A', -1));
+ _scene->_activeAnimation->setCurrentFrame(56);
+ }
+
+ if (_scene->_roomChanged) {
+ _game._objects.addToInventory(OBJ_TWINKIFRUIT);
+ _game._objects.addToInventory(OBJ_BOMB);
+ _game._objects.addToInventory(OBJ_CHICKEN);
+ _game._objects.addToInventory(OBJ_BONES);
+ }
+
+ _game.loadQuoteSet(0x311, 0x312, 0x313, 0x314, 0x315, 0);
+ _dialog1.setup(0x98, 0x311, 0x312, 0x313, 0x314, 0x315, 0);
+ sceneEntrySound();
+ _vm->_sound->command(28);
+}
+
+void Scene703::step() {
+ if (_startMonsterTimer) {
+ long diff = _scene->_frameStartTime - _lastFrameTime;
+ if ((diff >= 0) && (diff <= 12))
+ _monsterTime += diff;
+ else
+ _monsterTime++;
+
+ _lastFrameTime = _scene->_frameStartTime;
+ }
+
+ if ((_monsterTime >= 2400) && !_rexDeathFl && !_useBomb) {
+ _startMonsterTimer = false;
+ _rexDeathFl = true;
+ _game._player._stepEnabled = false;
+ _scene->freeAnimation();
+ _monsterMode = 3;
+ _scene->loadAnimation(formAnimName('D', -1));
+ _rexDeathFl = false;
+ _monsterTime = 0;
+ }
+
+
+ if (_game._trigger == 70)
+ _scene->_reloadSceneFlag = true;
+
+ if ((_monsterMode == 3) && (_scene->_activeAnimation != nullptr)) {
+ if (_scene->_activeAnimation->getCurrentFrame() != _boatFrame) {
+ _boatFrame = _scene->_activeAnimation->getCurrentFrame();
+ int nextBoatFrame = -1;
+
+ if (_boatFrame == 62) {
+ nextBoatFrame = 61;
+ if (_restartTrigger70Fl) {
+ _restartTrigger70Fl = false;
+ _scene->_sequences.addTimer(15, 70);
+ }
+ }
+
+ if ((nextBoatFrame >= 0) && (nextBoatFrame != _scene->_activeAnimation->getCurrentFrame())) {
+ _scene->_activeAnimation->setCurrentFrame(nextBoatFrame);
+ _boatFrame = nextBoatFrame;
+ }
+ }
+ }
+
+ if (_game._trigger == 70)
+ _scene->_reloadSceneFlag = true;
+
+ if ((_monsterMode == 0) && (_scene->_activeAnimation != nullptr)) {
+ if (_scene->_activeAnimation->getCurrentFrame() != _boatFrame) {
+ _boatFrame = _scene->_activeAnimation->getCurrentFrame();
+ int nextBoatFrame = -1;
+
+ switch (_boatFrame) {
+ case 11:
+ if (_curSequence == 7) {
+ _curSequence = 0;
+ nextBoatFrame = 100;
+ } else if (_curSequence == 5)
+ nextBoatFrame = 82;
+ else if (_curSequence == 1)
+ nextBoatFrame = 11;
+ else {
+ nextBoatFrame = 9;
+ if (!_game._player._stepEnabled)
+ _game._player._stepEnabled = true;
+ }
+ break;
+
+ case 34:
+ if (_curSequence != 2)
+ _scene->_nextSceneId = 704;
+ break;
+
+ case 57:
+ if (_curSequence == 6) {
+ _curSequence = 0;
+ nextBoatFrame = 91;
+ } else if (_curSequence == 4)
+ nextBoatFrame = 73;
+ else if (_curSequence == 3)
+ nextBoatFrame = 57;
+ else {
+ nextBoatFrame = 56;
+ if (!_game._player._stepEnabled)
+ _game._player._stepEnabled = true;
+ }
+ break;
+
+ case 73:
+ _scene->_nextSceneId = 701;
+ break;
+
+ case 82:
+ nextBoatFrame = 11;
+ break;
+
+ case 91:
+ nextBoatFrame = 57;
+ break;
+
+ case 100:
+ nextBoatFrame = 56;
+ if (!_game._player._stepEnabled) {
+ _scene->_sequences.addTimer(30, 80);
+ _game._player._stepEnabled = true;
+ }
+ break;
+
+ case 110:
+ nextBoatFrame = 9;
+ if (!_game._player._stepEnabled) {
+ _scene->_sequences.addTimer(30, 80);
+ _game._player._stepEnabled = true;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ if ((nextBoatFrame >= 0) && (nextBoatFrame != _scene->_activeAnimation->getCurrentFrame())) {
+ _scene->_activeAnimation->setCurrentFrame(nextBoatFrame);
+ _boatFrame = nextBoatFrame;
+ }
+ }
+ }
+
+ if (_game._trigger == 80) {
+ switch (_globals[kBottleStatus]) {
+ case 0:
+ _vm->_dialogs->show(432);
+ break;
+
+ case 1:
+ _vm->_dialogs->show(70324);
+ break;
+
+ case 2:
+ _vm->_dialogs->show(70325);
+ break;
+
+ case 3:
+ _vm->_dialogs->show(70326);
+ break;
+
+ case 4:
+ _vm->_dialogs->show(70327);
+ break;
+
+ default:
+ break;
+ }
+ }
+
+
+ if ((_monsterMode == 1) && (_scene->_activeAnimation != nullptr)) {
+ if (_scene->_activeAnimation->getCurrentFrame() != _boatFrame) {
+ _boatFrame = _scene->_activeAnimation->getCurrentFrame();
+ int nextBoatFrame = -1;
+
+ switch (_boatFrame) {
+ case 39:
+ _game._player._stepEnabled = true;
+ _startMonsterTimer = true;
+ _rexDeathFl = false;
+ break;
+
+ case 40:
+ case 49:
+ case 54:
+ case 67:
+ case 78:
+ case 87:
+ case 96:
+ case 105:
+ case 114:
+ case 123:
+ if (_curSequence == 8)
+ nextBoatFrame = 129;
+
+ break;
+
+ case 129:
+ nextBoatFrame = 39;
+ break;
+
+ case 151:
+ _scene->_nextSceneId = 701;
+ break;
+
+ default:
+ break;
+ }
+
+ if ((nextBoatFrame >= 0) && (nextBoatFrame != _scene->_activeAnimation->getCurrentFrame())) {
+ _scene->_activeAnimation->setCurrentFrame(nextBoatFrame);
+ _boatFrame = nextBoatFrame;
+ }
+ }
+ }
+
+ if ((_monsterMode == 2) && (_scene->_activeAnimation != nullptr)) {
+ if (_scene->_activeAnimation->getCurrentFrame() != _boatFrame) {
+ _boatFrame = _scene->_activeAnimation->getCurrentFrame();
+ int nextBoatFrame = -1;
+
+ switch (_boatFrame) {
+ case 14:
+ if (!_useBomb) {
+ if (_game._difficulty == DIFFICULTY_HARD)
+ _game._objects.setRoom(OBJ_CHICKEN, 1);
+ else
+ _vm->_dialogs->show(70319);
+ }
+ nextBoatFrame = 80;
+ break;
+
+ case 33:
+ if (_game._objects.isInInventory(OBJ_BONES)) {
+ _game._objects.setRoom(OBJ_BONES, 1);
+ _game._objects.addToInventory(OBJ_BONE);
+ } else
+ _game._objects.setRoom(OBJ_BONE, 1);
+
+ nextBoatFrame = 80;
+ break;
+
+ case 53:
+ _game._objects.setRoom(OBJ_TWINKIFRUIT, 1);
+ nextBoatFrame = 80;
+ _curSequence = 9;
+ break;
+
+ case 80:
+ if (_game._difficulty == DIFFICULTY_HARD) {
+ _game._objects.setRoom(OBJ_BOMB, 1);
+ _vm->_dialogs->show(70318);
+ } else
+ _vm->_dialogs->show(70317);
+
+ _scene->freeAnimation();
+ _monsterMode = 1;
+ _scene->loadAnimation(formAnimName('B', -1));
+ _scene->_activeAnimation->setCurrentFrame(39);
+ _game._player._stepEnabled = true;
+ break;
+
+ case 91:
+ if (!_useBomb) {
+ _scene->freeAnimation();
+ _monsterMode = 1;
+ _scene->loadAnimation(formAnimName('B', -1));
+ _scene->_activeAnimation->setCurrentFrame(39);
+ _game._player._stepEnabled = true;
+ } else
+ _game._objects.setRoom(OBJ_CHICKEN_BOMB, 1);
+
+ break;
+
+ case 126:
+ _scene->_hotspots.activate(NOUN_SEA_MONSTER, false);
+ _globals[kMonsterAlive] = false;
+ _scene->freeAnimation();
+ _monsterMode = 0;
+ _scene->loadAnimation(formAnimName('A', -1));
+ _scene->_activeAnimation->setCurrentFrame(9);
+ _game._player._stepEnabled = true;
+ if (_game._storyMode == STORYMODE_NAUGHTY)
+ _vm->_dialogs->show(70321);
+ else
+ _vm->_dialogs->show(70322);
+
+ break;
+
+ default:
+ break;
+ }
+
+ if ((nextBoatFrame >= 0) && (nextBoatFrame != _scene->_activeAnimation->getCurrentFrame())) {
+ _scene->_activeAnimation->setCurrentFrame(nextBoatFrame);
+ _boatFrame = nextBoatFrame;
+ }
+ }
+ }
+}
+
+void Scene703::actions() {
+ if (_game._screenObjects._inputMode == 1)
+ handleFillBottle(_action._activeAction._verbId);
+ else if (_action.isAction(0x3B1, 0x3B0)) {
+ _game._player._stepEnabled = false;
+ if (_globals[kMonsterAlive])
+ _curSequence = 8;
+ else if (_boatDir == 1)
+ _curSequence = 5;
+ else
+ _curSequence = 3;
+ } else if (_action.isAction(0x3B1, 0x3B2)) {
+ _game._player._stepEnabled = false;
+ if (_globals[kMonsterAlive]) {
+ _startMonsterTimer = false;
+ _rexDeathFl = true;
+ _monsterTime = 0;
+ _scene->freeAnimation();
+ _monsterMode = 3;
+ _scene->loadAnimation(formAnimName('D', -1));
+ } else if (_boatDir == 2)
+ _curSequence = 4;
+ else
+ _curSequence = 1;
+ } else if (_action.isAction(VERB_THROW, NOUN_BONE, 0x468) || _action.isAction(VERB_THROW, NOUN_BONES, 0x468)) {
+ _game._player._stepEnabled = false;
+ _scene->freeAnimation();
+ _monsterMode = 2;
+ _scene->loadAnimation(formAnimName('C', -1));
+ _scene->_activeAnimation->setCurrentFrame(19);
+ } else if (_action.isAction(VERB_THROW, NOUN_CHICKEN, 0x468)) {
+ _game._player._stepEnabled = false;
+ _scene->freeAnimation();
+ _monsterMode = 2;
+ _scene->loadAnimation(formAnimName('C', -1));
+ } else if (_action.isAction(VERB_THROW, NOUN_TWINKIFRUIT, 0x468)) {
+ _game._player._stepEnabled = false;
+ _scene->freeAnimation();
+ _monsterMode = 2;
+ _scene->loadAnimation(formAnimName('C', -1));
+ _scene->_activeAnimation->setCurrentFrame(39);
+ } else if (_action.isAction(VERB_THROW, NOUN_BOMB, 0x468)) {
+ _game._player._stepEnabled = false;
+ _scene->freeAnimation();
+ _monsterMode = 2;
+ _scene->loadAnimation(formAnimName('C', -1));
+ _scene->_activeAnimation->setCurrentFrame(59);
+ } else if (_action.isAction(VERB_THROW, NOUN_CHICKEN_BOMB, 0x468)) {
+ _useBomb = true;
+ _game._player._stepEnabled = false;
+ _scene->freeAnimation();
+ _monsterMode = 2;
+ _scene->loadAnimation(formAnimName('C', -1));
+ } else if (_action.isAction(VERB_PUT, NOUN_BOTTLE, 0x18F) || _action.isAction(0x85, 0x2E, 0x18F)) {
+ if (_globals[kBottleStatus] != 4) {
+ handleBottleInterface();
+ _dialog1.start();
+ } else
+ _vm->_dialogs->show(70323);
+ } else if (_action._lookFlag || _action.isAction(VERB_LOOK, NOUN_SEA_MONSTER)) {
+ if (_globals[kMonsterAlive])
+ _vm->_dialogs->show(70310);
+ } else if (_action.isAction(VERB_LOOK, NOUN_WATER)) {
+ if (!_globals[kMonsterAlive])
+ _vm->_dialogs->show(70311);
+ else
+ _vm->_dialogs->show(70312);
+ } else if (_action.isAction(VERB_LOOK, NOUN_BUILDING_TO_NORTH)) {
+ if (_globals[kMonsterAlive])
+ _vm->_dialogs->show(70313);
+ else if (_game._visitedScenes.exists(710))
+ _vm->_dialogs->show(70314);
+ else
+ _vm->_dialogs->show(70315);
+ } else if (_action.isAction(VERB_LOOK, NOUN_VOLCANO_RIM))
+ _vm->_dialogs->show(70316);
+ else
+ return;
+
+ _action._inProgress = false;
+}
+
+/*------------------------------------------------------------------------*/
+
+Scene704::Scene704(MADSEngine *vm) : Scene7xx(vm) {
+ _bottleHotspotId = -1;
+ _boatCurrentFrame = -1;
+ _animationMode = -1;
+ _boatDirection = -1;
+
+ _takeBottleFl = false;
+}
+
+void Scene704::synchronize(Common::Serializer &s) {
+ Scene7xx::synchronize(s);
+
+ s.syncAsSint16LE(_bottleHotspotId);
+ s.syncAsSint16LE(_boatCurrentFrame);
+ s.syncAsSint16LE(_animationMode);
+ s.syncAsSint16LE(_boatDirection);
+
+ s.syncAsByte(_takeBottleFl);
+}
+
+void Scene704::setup() {
+ _game._player._spritesPrefix = "";
+ setAAName();
+ _scene->addActiveVocab(NOUN_BOTTLE);
+ _scene->addActiveVocab(VERB_LOOK_AT);
+}
+
+void Scene704::handleBottleInterface() {
+ switch (_globals[kBottleStatus]) {
+ case 0:
+ _dialog1.write(0x311, true);
+ _dialog1.write(0x312, true);
+ _dialog1.write(0x313, true);
+ _dialog1.write(0x314, true);
+ _dialog1.write(0x315, true);
+ break;
+
+ case 1:
+ _dialog1.write(0x311, false);
+ _dialog1.write(0x312, true);
+ _dialog1.write(0x313, true);
+ _dialog1.write(0x314, true);
+ _dialog1.write(0x315, true);
+ break;
+
+ case 2:
+ _dialog1.write(0x311, false);
+ _dialog1.write(0x312, false);
+ _dialog1.write(0x313, true);
+ _dialog1.write(0x314, true);
+ _dialog1.write(0x315, true);
+ break;
+
+ case 3:
+ _dialog1.write(0x311, false);
+ _dialog1.write(0x312, false);
+ _dialog1.write(0x313, false);
+ _dialog1.write(0x314, true);
+ _dialog1.write(0x315, true);
+ break;
+
+ default:
+ break;
+ }
+}
+
+void Scene704::setBottleSequence() {
+ _scene->_userInterface.setup(kInputBuildingSentences);
+ _game._player._stepEnabled = false;
+ if (_boatDirection == 2)
+ _animationMode = 6;
+ else
+ _animationMode = 7;
+}
+
+void Scene704::handleFillBottle(int quote) {
+ switch (quote) {
+ case 0x311:
+ _globals[kBottleStatus] = 1;
+ setBottleSequence();
+ break;
+
+ case 0x312:
+ _globals[kBottleStatus] = 2;
+ setBottleSequence();
+ break;
+
+ case 0x313:
+ _globals[kBottleStatus] = 3;
+ setBottleSequence();
+ break;
+
+ case 0x314:
+ _globals[kBottleStatus] = 4;
+ setBottleSequence();
+ break;
+
+ case 0x315:
+ _scene->_userInterface.setup(kInputBuildingSentences);
+ break;
+
+ default:
+ break;
+ }
+}
+
+void Scene704::enter() {
+ if (_game._objects[OBJ_BOTTLE]._roomNumber == _scene->_currentSceneId) {
+ _globals._spriteIndexes[1] = _scene->_sprites.addSprites(formAnimName('b', 0));
+ _globals._sequenceIndexes[1] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[1], false, 6, 0, 0, 0);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 1);
+ if (_scene->_priorSceneId == 705) {
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[1], Common::Point(123, 125));
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 1);
+ } else {
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[1], Common::Point(190, 122));
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 2);
+ }
+ int idx = _scene->_dynamicHotspots.add(NOUN_BONES, 0xD1, _globals._sequenceIndexes[1], Common::Rect(0, 0, 0, 0));
+ _bottleHotspotId = _scene->_dynamicHotspots.setPosition(idx, Common::Point(-2, 0), FACING_NONE);
+ }
+
+ _game._player._visible = false;
+ _takeBottleFl = false;
+ _boatCurrentFrame = -1;
+
+ if (_scene->_priorSceneId == 705) {
+ _game._player._stepEnabled = false;
+ _animationMode = 2;
+ _boatDirection = 2;
+ _scene->loadAnimation(formAnimName('A', -1));
+ _scene->_activeAnimation->setCurrentFrame(36);
+ } else if (_scene->_priorSceneId != -2) {
+ _game._player._stepEnabled = false;
+ _boatDirection = 1;
+ _scene->loadAnimation(formAnimName('A', -1));
+ } else if (_boatDirection == 1) {
+ _scene->loadAnimation(formAnimName('A', -1));
+ _scene->_activeAnimation->setCurrentFrame(8);
+ } else if (_boatDirection == 2) {
+ if (_game._objects[OBJ_BOTTLE]._roomNumber == _scene->_currentSceneId) {
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[1], Common::Point(123, 125));
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 1);
+ }
+ _scene->loadAnimation(formAnimName('A', -1));
+ _scene->_activeAnimation->setCurrentFrame(57);
+ }
+
+ if (_scene->_roomChanged)
+ _globals[kMonsterAlive] = false;
+
+ _game.loadQuoteSet(0x311, 0x312, 0x313, 0x314, 0x315, 0);
+ _dialog1.setup(0x98, 0x311, 0x312, 0x313, 0x314, 0x315, 0);
+
+ sceneEntrySound();
+ _vm->_sound->command(28);
+}
+
+void Scene704::step() {
+ if (_scene->_activeAnimation != nullptr) {
+ if (_scene->_activeAnimation->getCurrentFrame() != _boatCurrentFrame) {
+ _boatCurrentFrame = _scene->_activeAnimation->getCurrentFrame();
+ int nextFrame = -1;
+
+ switch (_boatCurrentFrame) {
+ case 10:
+ switch (_animationMode) {
+ case 1:
+ nextFrame = 10;
+ break;
+ case 5:
+ nextFrame = 74;
+ break;
+ case 7:
+ _animationMode = 0;
+ nextFrame = 92;
+ break;
+ default:
+ if (!_game._player._stepEnabled)
+ _game._player._stepEnabled = true;
+
+ nextFrame = 8;
+ break;
+ }
+ break;
+
+ case 36:
+ if (_animationMode != 2)
+ _scene->_nextSceneId = 705;
+ break;
+
+ case 59:
+ switch (_animationMode) {
+ case 3:
+ nextFrame = 59;
+ break;
+
+ case 4:
+ nextFrame = 65;
+ break;
+
+ case 6:
+ _animationMode = 0;
+ nextFrame = 83;
+ break;
+
+ default:
+ if (!_game._player._stepEnabled) {
+ _game._player._stepEnabled = true;
+ }
+ nextFrame = 57;
+ break;
+ }
+ break;
+
+ case 65:
+ _scene->_nextSceneId = 703;
+ break;
+
+ case 74:
+ nextFrame = 10;
+ break;
+
+ case 83:
+ nextFrame = 59;
+ break;
+
+ case 90:
+ if (_takeBottleFl) {
+ _scene->_sequences.remove(_globals._sequenceIndexes[1]);
+ _scene->_dynamicHotspots.remove(_bottleHotspotId);
+ _game._objects.addToInventory(OBJ_BOTTLE);
+ _vm->_sound->command(15);
+ _vm->_dialogs->showItem(OBJ_BOTTLE, 70415);
+ }
+ break;
+
+ case 92:
+ nextFrame = 57;
+ if (!_game._player._stepEnabled && !_takeBottleFl) {
+ _scene->_sequences.addTimer(30, 70);
+ _game._player._stepEnabled = true;
+ }
+ break;
+
+ case 98:
+ if (_takeBottleFl) {
+ _scene->_sequences.remove(_globals._sequenceIndexes[1]);
+ _scene->_dynamicHotspots.remove(_bottleHotspotId);
+ _game._objects.addToInventory(OBJ_BOTTLE);
+ _vm->_sound->command(15);
+ _vm->_dialogs->showItem(OBJ_BOTTLE, 70415);
+ }
+ break;
+
+ case 101:
+ nextFrame = 8;
+ if (!_game._player._stepEnabled && !_takeBottleFl) {
+ _scene->_sequences.addTimer(30, 70);
+ _game._player._stepEnabled = true;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ if ((nextFrame >= 0) && (nextFrame != _scene->_activeAnimation->getCurrentFrame())) {
+ _scene->_activeAnimation->setCurrentFrame(nextFrame);
+ _boatCurrentFrame = nextFrame;
+ }
+ }
+ }
+
+ if (_game._trigger == 70) {
+ switch (_globals[kBottleStatus]) {
+ case 0:
+ _vm->_dialogs->show(432);
+ break;
+
+ case 1:
+ _vm->_dialogs->show(70324);
+ break;
+
+ case 2:
+ _vm->_dialogs->show(70325);
+ break;
+
+ case 3:
+ _vm->_dialogs->show(70326);
+ break;
+
+ case 4:
+ _vm->_dialogs->show(70327);
+ break;
+
+ default:
+ break;
+ }
+ }
+}
+
+void Scene704::actions() {
+ if (_game._screenObjects._inputMode == 1)
+ handleFillBottle(_action._activeAction._verbId);
+ else if (_action.isAction(0x3B1, 0x3B4)) {
+ _game._player._stepEnabled = false;
+ if (_boatDirection == 1)
+ _animationMode = 5;
+ else
+ _animationMode = 3;
+ } else if (_action.isAction(0x3B1, 0x3B2)) {
+ _game._player._stepEnabled = false;
+ if (_boatDirection == 2)
+ _animationMode = 4;
+ else
+ _animationMode = 1;
+ } else if (_action.isAction(VERB_TAKE, NOUN_BOTTLE)) {
+ if (!_game._objects.isInInventory(OBJ_BOTTLE)) {
+ _game._player._stepEnabled = false;
+ _takeBottleFl = true;
+ if (_boatDirection == 2) {
+ _animationMode = 6;
+ } else {
+ _animationMode = 7;
+ }
+ }
+ } else if (_action.isAction(VERB_PUT, NOUN_BOTTLE, 0x18F) || _action.isAction(0x85, 0x2E, 0x18F)) {
+ if (_game._objects.isInInventory(OBJ_BOTTLE)) {
+ if (_globals[kBottleStatus] != 4) {
+ _takeBottleFl = false;
+ handleBottleInterface();
+ _dialog1.start();
+ } else
+ _vm->_dialogs->show(70323);
+ }
+ } else if (_action._lookFlag || _action.isAction(VERB_LOOK, NOUN_WATER))
+ _vm->_dialogs->show(70410);
+ else if (_action.isAction(VERB_LOOK, NOUN_BUILDING_TO_NORTH)) {
+ if (_game._visitedScenes.exists(710))
+ _vm->_dialogs->show(70411);
+ else
+ _vm->_dialogs->show(70412);
+ } else if (_action.isAction(VERB_LOOK, NOUN_VOLCANO_RIM))
+ _vm->_dialogs->show(70413);
+ else if (_action.isAction(VERB_LOOK, NOUN_BOTTLE) && (_action._mainObjectSource == 4))
+ _vm->_dialogs->show(70414);
+ else if (_action.isAction(VERB_LOOK, NOUN_OPEN_WATER_TO_SOUTH))
+ _vm->_dialogs->show(70416);
+ else if (_action.isAction(VERB_LOOK, NOUN_SKY))
+ _vm->_dialogs->show(70417);
+ else
+ return;
+
+ _action._inProgress = false;
+}
+
+/*------------------------------------------------------------------------*/
+
+void Scene705::setup() {
+ _game._player._spritesPrefix = "";
+ setAAName();
+}
+
+void Scene705::synchronize(Common::Serializer &s) {
+ Scene7xx::synchronize(s);
+}
+
+void Scene705::handleBottleInterface() {
+ switch (_globals[kBottleStatus]) {
+ case 0:
+ _dialog1.write(0x311, true);
+ _dialog1.write(0x312, true);
+ _dialog1.write(0x313, true);
+ _dialog1.write(0x314, true);
+ _dialog1.write(0x315, true);
+ break;
+
+ case 1:
+ _dialog1.write(0x311, false);
+ _dialog1.write(0x312, true);
+ _dialog1.write(0x313, true);
+ _dialog1.write(0x314, true);
+ _dialog1.write(0x315, true);
+ break;
+
+ case 2:
+ _dialog1.write(0x311, false);
+ _dialog1.write(0x312, false);
+ _dialog1.write(0x313, true);
+ _dialog1.write(0x314, true);
+ _dialog1.write(0x315, true);
+ break;
+
+ case 3:
+ _dialog1.write(0x311, false);
+ _dialog1.write(0x312, false);
+ _dialog1.write(0x313, false);
+ _dialog1.write(0x314, true);
+ _dialog1.write(0x315, true);
+ break;
+
+ default:
+ break;
+ }
+}
+
+void Scene705::setBottleSequence() {
+ _scene->_userInterface.setup(kInputBuildingSentences);
+ _game._player._stepEnabled = false;
+ _scene->_sequences.remove(_globals._sequenceIndexes[3]);
+ _game._triggerSetupMode = SEQUENCE_TRIGGER_DAEMON;
+ _scene->loadAnimation(formAnimName('F', -1), 90);
+}
+
+void Scene705::handleFillBottle(int quote) {
+ switch (quote) {
+ case 0x311:
+ _globals[kBottleStatus] = 1;
+ setBottleSequence();
+ break;
+
+ case 0x312:
+ _globals[kBottleStatus] = 2;
+ setBottleSequence();
+ break;
+
+ case 0x313:
+ _globals[kBottleStatus] = 3;
+ setBottleSequence();
+ break;
+
+ case 0x314:
+ _globals[kBottleStatus] = 4;
+ setBottleSequence();
+ break;
+
+ case 0x315:
+ _scene->_userInterface.setup(kInputBuildingSentences);
+ break;
+
+ default:
+ break;
+ }
+}
+
+void Scene705::enter() {
+ _globals._spriteIndexes[1] = _scene->_sprites.addSprites(formAnimName('b', 0));
+ _globals._spriteIndexes[2] = _scene->_sprites.addSprites(formAnimName('b', 1));
+ _globals._spriteIndexes[3] = _scene->_sprites.addSprites(formAnimName('a', 0));
+
+ _game._player._visible = false;
+
+ if (_scene->_priorSceneId == 706) {
+ _game._player._stepEnabled = false;
+ _globals._sequenceIndexes[3] = _scene->_sequences.addReverseSpriteCycle(_globals._spriteIndexes[3], false, 9, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[3], 1, 4);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[3], SEQUENCE_TRIGGER_EXPIRE, 0, 71);
+ } else if (_scene->_priorSceneId != -2) {
+ _game._player._stepEnabled = false;
+ _scene->_sequences.addTimer(1, 80);
+ _vm->_sound->command(28);
+ } else
+ _globals._sequenceIndexes[3] = _scene->_sequences.startCycle(_globals._spriteIndexes[3], false, 1);
+
+ if (_scene->_roomChanged)
+ _game._objects.addToInventory(OBJ_BOTTLE);
+
+ _game.loadQuoteSet(0x311, 0x312, 0x313, 0x314, 0x315, 0);
+ _dialog1.setup(0x98, 0x311, 0x312, 0x313, 0x314, 0x315, 0);
+ sceneEntrySound();
+}
+
+void Scene705::step() {
+ switch (_game._trigger) {
+ case 70:
+ _globals._sequenceIndexes[3] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[3], false, 9, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[3], 1, 4);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[3], SEQUENCE_TRIGGER_EXPIRE, 0, 71);
+ break;
+
+ case 71: {
+ int syncIdx = _globals._sequenceIndexes[3];
+ _globals._sequenceIndexes[3] = _scene->_sequences.startCycle(_globals._spriteIndexes[3], false, 1);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[3], syncIdx);
+ _game._player._stepEnabled = true;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ switch (_game._trigger) {
+ case 80:
+ _globals._sequenceIndexes[1] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[1], false, 9, 1, 0, 0);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 2);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[1], SEQUENCE_TRIGGER_EXPIRE, 0, 81);
+ break;
+
+ case 81: {
+ _vm->_sound->command(19);
+ int syncIdx = _globals._sequenceIndexes[1];
+ _globals._sequenceIndexes[3] = _scene->_sequences.startCycle(_globals._spriteIndexes[3], false, 1);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[3], syncIdx);
+ _game._player._stepEnabled = true;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ switch (_game._trigger) {
+ case 90:
+ _globals._sequenceIndexes[3] = _scene->_sequences.startCycle(_globals._spriteIndexes[3], false, 1);
+ _scene->_sequences.addTimer(30, 91);
+ break;
+
+ case 91:
+ switch (_globals[kBottleStatus]) {
+ case 0:
+ _vm->_dialogs->show(432);
+ break;
+
+ case 1:
+ _vm->_dialogs->show(70324);
+ break;
+
+ case 2:
+ _vm->_dialogs->show(70325);
+ break;
+
+ case 3:
+ _vm->_dialogs->show(70326);
+ break;
+
+ case 4:
+ _vm->_dialogs->show(70327);
+ break;
+
+ default:
+ break;
+ }
+ _game._player._stepEnabled = true;
+ break;
+
+ default:
+ break;
+ }
+}
+
+void Scene705::actions() {
+ if (_game._screenObjects._inputMode == 1)
+ handleFillBottle(_action._activeAction._verbId);
+ else if (_action.isAction(0x3B1, 0x3B4)) {
+ switch (_game._trigger) {
+ case 0:
+ _game._player._stepEnabled = false;
+ _scene->_sequences.remove(_globals._sequenceIndexes[3]);
+ _globals._sequenceIndexes[2] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[2], false, 6, 1, 0, 0);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 2);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[2], SEQUENCE_TRIGGER_EXPIRE, 0, 1);
+ _vm->_sound->command(18);
+ break;
+
+ case 1: {
+ int syncIdx = _globals._sequenceIndexes[2];
+ _globals._sequenceIndexes[2] = _scene->_sequences.startCycle(_globals._spriteIndexes[2], false, -2);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 2);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[2], syncIdx);
+ _scene->_nextSceneId = 704;
+ _game._player._stepEnabled = true;
+ }
+ break;
+
+ default:
+ break;
+ }
+ } else if (_action.isAction(VERB_CLIMB_THROUGH, NOUN_WINDOW)) {
+ switch (_game._trigger) {
+ case 0:
+ _game._player._stepEnabled = false;
+ _scene->_sequences.remove(_globals._sequenceIndexes[3]);
+ _globals._sequenceIndexes[3] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[3], false, 6, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[3], 1, 16);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[3], SEQUENCE_TRIGGER_EXPIRE, 0, 1);
+ break;
+
+ case 1: {
+ int syncIdx = _globals._sequenceIndexes[3];
+ _globals._sequenceIndexes[3] = _scene->_sequences.startCycle(_globals._spriteIndexes[3], false, 16);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[3], syncIdx);
+ _scene->_nextSceneId = 706;
+ _game._player._stepEnabled = true;
+ }
+ break;
+
+ default:
+ break;
+ }
+ } else if (_action.isAction(0x85, 0x2E, 0x18F) || _action.isAction(VERB_PUT, NOUN_BOTTLE, 0x18F)) {
+ if (_globals[kBottleStatus] != 4) {
+ handleBottleInterface();
+ _dialog1.start();
+ } else
+ _vm->_dialogs->show(70323);
+ } if (_action._lookFlag || _action.isAction(VERB_LOOK, NOUN_WATER))
+ _vm->_dialogs->show(70511);
+ else if (_action.isAction(VERB_LOOK, NOUN_VOLCANO_RIM))
+ _vm->_dialogs->show(70512);
+ else if (_action.isAction(VERB_LOOK, NOUN_OPEN_WATER_TO_SOUTH))
+ _vm->_dialogs->show(70513);
+ else if (_action.isAction(VERB_LOOK, NOUN_SKY))
+ _vm->_dialogs->show(70514);
+ else if (_action.isAction(VERB_LOOK, NOUN_BUILDING))
+ _vm->_dialogs->show(70515);
+ else if (_action.isAction(VERB_LOOK, NOUN_WINDOW))
+ _vm->_dialogs->show(70516);
+ else
+ return;
+
+ _action._inProgress = false;
+}
+
+/*------------------------------------------------------------------------*/
+
+Scene706::Scene706(MADSEngine *vm) : Scene7xx(vm) {
+ _vaseHotspotId = -1;
+ _vaseMode = -1;
+ _animationMode = -1;
+ _animationFrame = -1;
+
+ _emptyPedestral = false;
+}
+
+void Scene706::synchronize(Common::Serializer &s) {
+ Scene7xx::synchronize(s);
+
+ s.syncAsSint16LE(_vaseHotspotId);
+ s.syncAsSint16LE(_vaseMode);
+ s.syncAsSint16LE(_animationMode);
+ s.syncAsSint16LE(_animationFrame);
+
+ s.syncAsByte(_emptyPedestral);
+}
+
+void Scene706::setup() {
+ setPlayerSpritesPrefix();
+ setAAName();
+ _scene->addActiveVocab(NOUN_BOTTLE);
+ _scene->addActiveVocab(NOUN_VASE);
+ _scene->addActiveVocab(VERB_WALKTO);
+}
+
+void Scene706::handleRexDeath() {
+ switch (_game._trigger) {
+ case 0:
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _scene->loadAnimation(formAnimName('a', -1), 2);
+ break;
+
+ case 2:
+ if (_animationMode == 1)
+ _vm->_dialogs->show(70625);
+ else if (_globals[kBottleStatus] < 2)
+ _vm->_dialogs->show(70628);
+ else
+ _vm->_dialogs->show(70629);
+
+ _game._objects.setRoom(OBJ_VASE, _scene->_currentSceneId);
+ if (_animationMode == 2)
+ _game._objects.setRoom(OBJ_BOTTLE, 2);
+
+ _animationMode = 0;
+ _scene->_reloadSceneFlag = true;
+ break;
+
+ default:
+ break;
+ }
+}
+
+void Scene706::handleTakeVase() {
+ switch (_game._trigger) {
+ case 0:
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._sequenceIndexes[3] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[3], false, 4, 2, 0, 0);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[3]);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[3], SEQUENCE_TRIGGER_SPRITE, 7, 1);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[3], SEQUENCE_TRIGGER_EXPIRE, 0, 2);
+ break;
+
+ case 1:
+ _vm->_sound->command(9);
+ _scene->_sequences.remove(_globals._sequenceIndexes[1]);
+ _scene->_dynamicHotspots.remove(_vaseHotspotId);
+ _game._objects.addToInventory(OBJ_VASE);
+ if (_vaseMode == 1) {
+ _globals._sequenceIndexes[4] = _scene->_sequences.startCycle(_globals._spriteIndexes[4], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[4], 4);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[4], Common::Point(195, 99));
+ int idx = _scene->_dynamicHotspots.add(NOUN_BOTTLE, VERB_WALKTO, _globals._sequenceIndexes[4], Common::Rect(0, 0, 0, 0));
+ _scene->_dynamicHotspots.setPosition(idx, Common::Point(175, 124), FACING_SOUTHEAST);
+ _game._objects.setRoom(OBJ_BOTTLE, _scene->_currentSceneId);
+ }
+ break;
+
+ case 2:
+ _scene->_sequences.updateTimeout(-1, _globals._sequenceIndexes[3]);
+ _game._player._visible = true;
+ _vm->_dialogs->showItem(OBJ_VASE, 70630);
+ _game._player._stepEnabled = true;
+ break;
+ }
+}
+
+void Scene706::enter() {
+ _globals._spriteIndexes[3] = _scene->_sprites.addSprites("*RXMRC_3");
+ _globals._spriteIndexes[4] = _scene->_sprites.addSprites(formAnimName('b', -1));
+
+ if (!_game._visitedScenes._sceneRevisited)
+ _emptyPedestral = false;
+
+ if (_game._objects[OBJ_VASE]._roomNumber == _scene->_currentSceneId) {
+ _globals._spriteIndexes[1] = _scene->_sprites.addSprites(formAnimName('v', -1));
+ _globals._sequenceIndexes[1] = _scene->_sequences.startCycle(_globals._spriteIndexes[1], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 4);
+ int idx = _scene->_dynamicHotspots.add(NOUN_VASE, VERB_WALKTO, _globals._sequenceIndexes[1], Common::Rect(0, 0, 0, 0));
+ _vaseHotspotId = _scene->_dynamicHotspots.setPosition(idx, Common::Point(175, 124), FACING_SOUTHEAST);
+ } else if (_game._objects.isInRoom(OBJ_BOTTLE)) {
+ _globals._sequenceIndexes[4] = _scene->_sequences.startCycle(_globals._spriteIndexes[4], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[4], 4);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[4], Common::Point(195, 99));
+ int idx = _scene->_dynamicHotspots.add(NOUN_BOTTLE, VERB_WALKTO, _globals._sequenceIndexes[4], Common::Rect(0, 0, 0, 0));
+ _scene->_dynamicHotspots.setPosition(idx, Common::Point(175, 124), FACING_SOUTHEAST);
+ }
+
+ _game._player._visible = true;
+
+ if (_scene->_priorSceneId == 707) {
+ _game._player._playerPos = Common::Point(277, 103);
+ _game._player._facing = FACING_SOUTHWEST;
+ } else if (_scene->_priorSceneId != -2) {
+ _game._player._playerPos = Common::Point(167, 152);
+ _game._player._facing = FACING_NORTH;
+ }
+
+ if (_globals[kTeleporterCommand]) {
+ _game._player._visible = false;
+ _game._player._stepEnabled = false;
+
+ switch (_globals[kTeleporterCommand]) {
+ case 1:
+ _scene->loadAnimation(formAnimName('E', 1), 75);
+ break;
+
+ case 2:
+ _scene->loadAnimation(formAnimName('E', -1), 80);
+ break;
+
+ default:
+ _game._player.walk(Common::Point(264, 116), FACING_SOUTHWEST);
+ _game._player._visible = true;
+ _game._player._stepEnabled = true;
+ break;
+ }
+ _globals[kTeleporterCommand] = 0;
+ }
+
+ _animationMode = 0;
+
+ if (_scene->_roomChanged) {
+ _game._objects.addToInventory(OBJ_BOTTLE);
+ _globals[kBottleStatus] = 2;
+ }
+
+ sceneEntrySound();
+}
+
+void Scene706::step() {
+ if (_game._trigger == 75) {
+ _game._player._stepEnabled = true;
+ _game._player._visible = true;
+ _game._player._priorTimer = _scene->_frameStartTime - _game._player._ticksAmount;
+ _game._player.walk(Common::Point(264, 116), FACING_SOUTHWEST);
+ }
+
+ if (_game._trigger == 80) {
+ _globals[kTeleporterCommand] = 1;
+ _scene->_nextSceneId = _globals[kTeleporterDestination];
+ _scene->_reloadSceneFlag = true;
+ }
+
+ if (_scene->_activeAnimation != nullptr) {
+ if ((_animationMode != 0) && (_scene->_activeAnimation->getCurrentFrame() != _animationFrame)) {
+ _animationFrame = _scene->_activeAnimation->getCurrentFrame();
+
+ if (_animationFrame == 6) {
+ _scene->_sequences.remove(_globals._sequenceIndexes[1]);
+ _game._objects.setRoom(OBJ_VASE, 2);
+
+ if (_animationMode == 2) {
+ _game._objects.setRoom(OBJ_BOTTLE, 1);
+
+ _globals._sequenceIndexes[4] = _scene->_sequences.startCycle(_globals._spriteIndexes[4], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[4], 4);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[4], Common::Point(195, 99));
+ int idx = _scene->_dynamicHotspots.add(NOUN_BOTTLE, VERB_WALKTO, _globals._sequenceIndexes[4], Common::Rect(0, 0, 0, 0));
+ _scene->_dynamicHotspots.setPosition(idx, Common::Point(175, 124), FACING_SOUTHEAST);
+ }
+ }
+ }
+ }
+}
+
+void Scene706::preActions() {
+ if (_action.isAction(VERB_LOOK, NOUN_PORTRAIT))
+ _game._player._needToWalk = true;
+}
+
+void Scene706::actions() {
+ if (_action.isAction(VERB_WALK_INSIDE, NOUN_TELEPORTER)) {
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _scene->_nextSceneId = 707;
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_EXIT, NOUN_ROOM)) {
+ _scene->_nextSceneId = 705;
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_TAKE, NOUN_VASE)) {
+ if (_game._difficulty != DIFFICULTY_EASY) {
+ _animationMode = 1;
+ handleRexDeath();
+ } else if (_game._trigger || !_game._objects.isInInventory(OBJ_VASE)) {
+ handleTakeVase();
+ _emptyPedestral = true;
+ }
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_PUT, NOUN_BOTTLE, 0x344)) {
+ if ((_globals[kBottleStatus] == 2 && _game._difficulty == DIFFICULTY_HARD) ||
+ (_globals[kBottleStatus] != 0 && _game._difficulty != DIFFICULTY_HARD)) {
+ if (!_game._objects.isInInventory(OBJ_VASE) || _game._trigger) {
+ _vaseMode = 1;
+ handleTakeVase();
+ _action._inProgress = false;
+ return;
+ }
+ } else if (_game._objects.isInRoom(OBJ_VASE) || _game._trigger) {
+ _animationMode = 2;
+ handleRexDeath();
+ _action._inProgress = false;
+ return;
+ }
+ }
+
+ if (_action.isAction(VERB_PUT, NOUN_PEDESTAL) && _game._objects.isInInventory(_game._objects.getIdFromDesc(_action._activeAction._objectNameId))) {
+ int objectId = _game._objects.getIdFromDesc(_action._activeAction._objectNameId);
+ if (_game._objects[objectId].hasQuality(10))
+ _vm->_dialogs->show(70626);
+ else
+ _vm->_dialogs->show(70627);
+ } else if (_action.isAction(VERB_TAKE, NOUN_BOTTLE) && _game._objects.isInInventory(OBJ_VASE))
+ _vm->_dialogs->show(70631);
+ else if (_action._lookFlag) {
+ if (_game._objects[OBJ_VASE]._roomNumber == _scene->_currentSceneId)
+ _vm->_dialogs->show(70610);
+ else
+ _vm->_dialogs->show(70611);
+ } else if (_action.isAction(VERB_LOOK, NOUN_FLOOR))
+ _vm->_dialogs->show(70612);
+ else if (_action.isAction(VERB_LOOK, NOUN_PILLAR))
+ _vm->_dialogs->show(70613);
+ else if (_action.isAction(VERB_LOOK, NOUN_OLD_TEA_CUP))
+ _vm->_dialogs->show(70614);
+ else if (_action.isAction(VERB_TAKE, NOUN_OLD_TEA_CUP))
+ _vm->_dialogs->show(70615);
+ else if (_action.isAction(VERB_LOOK, NOUN_OLD_VASE))
+ _vm->_dialogs->show(70616);
+ else if (_action.isAction(VERB_LOOK, NOUN_PORTRAIT))
+ _vm->_dialogs->show(70617);
+ else if (_action.isAction(VERB_LOOK, NOUN_NAME_PLATE))
+ _vm->_dialogs->show(70618);
+ else if (_action.isAction(VERB_LOOK, NOUN_WALL))
+ _vm->_dialogs->show(70619);
+ else if (_action.isAction(VERB_LOOK, NOUN_PEDESTAL)) {
+ if (_game._objects[OBJ_VASE]._roomNumber == _scene->_currentSceneId)
+ _vm->_dialogs->show(70620);
+ else if (_game._objects[OBJ_BOTTLE]._roomNumber == _scene->_currentSceneId)
+ _vm->_dialogs->show(70622);
+ else
+ _vm->_dialogs->show(70621);
+ } else if (_action.isAction(VERB_LOOK, NOUN_TELEPORTER))
+ _vm->_dialogs->show(70623);
+ else if (_action.isAction(VERB_LOOK, NOUN_VASE) && (_game._objects[OBJ_VASE]._roomNumber == _scene->_currentSceneId))
+ _vm->_dialogs->show(70624);
+ else if (_action.isAction(VERB_LOOK, NOUN_BOTTLE) && (_action._mainObjectSource == 4))
+ _vm->_dialogs->show(70632);
+ else
+ return;
+
+ _action._inProgress = false;
+}
+
+/*------------------------------------------------------------------------*/
+
+void Scene707::setup() {
+ _game._player._spritesPrefix = "";
+ // The original calls Scene7xx::setAAName()
+ _game._aaName = Resources::formatAAName(5);
+}
+
+void Scene707::enter() {
+ _handSpriteId = _scene->_sprites.addSprites("*REXHAND");
+ teleporterEnter();
+
+ // The original uses Scene7xx_sceneEntrySound
+ if (!_vm->_musicFlag)
+ _vm->_sound->command(2);
+ else
+ _vm->_sound->command(25);
+}
+
+void Scene707::step() {
+ teleporterStep();
+}
+
+void Scene707::actions() {
+ if (teleporterActions()) {
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_LOOK, NOUN_VIEWPORT) || _action.isAction(VERB_PEER_THROUGH, NOUN_VIEWPORT))
+ _vm->_dialogs->show(70710);
+ else if (_action.isAction(VERB_LOOK, NOUN_KEYPAD))
+ _vm->_dialogs->show(70711);
+ else if (_action.isAction(VERB_LOOK, NOUN_DISPLAY))
+ _vm->_dialogs->show(70712);
+ else if (_action.isAction(VERB_LOOK, NOUN_0_KEY) || _action.isAction(VERB_LOOK, NOUN_1_KEY)
+ || _action.isAction(VERB_LOOK, NOUN_2_KEY) || _action.isAction(VERB_LOOK, NOUN_3_KEY)
+ || _action.isAction(VERB_LOOK, NOUN_4_KEY) || _action.isAction(VERB_LOOK, NOUN_5_KEY)
+ || _action.isAction(VERB_LOOK, NOUN_6_KEY) || _action.isAction(VERB_LOOK, NOUN_7_KEY)
+ || _action.isAction(VERB_LOOK, NOUN_8_KEY) || _action.isAction(VERB_LOOK, NOUN_9_KEY)
+ || _action.isAction(VERB_LOOK, NOUN_SMILE_KEY) || _action.isAction(VERB_LOOK, NOUN_ENTER_KEY)
+ || _action.isAction(VERB_LOOK, NOUN_FROWN_KEY))
+ _vm->_dialogs->show(70713);
+ else if (_action.isAction(VERB_LOOK, NOUN_DEVICE) || _action._lookFlag)
+ _vm->_dialogs->show(70714);
+ else
+ return;
+
+ _action._inProgress = false;
+}
+
+/*------------------------------------------------------------------------*/
+
+void Scene710::setup() {
+ _game._player._spritesPrefix = "";
+ setAAName();
+}
+
+void Scene710::enter() {
+ _scene->_userInterface.setup(kInputLimitedSentences);
+
+ if (_game._objects[OBJ_VASE]._roomNumber == 706) {
+ _globals._spriteIndexes[1] = _scene->_sprites.addSprites(formAnimName('g', -1));
+ _globals._sequenceIndexes[1] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[1], false, 6, 0, 0, 0);
+ }
+
+ _game._player._visible = false;
+ _scene->_sequences.addTimer(600, 70);
+
+ sceneEntrySound();
+}
+
+void Scene710::step() {
+ if (_game._trigger == 70) {
+ if (_game._globals[kCityFlooded])
+ _scene->_nextSceneId = 701;
+ else
+ _scene->_nextSceneId = 751;
+ }
+}
+
+void Scene710::actions() {
+ if (_action.isAction(0x46F, 0x27)) {
+ _game._player._stepEnabled = false;
+
+ if (_game._globals[kCityFlooded])
+ _scene->_nextSceneId = 701;
+ else
+ _scene->_nextSceneId = 751;
+
+ _action._inProgress = false;
+ }
+}
+
+/*------------------------------------------------------------------------*/
+
+void Scene711::setup() {
+ // The original was calling Scene7xx::setPlayerSpreitesPrefix()
+ _vm->_sound->command(5);
+ Common::String oldName = _game._player._spritesPrefix;
+ _game._player._spritesPrefix = "";
+ _game._player._scalingVelocity = true;
+
+ if (oldName != _game._player._spritesPrefix)
+ _game._player._spritesChanged = true;
+
+ _vm->_palette->setEntry(16, 10, 63, 63);
+ _vm->_palette->setEntry(17, 10, 45, 45);
+
+ // The original was calling Scene7xx::setAAName()
+ _game._aaName = Resources::formatAAName(5);
+
+ _game._player._spritesPrefix = "";
+}
+
+void Scene711::enter() {
+ if (_globals[kSexOfRex] == REX_FEMALE)
+ _handSpriteId = _scene->_sprites.addSprites("*ROXHAND");
+ else
+ _handSpriteId = _scene->_sprites.addSprites("*REXHAND");
+
+ teleporterEnter();
+
+ // The original was using Scene7xx_SceneEntrySound()
+ if (!_vm->_musicFlag)
+ _vm->_sound->command(2);
+ else
+ _vm->_sound->command(25);
+}
+
+void Scene711::step() {
+ teleporterStep();
+}
+
+void Scene711::actions() {
+ if (teleporterActions())
+ _action._inProgress = false;
+}
+
+/*------------------------------------------------------------------------*/
+
+Scene751::Scene751(MADSEngine *vm) : Scene7xx(vm) {
+ _rexHandingLine = false;
+}
+
+void Scene751::synchronize(Common::Serializer &s) {
+ Scene7xx::synchronize(s);
+
+ s.syncAsByte(_rexHandingLine);
+}
+
+void Scene751::setup() {
+ setPlayerSpritesPrefix();
+ setAAName();
+ _scene->addActiveVocab(NOUN_FISHING_LINE);
+ _scene->addActiveVocab(VERB_WALKTO);
+}
+
+void Scene751::enter() {
+ _globals._spriteIndexes[1] = _scene->_sprites.addSprites("*RM701X0");
+ _globals._spriteIndexes[2] = _scene->_sprites.addSprites(formAnimName('a', 0));
+ _globals._spriteIndexes[3] = _scene->_sprites.addSprites(formAnimName('f', 0));
+ _globals._spriteIndexes[4] = _scene->_sprites.addSprites("*RM202A1");
+
+ if (!_game._visitedScenes._sceneRevisited)
+ _rexHandingLine = false;
+
+ if (_globals[kLineStatus] == 2 || _globals[kLineStatus] == 3) {
+ _globals._sequenceIndexes[3] = _scene->_sequences.startCycle(_globals._spriteIndexes[3], false, -1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 7);
+ int idx = _scene->_dynamicHotspots.add(NOUN_FISHING_LINE, 0xD, _globals._sequenceIndexes[3], Common::Rect(0, 0, 0, 0));
+ _scene->_dynamicHotspots.setPosition(idx, Common::Point(268, 140), FACING_NORTHWEST);
+ }
+
+ _globals._sequenceIndexes[1] = _scene->_sequences.startCycle(_globals._spriteIndexes[1], false, 1);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[1], Common::Point(48, 136));
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 10);
+
+ if (_scene->_priorSceneId == 752) {
+ _game._player._playerPos = Common::Point(309, 138);
+ _game._player._facing = FACING_WEST;
+ } else if (_scene->_priorSceneId == 710) {
+ _game._player._playerPos = Common::Point(154, 129);
+ _game._player._facing = FACING_NORTH;
+ _game._player._visible = false;
+ _game._player._stepEnabled = false;
+ _globals._sequenceIndexes[4] = _scene->_sequences.startCycle(_globals._spriteIndexes[4], false, -2);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[4], Common::Point(155, 129));
+ _scene->_sequences.addTimer(15, 70);
+ } else if (_scene->_priorSceneId != -2) {
+ _game._player._playerPos = Common::Point(22, 131);
+ _game._player._facing = FACING_EAST;
+ _game._player._stepEnabled = false;
+ _scene->_sequences.addTimer(60, 60);
+ } else if (_rexHandingLine) {
+ _game._player._visible = false;
+ _game._player._playerPos = Common::Point(268, 140);
+ _game._player._facing = FACING_NORTHWEST;
+ _game._player._visible = false;
+ _globals._sequenceIndexes[2] = _scene->_sequences.startCycle(_globals._spriteIndexes[2], false, 7);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[2]);
+ } else if (_globals[kLineStatus] == 2) {
+ _globals._sequenceIndexes[3] = _scene->_sequences.startCycle(_globals._spriteIndexes[3], false, -1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 7);
+ int idx = _scene->_dynamicHotspots.add(NOUN_FISHING_LINE, 0xD, _globals._sequenceIndexes[3], Common::Rect(0, 0, 0, 0));
+ _scene->_dynamicHotspots.setPosition(idx, Common::Point(268, 140), FACING_NORTHWEST);
+ }
+
+ if (_scene->_roomChanged) {
+ _game._objects.addToInventory(OBJ_FISHING_LINE);
+ _game._objects.addToInventory(OBJ_BINOCULARS);
+ }
+
+ sceneEntrySound();
+ _game.loadQuoteSet(0x30A, 0x30B, 0x30C, 0x30D, 0x30E, 0);
+
+ if (_globals[kTimebombTimer] > 0)
+ _globals[kTimebombTimer] = 10200;
+}
+
+void Scene751::step() {
+ switch (_game._trigger) {
+ case 70:
+ _scene->_sequences.remove(_globals._sequenceIndexes[4]);
+ _globals._sequenceIndexes[4] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[4], false, 6, 1, 0, 0);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[4], Common::Point(155, 129));
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[4], SEQUENCE_TRIGGER_EXPIRE, 0, 71);
+ break;
+
+ case 71:
+ _scene->_sequences.updateTimeout(-1, _globals._sequenceIndexes[4]);
+ _game._player._visible = true;
+ _game._player._stepEnabled = true;
+ break;
+
+ default:
+ break;
+ }
+
+ if ((_globals[kTimebombTimer] >= 10800) && (_globals[kTimebombStatus] == 1)) {
+ _globals[kTimebombStatus] = 3;
+ _globals[kTimebombTimer] = 0;
+ _globals[kCheckDaemonTimebomb] = false;
+ _scene->_nextSceneId = 620;
+ }
+
+ switch (_game._trigger) {
+ case 60:
+ _vm->_sound->command(16);
+ _scene->_sequences.remove(_globals._sequenceIndexes[1]);
+ _globals._sequenceIndexes[1] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[1], false, 5, 1, 0, 0);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[1], Common::Point(48, 136));
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 10);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[1], SEQUENCE_TRIGGER_EXPIRE, 0, 61);
+ break;
+
+ case 61:
+ _game._player.walk(Common::Point(61, 131), FACING_EAST);
+ _scene->_sequences.addTimer(120, 62);
+ break;
+
+ case 62:
+ _vm->_sound->command(17);
+ _globals._sequenceIndexes[1] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[1], false, 5, 1, 0, 0);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[1], Common::Point(48, 136));
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 10);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[1], SEQUENCE_TRIGGER_EXPIRE, 0, 63);
+ break;
+
+ case 63:
+ _globals._sequenceIndexes[1] = _scene->_sequences.startCycle(_globals._spriteIndexes[1], false, -1);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[1], Common::Point(48, 136));
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 10);
+ _game._player._stepEnabled = true;
+ _scene->_kernelMessages.reset();
+ break;
+
+ default:
+ break;
+ }
+}
+
+void Scene751::preActions() {
+ if (_action.isAction(VERB_LOOK, NOUN_TALL_BUILDING))
+ _game._player.walk(Common::Point(154, 129), FACING_NORTHEAST);
+
+ if (_action.isAction(VERB_LOOK, NOUN_BINOCULARS, 0x470))
+ _game._player.walk(Common::Point(154, 129), FACING_NORTH);
+
+ if (_action.isAction(VERB_WALKTO, NOUN_EAST_END_OF_PLATFORM))
+ _game._player._walkOffScreenSceneId = 752;
+
+ if (!_rexHandingLine)
+ return;
+
+ if (_action.isAction(VERB_LOOK) || _action.isAction(0x87) || _action.isAction(VERB_TALKTO))
+ _game._player._needToWalk = false;
+
+ if ((!_action.isAction(VERB_PUT, NOUN_FISHING_LINE, 0x467) || !_action.isAction(0x170, 0x87, 0x467) || !_action.isAction(0x19, 0x87, 0x467))
+ && (_game._player._needToWalk)) {
+ switch (_game._trigger) {
+ case 0:
+ _game._player._readyToWalk = false;
+ _game._player._stepEnabled = false;
+ _scene->_sequences.remove(_globals._sequenceIndexes[2]);
+ _globals._sequenceIndexes[2] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[2], false, 11, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[2], -1, 7);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[2], SEQUENCE_TRIGGER_EXPIRE, 0, 1);
+ break;
+
+ case 1:
+ _scene->_sequences.updateTimeout(-1, _globals._sequenceIndexes[2]);
+ _game._player._visible = true;
+ _rexHandingLine = false;
+ _game._player._stepEnabled = true;
+ _game._player._readyToWalk = true;
+ break;
+
+ default:
+ break;
+ }
+ }
+}
+
+void Scene751::actions() {
+ if (_action.isAction(VERB_WALK_ALONG, NOUN_PLATFORM))
+ ; // Nothing
+ else if (_action.isAction(VERB_LOOK, NOUN_BINOCULARS, 0x470)) {
+ switch (_game._trigger) {
+ case 0:
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._sequenceIndexes[4] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[4], false, 6, 1, 0, 0);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[4], Common::Point(155, 129));
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[4], SEQUENCE_TRIGGER_EXPIRE, 0, 1);
+ break;
+
+ case 1: {
+ int syncIdx = _globals._sequenceIndexes[4];
+ _globals._sequenceIndexes[4] = _scene->_sequences.startCycle(_globals._spriteIndexes[4], false, -2);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[4], Common::Point(155, 129));
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[4], syncIdx);
+ _scene->_sequences.addTimer(15, 2);
+ }
+ break;
+
+ case 2:
+ _scene->_nextSceneId = 710;
+ break;
+
+ default:
+ break;
+ }
+ } else if (_action.isAction(VERB_STEP_INTO, NOUN_ELEVATOR)) {
+ switch (_game._trigger) {
+ case 0:
+ _game._player._stepEnabled = false;
+ _scene->_sequences.remove(_globals._sequenceIndexes[1]);
+ _vm->_sound->command(16);
+ _globals._sequenceIndexes[1] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[1], false, 5, 1, 0, 0);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[1], Common::Point(48, 136));
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 10);
+ _scene->_kernelMessages.reset();
+ _scene->_kernelMessages.add(Common::Point(0, 0), 0x1110, 34, 0, 120, _game.getQuote(0x30D));
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[1], SEQUENCE_TRIGGER_EXPIRE, 0, 1);
+ break;
+
+ case 1:
+ _game._player.walk(Common::Point(22, 131), FACING_EAST);
+ _scene->_sequences.addTimer(120, 3);
+ break;
+
+ case 3:
+ _vm->_sound->command(17);
+ _globals._sequenceIndexes[1] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[1], false, 5, 1, 0, 0);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[1], Common::Point(48, 136));
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 10);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[1], SEQUENCE_TRIGGER_EXPIRE, 0, 4);
+ break;
+
+ case 4:
+ _globals._sequenceIndexes[1] = _scene->_sequences.startCycle(_globals._spriteIndexes[1], false, -1);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[1], Common::Point(48, 136));
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 10);
+ _scene->_sequences.addTimer(60, 5);
+ break;
+
+ case 5:
+ _game._player._stepEnabled = true;
+ _scene->_nextSceneId = 513;
+ break;
+
+ default:
+ break;
+ }
+ } else if (_action.isAction(VERB_PUT, NOUN_FISHING_LINE, 0x467) || _action.isAction(0x170, 0x87, 0x467) || _action.isAction(0x19, 0x87, 0x467)) {
+ if (_globals[kLineStatus] == 1) {
+ switch (_game._trigger) {
+ case 0:
+ _game._player._visible = false;
+ _game._player._stepEnabled = false;
+ _globals._sequenceIndexes[2] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[2], false, 8, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[2], -1, 6);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[2], -1);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[2], SEQUENCE_TRIGGER_EXPIRE, 0, 1);
+ break;
+
+ case 1: {
+ int syncIdx = _globals._sequenceIndexes[2];
+ _globals._sequenceIndexes[2] = _scene->_sequences.startCycle(_globals._spriteIndexes[2], false, 7);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[2], syncIdx);
+ _scene->_sequences.addTimer(30, 2);
+ }
+ break;
+
+ case 2:
+ _rexHandingLine = true;
+ _scene->_sequences.remove(_globals._sequenceIndexes[2]);
+ _globals._sequenceIndexes[2] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[2], false, 8, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[2], 8, -2);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[2], SEQUENCE_TRIGGER_EXPIRE, 0, 3);
+ break;
+
+ case 3: {
+ _scene->_sequences.updateTimeout(-1, _globals._sequenceIndexes[2]);
+ _game._player._visible = true;
+ _globals._sequenceIndexes[3] = _scene->_sequences.startCycle(_globals._spriteIndexes[3], false, -1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 7);
+ int idx = _scene->_dynamicHotspots.add(NOUN_FISHING_LINE, 0xD, _globals._sequenceIndexes[3], Common::Rect(0, 0, 0, 0));
+ _scene->_dynamicHotspots.setPosition(idx, Common::Point(268, 140), FACING_NORTHWEST);
+ _scene->_kernelMessages.reset();
+ _game._objects.setRoom(OBJ_FISHING_LINE, _scene->_currentSceneId);
+ _rexHandingLine = false;
+ _globals[kLineStatus] = 2;
+ _game._player._stepEnabled = true;
+ _vm->_dialogs->show(75120);
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+ } else if (_action._lookFlag || _action.isAction(VERB_LOOK, NOUN_CITY))
+ _vm->_dialogs->show(75110);
+ else if (_action.isAction(VERB_LOOK, NOUN_ELEVATOR))
+ _vm->_dialogs->show(75112);
+ else if (_action.isAction(VERB_LOOK, NOUN_PLATFORM))
+ _vm->_dialogs->show(75113);
+ else if (_action.isAction(VERB_LOOK, NOUN_CEMENT_PYLON))
+ _vm->_dialogs->show(75114);
+ else if ((_action.isAction(VERB_LOOK, NOUN_HOOK) || _action.isAction(VERB_LOOK, NOUN_FISHING_LINE))
+ && (_globals[kLineStatus] == 2 || _globals[kLineStatus] == 3))
+ _vm->_dialogs->show(75116);
+ else if (_action.isAction(VERB_LOOK, NOUN_HOOK))
+ _vm->_dialogs->show(75115);
+ else if (_action.isAction(VERB_LOOK, NOUN_ROCK))
+ _vm->_dialogs->show(75117);
+ else if (_action.isAction(VERB_TAKE, NOUN_ROCK))
+ _vm->_dialogs->show(75118);
+ else if (_action.isAction(VERB_LOOK, NOUN_EAST_END_OF_PLATFORM))
+ _vm->_dialogs->show(75119);
+ else if (_action.isAction(VERB_TAKE, NOUN_FISHING_LINE) && (_globals[kLineStatus] == 3 || _globals[kLineStatus] == 2))
+ _vm->_dialogs->show(75121);
+ else if (_action.isAction(VERB_LOOK, NOUN_TALL_BUILDING))
+ _vm->_dialogs->show(75122);
+ else if (_action.isAction(0x170, 0x87, 0x316) || _action.isAction(0x19, 0x87, 0x316))
+ _vm->_dialogs->show(75123);
+ else
+ return;
+
+ _action._inProgress = false;
+}
+
+/*------------------------------------------------------------------------*/
+
+Scene752::Scene752(MADSEngine *vm) : Scene7xx(vm) {
+ _cardId = -1;
+}
+
+void Scene752::synchronize(Common::Serializer &s) {
+ Scene7xx::synchronize(s);
+
+ s.syncAsSint16LE(_cardId);
+}
+
+void Scene752::setup() {
+ setPlayerSpritesPrefix();
+ setAAName();
+
+ _scene->addActiveVocab(NOUN_ID_CARD);
+ _scene->addActiveVocab(VERB_WALKTO);
+ _scene->addActiveVocab(VERB_LOOK_AT);
+ _scene->addActiveVocab(NOUN_LASER_BEAM);
+}
+
+void Scene752::enter() {
+ _globals._spriteIndexes[14] = _scene->_sprites.addSprites(formAnimName('l', -1));
+ _globals._spriteIndexes[12] = _scene->_sprites.addSprites("*RXMBD_8");
+
+ if (_scene->_priorSceneId == 751) {
+ _game._player._playerPos = Common::Point(13, 145);
+ _game._player._facing = FACING_EAST;
+ } else if (_scene->_priorSceneId != -2) {
+ _game._player._playerPos = Common::Point(289, 138);
+ _game._player.walk(Common::Point(262, 148), FACING_WEST);
+ _game._player._facing = FACING_WEST;
+ _game._player._visible = true;
+ }
+
+ if (_game._objects[OBJ_ID_CARD]._roomNumber == 752) {
+ _globals._spriteIndexes[13] = _scene->_sprites.addSprites(formAnimName('i', -1));
+ _globals._sequenceIndexes[13] = _scene->_sequences.startCycle(_globals._spriteIndexes[13], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[13], 8);
+ int idx = _scene->_dynamicHotspots.add(NOUN_ID_CARD, VERB_WALKTO, _globals._sequenceIndexes[13], Common::Rect(0, 0, 0, 0));
+ _cardId = _scene->_dynamicHotspots.setPosition(idx, Common::Point(234, 135), FACING_NORTH);
+ }
+
+ if (_game._globals[kLaserHoleIsThere]) {
+ _globals._sequenceIndexes[14] = _scene->_sequences.startCycle(_globals._spriteIndexes[14], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[14], 13);
+ int idx = _scene->_dynamicHotspots.add(NOUN_LASER_BEAM, VERB_LOOK_AT, _globals._sequenceIndexes[14], Common::Rect(0, 0, 0, 0));
+ _scene->_dynamicHotspots.setPosition(idx, Common::Point(215, 130), FACING_NORTHWEST);
+ }
+
+ if (_game._globals[kTeleporterCommand]) {
+ switch(_game._globals[kTeleporterCommand]) {
+ case TELEPORTER_BEAM_OUT:
+ case TELEPORTER_WRONG:
+ case TELEPORTER_STEP_OUT:
+ _game._player._visible = true;
+ _game._player._stepEnabled = true;
+ break;
+ default:
+ break;
+ }
+
+ _game._globals[kTeleporterCommand] = TELEPORTER_NONE;
+ }
+
+ if (_globals._timebombTimer > 0)
+ _globals._timebombTimer = 10800 - 600;
+
+ sceneEntrySound();
+}
+
+void Scene752::step() {
+ if (_globals._timebombTimer >= 10800 && _game._globals[kTimebombStatus] == TIMEBOMB_ACTIVATED) {
+ _globals[kTimebombStatus] = TIMEBOMB_DEAD;
+ _globals._timebombTimer = 0;
+ _globals[kCheckDaemonTimebomb] = false;
+ _scene->_nextSceneId = 620;
+ }
+}
+
+void Scene752::preActions() {
+ if (_action.isAction(VERB_WALKTO, NOUN_WEST_END_OF_PLATFORM)) {
+ _game._player._walkOffScreenSceneId = 751;
+ }
+}
+
+void Scene752::actions() {
+ if (_action.isAction(VERB_WALK_ALONG, NOUN_PLATFORM))
+ ;
+ else if (_action.isAction(VERB_STEP_INTO, NOUN_TELEPORTER)) {
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _scene->_nextSceneId = 711;
+ } else if (_action.isAction(VERB_TAKE, NOUN_ID_CARD) && (!_game._objects.isInInventory(OBJ_ID_CARD) || _game._trigger)) {
+ switch (_game._trigger) {
+ case 0:
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._sequenceIndexes[12] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[12], false, 5, 2, 0, 0);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[12]);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[12], SEQUENCE_TRIGGER_SPRITE, 4, 1);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[12], SEQUENCE_TRIGGER_EXPIRE, 0, 2);
+ break;
+ case 1:
+ _vm->_sound->command(0xF);
+ _scene->_sequences.remove(_globals._sequenceIndexes[13]);
+ _game._objects.addToInventory(OBJ_ID_CARD);
+ _scene->_dynamicHotspots.remove(_cardId);
+ _vm->_dialogs->show(OBJ_ID_CARD, 830);
+ break;
+ case 2:
+ _game._player._visible = true;
+ _game._player._stepEnabled = true;
+ break;
+ default:
+ break;
+ }
+ } else if (_action.isAction(VERB_TAKE, NOUN_BONES) && (_action._mainObjectSource == 4) && (!_game._objects.isInInventory(OBJ_BONES) || _game._trigger)) {
+ switch (_game._trigger) {
+ case 0:
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._sequenceIndexes[12] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[12], false, 5, 2, 0, 0);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[12]);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[12], SEQUENCE_TRIGGER_SPRITE, 4, 1);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[12], SEQUENCE_TRIGGER_EXPIRE, 0, 2);
+ break;
+ case 1:
+ _vm->_sound->command(0xF);
+ if (_game._objects.isInInventory(OBJ_BONE))
+ _game._objects.setRoom(OBJ_BONE, 1);
+ _game._objects.addToInventory(OBJ_BONES);
+ _vm->_dialogs->show(OBJ_BONES, 75221);
+ break;
+ case 2:
+ _scene->_sequences.updateTimeout(-1, _globals._sequenceIndexes[12]);
+ _game._player._visible = true;
+ _game._player._stepEnabled = true;
+ break;
+ default:
+ break;
+ }
+ } else if (_action._lookFlag || _action.isAction(VERB_LOOK, NOUN_CITY)) {
+ if (_globals[kLaserHoleIsThere])
+ _vm->_dialogs->show(75212);
+ else
+ _vm->_dialogs->show(75210);
+ } else if (_action.isAction(VERB_LOOK, NOUN_PLATFORM))
+ _vm->_dialogs->show(75213);
+ else if (_action.isAction(VERB_LOOK, NOUN_CEMENT_BLOCK))
+ _vm->_dialogs->show(75214);
+ else if (_action.isAction(VERB_LOOK, NOUN_ROCK))
+ _vm->_dialogs->show(75215);
+ else if (_action.isAction(VERB_TAKE, NOUN_ROCK))
+ _vm->_dialogs->show(75216);
+ else if (_action.isAction(VERB_LOOK, NOUN_WEST_END_OF_PLATFORM))
+ _vm->_dialogs->show(75217);
+ else if (_action.isAction(VERB_LOOK, NOUN_TELEPORTER))
+ _vm->_dialogs->show(75218);
+ else if ((_action.isAction(VERB_LOOK, NOUN_BONES) || _action.isAction(VERB_LOOK, NOUN_ID_CARD)) && (_action._mainObjectSource == 4)) {
+ if (_game._objects[OBJ_ID_CARD]._roomNumber == 752)
+ _vm->_dialogs->show(75219);
+ else
+ _vm->_dialogs->show(75220);
+ } else if (_action.isAction(VERB_TAKE, NOUN_BONES) && (_action._mainObjectSource == 4)) {
+ if (_game._objects.isInInventory(OBJ_BONES))
+ _vm->_dialogs->show(75222);
+ } else
+ return;
+
+ _action._inProgress = false;
+}
+
+/*------------------------------------------------------------------------*/
+
+} // End of namespace Nebular
+} // End of namespace MADS
diff --git a/engines/mads/nebular/nebular_scenes7.h b/engines/mads/nebular/nebular_scenes7.h
new file mode 100644
index 0000000000..454c76ebe9
--- /dev/null
+++ b/engines/mads/nebular/nebular_scenes7.h
@@ -0,0 +1,238 @@
+/* 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.
+ *
+ */
+
+#ifndef MADS_NEBULAR_SCENES7_H
+#define MADS_NEBULAR_SCENES7_H
+
+#include "common/scummsys.h"
+#include "mads/game.h"
+#include "mads/scene.h"
+#include "mads/nebular/nebular_scenes.h"
+
+namespace MADS {
+
+namespace Nebular {
+
+class Scene7xx : public NebularScene {
+protected:
+ /**
+ * Plays an appropriate sound when entering a scene
+ */
+ void setAAName();
+
+ /**
+ * Updates the prefix used for getting player sprites for the scene
+ */
+ void setPlayerSpritesPrefix();
+
+ void sceneEntrySound();
+
+public:
+ Scene7xx(MADSEngine *vm) : NebularScene(vm) {}
+};
+
+class Scene701: public Scene7xx {
+private:
+ int _fishingLineId;
+
+public:
+ Scene701(MADSEngine *vm);
+ void synchronize(Common::Serializer &s);
+
+ virtual void setup();
+ virtual void enter();
+ virtual void preActions();
+ virtual void actions();
+ virtual void step();
+};
+
+class Scene702: public Scene7xx {
+public:
+ Scene702(MADSEngine *vm) : Scene7xx(vm) {}
+
+ virtual void setup();
+ virtual void enter();
+ virtual void preActions();
+ virtual void actions();
+};
+
+class Scene703: public Scene7xx{
+private:
+ int _monsterMode;
+ int _boatFrame;
+ int _curSequence;
+ int _boatDir;
+
+ bool _useBomb;
+ bool _startMonsterTimer;
+ bool _rexDeathFl;
+ bool _restartTrigger70Fl;
+
+ uint32 _lastFrameTime;
+ uint32 _monsterTime;
+
+ Conversation _dialog1;
+
+ void handleBottleInterface();
+ void setBottleSequence();
+ void handleFillBottle(int quote);
+
+public:
+ Scene703(MADSEngine *vm);
+ void synchronize(Common::Serializer &s);
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+ virtual void actions();
+};
+
+class Scene704: public Scene7xx{
+private:
+ int _bottleHotspotId;
+ int _boatCurrentFrame;
+ int _animationMode;
+ int _boatDirection;
+
+ bool _takeBottleFl;
+
+ Conversation _dialog1;
+
+ void handleFillBottle(int quote);
+ void setBottleSequence();
+ void handleBottleInterface();
+
+public:
+ Scene704(MADSEngine *vm);
+ void synchronize(Common::Serializer &s);
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+ virtual void actions();
+};
+
+class Scene705: public Scene7xx{
+private:
+ Conversation _dialog1;
+
+ void handleFillBottle(int quote);
+ void setBottleSequence();
+ void handleBottleInterface();
+
+public:
+ Scene705(MADSEngine *vm) : Scene7xx(vm) {}
+ void synchronize(Common::Serializer &s);
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+ virtual void actions();
+};
+
+class Scene706: public Scene7xx{
+private:
+ int _vaseHotspotId;
+ int _vaseMode;
+ int _animationMode;
+ int _animationFrame;
+
+ bool _emptyPedestral;
+
+ void handleTakeVase();
+ void handleRexDeath();
+
+public:
+ Scene706(MADSEngine *vm);
+ void synchronize(Common::Serializer &s);
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+ virtual void preActions();
+ virtual void actions();
+};
+
+class Scene707: public SceneTeleporter {
+public:
+ Scene707(MADSEngine *vm) : SceneTeleporter(vm) {}
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+ virtual void actions();
+};
+
+class Scene710: public Scene7xx {
+public:
+ Scene710(MADSEngine *vm) : Scene7xx(vm) {}
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+ virtual void actions();
+};
+
+class Scene711: public SceneTeleporter {
+public:
+ Scene711(MADSEngine *vm) : SceneTeleporter(vm) {}
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+ virtual void actions();
+};
+
+class Scene751: public Scene7xx{
+private:
+ bool _rexHandingLine;
+
+public:
+ Scene751(MADSEngine *vm);
+ void synchronize(Common::Serializer &s);
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+ virtual void preActions();
+ virtual void actions();
+};
+
+class Scene752: public Scene7xx {
+private:
+ int _cardId;
+
+public:
+ Scene752(MADSEngine *vm);
+ void synchronize(Common::Serializer &s);
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+ virtual void preActions();
+ virtual void actions();
+};
+
+} // End of namespace Nebular
+} // End of namespace MADS
+
+#endif /* MADS_NEBULAR_SCENES7_H */
diff --git a/engines/mads/nebular/nebular_scenes8.cpp b/engines/mads/nebular/nebular_scenes8.cpp
new file mode 100644
index 0000000000..c0f24a78fc
--- /dev/null
+++ b/engines/mads/nebular/nebular_scenes8.cpp
@@ -0,0 +1,1524 @@
+/* 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 "mads/mads.h"
+#include "mads/scene.h"
+#include "mads/nebular/nebular_scenes.h"
+#include "mads/nebular/nebular_scenes8.h"
+
+namespace MADS {
+
+namespace Nebular {
+
+void Scene8xx::setPlayerSpritesPrefix() {
+ _vm->_sound->command(5);
+ if ((_globals[kFromCockpit] && !_globals[kExitShip]) ||
+ _scene->_nextSceneId == 804 || _scene->_nextSceneId == 805 ||
+ _scene->_nextSceneId == 808 || _scene->_nextSceneId == 810) {
+ _game._player._spritesPrefix = "";
+ } else
+ _game._player._spritesPrefix = _globals[kSexOfRex] == SEX_FEMALE ? "ROX" : "RXM";
+
+ _vm->_palette->setEntry(16, 0x0A, 0x3F, 0x3F);
+ _vm->_palette->setEntry(17, 0x0A, 0x2D, 0x2D);
+}
+
+void Scene8xx::setAAName() {
+ _game._aaName = Resources::formatAAName(5);
+}
+
+void Scene8xx::sceneEntrySound() {
+ if (!_vm->_musicFlag)
+ _vm->_sound->command(2);
+ else {
+ switch (_scene->_nextSceneId) {
+ case 801:
+ case 802:
+ case 803:
+ case 804:
+ case 806:
+ case 807:
+ case 808:
+ _vm->_sound->command(20);
+ break;
+
+ case 805:
+ _vm->_sound->command(23);
+ break;
+
+ case 810:
+ _vm->_sound->command(10);
+ break;
+
+ default:
+ break;
+ }
+ }
+}
+
+/*------------------------------------------------------------------------*/
+
+Scene801::Scene801(MADSEngine *vm) : Scene8xx(vm) {
+ _walkThroughDoor = false;
+}
+
+void Scene801::synchronize(Common::Serializer &s) {
+ Scene8xx::synchronize(s);
+
+ s.syncAsByte(_walkThroughDoor);
+}
+
+void Scene801::setup() {
+ setPlayerSpritesPrefix();
+ setAAName();
+}
+
+void Scene801::enter() {
+ _globals._spriteIndexes[1] = _scene->_sprites.addSprites(formAnimName('x', 1));
+ _globals._spriteIndexes[2] = _scene->_sprites.addSprites(formAnimName('x', 0));
+ _globals._spriteIndexes[3] = _scene->_sprites.addSprites(formAnimName('x', 2));
+ _globals._spriteIndexes[4] = _scene->_sprites.addSprites(formAnimName('x', 3));
+ _globals._spriteIndexes[5] = _scene->_sprites.addSprites(formAnimName('a', -1));
+
+ if (_scene->_priorSceneId != 802) {
+ _globals._sequenceIndexes[2] = _scene->_sequences.startCycle(_globals._spriteIndexes[2], false, 5);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 13);
+ }
+
+ if ((_globals[kCameFromCut]) && (_globals[kCutX] != 0)) {
+ _game._player._playerPos = Common::Point(_globals[kCutX], _globals[kCutY]);
+ _game._player._facing = (Facing)_globals[kCutFacing];
+ _globals[kCutX] = 0;
+ _globals[kCameFromCut] = false;
+ _globals[kReturnFromCut] = false;
+ _globals[kBeamIsUp] = false;
+ _globals[kForceBeamDown] = false;
+ _globals[kDontRepeat] = false;
+ } else if (_scene->_priorSceneId == 808) {
+ _game._player._playerPos = Common::Point(148, 110);
+ _game._player._facing = FACING_NORTH;
+ } else if (_scene->_priorSceneId == 802) {
+ _game._player._playerPos = Common::Point(307, 111);
+ _game._player.walk(Common::Point(270, 118), FACING_WEST);
+ _game._player._visible = true;
+ } else if ((_scene->_priorSceneId != -2) && !_globals[kTeleporterCommand]) {
+ _game._player._playerPos = Common::Point(8, 117);
+ _game._player.walk(Common::Point(41, 115), FACING_EAST);
+ _game._player._visible = true;
+ }
+
+ _globals[kBetweenRooms] = false;
+
+ if (_globals[kTeleporterCommand]) {
+ _game._player._stepEnabled = false;
+ switch (_globals[kTeleporterCommand]) {
+ case 1:
+ _game._player._playerPos = Common::Point(8, 117);
+ _globals[kTeleporterUnderstood] = true;
+ _globals._sequenceIndexes[1] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[1], false, 8, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[1], 1, 13);
+ _game._triggerSetupMode = SEQUENCE_TRIGGER_DAEMON;
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[1], SEQUENCE_TRIGGER_EXPIRE, 0, 75);
+ _vm->_sound->command(30);
+ break;
+
+ case 2:
+ _game._player._playerPos = Common::Point(8, 117);
+ _globals[kTeleporterUnderstood] = true;
+ _globals._sequenceIndexes[1] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[1], false, 8, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[1], 1, 13);
+ _game._triggerSetupMode = SEQUENCE_TRIGGER_DAEMON;
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[1], SEQUENCE_TRIGGER_EXPIRE, 0, 8090);
+ _vm->_sound->command(30);
+ break;
+
+ case 3:
+ case 4:
+ _game._player._playerPos = Common::Point(8, 117);
+ _game._player.walk(Common::Point(41, 115), FACING_EAST);
+ _game._player._visible = true;
+ _game._player._stepEnabled = true;
+ break;
+
+ default:
+ break;
+ }
+ _globals[kTeleporterCommand] = 0;
+ }
+
+ _walkThroughDoor = false;
+ if (_scene->_priorSceneId == 802) {
+ _game._player._stepEnabled = false;
+ _walkThroughDoor = true;
+ }
+
+ _globals._sequenceIndexes[3] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[3], false, 11, 0, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[3], -1, -2);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 14);
+
+ _globals._sequenceIndexes[4] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[4], false, 9, 0, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[4], -1, -2);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[4], 14);
+
+ sceneEntrySound();
+}
+
+void Scene801::step() {
+ if (_game._trigger == 75) {
+ if (_globals[kSexOfRex] == REX_FEMALE) {
+ _globals._sequenceIndexes[5] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[5], false, 8, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[5], 1, 8);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[5], SEQUENCE_TRIGGER_EXPIRE, 0, 140);
+ } else {
+ _game._player._stepEnabled = true;
+ _game._player._visible = true;
+ _game._player._playerPos = Common::Point(8, 117);
+ _game._player.walk(Common::Point(41, 115), FACING_EAST);
+ }
+ }
+
+ if (_game._trigger == 140) {
+ _vm->_sound->command(27);
+ _globals._sequenceIndexes[5] = _scene->_sequences.startCycle(_globals._spriteIndexes[5], false, 8);
+ _scene->_sequences.addTimer(100, 141);
+ }
+
+ if (_game._trigger == 141) {
+ _scene->_reloadSceneFlag = true;
+ _scene->_nextSceneId = _scene->_priorSceneId;
+ _globals[kTeleporterCommand] = 0;
+ }
+
+ if (_game._trigger == 80) {
+ _globals[kTeleporterCommand] = 1;
+ _scene->_nextSceneId = _globals[kTeleporterDestination];
+ _scene->_reloadSceneFlag = true;
+ }
+
+ if (_walkThroughDoor && (_game._player._playerPos == Common::Point(270, 118))) {
+ _game._player._stepEnabled = false;
+ _globals._sequenceIndexes[2] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[2], false, 4, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[2], 1, 5);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 10);
+ _walkThroughDoor = false;
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[2], SEQUENCE_TRIGGER_EXPIRE, 0, 120);
+ }
+
+ if (_game._trigger == 120) {
+ _vm->_sound->command(12);
+ _globals._sequenceIndexes[2] = _scene->_sequences.startCycle(_globals._spriteIndexes[2], false, 5);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 10);
+ _game._player._stepEnabled = true;
+ }
+
+ if (_game._trigger == 90) {
+ _game._player.walk(Common::Point(307, 111), FACING_EAST);
+ _scene->_sequences.addTimer(80, 130);
+ }
+
+ if (_game._trigger == 130) {
+ _vm->_sound->command(12);
+ _scene->_sequences.remove(_globals._sequenceIndexes[2]);
+ _globals._sequenceIndexes[2] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[2], false, 4, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[2], 1, 5);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 10);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[2], SEQUENCE_TRIGGER_EXPIRE, 0, 110);
+ }
+
+ if (_game._trigger == 110) {
+ _globals._sequenceIndexes[2] = _scene->_sequences.startCycle(_globals._spriteIndexes[2], false, 5);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 10);
+ _scene->_nextSceneId = 802;
+ }
+}
+
+void Scene801::preActions() {
+ if (_action.isAction(VERB_LOOK, NOUN_CONTROL_PANEL)) {
+ _game._player.walk(Common::Point(148, 110), FACING_NORTH);
+ _game._player._needToWalk = true;
+ _game._player._readyToWalk = true;
+ }
+
+ if (_action.isAction(VERB_WALK_INSIDE, NOUN_TELEPORTER) && _globals[kBeamIsUp]) {
+ _globals[kCutX] = _game._player._playerPos.x;
+ _globals[kCutY] = _game._player._playerPos.y;
+ _globals[kCutFacing] = _game._player._facing;
+ _globals[kForceBeamDown] = true;
+ _globals[kDontRepeat] = true;
+ _scene->_nextSceneId = 803;
+ }
+}
+
+void Scene801::actions() {
+ if (_action.isAction(VERB_LOOK, NOUN_CONTROL_PANEL))
+ _scene->_nextSceneId = 808;
+ else if (_action.isAction(VERB_WALK_INSIDE, NOUN_TELEPORTER)) {
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _scene->_nextSceneId = 807;
+ } else if (_action.isAction(VERB_WALK_THROUGH, NOUN_DOOR) && (_game._player._playerPos == Common::Point(270, 118))) {
+ _game._player._stepEnabled = false;
+ _game._player._facing = FACING_EAST;
+ _game._player.selectSeries();
+ _globals[kBetweenRooms] = true;
+ _game._triggerSetupMode = SEQUENCE_TRIGGER_DAEMON;
+ _scene->_sequences.remove(_globals._sequenceIndexes[2]);
+ _globals._sequenceIndexes[2] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[2], false, 4, 1, 0, 0);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[2], SEQUENCE_TRIGGER_EXPIRE, 0, 90);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[2], 1, 5);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 13);
+ _vm->_sound->command(11);
+ } else if (_action.isAction(VERB_LOOK, NOUN_CEILING))
+ _vm->_dialogs->show(80110);
+ else if (_action.isAction(VERB_LOOK, NOUN_MONITOR))
+ _vm->_dialogs->show(80111);
+ else if (_action.isAction(VERB_LOOK, NOUN_TELEPORTER))
+ _vm->_dialogs->show(80112);
+ else if (_action.isAction(VERB_LOOK, NOUN_EQUIPMENT) || _action._lookFlag)
+ _vm->_dialogs->show(80113);
+ else if (_action.isAction(VERB_LOOK, NOUN_SPEAKER))
+ _vm->_dialogs->show(80114);
+ else if (_action.isAction(VERB_LOOK, NOUN_EYE_CHART))
+ _vm->_dialogs->show(80115);
+ else if (_action.isAction(VERB_LOOK, NOUN_WALL))
+ _vm->_dialogs->show(80116);
+ else if (_action.isAction(VERB_LOOK, NOUN_DOOR))
+ _vm->_dialogs->show(80117);
+ else
+ return;
+
+ _action._inProgress = false;
+}
+
+/*------------------------------------------------------------------------*/
+
+void Scene802::setup() {
+ setPlayerSpritesPrefix();
+ setAAName();
+ _scene->addActiveVocab(NOUN_SHIELD_MODULATOR);
+ _scene->addActiveVocab(VERB_WALKTO);
+ _scene->addActiveVocab(NOUN_REMOTE);
+}
+
+void Scene802::enter() {
+ _globals._spriteIndexes[2] = _scene->_sprites.addSprites("*RXMRC_8");
+ _globals._spriteIndexes[1] = _scene->_sprites.addSprites(formAnimName('f', 2));
+ _globals._spriteIndexes[3] = _scene->_sprites.addSprites(formAnimName('f', 0));
+ _globals._spriteIndexes[4] = _scene->_sprites.addSprites(formAnimName('f', 1));
+ _globals._spriteIndexes[5] = _scene->_sprites.addSprites("*RXMBD_8");
+ _globals[kBetweenRooms] = false;
+
+ if ((_globals[kCameFromCut]) && (_globals[kCutX] != 0)) {
+ _game._player._playerPos.x = _globals[kCutX];
+ _game._player._playerPos.y = _globals[kCutY];
+ _game._player._facing = (Facing)_globals[kCutFacing];
+ _globals[kCutX] = 0;
+ _globals[kCameFromCut] = false;
+ _globals[kReturnFromCut] = false;
+ _globals[kBeamIsUp] = false;
+ _globals[kForceBeamDown] = false;
+ _globals[kDontRepeat] = false;
+ _globals[kAntigravClock] = _scene->_frameStartTime;
+ } else if (_scene->_priorSceneId == 801) {
+ _game._player._playerPos = Common::Point(15, 129);
+ _game._player._facing = FACING_EAST;
+ } else if (_scene->_priorSceneId == 803) {
+ _game._player._playerPos = Common::Point(303, 119);
+ _game._player._facing = FACING_WEST;
+
+ } else if (_scene->_priorSceneId != -2) {
+ _game._player._playerPos = Common::Point(15, 129);
+ _game._player._facing = FACING_EAST;
+ }
+
+ _game._player._visible = true;
+
+
+
+ if (_globals[kHasWatchedAntigrav] && !_globals[kRemoteSequenceRan]) {
+ _game._triggerSetupMode = SEQUENCE_TRIGGER_DAEMON;
+ _scene->_sequences.addTimer(200, 70);
+ }
+
+ if ((_globals[kRemoteOnGround]) && (!_game._objects.isInInventory(OBJ_REMOTE))) {
+ _globals._sequenceIndexes[4] = _scene->_sequences.startCycle(_globals._spriteIndexes[4], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[4], 8);
+ int idx = _scene->_dynamicHotspots.add(NOUN_REMOTE, 0xD,_globals._sequenceIndexes[4], Common::Rect(0, 0, 0, 0));
+ _scene->_dynamicHotspots.setPosition(idx, Common::Point(107, 99), FACING_NORTH);
+ }
+
+ if (!_game._objects.isInInventory(OBJ_SHIELD_MODULATOR) && !_globals[kShieldModInstalled]) {
+ _globals._sequenceIndexes[1] = _scene->_sequences.startCycle(_globals._spriteIndexes[1], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 8);
+ int idx = _scene->_dynamicHotspots.add(NOUN_SHIELD_MODULATOR, 0xD, _globals._sequenceIndexes[1], Common::Rect(0, 0, 0, 0));
+ _scene->_dynamicHotspots.setPosition(idx, Common::Point(93, 97), FACING_NORTH);
+ }
+ sceneEntrySound();
+}
+
+void Scene802::step() {
+ if (_game._trigger == 70) {
+ _game._player._stepEnabled = false;
+ _globals._sequenceIndexes[3] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[3], false, 8, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[3], 1, 19);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[3], SEQUENCE_TRIGGER_EXPIRE, 0, 71);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[3], SEQUENCE_TRIGGER_SPRITE, 4, 72);
+ }
+
+ if (_game._trigger == 71) {
+ _globals._sequenceIndexes[4] = _scene->_sequences.startCycle(_globals._spriteIndexes[4], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[4], 8);
+ int idx = _scene->_dynamicHotspots.add(NOUN_REMOTE, 0xD, _globals._sequenceIndexes[4], Common::Rect(0, 0, 0, 0));
+ _scene->_dynamicHotspots.setPosition(idx, Common::Point(107, 99), FACING_NORTH);
+
+ _globals[kRemoteSequenceRan] = true;
+ _globals[kRemoteOnGround] = true;
+ _game._player._stepEnabled = true;
+ }
+
+ if (_game._trigger == 72)
+ _vm->_sound->command(13);
+}
+
+void Scene802::preActions() {
+ if (_action.isAction(VERB_WALK_TOWARDS, NOUN_BUILDING_TO_WEST))
+ _game._player._walkOffScreenSceneId = 801;
+
+ if (_action.isAction(VERB_WALK_DOWN, NOUN_PATH_TO_EAST)) {
+ _game._player._walkOffScreenSceneId = 803;
+ _globals[kForceBeamDown] = false;
+ }
+
+ if (_action.isAction(VERB_TAKE, NOUN_SHIP))
+ _game._player._needToWalk = false;
+}
+
+void Scene802::actions() {
+ if (_action.isAction(VERB_TAKE, NOUN_SHIELD_MODULATOR) && !_game._objects.isInInventory(OBJ_SHIELD_MODULATOR)) {
+ switch (_game._trigger) {
+ case (0):
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._sequenceIndexes[2] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[2], true, 7, 2, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[2], 1, 2);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[2]);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[2], SEQUENCE_TRIGGER_SPRITE, 2, 1);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[2], SEQUENCE_TRIGGER_EXPIRE, 0, 2);
+ break;
+
+ case 1:
+ _scene->_sequences.remove(_globals._sequenceIndexes[1]);
+ _vm->_sound->command(9);
+ break;
+
+ case 2:
+ _game._player._priorTimer = _scene->_frameStartTime + _game._player._ticksAmount;
+ _game._player._visible = true;
+ _scene->_sequences.addTimer(20, 3);
+ break;
+
+ case 3:
+ _game._player._stepEnabled = true;
+ _game._objects.addToInventory(OBJ_SHIELD_MODULATOR);
+ _vm->_dialogs->showItem(OBJ_SHIELD_MODULATOR, 80215);
+ break;
+
+ default:
+ break;
+ }
+ } else if ((_action.isAction(VERB_TAKE, NOUN_REMOTE)) && (!_game._objects.isInInventory(OBJ_REMOTE))) {
+ switch (_game._trigger) {
+ case (0):
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._sequenceIndexes[5] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[5], true, 7, 2, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[5], 1, 4);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[5]);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[5], SEQUENCE_TRIGGER_SPRITE, 4, 1);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[5], SEQUENCE_TRIGGER_EXPIRE, 0, 2);
+ break;
+
+ case 1:
+ _scene->_sequences.remove(_globals._sequenceIndexes[4]);
+ _vm->_sound->command(9);
+ _globals[kRemoteOnGround] = false;
+ break;
+
+ case 2:
+ _game._player._priorTimer = _scene->_frameStartTime + _game._player._ticksAmount;
+ _game._player._visible = true;
+ _scene->_sequences.addTimer(20, 3);
+ break;
+
+ case 3:
+ _game._player._stepEnabled = true;
+ _game._objects.addToInventory(OBJ_REMOTE);
+ _vm->_dialogs->showItem(OBJ_REMOTE, 80223);
+ break;
+
+ default:
+ break;
+ }
+ } else if (!_globals[kRemoteOnGround] && (_game._objects.isInInventory(OBJ_SHIELD_MODULATOR) || _globals[kShieldModInstalled])
+ && (_action.isAction(VERB_LOOK, NOUN_LAUNCH_PAD) || _action._lookFlag))
+ _vm->_dialogs->show(80210);
+ else if (!_globals[kRemoteOnGround]&& !_game._objects.isInInventory(OBJ_SHIELD_MODULATOR) && !_globals[kShieldModInstalled]
+ && (_action.isAction(VERB_LOOK, NOUN_LAUNCH_PAD) || _action._lookFlag))
+ _vm->_dialogs->show(80211);
+ else if (_globals[kRemoteOnGround] && !_game._objects.isInInventory(OBJ_SHIELD_MODULATOR) && !_globals[kShieldModInstalled]
+ && (_action.isAction(VERB_LOOK, NOUN_LAUNCH_PAD) || _action._lookFlag))
+ _vm->_dialogs->show(80213);
+ else if (_globals[kRemoteOnGround] && (_game._objects.isInInventory(OBJ_SHIELD_MODULATOR) || _globals[kShieldModInstalled])
+ && (_action.isAction(VERB_LOOK, NOUN_LAUNCH_PAD) || _action._lookFlag))
+ _vm->_dialogs->show(80212);
+ else if (!_game._objects.isInInventory(OBJ_SHIELD_MODULATOR) && !_globals[kShieldModInstalled] && _action.isAction(VERB_LOOK, NOUN_SHIELD_MODULATOR))
+ _vm->_dialogs->show(80214);
+ else if (_globals[kRemoteOnGround] && _action.isAction(VERB_LOOK, NOUN_REMOTE))
+ _vm->_dialogs->show(80216);
+ else if (_action.isAction(VERB_LOOK, NOUN_SHIP)) {
+ if ((!_game._objects.isInInventory(OBJ_SHIELD_MODULATOR)) && (!_globals[kShieldModInstalled]))
+ _vm->_dialogs->show(80218);
+ else
+ _vm->_dialogs->show(80217);
+ } else if (_action.isAction(VERB_LOOK, NOUN_BUSHES))
+ _vm->_dialogs->show(80219);
+ else if (_action.isAction(VERB_LOOK, NOUN_PATH_TO_EAST))
+ _vm->_dialogs->show(80220);
+ else if (_action.isAction(VERB_LOOK, NOUN_SKY))
+ _vm->_dialogs->show(80221);
+ else if (_action.isAction(VERB_TAKE, NOUN_SHIP))
+ _vm->_dialogs->show(80222);
+ else if (_action.isAction(VERB_LOOK, NOUN_TREE) || _action.isAction(VERB_LOOK, NOUN_TREES))
+ _vm->_dialogs->show(80224);
+ else if (_action.isAction(VERB_LOOK, NOUN_BUILDING_TO_WEST))
+ _vm->_dialogs->show(80225);
+ else
+ return;
+
+ _action._inProgress = false;
+}
+
+/*------------------------------------------------------------------------*/
+
+void Scene803::setup() {
+ setPlayerSpritesPrefix();
+ setAAName();
+ _scene->addActiveVocab(NOUN_GUTS);
+ _scene->addActiveVocab(VERB_WALKTO);
+
+ if ((!_globals[kFromCockpit] && _globals[kReturnFromCut] && !_globals[kBeamIsUp])
+ || (_globals[kFromCockpit] && !_globals[kExitShip])) {
+ _game._player._spritesPrefix = "";
+ _game._player._spritesChanged = true;
+ }
+}
+
+void Scene803::enter() {
+ _globals[kBetweenRooms] = false;
+ _game._player._visible = false;
+ _globals._spriteIndexes[1] = _scene->_sprites.addSprites(formAnimName('f', 1));
+ _globals._spriteIndexes[9] = _scene->_sprites.addSprites("*RXMBD_2");
+ _globals._spriteIndexes[6] = _scene->_sprites.addSprites(formAnimName('d', 1));
+
+ _game.loadQuoteSet(0x31B, 0x31C, 0x31D, 0x31E, 0x31F, 0x320, 0x321, 0x322, 0);
+
+ if (_globals[kHoppyDead]) {
+ _globals._spriteIndexes[7] = _scene->_sprites.addSprites(formAnimName('e', 1));
+ _globals._sequenceIndexes[7] = _scene->_sequences.startCycle(_globals._spriteIndexes[7], false, 1);
+ int idx = _scene->_dynamicHotspots.add(NOUN_GUTS, 0xD, _globals._sequenceIndexes[7], Common::Rect(0, 0, 0, 0));
+ _scene->_dynamicHotspots.setPosition(idx, Common::Point(66, 123), FACING_SOUTH);
+ }
+
+ if (!_globals[kBeamIsUp] && !_globals[kReturnFromCut] && (!_globals[kFromCockpit] || _globals[kExitShip])) {
+ _globals._sequenceIndexes[1] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[1], false, 8, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[1], 2, 2);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 1);
+ }
+
+ if (!_globals[kFromCockpit]) {
+ if (!_globals[kReturnFromCut]) {
+ if (_scene->_priorSceneId != -2) {
+ _game._player._playerPos = Common::Point(15, 130);
+ _game._player._facing = FACING_EAST;
+ }
+ _game._player._visible = true;
+ } else if (!_globals[kBeamIsUp]){
+ _globals._spriteIndexes[3] = _scene->_sprites.addSprites(formAnimName('a', 1));
+ _globals._spriteIndexes[2] = _scene->_sprites.addSprites(formAnimName('a', 3));
+ _globals._spriteIndexes[4] = _scene->_sprites.addSprites(formAnimName('a', 2));
+ _game._player._visible = false;
+ _game._player._stepEnabled = false;
+ _globals._sequenceIndexes[3] = _scene->_sequences.startCycle(_globals._spriteIndexes[3], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 15);
+ _globals._sequenceIndexes[3] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[3], false, 8, 1, 0, 0);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 1);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[3], SEQUENCE_TRIGGER_EXPIRE, 0, 80);
+ _vm->_sound->command(14);
+ }
+
+ if (_globals[kBeamIsUp] && !_globals[kReturnFromCut]){
+ if (_globals[kForceBeamDown])
+ _game._player._visible = false;
+ else
+ _game._player._visible = true;
+
+ _globals._spriteIndexes[5] = _scene->_sprites.addSprites(formAnimName('b', 1));
+ _vm->_sound->command(15);
+ _game._player._stepEnabled = false;
+ _globals._sequenceIndexes[5] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[5], false, 12, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[5], 1, 6);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[5], 1);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[5], SEQUENCE_TRIGGER_EXPIRE, 0, 100);
+ }
+ } else if (!_globals[kExitShip]) {
+ if (!_globals[kBeamIsUp]) {
+ _globals._spriteIndexes[3] = _scene->_sprites.addSprites(formAnimName('a', 1));
+ _game._player._visible = false;
+ _game._player._stepEnabled = false;
+ _globals._sequenceIndexes[3] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[3], false, 8, 1, 0, 0);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 1);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[3], SEQUENCE_TRIGGER_EXPIRE, 0, 130);
+ _vm->_sound->command(14);
+ } else {
+ _globals._spriteIndexes[8] = _scene->_sprites.addSprites(formAnimName('c', 1));
+ _game._player._visible = false;
+ _game._player._stepEnabled = false;
+ _globals._sequenceIndexes[8] = _scene->_sequences.startCycle(_globals._spriteIndexes[8], false, 1);
+ _globals._sequenceIndexes[8] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[8], false, 8, 1, 0, 0);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[8], 1);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[8], SEQUENCE_TRIGGER_EXPIRE, 0, 140);
+ }
+ } else {
+ _game._player._stepEnabled = false;
+ _game._player._playerPos = Common::Point(197, 96);
+ _game._player._facing = FACING_SOUTHWEST;
+ _game._player._visible = true;
+ _globals._spriteIndexes[6] = _scene->_sprites.addSprites(formAnimName('d', 1));
+ _globals._sequenceIndexes[6] = _scene->_sequences.startCycle(_globals._spriteIndexes[6], false, 19);
+ _scene->_sequences.addTimer(1, 150);
+ }
+
+ sceneEntrySound();
+}
+
+void Scene803::step() {
+ if (_game._trigger == 120) {
+ _globals._sequenceIndexes[6] = _scene->_sequences.startCycle(_globals._spriteIndexes[6], false, 19);
+ _scene->_nextSceneId = 804;
+ }
+
+ if (_game._trigger == 100) {
+ _globals._sequenceIndexes[1] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[1], false, 8, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[1], 2, 2);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 1);
+ if (!_globals[kHoppyDead]) {
+ _globals._sequenceIndexes[5] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[5], false, 7, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[5], 7, 12);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[5],SEQUENCE_TRIGGER_EXPIRE, 0, 101);
+ } else {
+ _globals._sequenceIndexes[5] = _scene->_sequences.startCycle(_globals._spriteIndexes[5], false, -2);
+ int idx = _scene->_dynamicHotspots.add(NOUN_GUTS, 0xD, _globals._sequenceIndexes[5], Common::Rect(0, 0, 0, 0));
+ _scene->_dynamicHotspots.setPosition(idx, Common::Point(66, 123), FACING_SOUTH);
+ _vm->_sound->command(16);
+ _globals[kCameFromCut] = true;
+ _globals[kBeamIsUp] = false;
+ _globals[kReturnFromCut] = false;
+ _globals[kDontRepeat] = false;
+ _globals[kHoppyDead] = true;
+ _globals[kHasWatchedAntigrav] = true;
+
+ if (_globals[kForceBeamDown])
+ _scene->_nextSceneId = _scene->_priorSceneId;
+ else
+ _game._player._stepEnabled = true;
+ }
+ }
+
+ if (_game._trigger == 101) {
+ _globals._sequenceIndexes[5] = _scene->_sequences.startCycle(_globals._spriteIndexes[5], false, -2);
+ int idx = _scene->_dynamicHotspots.add(NOUN_GUTS, 0xD, _globals._sequenceIndexes[5], Common::Rect(0, 0, 0, 0));
+ _scene->_dynamicHotspots.setPosition(idx, Common::Point(66, 123), FACING_SOUTH);
+ _vm->_sound->command(16);
+ _globals[kCameFromCut] = true;
+ _globals[kBeamIsUp] = false;
+ _globals[kReturnFromCut] = false;
+ _globals[kDontRepeat] = false;
+ _globals[kHoppyDead] = true;
+ _globals[kHasWatchedAntigrav] = true;
+
+ if (_globals[kForceBeamDown])
+ _scene->_nextSceneId = _scene->_priorSceneId;
+ else
+ _game._player._stepEnabled = true;
+ }
+
+ if (_game._trigger == 80) {
+ if (!_globals[kHoppyDead])
+ _scene->_sequences.addTimer(350, 70);
+
+ _globals._sequenceIndexes[4] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[4], false, 12, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[4], 1, 3);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[4], SEQUENCE_TRIGGER_EXPIRE, 0, 90);
+ }
+
+ if (_game._trigger == 70) {
+ _globals._sequenceIndexes[2] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[2], false, 8, 1, 0, 0);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[2], SEQUENCE_TRIGGER_EXPIRE, 0, 71);
+ _vm->_sound->command(31);
+ }
+
+ if (_game._trigger == 71)
+ _scene->_sequences.addTimer(200, 110);
+
+ if (_game._trigger == 90) {
+ int syncIdx = _globals._sequenceIndexes[4];
+ _globals._sequenceIndexes[4] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[4], false, 15, 0, 0, 0);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[4], syncIdx);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[4], 4, 9);
+ if (_globals[kHoppyDead])
+ _scene->_sequences.addTimer(200, 110);
+ }
+
+ if (_game._trigger == 110)
+ _scene->_nextSceneId = 808;
+
+ if (_game._trigger == 130) {
+ _globals[kBeamIsUp] = true;
+ _scene->_nextSceneId = 804;
+ }
+
+ if (_game._trigger == 140) {
+ if (!_globals[kWindowFixed]) {
+ _scene->_nextSceneId = 810;
+ _globals[kInSpace] = true;
+ } else {
+ if (!_globals[kShieldModInstalled])
+ _game._winStatus = 1;
+ else if (!_globals[kTargetModInstalled])
+ _game._winStatus = 2;
+ else
+ _game._winStatus = 3;
+
+ _vm->quitGame();
+ }
+ }
+
+ if (_game._trigger == 150) {
+ _scene->_sequences.remove(_globals._sequenceIndexes[6]);
+ _vm->_sound->command(18);
+ _globals._sequenceIndexes[6] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[6], false, 8, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[6], 1, 19);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[6], 4);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[6], SEQUENCE_TRIGGER_EXPIRE, 0, 151);
+ }
+
+ if (_game._trigger == 151) {
+ _globals[kBeamIsUp] = false;
+ _globals[kFromCockpit] = false;
+ _globals[kExitShip] = false;
+ _game._player._stepEnabled = true;
+ }
+}
+
+void Scene803::preActions() {
+ if (_action.isAction(VERB_WALK_DOWN, NOUN_PATH_TO_WEST))
+ _game._player._walkOffScreenSceneId = 802;
+
+ if (_action.isAction(VERB_TAKE, NOUN_SHIP))
+ _game._player._needToWalk = false;
+}
+
+void Scene803::actions() {
+ if (_action.isAction(VERB_TAKE, NOUN_GUTS)) {
+ switch (_game._trigger) {
+ case 0:
+ _game._player._stepEnabled = false;
+ _game._player._visible = false;
+ _globals._sequenceIndexes[9] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[9], true, 6, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[9], 1, 4);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[9]);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[9], SEQUENCE_TRIGGER_EXPIRE, 0, 160);
+ break;
+
+ case 160: {
+ int syncIdx = _globals._sequenceIndexes[9];
+ _globals._sequenceIndexes[9] = _scene->_sequences.startCycle(_globals._spriteIndexes[9], false, 4);
+ _scene->_sequences.updateTimeout(_globals._sequenceIndexes[9], syncIdx);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[9]);
+ _scene->_sequences.addTimer(60, 161);
+ }
+ break;
+
+ case 161: {
+ int quoteId = 0x31A + _vm->getRandomNumber(1, 8);
+ _scene->_kernelMessages.add(Common::Point(64, 67), 0x1110, 32, 0, 80, _game.getQuote(quoteId));
+ _scene->_sequences.addTimer(60, 162);
+ }
+ break;
+
+ case 162:
+ _scene->_sequences.remove(_globals._sequenceIndexes[9]);
+ _globals._sequenceIndexes[9] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[9], true, 6, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[9], 1, 4);
+ _scene->_sequences.setMsgLayout(_globals._sequenceIndexes[9]);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[9], SEQUENCE_TRIGGER_EXPIRE, 0, 163);
+ break;
+
+ case 163:
+ _game._player._priorTimer = _scene->_frameStartTime + _game._player._ticksAmount;
+ _game._player._visible = true;
+ _game._player._stepEnabled = true;
+ break;
+
+ default:
+ break;
+ }
+ } else if (_action.isAction(VERB_ENTER, NOUN_SHIP)) {
+ _vm->_sound->command(17);
+ _game._player._stepEnabled = false;
+ _game._triggerSetupMode = SEQUENCE_TRIGGER_DAEMON;
+ _globals._sequenceIndexes[6] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[6], false, 8, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[6], 1, 19);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[6], 4);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[6], SEQUENCE_TRIGGER_EXPIRE, 0, 120);
+ _globals[kBeamIsUp] = false;
+ } else if (_action.isAction(VERB_LOOK, NOUN_LAUNCH_PAD))
+ _vm->_dialogs->show(80310);
+ else if (_action._lookFlag)
+ _vm->_dialogs->show(80310);
+ else if (_action.isAction(VERB_LOOK, NOUN_PAD_TO_WEST))
+ _vm->_dialogs->show(80311);
+ else if (_action.isAction(VERB_LOOK, NOUN_GUTS)) {
+ if (_game._storyMode == STORYMODE_NICE)
+ _vm->_dialogs->show(80312);
+ else
+ _vm->_dialogs->show(80313);
+ } else if (_action.isAction(VERB_LOOK, NOUN_BUSHES))
+ _vm->_dialogs->show(80315);
+ else if (_action.isAction(VERB_LOOK, NOUN_SHIP))
+ _vm->_dialogs->show(80317);
+ else if (_action.isAction(VERB_LOOK, NOUN_TOWER))
+ _vm->_dialogs->show(80318);
+ else if (_action.isAction(VERB_LOOK, NOUN_TREE) || _action.isAction(VERB_LOOK, NOUN_TREES))
+ _vm->_dialogs->show(80319);
+ else if (_action.isAction(VERB_LOOK, NOUN_SKY))
+ _vm->_dialogs->show(80320);
+ else if (_action.isAction(VERB_TAKE, NOUN_SHIP))
+ _vm->_dialogs->show(80321);
+ else
+ return;
+
+ _action._inProgress = false;
+}
+
+/*------------------------------------------------------------------------*/
+
+Scene804::Scene804(MADSEngine *vm) : Scene8xx(vm) {
+ _messWithThrottle = false;
+ _movingThrottle = false;
+ _throttleGone = false;
+ _dontPullThrottleAgain = false;
+ _pullThrottleReally = false;
+ _alreadyOrgan = false;
+ _alreadyPop = false;
+
+ _throttleCounter = 0;
+ _resetFrame = -1;
+}
+
+void Scene804::synchronize(Common::Serializer &s) {
+ Scene8xx::synchronize(s);
+
+ s.syncAsByte(_messWithThrottle);
+ s.syncAsByte(_movingThrottle);
+ s.syncAsByte(_throttleGone);
+ s.syncAsByte(_dontPullThrottleAgain);
+ s.syncAsByte(_pullThrottleReally);
+ s.syncAsByte(_alreadyOrgan);
+ s.syncAsByte(_alreadyPop);
+
+ s.syncAsSint16LE(_resetFrame);
+ s.syncAsUint32LE(_throttleCounter);
+}
+
+void Scene804::setup() {
+ Scene8xx::setPlayerSpritesPrefix();
+ Scene8xx::setAAName();
+}
+
+void Scene804::enter() {
+ _messWithThrottle = false;
+ _throttleCounter = 0;
+ _movingThrottle = false;
+ _throttleGone = false;
+ _dontPullThrottleAgain = false;
+ _resetFrame = -1;
+ _pullThrottleReally = false;
+ _alreadyOrgan = false;
+ _alreadyPop = false;
+
+
+ if (_globals[kCopyProtectFailed]) {
+ // Copy protection failed
+ _globals[kInSpace] = true;
+ _globals[kWindowFixed] = 0;
+ }
+
+ _globals._spriteIndexes[4] = _scene->_sprites.addSprites(formAnimName('x', 0));
+ _globals._spriteIndexes[5] = _scene->_sprites.addSprites(formAnimName('x', 1));
+ _globals._spriteIndexes[6] = _scene->_sprites.addSprites(formAnimName('x', 2));
+ _globals._spriteIndexes[1] = _scene->_sprites.addSprites(formAnimName('x', 3));
+ _globals._spriteIndexes[7] = _scene->_sprites.addSprites(formAnimName('x', 4));
+ _globals._spriteIndexes[8] = _scene->_sprites.addSprites(formAnimName('f', 1));
+
+ _game.loadQuoteSet(791, 0);
+
+ if (_globals[kInSpace]) {
+ if (_globals[kWindowFixed]) {
+ _globals._sequenceIndexes[5] = _scene->_sequences.startCycle(_globals._spriteIndexes[5], 0, 1);
+ _scene->_sequences.addTimer(60, 100);
+ } else {
+ _globals._sequenceIndexes[6] = _scene->_sequences.startCycle(_globals._spriteIndexes[6], false, 1);
+ _globals._sequenceIndexes[7] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[7], false, 4, 0, 0, 0);
+ _scene->_sequences.addTimer(160, 70);
+ _game._player._stepEnabled = false;
+ }
+ } else {
+ if (_globals[kBeamIsUp] == 0)
+ _globals._sequenceIndexes[8] = _scene->_sequences.startCycle(_globals._spriteIndexes[8], false, 1);
+
+ if (_globals[kWindowFixed] == 0)
+ _globals._sequenceIndexes[4] = _scene->_sequences.startCycle(_globals._spriteIndexes[4], false, 1);
+
+ _globals._sequenceIndexes[1] = _scene->_sequences.startCycle(_globals._spriteIndexes[1], false, 1);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[1], Common::Point(133, 139));
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 8);
+ }
+
+ _scene->loadAnimation(Resources::formatName(804, 'r', 1, EXT_AA, ""));
+
+ Scene8xx::sceneEntrySound();
+
+ if (_globals[kInSpace] && !_globals[kWindowFixed]) {
+ _scene->_userInterface.setup(kInputLimitedSentences);
+ _vm->_sound->command(19);
+ }
+}
+
+void Scene804::step() {
+ if (!_messWithThrottle) {
+
+ if ((_throttleGone) && (_movingThrottle) && (_scene->_activeAnimation->getCurrentFrame() == 39)) {
+ _globals._sequenceIndexes[1] = _scene->_sequences.startCycle
+ (_globals._spriteIndexes[1], false, 1);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[1], Common::Point(133, 139));
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 8);
+ _throttleGone = false;
+ }
+
+ if ((_movingThrottle) && (_scene->_activeAnimation->getCurrentFrame() == 42)) {
+ _resetFrame = 0;
+ _movingThrottle = false;
+ }
+
+ if (_game._trigger == 70) {
+ _resetFrame = 42;
+ }
+
+ if (_scene->_activeAnimation->getCurrentFrame() == 65)
+ _scene->_sequences.remove(_globals._sequenceIndexes[7]);
+
+ switch (_game._storyMode) {
+ case STORYMODE_NAUGHTY:
+ if (_scene->_activeAnimation->getCurrentFrame() == 81) {
+ _resetFrame = 80;
+ _globals[kInSpace] = false;
+ _globals[kBeamIsUp] = true;
+
+ assert(!_globals[kCopyProtectFailed]);
+ _game._winStatus = 4;
+ _vm->quitGame();
+ }
+ break;
+
+ case STORYMODE_NICE:
+ if (_scene->_activeAnimation->getCurrentFrame() == 68) {
+ _resetFrame = 66;
+ _globals[kInSpace] = false;
+ _globals[kBeamIsUp] = true;
+
+ assert(!_globals[kCopyProtectFailed]);
+ _game._winStatus = 4;
+ _vm->quitGame();
+ }
+ }
+
+ if (_scene->_activeAnimation->getCurrentFrame() == 34) {
+ _resetFrame = 36;
+ _scene->_sequences.remove(_globals._sequenceIndexes[1]);
+ }
+
+ if (_scene->_activeAnimation->getCurrentFrame() == 37) {
+ _resetFrame = 36;
+ if (!_dontPullThrottleAgain) {
+ _dontPullThrottleAgain = true;
+ _scene->_sequences.addTimer(60, 80);
+ }
+ }
+
+ if (_game._trigger == 80) {
+ _scene->_nextSceneId = 803;
+ }
+
+ if ((_scene->_activeAnimation->getCurrentFrame() == 7) && (!_globals[kWindowFixed])) {
+ _globals._sequenceIndexes[4] = _scene->_sequences.startCycle(_globals._spriteIndexes[4], false, 1);
+ _scene->_sequences.addTimer(20, 110);
+ _globals[kWindowFixed] = true;
+ }
+
+ if (_scene->_activeAnimation->getCurrentFrame() == 10) {
+ _resetFrame = 0;
+ _game._player._stepEnabled = true;
+ _game._objects.setRoom(OBJ_POLYCEMENT, NOWHERE);
+ }
+
+ if (_scene->_activeAnimation->getCurrentFrame() == 1) {
+ int randomVal = _vm->getRandomNumber(29) + 1;
+ switch (randomVal) {
+ case 1:
+ _resetFrame = 25;
+ break;
+ case 2:
+ _resetFrame = 27;
+ break;
+ case 3:
+ _resetFrame = 29;
+ break;
+ default:
+ _resetFrame = 0;
+ break;
+ }
+ }
+
+ switch (_scene->_activeAnimation->getCurrentFrame()) {
+ case 26:
+ case 28:
+ case 31:
+ _resetFrame = 0;
+ break;
+ }
+ } else {
+ if ((_scene->_activeAnimation->getCurrentFrame() == 36) && (!_throttleGone)) {
+ _scene->_sequences.remove(_globals._sequenceIndexes[1]);
+ _throttleGone = true;
+ }
+
+ if (_scene->_activeAnimation->getCurrentFrame() == 39) {
+ _movingThrottle = false;
+ switch (_throttleCounter) {
+ case 1:
+ break;
+ case 3:
+ _scene->_sequences.addTimer(130, 120);
+ break;
+ }
+ }
+
+ if (!_movingThrottle) {
+ ++_throttleCounter;
+ _movingThrottle = true;
+ if (_throttleCounter < 4) {
+ _resetFrame = 34;
+ } else {
+ _messWithThrottle = false;
+ _throttleCounter = 0;
+ _game._player._stepEnabled = true;
+ }
+ }
+ }
+
+ if (_game._trigger == 120) {
+ _vm->_dialogs->show(80422);
+ }
+
+ if (_game._trigger == 110) {
+ _vm->_dialogs->show(80426);
+ }
+
+ if (_pullThrottleReally) {
+ _resetFrame = 32;
+ _pullThrottleReally = false;
+ }
+
+ if (_resetFrame >= 0) {
+ if (_resetFrame != _scene->_activeAnimation->getCurrentFrame()) {
+ _scene->_activeAnimation->setCurrentFrame(_resetFrame);
+ _resetFrame = -1;
+ }
+ }
+
+ if (_game._trigger == 90) {
+ _scene->_nextSceneId = 803;
+ }
+
+ if ((_scene->_activeAnimation->getCurrentFrame() == 72) && !_alreadyPop) {
+ _vm->_sound->command(21);
+ _alreadyPop = true;
+ }
+
+ if ((_scene->_activeAnimation->getCurrentFrame() == 80) && !_alreadyOrgan) {
+ _vm->_sound->command(22);
+ _alreadyOrgan = true;
+ }
+}
+
+/*------------------------------------------------------------------------*/
+
+void Scene805::setup() {
+ setPlayerSpritesPrefix();
+ setAAName();
+ _scene->addActiveVocab(NOUN_REMOVE);
+ _scene->addActiveVocab(NOUN_TARGET_MODULE);
+ _scene->addActiveVocab(NOUN_SHIELD_MODULATOR);
+}
+
+void Scene805::enter() {
+ _game._player._visible = false;
+ _scene->_userInterface.setup(kInputLimitedSentences);
+
+ _globals._spriteIndexes[1] = _scene->_sprites.addSprites(formAnimName('a', 1));
+ _globals._spriteIndexes[2] = _scene->_sprites.addSprites(formAnimName('a', 2));
+
+ if (_globals[kShieldModInstalled]) {
+ _scene->_hotspots.activate(OBJ_SHIELD_MODULATOR, false);
+ _globals._sequenceIndexes[1] = _scene->_sequences.startCycle(_globals._spriteIndexes[1], false, 25);
+ int idx = _scene->_dynamicHotspots.add(NOUN_SHIELD_MODULATOR, 0x476, _globals._sequenceIndexes[1], Common::Rect(0, 0, 0, 0));
+ _scene->_dynamicHotspots.setPosition(idx, Common::Point(0, 0), FACING_DUMMY);
+ }
+
+ if (_globals[kTargetModInstalled]) {
+ _scene->_hotspots.activate(OBJ_TARGET_MODULE, false);
+ _globals._sequenceIndexes[2] = _scene->_sequences.startCycle(_globals._spriteIndexes[2], false, 12);
+ int idx = _scene->_dynamicHotspots.add(NOUN_TARGET_MODULE, 0x476, _globals._sequenceIndexes[2], Common::Rect(0, 0, 0, 0));
+ _scene->_dynamicHotspots.setPosition(idx, Common::Point(0, 0), FACING_DUMMY);
+ }
+
+ sceneEntrySound();
+}
+
+void Scene805::step() {
+ if (_game._trigger == 70) {
+ _scene->_hotspots.activate(OBJ_SHIELD_MODULATOR, false);
+ _globals._sequenceIndexes[1] = _scene->_sequences.startCycle(_globals._spriteIndexes[1], false, 25);
+ int idx = _scene->_dynamicHotspots.add(NOUN_SHIELD_MODULATOR, 0x476, _globals._sequenceIndexes[1], Common::Rect(0, 0, 0, 0));
+ _scene->_dynamicHotspots.setPosition(idx, Common::Point(0, 0), FACING_DUMMY);
+ _globals[kShieldModInstalled] = true;
+ _game._objects.setRoom(OBJ_SHIELD_MODULATOR, NOWHERE);
+ _game._player._stepEnabled = true;
+ _vm->_sound->command(24);
+ }
+
+ if (_game._trigger == 80) {
+ _scene->_hotspots.activate(OBJ_TARGET_MODULE, false);
+ _globals._sequenceIndexes[2] = _scene->_sequences.startCycle(_globals._spriteIndexes[2], false, 12);
+ int idx = _scene->_dynamicHotspots.add(NOUN_TARGET_MODULE, 0x476, _globals._sequenceIndexes[2], Common::Rect(0, 0, 0, 0));
+ _scene->_dynamicHotspots.setPosition(idx, Common::Point(0, 0), FACING_DUMMY);
+ _globals[kTargetModInstalled] = true;
+ _game._objects.setRoom(OBJ_TARGET_MODULE, NOWHERE);
+ _game._player._stepEnabled = true;
+ _vm->_sound->command(24);
+ }
+
+ if (_game._trigger == 71) {
+ _scene->_hotspots.activate(OBJ_SHIELD_MODULATOR, true);
+ _globals[kShieldModInstalled] = false;
+ _game._objects.addToInventory(OBJ_SHIELD_MODULATOR);
+ _game._player._stepEnabled = true;
+ }
+
+ if (_game._trigger == 81) {
+ _scene->_hotspots.activate(OBJ_TARGET_MODULE, true);
+ _globals[kTargetModInstalled] = false;
+ _game._objects.addToInventory(OBJ_TARGET_MODULE);
+ _game._player._stepEnabled = true;
+ }
+}
+
+void Scene805::preActions() {
+ _game._player._needToWalk = false;
+}
+
+void Scene805::actions() {
+ if (_action.isAction(VERB_EXIT, NOUN_SERVICE_PANEL))
+ _scene->_nextSceneId = 804;
+ else if (_action.isAction(VERB_INSTALL, NOUN_SHIELD_MODULATOR) && _game._objects.isInInventory(OBJ_SHIELD_MODULATOR)) {
+ _game._triggerSetupMode = SEQUENCE_TRIGGER_DAEMON;
+ _globals._sequenceIndexes[1] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[1], false, 7, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[1], -1, -2);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[1], SEQUENCE_TRIGGER_EXPIRE, 0, 70);
+ _game._player._stepEnabled = false;
+ } else if (_action.isAction(VERB_INSTALL, NOUN_TARGET_MODULE) && _game._objects.isInInventory(OBJ_TARGET_MODULE)) {
+ _game._triggerSetupMode = SEQUENCE_TRIGGER_DAEMON;
+ _globals._sequenceIndexes[2] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[2], false, 7, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[2], -1, -2);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[2], SEQUENCE_TRIGGER_EXPIRE, 0, 80);
+ _game._player._stepEnabled = false;
+ } else if (_action.isAction(VERB_REMOVE, NOUN_SHIELD_MODULATOR) && _globals[kShieldModInstalled]) {
+ _scene->_sequences.remove(_globals._sequenceIndexes[1]);
+ _game._triggerSetupMode = SEQUENCE_TRIGGER_DAEMON;
+ _globals._sequenceIndexes[1] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[1], false, 7, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[1], -1, -2);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[1], SEQUENCE_TRIGGER_EXPIRE, 0, 71);
+ _game._player._stepEnabled = false;
+ } else if (_action.isAction(VERB_REMOVE, NOUN_TARGET_MODULE) && _globals[kTargetModInstalled]) {
+ _scene->_sequences.remove(_globals._sequenceIndexes[2]);
+ _game._triggerSetupMode = SEQUENCE_TRIGGER_DAEMON;
+ _globals._sequenceIndexes[2] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[2], false, 7, 1, 0, 0);
+ _scene->_sequences.setAnimRange(_globals._sequenceIndexes[2], -1, -2);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[2], SEQUENCE_TRIGGER_EXPIRE, 0, 81);
+ _game._player._stepEnabled = false;
+ } else if (_action.isAction(VERB_INSTALL, NOUN_SHIELD_MODULATOR) && !_game._objects.isInInventory(OBJ_SHIELD_MODULATOR))
+ _vm->_dialogs->show(80511);
+ else if (_action.isAction(VERB_INSTALL, NOUN_TARGET_MODULE) && !_game._objects.isInInventory(OBJ_TARGET_MODULE))
+ _vm->_dialogs->show(80510);
+ else if (_action.isAction(VERB_REMOVE, NOUN_LIFE_SUPPORT_MODULE))
+ _vm->_dialogs->show(80512);
+ else
+ return;
+
+ _action._inProgress = false;
+}
+
+/*------------------------------------------------------------------------*/
+
+void Scene807::setup() {
+ _game._player._spritesPrefix = "";
+ // The original was calling Scene8xx::setAAName()
+ _game._aaName = Resources::formatAAName(5);
+}
+
+void Scene807::enter() {
+ if (_globals[kSexOfRex] == REX_FEMALE)
+ _handSpriteId = _scene->_sprites.addSprites("*ROXHAND");
+ else
+ _handSpriteId = _scene->_sprites.addSprites("*REXHAND");
+
+ teleporterEnter();
+
+ // The original uses Scene8xx::SceneEntrySound()
+ if (!_vm->_musicFlag)
+ _vm->_sound->command(2);
+ else
+ _vm->_sound->command(20);
+}
+
+void Scene807::step() {
+ teleporterStep();
+}
+
+void Scene807::actions() {
+ if (teleporterActions()) {
+ _action._inProgress = false;
+ return;
+ }
+
+ if (_action.isAction(VERB_LOOK, NOUN_VIEWPORT))
+ _vm->_dialogs->show(80710);
+ else if (_action.isAction(VERB_PEER_THROUGH, NOUN_VIEWPORT))
+ _vm->_dialogs->show(80710);
+ else if (_action.isAction(VERB_LOOK, NOUN_KEYPAD) && _action.isAction(VERB_INSPECT, NOUN_KEYPAD))
+ _vm->_dialogs->show(80711);
+ else if (_action.isAction(VERB_LOOK, NOUN_DISPLAY))
+ _vm->_dialogs->show(80712);
+ else if (_action.isAction(VERB_LOOK, NOUN_1_KEY) || _action.isAction(VERB_LOOK, NOUN_2_KEY)
+ || _action.isAction(VERB_LOOK, NOUN_3_KEY) || _action.isAction(VERB_LOOK, NOUN_4_KEY)
+ || _action.isAction(VERB_LOOK, NOUN_5_KEY) || _action.isAction(VERB_LOOK, NOUN_6_KEY)
+ || _action.isAction(VERB_LOOK, NOUN_7_KEY) || _action.isAction(VERB_LOOK, NOUN_8_KEY)
+ || _action.isAction(VERB_LOOK, NOUN_9_KEY) || _action.isAction(VERB_LOOK, NOUN_0_KEY)
+ || _action.isAction(VERB_LOOK, NOUN_SMILE_KEY) || _action.isAction(VERB_LOOK, NOUN_FROWN_KEY))
+ _vm->_dialogs->show(80713);
+ else if (_action.isAction(VERB_LOOK, NOUN_DEVICE) && _action._lookFlag)
+ _vm->_dialogs->show(80714);
+ else
+ return;
+
+ _action._inProgress = false;
+}
+
+/*------------------------------------------------------------------------*/
+
+Scene808::Scene808(MADSEngine *vm) : Scene8xx(vm) {
+ _goingTo803 = false;
+}
+
+void Scene808::synchronize(Common::Serializer &s) {
+ Scene8xx::synchronize(s);
+
+ s.syncAsByte(_goingTo803);
+}
+
+void Scene808::setup() {
+ setPlayerSpritesPrefix();
+ setAAName();
+}
+
+void Scene808::enter() {
+ _scene->_userInterface.setup(kInputLimitedSentences);
+
+ _globals._spriteIndexes[4] = _scene->_sprites.addSprites ("*REXHAND");
+ _globals._spriteIndexes[1] = _scene->_sprites.addSprites(formAnimName('b', 0));
+ _globals._spriteIndexes[2] = _scene->_sprites.addSprites(formAnimName('b', 1));
+ _globals._spriteIndexes[3] = _scene->_sprites.addSprites(formAnimName('b', 2));
+
+ if (_globals[kTopButtonPushed])
+ _globals._sequenceIndexes[1] = _scene->_sequences.startCycle(_globals._spriteIndexes[1], false, 1);
+ else
+ _globals._sequenceIndexes[2] = _scene->_sequences.startCycle(_globals._spriteIndexes[2], false, 1);
+
+ _goingTo803 = false;
+
+ if (_globals[kCameFromCut] && _globals[kCutX] != 0) {
+ _globals[kCutX] = 0;
+ _globals[kCameFromCut] = false;
+ _globals[kReturnFromCut] = false;
+ _globals[kBeamIsUp] = false;
+ _globals[kForceBeamDown] = false;
+ _globals[kDontRepeat] = false;
+ } else if ((_scene->_priorSceneId == 803) && _globals[kReturnFromCut]){
+ _globals[kDontRepeat] = false;
+ _globals[kBeamIsUp] = true;
+ _globals[kAntigravClock] = _scene->_frameStartTime;
+ _globals[kAntigravTiming] = _scene->_frameStartTime;
+ _globals[kForceBeamDown] = false;
+ _globals[kReturnFromCut] = false;
+ }
+
+ _globals[kBetweenRooms] = false;
+
+ if (_globals[kBeamIsUp]) {
+ _globals._sequenceIndexes[3] = _scene->_sequences.startCycle(_globals._spriteIndexes[3], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 8);
+ }
+
+ sceneEntrySound();
+}
+
+void Scene808::actions() {
+ if (_action.isAction(VERB_PRESS, NOUN_START_BUTTON_2)) {
+ switch (_game._trigger) {
+ case 0:
+ _game._player._stepEnabled = false;
+ _globals._sequenceIndexes[4] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[4], false, 4, 1, 0, 0);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[4], Common::Point(248, 211));
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[4], 2);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[4], SEQUENCE_TRIGGER_EXPIRE, 0, 70);
+ break;
+
+ case 70:
+ if (!_globals[kBeamIsUp] && !_globals[kTopButtonPushed]) {
+ _globals._sequenceIndexes[3] = _scene->_sequences.startCycle(_globals._spriteIndexes[3], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[3], 8);
+ _goingTo803 = true;
+ _vm->_sound->command(20);
+ _vm->_sound->command(25);
+ }
+ _globals._sequenceIndexes[4] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[4], false, 4, 1, 0, 0);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[4], Common::Point(248, 211));
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[4], 2);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[4], SEQUENCE_TRIGGER_EXPIRE, 0, 71);
+ break;
+
+ case 71:
+ _game._player._stepEnabled = true;
+ if (_goingTo803 && !_globals[kTopButtonPushed]) {
+ _goingTo803 = false;
+ _globals[kReturnFromCut] = true;
+ _scene->_nextSceneId = 803;
+ }
+ break;
+
+ default:
+ break;
+ }
+ } else if (_action.isAction(VERB_PRESS, NOUN_TIMER_BUTTON_2)) {
+ switch (_game._trigger) {
+ case 0:
+ _game._player._stepEnabled = false;
+ _globals._sequenceIndexes[4] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[4], false, 4, 1, 0, 0);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[4], Common::Point(248, 186));
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[4], 2);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[4], SEQUENCE_TRIGGER_EXPIRE, 0, 90);
+ break;
+ case 90:
+ if (_globals[kTopButtonPushed]) {
+ _scene->_sequences.remove(_globals._sequenceIndexes[1]);
+ _globals._sequenceIndexes[2] = _scene->_sequences.startCycle(_globals._spriteIndexes[2], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[2], 8);
+ _vm->_sound->command(20);
+ }
+ _globals[kTopButtonPushed] = false;
+ _globals._sequenceIndexes[4] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[4], false, 4, 1, 0, 0);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[4], Common::Point(248, 186));
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[4], 2);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[4], SEQUENCE_TRIGGER_EXPIRE, 0, 91);
+ break;
+
+ case 91:
+ _game._player._stepEnabled = true;
+ break;
+
+ default:
+ break;
+ }
+ } else if (_action.isAction(VERB_PRESS, NOUN_REMOTE_BUTTON_2)) {
+ switch (_game._trigger) {
+ case 0:
+ _game._player._stepEnabled = false;
+ _globals._sequenceIndexes[4] = _scene->_sequences.addSpriteCycle(_globals._spriteIndexes[4], false, 4, 1, 0, 0);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[4], Common::Point(248, 163));
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[4], 2);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[4], SEQUENCE_TRIGGER_EXPIRE, 0, 80);
+ break;
+
+ case 80:
+ if (!_globals[kTopButtonPushed]) {
+ _scene->_sequences.remove(_globals._sequenceIndexes[2]);
+ _globals._sequenceIndexes[1] = _scene->_sequences.startCycle(_globals._spriteIndexes[1], false, 1);
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[1], 8);
+ _vm->_sound->command(20);
+ }
+ _globals[kTopButtonPushed] = true;
+ _globals._sequenceIndexes[4] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[4], false, 4, 1, 0, 0);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[4], Common::Point(248, 163));
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[4], 2);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[4], SEQUENCE_TRIGGER_EXPIRE, 0, 81);
+ break;
+
+ case 81:
+ _game._player._stepEnabled = true;
+ break;
+
+ default:
+ break;
+ }
+ } else if (_action.isAction(VERB_PRESS, NOUN_START_BUTTON_1)) {
+ switch (_game._trigger) {
+ case 0:
+ _game._player._stepEnabled = false;
+ _globals._sequenceIndexes[4] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[4], false, 4, 2, 0, 0);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[4], Common::Point(168, 211));
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[4], 2);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[4], SEQUENCE_TRIGGER_EXPIRE, 0, 70);
+ break;
+
+ case 70:
+ _game._player._stepEnabled = true;
+ break;
+
+ default:
+ break;
+ }
+ } else if (_action.isAction(VERB_PRESS, NOUN_REMOTE_BUTTON_1)) {
+ switch (_game._trigger) {
+ case 0:
+ _game._player._stepEnabled = false;
+ _globals._sequenceIndexes[4] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[4], false, 4, 2, 0, 0);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[4], Common::Point(172, 163));
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[4], 2);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[4], SEQUENCE_TRIGGER_EXPIRE, 0, 80);
+ break;
+
+ case 80:
+ _game._player._stepEnabled = true;
+ break;
+
+ default:
+ break;
+ }
+ } else if (_action.isAction(VERB_PRESS, NOUN_TIMER_BUTTON_1)) {
+ switch (_game._trigger) {
+ case 0:
+ _game._player._stepEnabled = false;
+ _globals._sequenceIndexes[4] = _scene->_sequences.startReverseCycle(_globals._spriteIndexes[4], false, 4, 2, 0, 0);
+ _scene->_sequences.setPosition(_globals._sequenceIndexes[4], Common::Point(172, 186));
+ _scene->_sequences.setDepth(_globals._sequenceIndexes[4], 2);
+ _scene->_sequences.addSubEntry(_globals._sequenceIndexes[4], SEQUENCE_TRIGGER_EXPIRE, 0, 90);
+ break;
+
+ case 90:
+ _game._player._stepEnabled = true;
+ break;
+
+ default:
+ break;
+ }
+ } else if (_action.isAction(VERB_EXIT, NOUN_PANEL)) {
+ _scene->_nextSceneId = 801;
+ _globals[kBetweenRooms] = true;
+ } else
+ return;
+
+ _action._inProgress = false;
+}
+
+/*------------------------------------------------------------------------*/
+
+Scene810::Scene810(MADSEngine *vm) : Scene8xx(vm) {
+ _moveAllowed = false;
+}
+
+void Scene810::synchronize(Common::Serializer &s) {
+ Scene8xx::synchronize(s);
+
+ s.syncAsByte(_moveAllowed);
+}
+
+void Scene810::setup() {
+ setPlayerSpritesPrefix();
+ setAAName();
+}
+
+void Scene810::enter() {
+ _scene->_userInterface.setup(kInputLimitedSentences);
+ _game._player._visible = false;
+ _game._player._stepEnabled = false;
+ _scene->loadAnimation(Resources::formatName(810, 'a', -1, EXT_AA, ""));
+ _moveAllowed = true;
+
+ sceneEntrySound();
+}
+
+void Scene810::step() {
+ if ((_scene->_activeAnimation->getCurrentFrame() == 200) && _moveAllowed) {
+ _scene->_sequences.addTimer(100, 70);
+ _moveAllowed = false;
+ }
+
+ if (_game._trigger == 70)
+ _scene->_nextSceneId = 804;
+}
+
+/*------------------------------------------------------------------------*/
+
+} // End of namespace Nebular
+} // End of namespace MADS
diff --git a/engines/mads/nebular/nebular_scenes8.h b/engines/mads/nebular/nebular_scenes8.h
new file mode 100644
index 0000000000..150951dcaf
--- /dev/null
+++ b/engines/mads/nebular/nebular_scenes8.h
@@ -0,0 +1,165 @@
+/* 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.
+ *
+ */
+
+#ifndef MADS_NEBULAR_SCENES8_H
+#define MADS_NEBULAR_SCENES8_H
+
+#include "common/scummsys.h"
+#include "mads/game.h"
+#include "mads/scene.h"
+#include "mads/nebular/nebular_scenes.h"
+
+namespace MADS {
+
+namespace Nebular {
+
+class Scene8xx : public NebularScene {
+protected:
+ /**
+ * Initial setup code shared by several scenes
+ */
+ void setPlayerSpritesPrefix();
+
+ /**
+ * Initial setup code shared by several scenes
+ */
+ void setAAName();
+
+ /**
+ * Common scene enter code used by multiple scenes
+ */
+ void sceneEntrySound();
+public:
+ Scene8xx(MADSEngine *vm) : NebularScene(vm) {}
+};
+
+class Scene801: public Scene8xx{
+private:
+ bool _walkThroughDoor;
+
+public:
+ Scene801(MADSEngine *vm);
+ void synchronize(Common::Serializer &s);
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+ virtual void preActions();
+ virtual void actions();
+};
+
+class Scene802: public Scene8xx{
+public:
+ Scene802(MADSEngine *vm) : Scene8xx(vm) {}
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+ virtual void preActions();
+ virtual void actions();
+};
+
+class Scene803: public Scene8xx{
+public:
+ Scene803(MADSEngine *vm) : Scene8xx(vm) {}
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+ virtual void preActions();
+ virtual void actions();
+};
+
+class Scene804: public Scene8xx {
+private:
+ bool _messWithThrottle;
+ bool _movingThrottle;
+ bool _throttleGone;
+ bool _dontPullThrottleAgain;
+ bool _pullThrottleReally;
+ bool _alreadyOrgan;
+ bool _alreadyPop;
+ uint32 _throttleCounter;
+ int _resetFrame;
+
+public:
+ Scene804(MADSEngine *vm);
+ void synchronize(Common::Serializer &s);
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+ virtual void actions() {};
+};
+
+class Scene805: public Scene8xx{
+public:
+ Scene805(MADSEngine *vm) : Scene8xx(vm) {}
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+ virtual void preActions();
+ virtual void actions();
+};
+
+class Scene807: public SceneTeleporter {
+public:
+ Scene807(MADSEngine *vm) : SceneTeleporter(vm) {}
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+ virtual void actions();
+};
+
+class Scene808: public Scene8xx{
+private:
+ bool _goingTo803;
+
+public:
+ Scene808(MADSEngine *vm);
+ void synchronize(Common::Serializer &s);
+
+ virtual void setup();
+ virtual void enter();
+ virtual void actions();
+};
+
+class Scene810: public Scene8xx{
+private:
+ bool _moveAllowed;
+
+public:
+ Scene810(MADSEngine *vm);
+ void synchronize(Common::Serializer &s);
+
+ virtual void setup();
+ virtual void enter();
+ virtual void step();
+ virtual void actions() {};
+};
+
+} // End of namespace Nebular
+} // End of namespace MADS
+
+#endif /* MADS_NEBULAR_SCENES8_H */
diff --git a/engines/mads/nebular/sound_nebular.cpp b/engines/mads/nebular/sound_nebular.cpp
new file mode 100644
index 0000000000..6bc697459a
--- /dev/null
+++ b/engines/mads/nebular/sound_nebular.cpp
@@ -0,0 +1,3111 @@
+/* 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 "audio/audiostream.h"
+#include "audio/decoders/raw.h"
+#include "common/algorithm.h"
+#include "common/debug.h"
+#include "common/memstream.h"
+#include "mads/sound.h"
+#include "mads/nebular/sound_nebular.h"
+
+namespace MADS {
+
+namespace Nebular {
+
+bool AdlibChannel::_channelsEnabled;
+
+AdlibChannel::AdlibChannel() {
+ _activeCount = 0;
+ _field1 = 0;
+ _field2 = 0;
+ _field3 = 0;
+ _field4 = 0;
+ _sampleIndex = 0;
+ _volume = 0;
+ _field7 = 0;
+ _field8 = 0;
+ _field9 = 0;
+ _fieldA = 0;
+ _fieldB = 0;
+ _fieldC = 0;
+ _fieldD = 0;
+ _fieldE = 0;
+ _ptr1 = nullptr;
+ _pSrc = nullptr;
+ _ptr3 = nullptr;
+ _ptr4 = nullptr;
+ _field17 = 0;
+ _field19 = 0;
+ _soundData = nullptr;
+ _field1D = 0;
+ _field1E = 0;
+ _field1F = 0;
+
+ _field20 = 0;
+}
+
+void AdlibChannel::reset() {
+ _activeCount = 0;
+ _field1 = 0;
+ _field2 = 0;
+ _field3 = 0;
+}
+
+void AdlibChannel::enable(int flag) {
+ if (_activeCount) {
+ _fieldE = flag;
+
+ // WORKAROUND: Original set _soundData pointer to flag. Since this seems
+ // just intended to invalidate any prior pointer, I've replaced it with
+ // a simple null pointer
+ _soundData = nullptr;
+ }
+
+ _channelsEnabled = true;
+}
+
+void AdlibChannel::setPtr2(byte *pData) {
+ _pSrc = pData;
+ _field2 = 0xFF;
+ _fieldA = 1;
+ _field9 = 1;
+}
+
+void AdlibChannel::load(byte *pData) {
+ _ptr1 = _pSrc = _ptr3 = pData;
+ _ptr4 = _soundData = pData;
+ _fieldA = 0xFF;
+ _activeCount = 1;
+ _fieldD = 64;
+ _field1 = 0;
+ _field1F = 0;
+ _field2 = _field3 = 0;
+ _volume = _field7 = 0;
+ _field1D = _field1E = 0;
+ _fieldE = 0;
+ _field9 = 0;
+ _fieldB = 0;
+ _field17 = 0;
+ _field19 = 0;
+}
+
+void AdlibChannel::check(byte *nullPtr) {
+ if (_activeCount && _fieldE) {
+ if (!_field1E) {
+ _pSrc = nullPtr;
+ _fieldE = 0;
+ } else {
+ _field2 = 0xFF;
+ _fieldA = 4;
+ if (!_field9)
+ _field9 = 1;
+ }
+ }
+}
+
+/*-----------------------------------------------------------------------*/
+
+AdlibSample::AdlibSample(Common::SeekableReadStream &s) {
+ _attackRate = s.readByte();
+ _decayRate = s.readByte();
+ _sustainLevel = s.readByte();
+ _releaseRate = s.readByte();
+ _egTyp = s.readByte() != 0;
+ _ksr = s.readByte() != 0;
+ _totalLevel = s.readByte();
+ _scalingLevel = s.readByte();
+ _waveformSelect = s.readByte();
+ _freqMultiple = s.readByte();
+ _feedback = s.readByte();
+ _ampMod = s.readByte() != 0;
+ _vib = s.readByte();
+ _alg = s.readByte();
+ _fieldE = s.readByte();
+ s.skip(1);
+ _freqMask = s.readUint16LE();
+ _freqBase = s.readUint16LE();
+ _field14 = s.readUint16LE();
+}
+
+/*-----------------------------------------------------------------------*/
+
+ASound::ASound(Audio::Mixer *mixer, const Common::String &filename, int dataOffset) {
+ // Open up the appropriate sound file
+ if (!_soundFile.open(filename))
+ error("Could not open file - %s", filename.c_str());
+
+ // Initialize fields
+ _commandParam = 0;
+ _activeChannelPtr = nullptr;
+ _samplePtr = nullptr;
+ _frameCounter = 0;
+ _isDisabled = false;
+ _v1 = 0;
+ _v2 = 0;
+ _activeChannelNumber = 0;
+ _freqMask1 = _freqMask2 = 0;
+ _freqBase1 = _freqBase2 = 0;
+ _channelNum1 = _channelNum2 = 0;
+ _v7 = 0;
+ _v8 = 0;
+ _v9 = 0;
+ _v10 = 0;
+ _pollResult = 0;
+ _resultFlag = 0;
+ _nullData[0] = _nullData[1] = 0;
+ Common::fill(&_ports[0], &_ports[256], 0);
+ _stateFlag = false;
+ _activeChannelReg = 0;
+ _v11 = 0;
+ _randomSeed = 1234;
+ _amDep = _vibDep = _splitPoint = true;
+
+ _samplesTillCallback = 0;
+ _samplesTillCallbackRemainder = 0;
+ _samplesPerCallback = getRate() / CALLBACKS_PER_SECOND;
+ _samplesPerCallbackRemainder = getRate() % CALLBACKS_PER_SECOND;
+
+ AdlibChannel::_channelsEnabled = false;
+
+ // Store passed parameters, and setup OPL
+ _dataOffset = dataOffset;
+ _mixer = mixer;
+ _opl = OPL::Config::create();
+ assert(_opl);
+
+ _opl->init(getRate());
+ _mixer->playStream(Audio::Mixer::kPlainSoundType, &_soundHandle, this, -1,
+ Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, true);
+
+ // Initialise the Adlib
+ adlibInit();
+
+ // Reset the adlib
+ command0();
+}
+
+ASound::~ASound() {
+ Common::List<CachedDataEntry>::iterator i;
+ for (i = _dataCache.begin(); i != _dataCache.end(); ++i)
+ delete[] (*i)._data;
+
+ _mixer->stopHandle(_soundHandle);
+ delete _opl;
+}
+
+void ASound::adlibInit() {
+ write(4, 0x60);
+ write(4, 0x80);
+ write(2, 0xff);
+ write(4, 0x21);
+ write(4, 0x60);
+ write(4, 0x80);
+}
+
+int ASound::stop() {
+ command0();
+ int result = _pollResult;
+ _pollResult = 0;
+ return result;
+}
+
+int ASound::poll() {
+ // Update any playing sounds
+ update();
+
+ // Return result
+ int result = _pollResult;
+ _pollResult = 0;
+ return result;
+}
+
+void ASound::noise() {
+ int randomVal = getRandomNumber();
+
+ if (_v1) {
+ setFrequency(_channelNum1, ((randomVal ^ 0xFFFF) & _freqMask1) + _freqBase1);
+ }
+
+ if (_v2) {
+ setFrequency(_channelNum2, (randomVal & _freqMask2) + _freqBase2);
+ }
+}
+
+void ASound::write(int reg, int val) {
+ _queue.push(RegisterValue(reg, val));
+}
+
+int ASound::write2(int state, int reg, int val) {
+ // TODO: Original has a state parameter, not used when in Adlib mode?
+ _ports[reg] = val;
+ write(reg, val);
+ return state;
+}
+
+void ASound::flush() {
+ Common::StackLock slock(_driverMutex);
+
+ while (!_queue.empty()) {
+ RegisterValue v = _queue.pop();
+ _opl->writeReg(v._regNum, v._value);
+ }
+}
+
+void ASound::channelOn(int reg, int volume) {
+ write2(8, reg, (_ports[reg] & 0xC0) | (volume & 0x3F));
+}
+
+void ASound::channelOff(int reg) {
+ write2(8, reg, _ports[reg] | 0x3F);
+}
+
+void ASound::resultCheck() {
+ if (_resultFlag != 1) {
+ _resultFlag = 1;
+ _pollResult = 1;
+ }
+}
+
+byte *ASound::loadData(int offset, int size) {
+ // First scan for an existing copy
+ Common::List<CachedDataEntry>::iterator i;
+ for (i = _dataCache.begin(); i != _dataCache.end(); ++i) {
+ CachedDataEntry &e = *i;
+ if (e._offset == offset)
+ return e._data;
+ }
+
+ // No existing entry found, so load up data and store as a new entry
+ CachedDataEntry rec;
+ rec._offset = offset;
+ rec._data = new byte[size];
+ _soundFile.seek(_dataOffset + offset);
+ _soundFile.read(rec._data, size);
+ _dataCache.push_back(rec);
+
+ // Return the data
+ return rec._data;
+}
+
+void ASound::playSound(int offset, int size) {
+ // Load the specified data block
+ playSoundData(loadData(offset, size));
+}
+
+void ASound::playSoundData(byte *pData, int startingChannel) {
+ // Scan for a high level free channel
+ for (int i = startingChannel; i < ADLIB_CHANNEL_COUNT; ++i) {
+ if (!_channels[i]._activeCount) {
+ _channels[i].load(pData);
+ return;
+ }
+ }
+
+ // None found, do a secondary scan for an interruptable channel
+ for (int i = ADLIB_CHANNEL_COUNT - 1; i >= startingChannel; --i) {
+ if (_channels[i]._fieldE == 0xFF) {
+ _channels[i].load(pData);
+ return;
+ }
+ }
+}
+
+bool ASound::isSoundActive(byte *pData) {
+ for (int i = 0; i < ADLIB_CHANNEL_MIDWAY; ++i) {
+ if (_channels[i]._activeCount && _channels[i]._soundData == pData)
+ return true;
+ }
+
+ return false;
+}
+
+void ASound::setFrequency(int channel, int freq) {
+ write2(8, 0xA0 + channel, freq & 0xFF);
+ write2(8, 0xB0 + channel, (freq >> 8) | 0x20);
+}
+
+int ASound::getRandomNumber() {
+ int v = 0x9248 + (int)_randomSeed;
+ _randomSeed = ((v >> 3) | (v << 13)) & 0xFFFF;
+ return _randomSeed;
+}
+
+void ASound::update() {
+ getRandomNumber();
+ if (_isDisabled)
+ return;
+
+ ++_frameCounter;
+ pollChannels();
+ checkChannels();
+
+ if (_v1 == _v2) {
+ if (_resultFlag != -1) {
+ _resultFlag = -1;
+ _pollResult = -1;
+ }
+ } else {
+ if (_v1) {
+ _freqBase1 += _v7;
+ if (!--_v1) {
+ if (!_v2 || _channelNum1 != _channelNum2) {
+ write2(8, 0xA0 + _channelNum1, 0);
+ write2(8, 0xB0 + _channelNum1, 0);
+ }
+ }
+ }
+
+ if (_v2) {
+ _freqBase2 += _v8;
+ if (!--_v2) {
+ if (!_v1 || _channelNum2 != _channelNum1) {
+ write2(8, 0xA0 + _channelNum2, 0);
+ write2(8, 0xB0 + _channelNum2, 0);
+ }
+ }
+ }
+ }
+}
+
+void ASound::pollChannels() {
+ _activeChannelNumber = 0;
+ for (int i = 0; i < ADLIB_CHANNEL_COUNT; ++i) {
+ _activeChannelPtr = &_channels[i];
+ pollActiveChannel();
+ }
+}
+
+void ASound::checkChannels() {
+ if (AdlibChannel::_channelsEnabled) {
+ for (int i = 0; i < ADLIB_CHANNEL_COUNT; ++i)
+ _channels[i].check(_nullData);
+ }
+}
+
+void ASound::pollActiveChannel() {
+ AdlibChannel *chan = _activeChannelPtr;
+
+ if (chan->_activeCount) {
+ if (chan->_field8 > 0 && --chan->_field8 == 0)
+ updateOctave();
+
+ bool updateFlag = true;
+ if (--_activeChannelPtr->_activeCount <= 0) {
+ for (;;) {
+ byte *pSrc = chan->_pSrc;
+ if (!chan->_ptr1) {
+ warning("pollActiveChannel(): No data found for sound channel");
+ break;
+ }
+ if (!(*pSrc & 0x80) || (*pSrc <= 0xF0)) {
+ if (updateFlag)
+ updateActiveChannel();
+
+ chan->_field4 = *pSrc++;
+ chan->_activeCount = *pSrc++;
+ chan->_pSrc += 2;
+
+ if (!chan->_field4 || !chan->_activeCount) {
+ updateOctave();
+ } else {
+ chan->_field8 = chan->_activeCount - chan->_field7;
+ updateChannelState();
+ }
+
+ // Break out of processing loop
+ break;
+ } else {
+ updateFlag = false;
+
+ switch ((~*pSrc) & 0xF) {
+ case 0:
+ if (!chan->_field17) {
+ if (*++pSrc == 0) {
+ chan->_pSrc += 2;
+ chan->_ptr3 = chan->_pSrc;
+ chan->_field17 = 0;
+ } else {
+ chan->_field17 = *pSrc;
+ chan->_pSrc = chan->_ptr3;
+ }
+ } else if (--chan->_field17) {
+ chan->_pSrc = chan->_ptr3;
+ } else {
+ chan->_pSrc += 2;
+ chan->_ptr3 = chan->_pSrc;
+ }
+ break;
+
+ case 1:
+ if (!chan->_field19) {
+ if (*++pSrc == 0) {
+ chan->_pSrc += 2;
+ chan->_ptr4 = chan->_pSrc;
+ chan->_ptr3 = chan->_pSrc;
+ chan->_field17 = 0;
+ chan->_field19 = 0;
+ } else {
+ chan->_field19 = *pSrc;
+ chan->_pSrc = chan->_ptr4;
+ chan->_ptr3 = chan->_ptr4;
+ }
+ } else if (--chan->_field19) {
+ chan->_ptr4 = chan->_pSrc;
+ chan->_ptr3 = chan->_pSrc;
+ } else {
+ chan->_pSrc += 2;
+ chan->_ptr4 = chan->_pSrc;
+ chan->_ptr3 = chan->_pSrc;
+ }
+ break;
+
+ case 2:
+ // Loop sound data
+ chan->_field1 = 0;
+ chan->_field2 = chan->_field3 = 0;
+ chan->_volume = chan->_field7 = 0;
+ chan->_field1D = chan->_field1E = 0;
+ chan->_field8 = 0;
+ chan->_field9 = 0;
+ chan->_fieldB = 0;
+ chan->_field17 = 0;
+ chan->_field19 = 0;
+ chan->_fieldD = 0x40;
+ chan->_ptr1 = chan->_soundData;
+ chan->_pSrc = chan->_soundData;
+ chan->_ptr3 = chan->_soundData;
+ chan->_ptr4 = chan->_soundData;
+
+ chan->_pSrc += 2;
+ break;
+
+ case 3:
+ chan->_sampleIndex = *++pSrc;
+ chan->_pSrc += 2;
+ loadSample(chan->_sampleIndex);
+ break;
+
+ case 4:
+ chan->_field7 = *++pSrc;
+ chan->_pSrc += 2;
+ break;
+
+ case 5:
+ chan->_field1 = *++pSrc;
+ chan->_pSrc += 2;
+ break;
+
+ case 6:
+ ++pSrc;
+ if (chan->_fieldE) {
+ chan->_pSrc += 2;
+ } else {
+ chan->_volume = *pSrc >> 1;
+ updateFlag = true;
+ chan->_pSrc += 2;
+ }
+ break;
+
+ case 7:
+ ++pSrc;
+ if (!chan->_fieldE) {
+ chan->_fieldA = *pSrc;
+ chan->_field2 = *++pSrc;
+ chan->_field9 = 1;
+ }
+
+ chan->_pSrc += 3;
+ break;
+
+ case 8:
+ chan->_field1D = *++pSrc;
+ chan->_pSrc += 2;
+ break;
+
+ case 9: {
+ int v1 = *++pSrc;
+ ++pSrc;
+ int v2 = (v1 - 1) & getRandomNumber();
+ int v3 = pSrc[v2];
+ int v4 = pSrc[v1];
+
+ pSrc[v4 + v1 + 1] = v3;
+ chan->_pSrc += v1 + 3;
+ break;
+ }
+
+ case 10:
+ ++pSrc;
+ if (chan->_fieldE) {
+ chan->_pSrc += 2;
+ } else {
+ chan->_field1E = *pSrc >> 1;
+ updateFlag = true;
+ chan->_pSrc += 2;
+ }
+ break;
+
+ case 11:
+ chan->_fieldD = *++pSrc;
+ updateFlag = true;
+ chan->_pSrc += 2;
+ break;
+
+ case 12:
+ chan->_fieldC = *++pSrc;
+ chan->_field3 = *++pSrc;
+ chan->_fieldB = 1;
+ chan->_pSrc += 2;
+ break;
+
+ case 13:
+ ++pSrc;
+ chan->_pSrc += 2;
+ break;
+
+ case 14:
+ chan->_field1F = *++pSrc;
+ chan->_pSrc += 2;
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+ }
+
+ if (chan->_field1)
+ updateFNumber();
+
+ updateFlag = false;
+ if (chan->_field9 || chan->_fieldB) {
+ if (!--chan->_field9) {
+ chan->_field9 = chan->_fieldA;
+ if (chan->_field2) {
+ int8 newVal = (int8)chan->_field2 + (int8)chan->_field1E;
+ if (newVal < 0) {
+ chan->_field9 = 0;
+ newVal = 0;
+ } else if (newVal > 63) {
+ chan->_field9 = 0;
+ newVal = 63;
+ }
+
+ chan->_field1E = newVal;
+ updateFlag = true;
+ }
+ }
+
+ if (!--chan->_fieldB) {
+ chan->_fieldB = chan->_fieldC;
+ if (chan->_field3) {
+ chan->_fieldD = chan->_field3;
+ updateFlag = true;
+ }
+ }
+
+ if (updateFlag)
+ updateActiveChannel();
+ }
+ }
+
+ ++_activeChannelNumber;
+}
+
+void ASound::updateOctave() {
+ int reg = 0xB0 + _activeChannelNumber;
+ write2(8, reg, _ports[reg] & 0xDF);
+}
+
+static int _vList1[] = {
+ 0x200, 0x21E, 0x23F, 0x261, 0x285, 0x2AB,
+ 0x2D4, 0x2FF, 0x32D, 0x35D, 0x390, 0x3C7
+};
+
+void ASound::updateChannelState() {
+ updateActiveChannel();
+
+ if (_channelData[_activeChannelNumber]._field0) {
+ if (_channelNum1 == _activeChannelNumber)
+ _stateFlag = 0;
+ if (_channelNum2 == _activeChannelNumber)
+ _stateFlag = 1;
+
+ if (!_stateFlag) {
+ _stateFlag = 1;
+ if (_v1)
+ write2(8, 0xB0 + _channelNum1, _ports[0xB0 + _channelNum1] & 0xDF);
+
+ _channelNum1 = _activeChannelNumber;
+ _v1 = _channelData[_channelNum1]._field0;
+ _freqMask1 = _channelData[_channelNum1]._freqMask;
+ _freqBase1 = _channelData[_channelNum1]._freqBase;
+ _v7 = _channelData[_channelNum1]._field6;
+ } else {
+ _stateFlag = 0;
+ if (_v2)
+ write2(8, 0xB0 + _channelNum2, _ports[0xB0 + _channelNum2] & 0xDF);
+
+ _channelNum2 = _activeChannelNumber;
+ _v2 = _channelData[_channelNum2]._field0;
+ _freqMask2 = _channelData[_channelNum2]._freqMask;
+ _freqBase2 = _channelData[_channelNum2]._freqBase;
+ _v8 = _channelData[_channelNum2]._field6;
+ }
+
+ resultCheck();
+ } else {
+ int reg = 0xA0 + _activeChannelNumber;
+ int vTimes = (_activeChannelPtr->_field4 + _activeChannelPtr->_field1F) / 12;
+ int vOffset = (_activeChannelPtr->_field4 + _activeChannelPtr->_field1F) % 12;
+ int val = _vList1[vOffset] + _activeChannelPtr->_field1D;
+ write2(8, reg, val & 0xFF);
+
+ reg += 0x10;
+ write2(8, reg, (_ports[reg] & 0x20) | (vTimes << 2) | (val >> 8));
+
+ write2(8, reg, _ports[reg] | 0x20);
+ }
+}
+
+static const int outputIndexes[] = {
+ 0, 3, 1, 4, 2, 5, 6, 9, 7, 10, 8, 11, 12, 15, 13, 16, 14, 17
+};
+static const int outputChannels[] = {
+ 0, 1, 2, 3, 4, 5, 8, 9, 10, 11, 12, 13, 16, 17, 18, 19, 20, 21, 0
+};
+static const int volumeList[] = {
+ 0x3F, 0x3F, 0x36, 0x31, 0x2D, 0x2A, 0x28, 0x26, 0x24, 0x22, 0x21, 0x20, 0x1F, 0x1E, 0x1D, 0x1C,
+ 0x1B, 0x1A, 0x19, 0x19, 0x18, 0x17, 0x17, 0x16, 0x16, 0x15, 0x15, 0x14, 0x14, 0x13, 0x12, 0x12,
+ 0x11, 0x11, 0x10, 0x10, 0x0F, 0x0F, 0x0E, 0x0E, 0x0D, 0x0D, 0x0C, 0x0C, 0x0B, 0x0B, 0x0A, 0x0A,
+ 0x0A, 0x09, 0x09, 0x09, 0x09, 0x09, 0x08, 0x08, 0x08, 0x08, 0x08, 0x07, 0x07, 0x07, 0x07, 0x07,
+ 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x04,
+ 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
+ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
+void ASound::updateActiveChannel() {
+ int reg = 0x40 + outputChannels[outputIndexes[_activeChannelNumber * 2 + 1]];
+ int portVal = _ports[reg] & 0xFFC0;
+ int newVolume = CLIP(_activeChannelPtr->_volume + _activeChannelPtr->_field1E, 0, 63);
+
+ // Note: Original had a whole block not seeming to be used, since the initialisation
+ // sets a variable to 5660h, and doesn't change it, so the branch is never taken
+ int val = CLIP(newVolume - volumeList[_activeChannelPtr->_fieldD], 0, 63);
+ val = (63 - val) | portVal;
+
+ int val2 = CLIP(newVolume - volumeList[-(_activeChannelPtr->_fieldD - 127)], 0, 63);
+ val2 = (63 - val2) | portVal;
+ write2(0, reg, val);
+ write2(2, reg, val2);
+}
+
+void ASound::loadSample(int sampleIndex) {
+ _activeChannelReg = 0xB0 + _activeChannelNumber;
+ write2(8, _activeChannelReg, _ports[_activeChannelReg] & 0xDF);
+
+ _activeChannelReg = _activeChannelNumber;
+ _samplePtr = &_samples[sampleIndex * 2];
+ _v11 = outputChannels[outputIndexes[_activeChannelReg * 2]];
+ processSample();
+
+ AdlibChannelData &cd = _channelData[_activeChannelNumber];
+ cd._field6 = _samplePtr->_field14;
+ cd._freqBase = _samplePtr->_freqBase;
+ cd._freqMask = _samplePtr->_freqMask;
+ cd._field0 = _samplePtr->_fieldE;
+
+ _samplePtr = &_samples[sampleIndex * 2 + 1];
+ _v11 = outputChannels[outputIndexes[_activeChannelReg * 2 + 1]];
+ processSample();
+}
+
+void ASound::processSample() {
+ // Write out vib flags and split point
+ write2(8, 0x40 + _v11, 0x3F);
+ int depthRhythm = (_ports[0xBD] & 0x3F) | (_amDep ? 0x80 : 0) |
+ (_vibDep ? 0x40 : 0);
+ write2(8, 0xBD, depthRhythm);
+ write2(8, 8, _splitPoint ? 0x40 : 0);
+
+ // Write out feedback & Alg
+ int val = (_samplePtr->_feedback << 1) | (1 - _samplePtr->_alg);
+ write2(8, 0xC0 + _activeChannelReg, val);
+
+ // Write out attack/decay rate
+ val = (_samplePtr->_attackRate << 4) | (_samplePtr->_decayRate & 0xF);
+ write2(8, 0x60 + _v11, val);
+
+ // Write out sustain level/release rate
+ val = (_samplePtr->_sustainLevel << 4) | (_samplePtr->_releaseRate & 0xF);
+ write2(8, 0x80 + _v11, val);
+
+ // Write out misc flags
+ val = (_samplePtr->_ampMod ? 0x80 : 0) | (_samplePtr->_vib ? 0x40 : 0)
+ | (_samplePtr->_egTyp ? 0x20 : 0) | (_samplePtr->_ksr ? 0x10 : 0)
+ | (_samplePtr->_freqMultiple & 0xF);
+ write2(8, 0x20 + _v11, val);
+
+ // Write out waveform select
+ write2(8, 0xE0 + _v11, _samplePtr->_waveformSelect & 3);
+
+ // Write out total level & scaling level
+ val = -((_samplePtr->_totalLevel & 0x3F) - 0x3F) | (_samplePtr->_scalingLevel << 6);
+ write2(8, 0x40 + _v11, val);
+}
+
+void ASound::updateFNumber() {
+ int loReg = 0xA0 + _activeChannelNumber;
+ int hiReg = 0xB0 + _activeChannelNumber;
+ int val1 = (_ports[hiReg] & 0x1F) << 8;
+ val1 += _ports[loReg] + _activeChannelPtr->_field1;
+ write2(8, loReg, val1);
+
+ int val2 = (_ports[hiReg] & 0x20) | (val1 >> 8);
+ write2(8, hiReg, val2);
+}
+
+int ASound::readBuffer(int16 *buffer, const int numSamples) {
+ Common::StackLock slock(_driverMutex);
+
+ int32 samplesLeft = numSamples;
+ memset(buffer, 0, sizeof(int16) * numSamples);
+ while (samplesLeft) {
+ if (!_samplesTillCallback) {
+ poll();
+ flush();
+
+ _samplesTillCallback = _samplesPerCallback;
+ _samplesTillCallbackRemainder += _samplesPerCallbackRemainder;
+ if (_samplesTillCallbackRemainder >= CALLBACKS_PER_SECOND) {
+ _samplesTillCallback++;
+ _samplesTillCallbackRemainder -= CALLBACKS_PER_SECOND;
+ }
+ }
+
+ int32 render = MIN<int>(samplesLeft, _samplesTillCallback);
+ samplesLeft -= render;
+ _samplesTillCallback -= render;
+
+ _opl->readBuffer(buffer, render);
+ buffer += render;
+ }
+ return numSamples;
+}
+
+int ASound::command0() {
+ bool isDisabled = _isDisabled;
+ _isDisabled = true;
+
+ for (int i = 0; i < ADLIB_CHANNEL_COUNT; ++i)
+ _channels[i].reset();
+
+ _v1 = 0;
+ _v2 = 0;
+ _freqMask1 = _freqMask2 = 0;
+ _freqBase1 = _freqBase2 = 0;
+ _v7 = 0;
+ _v8 = 0;
+
+ // Reset Adlib port registers
+ for (int reg = 0x4F; reg >= 0x40; --reg)
+ write2(8, reg, 0x3F);
+ for (int reg = 0xFF; reg >= 0x60; --reg)
+ write2(8, reg, 0);
+ for (int reg = 0x3F; reg > 0; --reg)
+ write2(8, reg, 0);
+ write2(8, 1, 0x20);
+
+ _isDisabled = isDisabled;
+ return 0;
+}
+
+int ASound::command1() {
+ for (int i = 0; i < ADLIB_CHANNEL_COUNT; ++i)
+ _channels[i].enable(0xFF);
+ return 0;
+}
+
+int ASound::command2() {
+ for (int i = 0; i < ADLIB_CHANNEL_MIDWAY; ++i)
+ _channels[i].setPtr2(_nullData);
+ return 0;
+}
+
+int ASound::command3() {
+ for (int i = 0; i < ADLIB_CHANNEL_MIDWAY; ++i)
+ _channels[i].enable(0xFF);
+ return 0;
+}
+
+int ASound::command4() {
+ for (int i = ADLIB_CHANNEL_MIDWAY; i < ADLIB_CHANNEL_COUNT; ++i)
+ _channels[i].setPtr2(_nullData);
+ return 0;
+}
+
+int ASound::command5() {
+ for (int i = 5; i < ADLIB_CHANNEL_COUNT; ++i)
+ _channels[i].enable(0xFF);
+ return 0;
+}
+
+int ASound::command6() {
+ _v9 = _v1;
+ _v1 = 0;
+ _v10 = _v2;
+ _v2 = 0;
+
+ channelOff(0x43);
+ channelOff(0x44);
+ channelOff(0x45);
+ channelOff(0x4B);
+ channelOff(0x4C);
+ channelOff(0x4D);
+ channelOff(0x53);
+ channelOff(0x54);
+ channelOff(0x55);
+
+ return 0;
+}
+
+int ASound::command7() {
+ channelOn(0x43, _channels[0]._volume);
+ channelOn(0x44, _channels[1]._volume);
+ channelOn(0x45, _channels[2]._volume);
+ channelOn(0x4B, _channels[3]._volume);
+ channelOn(0x4C, _channels[4]._volume);
+ channelOn(0x4D, _channels[5]._volume);
+
+ _v1 = _v9;
+ _v2 = _v10;
+
+ if (_v9 != _v10)
+ resultCheck();
+
+ _isDisabled = 0;
+ return _v10;
+}
+
+int ASound::command8() {
+ int result = 0;
+ for (int i = 0; i < ADLIB_CHANNEL_COUNT; ++i)
+ result |= _channels[i]._activeCount;
+
+ return result;
+}
+
+/*-----------------------------------------------------------------------*/
+
+const ASound1::CommandPtr ASound1::_commandList[42] = {
+ &ASound1::command0, &ASound1::command1, &ASound1::command2, &ASound1::command3,
+ &ASound1::command4, &ASound1::command5, &ASound1::command6, &ASound1::command7,
+ &ASound1::command8, &ASound1::command9, &ASound1::command10, &ASound1::command11,
+ &ASound1::command12, &ASound1::command13, &ASound1::command14, &ASound1::command15,
+ &ASound1::command16, &ASound1::command17, &ASound1::command18, &ASound1::command19,
+ &ASound1::command20, &ASound1::command21, &ASound1::command22, &ASound1::command23,
+ &ASound1::command24, &ASound1::command25, &ASound1::command26, &ASound1::command27,
+ &ASound1::command28, &ASound1::command29, &ASound1::command30, &ASound1::command31,
+ &ASound1::command32, &ASound1::command33, &ASound1::command34, &ASound1::command35,
+ &ASound1::command36, &ASound1::command37, &ASound1::command38, &ASound1::command39,
+ &ASound1::command40, &ASound1::command41
+};
+
+ASound1::ASound1(Audio::Mixer *mixer): ASound(mixer, "asound.001", 0x1520) {
+ _cmd23Toggle = false;
+
+ // Load sound samples
+ _soundFile.seek(_dataOffset + 0x12C);
+ for (int i = 0; i < 98; ++i)
+ _samples.push_back(AdlibSample(_soundFile));
+}
+
+int ASound1::command(int commandId, int param) {
+ if (commandId > 41)
+ return 0;
+
+ _commandParam = param;
+ _frameCounter = 0;
+ return (this->*_commandList[commandId])();
+}
+
+int ASound1::command9() {
+ playSound(0xC68, 12);
+ return 0;
+}
+
+int ASound1::command10() {
+ byte *pData1 = loadData(0x130E, 48);
+ if (!isSoundActive(pData1)) {
+ command1();
+ _channels[0].load(pData1);
+ _channels[1].load(loadData(0x133E, 392));
+ _channels[2].load(loadData(0x14C6, 46));
+ _channels[3].load(loadData(0x14F4, 48));
+ }
+
+ return 0;
+}
+
+int ASound1::command11() {
+ command111213();
+ _channels[0]._field1E = 0;
+ _channels[1]._field1E = 0;
+ return 0;
+}
+
+int ASound1::command12() {
+ command111213();
+ _channels[0]._field1E = 40;
+ _channels[1]._field1E = 0;
+ return 0;
+}
+
+int ASound1::command13() {
+ command111213();
+ _channels[0]._field1E = 40;
+ _channels[1]._field1E = 50;
+ return 0;
+}
+
+int ASound1::command14() {
+ playSound(0x1216, 248);
+ return 0;
+}
+
+int ASound1::command15() {
+ byte *pData1 = loadData(0x1524, 152);
+ if (!isSoundActive(pData1)) {
+ command1();
+ _channels[4].load(pData1);
+ _channels[5].load(loadData(0x15BC, 94));
+ _channels[6].load(loadData(0x161A, 94));
+ _channels[7].load(loadData(0x1678, 42));
+ _channels[8].load(loadData(0x16A2, 42));
+ }
+
+ return 0;
+}
+
+int ASound1::command16() {
+ playSound(0xC74, 14);
+ return 0;
+}
+
+int ASound1::command17() {
+ playSound(0xE9A, 10);
+ return 0;
+}
+
+int ASound1::command18() {
+ command1();
+ playSound(0xCA6, 20);
+ return 0;
+}
+
+int ASound1::command19() {
+ command1();
+ playSound(0xCBA, 74);
+ return 0;
+}
+
+int ASound1::command20() {
+ byte *pData = loadData(0xD18, 28);
+ if (!isSoundActive(pData))
+ playSoundData(pData);
+ return 0;
+}
+
+int ASound1::command21() {
+ playSound(0xD04, 20);
+ return 0;
+}
+
+int ASound1::command22() {
+ byte *pData = loadData(0xD34, 10);
+ pData[6] = (getRandomNumber() & 7) + 85;
+
+ if (!isSoundActive(pData))
+ playSoundData(pData);
+
+ return 0;
+}
+
+int ASound1::command23() {
+ _cmd23Toggle = !_cmd23Toggle;
+ playSound(_cmd23Toggle ? 0xD3E : 0xD46, 8);
+ return 0;
+}
+
+int ASound1::command24() {
+ playSound(0xD4E, 18);
+ playSound(0xD60, 20);
+ playSound(0xD74, 14);
+ return 0;
+}
+
+int ASound1::command25() {
+ byte *pData = loadData(0xD82, 16);
+ if (!isSoundActive(pData))
+ playSoundData(pData);
+
+ return 0;
+}
+
+int ASound1::command26() {
+ byte *pData = loadData(0xEEC, 10);
+ pData[5] = (command2627293032() + 0x7F) & 0xFF;
+
+ if (!isSoundActive(pData))
+ _channels[6].load(pData);
+
+ return 0;
+}
+
+int ASound1::command27() {
+ byte *pData = loadData(0xEE2, 10);
+ pData[5] = (command2627293032() + 0x40) & 0xFF;
+
+ if (!isSoundActive(pData))
+ _channels[7].load(pData);
+
+ return 0;
+}
+
+int ASound1::command28() {
+ playSound(0xD92, 28);
+ return 0;
+}
+
+int ASound1::command29() {
+ byte *pData = loadData(0xC82, 36);
+ byte v = (command2627293032() + 0x40) & 0xFF;
+ pData[7] = pData[13] = pData[21] = pData[27] = v;
+
+ if (!isSoundActive(pData))
+ playSoundData(pData, 0);
+
+ return 0;
+}
+
+int ASound1::command30() {
+ byte *pData = loadData(0xEA6, 16);
+ pData[7] = (command2627293032() + 0x40) & 0xFF;
+
+ if (!isSoundActive(pData))
+ playSoundData(pData, 0);
+
+ return 0;
+}
+
+int ASound1::command31() {
+ byte *pData = loadData(0xDAE, 14);
+ if (!isSoundActive(pData))
+ playSoundData(pData);
+
+ return 0;
+}
+
+int ASound1::command32() {
+ byte *pData = loadData(0xEB4, 46);
+ int v = command2627293032() + 0x40;
+ pData[9] = pData[17] = pData[25] = pData[33] = v & 0xFF;
+ pData[11] = pData[19] = pData[27] = pData[35] = v >> 8;
+
+ if (!isSoundActive(pData))
+ playSoundData(pData, 0);
+
+ return 0;
+}
+
+int ASound1::command33() {
+ playSound(0xDBC, 10);
+ playSound(0xDC6, 10);
+ return 0;
+}
+
+int ASound1::command34() {
+ int v = getRandomNumber() & 0x20;
+ if (!v)
+ v = 0x60;
+
+ byte *pData = loadData(0xDD0, 22);
+ pData[8] = pData[15] = v;
+ playSoundData(pData);
+ return 0;
+}
+
+int ASound1::command35() {
+ playSound(0xDE6, 16);
+ return 0;
+}
+
+int ASound1::command36() {
+ playSound(0xE10, 10);
+ command34();
+
+ return 0;
+}
+
+int ASound1::command37() {
+ playSound(0xE1A, 14);
+ return 0;
+}
+
+int ASound1::command38() {
+ playSound(0xE28, 114);
+ return 0;
+}
+
+int ASound1::command39() {
+ byte *pData1 = loadData(0x16CC, 82);
+ if (!isSoundActive(pData1)) {
+ _channels[5].load(pData1);
+ _channels[6].load(loadData(0x171E, 30));
+ _channels[7].load(loadData(0x173C, 40));
+ _channels[8].load(loadData(0x1764, 64));
+ }
+ return 0;
+}
+
+int ASound1::command40() {
+ playSound(0xDF6, 26);
+ return 0;
+}
+
+int ASound1::command41() {
+ playSound(0xC32, 34);
+ playSound(0xC54, 20);
+ return 0;
+}
+
+void ASound1::command111213() {
+ byte *pData1 = loadData(0xEF6, 408);
+ if (!isSoundActive(pData1)) {
+ command1();
+ _channels[0].load(pData1);
+ _channels[1].load(loadData(0x108E, 266));
+ _channels[2].load(loadData(0x1198, 66));
+ _channels[2].load(loadData(0x11DA, 60));
+ }
+}
+
+int ASound1::command2627293032() {
+ return (_commandParam > 0x40) ? _commandParam - 0x40 : _commandParam & 0xff00;
+}
+
+
+/*-----------------------------------------------------------------------*/
+
+const ASound2::CommandPtr ASound2::_commandList[44] = {
+ &ASound2::command0, &ASound2::command1, &ASound2::command2, &ASound2::command3,
+ &ASound2::command4, &ASound2::command5, &ASound2::command6, &ASound2::command7,
+ &ASound2::command8, &ASound2::command9, &ASound2::command10, &ASound2::command11,
+ &ASound2::command12, &ASound2::command13, &ASound2::command14, &ASound2::command15,
+ &ASound2::command16, &ASound2::command17, &ASound2::command18, &ASound2::command19,
+ &ASound2::command20, &ASound2::command21, &ASound2::command22, &ASound2::command23,
+ &ASound2::command24, &ASound2::command25, &ASound2::command26, &ASound2::command27,
+ &ASound2::command28, &ASound2::command29, &ASound2::command30, &ASound2::command31,
+ &ASound2::command32, &ASound2::command33, &ASound2::command34, &ASound2::command35,
+ &ASound2::command36, &ASound2::command37, &ASound2::command38, &ASound2::command39,
+ &ASound2::command40, &ASound2::command41, &ASound2::command42, &ASound2::command43
+};
+
+ASound2::ASound2(Audio::Mixer *mixer) : ASound(mixer, "asound.002", 0x15E0) {
+ _command12Param = 0xFD;
+
+ // Load sound samples
+ _soundFile.seek(_dataOffset + 0x144);
+ for (int i = 0; i < 164; ++i)
+ _samples.push_back(AdlibSample(_soundFile));
+}
+
+int ASound2::command(int commandId, int param) {
+ if (commandId > 43)
+ return 0;
+
+ _frameCounter = 0;
+ return (this->*_commandList[commandId])();
+}
+
+int ASound2::command0() {
+ _command12Param = 0xFD;
+ return ASound::command0();
+}
+
+int ASound2::command9() {
+ byte *pData1 = loadData(0x1094, 376);
+ if (!isSoundActive(pData1)) {
+ command1();
+ _channels[0].load(pData1);
+ _channels[2].load(loadData(0x123E, 130));
+
+ command9Randomize();
+ _channels[1].load(loadData(0x120C, 50));
+ }
+ return 0;
+}
+
+void ASound2::command9Randomize() {
+ // Randomization
+ int v;
+ while (((v = getRandomNumber()) & 0x3F) > 36)
+ ;
+
+ byte *pData = loadData(0x120C, 50);
+ command9Apply(pData, v + 20, -1);
+ command9Apply(pData + 1, 10 - ((v + 1) / 6), 1);
+}
+
+void ASound2::command9Apply(byte *data, int val, int incr) {
+ data += 8;
+ for (int ctr = 0; ctr < 10; ++ctr, data += 4, val += incr) {
+ *data = val;
+ }
+}
+
+int ASound2::command10() {
+ byte *pData1 = loadData(0x12C0, 60);
+ if (!isSoundActive(pData1)) {
+ command1();
+ _channels[0].load(pData1);
+ _channels[1].load(loadData(0x12FC, 318));
+ _channels[2].load(loadData(0x143A, 110));
+ }
+
+ return 0;
+}
+
+int ASound2::command11() {
+ byte *pData = loadData(0x14A8, 170);
+ if (!isSoundActive(pData)) {
+ playSoundData(pData);
+ playSoundData(loadData(0x1552, 1802));
+ playSoundData(loadData(0x1C5C, 716));
+ playSoundData(loadData(0x1F28, 106));
+ }
+
+ return 0;
+}
+
+int ASound2::command12() {
+ _command12Param += 26;
+ byte v = _command12Param & 0x7f;
+
+ byte *pData = loadData(0x4A5E, 38);
+ pData[5] = pData[20] = v;
+ playSoundData(pData);
+
+ pData = loadData(0x4A84, 30);
+ pData[5] = pData[18] = v;
+ playSoundData(pData);
+
+ return 0;
+}
+
+int ASound2::command13() {
+ playSoundData(loadData(0x4AA2, 20));
+ playSoundData(loadData(0x4AB6, 20));
+
+ return 0;
+}
+
+int ASound2::command14() {
+ playSound(0x4ACA, 40);
+ playSound(0x4AF2, 42);
+
+ return 0;
+}
+
+int ASound2::command15() {
+ byte *pData1 = loadData(0x1F92, 1074);
+ if (!isSoundActive(pData1)) {
+ command1();
+ playSoundData(pData1);
+ playSound(0x23C4, 1050);
+ playSound(0x27DE, 58);
+ playSound(0x2818, 712);
+ playSound(0x2AE0, 256);
+ }
+
+ return 0;
+}
+
+int ASound2::command16() {
+ byte *pData1 = loadData(0x3960, 280);
+ if (!isSoundActive(pData1)) {
+ command1();
+ playSoundData(pData1);
+ playSound(0x3A78, 266);
+ playSound(0x3B72, 322);
+ playSound(0x3CC4, 488);
+ playSound(0x3EAC, 104);
+ playSound(0x3F14, 104);
+ }
+
+ return 0;
+}
+
+int ASound2::command17() {
+ byte *pData1 = loadData(0x3F7C, 432);
+ if (!isSoundActive(pData1)) {
+ command1();
+ playSoundData(pData1);
+ playSound(0x412C, 422);
+ playSound(0x42D2, 424);
+ playSound(0x447A, 418);
+ }
+
+ return 0;
+}
+
+static const int command18_list[16][2] = {
+ { 0x337C, 28 }, { 0x3398, 26 }, { 0x33B2, 26 }, { 0x33CC, 26 },
+ { 0x33E6, 56 }, { 0x341E, 46 }, { 0x344C, 56 }, { 0x3484, 22 },
+ { 0x349A, 38 }, { 0x34C0, 62 }, { 0x34FE, 26 }, { 0x3518, 26 },
+ { 0x3532, 26 }, { 0x354C, 26 }, { 0x3566, 32 }, { 0x3586, 24 }
+};
+
+int ASound2::command18() {
+ if (_channels[3]._activeCount == 0) {
+ int idx = (getRandomNumber() & 0x1E) >> 1;
+ byte *pData = loadData(command18_list[idx][0], command18_list[idx][1]);
+ _channels[3].load(pData);
+ }
+
+ return 0;
+}
+
+int ASound2::command19() {
+ byte *pData1 = loadData(0x2BE0, 366);
+ if (!isSoundActive(pData1)) {
+ command1();
+ playSoundData(pData1);
+ playSound(0x2D4E, 460);
+ playSound(0x2F1A, 266);
+ playSound(0x3024, 328);
+ playSound(0x316C, 162);
+ playSound(0x320E, 366);
+ }
+
+ return 0;
+}
+
+int ASound2::command20() {
+ playSound(0x4A36, 40);
+
+ return 0;
+}
+
+int ASound2::command21() {
+ playSound(0x49DE, 16);
+ playSound(0x49EE, 16);
+ playSound(0x49FF, 16);
+
+ return 0;
+}
+
+int ASound2::command22() {
+ playSound(0x4A0E, 24);
+ playSound(0x4A26, 16);
+
+ return 0;
+}
+
+int ASound2::command23() {
+ playSound(0x49B6, 16);
+
+ return 0;
+}
+
+int ASound2::command24() {
+ playSound(0x49C6, 24);
+
+ return 0;
+}
+
+int ASound2::command25() {
+ playSound(0x49AC, 10);
+
+ return 0;
+}
+
+int ASound2::command26() {
+ playSound(0x498A, 14);
+ playSound(0x4998, 20);
+
+ return 0;
+}
+
+int ASound2::command27() {
+ playSound(0x4912, 80);
+ playSound(0x4962, 40);
+
+ return 0;
+}
+
+int ASound2::command28() {
+ playSound(0x48E8, 28);
+ playSound(0x4904, 14);
+
+ return 0;
+}
+
+int ASound2::command29() {
+ playSound(0x48B2, 22);
+
+ return 0;
+}
+
+int ASound2::command30() {
+ playSound(0x4870, 22);
+ playSound(0x4886, 22);
+ playSound(0x489C, 22);
+
+ return 0;
+}
+
+int ASound2::command31() {
+ playSound(0x482E, 22);
+ playSound(0x4844, 22);
+ playSound(0x489C, 22);
+
+ return 0;
+}
+
+int ASound2::command32() {
+ playSound(0x46E8, 10);
+
+ return 0;
+}
+
+int ASound2::command33() {
+ playSound(0x46D8, 16);
+
+ return 0;
+}
+
+int ASound2::command34() {
+ playSound(0x46C8, 16);
+
+ return 0;
+}
+
+int ASound2::command35() {
+ playSound(0x46B2, 22);
+
+ return 0;
+}
+
+int ASound2::command36() {
+ playSound(0x4624, 16);
+
+ return 0;
+}
+
+int ASound2::command37() {
+ playSound(0x4674, 20);
+ playSound(0x4688, 32);
+ playSound(0x46A8, 10);
+
+ return 0;
+}
+
+int ASound2::command38() {
+ byte *pData1 = loadData(0x359E, 202);
+ if (!isSoundActive(pData1)) {
+ command1();
+ playSoundData(pData1);
+ playSound(0x3668, 220);
+ playSound(0x3744, 124);
+ playSound(0x37C0, 162);
+ playSound(0x3862, 78);
+ playSound(0x38B0, 176);
+ }
+
+ return 0;
+}
+
+int ASound2::command39() {
+ byte *pData = loadData(0x466A, 10);
+ pData[6] = (getRandomNumber() & 7) + 85;
+ playSoundData(pData);
+
+ return 0;
+}
+
+int ASound2::command40() {
+ playSound(0x4634, 34);
+ playSound(0x4656, 20);
+
+ return 0;
+}
+
+int ASound2::command41() {
+ playSound(0x48C8, 32);
+
+ return 0;
+}
+
+int ASound2::command42() {
+ playSound(0x46F2, 156);
+ playSound(0x478E, 160);
+
+ return 0;
+}
+
+int ASound2::command43() {
+ playSound(0x4B1C, 40);
+ playSound(0x4B44, 41);
+
+ return 0;
+}
+
+/*-----------------------------------------------------------------------*/
+
+const ASound3::CommandPtr ASound3::_commandList[61] = {
+ &ASound3::command0, &ASound3::command1, &ASound3::command2, &ASound3::command3,
+ &ASound3::command4, &ASound3::command5, &ASound3::command6, &ASound3::command7,
+ &ASound3::command8, &ASound3::command9, &ASound3::command10, &ASound3::command11,
+ &ASound3::nullCommand, &ASound3::command13, &ASound3::command14, &ASound3::command15,
+ &ASound3::command16, &ASound3::command17, &ASound3::command18, &ASound3::command19,
+ &ASound3::command20, &ASound3::command21, &ASound3::command22, &ASound3::command23,
+ &ASound3::command24, &ASound3::command25, &ASound3::command26, &ASound3::command27,
+ &ASound3::command28, &ASound3::command29, &ASound3::command30, &ASound3::command31,
+ &ASound3::command32, &ASound3::command33, &ASound3::command34, &ASound3::command35,
+ &ASound3::command36, &ASound3::command37, &ASound3::command38, &ASound3::command39,
+ &ASound3::command40, &ASound3::command41, &ASound3::command42, &ASound3::command43,
+ &ASound3::command44, &ASound3::command45, &ASound3::command46, &ASound3::command47,
+ &ASound3::nullCommand, &ASound3::command49, &ASound3::command50, &ASound3::command51,
+ &ASound3::nullCommand, &ASound3::nullCommand, &ASound3::nullCommand, &ASound3::nullCommand,
+ &ASound3::nullCommand, &ASound3::command57, &ASound3::nullCommand, &ASound3::command59,
+ &ASound3::command60
+};
+
+ASound3::ASound3(Audio::Mixer *mixer) : ASound(mixer, "asound.003", 0x15B0) {
+ _command39Flag = false;
+
+ // Load sound samples
+ _soundFile.seek(_dataOffset + 0x122);
+ for (int i = 0; i < 192; ++i)
+ _samples.push_back(AdlibSample(_soundFile));
+}
+
+int ASound3::command(int commandId, int param) {
+ if (commandId > 60)
+ return 0;
+
+ _commandParam = param;
+ _frameCounter = 0;
+ return (this->*_commandList[commandId])();
+}
+
+int ASound3::command9() {
+ AdlibChannel::_channelsEnabled = _commandParam != 0;
+
+ return 0;
+}
+
+int ASound3::command10() {
+ byte *pData1 = loadData(0x13EA, 254);
+ if (!isSoundActive(pData1)) {
+ command1();
+ _channels[0].load(pData1);
+ _channels[1].load(loadData(0X14E8, 452));
+ _channels[2].load(loadData(0x16AC, 396));
+ _channels[3].load(loadData(0x1838, 118));
+ _channels[4].load(loadData(0x18AE, 74));
+ }
+
+ return 0;
+}
+
+int ASound3::command11() {
+ byte *pData1 = loadData(0x2B84, 596);
+ if (!isSoundActive(pData1)) {
+ command1();
+ _channels[0].load(pData1);
+ _channels[1].load(loadData(0x2DD8, 562));
+ _channels[2].load(loadData(0x300A, 1694));
+ _channels[3].load(loadData(0x36A8, 1100));
+ _channels[4].load(loadData(0x3AF4, 420));
+ _channels[5].load(loadData(0x3C98, 1516));
+ }
+
+ return 0;
+}
+
+int ASound3::command13() {
+ byte *pData1 = loadData(0x4470, 64);
+ if (!isSoundActive(pData1)) {
+ command1();
+ playSoundData(pData1);
+ playSound(0x44B0, 64);
+ playSound(0x44F0, 64);
+ playSound(0x4530, 64);
+ playSound(0x4570, 64);
+ playSound(0X45b0, 64);
+ }
+
+ return 0;
+}
+
+int ASound3::command14() {
+ byte *pData1 = loadData(0X45F0, 36);
+ if (!isSoundActive(pData1)) {
+ command1();
+ playSoundData(pData1);
+ playSound(0x4614, 36);
+ playSound(0x4638, 36);
+ playSound(0x465C, 32);
+ playSound(0x467C, 76);
+ playSound(0x46C8, 74);
+ }
+
+ return 0;
+}
+
+int ASound3::command15() {
+ _channels[3].load(loadData(0x36A8, 1100));
+ _channels[4].load(loadData(0x3AF4, 420));
+ _channels[5].load(loadData(0x3C98, 1516));
+
+ _channels[3]._field20 = 0xDD;
+ _channels[4]._field20 = 0xDD;
+ _channels[5]._field20 = 0xDD;
+
+ return 0;
+}
+
+int ASound3::command16() {
+ byte *pData1 = loadData(0x4712, 398);
+ if (!isSoundActive(pData1)) {
+ command1();
+ _channels[0].load(pData1);
+ _channels[1].load(loadData(0x48A0, 354));
+ _channels[2].load(loadData(0x4A02, 410));
+ _channels[3].load(loadData(0x4B9C, 392));
+ }
+
+ return 0;
+}
+
+int ASound3::command17() {
+ byte *pData1 = loadData(0x18F8, 400);
+ if (!isSoundActive(pData1)) {
+ command1();
+ _channels[0].load(pData1);
+ _channels[1].load(loadData(0x1A88, 680));
+ _channels[2].load(loadData(0x1D30, 478));
+ _channels[3].load(loadData(0x1F0E, 1146));
+ _channels[4].load(loadData(0x2388, 1006));
+ _channels[5].load(loadData(0x2776, 1038));
+ }
+
+ return 0;
+}
+
+int ASound3::command18() {
+ byte *pData1 = loadData(0x4284, 142);
+ if (!isSoundActive(pData1)) {
+ command1();
+ playSoundData(pData1);
+ playSound(0x4312, 172);
+ playSound(0x43BE, 88);
+ playSound(0x4416, 90);
+ }
+
+ return 0;
+}
+
+int ASound3::command19() {
+ playSound(0x4F6, 8);
+
+ return 0;
+}
+
+int ASound3::command20() {
+ playSound(0x4F1C, 10);
+
+ return 0;
+}
+
+int ASound3::command21() {
+ playSound(0x4F2E, 8);
+
+ return 0;
+}
+
+int ASound3::command22() {
+ playSound(0x4F36, 16);
+
+ return 0;
+}
+
+int ASound3::command23() {
+ playSound(0x4F50, 10);
+ playSound(0x4F46, 10);
+
+ return 0;
+}
+
+int ASound3::command24() {
+ // WORKAROUND: Original calls isSoundActive without loading data pointer
+ byte *pData = loadData(0x4EFC, 12);
+ if (!isSoundActive(pData)) {
+ int v;
+ while ((v = (getRandomNumber() & 0x3F)) > 45)
+ ;
+
+ pData[6] = v + 19;
+ playSoundData(pData);
+ }
+
+ return 0;
+}
+
+int ASound3::command25() {
+ playSound(0x4EE6, 22);
+
+ return 0;
+}
+
+int ASound3::command26() {
+ playSound(0x4F5A, 8);
+
+ return 0;
+}
+
+int ASound3::command27() {
+ playSound(0x4DA2, 34);
+ playSound(0x4DC4, 20);
+
+ return 0;
+}
+
+int ASound3::command28() {
+ playSound(0x4F72, 10);
+ playSound(0x4F72, 10);
+
+ return 0;
+}
+
+int ASound3::command29() {
+ playSound(0x4F72, 10);
+ playSound(0x4F72, 10);
+
+ return 0;
+}
+
+int ASound3::command30() {
+ playSound(0x4E5A, 22);
+ playSound(0x4E70, 22);
+ playSound(0x4E86, 22);
+
+ return 0;
+}
+
+int ASound3::command31() {
+ playSound(0x4F7C, 40);
+
+ return 0;
+}
+
+int ASound3::command32() {
+ playSound(0x4ED2, 10);
+
+ return 0;
+}
+
+int ASound3::command33() {
+ playSound(0x4EC2, 16);
+
+ return 0;
+}
+
+int ASound3::command34() {
+ playSound(0x4EB2, 16);
+
+ return 0;
+}
+
+int ASound3::command35() {
+ playSound(0x4E9C, 22);
+
+ return 0;
+}
+
+int ASound3::command36() {
+ playSound(0x4D2C, 16);
+
+ return 0;
+}
+
+int ASound3::command37() {
+ playSound(0x4E1E, 20);
+ playSound(0x4E32, 30);
+ playSound(0x4E50, 10);
+
+ return 0;
+}
+
+int ASound3::command38() {
+ playSound(0x4FAC, 10);
+
+ return 0;
+}
+
+int ASound3::command39() {
+ _command39Flag = !_command39Flag;
+ if (_command39Flag) {
+ playSound(0x4FD0, 8);
+ } else {
+ playSound(0x4FD8, 8);
+ }
+
+ return 0;
+}
+
+int ASound3::command40() {
+ _command39Flag = !_command39Flag;
+ if (_command39Flag) {
+ playSound(0x4EE0, 8);
+ } else {
+ playSound(0x4EE8, 8);
+ }
+
+ return 0;
+}
+
+int ASound3::command41() {
+ playSound(0x4F08, 20);
+
+ return 0;
+}
+
+int ASound3::command42() {
+ playSound(0x4DD8, 28);
+ playSound(0x4DF4, 42);
+
+ return 0;
+}
+
+int ASound3::command43() {
+ playSound(0x4FB6, 12);
+ playSound(0x4FC2, 14);
+
+ return 0;
+}
+
+int ASound3::command44() {
+ playSound(0x4FFE, 14);
+
+ return 0;
+}
+
+int ASound3::command45() {
+ playSound(0x500C, 14);
+
+ return 0;
+}
+
+int ASound3::command46() {
+ playSound(0x4D78, 14);
+ playSound(0x4D86, 14);
+ playSound(0x4D94, 14);
+
+ return 0;
+}
+
+int ASound3::command47() {
+ playSound(0x4D62, 8);
+ playSound(0x4D6A, 14);
+
+ return 0;
+}
+
+int ASound3::command49() {
+ playSound(0x4D62, 8);
+ playSound(0x4D6A, 14);
+
+ return 0;
+}
+
+int ASound3::command50() {
+ playSound(0x4D3C, 14);
+ playSound(0x4D4A, 14);
+ playSound(0x4D58, 10);
+
+ return 0;
+}
+
+int ASound3::command51() {
+ playSound(0x4FF0, 14);
+
+ return 0;
+}
+
+int ASound3::command57() {
+ byte *pData = loadData(0x4EDC, 10);
+ pData[6] = (getRandomNumber() & 7) + 85;
+ playSoundData(pData);
+
+ return 0;
+}
+
+int ASound3::command59() {
+ playSound(0x4F62, 16);
+
+ return 0;
+}
+
+int ASound3::command60() {
+ playSound(0x4FA4, 8);
+
+ return 0;
+}
+
+/*-----------------------------------------------------------------------*/
+
+const ASound4::CommandPtr ASound4::_commandList[61] = {
+ &ASound4::command0, &ASound4::command1, &ASound4::command2, &ASound4::command3,
+ &ASound4::command4, &ASound4::command5, &ASound4::command6, &ASound4::command7,
+ &ASound4::command8, &ASound4::nullCommand, &ASound4::command10, &ASound4::nullCommand,
+ &ASound4::command12, &ASound4::nullCommand, &ASound4::nullCommand, &ASound4::nullCommand,
+ &ASound4::nullCommand, &ASound4::nullCommand, &ASound4::nullCommand, &ASound4::command19,
+ &ASound4::command20, &ASound4::command21, &ASound4::nullCommand, &ASound4::nullCommand,
+ &ASound4::command24, &ASound4::nullCommand, &ASound4::nullCommand, &ASound4::command27,
+ &ASound4::nullCommand, &ASound4::nullCommand, &ASound4::command30, &ASound4::nullCommand,
+ &ASound4::command32, &ASound4::command33, &ASound4::command34, &ASound4::command35,
+ &ASound4::command36, &ASound4::command37, &ASound4::command38, &ASound4::nullCommand,
+ &ASound4::nullCommand, &ASound4::nullCommand, &ASound4::nullCommand, &ASound4::command43,
+ &ASound4::nullCommand, &ASound4::nullCommand, &ASound4::nullCommand, &ASound4::nullCommand,
+ &ASound4::nullCommand, &ASound4::nullCommand, &ASound4::nullCommand, &ASound4::nullCommand,
+ &ASound4::nullCommand, &ASound4::nullCommand, &ASound4::nullCommand, &ASound4::nullCommand,
+ &ASound4::nullCommand, &ASound4::command57, &ASound4::nullCommand, &ASound4::command59,
+ &ASound4::command60
+};
+
+ASound4::ASound4(Audio::Mixer *mixer) : ASound(mixer, "asound.004", 0x14F0) {
+ // Load sound samples
+ _soundFile.seek(_dataOffset + 0x122);
+ for (int i = 0; i < 210; ++i)
+ _samples.push_back(AdlibSample(_soundFile));
+}
+
+int ASound4::command(int commandId, int param) {
+ if (commandId > 60)
+ return 0;
+
+ _commandParam = param;
+ _frameCounter = 0;
+ return (this->*_commandList[commandId])();
+}
+
+int ASound4::command10() {
+ byte *pData = loadData(0x22AA, 254);
+ if (!isSoundActive(pData)) {
+ command1();
+ _channels[0].load(pData);
+ _channels[1].load(loadData(0x23A8, 452));
+ _channels[2].load(loadData(0x256C, 396));
+ _channels[3].load(loadData(0x26F8, 118));
+ _channels[4].load(loadData(0x276E, 74));
+ }
+
+ return 0;
+}
+
+int ASound4::command12() {
+ byte *pData = loadData(0x16A8, 550);
+ if (!isSoundActive(pData)) {
+ command1();
+ _channels[0].load(pData);
+ _channels[1].load(loadData(0x18CE, 442));
+ _channels[2].load(loadData(0x1A88, 298));
+ _channels[3].load(loadData(0x1BB2, 354));
+ _channels[4].load(loadData(0x1D14, 572));
+ _channels[4].load(loadData(0x1F50, 560));
+ }
+
+ int v = (_commandParam > 0x40) ? _commandParam - 0x40 : 0;
+ v += 0xB5;
+ for (int channelNum = 0; channelNum < 6; ++channelNum)
+ _channels[channelNum]._field20 = v;
+
+ return 0;
+}
+
+int ASound4::command19() {
+ playSound(0x28EC, 8);
+
+ return 0;
+}
+
+int ASound4::command20() {
+ playSound(0x28E2, 10);
+
+ return 0;
+}
+
+int ASound4::command21() {
+ playSound(0x27C0, 8);
+
+ return 0;
+}
+
+int ASound4::command24() {
+ int v;
+ while ((v = (getRandomNumber() & 0x3F)) > 45)
+ ;
+
+ byte *pData = loadData(0x28D6, 12);
+ pData[6] = v + 19;
+ playSoundData(pData);
+
+ return 0;
+}
+
+int ASound4::command27() {
+ playSound(0x27D8, 34);
+ playSound(0x27FA, 20);
+
+ return 0;
+}
+
+int ASound4::command30() {
+ playSound(0x284A, 22);
+ playSound(0x2860, 22);
+ playSound(0x2876, 22);
+
+ return 0;
+}
+
+int ASound4::command32() {
+ playSound(0x28C2, 10);
+
+ return 0;
+}
+
+int ASound4::command33() {
+ playSound(0x28B2, 16);
+
+ return 0;
+}
+
+int ASound4::command34() {
+ playSound(0x28A2, 16);
+
+ return 0;
+}
+
+int ASound4::command35() {
+ playSound(0x288C, 22);
+
+ return 0;
+}
+
+int ASound4::command36() {
+ playSound(0x27C8, 16);
+
+ return 0;
+}
+
+int ASound4::command37() {
+ playSound(0x280E, 20);
+ playSound(0x2822, 30);
+ playSound(0x2840, 10);
+
+ return 0;
+}
+
+int ASound4::command38() {
+ playSound(0x2904, 10);
+
+ return 0;
+}
+
+int ASound4::command43() {
+ playSound(0x290E, 12);
+ playSound(0x291A, 14);
+
+ return 0;
+}
+
+int ASound4::command52() {
+ byte *pData = loadData(0x23A8, 452);
+ if (_channels[1]._ptr1 == pData) {
+ pData = loadData(0x146E, 570);
+ if (!isSoundActive(pData)) {
+ _channels[0].load(pData);
+ _channels[1]._field20 = 0xD8;
+ _channels[2]._field20 = 0xD8;
+ }
+ }
+
+ return 0;
+}
+
+int ASound4::command53() {
+ method1();
+ _channels[0]._field20 = 0;
+
+ return 0;
+}
+
+int ASound4::command54() {
+ method1();
+ _channels[1]._field20 = 0;
+ _channels[2]._field20 = 0;
+
+ return 0;
+}
+
+int ASound4::command55() {
+ method1();
+ _channels[3]._field20 = 0;
+ _channels[4]._field20 = 0;
+
+ return 0;
+}
+
+int ASound4::command56() {
+ method1();
+ _channels[5]._field20 = 0;
+
+ return 0;
+}
+
+int ASound4::command57() {
+ int v = (getRandomNumber() & 7) + 85;
+ byte *pData = loadData(0x28CC, 10);
+ pData[6] = v;
+ playSoundData(pData);
+
+ return 0;
+}
+
+int ASound4::command58() {
+ byte *pData = loadData(0x146E, 570);
+ if (_channels[1]._ptr1 == pData) {
+ _channels[0].load(loadData(0x22AA, 254));
+ _channels[1]._field20 = 0;
+ _channels[2]._field20 = 0;
+ }
+
+ return 0;
+}
+
+int ASound4::command59() {
+ playSound(0x28F4, 8);
+
+ return 0;
+}
+
+int ASound4::command60() {
+ playSound(0x28FC, 8);
+
+ return 0;
+}
+
+void ASound4::method1() {
+ byte *pData = loadData(0x2180, 58);
+ if (!isSoundActive(pData)) {
+ command1();
+
+ _channels[0].load(pData);
+ _channels[1].load(loadData(0x21BA, 48));
+ _channels[2].load(loadData(0x21EA, 50));
+ _channels[3].load(loadData(0x221C, 40));
+ _channels[4].load(loadData(0x2244, 28));
+ _channels[5].load(loadData(0x2260, 74));
+
+ for (int channel = 0; channel < 6; ++channel)
+ _channels[channel]._field20 = 0xB5;
+ }
+}
+
+
+/*-----------------------------------------------------------------------*/
+
+const ASound5::CommandPtr ASound5::_commandList[42] = {
+ &ASound5::command0, &ASound5::command1, &ASound5::command2, &ASound5::command3,
+ &ASound5::command4, &ASound5::command5, &ASound5::command6, &ASound5::command7,
+ &ASound5::command8, &ASound5::command9, &ASound5::command10, &ASound5::command11,
+ &ASound5::command11, &ASound5::command13, &ASound5::command14, &ASound5::command15,
+ &ASound5::command16, &ASound5::command17, &ASound5::command18, &ASound5::command19,
+ &ASound5::command20, &ASound5::command21, &ASound5::command22, &ASound5::command23,
+ &ASound5::command11, &ASound5::command11, &ASound5::command26, &ASound5::command27,
+ &ASound5::command28, &ASound5::command29, &ASound5::command30, &ASound5::command31,
+ &ASound5::command32, &ASound5::command33, &ASound5::command34, &ASound5::command35,
+ &ASound5::command36, &ASound5::command37, &ASound5::command38, &ASound5::command39,
+ &ASound5::command40, &ASound5::command41
+};
+
+ASound5::ASound5(Audio::Mixer *mixer) : ASound(mixer, "asound.002", 0x15E0) {
+ // Load sound samples
+ _soundFile.seek(_dataOffset + 0x144);
+ for (int i = 0; i < 164; ++i)
+ _samples.push_back(AdlibSample(_soundFile));
+}
+
+int ASound5::command(int commandId, int param) {
+ if (commandId > 41)
+ return 0;
+
+ _frameCounter = 0;
+ return (this->*_commandList[commandId])();
+}
+
+int ASound5::command9() {
+ byte *pData = loadData(0x2114, 10);
+ pData[6] = (getRandomNumber() & 7) + 85;
+ playSoundData(pData);
+
+ return 0;
+}
+
+int ASound5::command10() {
+ playSound(0x211E, 10);
+
+ return 0;
+}
+
+int ASound5::command11() {
+ playSound(0x2016, 10);
+
+ return 0;
+}
+
+int ASound5::command13() {
+ playSound(0x2154, 10);
+
+ return 0;
+}
+
+int ASound5::command14() {
+ playSound(0x21DC, 22);
+
+ return 0;
+}
+
+int ASound5::command15() {
+ byte *pData = loadData(0x21DC, 22);
+ if (_channels[0]._ptr1 == pData) {
+ pData = loadData(0x1F2, 12);
+ _channels[0]._soundData = pData;
+ _channels[0]._field17 = 1;
+ _channels[0]._field19 = 1;
+ }
+
+ return 0;
+}
+
+int ASound5::command16() {
+ playSound(0x214C, 8);
+
+ return 0;
+}
+
+int ASound5::command17() {
+ playSound(0x2142, 10);
+
+ return 0;
+}
+
+int ASound5::command18() {
+ playSound(0x21A2, 22);
+
+ return 0;
+}
+
+int ASound5::command19() {
+ playSound(0x2190, 18);
+
+ return 0;
+}
+
+int ASound5::command20() {
+ playSound(0x2170, 16);
+
+ return 0;
+}
+
+int ASound5::command21() {
+ playSound(0x2180, 16);
+
+ return 0;
+}
+
+int ASound5::command22() {
+ playSound(0x2168, 8);
+
+ return 0;
+}
+
+int ASound5::command23() {
+ playSound(0x215E, 10);
+
+ return 0;
+}
+
+int ASound5::command26() {
+ playSound(0x21B8, 12);
+
+ return 0;
+}
+
+int ASound5::command27() {
+ playSound(0x21C4, 24);
+
+ return 0;
+}
+
+int ASound5::command28() {
+ playSound(0x2020, 34);
+ playSound(0x4904, 20);
+
+ return 0;
+}
+
+int ASound5::command29() {
+ byte *pData = loadData(0x17C, 312);
+ if (!isSoundActive(pData)) {
+ command1();
+ _channels[0].load(pData);
+ _channels[1].load(loadData(0x1864, 304));
+ _channels[2].load(loadData(0x1994, 222));
+ _channels[3].load(loadData(0x1864, 304));
+ _channels[4].load(loadData(0x1994, 222));
+ }
+
+ return 0;
+}
+
+int ASound5::command30() {
+ playSound(0x2092, 22);
+ playSound(0x20A8, 22);
+ playSound(0x20BE, 22);
+
+ return 0;
+}
+
+int ASound5::command31() {
+ playSound(0x2128, 22);
+ playSound(0x2134, 14);
+
+ return 0;
+}
+
+int ASound5::command32() {
+ playSound(0x210A, 10);
+
+ return 0;
+}
+
+int ASound5::command33() {
+ playSound(0x20FA, 16);
+
+ return 0;
+}
+
+int ASound5::command34() {
+ playSound(0x20EA, 16);
+
+ return 0;
+}
+
+int ASound5::command35() {
+ playSound(0x20D4, 22);
+
+ return 0;
+}
+
+int ASound5::command36() {
+ playSound(0x2006, 16);
+
+ return 0;
+}
+
+int ASound5::command37() {
+ playSound(0x2056, 20);
+ playSound(0x206A, 30);
+ playSound(0x2088, 10);
+
+ return 0;
+}
+
+int ASound5::command38() {
+ byte *pData1 = loadData(0x14F2, 570);
+ if (_channels[3]._ptr1 == pData1) {
+ _channels[3].load(loadData(0x1A72, 522));
+ _channels[3].load(loadData(0x1C7C, 874));
+ }
+
+ return 0;
+}
+
+int ASound5::command39() {
+ playSound(0x1FEE, 8);
+
+ return 0;
+}
+
+int ASound5::command40() {
+ playSound(0x1FF6, 16);
+
+ return 0;
+}
+
+int ASound5::command41() {
+ byte *pData1 = loadData(0x14F2, 570);
+ if (!isSoundActive(pData1)) {
+ byte *pData2 = loadData(0x1A72, 522);
+ if (_channels[3]._ptr1 == pData2) {
+ _channels[3].load(pData1);
+ _channels[4].load(loadData(0x1FE6, 8));
+ }
+ }
+
+ return 0;
+}
+
+/*-----------------------------------------------------------------------*/
+
+const ASound6::CommandPtr ASound6::_commandList[30] = {
+ &ASound6::command0, &ASound6::command1, &ASound6::command2, &ASound6::command3,
+ &ASound6::command4, &ASound6::command5, &ASound6::command6, &ASound6::command7,
+ &ASound6::command8, &ASound6::command9, &ASound6::command10, &ASound6::command11,
+ &ASound6::command11, &ASound6::command13, &ASound6::command14, &ASound6::command15,
+ &ASound6::command16, &ASound6::command17, &ASound6::command18, &ASound6::command19,
+ &ASound6::command20, &ASound6::command21, &ASound6::command22, &ASound6::command23,
+ &ASound6::command11, &ASound6::command11, &ASound6::nullCommand, &ASound6::nullCommand,
+ &ASound6::nullCommand, &ASound6::command29
+};
+
+ASound6::ASound6(Audio::Mixer *mixer) : ASound(mixer, "asound.006", 0x1390) {
+ // Load sound samples
+ _soundFile.seek(_dataOffset + 0x122);
+ for (int i = 0; i < 200; ++i)
+ _samples.push_back(AdlibSample(_soundFile));
+}
+
+int ASound6::command(int commandId, int param) {
+ if (commandId > 29)
+ return 0;
+
+ _frameCounter = 0;
+ return (this->*_commandList[commandId])();
+}
+
+int ASound6::command9() {
+ byte *pData = loadData(0x2194, 10);
+ pData[6] = (getRandomNumber() & 7) + 85;
+ playSoundData(pData);
+
+ return 0;
+}
+
+int ASound6::command10() {
+ playSound(0x2224, 24);
+
+ return 0;
+}
+
+int ASound6::command11() {
+ playSound(0x2202, 34);
+
+ return 0;
+}
+
+int ASound6::command12() {
+ playSound(0x2246, 8);
+
+ return 0;
+}
+
+int ASound6::command13() {
+ playSound(0x2298, 28);
+
+ return 0;
+}
+
+int ASound6::command14() {
+ playSound(0x22B4, 27);
+
+ return 0;
+}
+
+int ASound6::command15() {
+ playSound(0x219E, 12);
+
+ return 0;
+}
+
+int ASound6::command16() {
+ playSound(0x21AA, 22);
+ playSound(0x21C0, 12);
+
+ return 0;
+}
+
+int ASound6::command17() {
+ playSound(0x21CC, 54);
+
+ return 0;
+}
+
+int ASound6::command18() {
+ playSound(0x2270, 16);
+
+ return 0;
+}
+
+int ASound6::command19() {
+ playSound(0x2280, 16);
+
+ return 0;
+}
+
+int ASound6::command20() {
+ playSound(0x223C, 10);
+
+ return 0;
+}
+
+int ASound6::command21() {
+ playSound(0x224E, 34);
+
+ return 0;
+}
+
+int ASound6::command22() {
+ playSound(0x2290, 8);
+
+ return 0;
+}
+
+int ASound6::command23() {
+ playSound(0x215E, 34);
+ playSound(0x2180, 20);
+
+ return 0;
+}
+
+int ASound6::command24() {
+ byte *pData1 = loadData(0x1D54, 540);
+ if (!isSoundActive(pData1)) {
+ command1();
+ _channels[0].load(pData1);
+ _channels[1].load(loadData(0x1F70, 52));
+ _channels[2].load(loadData(0x1FA4, 430));
+ }
+
+ return 0;
+}
+
+int ASound6::command25() {
+ playSound(0x2152, 12);
+
+ return 0;
+}
+
+int ASound6::command29() {
+ byte *pData1 = loadData(0x149A, 312);
+ if (!isSoundActive(pData1)) {
+ command1();
+ _channels[0].load(pData1);
+ _channels[1].load(loadData(0x15D2, 304));
+ _channels[2].load(loadData(0x1702, 222));
+ _channels[3].load(loadData(0x17E0, 522));
+ _channels[4].load(loadData(0x19EA, 874));
+ }
+
+ return 0;
+}
+
+/*-----------------------------------------------------------------------*/
+
+const ASound7::CommandPtr ASound7::_commandList[38] = {
+ &ASound7::command0, &ASound7::command1, &ASound7::command2, &ASound7::command3,
+ &ASound7::command4, &ASound7::command5, &ASound7::command6, &ASound7::command7,
+ &ASound7::command8, &ASound7::command9, &ASound7::nullCommand, &ASound7::nullCommand,
+ &ASound7::nullCommand, &ASound7::nullCommand, &ASound7::nullCommand, &ASound7::command15,
+ &ASound7::command16, &ASound7::command16, &ASound7::command18, &ASound7::command19,
+ &ASound7::command20, &ASound7::command21, &ASound7::command22, &ASound7::command23,
+ &ASound7::command24, &ASound7::command25, &ASound7::command26, &ASound7::command27,
+ &ASound7::command28, &ASound7::nullCommand, &ASound7::command30, &ASound7::nullCommand,
+ &ASound7::command32, &ASound7::command33, &ASound7::command34, &ASound7::command35,
+ &ASound7::command36, &ASound7::command37
+};
+
+ASound7::ASound7(Audio::Mixer *mixer) : ASound(mixer, "asound.007", 0x1460) {
+ // Load sound samples
+ _soundFile.seek(_dataOffset + 0x122);
+ for (int i = 0; i < 214; ++i)
+ _samples.push_back(AdlibSample(_soundFile));
+}
+
+int ASound7::command(int commandId, int param) {
+ if (commandId > 38)
+ return 0;
+
+ _frameCounter = 0;
+ return (this->*_commandList[commandId])();
+}
+
+int ASound7::command9() {
+ byte *pData1 = loadData(0x2992, 122);
+ if (!isSoundActive(pData1)) {
+ _channels[0].load(pData1);
+ _channels[1].load(loadData(0x2A0C, 76));
+ _channels[2].load(loadData(0x2A58, 122));
+ _channels[3].load(loadData(0x2AD2, 38));
+ }
+
+ return 0;
+}
+
+int ASound7::command15() {
+ byte *pData = loadData(0x2B3E, 10);
+ pData[6] = (getRandomNumber() & 7) + 85;
+
+ return 0;
+}
+
+int ASound7::command16() {
+ playSound(0x2CE2, 8);
+
+ return 0;
+}
+
+int ASound7::command18() {
+ playSound(0x2C94, 22);
+
+ return 0;
+}
+
+int ASound7::command19() {
+ byte *pData1 = loadData(0x2C94, 22);
+ byte *pData2 = loadData(0x2CAA, 16);
+ if (_channels[8]._ptr1 == pData1 || _channels[8]._ptr1 == pData2) {
+ _channels[8]._soundData = loadData(0x2CBA, 12);
+ _channels[8]._field17 = 1;
+ _channels[8]._field19 = 1;
+ }
+
+ return 0;
+}
+
+int ASound7::command20() {
+ playSound(0x2CD0, 18);
+
+ return 0;
+}
+
+int ASound7::command21() {
+ playSound(0x2CC6, 10);
+
+ return 0;
+}
+
+int ASound7::command22() {
+ playSound(0x2C08, 140);
+
+ return 0;
+}
+
+int ASound7::command23() {
+ playSound(0x2B08, 34);
+ playSound(0x2B2A, 20);
+
+ return 0;
+}
+
+int ASound7::command24() {
+ byte *pData1 = loadData(0x14C6, 144);
+ if (!isSoundActive(pData1)) {
+ command1();
+ _channels[0].load(pData1);
+ _channels[1].load(loadData(0x1556, 146));
+ _channels[2].load(loadData(0x15E8, 138));
+ _channels[3].load(loadData(0x1672, 122));
+ _channels[4].load(loadData(0x16EC, 74));
+ }
+
+ return 0;
+}
+
+int ASound7::command25() {
+ byte *pData1 = loadData(0x1DBE, 182);
+ if (!isSoundActive(pData1)) {
+ command1();
+ _channels[0].load(pData1);
+ _channels[1].load(loadData(0x1E74, 182));
+ _channels[2].load(loadData(0x1F2A, 186));
+ _channels[3].load(loadData(0x1FE4, 244));
+ }
+
+ return 0;
+}
+
+int ASound7::command26() {
+ byte *pData1 = loadData(0x20D8, 312);
+ if (!isSoundActive(pData1)) {
+ command1();
+ _channels[0].load(pData1);
+ _channels[1].load(loadData(0x2210, 304));
+ _channels[2].load(loadData(0x2340, 222));
+ _channels[3].load(loadData(0x241E, 522));
+ _channels[4].load(loadData(0x2628, 874));
+ }
+
+ return 0;
+}
+
+int ASound7::command27() {
+ byte *pData1 = loadData(0x1736, 158);
+ if (!isSoundActive(pData1)) {
+ command1();
+ _channels[0].load(pData1);
+ _channels[1].load(loadData(0x17D4, 288));
+ _channels[2].load(loadData(0x18F4, 290));
+ _channels[3].load(loadData(0x1A16, 396));
+ _channels[4].load(loadData(0x1BA2, 380));
+ _channels[5].load(loadData(0x1D1E, 160));
+ }
+
+ return 0;
+}
+
+int ASound7::command28() {
+ playSound(0x2CAA, 16);
+
+ return 0;
+}
+
+int ASound7::command30() {
+ playSound(0x2B86, 22);
+ playSound(0x2B9C, 22);
+ playSound(0x2BB2, 22);
+
+ return 0;
+}
+
+int ASound7::command32() {
+ playSound(0x2BFE, 10);
+
+ return 0;
+}
+
+int ASound7::command33() {
+ playSound(0x2BEE, 16);
+
+ return 0;
+}
+
+int ASound7::command34() {
+ playSound(0x2BDE, 16);
+
+ return 0;
+}
+
+int ASound7::command35() {
+ playSound(0x2BC8, 22);
+
+ return 0;
+}
+
+int ASound7::command36() {
+ playSound(0x2AF8, 16);
+
+ return 0;
+}
+
+int ASound7::command37() {
+ playSound(0x2B48, 20);
+ playSound(0x2B5C, 32);
+ playSound(0x2B7C, 10);
+
+ return 0;
+}
+
+/*-----------------------------------------------------------------------*/
+
+const ASound8::CommandPtr ASound8::_commandList[38] = {
+ &ASound8::command0, &ASound8::command1, &ASound8::command2, &ASound8::command3,
+ &ASound8::command4, &ASound8::command5, &ASound8::command6, &ASound8::command7,
+ &ASound8::command8, &ASound8::command9, &ASound8::command10, &ASound8::command11,
+ &ASound8::command12, &ASound8::command13, &ASound8::command14, &ASound8::command15,
+ &ASound8::command16, &ASound8::command16, &ASound8::command18, &ASound8::command19,
+ &ASound8::command20, &ASound8::command21, &ASound8::command22, &ASound8::command23,
+ &ASound8::command24, &ASound8::command25, &ASound8::command26, &ASound8::command27,
+ &ASound8::command28, &ASound8::command29, &ASound8::command30, &ASound8::command31,
+ &ASound8::command32, &ASound8::command33, &ASound8::command34, &ASound8::command35,
+ &ASound8::command36, &ASound8::command37
+};
+
+ASound8::ASound8(Audio::Mixer *mixer) : ASound(mixer, "asound.008", 0x1490) {
+ // Load sound samples
+ _soundFile.seek(_dataOffset + 0x122);
+ for (int i = 0; i < 174; ++i)
+ _samples.push_back(AdlibSample(_soundFile));
+}
+
+int ASound8::command(int commandId, int param) {
+ if (commandId > 38)
+ return 0;
+
+ _frameCounter = 0;
+ return (this->*_commandList[commandId])();
+}
+
+int ASound8::command9() {
+ byte *pData = loadData(0x15BE, 10);
+ pData[6] = (getRandomNumber() & 7) + 85;
+ playSoundData(pData);
+
+ return 0;
+}
+
+int ASound8::command10() {
+ byte *pData = loadData(0x2B3E, 10);
+ pData[6] = (getRandomNumber() & 7) + 85;
+ playSoundData(pData);
+
+ return 0;
+}
+
+int ASound8::command11() {
+ playSound(0x17CA, 12);
+
+ return 0;
+}
+
+int ASound8::command12() {
+ playSound(0x17D6, 12);
+
+ return 0;
+}
+
+int ASound8::command13() {
+ playSound(0x1694, 10);
+
+ return 0;
+}
+
+int ASound8::command14() {
+ playSound(0x169E, 24);
+
+ return 0;
+}
+
+int ASound8::command15() {
+ byte *pData = loadData(0x169E, 24);
+ if (_channels[8]._ptr1 == pData) {
+ _channels[8]._soundData = loadData(0x16B6, 12);
+ _channels[8]._field17 = 1;
+ _channels[8]._field19 = 1;
+ }
+
+ return 0;
+}
+
+int ASound8::command16() {
+ playSound(0x1686, 14);
+
+ return 0;
+}
+
+int ASound8::command17() {
+ playSound(0x17EC, 12);
+
+ return 0;
+}
+
+int ASound8::command18() {
+ playSound(0x17F8, 12);
+
+ return 0;
+}
+
+int ASound8::command19() {
+ playSound(0x16D8, 8);
+
+ return 0;
+}
+
+int ASound8::command20() {
+ playSound(0x16E0, 8);
+
+ return 0;
+}
+
+int ASound8::command21() {
+ playSound(0x17E2, 10);
+
+ return 0;
+}
+
+int ASound8::command22() {
+ playSound(0x178C, 14);
+ playSound(0x179A, 14);
+ playSound(0x17A8, 14);
+
+ return 0;
+}
+
+int ASound8::command23() {
+ playSound(0x2B08, 34);
+ playSound(0x2B2A, 20);
+
+ return 0;
+}
+
+int ASound8::command24() {
+ playSound(0x17B6, 8);
+
+ return 0;
+}
+
+int ASound8::command25() {
+ playSound(0x17BE, 12);
+
+ return 0;
+}
+
+int ASound8::command26() {
+ playSound(0x16C2, 22);
+
+ return 0;
+}
+
+int ASound8::command27() {
+ playSound(0x1588, 34);
+ playSound(0x15AA, 20);
+
+ return 0;
+}
+
+int ASound8::command28() {
+ byte *pData1 = loadData(0x114E, 376);
+ if (!isSoundActive(pData1)) {
+ command1();
+ _channels[0].load(pData1);
+ _channels[2].load(loadData(0x12F8, 130));
+
+ byte *pData = loadData(0x12C6, 50);
+ method1(pData);
+ _channels[1].load(pData);
+ }
+
+ return 0;
+}
+
+void ASound8::method1(byte *pData) {
+ int v;
+ while ((v = (getRandomNumber() & 0x3F)) > 36)
+ ;
+
+ adjustRange(pData, v + 20, -1);
+ adjustRange(pData + 1, 10 - ((v + 1) / 6), 1);
+}
+
+void ASound8::adjustRange(byte *pData, byte v, int incr) {
+ pData += 8;
+
+ for (int i = 0; i < 10; ++i, pData += 4, v += incr) {
+ *pData = v;
+ }
+}
+
+int ASound8::command29() {
+ byte *pData1 = loadData(0x137A, 60);
+ if (!isSoundActive(pData1)) {
+ command1();
+ _channels[0].load(pData1);
+ _channels[1].load(loadData(0x13B6, 318));
+ _channels[2].load(loadData(0x14F4, 118));
+ }
+
+ return 0;
+}
+
+int ASound8::command30() {
+ playSound(0x1644, 22);
+ playSound(0x165A, 22);
+ playSound(0x1670, 22);
+
+ return 0;
+}
+
+int ASound8::command31() {
+ playSound(0x156A, 14);
+
+ return 0;
+}
+
+int ASound8::command32() {
+ playSound(0x163A, 10);
+
+ return 0;
+}
+
+int ASound8::command33() {
+ playSound(0x162A, 16);
+
+ return 0;
+}
+
+int ASound8::command34() {
+ playSound(0x161A, 16);
+
+ return 0;
+}
+
+int ASound8::command35() {
+ playSound(0x1604, 22);
+
+ return 0;
+}
+
+int ASound8::command36() {
+ playSound(0x1578, 16);
+
+ return 0;
+}
+
+int ASound8::command37() {
+ playSound(0x15C8, 20);
+ playSound(0x15DC, 30);
+ playSound(0X15FA, 10);
+
+ return 0;
+}
+
+} // End of namespace Nebular
+
+} // End of namespace MADS
diff --git a/engines/mads/nebular/sound_nebular.h b/engines/mads/nebular/sound_nebular.h
new file mode 100644
index 0000000000..b5dee5b3ed
--- /dev/null
+++ b/engines/mads/nebular/sound_nebular.h
@@ -0,0 +1,720 @@
+/* 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.
+ *
+ */
+
+#ifndef MADS_SOUND_NEBULAR_H
+#define MADS_SOUND_NEBULAR_H
+
+#include "common/scummsys.h"
+#include "common/file.h"
+#include "common/mutex.h"
+#include "common/queue.h"
+#include "audio/audiostream.h"
+#include "audio/fmopl.h"
+#include "audio/mixer.h"
+
+namespace MADS {
+
+class SoundManager;
+
+namespace Nebular {
+
+/**
+ * Represents the data for a channel on the Adlib
+ */
+class AdlibChannel {
+public:
+ int _activeCount;
+ int _field1;
+ int _field2;
+ int _field3;
+ int _field4;
+ int _sampleIndex;
+ int _volume;
+ int _field7;
+ int _field8;
+ int _field9;
+ int _fieldA;
+ uint8 _fieldB;
+ int _fieldC;
+ int _fieldD;
+ int _fieldE;
+ byte *_ptr1;
+ byte *_pSrc;
+ byte *_ptr3;
+ byte *_ptr4;
+ int _field17;
+ int _field19;
+ byte *_soundData;
+ int _field1D;
+ int _field1E;
+ int _field1F;
+
+ // TODO: Only used by asound.003. Figure out usage
+ byte _field20;
+public:
+ static bool _channelsEnabled;
+public:
+ AdlibChannel();
+
+ void reset();
+ void enable(int flag);
+ void setPtr2(byte *pData);
+ void load(byte *pData);
+ void check(byte *nullPtr);
+};
+
+class AdlibChannelData {
+public:
+ int _field0;
+ int _freqMask;
+ int _freqBase;
+ int _field6;
+};
+
+class AdlibSample {
+public:
+ int _attackRate;
+ int _decayRate;
+ int _sustainLevel;
+ int _releaseRate;
+ bool _egTyp;
+ bool _ksr;
+ int _totalLevel;
+ int _scalingLevel;
+ int _waveformSelect;
+ int _freqMultiple;
+ int _feedback;
+ bool _ampMod;
+ int _vib;
+ int _alg;
+ int _fieldE;
+ int _freqMask;
+ int _freqBase;
+ int _field14;
+
+ AdlibSample() {}
+ AdlibSample(Common::SeekableReadStream &s);
+};
+
+struct RegisterValue {
+ uint8 _regNum;
+ uint8 _value;
+
+ RegisterValue(int regNum, int value) {
+ _regNum = regNum; _value = value;
+ }
+};
+
+#define ADLIB_CHANNEL_COUNT 9
+#define ADLIB_CHANNEL_MIDWAY 5
+#define CALLBACKS_PER_SECOND 60
+
+/**
+ * Base class for the sound player resource files
+ */
+class ASound: public Audio::AudioStream {
+private:
+ struct CachedDataEntry {
+ int _offset;
+ byte *_data;
+ };
+ Common::List<CachedDataEntry> _dataCache;
+ uint16 _randomSeed;
+
+ /**
+ * Does the initial Adlib initialisation
+ */
+ void adlibInit();
+
+ /**
+ * Does on-going processing for the Adlib sounds being played
+ */
+ void update();
+
+ /**
+ * Polls each of the channels for updates
+ */
+ void pollChannels();
+
+ /**
+ * Checks the status of the channels
+ */
+ void checkChannels();
+
+ /**
+ * Polls the currently active channel
+ */
+ void pollActiveChannel();
+
+ /**
+ * Updates the octave of the currently active channel
+ */
+ void updateOctave();
+
+ void updateChannelState();
+ void updateActiveChannel();
+
+ /**
+ * Loads up the specified sample
+ */
+ void loadSample(int sampleIndex);
+
+ /**
+ * Writes out the data of the selected sample to the Adlib
+ */
+ void processSample();
+
+ void updateFNumber();
+protected:
+ int _commandParam;
+
+ /**
+ * Queue a byte for an Adlib register
+ */
+ void write(int reg, int val);
+
+ /**
+ * Queue a byte for an Adlib register, and store it in the _ports array
+ */
+ int write2(int state, int reg, int val);
+
+ /**
+ * Flush any pending Adlib register values to the OPL driver
+ */
+ void flush();
+
+ /**
+ * Turn a channel on
+ */
+ void channelOn(int reg, int volume);
+
+ /**
+ * Turn a channel off
+ */
+ void channelOff(int reg);
+
+ /**
+ * Checks for whether a poll result needs to be set
+ */
+ void resultCheck();
+
+ /**
+ * Loads a data block from the sound file, caching the result for any future
+ * calls for the same data
+ */
+ byte *loadData(int offset, int size);
+
+ /**
+ * Play the specified sound
+ * @param offset Offset of sound data within sound player data segment
+ * @param size Size of sound data block
+ */
+ void playSound(int offset, int size);
+
+ /**
+ * Play the specified raw sound data
+ * @param pData Pointer to data block containing sound data
+ * @param startingChannel Channel to start scan from
+ */
+ void playSoundData(byte *pData, int startingChannel = ADLIB_CHANNEL_MIDWAY);
+
+ /**
+ * Checks to see whether the given block of data is already loaded into a channel.
+ */
+ bool isSoundActive(byte *pData);
+
+ /**
+ * Sets the frequency for a given channel.
+ */
+ void setFrequency(int channel, int freq);
+
+ /**
+ * Returns a 16-bit random number
+ */
+ int getRandomNumber();
+
+ virtual int command0();
+ int command1();
+ int command2();
+ int command3();
+ int command4();
+ int command5();
+ int command6();
+ int command7();
+ int command8();
+
+ int nullCommand() { return 0; }
+public:
+ Audio::Mixer *_mixer;
+ FM_OPL *_opl;
+ Audio::SoundHandle _soundHandle;
+ AdlibChannel _channels[ADLIB_CHANNEL_COUNT];
+ AdlibChannel *_activeChannelPtr;
+ AdlibChannelData _channelData[11];
+ Common::Array<AdlibSample> _samples;
+ AdlibSample *_samplePtr;
+ Common::File _soundFile;
+ Common::Queue<RegisterValue> _queue;
+ Common::Mutex _driverMutex;
+ int _dataOffset;
+ int _frameCounter;
+ bool _isDisabled;
+ int _v1;
+ int _v2;
+ int _activeChannelNumber;
+ int _freqMask1;
+ int _freqMask2;
+ int _freqBase1;
+ int _freqBase2;
+ int _channelNum1, _channelNum2;
+ int _v7;
+ int _v8;
+ int _v9;
+ int _v10;
+ int _pollResult;
+ int _resultFlag;
+ byte _nullData[2];
+ int _ports[256];
+ bool _stateFlag;
+ int _activeChannelReg;
+ int _v11;
+ bool _amDep, _vibDep, _splitPoint;
+ int _samplesPerCallback;
+ int _samplesPerCallbackRemainder;
+ int _samplesTillCallback;
+ int _samplesTillCallbackRemainder;
+public:
+ /**
+ * Constructor
+ * @param filename Specifies the adlib sound player file to use
+ * @param dataOffset Offset in the file of the data segment
+ */
+ ASound(Audio::Mixer *mixer, const Common::String &filename, int dataOffset);
+
+ /**
+ * Destructor
+ */
+ virtual ~ASound();
+
+ /**
+ * Execute a player command. Most commands represent sounds to play, but some
+ * low number commands also provide control operations.
+ * @param commandId Player ommand to execute.
+ * @param param Optional parameter used by a few commands
+ */
+ virtual int command(int commandId, int param) = 0;
+
+ /**
+ * Stop all currently playing sounds
+ */
+ int stop();
+
+ /**
+ * Main poll method to allow sounds to progress
+ */
+ int poll();
+
+ /**
+ * General noise/note output
+ */
+ void noise();
+
+ /**
+ * Return the current frame counter
+ */
+ int getFrameCounter() { return _frameCounter; }
+
+ // AudioStream interface
+ /**
+ * Main buffer read
+ */
+ virtual int readBuffer(int16 *buffer, const int numSamples);
+
+ /**
+ * Mono sound only
+ */
+ virtual bool isStereo() const { return false; }
+
+ /**
+ * Data is continuously pushed, so definitive end
+ */
+ virtual bool endOfData() const { return false; }
+
+ /**
+ * Return sample rate
+ */
+ virtual int getRate() const { return 11025; }
+};
+
+class ASound1: public ASound {
+private:
+ typedef int (ASound1::*CommandPtr)();
+ static const CommandPtr _commandList[42];
+ bool _cmd23Toggle;
+
+ int command9();
+ int command10();
+ int command11();
+ int command12();
+ int command13();
+ int command14();
+ int command15();
+ int command16();
+ int command17();
+ int command18();
+ int command19();
+ int command20();
+ int command21();
+ int command22();
+ int command23();
+ int command24();
+ int command25();
+ int command26();
+ int command27();
+ int command28();
+ int command29();
+ int command30();
+ int command31();
+ int command32();
+ int command33();
+ int command34();
+ int command35();
+ int command36();
+ int command37();
+ int command38();
+ int command39();
+ int command40();
+ int command41();
+
+ void command111213();
+ int command2627293032();
+public:
+ ASound1(Audio::Mixer *mixer);
+
+ virtual int command(int commandId, int param);
+};
+
+class ASound2 : public ASound {
+private:
+ byte _command12Param;
+private:
+ typedef int (ASound2::*CommandPtr)();
+ static const CommandPtr _commandList[44];
+
+ virtual int command0();
+ int command9();
+ int command10();
+ int command11();
+ int command12();
+ int command13();
+ int command14();
+ int command15();
+ int command16();
+ int command17();
+ int command18();
+ int command19();
+ int command20();
+ int command21();
+ int command22();
+ int command23();
+ int command24();
+ int command25();
+ int command26();
+ int command27();
+ int command28();
+ int command29();
+ int command30();
+ int command31();
+ int command32();
+ int command33();
+ int command34();
+ int command35();
+ int command36();
+ int command37();
+ int command38();
+ int command39();
+ int command40();
+ int command41();
+ int command42();
+ int command43();
+
+ void command9Randomize();
+ void command9Apply(byte *data, int val, int incr);
+public:
+ ASound2(Audio::Mixer *mixer);
+
+ virtual int command(int commandId, int param);
+};
+
+class ASound3 : public ASound {
+private:
+ bool _command39Flag;
+
+ typedef int (ASound3::*CommandPtr)();
+ static const CommandPtr _commandList[61];
+
+ int command9();
+ int command10();
+ int command11();
+ int command13();
+ int command14();
+ int command15();
+ int command16();
+ int command17();
+ int command18();
+ int command19();
+ int command20();
+ int command21();
+ int command22();
+ int command23();
+ int command24();
+ int command25();
+ int command26();
+ int command27();
+ int command28();
+ int command29();
+ int command30();
+ int command31();
+ int command32();
+ int command33();
+ int command34();
+ int command35();
+ int command36();
+ int command37();
+ int command38();
+ int command39();
+ int command40();
+ int command41();
+ int command42();
+ int command43();
+ int command44();
+ int command45();
+ int command46();
+ int command47();
+ int command49();
+ int command50();
+ int command51();
+ int command57();
+ int command59();
+ int command60();
+
+ void command9Randomize();
+ void command9Apply(byte *data, int val, int incr);
+public:
+ ASound3(Audio::Mixer *mixer);
+
+ virtual int command(int commandId, int param);
+};
+
+class ASound4 : public ASound {
+private:
+ typedef int (ASound4::*CommandPtr)();
+ static const CommandPtr _commandList[61];
+
+ int command10();
+ int command12();
+ int command19();
+ int command20();
+ int command21();
+ int command24();
+ int command27();
+ int command30();
+ int command32();
+ int command33();
+ int command34();
+ int command35();
+ int command36();
+ int command37();
+ int command38();
+ int command43();
+ int command52();
+ int command53();
+ int command54();
+ int command55();
+ int command56();
+ int command57();
+ int command58();
+ int command59();
+ int command60();
+
+ void method1();
+public:
+ ASound4(Audio::Mixer *mixer);
+
+ virtual int command(int commandId, int param);
+};
+
+class ASound5 : public ASound {
+private:
+ typedef int (ASound5::*CommandPtr)();
+ static const CommandPtr _commandList[42];
+
+ int command9();
+ int command10();
+ int command11();
+ int command12();
+ int command13();
+ int command14();
+ int command15();
+ int command16();
+ int command17();
+ int command18();
+ int command19();
+ int command20();
+ int command21();
+ int command22();
+ int command23();
+ int command24();
+ int command25();
+ int command26();
+ int command27();
+ int command28();
+ int command29();
+ int command30();
+ int command31();
+ int command32();
+ int command33();
+ int command34();
+ int command35();
+ int command36();
+ int command37();
+ int command38();
+ int command39();
+ int command40();
+ int command41();
+ int command42();
+ int command43();
+public:
+ ASound5(Audio::Mixer *mixer);
+
+ virtual int command(int commandId, int param);
+};
+
+class ASound6 : public ASound {
+private:
+ typedef int (ASound6::*CommandPtr)();
+ static const CommandPtr _commandList[30];
+
+ int command9();
+ int command10();
+ int command11();
+ int command12();
+ int command13();
+ int command14();
+ int command15();
+ int command16();
+ int command17();
+ int command18();
+ int command19();
+ int command20();
+ int command21();
+ int command22();
+ int command23();
+ int command24();
+ int command25();
+ int command29();
+public:
+ ASound6(Audio::Mixer *mixer);
+
+ virtual int command(int commandId, int param);
+};
+
+class ASound7 : public ASound {
+private:
+ typedef int (ASound7::*CommandPtr)();
+ static const CommandPtr _commandList[38];
+
+ int command9();
+ int command15();
+ int command16();
+ int command18();
+ int command19();
+ int command20();
+ int command21();
+ int command22();
+ int command23();
+ int command24();
+ int command25();
+ int command26();
+ int command27();
+ int command28();
+ int command30();
+ int command32();
+ int command33();
+ int command34();
+ int command35();
+ int command36();
+ int command37();
+public:
+ ASound7(Audio::Mixer *mixer);
+
+ virtual int command(int commandId, int param);
+};
+
+class ASound8 : public ASound {
+private:
+ typedef int (ASound8::*CommandPtr)();
+ static const CommandPtr _commandList[38];
+
+ int command9();
+ int command10();
+ int command11();
+ int command12();
+ int command13();
+ int command14();
+ int command15();
+ int command16();
+ int command17();
+ int command18();
+ int command19();
+ int command20();
+ int command21();
+ int command22();
+ int command23();
+ int command24();
+ int command25();
+ int command26();
+ int command27();
+ int command28();
+ int command29();
+ int command30();
+ int command31();
+ int command32();
+ int command33();
+ int command34();
+ int command35();
+ int command36();
+ int command37();
+
+ void method1(byte *pData);
+ void adjustRange(byte *pData, byte v, int incr);
+public:
+ ASound8(Audio::Mixer *mixer);
+
+ virtual int command(int commandId, int param);
+};
+
+} // End of namespace Nebular
+
+} // End of namespace MADS
+
+#endif /* MADS_SOUND_NEBULAR_H */
diff --git a/engines/mads/palette.cpp b/engines/mads/palette.cpp
new file mode 100644
index 0000000000..9f56223aa6
--- /dev/null
+++ b/engines/mads/palette.cpp
@@ -0,0 +1,829 @@
+/* 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 "engines/util.h"
+#include "graphics/palette.h"
+#include "mads/mads.h"
+#include "mads/msurface.h"
+#include "mads/staticres.h"
+
+namespace MADS {
+
+#define VGA_COLOR_TRANS(x) ((x) * 255 / 63)
+
+void RGB6::load(Common::SeekableReadStream *f) {
+ r = VGA_COLOR_TRANS(f->readByte());
+ g = VGA_COLOR_TRANS(f->readByte());
+ b = VGA_COLOR_TRANS(f->readByte());
+ _palIndex = f->readByte();
+ _u2 = f->readByte();
+ _flags = f->readByte();
+}
+
+/*------------------------------------------------------------------------*/
+
+PaletteUsage::PaletteUsage(MADSEngine *vm) {
+ _vm = vm;
+ _data = nullptr;
+}
+
+void PaletteUsage::load(Common::Array<UsageEntry> *data) {
+ _data = data;
+}
+
+void PaletteUsage::getKeyEntries(Common::Array<RGB6> &palette) {
+ _data->clear();
+
+ for (uint i = 0; i < palette.size(); ++i) {
+ byte *uPtr = &palette[i]._flags;
+ if ((*uPtr & 0x10) && _data->size() < 3) {
+ _data->push_back(UsageEntry(i));
+ }
+ }
+}
+
+static bool sortHelper(const PaletteUsage::UsageEntry &ue1, const PaletteUsage::UsageEntry &ue2) {
+ return ue1._sortValue < ue2._sortValue;
+}
+
+void PaletteUsage::prioritize(Common::Array<RGB6> &palette) {
+ for (uint i = 0; i < _data->size(); ++i) {
+ RGB6 &palEntry = palette[(*_data)[i]._palIndex];
+ (*_data)[i]._sortValue = _vm->_palette->rgbMerge(palEntry);
+ }
+
+ Common::sort(_data->begin(), _data->end(), sortHelper);
+}
+
+static bool rangeSorter(const PaletteUsage::UsageRange &ur1, const PaletteUsage::UsageRange &ur2) {
+ return ur1._v2 < ur2._v2;
+}
+
+int PaletteUsage::process(Common::Array<RGB6> &palette, uint flags) {
+ int palLow;
+ int palHigh = (flags & 0x800) ? 0x100 : 0xFC;
+ int palIdx;
+
+ PaletteUsage tempUsage(_vm);
+ Common::Array<UsageEntry> tempUsageData;
+ tempUsage.load(&tempUsageData);
+
+ if (flags & 0x4000) {
+ palLow = 0;
+ palIdx = palHigh;
+ } else {
+ palLow = _vm->_palette->_lowRange;
+ if ((PALETTE_COUNT - _vm->_palette->_highRange) > palHigh) {
+ palIdx = palHigh;
+ } else {
+ palIdx = PALETTE_COUNT - _vm->_palette->_highRange;
+ }
+ }
+
+ int rgbIndex = _vm->_palette->_rgbList.scan();
+ uint32 rgbMask = 1 << rgbIndex;
+ bool noUsageFlag = flags & 0x8000;
+ bool hasUsage = _data != nullptr;
+ bool flag1 = false;
+
+ if (hasUsage) {
+ if (noUsageFlag || _data->size() == 0)
+ hasUsage = false;
+
+ if (noUsageFlag && _data->size() > 0)
+ flag1 = true;
+ }
+
+ if (hasUsage) {
+ tempUsage.getKeyEntries(palette);
+ tempUsage.prioritize(palette);
+ }
+
+ int freeIndex;
+ int palCount = getGamePalFreeIndex(&freeIndex);
+ Common::Array<UsageRange> palRange;
+
+ for (uint palIndex = 0; palIndex < palette.size(); ++palIndex) {
+ byte pal2 = palIndex;
+ byte pal1 = 0;
+
+ if (!(palette[palIndex]._flags & 0x80)) {
+ pal1 = 0x40;
+ }
+ if (palette[palIndex]._flags & 0x60) {
+ pal1 |= 0x20;
+ }
+
+ palRange.push_back(UsageRange(pal1, pal2));
+ }
+
+ Common::sort(palRange.begin(), palRange.end(), rangeSorter);
+
+ int var3A = (flags & 0x4000) ? 0xffff : 0xfffe;
+
+ for (uint palIndex = 0; palIndex < palette.size(); ++palIndex) {
+ bool var48 = false;
+ int var4 = 0xffff;
+ int v1 = palRange[palIndex]._v2;
+
+ if (palette[v1]._flags & 8) {
+ var48 = true;
+ var4 = 0xFD;
+ }
+
+ if (hasUsage && palette[v1]._flags & 0x10) {
+ for (uint usageIndex = 0; usageIndex < tempUsage._data->size() && !var48; ++usageIndex) {
+ if ((*tempUsage._data)[usageIndex]._palIndex == palIndex) {
+ var48 = true;
+ int dataIndex = MIN(usageIndex, _data->size() - 1);
+ var4 = (*_data)[dataIndex]._palIndex;
+ }
+ }
+ }
+
+ if (flag1 && palette[palIndex]._flags & 0x10) {
+ for (uint usageIndex = 0; usageIndex < _data->size() && !var48; ++usageIndex) {
+ if ((*_data)[usageIndex]._palIndex == palIndex) {
+ var48 = true;
+ var4 = 0xF0 + usageIndex;
+
+ // Copy data into the high end of the main palette
+ RGB6 &pSrc = palette[palIndex];
+ byte *pDest = &_vm->_palette->_mainPalette[var4 * 3];
+ pDest[0] = pSrc.r;
+ pDest[1] = pSrc.g;
+ pDest[2] = pSrc.b;
+ }
+ }
+ }
+
+ if (!var48 && !noUsageFlag) {
+ int var2 = (palette[palIndex]._flags & 0x20) ||
+ (((flags & 0x2000) || (palette[palIndex]._flags & 0x4000)) &&
+ ((flags & 0x1000) || (palCount == 0))) ? 0x7fff : 1;
+ int var36 = (palette[palIndex]._flags & 0x80) ? 0 : 2;
+
+ for (int idx = palLow; idx < palIdx; ++idx) {
+ uint32 v = _vm->_palette->_palFlags[idx];
+ if ((v & var3A) && !(v & var36)) {
+ int var10;
+
+ if (var2 > 1) {
+ var10 = rgbFactor(&_vm->_palette->_mainPalette[idx * 3], palette[palIndex]);
+ }
+ else if (_vm->_palette->_mainPalette[idx * 3] != palette[palIndex].r ||
+ _vm->_palette->_mainPalette[idx * 3 + 1] != palette[palIndex].g ||
+ _vm->_palette->_mainPalette[idx * 3 + 2] != palette[palIndex].b) {
+ var10 = 1;
+ } else {
+ var10 = 0;
+ }
+
+ if (var2 > var10) {
+ var48 = true;
+ var4 = idx;
+ var2 = var10;
+ }
+ }
+ }
+ }
+
+ if (!var48 && (!(flags & 0x1000) || (!(palette[palIndex]._flags & 0x60) && !(flags & 0x2000)))) {
+ for (int idx = freeIndex; idx < palIdx && !var48; ++idx) {
+ if (!_vm->_palette->_palFlags[idx]) {
+ --palCount;
+ ++freeIndex;
+ var48 = true;
+ var4 = idx;
+
+ RGB6 &pSrc = palette[palIndex];
+ byte *pDest = &_vm->_palette->_mainPalette[idx * 3];
+ pDest[0] = pSrc.r;
+ pDest[1] = pSrc.g;
+ pDest[2] = pSrc.b;
+ }
+ }
+ }
+
+ assert(var48);
+ int var52 = (noUsageFlag && palette[palIndex]._u2) ? 2 : 0;
+
+ _vm->_palette->_palFlags[var4] |= var52 | rgbMask;
+ palette[palIndex]._palIndex = var4;
+ }
+
+ _vm->_palette->_rgbList[rgbIndex] = true;
+
+ return rgbIndex;
+}
+
+void PaletteUsage::transform(Common::Array<RGB6> &palette) {
+ if (!empty()) {
+ for (uint i = 0; i < _data->size(); ++i) {
+ int palIndex = (*_data)[i]._palIndex;
+ (*_data)[i]._palIndex = palette[palIndex]._palIndex;
+ }
+ }
+}
+
+void PaletteUsage::updateUsage(Common::Array<int> &usageList, int sceneUsageIndex) {
+ uint32 mask1 = 0xFFFFFFFF;
+ uint32 mask2 = 0;
+
+ for (uint idx = 0; idx < usageList.size(); ++idx) {
+ uint32 bitMask = 1 << usageList[idx];
+ mask1 ^= bitMask;
+ mask2 |= bitMask;
+ _vm->_palette->_rgbList[usageList[idx]] = false;
+ }
+
+ uint32 mask3 = 1 << sceneUsageIndex;
+
+ for (uint idx = 0; idx < PALETTE_COUNT; ++idx) {
+ uint32 mask = mask2 & _vm->_palette->_palFlags[idx];
+ if (mask) {
+ _vm->_palette->_palFlags[idx] = (_vm->_palette->_palFlags[idx] &
+ mask1) | mask3;
+ }
+ }
+
+ _vm->_palette->_rgbList[sceneUsageIndex] = true;
+}
+
+void PaletteUsage::resetPalFlags(int idx) {
+ if (idx >= 0 && idx < 32) {
+ uint32 rgbMask = ~(1 << idx);
+
+ uint32 *flagP = _vm->_palette->_palFlags;
+ for (int i = 0; i < 256; ++i, ++flagP) {
+ *flagP &= rgbMask;
+ if (*flagP == 2)
+ *flagP = 0;
+ }
+
+ _vm->_palette->_rgbList[idx] = 0;
+ }
+}
+
+int PaletteUsage::getGamePalFreeIndex(int *palIndex) {
+ *palIndex = -1;
+ int count = 0;
+
+ for (int i = 0; i < PALETTE_COUNT; ++i) {
+ if (!_vm->_palette->_palFlags[i]) {
+ ++count;
+ if (*palIndex < 0)
+ *palIndex = i;
+ }
+ }
+
+ return count;
+}
+
+int PaletteUsage::rgbFactor(byte *palEntry, RGB6 &pal6) {
+ int total = 0;
+ total += (palEntry[0] - pal6.r) * (palEntry[0] - pal6.r);
+ total += (palEntry[1] - pal6.g) * (palEntry[1] - pal6.g);
+ total += (palEntry[2] - pal6.b) * (palEntry[2] - pal6.b);
+
+ return total;
+}
+
+/*------------------------------------------------------------------------*/
+
+void RGBList::clear() {
+ for (int i = 0; i < 32; i++)
+ _data[i] = false;
+}
+
+void RGBList::reset() {
+ for (int i = 2; i < 32; i++)
+ _data[i] = false;
+}
+
+int RGBList::scan() {
+ for (int i = 0; i < 32; ++i) {
+ if (!_data[i])
+ return i;
+ }
+
+ error("RGBList was full");
+}
+
+void RGBList::copy(RGBList &src) {
+ Common::copy(&src._data[0], &src._data[32], &_data[0]);
+}
+
+/*------------------------------------------------------------------------*/
+
+Fader::Fader(MADSEngine *vm): _vm(vm) {
+ _colorFlags[0] = _colorFlags[1] = _colorFlags[2] = true;
+ _colorFlags[3] = false;
+ _colorValues[0] = _colorValues[1] = 0;
+ _colorValues[2] = _colorValues[3] = 0;
+
+ // TODO: It would be better if the fader routines could be refactored
+ // to work directly with 8-bit RGB values rather than 6-bit RGB values
+ Common::fill(&_rgb64Map[0], &_rgb64Map[PALETTE_COUNT], 0);
+ for (int i = 0; i < 64; ++i)
+ _rgb64Map[VGA_COLOR_TRANS(i)] = i;
+ byte v = 0;
+ for (int i = 0; i < PALETTE_COUNT; ++i) {
+ if (_rgb64Map[i])
+ v = _rgb64Map[i];
+ else
+ _rgb64Map[i] = v;
+ }
+}
+
+
+void Fader::setPalette(const byte *colors, uint start, uint num) {
+ g_system->getPaletteManager()->setPalette(colors, start, num);
+}
+
+void Fader::grabPalette(byte *colors, uint start, uint num) {
+ g_system->getPaletteManager()->grabPalette(colors, start, num);
+}
+
+void Fader::fadeOut(byte palette[PALETTE_SIZE], byte *paletteMap,
+ int baseColor, int numColors, int baseGrey, int numGreys,
+ int tickDelay, int steps) {
+ GreyEntry map[PALETTE_COUNT];
+ int intensity;
+ byte palIndex[PALETTE_COUNT][3];
+ int8 signs[PALETTE_COUNT][3];
+
+ mapToGreyRamp(palette, baseColor, numColors, baseGrey, numGreys, map);
+
+ for (int palCtr = baseColor; palCtr < (baseColor + numColors); ++palCtr) {
+ int index = palCtr - baseColor;
+ for (int colorCtr = 0; colorCtr < 3; ++colorCtr) {
+ if (_colorFlags[colorCtr]) {
+ int shiftSign = _colorValues[colorCtr];
+ if (shiftSign >= 0) {
+ intensity = map[index]._intensity << shiftSign;
+ } else {
+ intensity = map[index]._intensity >> ABS(shiftSign);
+ }
+ } else {
+ intensity = _colorValues[colorCtr];
+ }
+
+ int diff = intensity - _rgb64Map[palette[palCtr * 3 + colorCtr]];
+ palIndex[palCtr][colorCtr] = (byte)ABS(diff);
+ signs[palCtr][colorCtr] = (diff == 0) ? 0 : (diff < 0 ? -1 : 1);
+ }
+ }
+
+ for (int stepCtr = 0; stepCtr < steps; ++stepCtr) {
+ for (int palCtr = baseColor; palCtr < (baseColor + numColors); ++palCtr) {
+ int index = palCtr - baseColor;
+ for (int colorCtr = 0; colorCtr < 3; ++colorCtr) {
+ map[index]._accum[colorCtr] += palIndex[palCtr][colorCtr];
+ while (map[index]._accum[colorCtr] >= steps) {
+ map[index]._accum[colorCtr] -= steps;
+
+ byte rgb63 = _rgb64Map[palette[palCtr * 3 + colorCtr]] +
+ signs[palCtr][colorCtr];
+ palette[palCtr * 3 + colorCtr] = VGA_COLOR_TRANS(rgb63);
+ }
+ }
+ }
+
+ setFullPalette(palette);
+
+ _vm->_events->waitForNextFrame();
+ }
+
+ if (paletteMap != nullptr) {
+ for (int palCtr = 0; palCtr < numColors; palCtr++) {
+ paletteMap[palCtr] = map[palCtr]._mapColor;
+ }
+ }
+}
+
+void Fader::fadeIn(byte palette[PALETTE_SIZE], byte destPalette[PALETTE_SIZE],
+ int baseColor, int numColors, int baseGrey, int numGreys,
+ int tickDelay, int steps) {
+ GreyEntry map[PALETTE_COUNT];
+ byte tempPal[PALETTE_SIZE];;
+ int8 signs[PALETTE_COUNT][3];
+ byte palIndex[PALETTE_COUNT][3];
+ int intensity;
+
+ Common::copy(destPalette, destPalette + PALETTE_SIZE, tempPal);
+
+ mapToGreyRamp(tempPal, baseColor, numColors, baseGrey, numGreys, map);
+
+ for (int palCtr = baseColor; palCtr < (baseColor + numColors); ++palCtr) {
+ int index = palCtr - baseColor;
+ for (int colorCtr = 0; colorCtr < 3; ++colorCtr) {
+ if (_colorFlags[colorCtr]) {
+ int shiftSign = _colorValues[colorCtr];
+ if (shiftSign >= 0) {
+ intensity = map[index]._intensity << shiftSign;
+ }
+ else {
+ intensity = map[index]._intensity >> abs(shiftSign);
+ }
+ }
+ else {
+ intensity = _colorValues[colorCtr];
+ }
+
+ int diff = _rgb64Map[destPalette[palCtr * 3 + colorCtr]] - intensity;
+ palIndex[palCtr][colorCtr] = (byte)ABS(diff);
+ signs[palCtr][colorCtr] = (diff == 0) ? 0 : (diff < 0 ? -1 : 1);
+
+ map[index]._accum[colorCtr] = 0;
+ }
+ }
+
+ for (int stepCtr = 0; stepCtr < steps; ++stepCtr) {
+ for (int palCtr = baseColor; palCtr < (baseColor + numColors); ++palCtr) {
+ int index = palCtr - baseColor;
+ for (int colorCtr = 0; colorCtr < 3; ++colorCtr) {
+ map[index]._accum[colorCtr] += palIndex[palCtr][colorCtr];
+ while (map[index]._accum[colorCtr] >= steps) {
+ map[index]._accum[colorCtr] -= steps;
+
+ byte rgb63 = _rgb64Map[palette[palCtr * 3 + colorCtr]] +
+ signs[palCtr][colorCtr];
+ palette[palCtr * 3 + colorCtr] = VGA_COLOR_TRANS(rgb63);
+ }
+ }
+ }
+
+ setFullPalette(palette);
+
+ _vm->_events->waitForNextFrame();
+ }
+}
+
+void Fader::mapToGreyRamp(byte palette[PALETTE_SIZE], int baseColor, int numColors,
+ int baseGrey, int numGreys, GreyEntry *map) {
+ byte greyList[PALETTE_COUNT];
+ byte greyMapping[PALETTE_COUNT];
+ byte greyTable[64];
+ byte greyIntensity[64];
+ int intensity, shiftSign;
+
+ getGreyValues(palette, greyList, baseColor, numColors);
+ greyPopularity(greyList, greyTable, numColors);
+
+ for (int idx = 0; idx < numColors; ++idx) {
+ greyMapping[idx] = idx;
+ Common::fill(&map[idx]._accum[0], &map[idx]._accum[3], 0);
+ }
+
+ for (int idx = 0; idx < PALETTE_COUNT; ++idx) {
+ map[idx]._mapColor = (byte)idx;
+ }
+
+ // Sort the mapping lists
+ insertionSort(numColors, greyList, greyMapping);
+
+ // Initialise state variables
+ int greySum = 0;
+ int greyScan = 0;
+ int greyMark = 0;
+ int greyColors = 0;
+ int greyAccum = 0;
+ int firstColor = 0;
+
+ for (int greyCtr = 0; greyCtr < 64; ++greyCtr) {
+ for (int idx = 0; idx < greyTable[greyCtr]; ++idx) {
+ greySum += greyList[greyScan++];
+ ++greyColors;
+
+ greyAccum += numGreys;
+ while (greyAccum >= numColors) {
+ greyAccum -= numColors;
+ if (greyColors > 0) {
+ greyIntensity[greyMark] = (byte)(greySum / greyColors);
+ }
+
+ for (int rescan = firstColor; rescan < greyScan; ++rescan) {
+ map[greyMapping[rescan]]._intensity = greyIntensity[greyMark];
+ map[greyMapping[rescan]]._mapColor = (byte)(greyMark + baseGrey);
+ }
+
+ firstColor = greyScan;
+ greySum = 0;
+ greyColors = 0;
+ ++greyMark;
+ }
+ }
+ }
+
+ // Set the palette range of greyscale values to be used
+ byte *palP = &palette[baseGrey * 3];
+ for (int greys = 0; greys < numGreys; ++greys) {
+ for (int color = 0; color < 3; ++color) {
+ if (_colorFlags[color]) {
+ shiftSign = (byte)_colorValues[color];
+ if (shiftSign >= 0) {
+ intensity = greyIntensity[greys] << shiftSign;
+ } else {
+ intensity = greyIntensity[greys] >> abs(shiftSign);
+ }
+ } else {
+ intensity = _colorValues[color];
+ }
+ *palP++ = VGA_COLOR_TRANS(intensity);
+ }
+ }
+}
+
+void Fader::getGreyValues(const byte palette[PALETTE_SIZE],
+ byte greyList[PALETTE_COUNT], int baseColor, int numColors) {
+ const byte *palP = &palette[baseColor * 3];
+
+ for (int i = 0; i < numColors; ++i, palP += 3) {
+ int v = rgbMerge(palP[0], palP[1], palP[2]);
+ greyList[i] = v >> 7;
+ }
+}
+
+void Fader::greyPopularity(const byte greyList[PALETTE_COUNT],
+ byte greyTable[64], int numColors) {
+ Common::fill(&greyTable[0], &greyTable[64], 0);
+ for (int i = 0; i < numColors; ++i) {
+ int idx = greyList[i];
+ ++greyTable[idx];
+ }
+}
+
+void Fader::insertionSort(int size, byte *id, byte *value) {
+ bool restartFlag;
+ int endIndex = size - 1;
+
+ do {
+ restartFlag = false;
+ if (endIndex <= 0)
+ break;
+
+ for (int arrIndex = 0; arrIndex < endIndex && !restartFlag; ++arrIndex) {
+ byte *idP = id + arrIndex;
+ byte *valueP = value + arrIndex;
+
+ // Check whether the next index is out of order with the one following it
+ if (*idP > *(idP + 1)) {
+ // Found an incorrect ordering
+ restartFlag = true;
+
+ // Save id/value at current index
+ byte savedId = *idP;
+ byte savedValue = *valueP;
+
+ int moveCount = size - arrIndex - 1;
+ if (moveCount > 0) {
+ Common::copy(idP + 1, idP + moveCount + 2, idP);
+ Common::copy(valueP + 1, valueP + moveCount + 2, valueP);
+ }
+
+ // Scan for insert spot
+ int idx = 0;
+ if (endIndex > 0) {
+ bool breakFlag = false;
+ for (; idx <= endIndex && !breakFlag; ++idx) {
+ breakFlag = savedId < id[idx];
+ }
+ }
+
+ // Set up an insert point for entry
+ moveCount = size - idx - 1;
+ if (moveCount > 0) {
+ Common::copy_backward(id + idx, id + idx + moveCount, id + idx + moveCount + 1);
+ Common::copy_backward(value + idx, value + idx + moveCount, value + idx + moveCount + 1);
+ }
+
+ // Set shifted values at the new position
+ id[idx] = savedId;
+ value[idx] = savedValue;
+ }
+ }
+ } while (restartFlag);
+}
+
+int Fader::rgbMerge(RGB6 &palEntry) {
+ return rgbMerge(palEntry.r, palEntry.g, palEntry.b);
+}
+
+int Fader::rgbMerge(byte r, byte g, byte b) {
+ return _rgb64Map[r] * 38 + _rgb64Map[g] * 76 + _rgb64Map[b] * 14;
+}
+
+/*------------------------------------------------------------------------*/
+
+Palette::Palette(MADSEngine *vm) : Fader(vm), _paletteUsage(vm) {
+ _lockFl = false;
+ _lowRange = 0;
+ _highRange = 0;
+ Common::fill(&_mainPalette[0], &_mainPalette[PALETTE_SIZE], 0);
+ Common::fill(&_palFlags[0], &_palFlags[PALETTE_COUNT], 0);
+}
+
+void Palette::setEntry(byte palIndex, byte r, byte g, byte b) {
+ _mainPalette[palIndex * 3] = VGA_COLOR_TRANS(r);
+ _mainPalette[palIndex * 3 + 1] = VGA_COLOR_TRANS(g);
+ _mainPalette[palIndex * 3 + 2] = VGA_COLOR_TRANS(b);
+
+ setPalette((const byte *)&_mainPalette[palIndex * 3], palIndex, 1);
+}
+
+uint8 Palette::palIndexFromRgb(byte r, byte g, byte b, byte *paletteData) {
+ byte index = 0;
+ int32 minDist = 0x7fffffff;
+ byte palData[PALETTE_SIZE];
+
+ if (paletteData == NULL) {
+ g_system->getPaletteManager()->grabPalette(palData, 0, PALETTE_COUNT);
+ paletteData = &palData[0];
+ }
+
+ for (int palIndex = 0; palIndex < PALETTE_COUNT; ++palIndex) {
+ int Rdiff = r - paletteData[palIndex * 3];
+ int Gdiff = g - paletteData[palIndex * 3 + 1];
+ int Bdiff = b - paletteData[palIndex * 3 + 2];
+
+ if (Rdiff * Rdiff + Gdiff * Gdiff + Bdiff * Bdiff < minDist) {
+ minDist = Rdiff * Rdiff + Gdiff * Gdiff + Bdiff * Bdiff;
+ index = (uint8)palIndex;
+ }
+ }
+
+ return (uint8)index;
+}
+
+void Palette::setGradient(byte *palette, int start, int count, int rgbValue1, int rgbValue2) {
+ int rgbCurrent = rgbValue2;
+ int rgbDiff = -(rgbValue2 - rgbValue1);
+
+ if (count > 0) {
+ byte *pDest = palette + start * 3;
+ int endVal = count - 1;
+ int numLeft = count;
+
+ int rgbCtr = 0;
+ do {
+ pDest[0] = pDest[1] = pDest[2] = rgbCurrent;
+
+ if (numLeft > 1) {
+ rgbCtr += rgbDiff;
+ if (rgbCtr >= endVal) {
+ do {
+ ++rgbCurrent;
+ rgbCtr += 1 - numLeft;
+ } while (rgbCtr >= endVal);
+ }
+ }
+
+ pDest += 3;
+ } while (--numLeft > 0);
+ }
+}
+
+void Palette::setSystemPalette() {
+ byte palData[4 * 3];
+ palData[0 * 3] = palData[0 * 3 + 1] = palData[0 * 3 + 2] = 0;
+ palData[1 * 3] = palData[1 * 3 + 1] = palData[1 * 3 + 2] = 0x54;
+ palData[2 * 3] = palData[2 * 3 + 1] = palData[2 * 3 + 2] = 0xb4;
+ palData[3 * 3] = palData[3 * 3 + 1] = palData[3 * 3 + 2] = 0xff;
+
+ setPalette(palData, 0, 4);
+}
+
+void Palette::resetGamePalette(int lowRange, int highRange) {
+ Common::fill((byte *)&_palFlags[0], (byte *)&_palFlags[PALETTE_COUNT], 0);
+ initVGAPalette(_mainPalette);
+
+ // Reserve the start of the palette for things like on-screen text
+ if (lowRange) {
+ Common::fill(&_palFlags[0], &_palFlags[lowRange], 1);
+ }
+
+ // Reserve the high end of the palette for dialog display
+ if (highRange) {
+ Common::fill(&_palFlags[256 - highRange], &_palFlags[256], 1);
+ }
+
+ _rgbList.clear();
+ _rgbList[0] = _rgbList[1] = true;
+
+ _lockFl = false;
+ _lowRange = lowRange;
+ _highRange = highRange;
+}
+
+void Palette::initPalette() {
+ uint32 palMask = 1;
+
+ if (_vm->_game->_player._spritesLoaded && _vm->_game->_player._numSprites) {
+
+ for (int idx = 0; idx < _vm->_game->_player._numSprites; ++idx) {
+ SpriteAsset *asset = _vm->_game->_scene._sprites[
+ _vm->_game->_player._spritesStart + idx];
+
+ uint32 mask = 1;
+ if (asset->_usageIndex)
+ mask <<= asset->_usageIndex;
+
+ palMask = mask;
+ }
+ }
+
+ for (int idx = 0; idx < PALETTE_COUNT; ++idx)
+ _palFlags[idx] = palMask;
+
+ _lockFl = false;
+ _rgbList.reset();
+}
+
+void Palette::initVGAPalette(byte *palette) {
+ byte *destP = palette;
+ for (int palIndex = 0; palIndex < 16; ++palIndex) {
+ for (int byteCtr = 2; byteCtr >= 0; --byteCtr)
+ *destP++ = ((DEFAULT_VGA_LOW_PALETTE[palIndex] >> (8 * byteCtr)) & 0xff) >> 2;
+ }
+
+ destP = &palette[0xF0 * 3];
+ for (int palIndex = 0; palIndex < 16; ++palIndex) {
+ for (int byteCtr = 2; byteCtr >= 0; --byteCtr)
+ *destP++ = ((DEFAULT_VGA_HIGH_PALETTE[palIndex] >> (8 * byteCtr)) & 0xff) >> 2;
+ }
+}
+
+void Palette::setLowRange() {
+ _mainPalette[0] = _mainPalette[1] = _mainPalette[2] = VGA_COLOR_TRANS(0);
+ _mainPalette[3] = _mainPalette[4] = _mainPalette[5] = VGA_COLOR_TRANS(0x15);
+ _mainPalette[6] = _mainPalette[7] = _mainPalette[8] = VGA_COLOR_TRANS(0x2A);
+ _mainPalette[9] = _mainPalette[10] = _mainPalette[11] = VGA_COLOR_TRANS(0x3F);
+ _vm->_palette->setPalette(_mainPalette, 0, 4);
+}
+
+void Palette::setColorFlags(byte r, byte g, byte b) {
+ _colorFlags[0] = r;
+ _colorFlags[1] = g;
+ _colorFlags[2] = b;
+}
+
+void Palette::setColorValues(byte r, byte g, byte b) {
+ _colorValues[0] = r;
+ _colorValues[1] = g;
+ _colorValues[2] = b;
+}
+
+void Palette::lock() {
+ if (_rgbList[31] && !_lockFl)
+ error("Palette Lock - Unexpected values");
+
+ _lockFl = true;
+ _rgbList[31] = true;
+
+ for (int i = 0; i < 256; i++) {
+ if (_palFlags[i])
+ _palFlags[i] |= 0x80000000;
+ }
+}
+
+void Palette::unlock() {
+ if (!_lockFl)
+ return;
+
+ for (int i = 0; i < 256; i++)
+ _palFlags[i] &= 0x7FFFFFFF;
+
+ _rgbList[31] = false;
+ _lockFl = false;
+}
+
+void Palette::refreshSceneColors() {
+ int val = 18;
+ if (_vm->_game->_scene._cyclingActive)
+ val += _vm->_game->_scene._totalCycleColors;
+
+ setPalette(_mainPalette + (val * 3), val, 256 - val);
+}
+
+} // End of namespace MADS
diff --git a/engines/mads/palette.h b/engines/mads/palette.h
new file mode 100644
index 0000000000..0698e21a5f
--- /dev/null
+++ b/engines/mads/palette.h
@@ -0,0 +1,330 @@
+/* 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.
+ *
+ */
+
+#ifndef MADS_PALETTE_H
+#define MADS_PALETTE_H
+
+#include "common/scummsys.h"
+#include "common/stream.h"
+
+namespace MADS {
+
+class MADSEngine;
+
+#define PALETTE_USAGE_COUNT 4
+
+#define PALETTE_RESERVED_LOW_COUNT 18
+#define PALETTE_RESERVED_HIGH_COUNT 10
+
+#define PALETTE_COUNT 256
+#define PALETTE_SIZE (256 * 3)
+
+/**
+ * Palette mapping options
+ */
+enum {
+ PALFLAG_BACKGROUND = 0x8000, // Loading initial background
+ PALFLAG_RESERVED = 0x4000, // Enable mapping reserved colors
+ PALFLAG_ANY_TO_CLOSEST = 0x2000, // Any color can map to closest
+ PALFLAG_ALL_TO_CLOSEST = 0x1000, // Any colors that can map must map
+ PALFLAG_TOP_COLORS = 0x0800, // Allow mapping to high four colors
+ PALFLAG_DEFINE_RESERVED = 0x0400, // Define initial reserved color
+ PALFLAG_MASK = 0xfc00 // Mask for all the palette flags
+};
+
+struct PaletteCycle {
+ byte _colorCount;
+ byte _firstListColor;
+ byte _firstColorIndex;
+ byte _ticks;
+
+ PaletteCycle() { _colorCount = _firstListColor = _firstColorIndex = _ticks = 0; }
+};
+
+struct RGB6 {
+ byte r;
+ byte g;
+ byte b;
+ byte _palIndex;
+ byte _u2;
+ byte _flags;
+
+ /**
+ * Load an entry from a stream
+ */
+ void load(Common::SeekableReadStream *f);
+};
+
+class PaletteUsage {
+public:
+ struct UsageEntry {
+ uint16 _palIndex;
+ int _sortValue;
+
+ UsageEntry(int palIndex) { _palIndex = palIndex; _sortValue = -1; }
+ UsageEntry() { _palIndex = 0; _sortValue = 0; }
+ };
+ struct UsageRange {
+ byte _v1, _v2;
+
+ UsageRange(byte v1, byte v2) { _v1 = v1; _v2 = v2; }
+ };
+private:
+ MADSEngine *_vm;
+ Common::Array<UsageEntry> *_data;
+
+ int getGamePalFreeIndex(int *palIndex);
+
+ int rgbFactor(byte *palEntry, RGB6 &pal6);
+
+ Common::Array<UsageEntry> _nullUsage;
+public:
+ /**
+ * Constructor
+ */
+ PaletteUsage(MADSEngine *vm);
+
+ void load(Common::Array<UsageEntry> *data);
+
+ /**
+ * Returns whether the usage list is empty
+ */
+ bool empty() const { return _data == nullptr; }
+
+ uint16 &operator[](int index) { return (*_data)[index]._palIndex; }
+
+ /**
+ * Assigns the class to an empty usage array
+ */
+ void setEmpty() { _data = &_nullUsage; }
+
+ /**
+ * Gets key entries from the passed palette
+ * @param palette 6-bit per entry read in palette
+ */
+ void getKeyEntries(Common::Array<RGB6> &palette);
+
+ /**
+ * Prioritizes the palette index list based on the intensity of the
+ * RGB values of the palette entries that they refer to
+ */
+ void prioritize(Common::Array<RGB6> &palette);
+
+ int process(Common::Array<RGB6> &palette, uint flags);
+
+ void transform(Common::Array<RGB6> &palette);
+
+ void updateUsage(Common::Array<int> &usageList, int sceneUsageIndex);
+
+ void resetPalFlags(int idx);
+};
+
+class RGBList {
+private:
+ bool _data[32];
+public:
+ RGBList() { clear(); }
+
+ void clear();
+
+ void reset();
+
+ /**
+ * Copies the data from another instance
+ */
+ void copy(RGBList &src);
+
+ /**
+ * Scans for a free slot
+ */
+ int scan();
+
+ bool &operator[](int idx) { return _data[idx]; }
+};
+
+class Fader {
+public:
+ struct GreyEntry {
+ byte _intensity;
+ byte _mapColor;
+ uint16 _accum[3];
+ };
+private:
+ void mapToGreyRamp(byte palette[PALETTE_SIZE], int baseColor, int numColors,
+ int baseGrey, int numGreys, GreyEntry *map);
+
+ void getGreyValues(const byte palette[PALETTE_SIZE], byte greyList[PALETTE_COUNT],
+ int baseColor, int numColors);
+
+ /**
+ * Given a grey value list containing grey shades (0-63), creates a 64 byte
+ * grey table containing the number of grey values for each intensity
+ */
+ void greyPopularity(const byte greyList[PALETTE_COUNT], byte greyTable[64], int numColors);
+
+ /**
+ * Does an insertion sort of a given id/value array pair
+ */
+ void insertionSort(int size, byte *id, byte *value);
+protected:
+ MADSEngine *_vm;
+ byte _rgb64Map[PALETTE_COUNT];
+public:
+ bool _colorFlags[4];
+ int _colorValues[4];
+public:
+ /**
+ * Constructor
+ */
+ Fader(MADSEngine *vm);
+
+ /**
+ * Sets a new palette
+ */
+ void setPalette(const byte *colors, uint start, uint num);
+
+ /**
+ * Returns a subset of the currently loaded palette
+ */
+ void grabPalette(byte *colors, uint start, uint num);
+
+ /**
+ * Gets the entire palette at once
+ */
+ void getFullPalette(byte palette[PALETTE_SIZE]) {
+ grabPalette(&palette[0], 0, PALETTE_COUNT);
+ }
+
+ /**
+ * Sets the entire palette at once
+ */
+ void setFullPalette(byte palette[PALETTE_SIZE]) {
+ setPalette(&palette[0], 0, PALETTE_COUNT);
+ }
+
+ /**
+ * Calculates a merge/hash for a given palette entry
+ */
+ int rgbMerge(byte r, byte g, byte b);
+
+ /**
+ * Calculates a merge/hash for a given palette entry
+ */
+ int rgbMerge(RGB6 &palEntry);
+
+ /**
+ * Fades the given palette out to black or grey
+ */
+ void fadeOut(byte palette[PALETTE_SIZE], byte *paletteMap,
+ int baseColor, int numColors, int baseGrey, int numGreys,
+ int tickDelay, int steps);
+
+ /**
+ * Fade into the given palette
+ */
+ void fadeIn(byte palette[PALETTE_SIZE], byte destPalette[PALETTE_SIZE],
+ int baseColor, int numColors, int baseGrey, int numGreys,
+ int tickDelay, int steps);
+};
+
+class Palette: public Fader {
+private:
+ /**
+ * Initialises the first 16 palette indexes with the equivalent
+ * standard VGA palette
+ */
+ void initVGAPalette(byte *palette);
+public:
+ byte _mainPalette[PALETTE_SIZE];
+ byte _cyclingPalette[PALETTE_SIZE];
+ uint32 _palFlags[PALETTE_COUNT];
+ PaletteUsage _paletteUsage;
+ RGBList _rgbList;
+ bool _lockFl;
+ int _lowRange;
+ int _highRange;
+public:
+ /**
+ * Constructor
+ */
+ Palette(MADSEngine *vm);
+
+ /**
+ * Destructor
+ */
+ virtual ~Palette() {}
+
+ /**
+ * Set a palette entry
+ */
+ void setEntry(byte palIndex, byte r, byte g, byte b);
+
+ /**
+ * Returns the palette index in the palette that most closely matches the
+ * specified RGB pair
+ */
+ uint8 palIndexFromRgb(byte r, byte g, byte b, byte *paletteData = nullptr);
+
+ /**
+ * Sets a small set of system/core colors needed by the game
+ */
+ void setSystemPalette();
+
+ /**
+ * Update a range of an arbitrary palette
+ */
+ static void setGradient(byte *palette, int start, int count, int rgbValue1, int rgbValue2);
+
+ /**
+ * Resets the game palette
+ */
+ void resetGamePalette(int v1, int v2);
+
+ /**
+ * Initialises the main palette
+ */
+ void initPalette();
+
+ /**
+ * Set the first four palette entries with preset values
+ */
+ void setLowRange();
+
+ /**
+ * Set up the palette as the game ends
+ */
+ void close() {
+ warning("TODO: Palette::close");
+ }
+
+ void setColorFlags(byte r, byte g, byte b);
+ void setColorValues(byte r, byte g, byte b);
+
+ void lock();
+ void unlock();
+
+ void refreshSceneColors();
+};
+
+} // End of namespace MADS
+
+#endif /* MADS_PALETTE_H */
diff --git a/engines/mads/phantom/game_phantom.cpp b/engines/mads/phantom/game_phantom.cpp
new file mode 100644
index 0000000000..bcaec8e648
--- /dev/null
+++ b/engines/mads/phantom/game_phantom.cpp
@@ -0,0 +1,160 @@
+/* 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 "common/config-manager.h"
+#include "mads/mads.h"
+#include "mads/game.h"
+#include "mads/screen.h"
+#include "mads/msurface.h"
+#include "mads/phantom/game_phantom.h"
+//#include "mads/nebular/dialogs_nebular.h"
+//#include "mads/nebular/globals_nebular.h"
+#include "mads/phantom/phantom_scenes.h"
+
+namespace MADS {
+
+namespace Phantom {
+
+GamePhantom::GamePhantom(MADSEngine *vm): Game(vm) {
+ _surface = new MSurface(MADS_SCREEN_WIDTH, MADS_SCENE_HEIGHT);
+ _storyMode = STORYMODE_NAUGHTY;
+}
+
+ProtectionResult GamePhantom::checkCopyProtection() {
+ /*
+ // DEBUG: Flag copy protection failure
+ _globals[5] = -1;
+
+ if (!ConfMan.getBool("copy_protection"))
+ return true;
+
+ * DEBUG: Disabled for now
+ CopyProtectionDialog *dlg = new CopyProtectionDialog(_vm, false);
+ dlg->show();
+ delete dlg;
+ */
+
+ // DEBUG: Return that copy protection failed
+ return PROTECTION_SUCCEED;
+}
+
+void GamePhantom::initializeGlobals() {
+ //int count, count2;
+ //int bad;
+
+ _globals.reset();
+ //_globals[kTalkInanimateCount] = 8;
+
+ /* Section #1 variables */
+ // TODO
+
+ /* Section #2 variables */
+ // TODO
+
+ /* Section #3 variables */
+ // TODO
+
+ /* Section #4 variables */
+ // TODO
+
+ /* Section #5 variables */
+ // TODO
+
+ /* Section #9 variables */
+ // TODO
+
+ _player._facing = FACING_NORTH;
+ _player._turnToFacing = FACING_NORTH;
+
+ //Player::preloadSequences("RXM", 1);
+ //Player::preloadSequences("ROX", 1);
+}
+
+void GamePhantom::setSectionHandler() {
+ delete _sectionHandler;
+
+ switch (_sectionNumber) {
+ case 1:
+ _sectionHandler = new Section1Handler(_vm);
+ break;
+ case 2:
+ _sectionHandler = new Section2Handler(_vm);
+ break;
+ case 3:
+ _sectionHandler = new Section3Handler(_vm);
+ break;
+ case 4:
+ _sectionHandler = new Section4Handler(_vm);
+ break;
+ case 5:
+ _sectionHandler = new Section5Handler(_vm);
+ break;
+ default:
+ break;
+ }
+}
+
+void GamePhantom::checkShowDialog() {
+ // TODO: Copied from Nebular
+ if (_vm->_dialogs->_pendingDialog && _player._stepEnabled && !_globals[5]) {
+ _player.releasePlayerSprites();
+ _vm->_dialogs->showDialog();
+ _vm->_dialogs->_pendingDialog = DIALOG_NONE;
+ }
+}
+
+void GamePhantom::doObjectAction() {
+ // TODO: Copied from Nebular
+ //Scene &scene = _scene;
+ MADSAction &action = _scene._action;
+ //Dialogs &dialogs = *_vm->_dialogs;
+ //int id;
+
+ action._inProgress = false;
+}
+
+void GamePhantom::unhandledAction() {
+ // TODO
+}
+
+void GamePhantom::step() {
+ if (_player._visible && _player._stepEnabled && !_player._moving &&
+ (_player._facing == _player._turnToFacing)) {
+
+ // TODO
+ }
+
+}
+
+void GamePhantom::synchronize(Common::Serializer &s, bool phase1) {
+ Game::synchronize(s, phase1);
+
+ // TODO: Copied from Nebular
+ if (!phase1) {
+ _globals.synchronize(s);
+ }
+}
+
+} // End of namespace Phantom
+
+} // End of namespace MADS
diff --git a/engines/mads/phantom/game_phantom.h b/engines/mads/phantom/game_phantom.h
new file mode 100644
index 0000000000..c99e81ee70
--- /dev/null
+++ b/engines/mads/phantom/game_phantom.h
@@ -0,0 +1,124 @@
+/* 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.
+ *
+ */
+
+#ifndef MADS_GAME_PHANTOM_H
+#define MADS_GAME_PHANTOM_H
+
+#include "common/scummsys.h"
+#include "mads/game.h"
+#include "mads/globals.h"
+//#include "mads/nebular/globals_nebular.h"
+
+namespace MADS {
+
+namespace Phantom {
+
+// TODO: Adapt for Phantom's difficulty setting
+enum StoryMode { STORYMODE_NAUGHTY = 1, STORYMODE_NICE = 2 };
+
+enum InventoryObject {
+ OBJ_NONE = -1,
+ OBJ_KEY = 0,
+ OBJ_LANTERN = 1,
+ OBJ_RED_FRAME = 2,
+ OBJ_SANDBAG = 3,
+ OBJ_YELLOW_FRAME = 4,
+ OBJ_FIRE_AXE = 5,
+ OBJ_SMALL_NOTE = 6,
+ OBJ_ROPE = 7,
+ OBJ_SWORD = 8,
+ OBJ_ENVELOPE = 9,
+ OBJ_TICKET = 10,
+ OBJ_PIECE_OF_PAPER = 11,
+ OBJ_PARCHMENT = 12,
+ OBJ_LETTER = 13,
+ OBJ_NOTICE = 14,
+ OBJ_BOOK = 15,
+ OBJ_CRUMPLED_NOTE = 16,
+ OBJ_BLUE_FRAME = 17,
+ OBJ_LARGE_NOTE = 18,
+ OBJ_GREEN_FRAME = 19,
+ OBJ_MUSIC_SCORE = 20,
+ OBJ_WEDDING_RING = 21,
+ OBJ_CABLE_HOOK = 22,
+ OBJ_ROPE_WITH_HOOK = 23,
+ OBJ_OAR = 24
+};
+
+// HACK: A stub for now, remove from here once it's implemented properly
+class PhantomGlobals: public Globals {
+public:
+ PhantomGlobals() {
+ resize(210); // Rex has 210 globals
+ }
+ virtual ~PhantomGlobals() {}
+};
+
+class GamePhantom: public Game {
+ friend class Game;
+protected:
+ GamePhantom(MADSEngine *vm);
+
+ virtual ProtectionResult checkCopyProtection();
+
+ virtual void initializeGlobals();
+
+ virtual void setSectionHandler();
+
+ virtual void checkShowDialog();
+public:
+ PhantomGlobals _globals;
+ StoryMode _storyMode;
+
+ virtual Globals &globals() { return _globals; }
+
+ virtual void doObjectAction();
+
+ virtual void unhandledAction();
+
+ virtual void step();
+
+ virtual void synchronize(Common::Serializer &s, bool phase1);
+};
+
+
+class Section1Handler: public SectionHandler {
+public:
+ Section1Handler(MADSEngine *vm): SectionHandler(vm) {}
+
+ // TODO: Properly implement handler methods
+ virtual void preLoadSection() {}
+ virtual void sectionPtr2() {}
+ virtual void postLoadSection() {}
+};
+
+// TODO: Properly implement handler classes
+typedef Section1Handler Section2Handler;
+typedef Section1Handler Section3Handler;
+typedef Section1Handler Section4Handler;
+typedef Section1Handler Section5Handler;
+
+} // End of namespace Nebular
+
+} // End of namespace MADS
+
+#endif /* MADS_GAME_PHANTOM_H */
diff --git a/engines/mads/phantom/phantom_scenes.cpp b/engines/mads/phantom/phantom_scenes.cpp
new file mode 100644
index 0000000000..dbce014525
--- /dev/null
+++ b/engines/mads/phantom/phantom_scenes.cpp
@@ -0,0 +1,204 @@
+/* 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 "common/config-manager.h"
+#include "mads/mads.h"
+#include "mads/compression.h"
+#include "mads/resources.h"
+#include "mads/scene.h"
+#include "mads/phantom/game_phantom.h"
+#include "mads/phantom/phantom_scenes.h"
+
+namespace MADS {
+
+namespace Phantom {
+
+SceneLogic *SceneFactory::createScene(MADSEngine *vm) {
+ Scene &scene = vm->_game->_scene;
+
+ // TODO
+ //scene.addActiveVocab(NOUN_DROP);
+
+ switch (scene._nextSceneId) {
+ // Scene group #1 (theater, stage and dressing rooms)
+ case 101: // seats
+ return new DummyScene(vm); // TODO
+ case 102: // music stands
+ return new DummyScene(vm); // TODO
+ case 103: // below stage
+ return new DummyScene(vm); // TODO
+ case 104: // stage
+ return new DummyScene(vm); // TODO
+ case 105: // ground floor, storage room
+ return new DummyScene(vm); // TODO
+ case 106: // behind stage
+ return new DummyScene(vm); // TODO
+ case 107: // stage right wing
+ return new DummyScene(vm); // TODO
+ case 108: // stage left wing
+ return new DummyScene(vm); // TODO
+ case 109: // upper floor, staircase
+ return new DummyScene(vm); // TODO
+ case 110: // outside dressing rooms 1
+ return new DummyScene(vm); // TODO
+ case 111: // outside dressing rooms 2
+ return new DummyScene(vm); // TODO
+ case 112: // inside dressing room 1
+ return new DummyScene(vm); // TODO
+ case 113: // inside dressing room 2
+ return new DummyScene(vm); // TODO
+ case 114: // lower floor, storage room
+ return new DummyScene(vm); // TODO
+ case 150: // cutscene
+ return new DummyScene(vm); // TODO
+
+ // Scene group #2 (theater entrance, offices, balcony)
+ case 201: // entrance / ticket office
+ return new DummyScene(vm); // TODO
+ case 202: // outside offices / paintings room
+ return new DummyScene(vm); // TODO
+ case 203: // office
+ return new DummyScene(vm); // TODO
+ case 204: // library
+ return new DummyScene(vm); // TODO
+ case 205: // upper floor, outside balcony boxes
+ return new DummyScene(vm); // TODO
+ case 206: // balcony box #1
+ return new DummyScene(vm); // TODO
+ case 207: // balcony box #2
+ return new DummyScene(vm); // TODO
+ case 208: // stage and balcony view
+ return new DummyScene(vm); // TODO
+ case 250: // cutscene
+ return new DummyScene(vm); // TODO
+
+ // Scene group #3 (catwalks, chandelier, lake / catacombs entrance)
+ case 301: // catwalk #1 above stage
+ return new DummyScene(vm); // TODO
+ case 302: // catwalk #2 above stage
+ return new DummyScene(vm); // TODO
+ case 303: // above chandelier
+ return new DummyScene(vm); // TODO
+ case 304: // chandelier
+ return new DummyScene(vm); // TODO
+ case 305: // chandelier fight, phantom closeup
+ return new DummyScene(vm); // TODO
+ case 306: // chandelier #2
+ return new DummyScene(vm); // TODO
+ case 307: // catwalk #3 above stage
+ return new DummyScene(vm); // TODO
+ case 308: // hidden staircase behind balcony box
+ return new DummyScene(vm); // TODO
+ case 309: // lake and archway
+ return new DummyScene(vm); // TODO
+ case 310: // lake
+ return new DummyScene(vm); // TODO
+
+ // Scene group #4 (labyrinth)
+ case 401: // labyrinth room, 3 exits
+ return new DummyScene(vm); // TODO
+ case 403: // labyrinth room (big), 4 exits + 1 bricked door, left
+ return new DummyScene(vm); // TODO
+ case 404: // labyrinth room, 3 exits
+ return new DummyScene(vm); // TODO
+ case 406: // labyrinth room, 2 exits
+ return new DummyScene(vm); // TODO
+ case 407: // catacomb room / lake
+ return new DummyScene(vm); // TODO
+ case 408: // catacomb corridor
+ return new DummyScene(vm); // TODO
+ case 409: // catacomb room, door with switch panel
+ return new DummyScene(vm); // TODO
+ case 410: // skull switch panel
+ return new DummyScene(vm); // TODO
+ case 453: // Labyrinth room (big), 4 exits + 1 bricked door, right
+ return new DummyScene(vm); // TODO
+ case 456: // Labyrinth room, 2 exits
+ return new DummyScene(vm); // TODO
+
+ // Scene group #5 (Phantom's hideout)
+ case 501: // catacombs, outside phantom's hideout, lake and boat
+ return new DummyScene(vm); // TODO
+ case 502: // push panel trap
+ return new DummyScene(vm); // TODO
+ case 504: // Phantom's hideout, church organ
+ return new DummyScene(vm); // TODO
+ case 505: // Phantom's hideout, sarcophagus
+ return new DummyScene(vm); // TODO
+ case 506: // catacomb room with ramp
+ return new DummyScene(vm); // TODO
+
+ default:
+ error("Invalid scene %d called", scene._nextSceneId);
+ }
+}
+
+/*------------------------------------------------------------------------*/
+
+PhantomScene::PhantomScene(MADSEngine *vm) : SceneLogic(vm),
+ _globals(static_cast<GamePhantom *>(vm->_game)->_globals),
+ _game(*static_cast<GamePhantom *>(vm->_game)),
+ _action(vm->_game->_scene._action) {
+}
+
+Common::String PhantomScene::formAnimName(char sepChar, int suffixNum) {
+ return Resources::formatName(_scene->_currentSceneId, sepChar, suffixNum,
+ EXT_NONE, "");
+}
+
+/*------------------------------------------------------------------------*/
+
+void SceneInfoPhantom::loadCodes(MSurface &depthSurface, int variant) {
+ File f(Resources::formatName(RESPREFIX_RM, _sceneId, ".DAT"));
+ MadsPack codesPack(&f);
+ Common::SeekableReadStream *stream = codesPack.getItemStream(variant + 1);
+
+ loadCodes(depthSurface, stream);
+
+ delete stream;
+ f.close();
+}
+
+void SceneInfoPhantom::loadCodes(MSurface &depthSurface, Common::SeekableReadStream *stream) {
+ byte *destP = depthSurface.getData();
+ byte *endP = depthSurface.getBasePtr(0, depthSurface.h);
+
+ byte runLength = stream->readByte();
+ while (destP < endP && runLength > 0) {
+ byte runValue = stream->readByte();
+
+ // Write out the run length
+ Common::fill(destP, destP + runLength, runValue);
+ destP += runLength;
+
+ // Get the next run length
+ runLength = stream->readByte();
+ }
+
+ if (destP < endP)
+ Common::fill(destP, endP, 0);
+}
+
+} // End of namespace Phantom
+
+} // End of namespace MADS
diff --git a/engines/mads/phantom/phantom_scenes.h b/engines/mads/phantom/phantom_scenes.h
new file mode 100644
index 0000000000..e585ead542
--- /dev/null
+++ b/engines/mads/phantom/phantom_scenes.h
@@ -0,0 +1,521 @@
+/* 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.
+ *
+ */
+
+#ifndef MADS_PHANTOM_SCENES_H
+#define MADS_PHANTOM_SCENES_H
+
+#include "common/scummsys.h"
+#include "mads/game.h"
+#include "mads/scene.h"
+#include "mads/phantom/game_phantom.h"
+//#include "mads/phantom/globals_phantom.h"
+
+
+namespace MADS {
+
+namespace Phantom {
+
+enum Noun {
+ NOUN_GAME = 0x1,
+ NOUN_QSAVE = 0x2,
+ NOUN_LOOK = 0x3,
+ NOUN_TAKE = 0x4,
+ NOUN_PUSH = 0x5,
+ NOUN_OPEN = 0x6,
+ NOUN_PUT = 0x7,
+ NOUN_TALK_TO = 0x8,
+ NOUN_GIVE = 0x9,
+ NOUN_PULL = 0xA,
+ NOUN_CLOSE = 0xB,
+ NOUN_THROW = 0xC,
+ NOUN_WALK_TO = 0xD,
+ NOUN_ = 0xE,
+ NOUN_IN_ONE = 0xF,
+ NOUN_IN_TWO = 0x10,
+ NOUN_ACT_CURTAIN = 0x11,
+ NOUN_AISLE = 0x12,
+ NOUN_APRON = 0x13,
+ NOUN_ATTACK = 0x14,
+ NOUN_BACKSTAGE = 0x15,
+ NOUN_BEAR_PROP = 0x16,
+ NOUN_BLUE_FRAME = 0x17,
+ NOUN_BOOK = 0x18,
+ NOUN_BUST = 0x19,
+ NOUN_CABLE = 0x1A,
+ NOUN_CARPET = 0x1B,
+ NOUN_CARTON = 0x1C,
+ NOUN_CARTONS = 0x1D,
+ NOUN_CEILING = 0x1E,
+ NOUN_CHAIR = 0x1F,
+ NOUN_CIRCULAR_STAIRCASE = 0x20,
+ NOUN_CLIMB_DOWN = 0x21,
+ NOUN_CLIMB_INTO = 0x22,
+ NOUN_CLIMB_THROUGH = 0x23,
+ NOUN_COLUMN_PROP = 0x24,
+ NOUN_CONDUCTORS_STAND = 0x25,
+ NOUN_CORRIDOR = 0x26,
+ NOUN_COUCH = 0x27,
+ NOUN_COUNTERWEIGHT_SYSTEM = 0x28,
+ NOUN_CRATE = 0x29,
+ NOUN_CRATES = 0x2A,
+ NOUN_CRUMPLED_NOTE = 0x2B,
+ NOUN_CYCLORAMA = 0x2C,
+ NOUN_CYLINDER = 0x2D,
+ NOUN_DOOR = 0x2E,
+ NOUN_DRESSING_ROOM_DOOR = 0x2F,
+ NOUN_DRESSING_SCREEN = 0x30,
+ NOUN_DRESSING_TABLE = 0x31,
+ NOUN_ELEPHANT_PROP = 0x32,
+ NOUN_ENVELOPE = 0x33,
+ NOUN_EXIT = 0x34,
+ NOUN_EXIT_DOWN = 0x35,
+ NOUN_EXIT_SIGN = 0x36,
+ NOUN_EXIT_TO = 0x37,
+ NOUN_EXIT_TO_BACKSTAGE = 0x38,
+ NOUN_EXIT_TO_CELLAR = 0x39,
+ NOUN_EXIT_TO_CORRIDOR = 0x3A,
+ NOUN_EXIT_TO_DRESSING_RMS = 0x3B,
+ NOUN_EXIT_TO_LEFT_WING = 0x3C,
+ NOUN_EXIT_TO_PIT = 0x3D,
+ NOUN_EXIT_TO_RIGHT_WING = 0x3E,
+ NOUN_EXIT_TO_STAGE = 0x3F,
+ NOUN_EXIT_TO_STAIRWELL = 0x40,
+ NOUN_EXIT_TO_TRAP_ROOM = 0x41,
+ NOUN_EXIT_UP = 0x42,
+ NOUN_EXPOSED_BRICK = 0x43,
+ NOUN_FAN = 0x44,
+ NOUN_FIRE_AXE = 0x45,
+ NOUN_FL = 0x46,
+ NOUN_FLAT = 0x47,
+ NOUN_FLATS = 0x48,
+ NOUN_FLOOR = 0x49,
+ NOUN_FOLDING_CHAIRS = 0x4A,
+ NOUN_GARBAGE_CAN = 0x4B,
+ NOUN_GRAFFITI = 0x4C,
+ NOUN_GREEN_FRAME = 0x4D,
+ NOUN_HEMP = 0x4E,
+ NOUN_HOLE = 0x4F,
+ NOUN_HOUSE = 0x50,
+ NOUN_IN_ONE2 = 0x51,
+ NOUN_IN_TWO2 = 0x52,
+ NOUN_JUMP_INTO = 0x53,
+ NOUN_JUNK = 0x54,
+ NOUN_KEY = 0x55,
+ NOUN_LAMP = 0x56,
+ NOUN_LANTERN = 0x57,
+ NOUN_LARGE_NOTE = 0x58,
+ NOUN_LASSO = 0x59,
+ NOUN_LEG = 0x5A,
+ NOUN_LETTER = 0x5B,
+ NOUN_LIGHT_FIXTURE = 0x5C,
+ NOUN_LOCK = 0x5D,
+ NOUN_LOCKING_RAIL = 0x5E,
+ NOUN_LOCKRAIL = 0x5F,
+ NOUN_LOOK_AT = 0x60,
+ NOUN_LOOK_THROUGH = 0x61,
+ NOUN_MANNEQUINS = 0x62,
+ NOUN_MIRROR = 0x63,
+ NOUN_MUMMY_PROP = 0x64,
+ NOUN_MURAL = 0x65,
+ NOUN_MUSIC_SCORE = 0x66,
+ NOUN_MUSIC_STAND = 0x67,
+ NOUN_MUSIC_STANDS = 0x68,
+ NOUN_NOTHING = 0x69,
+ NOUN_NOTICE = 0x6A,
+ NOUN_ORCHESTRA_DOOR = 0x6B,
+ NOUN_ORCHESTRA_PIT = 0x6C,
+ NOUN_PAINTING = 0x6D,
+ NOUN_PARCHMENT = 0x6E,
+ NOUN_PIECE_OF_PAPER = 0x6F,
+ NOUN_PIPE = 0x70,
+ NOUN_PIT = 0x71,
+ NOUN_PLANT = 0x72,
+ NOUN_POSTER = 0x73,
+ NOUN_PROMPTERS_BOX = 0x74,
+ NOUN_PROP_TABLE = 0x75,
+ NOUN_PROPS = 0x76,
+ NOUN_PROSCENIUM_ARCH = 0x77,
+ NOUN_PURCHASE_LINES = 0x78,
+ NOUN_RAILING = 0x79,
+ NOUN_READ = 0x7A,
+ NOUN_RED_FRAME = 0x7B,
+ NOUN_REMOVE = 0x7C,
+ NOUN_ROPE = 0x7D,
+ NOUN_RUG = 0x7E,
+ NOUN_SANDBAG = 0x7F,
+ NOUN_SCAFFOLDING = 0x80,
+ NOUN_SEATS = 0x81,
+ NOUN_SIDE_WALL = 0x82,
+ NOUN_SMALL_NOTE = 0x83,
+ NOUN_STAGE = 0x84,
+ NOUN_STAGE_EXIT = 0x85,
+ NOUN_STAGE_LEFT = 0x86,
+ NOUN_STAGE_RIGHT = 0x87,
+ NOUN_STAGEMANAGERS_POST = 0x88,
+ NOUN_STAIR_UNIT = 0x89,
+ NOUN_STAIRCASE = 0x8A,
+ NOUN_STAIRWELL = 0x8B,
+ NOUN_STOOL = 0x8C,
+ NOUN_STRIKE = 0x8D,
+ NOUN_SWORD = 0x8E,
+ NOUN_TABLE = 0x8F,
+ NOUN_THE_HOUSE = 0x90,
+ NOUN_THUNDER_MACHINE = 0x91,
+ NOUN_TICKET = 0x92,
+ NOUN_TRAP_CEILING = 0x93,
+ NOUN_TRAP_DOOR = 0x94,
+ NOUN_TURN_OFF = 0x95,
+ NOUN_TURN_ON = 0x96,
+ NOUN_UNLOCK = 0x97,
+ NOUN_URN = 0x98,
+ NOUN_WALK_ACROSS = 0x99,
+ NOUN_WALK_DOWN = 0x9A,
+ NOUN_WALK_THROUGH = 0x9B,
+ NOUN_WALK_UP = 0x9C,
+ NOUN_WALL = 0x9D,
+ NOUN_WARDROBE = 0x9E,
+ NOUN_WASTE_BASKET = 0x9F,
+ NOUN_WATER_PIPE = 0xA0,
+ NOUN_WEAR = 0xA1,
+ NOUN_WEDDING_RING = 0xA2,
+ NOUN_YELLOW_FRAME = 0xA3,
+ NOUN_PROP = 0xA4,
+ NOUN_CLIMB_UP = 0xA5,
+ NOUN_WALK_ONTO = 0xA6,
+ NOUN_WALK = 0xA7,
+ NOUN_LEFT_DOOR = 0xA8,
+ NOUN_RIGHT_DOOR = 0xA9,
+ NOUN_DOOR_TO_PIT = 0xAA,
+ NOUN_HEADPHONES = 0xAB,
+ NOUN_BOXES = 0xAC,
+ NOUN_MUG = 0xAD,
+ NOUN_DINETTE_SET = 0xAE,
+ NOUN_BOX = 0xAF,
+ NOUN_CASES = 0xB0,
+ NOUN_TRASH_BUCKET = 0xB1,
+ NOUN_CORK_BOARD = 0xB2,
+ NOUN_HEADSET = 0xB3,
+ NOUN_GRAND_FOYER = 0xB4,
+ NOUN_BACK_WALL = 0xB5,
+ NOUN_BALLET_BAR = 0xB6,
+ NOUN_THROW_RUGS = 0xB7,
+ NOUN_COSTUME_RACK = 0xB8,
+ NOUN_COAT_RACK = 0xB9,
+ NOUN_PAINTINGS = 0xBA,
+ NOUN_UMBRELLA = 0xBB,
+ NOUN_SHELF = 0xBC,
+ NOUN_CONTAINER = 0xBD,
+ NOUN_TORN_POSTER = 0xBE,
+ NOUN_REVIEW = 0xBF,
+ NOUN_REVIEWS = 0xC0,
+ NOUN_STAGE_RIGHT_WING = 0xC1,
+ NOUN_STAGE_LEFT_WING = 0xC2,
+ NOUN_PEDESTAL = 0xC3,
+ NOUN_PLANT_PROP = 0xC4,
+ NOUN_STATUE = 0xC5,
+ NOUN_BATTEN = 0xC6,
+ NOUN_BIG_PROP = 0xC7,
+ NOUN_VENTILATION_DUCT = 0xC8,
+ NOUN_CHANDELIER = 0xC9,
+ NOUN_BARRIER = 0xCA,
+ NOUN_PLACARD = 0xCB,
+ NOUN_TICKET_WINDOW = 0xCC,
+ NOUN_ARCHWAY = 0xCD,
+ NOUN_COLUMN = 0xCE,
+ NOUN_RAIL = 0xCF,
+ NOUN_SEAT = 0xD0,
+ NOUN_LOGE_CORRIDOR = 0xD1,
+ NOUN_HOUSE_LIGHT = 0xD2,
+ NOUN_FLOV = 0xD3,
+ NOUN_LEFT_COLUMN = 0xD4,
+ NOUN_RIGHT_COLUMN = 0xD5,
+ NOUN_BOOKCASE = 0xD6,
+ NOUN_DOORWAY = 0xD7,
+ NOUN_COMFY_CHAIR = 0xD8,
+ NOUN_DESK = 0xD9,
+ NOUN_MANAGERS_CHAIR = 0xDA,
+ NOUN_DESK_LAMP = 0xDB,
+ NOUN_WINDOW = 0xDC,
+ NOUN_SHEERS = 0xDD,
+ NOUN_TAPESTRY = 0xDE,
+ NOUN_OVERDOOR_MEDALLION = 0xDF,
+ NOUN_LATTICEWORK = 0xE0,
+ NOUN_DECORATIVE_MOLDING = 0xE1,
+ NOUN_LEFT_DOORWAY = 0xE2,
+ NOUN_LEFT_ARCHWAY = 0xE3,
+ NOUN_RIGHT_DOORWAY = 0xE4,
+ NOUN_RIGHT_ARCHWAY = 0xE5,
+ NOUN_SOFA = 0xE6,
+ NOUN_END_TABLE = 0xE7,
+ NOUN_COFFEE_TABLE = 0xE8,
+ NOUN_DECORATIVE_VASE = 0xE9,
+ NOUN_MARBLE_COLUMN = 0xEA,
+ NOUN_BOX_FIVE = 0xEB,
+ NOUN_ENTER = 0xEC,
+ NOUN_BOX_SIX = 0xED,
+ NOUN_BOX_SEVEN = 0xEE,
+ NOUN_BOX_EIGHT = 0xEF,
+ NOUN_BOX_NINE = 0xF0,
+ NOUN_STEP = 0xF1,
+ NOUN_PANEL = 0xF2,
+ NOUN_WALK_BEHIND = 0xF3,
+ NOUN_MIDDLE_DOORWAY = 0xF4,
+ NOUN_LIGHT = 0xF5,
+ NOUN_CANDLE = 0xF6,
+ NOUN_CASE = 0xF7,
+ NOUN_HANDLE = 0xF8,
+ NOUN_AXE = 0xF9,
+ NOUN_DOOR_CHUNKS = 0xFA,
+ NOUN_FLO = 0xFB,
+ NOUN_BULLETIN_BOARD = 0xFC,
+ NOUN_JULIE = 0xFD,
+ NOUN_GLASS_CASE = 0xFE,
+ NOUN_KEYHOLE = 0xFF,
+ NOUN_MIDDLE_DOOR = 0x100,
+ NOUN_DRESSING_GOWN = 0x101,
+ NOUN_MONSIEUR_BRIE = 0x102,
+ NOUN_CATWALK = 0x103,
+ NOUN_GRID = 0x104,
+ NOUN_GIRDER = 0x105,
+ NOUN_GRIDWORK = 0x106,
+ NOUN_DUCTWORK = 0x107,
+ NOUN_OPENING = 0x108,
+ NOUN_DOME = 0x109,
+ NOUN_ALCOVE = 0x10A,
+ NOUN_CHRISTINE_DAAE = 0x10B,
+ NOUN_CHRISTINE = 0x10C,
+ NOUN_WOMAN = 0x10D,
+ NOUN_PROMPTERS_STAND = 0x10E,
+ NOUN_SUPPORT = 0x10F,
+ NOUN_OTHER_CATWALK = 0x110,
+ NOUN_SLOT = 0x111,
+ NOUN_BEAM_POSITION = 0x112,
+ NOUN_LIGHTING_INSTRUMENT = 0x113,
+ NOUN_TARP = 0x114,
+ NOUN_FACE = 0x115,
+ NOUN_CATWALK_OVER_HOUSE = 0x116,
+ NOUN_STAIRCASE_POST = 0x117,
+ NOUN_JACQUES = 0x118,
+ NOUN_GENTLEMAN = 0x119,
+ NOUN_BODY = 0x11A,
+ NOUN_HOLLOW_COLUMN = 0x11B,
+ NOUN_UPPER_LEVEL = 0x11C,
+ NOUN_MIDDLE_LEVEL = 0x11D,
+ NOUN_LOWER_LEVEL = 0x11E,
+ NOUN_LADDER = 0x11F,
+ NOUN_CLIMB = 0x120,
+ NOUN_CHANDELIER_TRAP = 0x121,
+ NOUN_PIECE_OF_WOOD = 0x122,
+ NOUN_CUT_HEMP = 0x123,
+ NOUN_STONE_WALL = 0x124,
+ NOUN_LAKE = 0x125,
+ NOUN_STONE_COLUMN = 0x126,
+ NOUN_EXIT_THROUGH = 0x127,
+ NOUN_STONE_FLOOR = 0x128,
+ NOUN_STONE_ARCHWAY = 0x129,
+ NOUN_CHARLES = 0x12A,
+ NOUN_SWITCH = 0x12B,
+ NOUN_PROMPTERS_SEAT = 0x12C,
+ NOUN_LEVER = 0x12D,
+ NOUN_MONSIEUR_RICHARD = 0x12E,
+ NOUN_JULIE2 = 0x12F,
+ NOUN_CABLE_HOOK = 0x130,
+ NOUN_ATTACH = 0x131,
+ NOUN_ROPE_WITH_HOOK = 0x132,
+ NOUN_GRAPPLE = 0x133,
+ NOUN_OAR = 0x134,
+ NOUN_ORGAN = 0x135,
+ NOUN_SIT_AT = 0x136,
+ NOUN_ORGAN_BENCH = 0x137,
+ NOUN_SIT_ON = 0x138,
+ NOUN_LARGE_CHAIR = 0x139,
+ NOUN_SIT_IN = 0x13A,
+ NOUN_SARCOPHAGUS = 0x13B,
+ NOUN_SKULL = 0x13C,
+ NOUN_SKULLS = 0x13D,
+ NOUN_TOTEM = 0x13E,
+ NOUN_POLE = 0x13F,
+ NOUN_CURTAIN = 0x140,
+ NOUN_TORCH = 0x141,
+ NOUN_RAMP = 0x142,
+ NOUN_MADAME_GIRY = 0x143,
+ NOUN_PANELS = 0x144,
+ NOUN_MORE_CATACOMBS = 0x145,
+ NOUN_BLOCKED_ARCHWAY = 0x146,
+ NOUN_GRATE = 0x147,
+ NOUN_CATACOMBS = 0x148,
+ NOUN_TICKET_SELLER = 0x149,
+ NOUN_USHER = 0x14A,
+ NOUN_UNLUCKY_ADVENTURER = 0x14B,
+ NOUN_SWITCH_PANEL = 0x14C,
+ NOUN_SKULL_SWITCH = 0x14D,
+ NOUN_TOGGLE = 0x14E,
+ NOUN_CATACOMB_ROOM = 0x14F,
+ NOUN_BOX_TEN = 0x150,
+ NOUN_FOYER = 0x151,
+ NOUN_WALK_DOWN_STAIRCASE = 0x152,
+ NOUN_WALK_DOWN_STAIRS_TO = 0x153,
+ NOUN_HAT_RACK = 0x154,
+ NOUN_VASE = 0x155,
+ NOUN_CLOTHES_DUMMY = 0x156,
+ NOUN_NOTICES = 0x157,
+ NOUN_ARCHWAY_TO_NORTH = 0x158,
+ NOUN_ARCHWAY_TO_WEST = 0x159,
+ NOUN_ARCHWAY_TO_EAST = 0x15A,
+ NOUN_GATE = 0x15B,
+ NOUN_NEST = 0x15C,
+ NOUN_POT = 0x15D,
+ NOUN_PUDDLE = 0x15E,
+ NOUN_WEB = 0x15F,
+ NOUN_PLANK = 0x160,
+ NOUN_BLOCK = 0x161,
+ NOUN_RATS_NEST = 0x162,
+ NOUN_BROKEN_POT = 0x163,
+ NOUN_STONE = 0x164,
+ NOUN_DRAIN = 0x165,
+ NOUN_FATE = 0x166,
+ NOUN_SKULL_SWITCH_1 = 0x167,
+ NOUN_SKULL_SWITCH_2 = 0x168,
+ NOUN_SKULL_SWITCH_3 = 0x169,
+ NOUN_SKULL_SWITCH_4 = 0x16A,
+ NOUN_SKULL_SWITCH_5 = 0x16B,
+ NOUN_SKULL_SWITCH_6 = 0x16C,
+ NOUN_SKULL_SWITCH_7 = 0x16D,
+ NOUN_SKULL_SWITCH_8 = 0x16E,
+ NOUN_SKULL_SWITCH_9 = 0x16F,
+ NOUN_SKULL_SWITCH_10 = 0x170,
+ NOUN_SKULL_SWITCH_11 = 0x171,
+ NOUN_SKULL_SWITCH_12 = 0x172,
+ NOUN_SKULL_SWITCH_13 = 0x173,
+ NOUN_SKULL_SWITCH_14 = 0x174,
+ NOUN_SKULL_SWITCH_15 = 0x175,
+ NOUN_SKULL_SWITCH_16 = 0x176,
+ NOUN_SKULL_SWITCH_17 = 0x177,
+ NOUN_SKULL_SWITCH_18 = 0x178,
+ NOUN_SKULL_SWITCH_19 = 0x179,
+ NOUN_SKULL_SWITCH_20 = 0x17A,
+ NOUN_SKULL_SWITCH_21 = 0x17B,
+ NOUN_SKULL_SWITCH_22 = 0x17C,
+ NOUN_SKULL_SWITCH_23 = 0x17D,
+ NOUN_SKULL_SWITCH_24 = 0x17E,
+ NOUN_SKULL_SWITCH_25 = 0x17F,
+ NOUN_SKULL_SWITCH_26 = 0x180,
+ NOUN_EDGAR_DEGAS = 0x181,
+ NOUN_CHANDELIER_CABLE = 0x182,
+ NOUN_COB_WEB = 0x183,
+ NOUN_SKULL_FACE = 0x184,
+ NOUN_BOAT = 0x185,
+ NOUN_HOOK = 0x186,
+ NOUN_AROUND = 0x187,
+ NOUN_CANE = 0x188,
+ NOUN_MASK = 0x189,
+ NOUN_COVER = 0x18A,
+ NOUN_PADLOCK = 0x18B,
+ NOUN_LID = 0x18C,
+ NOUN_COBWEB = 0x18D,
+ NOUN_PHANTOM = 0x18E,
+ NOUN_PAPER = 0x18F
+};
+
+class SceneFactory {
+public:
+ static SceneLogic *createScene(MADSEngine *vm);
+};
+
+/**
+ * Specialized base class for Dragonsphere game scenes
+ */
+class PhantomScene : public SceneLogic {
+protected:
+ PhantomGlobals &_globals;
+ GamePhantom &_game;
+ MADSAction &_action;
+
+ /**
+ * Forms an animation resource name
+ */
+ Common::String formAnimName(char sepChar, int suffixNum);
+
+ /**
+ * Plays appropriate sound for entering varous rooms
+ */
+ void lowRoomsEntrySound();
+public:
+ /**
+ * Constructor
+ */
+ PhantomScene(MADSEngine *vm);
+
+ void sub7178C();
+};
+
+class SceneInfoPhantom : public SceneInfo {
+ friend class SceneInfo;
+protected:
+ virtual void loadCodes(MSurface &depthSurface, int variant);
+
+ virtual void loadCodes(MSurface &depthSurface, Common::SeekableReadStream *stream);
+
+ /**
+ * Constructor
+ */
+ SceneInfoPhantom(MADSEngine *vm) : SceneInfo(vm) {}
+};
+
+// TODO: Temporary, remove once implemented properly
+class Scene1xx : public PhantomScene {
+protected:
+ /**
+ * Plays an appropriate sound when entering a scene
+ */
+ void sceneEntrySound() {}
+
+ /**
+ *Sets the AA file to use for the scene
+ */
+ void setAAName() {}
+
+ /**
+ * Updates the prefix used for getting player sprites for the scene
+ */
+ void setPlayerSpritesPrefix() {}
+public:
+ Scene1xx(MADSEngine *vm) : PhantomScene(vm) {}
+};
+
+// TODO: Temporary, remove once implemented properly
+class DummyScene: public PhantomScene {
+public:
+ DummyScene(MADSEngine *vm) : PhantomScene(vm) {
+ warning("Unimplemented scene");
+ }
+
+ virtual void setup() {}
+ virtual void enter() {}
+ virtual void actions() {}
+};
+
+} // End of namespace Phantom
+
+} // End of namespace MADS
+
+#endif /* MADS_PHANTOM_SCENES_H */
diff --git a/engines/mads/player.cpp b/engines/mads/player.cpp
new file mode 100644
index 0000000000..077771306e
--- /dev/null
+++ b/engines/mads/player.cpp
@@ -0,0 +1,785 @@
+/* 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 "mads/mads.h"
+#include "mads/player.h"
+
+namespace MADS {
+
+#define PLAYER_SEQ_INDEX -2
+
+const int Player::_directionListIndexes[32] = {
+ 0, 7, 4, 3, 6, 0, 2, 5, 0, 1, 9, 4, 1, 2, 7, 9, 3, 8, 9, 6, 7, 2, 3, 6, 1, 7, 9, 4, 7, 8, 0, 0
+};
+
+Player::Player(MADSEngine *vm): _vm(vm) {
+ _action = nullptr;
+ _facing = FACING_NORTH;
+ _turnToFacing = FACING_NORTH;
+ _targetFacing = FACING_NORTH;
+ _prepareWalkFacing = FACING_NONE;
+ _mirror = false;
+ _spritesLoaded = false;
+ _spritesStart = 0;
+ _spritesIdx = 0;
+ _numSprites = 0;
+ _stepEnabled = false;
+ _visible = false;
+ _priorVisible = false;
+ _needToWalk = false;
+ _readyToWalk = false;
+ _beenVisible = false;
+ _loadsFirst = false;
+ _loadedFirst = false;
+ _walkAnywhere = false;
+ _special = 0;
+ _ticksAmount = 0;
+ _priorTimer = 0;
+ _trigger = 0;
+ _scalingVelocity = false;
+ _spritesChanged = false;
+ _forceRefresh = false;
+ _highSprites = false;
+ _currentDepth = 0;
+ _currentScale = 0;
+ _frameNumber = 0;
+ _centerOfGravity = 0;
+ _frameCount = 0;
+ _velocity = 0;
+ _upcomingTrigger = 0;
+ _trigger = 0;
+ _frameListIndex = 0;
+ _stopWalkerIndex = 0;
+ _totalDistance = 0;
+
+ Common::fill(&_stopWalkerList[0], &_stopWalkerList[12], 0);
+ Common::fill(&_stopWalkerTrigger[0], &_stopWalkerTrigger[12], 0);
+ Common::fill(&_spriteSetsPresent[0], &_spriteSetsPresent[PLAYER_SPRITES_FILE_COUNT], false);
+}
+
+void Player::cancelWalk() {
+ Scene &scene = _vm->_game->_scene;
+ _action = &scene._action;
+ _targetPos = _playerPos;
+ _targetFacing = FACING_NONE;
+ _turnToFacing = _facing;
+ _moving = false;
+ _walkOffScreen = _walkOffScreenSceneId = 0;
+ scene._rails.resetRoute();
+ _walkAnywhere = false;
+
+ _needToWalk = false;
+ _readyToWalk = false;
+}
+
+bool Player::loadSprites(const Common::String &prefix) {
+ Common::String suffixList = "89632741";
+
+ Common::String newPrefix;
+ if (prefix.empty()) {
+ newPrefix = _spritesPrefix;
+ } else {
+ _spritesPrefix = prefix;
+ newPrefix = prefix;
+ }
+
+ _numSprites = 0;
+ if (!_spritesPrefix.empty()) {
+ for (int fileIndex = 0; fileIndex < PLAYER_SPRITES_FILE_COUNT; ++fileIndex) {
+ Common::String setName = Common::String::format("*%s_%c.SS",
+ newPrefix.c_str(), suffixList[fileIndex]);
+ if (fileIndex >= 5)
+ _highSprites = true;
+
+ _spriteSetsPresent[fileIndex] = true;
+
+ int setIndex = -1;
+ if (Common::File::exists(setName)) {
+ setIndex = _vm->_game->_scene._sprites.addSprites(setName, 4);
+ ++_numSprites;
+ } else if (fileIndex < 5) {
+ _highSprites = 0;
+ return true;
+ } else {
+ _spriteSetsPresent[fileIndex] = false;
+ }
+
+ if (fileIndex == 0)
+ _spritesStart = setIndex;
+ }
+
+ _spritesLoaded = true;
+ _spritesChanged = false;
+ _highSprites = false;
+ return false;
+ } else {
+ Common::fill(&_spriteSetsPresent[0], &_spriteSetsPresent[PLAYER_SPRITES_FILE_COUNT], false);
+ _highSprites = false;
+ return false;
+ }
+}
+
+void Player::setFinalFacing() {
+ if (_targetFacing != FACING_NONE)
+ _turnToFacing = _targetFacing;
+}
+
+void Player::changeFacing() {
+ int dirIndex = 0, dirIndex2 = 0;
+ int newDir = 0, newDir2 = 0;
+
+ if (_facing != _turnToFacing) {
+ // Find the index for the given direction in the player direction list
+ int tempDir = _facing;
+ do {
+ ++dirIndex;
+ newDir += tempDir;
+ tempDir = _directionListIndexes[tempDir + 10];
+ } while (tempDir != _turnToFacing);
+ }
+
+
+ if (_facing != _turnToFacing) {
+ // Find the index for the given direction in the player direction list
+ int tempDir = _facing;
+ do {
+ ++dirIndex2;
+ newDir2 += tempDir;
+ tempDir = _directionListIndexes[tempDir + 20];
+ } while (tempDir != _turnToFacing);
+ }
+
+ int diff = dirIndex - dirIndex2;
+ if (diff == 0)
+ diff = newDir - newDir2;
+
+ _facing = (diff >= 0) ? (Facing)_directionListIndexes[_facing + 20] :
+ (Facing)_directionListIndexes[_facing + 10];
+ selectSeries();
+
+ if ((_facing == _turnToFacing) && !_moving)
+ updateFrame();
+
+ _priorTimer += 1;
+}
+
+void Player::cancelCommand() {
+ cancelWalk();
+ _action->_inProgress = false;
+}
+
+void Player::selectSeries() {
+ Scene &scene = _vm->_game->_scene;
+
+ clearStopList();
+ _mirror = false;
+
+ _spritesIdx = _directionListIndexes[_facing];
+ if (!_spriteSetsPresent[_spritesIdx]) {
+ // Direction isn't present, so use alternate direction, with entries flipped
+ _spritesIdx -= 4;
+ _mirror = true;
+ }
+
+ // If the user isn't to be present (such as for a cutscene), exit immediately
+ // WORKAROUND: Original didn't do a secondary check for the sprite set being
+ // present, but it's needed to prevent invalid reads during cutscenes
+ if ((_spritesStart + _spritesIdx) < 0 || !_spriteSetsPresent[_spritesIdx])
+ return;
+
+ SpriteAsset &spriteSet = *scene._sprites[_spritesStart + _spritesIdx];
+ assert(spriteSet._charInfo);
+ _velocity = MAX(spriteSet._charInfo->_velocity, 100);
+ setBaseFrameRate();
+
+ _frameCount = spriteSet._charInfo->_totalFrames;
+ if (_frameCount == 0)
+ _frameCount = spriteSet.getCount();
+
+ _centerOfGravity = spriteSet._charInfo->_centerOfGravity;
+
+ if ((_frameNumber <= 0) || (_frameNumber > _frameCount))
+ _frameNumber = 1;
+
+ _forceRefresh = true;
+}
+
+void Player::updateFrame() {
+ // WORKAROUND: Prevent character info being referenced when not present
+ if ((_spritesStart + _spritesIdx) < 0 || !_spriteSetsPresent[_spritesStart + _spritesIdx])
+ return;
+
+ Scene &scene = _vm->_game->_scene;
+ SpriteAsset &spriteSet = *scene._sprites[_spritesStart + _spritesIdx];
+ assert(spriteSet._charInfo);
+
+ if (!spriteSet._charInfo->_numEntries) {
+ _frameNumber = 1;
+ } else {
+ _frameListIndex = _stopWalkerList[_stopWalkerIndex];
+
+ if (!_visible) {
+ _upcomingTrigger = 0;
+ } else {
+ _upcomingTrigger = _stopWalkerTrigger[_stopWalkerIndex];
+
+ if (_stopWalkerIndex > 0)
+ --_stopWalkerIndex;
+ }
+
+ // Set the player frame number
+ int listIndex = ABS(_frameListIndex);
+ _frameNumber = (_frameListIndex >= 0) ? spriteSet._charInfo->_startFrames[listIndex] :
+ spriteSet._charInfo->_stopFrames[listIndex];
+
+ // Set next waiting period in ticks
+ if (listIndex == 0) {
+ setBaseFrameRate();
+ } else {
+ _ticksAmount = spriteSet._charInfo->_ticksList[listIndex];
+ }
+ }
+
+ _forceRefresh = true;
+}
+
+void Player::update() {
+ Scene &scene = _vm->_game->_scene;
+
+ if (_forceRefresh || (_visible != _priorVisible)) {
+ int slotIndex = getSpriteSlot();
+ if (slotIndex >= 0)
+ scene._spriteSlots[slotIndex]._flags = IMG_ERASE;
+
+ int newDepth = 1;
+ int yp = MIN(_playerPos.y, (int16)(MADS_SCENE_HEIGHT - 1));
+
+ for (int idx = 1; idx < 15; ++idx) {
+ if (scene._sceneInfo->_depthList[newDepth] >= yp)
+ newDepth = idx + 1;
+ }
+ _currentDepth = newDepth;
+
+ // Get the scale
+ int newScale = getScale(_playerPos.y);
+ _currentScale = MIN(newScale, 100);
+
+ if (_visible) {
+ // Player sprite needs to be rendered
+ SpriteSlot slot;
+ slot._flags = IMG_UPDATE;
+ slot._seqIndex = PLAYER_SEQ_INDEX;
+ slot._spritesIndex = _spritesStart + _spritesIdx;
+ slot._frameNumber = _mirror ? -_frameNumber : _frameNumber;
+ slot._position.x = _playerPos.x;
+ slot._position.y = _playerPos.y + (_centerOfGravity * newScale) / 100;
+ slot._depth = newDepth;
+ slot._scale = newScale;
+
+ if (slotIndex >= 0) {
+ // Check if the existing player slot has the same details, and can be re-used
+ SpriteSlot &s2 = scene._spriteSlots[slotIndex];
+ bool equal = (s2._seqIndex == slot._seqIndex)
+ && (s2._spritesIndex == slot._spritesIndex)
+ && (s2._frameNumber == slot._frameNumber)
+ && (s2._position == slot._position)
+ && (s2._depth == slot._depth)
+ && (s2._scale == slot._scale);
+
+ if (equal)
+ // Undo the prior expiry of the player sprite
+ s2._flags = IMG_STATIC;
+ else
+ slotIndex = -1;
+ }
+
+ if (slotIndex < 0) {
+ // New slot needed, so allocate one and copy the slot data
+ slotIndex = scene._spriteSlots.add();
+ scene._spriteSlots[slotIndex] = slot;
+ }
+
+ // If changing a scene, check to change the scene when the player
+ // has moved off-screen
+ if (_walkOffScreen) {
+ SpriteAsset *asset = scene._sprites[slot._spritesIndex];
+ MSprite *frame = asset->getFrame(_frameNumber - 1);
+ int xScale = frame->w * newScale / 200;
+ int yScale = frame->h * newScale / 100;
+ int playerX = slot._position.x;
+ int playerY = slot._position.y;
+
+ if ((playerX + xScale) < 0 || (playerX + xScale) >= MADS_SCREEN_WIDTH ||
+ playerY < 0 || (playerY + yScale) >= MADS_SCENE_HEIGHT) {
+ scene._nextSceneId = _walkOffScreen;
+ _walkOffScreen = 0;
+ _walkAnywhere = false;
+ }
+ }
+
+ }
+ }
+
+ _beenVisible |= _visible;
+ _priorVisible = _visible;
+ _forceRefresh = false;
+}
+
+void Player::clearStopList() {
+ _stopWalkerList[0] = 0;
+ _stopWalkerTrigger[0] = 0;
+ _stopWalkerIndex = 0;
+ _upcomingTrigger = 0;
+ _trigger = 0;
+}
+
+void Player::startWalking(const Common::Point &pt, Facing facing) {
+ Scene &scene = _vm->_game->_scene;
+
+ clearStopList();
+ setBaseFrameRate();
+ _moving = true;
+ _targetFacing = facing;
+
+ bool v = scene._depthSurface.getDepthHighBit(pt);
+
+ scene._rails.setupRoute(v, _playerPos, pt);
+}
+
+void Player::walk(const Common::Point &pos, Facing facing) {
+ cancelWalk();
+ _needToWalk = true;
+ _readyToWalk = true;
+ _prepareWalkPos = pos;
+ _prepareWalkFacing = facing;
+}
+
+void Player::nextFrame() {
+ Scene &scene = _vm->_game->_scene;
+
+ uint32 newTime = _priorTimer + _ticksAmount;
+ if (scene._frameStartTime >= newTime) {
+ _priorTimer = scene._frameStartTime;
+ if (_moving) {
+ move();
+ } else {
+ idle();
+ }
+
+ setFrame();
+ update();
+ }
+}
+
+void Player::move() {
+ Scene &scene = _vm->_game->_scene;
+ Rails &rails = scene._rails;
+ bool newFacing = false;
+
+ if (_moving) {
+ while (!_walkOffScreen && _playerPos == _targetPos) {
+ bool isRouteEmpty = rails.empty();
+ if (!isRouteEmpty) {
+ const WalkNode &node = rails.popNode();
+
+ _targetPos = node._walkPos;
+ newFacing = true;
+ } else if (!_walkOffScreenSceneId) {
+ // End of walking path
+ rails.resetRoute();
+ _moving = false;
+ setFinalFacing();
+ newFacing = true;
+ } else {
+ _walkOffScreen = _walkOffScreenSceneId;
+ _walkAnywhere = true;
+ _walkOffScreenSceneId = 0;
+ _stepEnabled = false;
+ newFacing = false;
+ }
+
+ if (!_moving)
+ break;
+ }
+ }
+
+ if (newFacing && _moving)
+ startMovement();
+
+ if (_turnToFacing != _facing)
+ changeFacing();
+ else if (!_moving)
+ updateFrame();
+
+ int velocity = _velocity;
+ if (_scalingVelocity && (_totalDistance > 0)) {
+ int angleRange = 100 - _currentScale;
+ int angleScale = angleRange * (_posDiff.x - 1) / _totalDistance + _currentScale;
+ velocity = MAX(1L, (angleScale * _currentScale * velocity) / 10000L);
+ }
+
+ if (!_moving || (_facing != _turnToFacing))
+ return;
+
+ Common::Point newPos = _playerPos;
+ newFacing = false;
+ _special = 0;
+
+ if (_distAccum < velocity) {
+ do {
+ if (_pixelAccum < _posDiff.x)
+ _pixelAccum += _posDiff.y;
+ if (_pixelAccum >= _posDiff.x) {
+ if ((_posChange.y > 0) || _walkOffScreen)
+ newPos.y += _yDirection;
+ --_posChange.y;
+ _pixelAccum -= _posDiff.x;
+ }
+
+ if (_pixelAccum < _posDiff.x) {
+ if ((_posChange.x > 0) || _walkOffScreen)
+ newPos.x += _xDirection;
+ --_posChange.x;
+ }
+
+ if (!_walkAnywhere && !_walkOffScreen && (_walkOffScreenSceneId == 0)) {
+ newFacing = scene._depthSurface.getDepthHighBit(newPos);
+
+ if (_special == 0)
+ _special = scene.getDepthHighBits(newPos);
+ }
+
+ _distAccum += _deltaDistance;
+
+ } while ((_distAccum < velocity) && !newFacing && ((_posChange.x > 0) || (_posChange.y > 0) || (_walkOffScreen != 0)));
+ }
+
+ _distAccum -= velocity;
+
+ if (newFacing) {
+ cancelCommand();
+ } else {
+ if (!_walkOffScreen) {
+ // If the move is complete, make sure the position is exactly on the given destination
+ if (_posChange.x == 0)
+ newPos.x = _targetPos.x;
+ if (_posChange.y == 0)
+ newPos.y = _targetPos.y;
+ }
+
+ _playerPos = newPos;
+ }
+}
+
+void Player::idle() {
+ Scene &scene = _vm->_game->_scene;
+
+ if (_facing != _turnToFacing) {
+ // The direction has changed, so reset for new direction
+ changeFacing();
+ return;
+ }
+
+ if ((_spritesStart + _spritesIdx) < 0 || !_spriteSetsPresent[_spritesStart + _spritesIdx])
+ return;
+
+ SpriteAsset &spriteSet = *scene._sprites[_spritesStart + _spritesIdx];
+ assert(spriteSet._charInfo);
+ if (spriteSet._charInfo->_numEntries == 0)
+ // No entries, so exit immediately
+ return;
+
+ int frameIndex = ABS(_frameListIndex);
+ int direction = (_frameListIndex < 0) ? -1 : 1;
+
+ if (frameIndex >= spriteSet._charInfo->_numEntries) {
+ // Reset back to the start of the list
+ _frameListIndex = 0;
+ } else {
+ _frameNumber += direction;
+ _forceRefresh = true;
+
+ if (spriteSet._charInfo->_stopFrames[frameIndex] < _frameNumber) {
+ _trigger = _upcomingTrigger;
+ updateFrame();
+ }
+ if (spriteSet._charInfo->_startFrames[frameIndex] < _frameNumber) {
+ _trigger = _upcomingTrigger;
+ updateFrame();
+ }
+ }
+}
+
+void Player::setFrame() {
+ if (_moving) {
+ if (++_frameNumber > _frameCount)
+ _frameNumber = 1;
+ _forceRefresh = true;
+ } else {
+ if (!_forceRefresh)
+ idle();
+ }
+}
+
+int Player::getSpriteSlot() {
+ SpriteSlots &spriteSlots = _vm->_game->_scene._spriteSlots;
+
+ for (uint idx = 0; idx < spriteSlots.size(); ++idx) {
+ if (spriteSlots[idx]._seqIndex == PLAYER_SEQ_INDEX &&
+ spriteSlots[idx]._flags >= IMG_STATIC)
+ return idx;
+ }
+
+ return - 1;
+}
+
+int Player::getScale(int yp) {
+ Scene &scene = _vm->_game->_scene;
+
+ int scale = (scene._bandsRange == 0) ? scene._sceneInfo->_maxScale :
+ (yp - scene._sceneInfo->_yBandsStart) * scene._scaleRange / scene._bandsRange +
+ scene._sceneInfo->_minScale;
+
+ return MIN(scale, 100);
+}
+
+void Player::setBaseFrameRate() {
+ Scene &scene = _vm->_game->_scene;
+
+ SpriteAsset &spriteSet = *scene._sprites[_spritesStart + _spritesIdx];
+ assert(spriteSet._charInfo);
+
+ _ticksAmount = spriteSet._charInfo->_ticksAmount;
+ if (_ticksAmount == 0)
+ _ticksAmount = 6;
+}
+
+void Player::startMovement() {
+ int xDiff = _targetPos.x - _playerPos.x;
+ int yDiff = _targetPos.y - _playerPos.y;
+ int srcScale = getScale(_playerPos.y);
+ int destScale = getScale(_targetPos.y);
+
+ // Sets the X direction
+ if (xDiff > 0)
+ _xDirection = 1;
+ else if (xDiff < 0)
+ _xDirection = -1;
+ else
+ _xDirection = 0;
+
+ // Sets the Y direction
+ if (yDiff > 0)
+ _yDirection = 1;
+ else if (yDiff < 0)
+ _yDirection = -1;
+ else
+ _yDirection = 0;
+
+ xDiff = ABS(xDiff);
+ yDiff = ABS(yDiff);
+ int scaleDiff = ABS(srcScale - destScale);
+
+ int xAmt100 = xDiff * 100;
+ int yAmt100 = yDiff * 100;
+ int xAmt33 = xDiff * 33;
+
+ int scaleAmount = (_scalingVelocity ? scaleDiff * 3 : 0) + 100 * yDiff / 100;
+ int scaleAmount100 = scaleAmount * 100;
+
+ // Figure out direction that will need to be moved in
+ int majorDir;
+ if (xDiff == 0) {
+ majorDir = 1;
+ } else if (yDiff == 0) {
+ majorDir = 3;
+ } else {
+ if ((scaleAmount < xDiff) && ((xAmt33 / scaleAmount) >= 141))
+ majorDir = 3;
+ else if (yDiff <= xDiff)
+ majorDir = 2;
+ else if ((scaleAmount100 / xDiff) >= 141)
+ majorDir = 1;
+ else
+ majorDir = 2;
+ }
+
+ switch (majorDir) {
+ case 1:
+ _turnToFacing = (_yDirection <= 0) ? FACING_NORTH : FACING_SOUTH;
+ break;
+ case 2: {
+ _turnToFacing = (Facing)(((_yDirection <= 0) ? 9 : 3) - ((_xDirection <= 0) ? 2 : 0));
+ break;
+ }
+ case 3:
+ _turnToFacing = (_xDirection <= 0) ? FACING_WEST : FACING_EAST;
+ break;
+ default:
+ break;
+ }
+
+ _totalDistance = sqrt((double)(xAmt100 * xAmt100 + yAmt100 * yAmt100));
+ _posDiff.x = xDiff + 1;
+ _posDiff.y = yDiff + 1;
+ _posChange.x = xDiff;
+ _posChange.y = yDiff;
+
+ int majorChange = MAX(xDiff, yDiff);
+ _deltaDistance = (majorChange == 0) ? 0 : _totalDistance / majorChange;
+
+ if (_playerPos.x > _targetPos.x)
+ _pixelAccum = MAX(_posChange.x, _posChange.y);
+ else
+ _pixelAccum = 0;
+
+ _totalDistance /= 100;
+ _distAccum = -_deltaDistance;
+}
+
+void Player::newWalk() {
+ if (_needToWalk && _readyToWalk) {
+ startWalking(_prepareWalkPos, _prepareWalkFacing);
+ _needToWalk = false;
+ }
+}
+
+void Player::addWalker(int walker, int trigger) {
+ Scene &scene = _vm->_game->_scene;
+ SpriteAsset &spriteSet = *scene._sprites[_spritesStart + _spritesIdx];
+ assert(spriteSet._charInfo);
+
+ if (walker < spriteSet._charInfo->_numEntries && _stopWalkerIndex < 11) {
+ ++_stopWalkerIndex;
+ _stopWalkerList[_stopWalkerIndex] = walker;
+ _stopWalkerTrigger[_stopWalkerIndex] = trigger;
+ }
+}
+
+
+/**
+* Releases any sprites used by the player
+*/
+void Player::releasePlayerSprites() {
+ Scene &scene = _vm->_game->_scene;
+
+ if (_spritesLoaded && _numSprites > 0) {
+ int spriteEnd = _spritesStart + _numSprites - 1;
+ do {
+ scene._sprites.remove(spriteEnd);
+ } while (--spriteEnd >= _spritesStart);
+ }
+
+ _numSprites = 0;
+ _spritesLoaded = false;
+ _spritesChanged = true;
+
+ if (scene._sprites._assetCount > 0) {
+ warning("Player::releasePlayerSprites(): leftover sprites remain, clearing list");
+ scene._sprites.clear();
+ }
+}
+
+void Player::synchronize(Common::Serializer &s) {
+ s.syncAsByte(_moving);
+ s.syncAsSint16LE(_playerPos.x);
+ s.syncAsSint16LE(_playerPos.y);
+ s.syncAsSint16LE(_targetPos.x);
+ s.syncAsSint16LE(_targetPos.y);
+ s.syncAsSint16LE(_xDirection);
+ s.syncAsSint16LE(_yDirection);
+ s.syncAsSint16LE(_posDiff.x);
+ s.syncAsSint16LE(_posDiff.y);
+ s.syncAsSint16LE(_posChange.x);
+ s.syncAsSint16LE(_posChange.y);
+ s.syncAsUint16LE(_targetFacing);
+ s.syncAsSint16LE(_special);
+ s.syncAsByte(_forceRefresh);
+ s.syncAsSint16LE(_ticksAmount);
+ s.syncAsByte(_walkAnywhere);
+ s.syncAsUint16LE(_walkOffScreenSceneId);
+ s.syncAsByte(_walkOffScreen);
+ s.syncAsByte(_needToWalk);
+ s.syncAsByte(_readyToWalk);
+ s.syncAsUint16LE(_prepareWalkFacing);
+ s.syncAsSint16LE(_prepareWalkPos.x);
+ s.syncAsSint16LE(_prepareWalkPos.y);
+ s.syncAsByte(_stepEnabled);
+ s.syncAsByte(_visible);
+ s.syncAsByte(_priorVisible);
+
+ for (int i = 0; i < 8; ++i)
+ s.syncAsByte(_spriteSetsPresent[i]);
+
+ s.syncAsByte(_facing);
+ s.syncAsByte(_turnToFacing);
+ s.syncAsSint16LE(_spritesIdx);
+ s.syncAsSint16LE(_frameNumber);
+ s.syncAsSint16LE(_currentDepth);
+ s.syncAsSint16LE(_currentScale);
+ s.syncAsSint16LE(_frameListIndex);
+
+ for (int i = 0; i < 12; ++i) {
+ s.syncAsSint16LE(_stopWalkerList[i]);
+ s.syncAsSint16LE(_stopWalkerTrigger[i]);
+ }
+
+ s.syncAsSint16LE(_stopWalkerIndex);
+ s.syncAsSint16LE(_upcomingTrigger);
+ s.syncAsSint16LE(_trigger);
+ s.syncAsSint16LE(_scalingVelocity);
+ s.syncAsSint16LE(_pixelAccum);
+ s.syncAsSint16LE(_distAccum);
+ s.syncAsSint16LE(_deltaDistance);
+ s.syncAsSint16LE(_totalDistance);
+ s.syncAsSint16LE(_velocity);
+ s.syncAsUint16LE(_frameCount);
+ s.syncString(_spritesPrefix);
+ s.syncAsUint32LE(_priorTimer);
+ s.syncAsByte(_loadsFirst);
+ s.syncAsByte(_loadedFirst);
+ s.syncAsByte(_spritesLoaded);
+ s.syncAsByte(_spritesChanged);
+ s.syncAsByte(_beenVisible);
+ s.syncAsSint16LE(_centerOfGravity);
+ s.syncAsByte(_mirror);
+}
+
+void Player::removePlayerSprites() {
+ Scene &scene = _vm->_game->_scene;
+ int heroSpriteId = _spritesStart;
+ for (int i = 0; i < 8; i++) {
+ if (_spriteSetsPresent[i]) {
+ scene._sprites.remove(heroSpriteId++);
+ _spriteSetsPresent[i] = false;
+ }
+ }
+
+ if (scene._activeAnimation != nullptr)
+ scene._activeAnimation->resetSpriteSetsCount();
+
+ scene._spriteSlots.fullRefresh();
+ _visible = false;
+}
+
+} // End of namespace MADS
diff --git a/engines/mads/player.h b/engines/mads/player.h
new file mode 100644
index 0000000000..671ac9d16e
--- /dev/null
+++ b/engines/mads/player.h
@@ -0,0 +1,228 @@
+/* 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.
+ *
+ */
+
+#ifndef MADS_PLAYER_H
+#define MADS_PLAYER_H
+
+#include "common/scummsys.h"
+#include "common/str.h"
+#include "common/serializer.h"
+
+namespace MADS {
+
+class MADSEngine;
+class MADSAction;
+
+#define PLAYER_SPRITES_FILE_COUNT 8
+#define MAX_ROUTE_NODES 22
+
+/**
+ * Player facings
+ */
+enum Facing {
+ FACING_NORTH = 8, FACING_SOUTH = 2, FACING_EAST = 6, FACING_WEST = 4,
+ FACING_NORTHEAST = 9, FACING_SOUTHEAST = 3,
+ FACING_SOUTHWEST = 1, FACING_NORTHWEST = 7,
+ FACING_NONE = 5, FACING_DUMMY = 0
+};
+
+class Player {
+private:
+ static const int _directionListIndexes[32];
+private:
+ MADSEngine *_vm;
+ bool _highSprites;
+ bool _spriteSetsPresent[PLAYER_SPRITES_FILE_COUNT];
+ bool _mirror;
+ int _frameCount;
+ int _frameListIndex;
+ int _distAccum;
+ int _pixelAccum;
+ int _deltaDistance;
+ int _stopWalkerList[12];
+ int _stopWalkerTrigger[12];
+ int _totalDistance;
+
+ void clearStopList();
+
+ /**
+ * If the player is moving, handles figuring out the correct motion
+ */
+ void move();
+
+ /**
+ * Update the player's frame number
+ */
+ void setFrame();
+
+ /**
+ * Get the sprite slot index for the player
+ */
+ int getSpriteSlot();
+
+ /**
+ * Get the scale for the player at the given Y position
+ */
+ int getScale(int yp);
+
+ /**
+ * Sets the frame rate for the current sprite set
+ */
+ void setBaseFrameRate();
+
+ /**
+ * Starts a player moving to a given destination
+ */
+ void startMovement();
+
+ void changeFacing();
+public:
+ MADSAction *_action;
+
+ Facing _facing;
+ Facing _turnToFacing;
+ Facing _prepareWalkFacing;
+ int _xDirection, _yDirection;
+ Facing _targetFacing;
+ bool _spritesLoaded;
+ int _spritesStart;
+ int _spritesIdx;
+ int _numSprites;
+ bool _stepEnabled;
+ bool _spritesChanged;
+ bool _visible;
+ bool _priorVisible;
+ bool _beenVisible;
+ bool _walkAnywhere;
+ int _frameNumber;
+ bool _loadsFirst;
+ bool _loadedFirst;
+ Common::Point _playerPos;
+ Common::Point _targetPos;
+ Common::Point _posChange;
+ Common::Point _posDiff;
+ Common::Point _prepareWalkPos;
+ bool _moving;
+ int _walkOffScreen, _walkOffScreenSceneId;
+ int _special;
+ int _ticksAmount;
+ uint32 _priorTimer;
+ int _velocity;
+ int _upcomingTrigger;
+ int _trigger;
+ bool _scalingVelocity;
+ bool _forceRefresh;
+ bool _needToWalk;
+ bool _readyToWalk;
+ int _stopWalkerIndex;
+ int _centerOfGravity;
+ int _currentDepth;
+ int _currentScale;
+ Common::String _spritesPrefix;
+public:
+ Player(MADSEngine *vm);
+
+ /**
+ * Load sprites for the player
+ */
+ bool loadSprites(const Common::String &prefix);
+
+ /**
+ * Called when the player has reached the given destination, start him
+ * turning to the specified facing
+ */
+ void setFinalFacing();
+
+ /**
+ * Stops the player walking
+ */
+ void cancelWalk();
+
+ /**
+ * Cancels any oustanding player action
+ */
+ void cancelCommand();
+
+ /**
+ * Set up control parameters for the current active series (the
+ * direction which the player is facing in) */
+ void selectSeries();
+
+ /*
+ * Moves to the next frame for the currently active player sprite set
+ */
+ void updateFrame();
+
+ void update();
+
+ /**
+ * Handler method for when the player is not moving
+ */
+ void idle();
+
+ /**
+ * Starts the player walking towards a given point and direction facing
+ * @param pos Destination location
+ * @param facing Direction to face once the destination is reached
+ */
+ void startWalking(const Common::Point &pt, Facing facing);
+
+ /**
+ * Used by the game scripst to make the player walk to a given destination.
+ * The difference from startWalking is that this contains several extra
+ * layers of checking that startWalking bypasses.
+ */
+ void walk(const Common::Point &pos, Facing facing);
+
+ /**
+ * If a new walk sequence is pending, and has been okayed by the preparser,
+ * start the actual walking
+ */
+ void newWalk();
+
+ void nextFrame();
+
+ /**
+ * Add a walker to the current queue
+ */
+ void addWalker(int walker, int trigger);
+
+ /**
+ * Delete any sprites used by the player
+ */
+ void releasePlayerSprites();
+
+ /**
+ * Serialize the data of the player
+ */
+ void synchronize(Common::Serializer &s);
+
+ static void preloadSequences(const Common::String &prefix, int level) {
+ // No implementation in ScummVM
+ }
+
+ void removePlayerSprites();
+};
+
+} // End of namespace MADS
+
+#endif /* MADS_PLAYER_H */
diff --git a/engines/mads/rails.cpp b/engines/mads/rails.cpp
new file mode 100644
index 0000000000..6beee5a242
--- /dev/null
+++ b/engines/mads/rails.cpp
@@ -0,0 +1,284 @@
+/* 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 "mads/mads.h"
+#include "mads/rails.h"
+
+namespace MADS {
+
+WalkNode::WalkNode() {
+ _active = false;
+ Common::fill(&_distances[0], &_distances[MAX_ROUTE_NODES], 0);
+}
+
+void WalkNode::load(Common::SeekableReadStream *f) {
+ _walkPos.x = f->readSint16LE();
+ _walkPos.y = f->readSint16LE();
+ for (int i = 0; i < MAX_ROUTE_NODES; ++i)
+ _distances[i] = f->readUint16LE();
+}
+
+/*------------------------------------------------------------------------*/
+
+Rails::Rails() {
+ _depthSurface = nullptr;
+ _routeLength = 0;
+}
+
+void Rails::load(const WalkNodeList &nodes, DepthSurface *depthSurface, int depthStyle) {
+ // Store the depth surface and depth style to use
+ _depthSurface = depthSurface;
+ _depthStyle = depthStyle;
+
+ // Load the passed node list
+ _nodes.clear();
+
+ for (uint i = 0; i < nodes.size(); ++i)
+ _nodes.push_back(nodes[i]);
+
+ // Add two more empty nodes for the start and end points of any walk sequence
+ _nodes.push_back(WalkNode());
+ _nodes.push_back(WalkNode());
+}
+
+
+void Rails::setupRoute(bool bitFlag, const Common::Point &srcPos, const Common::Point &destPos) {
+ // Reset the nodes in as being inactive
+ for (uint i = 0; i < _nodes.size(); ++i)
+ _nodes[i]._active = false;
+
+ // Set the two extra walk nodes to the start and destination positions
+ setNodePosition(_nodes.size() - 2, srcPos);
+ setNodePosition(_nodes.size() - 1, destPos);
+
+ // Start constructing route node list
+ _routeLength = 0x3FFF;
+ _routeIndexes.clear();
+
+ // Recursively form a route from the destination walk node back to the player's position
+ setupRouteNode(&_tempRoute[0], _nodes.size() - 1, bitFlag ? 0xC000 : 0x8000, 0);
+
+ _next = 0;
+ if (_routeIndexes.size() > 0) {
+ Common::Point currPos = srcPos;
+ for (int routeCtr = size() - 1; (routeCtr >= 0) && !_next; --routeCtr) {
+ int idx = _routeIndexes[routeCtr];
+ const Common::Point &pt = _nodes[idx]._walkPos;
+
+ _next = scanPath(currPos, pt);
+ currPos = pt;
+ }
+ }
+}
+
+void Rails::setupRouteNode(int *routeIndexP, int nodeIndex, int flags, int routeLength) {
+ WalkNode &currentNode = _nodes[nodeIndex];
+ currentNode._active = true;
+
+ *routeIndexP++ = nodeIndex;
+
+ // Get the index of the ultimate source position (the player)
+ int subIndex = _nodes.size() - 2;
+
+ int distanceVal = _nodes[nodeIndex]._distances[subIndex];
+ if (distanceVal & flags) {
+ routeLength += distanceVal & 0x3FFF;
+ if (routeLength < _routeLength) {
+ // Found a new shorter route to destination, so set up the route with the found one
+ _routeIndexes.clear();
+ for (int i = 0; routeIndexP != &_tempRoute[i]; ++i)
+ _routeIndexes.push(_tempRoute[i]);
+ _routeLength = routeLength;
+ }
+ } else {
+ for (int idx = _nodes.size() - 2; idx > 0; --idx) {
+ int nodePos = idx - 1;
+ if (!_nodes[nodePos]._active && ((currentNode._distances[nodePos] & flags) != 0))
+ setupRouteNode(routeIndexP, nodePos, 0x8000, routeLength + (distanceVal & 0x3fff));
+ }
+ }
+
+ currentNode._active = false;
+}
+
+
+int Rails::scanPath(const Common::Point &srcPos, const Common::Point &destPos) {
+ // For compressed depth surfaces, always return 0
+ if (_depthStyle == 2)
+ return 0;
+
+ int yDiff = destPos.y - srcPos.y;
+ int yAmount = MADS_SCREEN_WIDTH;
+
+ if (yDiff < 0) {
+ yDiff = -yDiff;
+ yAmount = -yAmount;
+ }
+
+ int xDiff = destPos.x - srcPos.x;
+ int xDirection = 1;
+ int xAmount = 0;
+ if (xDiff < 0) {
+ xDiff = -xDiff;
+ xDirection = -xDirection;
+ xAmount = MIN(yDiff, xDiff);
+ }
+
+ ++xDiff;
+ ++yDiff;
+
+ const byte *srcP = _depthSurface->getBasePtr(srcPos.x, srcPos.y);
+ int index = xAmount;
+
+ // Outer loop
+ for (int xCtr = 0; xCtr < xDiff; ++xCtr, srcP += xDirection) {
+ index += yDiff;
+ int v = (*srcP & 0x7F) >> 4;
+ if (v)
+ return v;
+
+ // Inner loop for handling vertical movement
+ while (index >= xDiff) {
+ index -= xDiff;
+
+ v = (*srcP & 0x7F) >> 4;
+ if (v)
+ return v;
+
+ srcP += yAmount;
+ }
+ }
+
+ return 0;
+}
+
+void Rails::resetRoute() {
+ _routeIndexes.clear();
+ _next = 0;
+}
+
+const WalkNode &Rails::popNode() {
+ assert(!_routeIndexes.empty());
+
+ return _nodes[_routeIndexes.pop()];
+}
+
+void Rails::setNodePosition(int nodeIndex, const Common::Point &pt) {
+ int flags, hypotenuse;
+
+ _nodes[nodeIndex]._walkPos = pt;
+
+ // Recalculate inter-node lengths
+ for (uint idx = 0; idx < _nodes.size(); ++idx) {
+ int entry;
+ if (idx == (uint)nodeIndex) {
+ entry = 0x3FFF;
+ } else {
+ // Process the node
+ flags = getRouteFlags(pt, _nodes[idx]._walkPos);
+
+ int xDiff = ABS(_nodes[idx]._walkPos.x - pt.x);
+ int yDiff = ABS(_nodes[idx]._walkPos.y - pt.y);
+ hypotenuse = sqrt((double)(xDiff * xDiff + yDiff * yDiff));
+
+ if (hypotenuse >= 0x3FFF)
+ // Shouldn't ever be this large
+ hypotenuse = 0x3FFF;
+
+ entry = hypotenuse | flags;
+ }
+
+ _nodes[idx]._distances[nodeIndex] = entry;
+ _nodes[nodeIndex]._distances[idx] = entry;
+ }
+}
+
+int Rails::getRouteFlags(const Common::Point &src, const Common::Point &dest) {
+ int result = 0x8000;
+ bool flag = false;
+
+ int xDiff = ABS(dest.x - src.x);
+ int yDiff = ABS(dest.y - src.y);
+ int xDirection = dest.x >= src.x ? 1 : -1;
+ int yDirection = dest.y >= src.y ? _depthSurface->w : -_depthSurface->w;
+ int minorDiff = 0;
+ if (dest.x < src.x)
+ minorDiff = MIN(xDiff, yDiff);
+ ++xDiff;
+ ++yDiff;
+
+ byte *srcP = _depthSurface->getBasePtr(src.x, src.y);
+
+ int totalCtr = minorDiff;
+ for (int xCtr = 0; xCtr < xDiff; ++xCtr, srcP += xDirection) {
+ totalCtr += yDiff;
+
+ if ((*srcP & 0x80) == 0)
+ flag = false;
+ else if (!flag) {
+ flag = true;
+ result -= 0x4000;
+ if (result == 0)
+ break;
+ }
+
+ while (totalCtr >= xDiff) {
+ totalCtr -= xDiff;
+
+ if ((*srcP & 0x80) == 0)
+ flag = false;
+ else if (!flag) {
+ flag = true;
+ result -= 0x4000;
+ if (result == 0)
+ break;
+ }
+
+ srcP += yDirection;
+ }
+ if (result == 0)
+ break;
+ }
+
+ return result;
+}
+
+void Rails::synchronize(Common::Serializer &s) {
+ s.syncAsSint16LE(_routeLength);
+ s.syncAsSint16LE(_next);
+
+ int count = _routeIndexes.size();
+ if (s.isSaving()) {
+ for (int i = 0; i < count; ++i)
+ s.syncAsUint16LE(_routeIndexes[i]);
+ } else {
+ _routeIndexes.clear();
+ for (int i = 0; i < count; ++i) {
+ int v = 0;
+ s.syncAsUint16LE(v);
+ _routeIndexes.push(v);
+ }
+ }
+}
+
+} // End of namespace MADS
diff --git a/engines/mads/rails.h b/engines/mads/rails.h
new file mode 100644
index 0000000000..e6cab08f85
--- /dev/null
+++ b/engines/mads/rails.h
@@ -0,0 +1,134 @@
+/* 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.
+ *
+ */
+
+#ifndef MADS_RAILS_H
+#define MADS_RAILS_H
+
+#include "common/scummsys.h"
+#include "common/array.h"
+#include "common/rect.h"
+#include "common/serializer.h"
+#include "common/stack.h"
+#include "mads/msurface.h"
+
+namespace MADS {
+
+class WalkNode {
+public:
+ Common::Point _walkPos;
+ uint16 _distances[MAX_ROUTE_NODES];
+ bool _active;
+
+ /**
+ * Constructor
+ */
+ WalkNode();
+
+ /**
+ * Loads the scene node
+ */
+ void load(Common::SeekableReadStream *f);
+};
+typedef Common::Array<WalkNode> WalkNodeList;
+
+/**
+ * This class handles storing the intermediate walk node points for a
+ * given scene, and calculating walking routes between any two positions.
+ */
+class Rails {
+private:
+ WalkNodeList _nodes;
+ DepthSurface *_depthSurface;
+ int _depthStyle;
+ int _routeLength;
+ int _next;
+ int _tempRoute[MAX_ROUTE_NODES];
+ Common::Stack<int> _routeIndexes;
+private:
+ /**
+ * Change the position of a walking node. Doing so causes a recalculation of the
+ * distance between it and every other node, and vice versa
+ */
+ void setNodePosition(int nodeIndex, const Common::Point &pt);
+
+ int getRouteFlags(const Common::Point &src, const Common::Point &dest);
+public:
+ /**
+ * Constructor
+ */
+ Rails();
+
+ /**
+ * Loads the scene data for the list of intermediate walk nodes and the
+ * depth surface to use.
+ * @param nodes Intermediate walk-points
+ * @param depthSurface Depth surface to use
+ */
+ void load(const WalkNodeList &nodes, DepthSurface *depthSurface, int depthStyle);
+
+ /**
+ * Set up a route between two points in a scene
+ */
+ void setupRoute(bool bitFlag, const Common::Point &srcPos, const Common::Point &destPos);
+
+ void setupRouteNode(int *routeIndexP, int nodeIndex, int flags, int routeLength);
+
+ /**
+ * Resets any currently running route
+ */
+ void resetRoute();
+
+ /**
+ * Scans along an edge connecting two points within the depths/walk surface, and returns the information of the first
+ * pixel high nibble encountered with a non-zero value
+ */
+ int scanPath(const Common::Point &srcPos, const Common::Point &destPos);
+
+ /*
+ * Return the number of walk nodes in the calculated route
+ */
+ int size() const { return _routeIndexes.size(); }
+
+ /**
+ * Returns true if the current calculated walk route is empty
+ */
+ bool empty() const { return _routeIndexes.empty(); }
+
+ /**
+ * Returns the data for a given walk node
+ */
+ const WalkNode &operator[](int idx) { return _nodes[_routeIndexes[idx]]; }
+
+ const WalkNode &popNode();
+
+ void resetNext() { _next = 0; }
+ int getNext() { return _next; }
+
+ /**
+ * Synchronize the data for the route
+ */
+ void synchronize(Common::Serializer &s);
+};
+
+} // End of namespace MADS
+
+#endif /* MADS_RAILS_H */
diff --git a/engines/mads/resources.cpp b/engines/mads/resources.cpp
new file mode 100644
index 0000000000..745583b516
--- /dev/null
+++ b/engines/mads/resources.cpp
@@ -0,0 +1,416 @@
+/* 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 "common/archive.h"
+#include "common/textconsole.h"
+#include "mads/mads.h"
+#include "mads/resources.h"
+
+namespace MADS {
+
+enum ResourceType {RESTYPE_ROOM, RESTYPE_SC, RESTYPE_TEXT, RESTYPE_QUO, RESTYPE_I,
+ RESTYPE_OB, RESTYPE_FONT, RESTYPE_SOUND, RESTYPE_SPEECH, RESTYPE_HAS_EXT, RESTYPE_NO_EXT};
+
+/**
+ * HAG Archives implementation
+ */
+class HagArchive : public Common::Archive {
+private:
+ /**
+ * Details of a single entry in a HAG file index
+ */
+ struct HagEntry {
+ Common::String _resourceName;
+ uint32 _offset;
+ uint32 _size;
+
+ HagEntry(): _offset(0), _size(0) {}
+ HagEntry(Common::String resourceName, uint32 offset, uint32 size):
+ _resourceName(resourceName), _offset(offset), _size(size) {}
+ };
+
+ class HagIndex {
+ public:
+ Common::List<HagEntry> _entries;
+ Common::String _filename;
+ };
+
+ Common::Array<HagIndex> _index;
+
+ /**
+ * Load the index of all the game's HAG files
+ */
+ void loadIndex(MADSEngine *vm);
+
+ /**
+ * Given a resource name, opens up the correct HAG file and returns whether
+ * an entry with the given name exists.
+ */
+ bool getHeaderEntry(const Common::String &resourceName, HagIndex &hagIndex, HagEntry &hagEntry) const;
+
+ /**
+ * Returns the HAG resource filename that will contain a given resource
+ */
+ Common::String getResourceFilename(const Common::String &resourceName) const;
+
+ /**
+ * Return a resource type given a resource name
+ */
+ ResourceType getResourceType(const Common::String &resourceName) const;
+public:
+ HagArchive(MADSEngine *vm);
+ virtual ~HagArchive();
+
+ // Archive implementation
+ virtual bool hasFile(const Common::String &name) const;
+ virtual int listMembers(Common::ArchiveMemberList &list) const;
+ virtual const Common::ArchiveMemberPtr getMember(const Common::String &name) const;
+ virtual Common::SeekableReadStream *createReadStreamForMember(const Common::String &name) const;
+};
+
+const char *const MADSCONCAT_STRING = "MADSCONCAT";
+
+HagArchive::HagArchive(MADSEngine *vm) {
+ loadIndex(vm);
+}
+
+HagArchive::~HagArchive() {
+}
+
+// Archive implementation
+bool HagArchive::hasFile(const Common::String &name) const {
+ HagIndex hagIndex;
+ HagEntry hagEntry;
+ return getHeaderEntry(name, hagIndex, hagEntry);
+}
+
+int HagArchive::listMembers(Common::ArchiveMemberList &list) const {
+ int members = 0;
+
+ for (uint hagCtr = 0; hagCtr < _index.size(); ++hagCtr) {
+ HagIndex hagIndex = _index[hagCtr];
+ Common::List<HagEntry>::iterator i;
+
+ for (i = hagIndex._entries.begin(); i != hagIndex._entries.end(); ++i) {
+ list.push_back(Common::ArchiveMemberList::value_type(
+ new Common::GenericArchiveMember((*i)._resourceName, this)));
+ ++members;
+ }
+ }
+
+ return members;
+}
+
+const Common::ArchiveMemberPtr HagArchive::getMember(const Common::String &name) const {
+ if (!hasFile(name))
+ return Common::ArchiveMemberPtr();
+
+ return Common::ArchiveMemberPtr(new Common::GenericArchiveMember(name, this));
+}
+
+Common::SeekableReadStream *HagArchive::createReadStreamForMember(const Common::String &name) const {
+ HagIndex hagIndex;
+ HagEntry hagEntry;
+
+ if (getHeaderEntry(name, hagIndex, hagEntry)) {
+ // Entry found. If the correct file is not already open, open it
+ Common::File f;
+ if (!f.open(hagIndex._filename))
+ error("Could not open HAG file");
+
+ // Return a new stream for the specific resource
+ f.seek(hagEntry._offset);
+ return f.readStream(hagEntry._size);
+ }
+
+ return nullptr;
+}
+
+void HagArchive::loadIndex(MADSEngine *vm) {
+ Common::File hagFile;
+
+ for (int sectionIndex = -1; sectionIndex < 11; ++sectionIndex) {
+ if (sectionIndex == 0)
+ continue;
+
+ // Dragonsphere does not have some sections - skip them
+ if (vm->getGameID() == GType_Dragonsphere) {
+ if (sectionIndex == 7 || sectionIndex == 8)
+ continue;
+ }
+
+ // Phantom does not have some sections - skip them
+ if (vm->getGameID() == GType_Phantom) {
+ if (sectionIndex == 6 || sectionIndex == 7 || sectionIndex == 8)
+ continue;
+ }
+
+ Common::String filename = (sectionIndex == -1) ? "GLOBAL.HAG" :
+ Common::String::format("SECTION%d.HAG", sectionIndex);
+ if (sectionIndex == 10) {
+ // Speech
+ if (!Common::File::exists("SPEECH.HAG"))
+ break;
+ else
+ filename = "SPEECH.HAG";
+ }
+ if (!hagFile.open(filename))
+ error("Could not locate HAG file - %s", filename.c_str());
+
+ // Check for header
+ char headerBuffer[16];
+ if ((hagFile.read(headerBuffer, 16) != 16) ||
+ (strncmp(headerBuffer, MADSCONCAT_STRING, 10) != 0))
+ error("Invalid HAG file opened");
+
+ // Scan through the HAG index
+ int numEntries = hagFile.readUint16LE();
+
+ HagIndex hagIndex;
+ hagIndex._filename = filename;
+
+ for (int idx = 0; idx < numEntries; ++idx) {
+ // Read in the details of the next resource
+ char resourceBuffer[14];
+ uint32 offset = hagFile.readUint32LE();
+ uint32 size = hagFile.readUint32LE();
+ hagFile.read(resourceBuffer, 14);
+
+ hagIndex._entries.push_back(HagEntry(resourceBuffer, offset, size));
+ }
+
+ hagFile.close();
+ _index.push_back(hagIndex);
+ }
+}
+
+bool HagArchive::getHeaderEntry(const Common::String &resourceName,
+ HagIndex &hagIndex, HagEntry &hagEntry) const {
+ Common::String resName = resourceName;
+ resName.toUppercase();
+ if (resName[0] == '*')
+ resName.deleteChar(0);
+
+ Common::String hagFilename = getResourceFilename(resName);
+
+ // Find the index for the given file
+ for (uint hagCtr = 0; hagCtr < _index.size(); ++hagCtr) {
+ hagIndex = _index[hagCtr];
+
+ if (hagIndex._filename == hagFilename) {
+ Common::List<HagEntry>::iterator ei;
+ for (ei = hagIndex._entries.begin(); ei != hagIndex._entries.end(); ++ei) {
+ hagEntry = *ei;
+ if (hagEntry._resourceName.compareToIgnoreCase(resName) == 0)
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+Common::String HagArchive::getResourceFilename(const Common::String &resourceName) const {
+ ResourceType resType = getResourceType(resourceName);
+ Common::String outputFilename = "GLOBAL.HAG";
+
+ if ((resType == RESTYPE_ROOM) || (resType == RESTYPE_SC)) {
+ int value = atoi(resourceName.c_str() + 2);
+ int hagFileNum = (resType == RESTYPE_ROOM) ? value / 100 : value;
+
+ if (hagFileNum > 0)
+ outputFilename = Common::String::format("SECTION%d.HAG", hagFileNum);
+ }
+
+ if (resType == RESTYPE_SPEECH)
+ outputFilename = "SPEECH.HAG";
+
+ return outputFilename;
+}
+
+ResourceType HagArchive::getResourceType(const Common::String &resourceName) const {
+ if (resourceName.hasPrefix("RM")) {
+ // Room resource
+ return RESTYPE_ROOM;
+ } else if (resourceName.hasPrefix("SC")) {
+ // SC resource
+ return RESTYPE_SC;
+ } else if (resourceName.hasSuffix(".TXT")) {
+ // Text resource
+ return RESTYPE_TEXT;
+ } else if (resourceName.hasSuffix(".QUO")) {
+ // QUO resource
+ return RESTYPE_QUO;
+ } else if (resourceName.hasPrefix("I")) {
+ // I resource
+ return RESTYPE_I;
+ } else if (resourceName.hasPrefix("OB")) {
+ // OB resource
+ return RESTYPE_OB;
+ } else if (resourceName.hasPrefix("FONT")) {
+ // FONT resource
+ return RESTYPE_FONT;
+ } else if (resourceName.hasPrefix("SOUND")) {
+ // SOUND resource
+ return RESTYPE_SOUND;
+ } else if (resourceName.hasPrefix("SPCHC")) {
+ // SPEECH resource
+ return RESTYPE_SPEECH;
+ }
+
+ // Check for a known extension
+ const char *extPos = strchr(resourceName.c_str(), '.');
+ if (extPos) {
+ ++extPos;
+ if (!strcmp(extPos, "FL") || !strcmp(extPos, "LBM") || !strcmp(extPos, "ANM") ||
+ !strcmp(extPos, "AA") || !strcmp(extPos, "SS")) {
+ return RESTYPE_HAS_EXT;
+ }
+ }
+
+ return RESTYPE_NO_EXT;
+}
+
+/*------------------------------------------------------------------------*/
+
+void Resources::init(MADSEngine *vm) {
+ SearchMan.add("HAG", new HagArchive(vm));
+}
+
+Common::String Resources::formatName(RESPREFIX resType, int id, const Common::String &ext) {
+ Common::String result = "*";
+
+ if (resType == 3 && !id) {
+ id = id / 100;
+ }
+
+ if (!ext.empty()) {
+ switch (resType) {
+ case RESPREFIX_GL:
+ result += "GL000";
+ break;
+ case RESPREFIX_SC:
+ result += Common::String::format("SC%.3d", id);
+ break;
+ case RESPREFIX_RM:
+ result += Common::String::format("RM%.3d", id);
+ break;
+ default:
+ break;
+ }
+
+ result += ext;
+ }
+
+ return result;
+}
+
+Common::String Resources::formatName(int prefix, char asciiCh, int id, EXTTYPE extType,
+ const Common::String &suffix) {
+ Common::String result;
+ if (prefix <= 0) {
+ result = "*";
+ } else {
+ result = Common::String::format("%s%.3d",
+ (prefix < 100) ? "*SC" : "*RM", prefix);
+ }
+
+ result += Common::String::format("%c", asciiCh);
+ if (id >= 0)
+ result += Common::String::format("%d", id);
+ if (!suffix.empty())
+ result += suffix;
+
+ switch (extType) {
+ case EXT_SS:
+ result += ".SS";
+ break;
+ case EXT_AA:
+ result += ".AA";
+ break;
+ case EXT_DAT:
+ result += ".DAT";
+ break;
+ case EXT_HH:
+ result += ".HH";
+ break;
+ case EXT_ART:
+ result += ".ART";
+ break;
+ case EXT_INT:
+ result += ".INT";
+ break;
+ default:
+ break;
+ }
+
+ return result;
+}
+
+Common::String Resources::formatResource(const Common::String &resName,
+ const Common::String &hagFilename) {
+// int v1 = 0, v2 = 0;
+
+ if (resName.hasPrefix("*")) {
+ // Resource file specified
+ error("TODO: formatResource");
+ } else {
+ // File outside of hag file
+ return resName;
+ }
+}
+
+Common::String Resources::formatAAName(int idx) {
+ return formatName(0, 'I', idx, EXT_AA, "");
+}
+
+/*------------------------------------------------------------------------*/
+
+void File::openFile(const Common::String &filename) {
+ if (!Common::File::open(filename))
+ error("Could not open file - %s", filename.c_str());
+}
+
+/*------------------------------------------------------------------------*/
+
+void SynchronizedList::synchronize(Common::Serializer &s) {
+ int v;
+ int count = size();
+ s.syncAsUint16LE(count);
+
+ if (s.isSaving()) {
+ for (int idx = 0; idx < count; ++idx) {
+ v = (*this)[idx];
+ s.syncAsSint32LE(v);
+ }
+ } else {
+ clear();
+ reserve(count);
+ for (int idx = 0; idx < count; ++idx) {
+ s.syncAsSint32LE(v);
+ push_back(v);
+ }
+ }
+}
+
+} // End of namespace MADS
diff --git a/engines/mads/resources.h b/engines/mads/resources.h
new file mode 100644
index 0000000000..003684ef84
--- /dev/null
+++ b/engines/mads/resources.h
@@ -0,0 +1,89 @@
+/* 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.
+ *
+ */
+
+#ifndef MADS_RESOURCES_H
+#define MADS_RESOURCES_H
+
+#include "common/scummsys.h"
+#include "common/file.h"
+#include "common/serializer.h"
+#include "common/str.h"
+
+namespace MADS {
+
+class MADSEngine;
+
+enum RESPREFIX {
+ RESPREFIX_GL = 1, RESPREFIX_SC = 2, RESPREFIX_RM = 3
+};
+
+enum EXTTYPE {
+ EXT_NONE = -1, EXT_SS = 1, EXT_AA = 2, EXT_DAT = 3, EXT_HH = 4,
+ EXT_ART = 5, EXT_INT = 6
+};
+
+class Resources {
+public:
+ /**
+ * Instantiates the resource manager
+ */
+ static void init(MADSEngine *vm);
+
+ static Common::String formatName(RESPREFIX resType, int id, const Common::String &ext);
+ static Common::String formatName(int prefix, char asciiCh, int id,
+ EXTTYPE extType, const Common::String &suffix);
+ static Common::String formatResource(const Common::String &resName, const Common::String &hagFilename);
+ static Common::String formatAAName(int idx);
+};
+
+/**
+ * Derived file class
+ */
+class File: public Common::File {
+public:
+ /**
+ * Constructor
+ */
+ File(): Common::File() {}
+
+ /**
+ * Constructor
+ */
+ File(const Common::String &filename) { openFile(filename); }
+
+ /**
+ * Opens the given file, throwing an error if it can't be opened
+ */
+ void openFile(const Common::String &filename);
+};
+
+class SynchronizedList : public Common::Array<int> {
+public:
+ /**
+ * Synchronize the list
+ */
+ void synchronize(Common::Serializer &s);
+};
+
+} // End of namespace MADS
+
+#endif /* MADS_RESOURCES_H */
diff --git a/engines/mads/scene.cpp b/engines/mads/scene.cpp
new file mode 100644
index 0000000000..4af956a9f6
--- /dev/null
+++ b/engines/mads/scene.cpp
@@ -0,0 +1,718 @@
+/* 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 "mads/scene.h"
+#include "mads/compression.h"
+#include "mads/mads.h"
+#include "mads/dragonsphere/dragonsphere_scenes.h"
+#include "mads/nebular/nebular_scenes.h"
+#include "mads/phantom/phantom_scenes.h"
+
+namespace MADS {
+
+Scene::Scene(MADSEngine *vm): _vm(vm), _action(_vm), _depthSurface(vm),
+ _dirtyAreas(_vm), _dynamicHotspots(vm), _hotspots(vm),
+ _kernelMessages(vm), _sequences(vm), _sprites(vm), _spriteSlots(vm),
+ _textDisplay(vm), _userInterface(vm) {
+ _priorSceneId = 0;
+ _nextSceneId = 0;
+ _currentSceneId = 0;
+ _sceneLogic = nullptr;
+ _sceneInfo = nullptr;
+ _cyclingActive = false;
+ _cyclingThreshold = 0;
+ _cyclingDelay = 0;
+ _totalCycleColors = 0;
+ _depthStyle = 0;
+ _roomChanged = false;
+ _reloadSceneFlag = false;
+ _freeAnimationFlag = false;
+ _animationData = nullptr;
+ _activeAnimation = nullptr;
+ _textSpacing = -1;
+ _frameStartTime = 0;
+ _layer = LAYER_GUI;
+ _lookFlag = false;
+ _bandsRange = 0;
+ _scaleRange = 0;
+ _interfaceY = 0;
+ _spritesCount = 0;
+ _variant = 0;
+
+ _paletteUsageF.push_back(PaletteUsage::UsageEntry(0xF));
+
+ // Set up a scene surface that maps to our physical screen drawing surface
+ _sceneSurface.init(MADS_SCREEN_WIDTH, MADS_SCENE_HEIGHT, MADS_SCREEN_WIDTH,
+ _vm->_screen.getPixels(), Graphics::PixelFormat::createFormatCLUT8());
+
+ // Set up the verb list
+ _verbList.push_back(VerbInit(VERB_LOOK, VERB_THAT, PREP_NONE));
+ _verbList.push_back(VerbInit(VERB_TAKE, VERB_THAT, PREP_NONE));
+ _verbList.push_back(VerbInit(VERB_PUSH, VERB_THAT, PREP_NONE));
+ _verbList.push_back(VerbInit(VERB_OPEN, VERB_THAT, PREP_NONE));
+ _verbList.push_back(VerbInit(VERB_PUT, VERB_THIS, PREP_RELATIONAL));
+ _verbList.push_back(VerbInit(VERB_TALKTO, VERB_THAT, PREP_NONE));
+ _verbList.push_back(VerbInit(VERB_GIVE, VERB_THIS, PREP_TO));
+ _verbList.push_back(VerbInit(VERB_PULL, VERB_THAT, PREP_NONE));
+ _verbList.push_back(VerbInit(VERB_CLOSE, VERB_THAT, PREP_NONE));
+ _verbList.push_back(VerbInit(VERB_THROW, VERB_THIS, PREP_TO));
+}
+
+Scene::~Scene() {
+ delete _sceneLogic;
+ delete _sceneInfo;
+}
+
+void Scene::clearVocab() {
+ _activeVocabs.clear();
+}
+
+void Scene::addActiveVocab(int vocabId) {
+ if (activeVocabIndexOf(vocabId) == -1) {
+ assert(_activeVocabs.size() < 200);
+ _activeVocabs.push_back(vocabId);
+ }
+}
+
+int Scene::activeVocabIndexOf(int vocabId) {
+ for (uint i = 0; i < _activeVocabs.size(); ++i) {
+ if (_activeVocabs[i] == vocabId)
+ return i;
+ }
+
+ return -1;
+}
+
+void Scene::clearSequenceList() {
+ _sequences.clear();
+}
+
+void Scene::clearMessageList() {
+ _kernelMessages.clear();
+ _talkFont = FONT_CONVERSATION;
+ _textSpacing = -1;
+}
+
+void Scene::loadSceneLogic() {
+ delete _sceneLogic;
+
+ switch (_vm->getGameID()) {
+ case GType_RexNebular:
+ _sceneLogic = Nebular::SceneFactory::createScene(_vm);
+ break;
+ case GType_Dragonsphere:
+ _sceneLogic = Dragonsphere::SceneFactory::createScene(_vm);
+ break;
+ case GType_Phantom:
+ _sceneLogic = Phantom::SceneFactory::createScene(_vm);
+ break;
+ default:
+ error("Scene logic: Unknown game");
+ }
+}
+
+void Scene::loadScene(int sceneId, const Common::String &prefix, bool palFlag) {
+ // Store the previously active scene number and set the new one
+ _priorSceneId = _currentSceneId;
+ _currentSceneId = sceneId;
+
+ _variant = 0;
+ if (palFlag)
+ _vm->_palette->resetGamePalette(18, 10);
+
+ _spriteSlots.reset(false);
+ _sequences.clear();
+ _kernelMessages.clear();
+ _vm->_palette->_paletteUsage.load(&_scenePaletteUsage);
+
+ int flags = SCENEFLAG_LOAD_SHADOW;
+ if (_vm->_dithering)
+ flags |= SCENEFLAG_DITHER;
+
+ _sceneInfo = SceneInfo::init(_vm);
+ _sceneInfo->load(_currentSceneId, _variant, Common::String(), flags,
+ _depthSurface, _backgroundSurface);
+
+ // Initialise palette animation for the scene
+ initPaletteAnimation(_sceneInfo->_paletteCycles, false);
+
+ // Copy over nodes
+ _rails.load(_sceneInfo->_nodes, &_depthSurface, _sceneInfo->_depthStyle);
+
+ // Load hotspots
+ loadHotspots();
+
+ // Load vocab
+ loadVocab();
+
+ // Load palette usage
+ _vm->_palette->_paletteUsage.load(&_paletteUsageF);
+
+ // Load interface
+ flags = PALFLAG_RESERVED | ANIMFLAG_LOAD_BACKGROUND;
+ if (_vm->_dithering)
+ flags |= ANIMFLAG_DITHER;
+ if (_vm->_textWindowStill)
+ flags |= ANIMFLAG_LOAD_BACKGROUND_ONLY;
+
+ _animationData = Animation::init(_vm, this);
+ DepthSurface depthSurface(_vm);
+ _animationData->load(_userInterface, depthSurface, prefix, flags, nullptr, nullptr);
+
+ _vm->_palette->_paletteUsage.load(&_scenePaletteUsage);
+
+ _bandsRange = _sceneInfo->_yBandsEnd - _sceneInfo->_yBandsStart;
+ _scaleRange = _sceneInfo->_maxScale - _sceneInfo->_minScale;
+
+ _spriteSlots.reset(false);
+ _interfaceY = MADS_SCENE_HEIGHT;
+ _spritesCount = _sprites.size();
+
+ _userInterface.setup(_vm->_game->_screenObjects._inputMode);
+
+ _vm->_game->_screenObjects._category = CAT_NONE;
+ _vm->_events->showCursor();
+}
+
+void Scene::loadHotspots() {
+ File f(Resources::formatName(RESPREFIX_RM, _currentSceneId, ".HH"));
+ MadsPack madsPack(&f);
+ bool isV2 = (_vm->getGameID() != GType_RexNebular);
+
+ Common::SeekableReadStream *stream = madsPack.getItemStream(0);
+ int count = stream->readUint16LE();
+ delete stream;
+
+ stream = madsPack.getItemStream(1);
+ _hotspots.clear();
+ for (int i = 0; i < count; ++i)
+ _hotspots.push_back(Hotspot(*stream, isV2));
+
+ delete stream;
+ f.close();
+}
+
+void Scene::loadVocab() {
+ // Add all the verbs to the active vocab list
+ for (uint i = 0; i < _verbList.size(); ++i)
+ addActiveVocab(_verbList[i]._id);
+
+ // Load the vocabs for any object descriptions and custom actions
+ for (uint objIndex = 0; objIndex < _vm->_game->_objects.size(); ++objIndex) {
+ InventoryObject &io = _vm->_game->_objects[objIndex];
+ addActiveVocab(io._descId);
+
+ for (int vocabIndex = 0; vocabIndex <io._vocabCount; ++vocabIndex) {
+ addActiveVocab(io._vocabList[vocabIndex]._vocabId);
+ }
+ }
+
+ // Load scene hotspot list vocabs and verbs
+ for (uint i = 0; i < _hotspots.size(); ++i) {
+ addActiveVocab(_hotspots[i]._vocabId);
+ if (_hotspots[i]._verbId)
+ addActiveVocab(_hotspots[i]._verbId);
+ }
+
+ loadVocabStrings();
+}
+
+void Scene::loadVocabStrings() {
+ _vocabStrings.clear();
+ File f("*VOCAB.DAT");
+ Common::String msg;
+
+ for (;;) {
+ char c = (char)f.readByte();
+ if (f.eos()) break;
+
+ if (c == '\0') {
+ _vocabStrings.push_back(msg);
+ msg = "";
+ } else {
+ msg += c;
+ }
+ }
+
+ f.close();
+}
+
+uint32 Scene::getVocabStringsCount() const {
+ return _vocabStrings.size();
+}
+
+void Scene::initPaletteAnimation(Common::Array<PaletteCycle> &palCycles, bool animFlag) {
+ // Initialize the animation palette and ticks list
+ _cycleTicks.clear();
+ _paletteCycles.clear();
+
+ for (uint i = 0; i < palCycles.size(); ++i) {
+ _cycleTicks.push_back(_vm->_events->getFrameCounter());
+ _paletteCycles.push_back(palCycles[i]);
+ }
+
+ // Save the initial starting palette
+ Common::copy(&_vm->_palette->_mainPalette[0], &_vm->_palette->_mainPalette[PALETTE_SIZE],
+ &_vm->_palette->_cyclingPalette[0]);
+
+ // Calculate total
+ _totalCycleColors = 0;
+ for (uint i = 0; i < _paletteCycles.size(); ++i)
+ _totalCycleColors += _paletteCycles[i]._colorCount;
+
+ _cyclingThreshold = (_totalCycleColors > 16) ? 3 : 0;
+ _cyclingActive = animFlag;
+}
+
+void Scene::animatePalette() {
+ byte rgb[3];
+
+ if (_cyclingActive) {
+ Scene::_cyclingDelay++;
+ if (_cyclingDelay >= _cyclingThreshold) {
+ uint32 frameCounter = _vm->_events->getFrameCounter();
+ bool changesFlag = false;
+ for (uint16 idx = 0; idx < _paletteCycles.size(); idx++) {
+ if (frameCounter >= (_cycleTicks[idx] + _paletteCycles[idx]._ticks)) {
+ _cycleTicks[idx] = frameCounter;
+ int count = _paletteCycles[idx]._colorCount;
+ int first = _paletteCycles[idx]._firstColorIndex;
+ int listIndex = _paletteCycles[idx]._firstListColor;
+ changesFlag = true;
+
+ if (count > 1) {
+ // Make a copy of the last color
+ byte *pSrc = &_vm->_palette->_cyclingPalette[first * 3];
+ byte *pEnd = pSrc + count * 3;
+ Common::copy(pEnd - 3, pEnd, &rgb[0]);
+
+ // Shift the cycle palette forward one entry
+ Common::copy_backward(pSrc, pEnd - 3, pEnd);
+
+ // Move the saved color to the start of the cycle
+ Common::copy(&rgb[0], &rgb[3], pSrc);
+
+ if (++listIndex >= count)
+ listIndex = 0;
+ }
+
+ _paletteCycles[idx]._firstListColor = listIndex;
+ }
+ }
+
+ if (changesFlag) {
+ int firstColor = _paletteCycles[0]._firstColorIndex;
+ byte *pSrc = &_vm->_palette->_cyclingPalette[firstColor * 3];
+ _vm->_palette->setPalette(pSrc, firstColor, _totalCycleColors);
+ }
+
+ _cyclingDelay = 0;
+ }
+ }
+}
+
+bool Scene::getDepthHighBits(const Common::Point &pt) {
+ if (_sceneInfo->_depthStyle == 2) {
+ return 0;
+ } else {
+ const byte *p = _depthSurface.getBasePtr(pt.x, pt.y);
+ return (*p & 0x70) >> 4;
+ }
+}
+
+void Scene::loop() {
+ while (!_vm->shouldQuit() && !_reloadSceneFlag && (_nextSceneId == _currentSceneId)) {
+ // Handle drawing a game frame
+ doFrame();
+
+ // TODO: Verify correctness of frame wait
+ _vm->_events->waitForNextFrame();
+
+ if (_vm->_dialogs->_pendingDialog != DIALOG_NONE && !_vm->_game->_trigger
+ && _vm->_game->_player._stepEnabled)
+ _reloadSceneFlag = true;
+ }
+}
+
+void Scene::doFrame() {
+ Player &player = _vm->_game->_player;
+ bool flag = false;
+
+ if (_action._selectedAction || !player._stepEnabled) {
+ _action.clear();
+ _action._selectedAction = 0;
+ }
+
+ if (!_vm->_game->_trigger && !player._trigger) {
+ // Refresh the dynamic hotspots if they've changed
+ if (_dynamicHotspots._changed)
+ _dynamicHotspots.refresh();
+
+ // Check all on-screen visual objects
+ _vm->_game->_screenObjects.check(player._stepEnabled && !player._needToWalk &&
+ !_vm->_game->_fx);
+ }
+
+ if (_action._selectedAction && player._stepEnabled && !player._needToWalk &&
+ !_vm->_game->_trigger && !player._trigger) {
+ _action.startAction();
+ if (_action._activeAction._verbId == Nebular::VERB_LOOK_AT) {
+ _action._activeAction._verbId = VERB_LOOK;
+ _action._savedFields._command = false;
+ }
+
+ flag = true;
+ }
+
+ if (flag || (_vm->_game->_trigger && _vm->_game->_triggerMode == SEQUENCE_TRIGGER_PREPARE)) {
+ doPreactions();
+ }
+
+ player.newWalk();
+ if (!_vm->_game->_fx)
+ _frameStartTime = _vm->_events->getFrameCounter();
+
+ // Handle parser actions as well as game triggers
+ if ((_action._inProgress && !player._moving && !player._needToWalk &&
+ (player._facing == player._turnToFacing) && !_vm->_game->_trigger) ||
+ (_vm->_game->_trigger && (_vm->_game->_triggerMode == SEQUENCE_TRIGGER_PARSER))) {
+ doAction();
+ }
+
+ if (_currentSceneId != _nextSceneId) {
+ _freeAnimationFlag = true;
+ } else {
+ doSceneStep();
+ checkKeyboard();
+
+ if (_currentSceneId != _nextSceneId) {
+ _freeAnimationFlag = true;
+ } else {
+ player.nextFrame();
+
+ // Cursor update code
+ updateCursor();
+
+ if (!_vm->_game->_trigger) {
+ // Handle any active sequences
+ _sequences.tick();
+
+ // Handle any active animation
+ if (_activeAnimation)
+ _activeAnimation->update();
+ }
+
+ // If the debugget flag is set, show the mouse position
+ int mouseTextIndex = 0;
+ if (_vm->_debugger->_showMousePos) {
+ Common::Point pt = _vm->_events->mousePos();
+ Common::String msg = Common::String::format("(%d,%d)", pt.x, pt.y);
+ mouseTextIndex = _kernelMessages.add(Common::Point(5, 5),
+ 0x203, 0, 0, 1, msg);
+ }
+
+ if (!_vm->_game->_trigger) {
+ if (_reloadSceneFlag || _currentSceneId != _nextSceneId)
+ _kernelMessages.reset();
+ _kernelMessages.update();
+ }
+
+ _userInterface._uiSlots.draw(!_vm->_game->_fx, _vm->_game->_fx);
+
+ // Write any text needed by the interface
+ if (_vm->_game->_fx)
+ _userInterface.drawTextElements();
+
+ // Draw any elements
+ drawElements((ScreenTransition)_vm->_game->_fx, _vm->_game->_fx);
+
+ // Handle message updates
+ if (_vm->_game->_fx) {
+ uint32 priorTime = _vm->_game->_priorFrameTimer;
+ uint32 newTime = _vm->_events->getFrameCounter();
+ _sequences.delay(newTime, priorTime);
+ _kernelMessages.delay(newTime, priorTime);
+ }
+
+ if (_vm->_debugger->_showMousePos)
+ // Mouse position display isn't persistent, so remove it
+ _kernelMessages.remove(mouseTextIndex);
+
+ // Original had a debugger check/call here to allow pausing after
+ // drawing each frame. Not implemented under ScummVM
+ }
+ }
+
+ if (_vm->_game->_fx)
+ _cyclingActive = true;
+ _vm->_game->_fx = kTransitionNone;
+
+ if (_freeAnimationFlag)
+ freeAnimation();
+}
+
+void Scene::drawElements(ScreenTransition transitionType, bool surfaceFlag) {
+ // Draw any sprite backgrounds
+ _spriteSlots.drawBackground();
+
+ // Set up dirty areas for any text display
+ _textDisplay.setDirtyAreas();
+
+ // Merge any identified dirty areas
+ _dirtyAreas.merge(1, DIRTY_AREAS_SIZE);
+
+ // Copy background for the dirty areas to the screen
+ _dirtyAreas.copy(&_backgroundSurface, &_vm->_screen, _posAdjust);
+
+ // Handle dirty areas for foreground objects
+ if (_vm->getGameID() == GType_RexNebular) // TODO: Implement for V2 games
+ _spriteSlots.setDirtyAreas();
+ _textDisplay.setDirtyAreas2();
+ _dirtyAreas.merge(1, DIRTY_AREAS_SIZE);
+
+ // Draw sprites that have changed
+ if (_vm->getGameID() == GType_RexNebular) // TODO: Implement for V2 games
+ _spriteSlots.drawSprites(&_sceneSurface);
+
+ // Draw text elements onto the view
+ _textDisplay.draw(&_vm->_screen);
+
+ if (transitionType) {
+ // Fading in the screen
+ _vm->_screen.transition(transitionType, surfaceFlag);
+ _vm->_sound->startQueuedCommands();
+ } else {
+ // Copy dirty areas to the screen
+ _dirtyAreas.copyToScreen(_vm->_screen._offset);
+ }
+
+ _spriteSlots.cleanUp();
+ _textDisplay.cleanUp();
+}
+
+void Scene::doPreactions() {
+ if (_vm->_game->_screenObjects._inputMode == kInputBuildingSentences ||
+ _vm->_game->_screenObjects._inputMode == kInputLimitedSentences) {
+ _vm->_game->_triggerSetupMode = SEQUENCE_TRIGGER_PREPARE;
+ _action.checkAction();
+ _sceneLogic->preActions();
+
+ if (_vm->_game->_triggerMode == SEQUENCE_TRIGGER_PREPARE)
+ _vm->_game->_trigger = 0;
+ }
+}
+
+void Scene::doAction() {
+ bool flag = false;
+
+ _vm->_game->_triggerSetupMode = SEQUENCE_TRIGGER_PARSER;
+ if ((_action._inProgress || _vm->_game->_trigger) && !_action._savedFields._commandError) {
+ _sceneLogic->actions();
+ flag = !_action._inProgress;
+ }
+
+ if (_vm->_game->_screenObjects._inputMode == kInputConversation) {
+ _action._inProgress = false;
+ } else {
+ if ((_action._inProgress || _vm->_game->_trigger) ||
+ (!flag && _action._savedFields._commandError == flag)) {
+ _vm->_game->_sectionHandler->sectionPtr2();
+ flag = !_action._inProgress;
+ }
+
+ if ((_action._inProgress || _vm->_game->_trigger) &&
+ (!flag || _action._savedFields._commandError == flag)) {
+ _vm->_game->doObjectAction();
+ }
+
+ if (!_action._savedFields._lookFlag) {
+ if (_action._inProgress) {
+ _action._savedFields._commandError = true;
+ _sceneLogic->postActions();
+ }
+
+ if (_action._inProgress) {
+ _action._savedFields._commandError = true;
+ _sceneLogic->unhandledAction();
+ }
+
+ if (_action._inProgress)
+ _vm->_game->unhandledAction();
+ }
+ }
+
+ _action._inProgress = false;
+ if (_vm->_game->_triggerMode == SEQUENCE_TRIGGER_PARSER)
+ _vm->_game->_trigger = 0;
+}
+
+void Scene::doSceneStep() {
+ _vm->_game->_triggerSetupMode = SEQUENCE_TRIGGER_DAEMON;
+ _sceneLogic->step();
+ _vm->_game->_sectionHandler->step();
+ _vm->_game->step();
+
+ if (_vm->_game->_triggerMode == SEQUENCE_TRIGGER_DAEMON)
+ _vm->_game->_trigger = 0;
+}
+
+void Scene::checkKeyboard() {
+ if (_vm->_events->isKeyPressed()) {
+ Common::Event evt = _vm->_events->_pendingKeys.pop();
+ _vm->_game->handleKeypress(evt);
+ }
+
+ if ((_vm->_events->_mouseStatus & 3) == 3 && _vm->_game->_player._stepEnabled) {
+ _reloadSceneFlag = true;
+ _vm->_dialogs->_pendingDialog = DIALOG_GAME_MENU;
+ _action.clear();
+ _action._selectedAction = 0;
+ }
+}
+
+void Scene::loadAnimation(const Common::String &resName, int trigger) {
+ // WORKAROUND: If there's already a previous active animation used by the
+ // scene, then free it before we create the new one
+ if (_activeAnimation)
+ freeAnimation();
+
+ DepthSurface depthSurface(_vm);
+ UserInterface interfaceSurface(_vm);
+
+ _activeAnimation = Animation::init(_vm, this);
+ _activeAnimation->load(interfaceSurface, depthSurface, resName,
+ _vm->_dithering ? ANIMFLAG_DITHER : 0, nullptr, nullptr);
+ _activeAnimation->startAnimation(trigger);
+}
+
+void Scene::updateCursor() {
+ Player &player = _vm->_game->_player;
+
+ CursorType cursorId = CURSOR_ARROW;
+ if (_action._interAwaiting == AWAITING_COMMAND && !_vm->_events->_rightMousePressed &&
+ _vm->_game->_screenObjects._category == CAT_HOTSPOT) {
+ int idx = _vm->_game->_screenObjects._selectedObject -
+ _userInterface._categoryIndexes[CAT_HOTSPOT - 1];
+ assert(idx >= 0);
+
+ if (idx >= (int)_hotspots.size()) {
+ idx -= _hotspots.size();
+ _vm->_events->_newCursorId = _dynamicHotspots[idx]._cursor;
+ } else {
+ idx = _hotspots.size() - idx - 1;
+ _vm->_events->_newCursorId = _hotspots[idx]._cursor;
+ }
+
+ cursorId = _vm->_events->_newCursorId == CURSOR_NONE ?
+ CURSOR_ARROW : _vm->_events->_newCursorId;
+ }
+
+ if (!player._stepEnabled)
+ cursorId = CURSOR_WAIT;
+ if (cursorId >= _vm->_events->_cursorSprites->getCount())
+ cursorId = (CursorType)_vm->_events->_cursorSprites->getCount();
+ _vm->_events->_newCursorId = cursorId;
+
+ if (cursorId != _vm->_events->_cursorId) {
+ _vm->_events->setCursor(cursorId);
+ }
+}
+
+void Scene::freeCurrentScene() {
+ if (_animationData) {
+ delete _animationData;
+ _animationData = nullptr;
+ }
+ if (_activeAnimation) {
+ delete _activeAnimation;
+ _activeAnimation = nullptr;
+ }
+
+ _vm->_palette->_paletteUsage.load(nullptr);
+ _hotspots.clear();
+ _backgroundSurface.free();
+ _depthSurface.free();
+
+ delete _sceneInfo;
+ _sceneInfo = nullptr;
+}
+
+void Scene::removeSprites() {
+ for (int idx = _sprites.size() - 1; idx >= _spritesCount; --idx)
+ _sprites.remove(idx);
+}
+
+void Scene::changeVariant(int variant) {
+ _variant = variant;
+ _sceneInfo->loadCodes(_depthSurface, variant);
+ _spriteSlots.fullRefresh();
+}
+
+void Scene::resetScene() {
+ _vm->_game->clearQuotes();
+ _spriteSlots.fullRefresh(true);
+ _sequences.clear();
+}
+
+void Scene::freeAnimation() {
+ if (_activeAnimation) {
+ Player &player = _vm->_game->_player;
+
+ if (!_freeAnimationFlag) {
+ _spriteSlots.fullRefresh(true);
+ _sequences.scan();
+ }
+
+ // Refresh the player
+ if (player._visible) {
+ player._forceRefresh = true;
+ player.update();
+ }
+
+ // Remove any kernel messages in use by the animation
+ for (uint i = 0; i < _activeAnimation->_messages.size(); ++i) {
+ int msgIndex = _activeAnimation->_messages[i]._kernelMsgIndex;
+ if (msgIndex >= 0)
+ _kernelMessages.remove(msgIndex);
+ }
+
+ // Delete the animation
+ delete _activeAnimation;
+ _activeAnimation = nullptr;
+ }
+
+ _freeAnimationFlag = false;
+}
+
+void Scene::synchronize(Common::Serializer &s) {
+ _action.synchronize(s);
+ _rails.synchronize(s);
+ _userInterface.synchronize(s);
+ s.syncAsByte(_reloadSceneFlag);
+ s.syncAsByte(_roomChanged);
+ s.syncAsUint16LE(_nextSceneId);
+ s.syncAsUint16LE(_priorSceneId);
+ _dynamicHotspots.synchronize(s);
+}
+
+} // End of namespace MADS
diff --git a/engines/mads/scene.h b/engines/mads/scene.h
new file mode 100644
index 0000000000..7a01d7360a
--- /dev/null
+++ b/engines/mads/scene.h
@@ -0,0 +1,251 @@
+/* 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.
+ *
+ */
+
+#ifndef MADS_SCENE_H
+#define MADS_SCENE_H
+
+#include "common/scummsys.h"
+#include "common/array.h"
+#include "common/rect.h"
+#include "mads/assets.h"
+#include "mads/screen.h"
+#include "mads/hotspots.h"
+#include "mads/messages.h"
+#include "mads/msurface.h"
+#include "mads/scene_data.h"
+#include "mads/animation.h"
+#include "mads/rails.h"
+#include "mads/sequence.h"
+#include "mads/sprites.h"
+#include "mads/user_interface.h"
+
+namespace MADS {
+
+class Scene {
+private:
+ /**
+ * Return the index of a given Vocab in the active vocab list
+ */
+ int activeVocabIndexOf(int vocabId);
+
+ /**
+ * Secondary loading vocab list
+ */
+ void loadVocabStrings();
+
+ /*
+ * Initialises the data for palette animation within the scene
+ */
+ void initPaletteAnimation(Common::Array<PaletteCycle> &palCycles, bool animFlag);
+
+ /**
+ * Handles a single frame within the game scene
+ */
+ void doFrame();
+
+ void doPreactions();
+
+ void doAction();
+
+ /**
+ * Calls all the necessary step handlers for the current frame
+ */
+ void doSceneStep();
+
+ /**
+ * Checks whether there's a pending keypress, and if so handles it.
+ */
+ void checkKeyboard();
+
+ /**
+ * Checks for a highlighted hotspot, and updates the cursor accordingly
+ */
+ void updateCursor();
+protected:
+ MADSEngine *_vm;
+public:
+ SceneLogic *_sceneLogic;
+ MSurface _sceneSurface;
+ int _priorSceneId;
+ int _nextSceneId;
+ int _currentSceneId;
+ Common::Array<VerbInit> _verbList;
+ TextDisplayList _textDisplay;
+ SpriteSlots _spriteSlots;
+ SpriteSets _sprites;
+ DynamicHotspots _dynamicHotspots;
+ Common::Array<int> _activeVocabs;
+ SequenceList _sequences;
+ KernelMessages _kernelMessages;
+ Rails _rails;
+ Common::String _talkFont;
+ int _textSpacing;
+ Hotspots _hotspots;
+ DirtyAreas _dirtyAreas;
+ int _variant;
+ SceneInfo *_sceneInfo;
+ MSurface _backgroundSurface;
+ DepthSurface _depthSurface;
+ UserInterface _userInterface;
+ bool _cyclingActive;
+ int _cyclingThreshold;
+ int _cyclingDelay;
+ int _totalCycleColors;
+ Common::Array<uint32> _cycleTicks;
+ Common::Array<PaletteCycle> _paletteCycles;
+ Common::StringArray _vocabStrings;
+ Animation *_animationData;
+ Animation *_activeAnimation;
+ bool _freeAnimationFlag;
+ int _depthStyle;
+ int _bandsRange;
+ int _scaleRange;
+ int _interfaceY;
+ int _spritesCount;
+ MADSAction _action;
+ bool _roomChanged;
+ bool _reloadSceneFlag;
+ Common::Point _posAdjust;
+ uint32 _frameStartTime;
+ Layer _layer;
+ bool _lookFlag;
+ Common::Point _customDest;
+ Common::Array<PaletteUsage::UsageEntry> _paletteUsageF;
+ Common::Array<PaletteUsage::UsageEntry> _scenePaletteUsage;
+
+ /**
+ * Constructor
+ */
+ Scene(MADSEngine *vm);
+
+ /**
+ * Destructor
+ */
+ ~Scene();
+
+ /**
+ * Clear the vocabulary list
+ */
+ void clearVocab();
+
+ /**
+ * Add a given vocab entry to the active list
+ */
+ void addActiveVocab(int vocabId);
+
+ /**
+ * Get the number of entries in the game's vocabulary
+ */
+ uint32 getVocabStringsCount() const;
+
+ /**
+ * Clear the sequence list
+ */
+ void clearSequenceList();
+
+ /**
+ * Clear the message list
+ */
+ void clearMessageList();
+
+ /**
+ * Loads the scene logic for a given scene
+ */
+ void loadSceneLogic();
+
+ /**
+ * Loads the resources associated with the given scene
+ * @param sceneId Scene to load
+ * @param prefix Prefix to use for retrieving animation data
+ * @param palFlag Flag for whether to reset the high/lo palette areas
+ */
+ void loadScene(int sceneId, const Common::String &prefix, bool palFlag);
+
+ /**
+ * Loads the hotstpots for the scene
+ */
+ void loadHotspots();
+
+ /**
+ * Loads the vocab list
+ */
+ void loadVocab();
+
+ bool getDepthHighBits(const Common::Point &pt);
+
+ /**
+ * Main scene loop
+ */
+ void loop();
+
+ /**
+ * Draw all the elements onto the scene
+ */
+ void drawElements(ScreenTransition transitionType, bool surfaceFlag);
+
+ /**
+ * Handles cycling palette colors for the scene
+ */
+ void animatePalette();
+
+ /**
+ * Load an animation
+ */
+ void loadAnimation(const Common::String &resName, int trigger = 0);
+
+ /**
+ * Returns a vocab entry
+ */
+ Common::String getVocab(int vocabId) { return _vocabStrings[vocabId - 1]; }
+
+ /**
+ * Clear the data for the currently loaded scene
+ */
+ void freeCurrentScene();
+
+ /**
+ * Set the walk surface for a scene to a different variant
+ */
+ void changeVariant(int variant);
+
+ void resetScene();
+
+ /**
+ * Removes all the scene specific sprites fromt the sprites list,
+ * leaving any player sprites list in place at the start of the list.
+ */
+ void removeSprites();
+
+ /**
+ * Frees any currently active animation for the scene
+ */
+ void freeAnimation();
+
+ /**
+ * Synchronise the game
+ */
+ void synchronize(Common::Serializer &s);
+};
+
+} // End of namespace MADS
+
+#endif /* MADS_SCENE_H */
diff --git a/engines/mads/scene_data.cpp b/engines/mads/scene_data.cpp
new file mode 100644
index 0000000000..5656ac4069
--- /dev/null
+++ b/engines/mads/scene_data.cpp
@@ -0,0 +1,446 @@
+/* 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 "mads/scene_data.h"
+#include "mads/mads.h"
+#include "mads/compression.h"
+#include "mads/screen.h"
+#include "mads/resources.h"
+#include "mads/dragonsphere/dragonsphere_scenes.h"
+#include "mads/nebular/nebular_scenes.h"
+#include "mads/phantom/phantom_scenes.h"
+
+namespace MADS {
+
+KernelMessage::KernelMessage() {
+ _flags = 0;
+ _sequenceIndex = 0;
+ _color1 = 0;
+ _color2 = 0;
+ _msgOffset = 0;
+ _numTicks = 0;
+ _frameTimer2 = 0;
+ _frameTimer = 0;
+ _timeout = 0;
+ _trigger = 0;
+ _abortMode = SEQUENCE_TRIGGER_PARSER;
+ _actionDetails._verbId = VERB_NONE;
+ _actionDetails._objectNameId = 0;
+ _actionDetails._indirectObjectId = 0;
+}
+
+/*------------------------------------------------------------------------*/
+
+void ARTHeader::load(Common::SeekableReadStream *f, bool isV2) {
+ if (!isV2) {
+ // Read in dimensions of image
+ _width = f->readUint16LE();
+ _height = f->readUint16LE();
+ }
+
+ // Read in palette information
+ int palCount = f->readUint16LE();
+ for (int i = 0; i < palCount; ++i) {
+ RGB6 rgb;
+ rgb.load(f);
+ _palette.push_back(rgb);
+ }
+ f->skip(6 * (256 - palCount));
+
+ // Read palette animations
+ int cycleCount = f->readUint16LE();
+ for (int i = 0; i < cycleCount; ++i) {
+ PaletteCycle cycle;
+ cycle._colorCount = f->readByte();
+ cycle._firstListColor = f->readByte();
+ cycle._firstColorIndex = f->readByte();
+ cycle._ticks = f->readByte();
+
+ _paletteCycles.push_back(cycle);
+ }
+}
+
+/*------------------------------------------------------------------------*/
+
+void SceneInfo::SpriteInfo::load(Common::SeekableReadStream *f) {
+ f->skip(3);
+ _spriteSetIndex = f->readByte();
+ f->skip(2);
+ _position.x = f->readSint16LE();
+ _position.y = f->readSint16LE();
+ _depth = f->readByte();
+ _scale = f->readByte();
+}
+
+/*------------------------------------------------------------------------*/
+
+SceneInfo *SceneInfo::init(MADSEngine *vm) {
+ switch (vm->getGameID()) {
+ case GType_RexNebular:
+ return new Nebular::SceneInfoNebular(vm);
+ case GType_Dragonsphere:
+ return new Dragonsphere::SceneInfoDragonsphere(vm);
+ case GType_Phantom:
+ return new Phantom::SceneInfoPhantom(vm);
+ default:
+ error("SceneInfo: Unknown game");
+ }
+
+ return nullptr;
+}
+
+void SceneInfo::load(int sceneId, int variant, const Common::String &resName,
+ int flags, DepthSurface &depthSurface, MSurface &bgSurface) {
+ bool sceneFlag = sceneId >= 0;
+
+ // Figure out the resource to use
+ Common::String resourceName;
+ if (sceneFlag) {
+ resourceName = Resources::formatName(RESPREFIX_RM, sceneId, ".DAT");
+ } else {
+ resourceName = "*" + Resources::formatResource(resName, resName);
+ }
+
+ // Open the scene info resource for access
+ File infoFile(resourceName);
+ MadsPack infoPack(&infoFile);
+
+ // Read in basic data
+ Common::SeekableReadStream *infoStream = infoPack.getItemStream(0);
+ if (_vm->getGameID() == GType_RexNebular) {
+ _sceneId = infoStream->readUint16LE();
+ } else {
+ infoStream->skip(6); // actual scene ID (string)
+ _sceneId = sceneId;
+ }
+
+ // TODO: The following isn't quite right for V2 games (it's all 0)
+ _artFileNum = infoStream->readUint16LE();
+ _depthStyle = infoStream->readUint16LE();
+ _width = infoStream->readUint16LE();
+ _height = infoStream->readUint16LE();
+
+ // HACK for V2 games (for now)
+ if (_vm->getGameID() != GType_RexNebular) {
+ _width = 320;
+ _height = 156;
+ }
+
+ infoStream->skip(24);
+
+ int nodeCount = infoStream->readUint16LE();
+ _yBandsEnd = infoStream->readUint16LE();
+ _yBandsStart = infoStream->readUint16LE();
+ _maxScale = infoStream->readUint16LE();
+ _minScale = infoStream->readUint16LE();
+ for (int i = 0; i < DEPTH_BANDS_SIZE; ++i)
+ _depthList[i] = infoStream->readUint16LE();
+ _field4A = infoStream->readUint16LE();
+
+ // Load the set of objects that are associated with the scene
+ for (int i = 0; i < 20; ++i) {
+ WalkNode node;
+ node.load(infoStream);
+
+ if (i < nodeCount)
+ _nodes.push_back(node);
+ }
+
+ int spriteSetsCount = infoStream->readUint16LE();
+ int spriteInfoCount = infoStream->readUint16LE();
+
+ // Load in sprite sets
+ Common::StringArray setNames;
+ for (int i = 0; i < 10; ++i) {
+ char name[64];
+ infoStream->read(name, 64);
+
+ if (i < spriteSetsCount)
+ setNames.push_back(Common::String(name));
+ }
+
+ // Load in sprite draw information
+ Common::Array<SpriteInfo> spriteInfo;
+ // TODO: The following isn't quite right for V2 games
+ if (_vm->getGameID() == GType_RexNebular) {
+ for (int i = 0; i < 50; ++i) {
+ SpriteInfo info;
+ info.load(infoStream);
+
+ if (i < spriteInfoCount)
+ spriteInfo.push_back(info);
+ }
+ }
+ delete infoStream;
+
+ int width = _width;
+ int height = _height;
+
+ if (!bgSurface.getPixels()) {
+ bgSurface.setSize(width, height);
+ }
+
+ if (_depthStyle == 2)
+ width >>= 2;
+ if (!depthSurface.getPixels()) {
+ depthSurface.setSize(width, height);
+ }
+
+ if (_vm->getGameID() == GType_RexNebular) {
+ // Load the depth surface with the scene codes
+ Common::SeekableReadStream *depthStream = infoPack.getItemStream(variant + 1);
+ loadCodes(depthSurface, depthStream);
+ delete depthStream;
+ }
+
+ infoFile.close();
+
+ if (_vm->getGameID() == GType_RexNebular) {
+ loadMadsV1Background(sceneId, resName, flags, bgSurface);
+ loadPalette(sceneId, _artFileNum, resName, flags, bgSurface);
+ } else {
+ loadMadsV2Background(sceneId, resName, flags, bgSurface);
+ loadPalette(sceneId, sceneId, resName, flags, bgSurface);
+ }
+
+ Common::Array<SpriteAsset *> spriteSets;
+ Common::Array<int> usageList;
+
+ // TODO: The following isn't quite right for V2 games
+ if (_vm->getGameID() == GType_RexNebular) {
+ for (uint i = 0; i < setNames.size(); ++i) {
+ Common::String setResName;
+ if (sceneFlag || resName.hasPrefix("*"))
+ setResName += "*";
+ setResName += setNames[i];
+
+ SpriteAsset *sprites = new SpriteAsset(_vm, setResName, flags);
+ spriteSets.push_back(sprites);
+ usageList.push_back(sprites->_usageIndex);
+ }
+ }
+
+ _vm->_palette->_paletteUsage.updateUsage(usageList, _usageIndex);
+
+ for (uint i = 0; i < spriteInfo.size(); ++i) {
+ SpriteInfo &si = spriteInfo[i];
+ SpriteAsset *asset = spriteSets[si._spriteSetIndex];
+ assert(asset && _depthStyle != 2);
+
+ MSprite *spr = asset->getFrame(asset->getCount() - 1);
+ bgSurface.copyFrom(spr, si._position, si._depth, &depthSurface, si._scale,
+ spr->getTransparencyIndex());
+ }
+
+ // Free the sprite sets
+ for (int i = (int)spriteSets.size() - 1; i >= 0; --i) {
+ warning("TODO: sub_201C8 SPRITE_SET.field_6");
+ delete spriteSets[i];
+ }
+}
+
+void SceneInfo::loadPalette(int sceneId, int artFileNum, const Common::String &resName, int flags, MSurface &bgSurface) {
+ bool sceneFlag = sceneId >= 0;
+ Common::String resourceName;
+ bool isV2 = (_vm->getGameID() != GType_RexNebular);
+ Common::String extension = !isV2 ? ".ART" : ".TT";
+ int paletteStream = !isV2 ? 0 : 2;
+
+ // Get the ART resource
+ if (sceneFlag) {
+ resourceName = Resources::formatName(RESPREFIX_RM, artFileNum, extension);
+ } else {
+ resourceName = "*" + Resources::formatResource(resName, resName);
+ }
+
+ // Load in the ART header and palette
+ File artFile(resourceName);
+ MadsPack artResource(&artFile);
+ Common::SeekableReadStream *stream = artResource.getItemStream(paletteStream);
+
+ ARTHeader artHeader;
+ artHeader.load(stream, isV2);
+ delete stream;
+
+ // Copy out the palette animation data
+ for (uint i = 0; i < artHeader._paletteCycles.size(); ++i)
+ _paletteCycles.push_back(artHeader._paletteCycles[i]);
+
+ if (!(flags & 1)) {
+ if (!_vm->_palette->_paletteUsage.empty()) {
+ _vm->_palette->_paletteUsage.getKeyEntries(artHeader._palette);
+ _vm->_palette->_paletteUsage.prioritize(artHeader._palette);
+ }
+
+ _usageIndex = _vm->_palette->_paletteUsage.process(artHeader._palette,
+ (flags & 0xF800) | 0x8000);
+ if (_usageIndex > 0) {
+ _vm->_palette->_paletteUsage.transform(artHeader._palette);
+
+ for (uint i = 0; i < _paletteCycles.size(); ++i) {
+ byte listColor = _paletteCycles[i]._firstListColor;
+ _paletteCycles[i]._firstColorIndex = artHeader._palette[listColor]._palIndex;
+ }
+ }
+ }
+
+ if (!(flags & 1)) {
+ // Translate the background to use the correct palette indexes
+ bgSurface.translate(artHeader._palette);
+ }
+}
+
+void SceneInfo::loadMadsV1Background(int sceneId, const Common::String &resName, int flags, MSurface &bgSurface) {
+ bool sceneFlag = sceneId >= 0;
+ Common::String resourceName;
+ Common::SeekableReadStream *stream;
+
+ // Get the ART resource
+ if (sceneFlag) {
+ resourceName = Resources::formatName(RESPREFIX_RM, _artFileNum, ".ART");
+ } else {
+ resourceName = "*" + Resources::formatResource(resName, resName);
+ }
+
+ // Load in the ART data
+ File artFile(resourceName);
+ MadsPack artResource(&artFile);
+
+ // Read in the background surface data
+ assert(_width == bgSurface.w && _height == bgSurface.h);
+ stream = artResource.getItemStream(1);
+ stream->read(bgSurface.getPixels(), bgSurface.w * bgSurface.h);
+
+ // Close the ART file
+ delete stream;
+ artFile.close();
+}
+
+void SceneInfo::loadMadsV2Background(int sceneId, const Common::String &resName, int flags, MSurface &bgSurface) {
+ Common::String tileMapResourceName = Resources::formatName(RESPREFIX_RM, sceneId, ".MM");
+ File tileMapFile(tileMapResourceName);
+ MadsPack tileMapPack(&tileMapFile);
+ Common::SeekableReadStream *mapStream = tileMapPack.getItemStream(0);
+
+ // Get the details of the tiles and map
+ mapStream->readUint32LE();
+ int tileCountX = mapStream->readUint16LE();
+ int tileCountY = mapStream->readUint16LE();
+ int tileWidthMap = mapStream->readUint16LE();
+ int tileHeightMap = mapStream->readUint16LE();
+ int screenWidth = mapStream->readUint16LE();
+ int screenHeight = mapStream->readUint16LE();
+ int tileCountMap = tileCountX * tileCountY;
+ delete mapStream;
+
+ // Obtain tile map information
+ typedef Common::List<Common::SharedPtr<MSurface> > TileSetList;
+ typedef TileSetList::iterator TileSetIterator;
+ TileSetList tileSet;
+ uint16 *tileMap = new uint16[tileCountMap];
+ mapStream = tileMapPack.getItemStream(1);
+ for (int i = 0; i < tileCountMap; ++i)
+ tileMap[i] = mapStream->readUint16LE();
+ delete mapStream;
+ tileMapFile.close();
+
+ // --------------------------------------------------------------------------------
+
+ // Tile data, which needs to be kept compressed, as the tile map offsets refer to
+ // the compressed data. Each tile is then uncompressed separately
+ Common::String tileDataResourceName = Resources::formatName(RESPREFIX_RM, sceneId, ".TT");
+ File tileDataFile(tileDataResourceName);
+ MadsPack tileDataPack(&tileDataFile);
+ Common::SeekableReadStream *tileDataUncomp = tileDataPack.getItemStream(0);
+
+ // Validate that the data matches between the tiles and tile map file and is valid
+ int tileCount = tileDataUncomp->readUint16LE();
+ int tileWidth = tileDataUncomp->readUint16LE();
+ int tileHeight = tileDataUncomp->readUint16LE();
+ delete tileDataUncomp;
+ assert(tileCountMap == tileCount);
+ assert(tileWidth == tileWidthMap);
+ assert(tileHeight == tileHeightMap);
+ assert(screenWidth == _width);
+ assert(screenHeight <= _height);
+
+ // --------------------------------------------------------------------------------
+
+ // Get tile data
+
+ tileDataUncomp = tileDataPack.getItemStream(1);
+ FabDecompressor fab;
+ uint32 compressedTileDataSize = 0;
+
+ for (int i = 0; i < tileCount; i++) {
+ tileDataUncomp->seek(i * 4, SEEK_SET);
+ uint32 tileOfs = tileDataUncomp->readUint32LE();
+ MSurface* newTile = new MSurface(tileWidth, tileHeight);
+
+ if (i == tileCount - 1)
+ compressedTileDataSize = tileDataFile.size() - tileOfs;
+ else
+ compressedTileDataSize = tileDataUncomp->readUint32LE() - tileOfs;
+
+ //debugCN(kDebugGraphics, "Tile: %i, compressed size: %i\n", i, compressedTileDataSize);
+
+ newTile->empty();
+
+ byte *compressedTileData = new byte[compressedTileDataSize];
+
+ tileDataFile.seek(tileDataPack.getDataOffset() + tileOfs, SEEK_SET);
+ tileDataFile.read(compressedTileData, compressedTileDataSize);
+
+ fab.decompress(compressedTileData, compressedTileDataSize, (byte*)newTile->getPixels(), tileWidth * tileHeight);
+ tileSet.push_back(TileSetList::value_type(newTile));
+ delete[] compressedTileData;
+ }
+
+ delete tileDataUncomp;
+
+ // --------------------------------------------------------------------------------
+
+ // Loop through the mapping data to place the tiles on the screen
+
+ uint16 *tIndex = &tileMap[0];
+ for (int y = 0; y < tileCountY; y++) {
+ for (int x = 0; x < tileCountX; x++) {
+ int tileIndex = *tIndex++;
+ assert(tileIndex < tileCount);
+ TileSetIterator tile = tileSet.begin();
+ for (int i = 0; i < tileIndex; i++)
+ ++tile;
+ ((*tile).get())->copyTo(&bgSurface, Common::Point(x * tileWidth, y * tileHeight));
+ }
+ }
+ tileSet.clear();
+ tileDataFile.close();
+}
+
+/*------------------------------------------------------------------------*/
+
+SceneLogic::SceneLogic(MADSEngine *vm) : _vm(vm) {
+ _scene = &_vm->_game->_scene;
+}
+
+} // End of namespace MADS
diff --git a/engines/mads/scene_data.h b/engines/mads/scene_data.h
new file mode 100644
index 0000000000..392383af2f
--- /dev/null
+++ b/engines/mads/scene_data.h
@@ -0,0 +1,223 @@
+/* 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.
+ *
+ */
+
+#ifndef MADS_SCENE_DATA_H
+#define MADS_SCENE_DATA_H
+
+#include "common/scummsys.h"
+#include "common/array.h"
+#include "common/serializer.h"
+#include "common/str.h"
+#include "common/str-array.h"
+#include "common/rect.h"
+#include "mads/action.h"
+#include "mads/assets.h"
+#include "mads/events.h"
+#include "mads/game_data.h"
+#include "mads/hotspots.h"
+#include "mads/messages.h"
+#include "mads/rails.h"
+#include "mads/user_interface.h"
+
+namespace MADS {
+
+class MADSEngine;
+class Scene;
+class SpriteSlot;
+
+#define MADS_INTERFACE_HEIGHT 44
+#define MADS_SCENE_HEIGHT 156
+
+#define DEPTH_BANDS_SIZE 15
+
+#define SPRITE_SLOTS_MAX_SIZE 50
+#define TEXT_DISPLAY_MAX_SIZE 40
+#define DIRTY_AREAS_SIZE (SPRITE_SLOTS_MAX_SIZE + TEXT_DISPLAY_MAX_SIZE)
+
+enum {
+ SCENEFLAG_DITHER = 0x01, // Dither to 16 colors
+ SCENEFLAG_LOAD_SHADOW = 0x10 // Load hard shadows
+};
+
+class VerbInit {
+public:
+ int _id;
+ VerbType _verbType;
+ PrepType _prepType;
+
+ VerbInit() {}
+ VerbInit(int id, VerbType verbType, PrepType prepType): _id(id),
+ _verbType(verbType), _prepType(prepType) {}
+};
+
+class SceneLogic {
+protected:
+ MADSEngine *_vm;
+ Scene *_scene;
+public:
+ /**
+ * Constructor
+ */
+ SceneLogic(MADSEngine *vm);
+
+ /**
+ * Destructor
+ */
+ virtual ~SceneLogic() {}
+
+ /**
+ * Called to initially setup a scene
+ */
+ virtual void setup() = 0;
+
+ /**
+ * Called as the scene is entered (made active)
+ */
+ virtual void enter() = 0;
+
+ /**
+ * Called one per frame
+ */
+ virtual void step() {}
+
+ /**
+ * Called before an action is started
+ */
+ virtual void preActions() {}
+
+ /**
+ * Handles scene actions
+ */
+ virtual void actions() = 0;
+
+ /**
+ * Post-action handling
+ */
+ virtual void postActions() {}
+
+ /**
+ * Unhandled action handling
+ */
+ virtual void unhandledAction() {}
+
+ /**
+ * Synchronize any local data for the scene
+ */
+ virtual void synchronize(Common::Serializer &s) {}
+};
+
+struct ARTHeader {
+ int _width;
+ int _height;
+ Common::Array<RGB6> _palette;
+ Common::Array<PaletteCycle> _paletteCycles;
+
+ void load(Common::SeekableReadStream *f, bool isV2);
+};
+
+/**
+ * Handles general data for a given scene
+ */
+class SceneInfo {
+ class SpriteInfo {
+ public:
+ int _spriteSetIndex;
+ Common::Point _position;
+ int _depth;
+ int _scale;
+
+ void load(Common::SeekableReadStream *f);
+ };
+protected:
+ MADSEngine *_vm;
+
+ /**
+ * Constructor
+ */
+ SceneInfo(MADSEngine *vm) : _vm(vm) {}
+public:
+ int _sceneId;
+ int _artFileNum;
+ int _depthStyle;
+ int _width;
+ int _height;
+
+ int _yBandsEnd;
+ int _yBandsStart;
+ int _maxScale;
+ int _minScale;
+ int _depthList[DEPTH_BANDS_SIZE];
+ int _field4A;
+
+ int _usageIndex;
+ Common::Array<PaletteCycle> _paletteCycles;
+ WalkNodeList _nodes;
+public:
+ /**
+ * Destructor
+ */
+ virtual ~SceneInfo() {}
+
+ /**
+ * Instantiates the class
+ */
+ static SceneInfo *init(MADSEngine *vm);
+
+ /**
+ * loads the data
+ */
+ void load(int sceneId, int variant, const Common::String &resName, int flags,
+ DepthSurface &depthSurface, MSurface &bgSurface);
+
+ /**
+ * Loads the palette for a scene
+ */
+ void loadPalette(int sceneId, int artFileNum, const Common::String &resName, int flags, MSurface &bgSurface);
+
+ /**
+ * Loads a V1 game background
+ */
+ void loadMadsV1Background(int sceneId, const Common::String &resName, int flags, MSurface &bgSurface);
+
+ /**
+ * Loads a V2 game background
+ */
+ void loadMadsV2Background(int sceneId, const Common::String &resName, int flags, MSurface &bgSurface);
+
+ /**
+ * Loads the given surface with depth information of a given scene
+ * @param depthSurface Depth/walk surface
+ * @param variant Variant number to load
+ */
+ virtual void loadCodes(MSurface &depthSurface, int variant) = 0;
+
+ /**
+ * Loads the given surface with depth information of a given scene
+ * @param depthSurface Depth/walk surface
+ * @param stream Stream to load the data from
+ */
+ virtual void loadCodes(MSurface &depthSurface, Common::SeekableReadStream *stream) = 0;
+};
+
+} // End of namespace MADS
+
+#endif /* MADS_SCENE_DATA_H */
diff --git a/engines/mads/screen.cpp b/engines/mads/screen.cpp
new file mode 100644
index 0000000000..dacd20a348
--- /dev/null
+++ b/engines/mads/screen.cpp
@@ -0,0 +1,641 @@
+/* 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 "mads/mads.h"
+#include "mads/game.h"
+#include "mads/screen.h"
+#include "mads/palette.h"
+#include "mads/user_interface.h"
+
+namespace MADS {
+
+MADSEngine *DirtyArea::_vm = nullptr;
+
+DirtyArea::DirtyArea() {
+ _active = false;
+ _textActive = false;
+ _mergedArea = nullptr;
+}
+
+void DirtyArea::setArea(int width, int height, int maxWidth, int maxHeight) {
+ if (_bounds.left % 2) {
+ --_bounds.left;
+ ++width;
+ }
+
+ if (_bounds.left < 0)
+ _bounds.left = 0;
+ else if (_bounds.left > maxWidth)
+ _bounds.left = maxWidth;
+ int right = _bounds.left + width;
+ if (right < 0)
+ right = 0;
+ if (right > maxWidth)
+ right = maxWidth;
+
+ _bounds.right = right;
+
+ if (_bounds.top < 0)
+ _bounds.top = 0;
+ else if (_bounds.top > maxHeight)
+ _bounds.top = maxHeight;
+ int bottom = _bounds.top + height;
+ if (bottom < 0)
+ bottom = 0;
+ if (bottom > maxHeight)
+ bottom = maxHeight;
+
+ _bounds.bottom = bottom;
+ _active = true;
+}
+
+
+void DirtyArea::setSpriteSlot(const SpriteSlot *spriteSlot) {
+ int width, height;
+ Scene &scene = _vm->_game->_scene;
+
+ if (spriteSlot->_flags == IMG_REFRESH) {
+ // Special entry to refresh the entire screen
+ _bounds.left = 0;
+ _bounds.top = 0;
+ width = MADS_SCREEN_WIDTH;
+ height = MADS_SCENE_HEIGHT;
+ } else {
+ // Standard sprite slots
+ _bounds.left = spriteSlot->_position.x - scene._posAdjust.x;
+ _bounds.top = spriteSlot->_position.y - scene._posAdjust.y;
+
+ SpriteAsset &spriteSet = *scene._sprites[spriteSlot->_spritesIndex];
+ MSprite *frame = spriteSet.getFrame(ABS(spriteSlot->_frameNumber) - 1);
+
+ if (spriteSlot->_scale == -1) {
+ width = frame->w;
+ height = frame->h;
+ } else {
+ width = frame->w * spriteSlot->_scale / 100;
+ height = frame->h * spriteSlot->_scale / 100;
+
+ _bounds.left -= width / 2;
+ _bounds.top += -(height - 1);
+ }
+ }
+
+ setArea(width, height, MADS_SCREEN_WIDTH, MADS_SCENE_HEIGHT);
+}
+
+void DirtyArea::setTextDisplay(const TextDisplay *textDisplay) {
+ _bounds.left = textDisplay->_bounds.left;
+ _bounds.top = textDisplay->_bounds.top;
+
+ setArea(textDisplay->_bounds.width(), textDisplay->_bounds.height(),
+ MADS_SCREEN_WIDTH, MADS_SCENE_HEIGHT);
+}
+
+void DirtyArea::setUISlot(const UISlot *slot) {
+ int type = slot->_flags;
+ if (type <= IMG_UPDATE_ONLY)
+ type += -IMG_UPDATE_ONLY;
+ if (type >= 0x40)
+ type &= ~0x40;
+
+ MSurface &intSurface = _vm->_game->_scene._userInterface;
+ switch (type) {
+ case IMG_REFRESH:
+ _bounds.left = 0;
+ _bounds.top = 0;
+ setArea(intSurface.w, intSurface.h, intSurface.w, intSurface.h);
+ break;
+
+ case IMG_OVERPRINT:
+ _bounds.left = slot->_position.x;
+ _bounds.top = slot->_position.y;
+ _bounds.setWidth(slot->_width);
+ _bounds.setHeight(slot->_height);
+ setArea(slot->_width, slot->_height, intSurface.w, intSurface.h);
+ break;
+
+ default: {
+ SpriteAsset *asset = _vm->_game->_scene._sprites[slot->_spritesIndex];
+ MSprite *frame = asset->getFrame(slot->_frameNumber - 1);
+ int w = frame->w;
+ int h = frame->h;
+
+ if (slot->_segmentId == IMG_SPINNING_OBJECT) {
+ _bounds.left = slot->_position.x;
+ _bounds.top = slot->_position.y;
+ } else {
+ _bounds.left = slot->_position.x + w / 2;
+ _bounds.top = slot->_position.y - h + 1;
+ }
+
+ setArea(w, h, intSurface.w, intSurface.h);
+ break;
+ }
+ }
+}
+
+/*------------------------------------------------------------------------*/
+
+DirtyAreas::DirtyAreas(MADSEngine *vm) : _vm(vm) {
+ DirtyArea::_vm = vm;
+
+ for (int i = 0; i < DIRTY_AREAS_SIZE; ++i) {
+ DirtyArea rec;
+ rec._active = false;
+ push_back(rec);
+ }
+}
+
+void DirtyAreas::merge(int startIndex, int count) {
+ if (startIndex >= count)
+ return;
+
+ for (int outerCtr = startIndex - 1, idx = 0; idx < count; ++outerCtr, ++idx) {
+ if (!(*this)[outerCtr]._active)
+ continue;
+
+ for (int innerCtr = outerCtr + 1; innerCtr < count; ++innerCtr) {
+ if (!(*this)[innerCtr]._active || !intersects(outerCtr, innerCtr))
+ continue;
+
+ if ((*this)[outerCtr]._textActive && (*this)[innerCtr]._textActive)
+ mergeAreas(innerCtr, outerCtr);
+ }
+ }
+}
+
+/**
+* Returns true if two dirty areas intersect
+*/
+bool DirtyAreas::intersects(int idx1, int idx2) {
+ return (*this)[idx1]._bounds.intersects((*this)[idx2]._bounds);
+}
+
+void DirtyAreas::mergeAreas(int idx1, int idx2) {
+ DirtyArea &da1 = (*this)[idx1];
+ DirtyArea &da2 = (*this)[idx2];
+
+ da1._bounds.extend(da2._bounds);
+
+ da2._active = false;
+ da2._mergedArea = &da1;
+ da1._textActive = true;
+}
+
+void DirtyAreas::copy(MSurface *srcSurface, MSurface *destSurface, const Common::Point &posAdjust) {
+ for (uint i = 0; i < size(); ++i) {
+ const Common::Rect &srcBounds = (*this)[i]._bounds;
+
+ // Check if this is a sane rectangle before attempting to create it
+ if (srcBounds.left >= srcBounds.right || srcBounds.top >= srcBounds.bottom)
+ continue;
+
+ Common::Rect bounds(srcBounds.left + posAdjust.x, srcBounds.top + posAdjust.y,
+ srcBounds.right + posAdjust.x, srcBounds.bottom + posAdjust.y);
+
+ if ((*this)[i]._active && bounds.isValidRect()) {
+ srcSurface->copyTo(destSurface, bounds, Common::Point(bounds.left, bounds.top));
+ }
+ }
+}
+
+void DirtyAreas::copyToScreen(const Common::Point &posAdjust) {
+ for (uint i = 0; i < size(); ++i) {
+ const Common::Rect &srcBounds = (*this)[i]._bounds;
+
+ // Check if this is a sane rectangle before attempting to create it
+ if (srcBounds.left >= srcBounds.right || srcBounds.top >= srcBounds.bottom)
+ continue;
+
+ Common::Rect bounds(srcBounds.left + posAdjust.x, srcBounds.top + posAdjust.y,
+ srcBounds.right + posAdjust.x, srcBounds.bottom + posAdjust.y);
+
+ if ((*this)[i]._active && (*this)[i]._bounds.isValidRect()) {
+ _vm->_screen.copyRectToScreen(bounds);
+ }
+ }
+}
+
+void DirtyAreas::reset() {
+ for (uint i = 0; i < size(); ++i)
+ (*this)[i]._active = false;
+}
+
+/*------------------------------------------------------------------------*/
+
+ScreenObject::ScreenObject() {
+ _category = CAT_NONE;
+ _descId = 0;
+ _layer = 0;
+}
+
+/*------------------------------------------------------------------------*/
+
+ScreenObjects::ScreenObjects(MADSEngine *vm) : _vm(vm) {
+ _objectY = -1;
+ _forceRescan = false;
+ _inputMode = kInputBuildingSentences;
+ _v7FED6 = 0;
+ _v8332A = 0;
+ _category = CAT_NONE;
+ _spotId = 0;
+ _released = false;
+ _uiCount = 0;
+ _selectedObject = -1;
+ _eventFlag = false;
+ _baseTime = 0;
+}
+
+void ScreenObjects::add(const Common::Rect &bounds, Layer layer, ScrCategory category, int descId) {
+ //assert(size() < 100);
+
+ ScreenObject so;
+ so._bounds = bounds;
+ so._category = category;
+ so._descId = descId;
+ so._layer = layer;
+ so._active = true;
+
+ push_back(so);
+}
+
+void ScreenObjects::check(bool scanFlag) {
+ Scene &scene = _vm->_game->_scene;
+ UserInterface &userInterface = scene._userInterface;
+
+ if (!_vm->_events->_mouseButtons || _inputMode != kInputBuildingSentences)
+ _vm->_events->_rightMousePressed = false;
+
+ if ((_vm->_events->_mouseMoved || userInterface._scrollbarActive
+ || _v8332A || _forceRescan) && scanFlag) {
+ _category = CAT_NONE;
+ _selectedObject = scanBackwards(_vm->_events->currentPos(), LAYER_GUI);
+ if (_selectedObject > 0) {
+ ScreenObject &scrObject = (*this)[_selectedObject];
+ _category = (ScrCategory)(scrObject._category & 7);
+ _spotId = scrObject._descId;
+ }
+
+ // Handling for easy mouse
+ ScrCategory category = scene._userInterface._category;
+ if (_vm->_easyMouse && _vm->_events->_mouseButtons && category != _category
+ && scene._userInterface._category != CAT_NONE) {
+ _released = true;
+ if (category >= CAT_COMMAND && category <= CAT_TALK_ENTRY) {
+ elementHighlighted();
+ }
+
+ scene._action.checkActionAtMousePos();
+ }
+
+ //_released = _vm->_events->_mouseReleased;
+ if (_vm->_events->_vD2 || (_vm->_easyMouse && !_vm->_events->_mouseStatusCopy))
+ scene._userInterface._category = _category;
+
+ if (!_vm->_events->_mouseButtons || _vm->_easyMouse) {
+ if (userInterface._category >= CAT_COMMAND && userInterface._category <= CAT_TALK_ENTRY) {
+ elementHighlighted();
+ }
+ }
+
+ if (_vm->_events->_mouseButtons || (_vm->_easyMouse && scene._action._interAwaiting > AWAITING_COMMAND
+ && scene._userInterface._category == CAT_INV_LIST) ||
+ (_vm->_easyMouse && scene._userInterface._category == CAT_HOTSPOT)) {
+ scene._action.checkActionAtMousePos();
+ }
+
+ if (_vm->_events->_mouseReleased) {
+ scene._action.leftClick();
+ scene._userInterface._category = CAT_NONE;
+ }
+
+ if (_vm->_events->_mouseButtons || _vm->_easyMouse || userInterface._scrollbarActive)
+ scene._userInterface.updateInventoryScroller();
+
+ if (_vm->_events->_mouseButtons || _vm->_easyMouse)
+ scene._action.set();
+
+ _forceRescan = false;
+ }
+
+ scene._action.refresh();
+
+ uint32 currentTicks = _vm->_events->getFrameCounter();
+ if (currentTicks >= _baseTime) {
+ // Check the user interface slots to see if there's any slots that need to be expired
+ UISlots &uiSlots = userInterface._uiSlots;
+ for (uint idx = 0; idx < uiSlots.size(); ++idx) {
+ UISlot &slot = uiSlots[idx];
+
+ if (slot._flags != IMG_REFRESH && slot._flags > IMG_UPDATE_ONLY
+ && slot._segmentId != IMG_SPINNING_OBJECT)
+ slot._flags = IMG_ERASE;
+ }
+
+ // Any background animation in the user interface
+ userInterface.doBackgroundAnimation();
+
+ // Handle animating the selected inventory item
+ userInterface.inventoryAnim();
+
+ // Set the base time
+ _baseTime = currentTicks + 6;
+ }
+}
+
+int ScreenObjects::scanBackwards(const Common::Point &pt, int layer) {
+ for (int i = (int)size(); i >= 1; --i) {
+ ScreenObject &sObj = (*this)[i];
+ if (sObj._active && sObj._bounds.contains(pt) && sObj._layer == layer)
+ return i;
+ }
+
+ // Entry not found
+ return 0;
+}
+
+void ScreenObjects::elementHighlighted() {
+ Scene &scene = _vm->_game->_scene;
+ UserInterface &userInterface = scene._userInterface;
+ Common::Array<int> &invList = _vm->_game->_objects._inventoryList;
+ MADSAction &action = scene._action;
+ int varA;
+ int topIndex;
+ int *idxP;
+ int var4;
+ int index;
+ int indexEnd = -1;
+ int var8 = 0;
+ int uiCount;
+
+ switch (userInterface._category) {
+ case CAT_COMMAND:
+ index = 10;
+ indexEnd = 9;
+ varA = 5;
+ topIndex = 0;
+ idxP = !_vm->_events->_rightMousePressed ? &userInterface._highlightedCommandIndex :
+ &userInterface._selectedActionIndex;
+
+ if (_vm->_events->_rightMousePressed && userInterface._selectedItemVocabIdx >= 0)
+ userInterface.updateSelection(CAT_INV_VOCAB, -1, &userInterface._selectedItemVocabIdx);
+
+ var4 = _released && !_vm->_events->_rightMousePressed ? 1 : 0;
+ break;
+
+ case CAT_INV_LIST:
+ userInterface.scrollInventory();
+
+ index = MIN((int)invList.size() - userInterface._inventoryTopIndex, 5);
+ indexEnd = invList.size() - 1;
+ varA = 0;
+ topIndex = userInterface._inventoryTopIndex;
+ idxP = &userInterface._highlightedInvIndex;
+ var4 = (!_released || (_vm->_events->_mouseButtons && action._interAwaiting == 1)) ? 0 : 1;
+ break;
+
+ case CAT_INV_VOCAB:
+ if (userInterface._selectedInvIndex >= 0) {
+ InventoryObject &invObject = _vm->_game->_objects.getItem(
+ userInterface._selectedInvIndex);
+ index = invObject._vocabCount;
+ indexEnd = index - 1;
+ } else {
+ index = 0;
+ }
+
+ varA = 0;
+ topIndex = 0;
+ idxP = _vm->_events->_rightMousePressed ? &userInterface._selectedItemVocabIdx : &userInterface._highlightedItemVocabIndex;
+
+ if (_vm->_events->_rightMousePressed && userInterface._selectedActionIndex >= 0)
+ userInterface.updateSelection(CAT_COMMAND, -1, &userInterface._selectedActionIndex);
+
+ var4 = _released && !_vm->_events->_rightMousePressed ? 1 : 0;
+ break;
+
+ case CAT_INV_ANIM:
+ index = 1;
+ indexEnd = invList.size() - 1;
+ varA = 0;
+ topIndex = userInterface._selectedInvIndex;
+ idxP = &var8;
+ var4 = -1;
+ break;
+
+ case CAT_TALK_ENTRY:
+ index = userInterface._talkStrings.size();
+ indexEnd = index - 1;
+ varA = 0;
+ topIndex = 0;
+ idxP = &userInterface._highlightedCommandIndex;
+ var4 = -1;
+ break;
+
+ default:
+ uiCount = size() - _uiCount;
+ index = uiCount + scene._hotspots.size();
+ indexEnd = index - 1;
+ varA = 0;
+ topIndex = 0;
+ idxP = &var8;
+ var4 = -1;
+ break;
+ }
+
+ int newIndex = -1;
+ int catIndex = userInterface._categoryIndexes[userInterface._category - 1];
+ int newX = 0, newY = 0;
+ Common::Point currentPos = _vm->_events->currentPos();
+
+ for (int idx = 0; idx < index && newIndex < 0; ++idx) {
+ int scrObjIndex = (_category == CAT_HOTSPOT) ? catIndex - idx + index - 1 :
+ catIndex + idx;
+
+ ScreenObject &scrObject = (*this)[scrObjIndex];
+ if (!scrObject._active)
+ continue;
+
+ const Common::Rect &bounds = scrObject._bounds;
+ newY = MAX((int)bounds.bottom, newY);
+ newX = MAX((int)bounds.left, newX);
+
+ if (currentPos.y >= bounds.top && currentPos.y < bounds.bottom) {
+ if (var4) {
+ if (currentPos.x >= bounds.left && currentPos.x < bounds.right) {
+ // Cursor is inside hotspot bounds
+ newIndex = scrObjIndex - catIndex;
+ if (_category == CAT_HOTSPOT && newIndex < (int)scene._hotspots.size())
+ newIndex = scene._hotspots.size() - newIndex - 1;
+ }
+ } else if (!varA) {
+ newIndex = idx;
+ } else if (varA <= idx) {
+ if (currentPos.x > bounds.left)
+ newIndex = idx;
+ } else {
+ if (currentPos.x < bounds.right)
+ newIndex = idx;
+ }
+ }
+ }
+
+ if (newIndex == -1 && index > 0 && !var4) {
+ if (_vm->_events->currentPos().y <= newY) {
+ newIndex = 0;
+ if (varA && _vm->_events->currentPos().x >= newX)
+ newIndex = varA;
+ } else {
+ newIndex = index - 1;
+ }
+ }
+
+ if (newIndex >= 0)
+ newIndex = MIN(newIndex + topIndex, indexEnd);
+
+ action._pickedWord = newIndex;
+
+ if (_category == CAT_INV_LIST || _category == CAT_INV_ANIM) {
+ if (action._interAwaiting == 1 && newIndex >= 0 && _released &&
+ (!_vm->_events->_mouseReleased || !_vm->_easyMouse))
+ newIndex = -1;
+ }
+
+ if (_released && !_vm->_events->_rightMousePressed &&
+ (_vm->_events->_mouseReleased || !_vm->_easyMouse))
+ newIndex = -1;
+
+ if (_category != CAT_HOTSPOT && _category != CAT_INV_ANIM)
+ userInterface.updateSelection(_category, newIndex, idxP);
+}
+
+void ScreenObjects::setActive(ScrCategory category, int descId, bool active) {
+ for (uint idx = 1; idx < size(); ++idx) {
+ ScreenObject &sObj = (*this)[idx];
+ if (sObj._category == category && sObj._descId == descId)
+ sObj._active = active;
+ }
+}
+
+void ScreenObjects::synchronize(Common::Serializer &s) {
+ s.syncAsSint16LE(_selectedObject);
+ s.syncAsSint16LE(_category);
+}
+
+/*------------------------------------------------------------------------*/
+
+ScreenSurface::ScreenSurface() {
+ _shakeCountdown = -1;
+ _random = 0x4D2;
+}
+
+void ScreenSurface::init() {
+ setSize(g_system->getWidth(), g_system->getHeight());
+}
+
+void ScreenSurface::copyRectToScreen(const Common::Point &destPos,
+ const Common::Rect &bounds) {
+ const byte *buf = getBasePtr(destPos.x, destPos.y);
+
+ if (bounds.width() != 0 && bounds.height() != 0)
+ g_system->copyRectToScreen(buf, this->pitch, bounds.left, bounds.top,
+ bounds.width(), bounds.height());
+}
+
+void ScreenSurface::copyRectToScreen(const Common::Rect &bounds) {
+ copyRectToScreen(Common::Point(bounds.left, bounds.top), bounds);
+}
+
+void ScreenSurface::updateScreen() {
+ if (_shakeCountdown >= 0) {
+ _random = _random * 5 + 1;
+ int offset = (_random >> 8) & 3;
+ if (_shakeCountdown-- <= 0)
+ offset = 0;
+
+ // Copy the screen with the left hand hide side of the screen of a given
+ // offset width shown at the very right. The offset changes to give
+ // an effect of shaking the screen
+ offset *= 4;
+ const byte *buf = getBasePtr(offset, 0);
+ g_system->copyRectToScreen(buf, this->pitch, 0, 0,
+ this->pitch - offset, this->h);
+ if (offset > 0)
+ g_system->copyRectToScreen(this->pixels, this->pitch,
+ this->pitch - offset, 0, offset, this->h);
+ }
+
+ g_system->updateScreen();
+}
+
+void ScreenSurface::transition(ScreenTransition transitionType, bool surfaceFlag) {
+ Palette &pal = *_vm->_palette;
+ byte palData[PALETTE_SIZE];
+
+ switch (transitionType) {
+ case kTransitionFadeIn:
+ case kTransitionFadeOutIn:
+ Common::fill(&pal._colorValues[0], &pal._colorValues[3], 0);
+ Common::fill(&pal._colorFlags[0], &pal._colorFlags[3], false);
+
+ if (transitionType == kTransitionFadeOutIn) {
+ // Fade out
+ pal.getFullPalette(palData);
+ pal.fadeOut(palData, nullptr, 0, PALETTE_COUNT, 0, 0, 1, 16);
+ }
+
+ // Reset palette to black
+ Common::fill(&palData[0], &palData[PALETTE_SIZE], 0);
+ pal.setFullPalette(palData);
+
+ copyRectToScreen(getBounds());
+ pal.fadeIn(palData, pal._mainPalette, 0, 256, 0, 1, 1, 16);
+ break;
+
+ case kTransitionBoxInBottomLeft:
+ case kTransitionBoxInBottomRight:
+ case kTransitionBoxInTopLeft:
+ case kTransitionBoxInTopRight:
+ error("TODO: transition");
+ break;
+
+ case kTransitionPanLeftToRight:
+ case kTransitionPanRightToLeft:
+ error("TODO: transition");
+
+ case kTransitionCircleIn1:
+ case kTransitionCircleIn2:
+ case kTransitionCircleIn3:
+ case kTransitionCircleIn4:
+ error("TODO circle transition");
+
+ case kCenterVertTransition:
+ error("TODO: center vert transition");
+
+ default:
+ // Quick transitions
+ break;
+ }
+}
+
+} // End of namespace MADS
diff --git a/engines/mads/screen.h b/engines/mads/screen.h
new file mode 100644
index 0000000000..b81fddd87a
--- /dev/null
+++ b/engines/mads/screen.h
@@ -0,0 +1,240 @@
+/* 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.
+ *
+ */
+
+#ifndef MADS_SCREEN_H
+#define MADS_SCREEN_H
+
+#include "common/scummsys.h"
+#include "common/array.h"
+#include "mads/msurface.h"
+#include "mads/action.h"
+
+namespace MADS {
+
+#define MADS_SCREEN_WIDTH 320
+#define MADS_SCREEN_HEIGHT 200
+
+enum Layer {
+ LAYER_GUI = 19
+};
+
+enum ScreenTransition {
+ kTransitionNone = 0,
+ kTransitionFadeIn, kTransitionFadeOutIn,
+ kTransitionBoxInBottomLeft, kTransitionBoxInBottomRight,
+ kTransitionBoxInTopLeft, kTransitionBoxInTopRight,
+ kTransitionPanLeftToRight, kTransitionPanRightToLeft,
+ kTransitionCircleIn1, kTransitionCircleIn2,
+ kTransitionCircleIn3, kTransitionCircleIn4,
+ kVertTransition1, kVertTransition2, kVertTransition3,
+ kVertTransition4, kVertTransition5, kVertTransition6,
+ kVertTransition7, kCenterVertTransition
+};
+
+enum InputMode {
+ kInputBuildingSentences = 0, // Normal sentence building
+ kInputConversation = 1, // Conversation mode
+ kInputLimitedSentences = 2 // Use only scene hotspots
+};
+
+class SpriteSlot;
+class TextDisplay;
+class UISlot;
+
+class DirtyArea {
+private:
+ static MADSEngine *_vm;
+ friend class DirtyAreas;
+public:
+ Common::Rect _bounds;
+ bool _textActive;
+ bool _active;
+ DirtyArea *_mergedArea;
+
+ DirtyArea();
+
+ void setArea(int width, int height, int maxWidth, int maxHeight);
+
+ /**
+ * Set up a dirty area for a sprite slot
+ */
+ void setSpriteSlot(const SpriteSlot *spriteSlot);
+
+ /**
+ * Set up a dirty area for a text display
+ */
+ void setTextDisplay(const TextDisplay *textDisplay);
+
+ /**
+ * Set up a dirty area for a UI slot
+ */
+ void setUISlot(const UISlot *slot);
+};
+
+class DirtyAreas : public Common::Array<DirtyArea> {
+private:
+ MADSEngine *_vm;
+public:
+ DirtyAreas(MADSEngine *vm);
+
+ /**
+ * Merge together any designated dirty areas that overlap
+ * @param startIndex 1-based starting dirty area starting index
+ * @param count Number of entries to process
+ */
+ void merge(int startIndex, int count);
+
+ bool intersects(int idx1, int idx2);
+ void mergeAreas(int idx1, int idx2);
+
+ /**
+ * Copy the data specified by the dirty rect list between surfaces
+ * @param srcSurface Source surface
+ * @param destSurface Dest surface
+ * @param posAdjust Position adjustment
+ */
+ void copy(MSurface *srcSurface, MSurface *destSurface, const Common::Point &posAdjust);
+
+ /**
+ * Use the lsit of dirty areas to copy areas of the screen surface to
+ * the physical screen
+ * @param posAdjust Position adjustment */
+ void copyToScreen(const Common::Point &posAdjust);
+
+ void reset();
+};
+
+
+class ScreenObject {
+public:
+ bool _active;
+ Common::Rect _bounds;
+ ScrCategory _category;
+ int _descId;
+ int _layer;
+
+ ScreenObject();
+};
+
+class ScreenObjects : public Common::Array<ScreenObject> {
+private:
+ MADSEngine *_vm;
+ int _objectY;
+
+ int scanBackwards(const Common::Point &pt, int layer);
+public:
+ InputMode _inputMode;
+ int _v7FED6;
+ int _v8332A;
+ int _forceRescan;
+ int _selectedObject;
+ ScrCategory _category;
+ bool _released;
+ int _uiCount;
+ bool _eventFlag;
+ uint32 _baseTime;
+ int _spotId;
+
+ /*
+ * Constructor
+ */
+ ScreenObjects(MADSEngine *vm);
+
+ /**
+ * Add a new item to the list
+ */
+ void add(const Common::Rect &bounds, Layer layer, ScrCategory category, int descId);
+
+ /**
+ */
+ void check(bool scanFlag);
+
+ /**
+ * Handle an element being highlighted on the screen, and make it active.
+ */
+ void elementHighlighted();
+
+ /**
+ * Retrieve a ScreenObject from the list
+ * @remarks This array is 1-based indexed by the game
+ */
+ ScreenObject &operator[](int idx) {
+ assert(idx > 0);
+ return Common::Array<ScreenObject>::operator[](idx - 1);
+ }
+
+ /**
+ * Sets an item identified by category and Desc Id as active or not
+ * @param category Screen category
+ * @param descId Description for item
+ * @param active Whether to set item as active or not
+ */
+ void setActive(ScrCategory category, int descId, bool active);
+
+ /**
+ * Synchronize the data
+ */
+ void synchronize(Common::Serializer &s);
+};
+
+class ScreenSurface : public MSurface {
+private:
+ uint16 _random;
+public:
+ Common::Point _offset;
+ int _shakeCountdown;
+public:
+ /**
+ * Constructor
+ */
+ ScreenSurface();
+
+ /**
+ * Initialise the surface
+ */
+ void init();
+
+ /**
+ * Copys an area of the screen surface to a given destination position on
+ * the ScummVM physical screen buffer
+ * @param destPos Destination position
+ * @param bounds Area of screen surface to copy
+ */
+ void copyRectToScreen(const Common::Point &destPos, const Common::Rect &bounds);
+
+ /**
+ * Copys an area of the screen surface to the ScmmVM physical screen buffer
+ * @param bounds Area of screen surface to copy
+ */
+ void copyRectToScreen(const Common::Rect &bounds);
+
+ /**
+ * Updates the screen with the contents of the surface
+ */
+ void updateScreen();
+
+ void transition(ScreenTransition transitionType, bool surfaceFlag);
+};
+
+} // End of namespace MADS
+
+#endif /* MADS_SCREEN_H */
diff --git a/engines/mads/sequence.cpp b/engines/mads/sequence.cpp
new file mode 100644
index 0000000000..6461102a5e
--- /dev/null
+++ b/engines/mads/sequence.cpp
@@ -0,0 +1,533 @@
+/* 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 "mads/mads.h"
+#include "mads/assets.h"
+#include "mads/sequence.h"
+#include "mads/scene.h"
+
+namespace MADS {
+
+SequenceEntry::SequenceEntry() {
+ _spritesIndex = 0;
+ _flipped = 0;
+ _frameIndex = 0;
+ _frameStart = 0;
+ _numSprites = 0;
+ _animType = ANIMTYPE_NONE;
+ _frameInc = 0;
+ _depth = 0;
+ _scale = 0;
+ _dynamicHotspotIndex = -1;
+ _triggerCountdown = 0;
+ _doneFlag = 0;
+ _triggerMode = SEQUENCE_TRIGGER_DAEMON;
+ _numTicks = 0;
+ _extraTicks = 0;
+ _timeout = 0;
+
+ _entries._count = 0;
+ Common::fill(&_entries._mode[0], &_entries._mode[SEQUENCE_ENTRY_SUBSET_MAX], SEQUENCE_TRIGGER_EXPIRE);
+ Common::fill(&_entries._frameIndex[0], &_entries._frameIndex[SEQUENCE_ENTRY_SUBSET_MAX], 0);
+ Common::fill(&_entries._trigger[0], &_entries._trigger[SEQUENCE_ENTRY_SUBSET_MAX], 0);
+}
+
+/*------------------------------------------------------------------------*/
+
+#define SEQUENCE_LIST_SIZE 30
+
+SequenceList::SequenceList(MADSEngine *vm) : _vm(vm) {
+ // IMPORTANT: Preallocate timer slots. Note that sprite slots refer to entries
+ // in this list by index, so we can't just add or delete entries later
+ for (int i = 0; i < SEQUENCE_LIST_SIZE; ++i) {
+ SequenceEntry rec;
+ rec._active = false;
+ rec._dynamicHotspotIndex = -1;
+ _entries.push_back(rec);
+ }
+}
+
+void SequenceList::clear() {
+ for (uint i = 0; i < _entries.size(); ++i) {
+ _entries[i]._active = false;
+ _entries[i]._dynamicHotspotIndex = -1;
+ }
+}
+
+bool SequenceList::addSubEntry(int index, SequenceTrigger mode, int frameIndex, int trigger) {
+ if (_entries[index]._entries._count >= SEQUENCE_ENTRY_SUBSET_MAX)
+ return true;
+
+ int subIndex = _entries[index]._entries._count++;
+ _entries[index]._entries._mode[subIndex] = mode;
+ _entries[index]._entries._frameIndex[subIndex] = frameIndex;
+ _entries[index]._entries._trigger[subIndex] = trigger;
+
+ return false;
+}
+
+int SequenceList::add(int spriteListIndex, bool flipped, int frameIndex, int triggerCountdown, int delayTicks, int extraTicks, int numTicks,
+ int msgX, int msgY, bool nonFixed, int scale, int depth, int frameInc, SpriteAnimType animType, int numSprites,
+ int frameStart) {
+ Scene &scene = _vm->_game->_scene;
+
+ // Find a free slot
+ uint seqIndex = 0;
+ while ((seqIndex < _entries.size()) && _entries[seqIndex]._active)
+ ++seqIndex;
+ if (seqIndex == _entries.size())
+ error("TimerList full");
+
+ if (frameStart <= 0)
+ frameStart = 1;
+ if (numSprites == 0)
+ numSprites = scene._sprites[spriteListIndex]->getCount();
+ if (frameStart == numSprites)
+ frameInc = 0;
+
+ // Set the list entry fields
+ _entries[seqIndex]._active = true;
+ _entries[seqIndex]._spritesIndex = spriteListIndex;
+ _entries[seqIndex]._flipped = flipped;
+ _entries[seqIndex]._frameIndex = frameIndex;
+ _entries[seqIndex]._frameStart = frameStart;
+ _entries[seqIndex]._numSprites = numSprites;
+ _entries[seqIndex]._animType = animType;
+ _entries[seqIndex]._frameInc = frameInc;
+ _entries[seqIndex]._depth = depth;
+ _entries[seqIndex]._scale = scale;
+ _entries[seqIndex]._nonFixed = nonFixed;
+ _entries[seqIndex]._position.x = msgX;
+ _entries[seqIndex]._position.y = msgY;
+ _entries[seqIndex]._numTicks = numTicks;
+ _entries[seqIndex]._extraTicks = extraTicks;
+
+ _entries[seqIndex]._timeout = scene._frameStartTime + delayTicks;
+
+ _entries[seqIndex]._triggerCountdown = triggerCountdown;
+ _entries[seqIndex]._doneFlag = false;
+ _entries[seqIndex]._flags = 0;
+ _entries[seqIndex]._dynamicHotspotIndex = -1;
+ _entries[seqIndex]._entries._count = 0;
+ _entries[seqIndex]._triggerMode = _vm->_game->_triggerSetupMode;
+
+ _entries[seqIndex]._actionNouns = _vm->_game->_scene._action._activeAction;
+
+ return seqIndex;
+}
+
+int SequenceList::addTimer(int timeout, int abortVal) {
+ Scene &scene = _vm->_game->_scene;
+ uint seqIndex;
+ for (seqIndex = 0; seqIndex < _entries.size(); ++seqIndex) {
+ if (!_entries[seqIndex]._active)
+ break;
+ }
+ assert(seqIndex < _entries.size());
+
+ SequenceEntry &se = _entries[seqIndex];
+ se._active = true;
+ se._spritesIndex = -1;
+ se._numTicks = timeout;
+ se._extraTicks = 0;
+ se._timeout = scene._frameStartTime + timeout;
+ se._triggerCountdown = true;
+ se._doneFlag = false;
+ se._entries._count = 0;
+ se._triggerMode = _vm->_game->_triggerSetupMode;
+ se._actionNouns = _vm->_game->_scene._action._activeAction;
+ addSubEntry(seqIndex, SEQUENCE_TRIGGER_EXPIRE, 0, abortVal);
+
+ return seqIndex;
+}
+
+void SequenceList::remove(int seqIndex) {
+ Scene &scene = _vm->_game->_scene;
+
+ if (_entries[seqIndex]._active) {
+ if (_entries[seqIndex]._dynamicHotspotIndex >= 0)
+ scene._dynamicHotspots.remove(_entries[seqIndex]._dynamicHotspotIndex);
+ }
+
+ _entries[seqIndex]._active = false;
+ scene._spriteSlots.deleteTimer(seqIndex);
+}
+
+void SequenceList::setSpriteSlot(int seqIndex, SpriteSlot &spriteSlot) {
+ Scene &scene = _vm->_game->_scene;
+ SequenceEntry &timerEntry = _entries[seqIndex];
+ SpriteAsset &spriteSet = *scene._sprites[timerEntry._spritesIndex];
+
+ spriteSlot._flags = spriteSet.isBackground() ? IMG_DELTA : IMG_UPDATE;
+ spriteSlot._seqIndex = seqIndex;
+ spriteSlot._spritesIndex = timerEntry._spritesIndex;
+ spriteSlot._frameNumber = timerEntry._flipped ? -timerEntry._frameIndex : timerEntry._frameIndex;
+ spriteSlot._depth = timerEntry._depth;
+ spriteSlot._scale = timerEntry._scale;
+
+ if (!timerEntry._nonFixed) {
+ spriteSlot._position = timerEntry._position;
+ } else {
+ MSprite *sprite = spriteSet.getFrame(timerEntry._frameIndex - 1);
+ spriteSlot._position = sprite->_offset;
+ }
+}
+
+bool SequenceList::loadSprites(int seqIndex) {
+ Scene &scene = _vm->_game->_scene;
+ SequenceEntry &seqEntry = _entries[seqIndex];
+ int slotIndex;
+ bool result = false;
+ int idx = -1;
+
+ scene._spriteSlots.deleteTimer(seqIndex);
+ if (seqEntry._doneFlag) {
+ remove(seqIndex);
+ return false;
+ }
+
+ if (seqEntry._spritesIndex == -1) {
+ // Doesn't have an associated sprite anymore, so mark as done
+ seqEntry._doneFlag = true;
+ } else if ((slotIndex = scene._spriteSlots.add()) >= 0) {
+ SpriteSlot &spriteSlot = scene._spriteSlots[slotIndex];
+ setSpriteSlot(seqIndex, spriteSlot);
+
+ if ((seqEntry._flags != 0) || (seqEntry._dynamicHotspotIndex >= 0)) {
+ SpriteAsset &spriteSet = *scene._sprites[seqEntry._spritesIndex];
+ MSprite *frame = spriteSet.getFrame(seqEntry._frameIndex - 1);
+ int width = frame->getWidth() * seqEntry._scale / 200;
+ int height = frame->getHeight() * seqEntry._scale / 100;
+ Common::Point pt = spriteSlot._position;
+
+ // Handle sprite movement, if present
+ if (seqEntry._flags & 1) {
+ seqEntry._posAccum.x += seqEntry._posDiff.x;
+ if (seqEntry._posAccum.x >= 100) {
+ int v = seqEntry._posAccum.x / 100;
+ seqEntry._position.x += v * seqEntry._posSign.x;
+ seqEntry._posAccum.x -= v * 100;
+ }
+
+ seqEntry._posAccum.y += seqEntry._posDiff.y;
+ if (seqEntry._posAccum.y >= 100) {
+ int v = seqEntry._posAccum.y / 100;
+ seqEntry._position.y += v * seqEntry._posSign.y;
+ seqEntry._posAccum.y -= v * 100;
+ }
+ }
+
+ if (seqEntry._flags & 2) {
+ // Check for object having moved off-scren
+ if ((pt.x + width) < 0 || (pt.x + width) >= MADS_SCREEN_WIDTH ||
+ pt.y < 0 || (pt.y - height) >= MADS_SCENE_HEIGHT) {
+ result = true;
+ seqEntry._doneFlag = true;
+ }
+ }
+
+ if (seqEntry._dynamicHotspotIndex >= 0) {
+ DynamicHotspot &dynHotspot = scene._dynamicHotspots[seqEntry._dynamicHotspotIndex];
+
+ dynHotspot._bounds.left = MAX(pt.x - width, 0);
+ dynHotspot._bounds.top = MAX(pt.y - height, 0);
+ dynHotspot._bounds.right = dynHotspot._bounds.left + width;
+ dynHotspot._bounds.bottom = dynHotspot._bounds.top + height;
+
+ scene._dynamicHotspots._changed = true;
+ }
+ }
+
+ // Frame adjustments
+ if (seqEntry._frameStart != seqEntry._numSprites)
+ seqEntry._frameIndex += seqEntry._frameInc;
+
+ if (seqEntry._frameIndex >= seqEntry._frameStart) {
+ if (seqEntry._frameIndex > seqEntry._numSprites) {
+ result = true;
+ if (seqEntry._animType == ANIMTYPE_CYCLED) {
+ // back to the starting frame (cyclic)
+ seqEntry._frameIndex = seqEntry._frameStart;
+ } else {
+ // Switch into reverse mode
+ seqEntry._frameIndex = seqEntry._numSprites - 1;
+ seqEntry._frameInc = -1;
+ }
+ }
+ } else {
+ // Currently in reverse mode and moved past starting frame
+ result = true;
+
+ if (seqEntry._animType == ANIMTYPE_CYCLED)
+ {
+ // Switch back to forward direction again
+ seqEntry._frameIndex = seqEntry._frameStart + 1;
+ seqEntry._frameInc = 1;
+ } else {
+ // Otherwise reset back to last sprite for further reverse animating
+ seqEntry._frameIndex = seqEntry._numSprites;
+ }
+ }
+
+ if (result && (seqEntry._triggerCountdown != 0)) {
+ if (--seqEntry._triggerCountdown == 0)
+ seqEntry._doneFlag = true;
+ }
+ } else {
+ // Out of sprite display slots, so mark entry as done
+ seqEntry._doneFlag = true;
+ }
+
+ for (int i = 0; i < seqEntry._entries._count; ++i) {
+ switch (seqEntry._entries._mode[i]) {
+ case SEQUENCE_TRIGGER_EXPIRE:
+ case SEQUENCE_TRIGGER_LOOP:
+ if (((seqEntry._entries._mode[i] == SEQUENCE_TRIGGER_EXPIRE) && seqEntry._doneFlag) ||
+ ((seqEntry._entries._mode[i] == SEQUENCE_TRIGGER_LOOP) && result))
+ idx = i;
+ break;
+
+ case SEQUENCE_TRIGGER_SPRITE: {
+ int v = seqEntry._entries._frameIndex[i];
+ if ((v == seqEntry._frameIndex) || (v == 0))
+ idx = i;
+ break;
+ }
+
+ default:
+ break;
+ }
+ }
+
+ if (idx >= 0) {
+ _vm->_game->_trigger = seqEntry._entries._trigger[idx];
+ _vm->_game->_triggerMode = seqEntry._triggerMode;
+
+ if (seqEntry._triggerMode != SEQUENCE_TRIGGER_DAEMON)
+ scene._action._activeAction = seqEntry._actionNouns;
+ }
+
+ return result;
+}
+
+/**
+* Handles counting down entries in the timer list for action
+*/
+void SequenceList::tick() {
+ Scene &scene = _vm->_game->_scene;
+ for (uint idx = 0; idx < _entries.size(); ++idx) {
+ if ((_vm->_game->_fx == 0) && (_vm->_game->_trigger != 0))
+ break;
+
+ SequenceEntry &seqEntry = _entries[idx];
+ uint32 currentTimer = scene._frameStartTime;
+
+ if (!seqEntry._active || (currentTimer < seqEntry._timeout))
+ continue;
+
+ // Set the next timeout for the timer entry
+ seqEntry._timeout = currentTimer + seqEntry._numTicks;
+
+ // Action the sprite
+ if (loadSprites(idx)) {
+ seqEntry._timeout += seqEntry._extraTicks;
+ }
+ }
+}
+
+void SequenceList::delay(uint32 priorFrameTime, uint32 currentTime) {
+ for (uint idx = 0; idx < _entries.size(); ++idx) {
+ if (_entries[idx]._active) {
+ _entries[idx]._timeout += currentTime - priorFrameTime;
+ }
+ }
+}
+
+void SequenceList::setAnimRange(int seqIndex, int startVal, int endVal) {
+ Scene &scene = _vm->_game->_scene;
+ SequenceEntry &seqEntry = _entries[seqIndex];
+ SpriteAsset &spriteSet = *scene._sprites[seqEntry._spritesIndex];
+ int numSprites = spriteSet.getCount();
+ int tempStart, tempEnd;
+
+ switch (startVal) {
+ case -2:
+ tempStart = numSprites;
+ break;
+ case -1:
+ tempStart = 1;
+ break;
+ default:
+ tempStart = startVal;
+ break;
+ }
+
+ switch (endVal) {
+ case -2:
+ case 0:
+ tempEnd = numSprites;
+ break;
+ case -1:
+ tempEnd = 1;
+ break;
+ default:
+ tempEnd = endVal;
+ break;
+ }
+
+ seqEntry._frameStart = tempStart;
+ seqEntry._numSprites = tempEnd;
+
+ seqEntry._frameIndex = (seqEntry._frameInc >= 0) ? tempStart : tempEnd;
+}
+
+void SequenceList::scan() {
+ Scene &scene = _vm->_game->_scene;
+
+ for (uint i = 0; i < _entries.size(); ++i) {
+ if (_entries[i]._active && (_entries[i]._spritesIndex != -1)) {
+ int idx = scene._spriteSlots.add();
+ setSpriteSlot(i, scene._spriteSlots[idx]);
+ }
+ }
+}
+
+/**
+* Sets the depth of the specified entry in the sequence list
+*/
+void SequenceList::setDepth(int seqIndex, int depth) {
+ _entries[seqIndex]._depth = depth;
+}
+
+void SequenceList::setPosition(int seqIndex, const Common::Point &pt) {
+ _entries[seqIndex]._position = pt;
+ _entries[seqIndex]._nonFixed = false;
+}
+
+int SequenceList::addSpriteCycle(int srcSpriteIdx, bool flipped, int numTicks, int triggerCountdown, int timeoutTicks, int extraTicks) {
+ Scene &scene = _vm->_game->_scene;
+ MSprite *spriteFrame = scene._sprites[srcSpriteIdx]->getFrame(0);
+ int depth = scene._depthSurface.getDepth(Common::Point(
+ spriteFrame->_offset.x + (spriteFrame->w / 2),
+ spriteFrame->_offset.y + (spriteFrame->h / 2)));
+
+ return add(srcSpriteIdx, flipped, 1, triggerCountdown, timeoutTicks, extraTicks, numTicks, 0, 0,
+ true, 100, depth - 1, 1, ANIMTYPE_CYCLED, 0, 0);
+}
+
+int SequenceList::addReverseSpriteCycle(int srcSpriteIdx, bool flipped, int numTicks,
+ int triggerCountdown, int timeoutTicks, int extraTicks) {
+ Scene &scene = _vm->_game->_scene;
+
+ SpriteAsset *asset = scene._sprites[srcSpriteIdx];
+ MSprite *spriteFrame = asset->getFrame(0);
+ int depth = scene._depthSurface.getDepth(Common::Point(
+ spriteFrame->_offset.x + (spriteFrame->w / 2),
+ spriteFrame->_offset.y + (spriteFrame->h / 2)));
+
+ return add(srcSpriteIdx, flipped, asset->getCount(), triggerCountdown, timeoutTicks, extraTicks,
+ numTicks, 0, 0, true, 100, depth - 1, -1, ANIMTYPE_CYCLED, 0, 0);
+}
+
+
+int SequenceList::startCycle(int srcSpriteIndex, bool flipped, int cycleIndex) {
+ int result = addSpriteCycle(srcSpriteIndex, flipped, INDEFINITE_TIMEOUT, 0, 0, 0);
+ if (result >= 0)
+ setAnimRange(result, cycleIndex, cycleIndex);
+
+ return result;
+}
+
+int SequenceList::startReverseCycle(int srcSpriteIndex, bool flipped, int numTicks,
+ int triggerCountdown, int timeoutTicks, int extraTicks) {
+ SpriteAsset *sprites = _vm->_game->_scene._sprites[srcSpriteIndex];
+ MSprite *frame = sprites->getFrame(0);
+ int depth = _vm->_game->_scene._depthSurface.getDepth(Common::Point(
+ frame->_offset.x + frame->w / 2, frame->_offset.y + frame->h / 2));
+
+ return add(srcSpriteIndex, flipped, 1, triggerCountdown, timeoutTicks, extraTicks,
+ numTicks, 0, 0, true, 100, depth - 1, 1, ANIMTYPE_REVERSIBLE, 0, 0);
+}
+
+void SequenceList::updateTimeout(int spriteIdx, int seqIndex) {
+ Player &player = _vm->_game->_player;
+ int timeout;
+
+ if (spriteIdx >= 0)
+ timeout = _entries[spriteIdx]._timeout;
+ else
+ timeout = player._priorTimer + player._ticksAmount;
+
+ if (seqIndex >= 0)
+ _entries[seqIndex]._timeout = timeout;
+ else
+ player._priorTimer = timeout - player._ticksAmount;
+
+}
+
+void SequenceList::setScale(int spriteIdx, int scale) {
+ _entries[spriteIdx]._scale = scale;
+}
+
+void SequenceList::setMsgLayout(int seqIndex) {
+ Player &player = _vm->_game->_player;
+ int yp = player._playerPos.y + (player._centerOfGravity * player._currentScale) / 100;
+ setPosition(seqIndex, Common::Point(player._playerPos.x, yp));
+ setDepth(seqIndex, player._currentDepth);
+ setScale(seqIndex, player._currentScale);
+ updateTimeout(-1, seqIndex);
+}
+
+void SequenceList::setDone(int seqIndex) {
+ _entries[seqIndex]._doneFlag = true;
+ _entries[seqIndex]._timeout = _vm->_game->_player._priorTimer;
+}
+
+void SequenceList::setMotion(int seqIndex, int flags, int deltaX, int deltaY) {
+ SequenceEntry &se = _entries[seqIndex];
+ se._flags = flags | 1;
+
+ // Set the direction sign for movement
+ if (deltaX > 0) {
+ se._posSign.x = 1;
+ } else if (deltaX < 0) {
+ se._posSign.x = -1;
+ } else {
+ se._posSign.x = 0;
+ }
+
+ if (deltaY > 0) {
+ se._posSign.y = 1;
+ }
+ else if (deltaY < 0) {
+ se._posSign.y = -1;
+ } else {
+ se._posSign.y = 0;
+ }
+
+ se._posDiff.x = ABS(deltaX);
+ se._posDiff.y = ABS(deltaY);
+ se._posAccum.x = se._posAccum.y = 0;
+}
+
+} // End of namespace
diff --git a/engines/mads/sequence.h b/engines/mads/sequence.h
new file mode 100644
index 0000000000..ee587ff02d
--- /dev/null
+++ b/engines/mads/sequence.h
@@ -0,0 +1,131 @@
+/* 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.
+ *
+ */
+
+#ifndef MADS_SEQUENCE_H
+#define MADS_SEQUENCE_H
+
+#include "common/scummsys.h"
+#include "common/array.h"
+#include "common/rect.h"
+#include "mads/action.h"
+
+namespace MADS {
+
+class SpriteSlot;
+
+enum SequenceTrigger {
+ SEQUENCE_TRIGGER_EXPIRE = 0, // Trigger when the sequence finishes
+ SEQUENCE_TRIGGER_LOOP = 1, // Trigger when the sequence loops
+ SEQUENCE_TRIGGER_SPRITE = 2 // Trigger when sequence reaches specific sprite
+};
+
+enum SpriteAnimType { ANIMTYPE_NONE = 0, ANIMTYPE_CYCLED = 1, ANIMTYPE_REVERSIBLE = 2 };
+
+#define SEQUENCE_ENTRY_SUBSET_MAX 5
+
+struct SequenceSubEntries {
+ int _count;
+ SequenceTrigger _mode[SEQUENCE_ENTRY_SUBSET_MAX];
+ int _frameIndex[SEQUENCE_ENTRY_SUBSET_MAX];
+ int _trigger[SEQUENCE_ENTRY_SUBSET_MAX];
+};
+
+struct SequenceEntry {
+ bool _active;
+ int8 _spritesIndex;
+ bool _flipped;
+
+ int _frameIndex;
+ int _frameStart;
+ int _numSprites;
+
+ SpriteAnimType _animType;
+ int _frameInc;
+
+ int _depth;
+ int _scale;
+ int _dynamicHotspotIndex;
+
+ bool _nonFixed;
+ uint32 _flags;
+
+ Common::Point _position;
+ Common::Point _posDiff;
+ Common::Point _posSign;
+ Common::Point _posAccum;
+ int _triggerCountdown;
+ bool _doneFlag;
+ SequenceSubEntries _entries;
+ TriggerMode _triggerMode;
+
+ ActionDetails _actionNouns;
+ int _numTicks;
+ int _extraTicks;
+ uint32 _timeout;
+
+ SequenceEntry();
+};
+
+class MADSEngine;
+
+class SequenceList {
+private:
+ MADSEngine *_vm;
+ Common::Array<SequenceEntry> _entries;
+public:
+ SequenceList(MADSEngine *vm);
+
+ SequenceEntry &operator[](int index) { return _entries[index]; }
+ void clear();
+ bool addSubEntry(int index, SequenceTrigger mode, int frameIndex, int trigger);
+ int add(int spriteListIndex, bool flipped, int frameIndex, int triggerCountdown, int delayTicks,
+ int extraTicks, int numTicks, int msgX, int msgY, bool nonFixed, int scale, int depth,
+ int frameInc, SpriteAnimType animType, int numSprites, int frameStart);
+
+ int addTimer(int timeout, int abortVal);
+ void remove(int seqIndex);
+ void setSpriteSlot(int seqIndex, SpriteSlot &spriteSlot);
+ bool loadSprites(int seqIndex);
+ void tick();
+ void delay(uint32 priorFrameTime, uint32 currentTime);
+ void setAnimRange(int seqIndex, int startVal, int endVal);
+ void scan();
+ void setDepth(int seqIndex, int depth);
+ void setPosition(int seqIndex, const Common::Point &pt);
+ int addSpriteCycle(int srcSpriteIdx, bool flipped, int numTicks,
+ int triggerCountdown = 0, int timeoutTicks = 0, int extraTicks = 0);
+ int addReverseSpriteCycle(int srcSpriteIdx, bool flipped, int numTicks,
+ int triggerCountdown = 0, int timeoutTicks = 0, int extraTicks = 0);
+
+ int startCycle(int srcSpriteIdx, bool flipped, int cycleIndex);
+ int startReverseCycle(int srcSpriteIndex, bool flipped, int numTicks,
+ int triggerCountdown = 0, int timeoutTicks = 0, int extraTicks = 0);
+ void updateTimeout(int spriteIdx, int seqIndex);
+ void setScale(int spriteIdx, int scale);
+ void setMsgLayout(int seqIndex);
+ void setDone(int seqIndex);
+ void setMotion(int seqIndex, int flags, int deltaX, int deltaY);
+};
+
+} // End of namespace MADS
+
+#endif /* MADS_SEQUENCE_H */
diff --git a/engines/mads/sound.cpp b/engines/mads/sound.cpp
new file mode 100644
index 0000000000..bd99aed2f4
--- /dev/null
+++ b/engines/mads/sound.cpp
@@ -0,0 +1,142 @@
+/* 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 "audio/audiostream.h"
+#include "audio/decoders/raw.h"
+#include "common/memstream.h"
+#include "mads/sound.h"
+#include "mads/mads.h"
+#include "mads/nebular/sound_nebular.h"
+
+namespace MADS {
+
+SoundManager::SoundManager(MADSEngine *vm, Audio::Mixer *mixer) {
+ _vm = vm;
+ _mixer = mixer;
+ _driver = nullptr;
+ _pollSoundEnabled = false;
+ _soundPollFlag = false;
+ _newSoundsPaused = false;
+}
+
+SoundManager::~SoundManager() {
+ delete _driver;
+}
+
+void SoundManager::init(int sectionNumber) {
+ assert(sectionNumber > 0 && sectionNumber < 10);
+
+ switch (_vm->getGameID()) {
+ case GType_RexNebular:
+ switch (sectionNumber) {
+ case 1:
+ _driver = new Nebular::ASound1(_mixer);
+ break;
+ case 2:
+ _driver = new Nebular::ASound2(_mixer);
+ break;
+ case 3:
+ _driver = new Nebular::ASound3(_mixer);
+ break;
+ case 4:
+ _driver = new Nebular::ASound4(_mixer);
+ break;
+ case 5:
+ _driver = new Nebular::ASound5(_mixer);
+ break;
+ case 6:
+ _driver = new Nebular::ASound6(_mixer);
+ break;
+ case 7:
+ _driver = new Nebular::ASound7(_mixer);
+ break;
+ case 8:
+ _driver = new Nebular::ASound8(_mixer);
+ break;
+ case 9:
+ error("Sound driver 9 not implemented");
+ default:
+ _driver = nullptr;
+ break;
+ }
+ break;
+
+ default:
+ warning("SoundManager: Unknown game");
+ _driver = nullptr;
+ break;
+ }
+}
+
+void SoundManager::closeDriver() {
+ if (_driver) {
+ command(0);
+ setEnabled(false);
+ stop();
+
+ removeDriver();
+ }
+}
+
+void SoundManager::removeDriver() {
+ delete _driver;
+ _driver = nullptr;
+}
+
+void SoundManager::setEnabled(bool flag) {
+ _pollSoundEnabled = flag;
+ _soundPollFlag = false;
+}
+
+void SoundManager::pauseNewCommands() {
+ _newSoundsPaused = true;
+}
+
+void SoundManager::startQueuedCommands() {
+ _newSoundsPaused = false;
+
+ while (!_queuedCommands.empty()) {
+ int commandId = _queuedCommands.pop();
+ command(commandId);
+ }
+}
+
+void SoundManager::command(int commandId, int param) {
+ if (_newSoundsPaused) {
+ if (_queuedCommands.size() < 8)
+ _queuedCommands.push(commandId);
+ } else if (_driver) {
+ _driver->command(commandId, param);
+ }
+}
+
+void SoundManager::stop() {
+ if (_driver)
+ _driver->stop();
+}
+
+void SoundManager::noise() {
+ if (_driver)
+ _driver->noise();
+}
+
+} // End of namespace MADS
diff --git a/engines/mads/sound.h b/engines/mads/sound.h
new file mode 100644
index 0000000000..0fd9ac1095
--- /dev/null
+++ b/engines/mads/sound.h
@@ -0,0 +1,103 @@
+/* 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.
+ *
+ */
+
+#ifndef MADS_SOUND_H
+#define MADS_SOUND_H
+
+#include "common/scummsys.h"
+#include "common/queue.h"
+#include "audio/audiostream.h"
+#include "audio/mixer.h"
+#include "mads/nebular/sound_nebular.h"
+
+namespace MADS {
+
+class MADSEngine;
+
+class SoundManager {
+private:
+ MADSEngine *_vm;
+ Audio::Mixer *_mixer;
+ Nebular::ASound *_driver;
+ bool _pollSoundEnabled;
+ bool _soundPollFlag;
+ bool _newSoundsPaused;
+ Common::Queue<int> _queuedCommands;
+public:
+ SoundManager(MADSEngine *vm, Audio::Mixer *mixer);
+ ~SoundManager();
+
+ /**
+ * Initialises the sound driver for a given game section
+ */
+ void init(int sectionNumber);
+
+ /**
+ * Stop any currently active sound and remove the driver
+ */
+ void closeDriver();
+
+ /**
+ * Remove the driver
+ */
+ void removeDriver();
+
+ /**
+ * Sets the enabled status of the sound
+ * @flag True if sound should be enabled
+ */
+ void setEnabled(bool flag);
+
+ /**
+ * Temporarily pause the playback of any new sound commands
+ */
+ void pauseNewCommands();
+
+ /**
+ * Stop queueing sound commands, and execute any previously queued ones
+ */
+ void startQueuedCommands();
+
+ //@{
+ /**
+ * Executes a command on the sound driver
+ * @param commandid Command Id to execute
+ * @param param Optional paramater specific to a few commands
+ */
+ void command(int commandId, int param = 0);
+
+ /**
+ * Stops any currently playing sound
+ */
+ void stop();
+
+ /**
+ * Noise
+ * Some sort of random noise generation?
+ */
+ void noise();
+ //@}
+};
+
+} // End of namespace MADS
+
+#endif /* MADS_SOUND_H */
diff --git a/engines/mads/sprites.cpp b/engines/mads/sprites.cpp
new file mode 100644
index 0000000000..c98a0963f6
--- /dev/null
+++ b/engines/mads/sprites.cpp
@@ -0,0 +1,416 @@
+/* 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 "engines/util.h"
+#include "graphics/palette.h"
+#include "mads/mads.h"
+#include "mads/screen.h"
+#include "mads/msurface.h"
+#include "mads/sprites.h"
+
+namespace MADS {
+
+enum {
+ kEndOfLine = 0,
+ kEndOfSprite = 1,
+ kMarker = 2
+};
+
+#define TRANSPARENT_COLOR_INDEX 0xFF
+
+class DepthEntry {
+public:
+ int depth;
+ int index;
+
+ DepthEntry(int depthAmt, int indexVal) { depth = depthAmt; index = indexVal; }
+};
+
+bool sortHelper(const DepthEntry &entry1, const DepthEntry &entry2) {
+ return entry1.depth < entry2.depth;
+}
+
+typedef Common::List<DepthEntry> DepthList;
+
+/*------------------------------------------------------------------------*/
+
+MSprite::MSprite(): MSurface() {
+}
+
+MSprite::MSprite(Common::SeekableReadStream *source, const Common::Array<RGB6> &palette,
+ const Common::Rect &bounds):
+ MSurface(bounds.width(), bounds.height()),
+ _offset(Common::Point(bounds.left, bounds.top)) {
+ // Load the sprite data
+ loadSprite(source, palette);
+}
+
+MSprite::~MSprite() {
+}
+
+void MSprite::loadSprite(Common::SeekableReadStream *source,
+ const Common::Array<RGB6> &palette) {
+ byte *outp, *lineStart;
+ bool newLine = false;
+
+ outp = getData();
+ lineStart = getData();
+ int spriteSize = this->w * this->h;
+ byte transIndex = getTransparencyIndex();
+ Common::fill(outp, outp + spriteSize, transIndex);
+
+ for (;;) {
+ byte cmd1, cmd2, count, pixel;
+
+ if (newLine) {
+ outp = lineStart + getWidth();
+ lineStart = outp;
+ newLine = false;
+ }
+
+ cmd1 = source->readByte();
+
+ if (cmd1 == 0xFC)
+ break;
+ else if (cmd1 == 0xFF)
+ newLine = true;
+ else if (cmd1 == 0xFD) {
+ while (!newLine) {
+ count = source->readByte();
+ if (count == 0xFF) {
+ newLine = true;
+ } else {
+ pixel = source->readByte();
+ while (count--)
+ *outp++ = (pixel == 0xFD) ? getTransparencyIndex() : pixel;
+ }
+ }
+ } else {
+ while (!newLine) {
+ cmd2 = source->readByte();
+ if (cmd2 == 0xFF) {
+ newLine = true;
+ } else if (cmd2 == 0xFE) {
+ count = source->readByte();
+ pixel = source->readByte();
+ while (count--)
+ *outp++ = (pixel == 0xFD) ? getTransparencyIndex() : pixel;
+ } else {
+ *outp++ = (cmd2 == 0xFD) ? getTransparencyIndex() : cmd2;
+ }
+ }
+ }
+ }
+
+ // Do a final iteration over the sprite to convert it's pixels to
+ // the final positions in the main palette
+ for (outp = getData(); spriteSize > 0; --spriteSize, ++outp) {
+ if (*outp != transIndex)
+ *outp = palette[*outp]._palIndex;
+ }
+}
+
+byte MSprite::getTransparencyIndex() const {
+ return TRANSPARENT_COLOR_INDEX;
+}
+
+/*------------------------------------------------------------------------*/
+
+MADSEngine *SpriteSlot::_vm = nullptr;
+
+SpriteSlot::SpriteSlot() {
+ _flags = IMG_STATIC;
+ _seqIndex = 0;
+ _spritesIndex = 0;
+ _frameNumber = 0;
+ _depth = 0;
+ _scale = 0;
+}
+
+SpriteSlot::SpriteSlot(SpriteFlags type, int seqIndex) {
+ _flags = type;
+ _seqIndex = seqIndex;
+ _spritesIndex = 0;
+ _frameNumber = 0;
+ _depth = 0;
+ _scale = 0;
+}
+
+bool SpriteSlot::operator==(const SpriteSlotSubset &other) const {
+ return (_spritesIndex == other._spritesIndex) && (_frameNumber == other._frameNumber) &&
+ (_position == other._position) && (_depth == other._depth) &&
+ (_scale == other._scale);
+}
+
+void SpriteSlot::copy(const SpriteSlotSubset &other) {
+ _spritesIndex = other._spritesIndex;
+ _frameNumber = other._frameNumber;
+ _position = other._position;
+ _depth = other._depth;
+ _scale = other._scale;
+}
+
+/*------------------------------------------------------------------------*/
+
+SpriteSlots::SpriteSlots(MADSEngine *vm) : _vm(vm) {
+ SpriteSlot::_vm = vm;
+}
+
+void SpriteSlots::reset(bool flag) {
+ _vm->_game->_scene._textDisplay.reset();
+
+ if (flag)
+ _vm->_game->_scene._sprites.clear();
+
+ Common::Array<SpriteSlot>::clear();
+ push_back(SpriteSlot(IMG_REFRESH, -1));
+}
+
+void SpriteSlots::deleteEntry(int index) {
+ remove_at(index);
+}
+
+void SpriteSlots::setDirtyAreas() {
+ Scene &scene = _vm->_game->_scene;
+
+ for (uint i = 0; i < size(); ++i) {
+ if ((*this)[i]._flags >= IMG_STATIC) {
+ scene._dirtyAreas[i].setSpriteSlot(&(*this)[i]);
+
+ scene._dirtyAreas[i]._textActive = ((*this)[i]._flags <= IMG_STATIC) ? 0 : 1;
+ (*this)[i]._flags = IMG_STATIC;
+ }
+ }
+}
+
+void SpriteSlots::fullRefresh(bool clearAll) {
+ if (clearAll)
+ Common::Array<SpriteSlot>::clear();
+
+ push_back(SpriteSlot(IMG_REFRESH, -1));
+}
+
+void SpriteSlots::deleteTimer(int seqIndex) {
+ for (uint idx = 0; idx < size(); ++idx) {
+ SpriteSlot &slot = (*this)[idx];
+ if (slot._seqIndex == seqIndex) {
+ slot._flags = IMG_ERASE;
+ return;
+ }
+ }
+}
+
+int SpriteSlots::add() {
+ SpriteSlot ss;
+ push_back(ss);
+ return size() - 1;
+}
+
+void SpriteSlots::drawBackground() {
+ Scene &scene = _vm->_game->_scene;
+
+ // Initial draw loop for any active sprites in the background
+ for (uint i = 0; i < size(); ++i) {
+ SpriteSlot &spriteSlot = (*this)[i];
+ DirtyArea &dirtyArea = scene._dirtyAreas[i];
+
+ if (spriteSlot._flags >= IMG_STATIC) {
+ // Foreground sprite, so we can ignore it
+ dirtyArea._active = false;
+ } else {
+ dirtyArea._active = true;
+ dirtyArea.setSpriteSlot(&spriteSlot);
+
+ if (spriteSlot._flags == IMG_DELTA) {
+ // Background object, so need to draw it
+ assert(spriteSlot._frameNumber > 0);
+ SpriteAsset *asset = scene._sprites[spriteSlot._spritesIndex];
+ MSprite *frame = asset->getFrame(spriteSlot._frameNumber - 1);
+
+ Common::Point pt = spriteSlot._position;
+ if (spriteSlot._scale != -1) {
+ // Adjust the drawing position
+ pt.x -= frame->w / 2;
+ pt.y -= frame->h / 2;
+ }
+
+
+ if (spriteSlot._depth <= 1) {
+ frame->copyTo(&scene._backgroundSurface, pt, frame->getTransparencyIndex());
+ } else if (scene._depthStyle == 0) {
+ scene._backgroundSurface.copyFrom(frame, pt, spriteSlot._depth, &scene._depthSurface,
+ 100, frame->getTransparencyIndex());
+ } else {
+ error("Unsupported depth style");
+ }
+ }
+ }
+ }
+
+ // Mark any remaning sprite slot dirty areas as inactive
+ for (uint i = size(); i < SPRITE_SLOTS_MAX_SIZE; ++i)
+ scene._dirtyAreas[i]._active = false;
+
+ // Flag any active text display
+ for (uint i = 0; i < scene._textDisplay.size(); ++i) {
+ TextDisplay &textDisplay = scene._textDisplay[i];
+ DirtyArea &dirtyArea = scene._dirtyAreas[i + SPRITE_SLOTS_MAX_SIZE];
+
+ if (textDisplay._expire >= 0 || !textDisplay._active) {
+ dirtyArea._active = false;
+ } else {
+ dirtyArea._active = true;
+ dirtyArea.setTextDisplay(&textDisplay);
+ }
+ }
+}
+
+void SpriteSlots::drawSprites(MSurface *s) {
+ DepthList depthList;
+ Scene &scene = _vm->_game->_scene;
+
+ // Get a list of sprite object depths for active objects
+ for (uint i = 0; i < size(); ++i) {
+ SpriteSlot &spriteSlot = (*this)[i];
+ if (spriteSlot._flags >= IMG_STATIC) {
+ DepthEntry rec(16 - spriteSlot._depth, i);
+ depthList.push_back(rec);
+ }
+ }
+
+ // Sort the list in order of the depth
+ Common::sort(depthList.begin(), depthList.end(), sortHelper);
+
+ // Loop through each of the objects
+ DepthList::iterator i;
+ for (i = depthList.begin(); i != depthList.end(); ++i) {
+ DepthEntry &de = *i;
+ SpriteSlot &slot = (*this)[de.index];
+ assert(slot._spritesIndex < (int)scene._sprites.size());
+ SpriteAsset &spriteSet = *scene._sprites[slot._spritesIndex];
+
+ // Get the sprite frame
+ int frameNumber = ABS(slot._frameNumber);
+ bool flipped = slot._frameNumber < 0;
+
+ assert(frameNumber > 0);
+ MSprite *sprite = spriteSet.getFrame(frameNumber - 1);
+
+ MSurface *spr = sprite;
+ if (flipped) {
+ // Create a flipped copy of the sprite temporarily
+ spr = sprite->flipHorizontal();
+ }
+
+ if ((slot._scale < 100) && (slot._scale != -1)) {
+ // Minimalised drawing
+ s->copyFrom(spr, slot._position, slot._depth, &scene._depthSurface,
+ slot._scale, sprite->getTransparencyIndex());
+ } else {
+ int xp, yp;
+
+ if (slot._scale == -1) {
+ xp = slot._position.x - scene._posAdjust.x;
+ yp = slot._position.y - scene._posAdjust.y;
+ } else {
+ xp = slot._position.x - (spr->w / 2) - scene._posAdjust.x;
+ yp = slot._position.y - spr->h - scene._posAdjust.y + 1;
+ }
+
+ if (slot._depth > 1) {
+ // Draw the frame with depth processing
+ s->copyFrom(spr, Common::Point(xp, yp), slot._depth, &scene._depthSurface,
+ 100, sprite->getTransparencyIndex());
+ } else {
+ // No depth, so simply draw the image
+ spr->copyTo(s, Common::Point(xp, yp), sprite->getTransparencyIndex());
+ }
+ }
+
+ // Free sprite if it was a flipped one
+ if (flipped)
+ delete spr;
+ }
+}
+
+void SpriteSlots::cleanUp() {
+ for (int i = (int)size() - 1; i >= 0; --i) {
+ if ((*this)[i]._flags < IMG_STATIC)
+ remove_at(i);
+ }
+}
+
+/*------------------------------------------------------------------------*/
+
+SpriteSets::~SpriteSets() {
+ clear();
+}
+
+int SpriteSets::add(SpriteAsset *asset, int idx) {
+ if (idx)
+ idx = idx + 49;
+ else
+ idx = size();
+
+ if (idx >= (int)size())
+ resize(idx + 1);
+
+ if ((*this)[idx]) {
+ delete (*this)[idx];
+ } else {
+ ++_assetCount;
+ }
+
+ (*this)[idx] = asset;
+ return idx;
+}
+
+int SpriteSets::addSprites(const Common::String &resName, int flags) {
+ return add(new SpriteAsset(_vm, resName, flags));
+}
+
+void SpriteSets::clear() {
+ for (uint i = 0; i < size(); ++i)
+ delete (*this)[i];
+
+ _assetCount = 0;
+ Common::Array<SpriteAsset *>::clear();
+}
+
+void SpriteSets::remove(int idx) {
+ if (idx >= 0) {
+ if (idx < ((int)size() - 1)) {
+ delete (*this)[idx];
+ (*this)[idx] = nullptr;
+ } else {
+ while (size() > 0 && (*this)[size() - 1] == nullptr) {
+ remove_at(size() - 1);
+ }
+ }
+
+ if (_assetCount > 0)
+ --_assetCount;
+ }
+}
+
+} // End of namespace MADS
diff --git a/engines/mads/sprites.h b/engines/mads/sprites.h
new file mode 100644
index 0000000000..f807e733b7
--- /dev/null
+++ b/engines/mads/sprites.h
@@ -0,0 +1,239 @@
+/* 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.
+ *
+ */
+
+#ifndef MADS_SPRITES_H
+#define MADS_SPRITES_H
+
+#include "common/scummsys.h"
+#include "common/array.h"
+#include "mads/assets.h"
+#include "mads/msurface.h"
+
+namespace MADS {
+
+enum SpriteFlags {
+ IMG_STATIC = 0, // Item should remain fixed on the screen
+ IMG_UPDATE = 1, // Item needs to be redrawn
+ IMG_ERASE = -1, // Erase image and remove it
+ IMG_REFRESH = -2, // Full refresh
+ IMG_OVERPRINT = -3, // Interface overprint
+ IMG_DELTA = -4, // Delta change
+ IMG_FULL_UPDATE = -5, // Interface refresh
+ IMG_UPDATE_ONLY = -20 // Update the active screen area only
+};
+
+class MADSEngine;
+
+struct BGR8 {
+ uint8 b, g, r;
+};
+
+typedef struct {
+ int32 x; // x position relative to GrBuff(0, 0)
+ int32 y; // y position relative to GrBuff(0, 0)
+ int32 scale_x; // x scale factor (can be negative for reverse draw)
+ int32 scale_y; // y scale factor (can't be negative)
+ uint8* depth_map; // depth code array for destination (doesn't care if srcDepth is 0)
+ BGR8* Pal; // palette for shadow draw (doesn't care if SHADOW bit is not set in Src.encoding)
+ uint8* ICT; // Inverse Color Table (doesn't care if SHADOW bit is not set in Src.encoding)
+ uint8 depth; // depth code for source (0 if no depth processing)
+} DrawRequestX;
+
+typedef struct {
+ uint32 Pack;
+ uint32 Stream;
+ long hot_x;
+ long hot_y;
+ uint32 Width;
+ uint32 Height;
+ uint32 Comp;
+ uint32 Reserved[8];
+ uint8* data;
+} RendCell;
+
+#define SS_HEADER_NUM_FIELDS 14
+struct SpriteSeriesHeader {
+ uint32 header;
+ uint32 size;
+ uint32 packing;
+ uint32 frameRate;
+ uint32 pixSpeed;
+ uint32 maxWidth;
+ uint32 maxHeight;
+ uint32 reserved3;
+ uint32 reserved4;
+ uint32 reserved5;
+ uint32 reserved6;
+ uint32 reserved7;
+ uint32 reserved8;
+ uint32 count;
+};
+
+#define SF_HEADER_NUM_FIELDS 15
+struct SpriteFrameHeader {
+ uint32 pack;
+ uint32 stream;
+ uint32 x;
+ uint32 y;
+ uint32 width;
+ uint32 height;
+ uint32 comp;
+ uint32 reserved1;
+ uint32 reserved2;
+ uint32 reserved3;
+ uint32 reserved4;
+ uint32 reserved5;
+ uint32 reserved6;
+ uint32 reserved7;
+ uint32 reserved8;
+};
+
+class MSprite: public MSurface {
+private:
+ void loadSprite(Common::SeekableReadStream *source, const Common::Array<RGB6> &palette);
+public:
+ MSprite();
+ MSprite(Common::SeekableReadStream *source, const Common::Array<RGB6> &palette,
+ const Common::Rect &bounds);
+ virtual ~MSprite();
+
+ Common::Point _offset;
+
+ byte getTransparencyIndex() const;
+};
+
+class SpriteSlotSubset {
+public:
+ int _spritesIndex;
+ int _frameNumber;
+ Common::Point _position;
+ int _depth;
+ int _scale;
+};
+
+class SpriteSlot : public SpriteSlotSubset {
+private:
+ static MADSEngine *_vm;
+ friend class SpriteSlots;
+public:
+ SpriteFlags _flags;
+ int _seqIndex;
+public:
+ SpriteSlot();
+ SpriteSlot(SpriteFlags type, int seqIndex);
+
+ void setup(int dirtyAreaIndex);
+ bool operator==(const SpriteSlotSubset &other) const;
+ void copy(const SpriteSlotSubset &other);
+};
+
+class SpriteSlots : public Common::Array<SpriteSlot> {
+private:
+ MADSEngine *_vm;
+public:
+ SpriteSlots(MADSEngine *vm);
+
+ /**
+ * Clears any pending slot data and schedules a full screen refresh.
+ * @param flag Also reset sprite list
+ */
+ void reset(bool flag = true);
+
+ /**
+ * Delete a sprite entry
+ * @param index Specifies the index in the array
+ */
+ void deleteEntry(int index);
+
+ /**
+ * Setup dirty areas for the sprite slots
+ */
+ void setDirtyAreas();
+
+ /**
+ * Adds a full screen refresh to the sprite slots
+ */
+ void fullRefresh(bool clearAll = false);
+
+ /**
+ * Delete a timer entry with the given Id
+ */
+ void deleteTimer(int seqIndex);
+
+ /**
+ * Add a new slot entry and return it's index
+ */
+ int add();
+
+ /**
+ * Draw any sprites into the background of the scene
+ */
+ void drawBackground();
+
+ /**
+ * Draw any sprites into the foreground of the scene
+ */
+ void drawSprites(MSurface *s);
+
+ void cleanUp();
+};
+
+class SpriteSets : public Common::Array<SpriteAsset *> {
+private:
+ MADSEngine *_vm;
+public:
+ int _assetCount;
+
+ /**
+ * Constructor
+ */
+ SpriteSets(MADSEngine *vm) : _vm(vm), _assetCount(0) {}
+
+ /**
+ * Destructor
+ */
+ ~SpriteSets();
+
+ /**
+ * Clears the current list, freeing any laoded assets
+ */
+ void clear();
+
+ /**
+ * Add a sprite asset to the list
+ */
+ int add(SpriteAsset *asset, int idx = 0);
+
+ /**
+ * Adds a sprite asset to the list by name
+ */
+ int addSprites(const Common::String &resName, int flags = 0);
+
+ /**
+ * Remove an asset from the list
+ */
+ void remove(int idx);
+};
+
+} // End of namespace MADS
+
+#endif /* MADS_SPRITES_H */
diff --git a/engines/mads/staticres.cpp b/engines/mads/staticres.cpp
new file mode 100644
index 0000000000..189e5f72e7
--- /dev/null
+++ b/engines/mads/staticres.cpp
@@ -0,0 +1,58 @@
+/* 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 "mads/staticres.h"
+
+namespace MADS {
+
+const char *const kArticleList[9] = {
+ nullptr, "with", "to", "at", "from", "on", "in", "under", "behind"
+};
+
+const char *const kCheatingEnabledDesc[3] = {
+ "CHEATING ENABLED",
+ "(For your convenience).",
+ nullptr
+};
+
+const char *const kLookAroundStr = "Look around";
+const char *const kToStr = "to ";
+const char *const kUseStr = "Use ";
+const char *const kWalkToStr = "Walk to ";
+const char *const kFenceStr = "fence";
+const char *const kOverStr = "over";
+
+const char *const kGameReleaseInfoStr = "ScummVM rev: 8.43 14-Sept-92";
+const char *const kGameReleaseTitleStr = "GAME RELASE VERSION INFO";
+
+const uint32 DEFAULT_VGA_LOW_PALETTE[16] = {
+ 0x000000, 0x0000a8, 0x00a800, 0x00a8a8, 0xa80000, 0xa800a8, 0xa85400, 0xa8a8a8,
+ 0x545454, 0x5454fc, 0x54fc54, 0x54fcfc, 0xfc5454, 0xfc54fc, 0xfcfc54, 0xfcfcfc
+};
+
+const uint32 DEFAULT_VGA_HIGH_PALETTE[16] = {
+ 0x2c402c, 0x2c4030, 0x2c4034, 0x2c403c, 0x2c4040, 0x2c3c40, 0x2c3440, 0x2c3040,
+ 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000
+};
+
+} // End of namespace MADS
diff --git a/engines/mads/staticres.h b/engines/mads/staticres.h
new file mode 100644
index 0000000000..560fd12e67
--- /dev/null
+++ b/engines/mads/staticres.h
@@ -0,0 +1,47 @@
+/* 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.
+ *
+ */
+
+#ifndef MADS_STATICRES_H
+#define MADS_STATICRES_H
+
+namespace MADS {
+
+extern const char *const kArticleList[9];
+
+extern const char *const kCheatingEnabledDesc[3];
+
+extern const char *const kLookAroundStr;
+extern const char *const kToStr;
+extern const char *const kUseStr;
+extern const char *const kWalkToStr;
+extern const char *const kFenceStr;
+extern const char *const kOverStr;
+
+extern const char *const kGameReleaseInfoStr;
+extern const char *const kGameReleaseTitleStr;
+
+extern const uint32 DEFAULT_VGA_LOW_PALETTE[16];
+extern const uint32 DEFAULT_VGA_HIGH_PALETTE[16];
+
+} // End of namespace MADS
+
+#endif /* MADS_STATICRES_H */
diff --git a/engines/mads/user_interface.cpp b/engines/mads/user_interface.cpp
new file mode 100644
index 0000000000..e21a0f6243
--- /dev/null
+++ b/engines/mads/user_interface.cpp
@@ -0,0 +1,1092 @@
+/* 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 "mads/mads.h"
+#include "mads/compression.h"
+#include "mads/user_interface.h"
+#include "mads/nebular/game_nebular.h"
+
+namespace MADS {
+
+UISlot::UISlot() {
+ _flags = IMG_STATIC;
+ _segmentId = 0;
+ _spritesIndex = 0;
+ _frameNumber = 0;
+ _width = _height = 0;
+}
+
+/*------------------------------------------------------------------------*/
+
+void UISlots::fullRefresh() {
+ UISlot slot;
+ slot._flags = IMG_REFRESH;
+ slot._segmentId = -1;
+
+ push_back(slot);
+}
+
+void UISlots::add(const Common::Rect &bounds) {
+ assert(size() < 50);
+
+ UISlot ie;
+ ie._flags = IMG_OVERPRINT;
+ ie._segmentId = IMG_TEXT_UPDATE;
+ ie._position = Common::Point(bounds.left, bounds.top);
+ ie._width = bounds.width();
+ ie._height = bounds.height();
+
+ push_back(ie);
+}
+
+void UISlots::add(const AnimFrameEntry &frameEntry) {
+ assert(size() < 50);
+
+ UISlot ie;
+ ie._flags = IMG_UPDATE;
+ ie._segmentId = frameEntry._seqIndex;
+ ie._spritesIndex = frameEntry._spriteSlot._spritesIndex;
+ ie._frameNumber = frameEntry._spriteSlot._frameNumber;
+ ie._position = frameEntry._spriteSlot._position;
+
+ push_back(ie);
+}
+
+void UISlots::draw(bool updateFlag, bool delFlag) {
+ Scene &scene = _vm->_game->_scene;
+ UserInterface &userInterface = scene._userInterface;
+ DirtyArea *dirtyAreaPtr = nullptr;
+
+ // Loop through setting up the dirty areas
+ for (uint idx = 0; idx < size(); ++idx) {
+ DirtyArea &dirtyArea = userInterface._dirtyAreas[idx];
+ UISlot &slot = (*this)[idx];
+
+ if (slot._flags >= IMG_STATIC) {
+ dirtyArea._active = false;
+ } else {
+ dirtyArea.setUISlot(&slot);
+ dirtyArea._textActive = true;
+ if (slot._segmentId == IMG_SPINNING_OBJECT && slot._flags == IMG_FULL_UPDATE) {
+ dirtyArea._active = false;
+ dirtyAreaPtr = &dirtyArea;
+ }
+ }
+ }
+
+ userInterface._dirtyAreas.merge(1, userInterface._uiSlots.size());
+ if (dirtyAreaPtr)
+ dirtyAreaPtr->_active = true;
+
+ // Copy parts of the user interface background that need to be erased
+ for (uint idx = 0; idx < size(); ++idx) {
+ DirtyArea &dirtyArea = userInterface._dirtyAreas[idx];
+ UISlot &slot = (*this)[idx];
+
+ if (dirtyArea._active && dirtyArea._bounds.width() > 0
+ && dirtyArea._bounds.height() > 0 && slot._flags > -20) {
+
+ if (slot._flags >= IMG_ERASE) {
+ // Merge area
+ userInterface.mergeFrom(&userInterface._surface, dirtyArea._bounds,
+ Common::Point(dirtyArea._bounds.left, dirtyArea._bounds.top));
+ } else {
+ // Copy area
+ userInterface._surface.copyTo(&userInterface, dirtyArea._bounds,
+ Common::Point(dirtyArea._bounds.left, dirtyArea._bounds.top));
+ }
+ }
+ }
+
+ for (uint idx = 0; idx < size(); ++idx) {
+ DirtyArea &dirtyArea = userInterface._dirtyAreas[idx];
+ UISlot &slot = (*this)[idx];
+
+ int slotType = slot._flags;
+ if (slotType >= IMG_STATIC) {
+ dirtyArea.setUISlot(&slot);
+ if (!updateFlag)
+ slotType &= ~0x40;
+
+ dirtyArea._textActive = slotType > 0;
+ slot._flags &= 0x40;
+ }
+ }
+
+ userInterface._dirtyAreas.merge(1, userInterface._uiSlots.size());
+
+ for (uint idx = 0; idx < size(); ++idx) {
+ DirtyArea *dirtyArea = &userInterface._dirtyAreas[idx];
+ UISlot &slot = (*this)[idx];
+
+ if (slot._flags >= IMG_STATIC && !(slot._flags & 0x40)) {
+ if (!dirtyArea->_active) {
+ do {
+ dirtyArea = dirtyArea->_mergedArea;
+ } while (!dirtyArea->_active);
+ }
+
+ if (dirtyArea->_textActive) {
+ SpriteAsset *asset = scene._sprites[slot._spritesIndex];
+
+ // Get the frame details
+ int frameNumber = ABS(slot._frameNumber);
+ bool flipped = slot._frameNumber < 0;
+
+ if (slot._segmentId == IMG_SPINNING_OBJECT) {
+ MSprite *sprite = asset->getFrame(frameNumber);
+ sprite->copyTo(&userInterface, slot._position,
+ sprite->getTransparencyIndex());
+ } else {
+ MSprite *sprite = asset->getFrame(frameNumber - 1);
+
+ if (flipped) {
+ MSurface *spr = sprite->flipHorizontal();
+ userInterface.mergeFrom(spr, spr->getBounds(), slot._position,
+ sprite->getTransparencyIndex());
+ delete spr;
+ } else {
+ userInterface.mergeFrom(sprite, sprite->getBounds(), slot._position,
+ sprite->getTransparencyIndex());
+ }
+ }
+ }
+ }
+ }
+
+ // Mark areas of the screen surface for updating
+ if (updateFlag) {
+ for (uint idx = 0; idx < size(); ++idx) {
+ DirtyArea &dirtyArea = userInterface._dirtyAreas[idx];
+
+ if (dirtyArea._active && dirtyArea._textActive &&
+ dirtyArea._bounds.width() > 0 && dirtyArea._bounds.height() > 0) {
+ // Flag area of screen as needing update
+ Common::Rect r = dirtyArea._bounds;
+ r.translate(0, scene._interfaceY);
+ _vm->_screen.copyRectToScreen(r);
+ }
+ }
+ }
+
+ // Post-processing to remove slots no longer needed
+ for (int idx = (int)size() - 1; idx >= 0; --idx) {
+ UISlot &slot = (*this)[idx];
+
+ if (slot._flags < IMG_STATIC) {
+ if (delFlag || updateFlag)
+ remove_at(idx);
+ else if (slot._flags > -20)
+ slot._flags -= 20;
+ } else {
+ if (updateFlag)
+ slot._flags &= ~0x40;
+ else
+ slot._flags |= 0x40;
+ }
+ }
+}
+
+/*------------------------------------------------------------------------*/
+
+MADSEngine *Conversation::_vm;
+
+void Conversation::init(MADSEngine *vm) {
+ _vm = vm;
+}
+
+void Conversation::setup(int globalId, ...) {
+ va_list va;
+ va_start(va, globalId);
+
+ // Load the list of conversation quotes
+ _quotes.clear();
+ int quoteId = va_arg(va, int);
+ while (quoteId > 0) {
+ _quotes.push_back(quoteId);
+ quoteId = va_arg(va, int);
+ }
+ va_end(va);
+
+ if (quoteId < 0) {
+ // For an ending value of -1, also initial the bitflags for the global
+ // associated with the conversation entry, which enables all the quote Ids
+ _vm->_game->globals()[globalId] = (int16)0xffff;
+ }
+
+ _globalId = globalId;
+}
+
+void Conversation::set(int quoteId, ...) {
+ _vm->_game->globals()[_globalId] = 0;
+
+ va_list va;
+ va_start(va, quoteId);
+
+ // Loop through handling each quote
+ while (quoteId > 0) {
+ for (uint idx = 0; idx < _quotes.size(); ++idx) {
+ if (_quotes[idx] == quoteId) {
+ // Found index, so set that bit in the global keeping track of conversation state
+ _vm->_game->globals()[_globalId] |= 1 << idx;
+ break;
+ }
+ }
+
+ quoteId = va_arg(va, int);
+ }
+ va_end(va);
+}
+
+int Conversation::read(int quoteId) {
+ uint16 flags = _vm->_game->globals()[_globalId];
+ int count = 0;
+
+ for (uint idx = 0; idx < _quotes.size(); ++idx) {
+ if (flags & (1 << idx))
+ ++count;
+
+ if (_quotes[idx] == quoteId)
+ return flags & (1 << idx);
+ }
+
+ // Could not find it, simply return number of active quotes
+ return count;
+}
+
+void Conversation::write(int quoteId, bool flag) {
+ for (uint idx = 0; idx < _quotes.size(); ++idx) {
+ if (_quotes[idx] == quoteId) {
+ // Found index, so set or clear the flag
+ if (flag) {
+ // Set bit
+ _vm->_game->globals()[_globalId] |= 1 << idx;
+ } else {
+ // Clear bit
+ _vm->_game->globals()[_globalId] &= ~(1 << idx);
+ }
+ return;
+ }
+ }
+}
+
+void Conversation::start() {
+ UserInterface &userInterface = _vm->_game->_scene._userInterface;
+ userInterface.emptyConversationList();
+
+ // Loop through each of the quotes loaded into the conversation
+ for (uint idx = 0; idx < _quotes.size(); ++idx) {
+ // Check whether the given quote is enabled or not
+ if (_vm->_game->globals()[_globalId] & (1 << idx)) {
+ // Quote enabled, so add it to the list of talk selections
+ Common::String msg = _vm->_game->getQuote(_quotes[idx]);
+ userInterface.addConversationMessage(_quotes[idx], msg);
+ }
+ }
+
+ userInterface.setup(kInputConversation);
+}
+
+/*------------------------------------------------------------------------*/
+
+UserInterface::UserInterface(MADSEngine *vm) : _vm(vm), _dirtyAreas(vm),
+ _uiSlots(vm) {
+ _invSpritesIndex = -1;
+ _invFrameNumber = 1;
+ _scrollMilli = 0;
+ _scrollFlag = false;
+ _category = CAT_NONE;
+ _inventoryTopIndex = 0;
+ _selectedInvIndex = -1;
+ _selectedActionIndex = 0;
+ _selectedItemVocabIdx = -1;
+ _scrollbarActive = SCROLLBAR_NONE;
+ _scrollbarOldActive = SCROLLBAR_NONE;
+ _scrollbarStrokeType = SCROLLBAR_NONE;
+ _scrollbarQuickly = false;
+ _scrollbarMilliTime = 0;
+ _scrollbarElevator = _scrollbarOldElevator = 0;
+ _highlightedCommandIndex = -1;
+ _highlightedInvIndex = -1;
+ _highlightedItemVocabIndex = -1;
+ _dirtyAreas.resize(50);
+ _inventoryChanged = false;
+ Common::fill(&_categoryIndexes[0], &_categoryIndexes[7], 0);
+
+ // Map the user interface to the bottom of the game's screen surface
+ byte *pData = _vm->_screen.getBasePtr(0, MADS_SCENE_HEIGHT);
+ setPixels(pData, MADS_SCREEN_WIDTH, MADS_INTERFACE_HEIGHT);
+
+ _surface.setSize(MADS_SCREEN_WIDTH, MADS_INTERFACE_HEIGHT);
+}
+
+void UserInterface::load(const Common::String &resName) {
+ File f(resName);
+ MadsPack madsPack(&f);
+
+ // Load in the palette
+ Common::SeekableReadStream *palStream = madsPack.getItemStream(0);
+
+ uint32 *gamePalP = &_vm->_palette->_palFlags[0];
+ byte *palP = &_vm->_palette->_mainPalette[0];
+
+ for (int i = 0; i < 16; ++i, gamePalP++, palP += 3) {
+ RGB6 rgb;
+ rgb.load(palStream);
+ palP[0] = rgb.r;
+ palP[1] = rgb.g;
+ palP[2] = rgb.b;
+ *gamePalP |= 1;
+ }
+ delete palStream;
+
+ // Read in the surface data
+ Common::SeekableReadStream *pixelsStream = madsPack.getItemStream(1);
+ pixelsStream->read(_surface.getData(), MADS_SCREEN_WIDTH * MADS_INTERFACE_HEIGHT);
+ delete pixelsStream;
+}
+
+void UserInterface::setup(InputMode inputMode) {
+ Scene &scene = _vm->_game->_scene;
+
+ if (_vm->_game->_screenObjects._inputMode != inputMode) {
+ Common::String resName = _vm->_game->_aaName;
+
+ // Strip off any extension
+ const char *p = strchr(resName.c_str(), '.');
+ if (p) {
+ resName = Common::String(resName.c_str(), p);
+ }
+
+ // Add on suffix if necessary
+ if (inputMode != kInputBuildingSentences)
+ resName += "A";
+
+ resName += ".INT";
+
+ load(resName);
+ _surface.copyTo(this);
+ }
+ _vm->_game->_screenObjects._inputMode = inputMode;
+
+ scene._userInterface._uiSlots.clear();
+ scene._userInterface._uiSlots.fullRefresh();
+ _vm->_game->_screenObjects._baseTime = _vm->_events->getFrameCounter();
+ _highlightedCommandIndex = -1;
+ _highlightedItemVocabIndex = -1;
+ _highlightedInvIndex = -1;
+
+ if (_vm->_game->_kernelMode == KERNEL_ACTIVE_CODE)
+ scene._userInterface._uiSlots.draw(false, false);
+
+ scene._action.clear();
+ drawTextElements();
+ loadElements();
+ scene._dynamicHotspots.refresh();
+}
+
+void UserInterface::drawTextElements() {
+ if (_vm->_game->_screenObjects._inputMode) {
+ drawConversationList();
+ } else {
+ // Draw the actions
+ drawActions();
+ drawInventoryList();
+ drawItemVocabList();
+ }
+}
+
+void UserInterface::mergeFrom(MSurface *src, const Common::Rect &srcBounds,
+ const Common::Point &destPos, int transparencyIndex) {
+ // Validation of the rectangle and position
+ int destX = destPos.x, destY = destPos.y;
+ if ((destX >= w) || (destY >= h))
+ return;
+
+ Common::Rect copyRect = srcBounds;
+ if (destX < 0) {
+ copyRect.left += -destX;
+ destX = 0;
+ } else if (destX + copyRect.width() > w) {
+ copyRect.right -= destX + copyRect.width() - w;
+ }
+ if (destY < 0) {
+ copyRect.top += -destY;
+ destY = 0;
+ } else if (destY + copyRect.height() > h) {
+ copyRect.bottom -= destY + copyRect.height() - h;
+ }
+
+ if (!copyRect.isValidRect())
+ return;
+
+ // Copy the specified area
+
+ byte *data = src->getData();
+ byte *srcPtr = data + (src->getWidth() * copyRect.top + copyRect.left);
+ byte *destPtr = (byte *)this->pixels + (destY * getWidth()) + destX;
+
+ for (int rowCtr = 0; rowCtr < copyRect.height(); ++rowCtr) {
+ // Process each line of the area
+ for (int xCtr = 0; xCtr < copyRect.width(); ++xCtr) {
+ // Check for the range used for the user interface background,
+ // which are the only pixels that can be replaced
+ if ((destPtr[xCtr] >= 8 && destPtr[xCtr] <= 15) && (int)srcPtr[xCtr] != transparencyIndex)
+ destPtr[xCtr] = srcPtr[xCtr];
+ }
+
+ srcPtr += src->getWidth();
+ destPtr += getWidth();
+ }
+}
+
+void UserInterface::drawActions() {
+ for (int idx = 0; idx < 10; ++idx) {
+ writeVocab(CAT_COMMAND, idx);
+ }
+}
+
+void UserInterface::drawInventoryList() {
+ int endIndex = MIN((int)_vm->_game->_objects._inventoryList.size(), _inventoryTopIndex + 5);
+ for (int idx = _inventoryTopIndex; idx < endIndex; ++idx) {
+ writeVocab(CAT_INV_LIST, idx);
+ }
+}
+
+void UserInterface::drawItemVocabList() {
+ if (_selectedInvIndex >= 0) {
+ InventoryObject &io = _vm->_game->_objects[
+ _vm->_game->_objects._inventoryList[_selectedInvIndex]];
+ for (int idx = 0; idx < io._vocabCount; ++idx) {
+ writeVocab(CAT_INV_VOCAB, idx);
+ }
+ }
+}
+
+void UserInterface::drawScrolller() {
+ if (_scrollbarActive)
+ writeVocab(CAT_INV_SCROLLER, _scrollbarActive);
+ writeVocab(CAT_INV_SCROLLER, 4);
+}
+
+void UserInterface::updateInventoryScroller() {
+ ScreenObjects &screenObjects = _vm->_game->_screenObjects;
+ Common::Array<int> &inventoryList = _vm->_game->_objects._inventoryList;
+
+ if (screenObjects._inputMode != kInputBuildingSentences)
+ return;
+
+ _scrollbarActive = SCROLLBAR_NONE;
+
+ if ((screenObjects._category == CAT_INV_SCROLLER) || (screenObjects._category != CAT_INV_SCROLLER
+ && _scrollbarOldActive == SCROLLBAR_ELEVATOR && _vm->_events->_mouseStatusCopy)) {
+ if (_vm->_events->_mouseStatusCopy || _vm->_easyMouse) {
+ if ((_vm->_events->_mouseClicked || (_vm->_easyMouse && !_vm->_events->_mouseStatusCopy))
+ && (screenObjects._category == CAT_INV_SCROLLER))
+ _scrollbarStrokeType = (ScrollbarActive)screenObjects._spotId;
+
+ if (screenObjects._spotId == _scrollbarStrokeType || _scrollbarOldActive == SCROLLBAR_ELEVATOR) {
+ _scrollbarActive = _scrollbarStrokeType;
+ uint32 currentMilli = g_system->getMillis();
+ uint32 timeInc = _scrollbarQuickly ? 100 : 380;
+
+ if (_vm->_events->_mouseStatus && (_scrollbarMilliTime + timeInc) <= currentMilli) {
+ _scrollbarQuickly = _vm->_events->_vD2 < 1;
+ _scrollbarMilliTime = currentMilli;
+
+ switch (_scrollbarStrokeType) {
+ case SCROLLBAR_UP:
+ // Scroll up
+ if (_inventoryTopIndex > 0 && inventoryList.size() > 0) {
+ --_inventoryTopIndex;
+ _inventoryChanged = true;
+ }
+ break;
+
+ case SCROLLBAR_DOWN:
+ // Scroll down
+ if (_inventoryTopIndex < ((int)inventoryList.size() - 1) && inventoryList.size() > 1) {
+ ++_inventoryTopIndex;
+ _inventoryChanged = true;
+ }
+ break;
+
+ case SCROLLBAR_ELEVATOR: {
+ // Inventory slider
+ int newIndex = CLIP((int)_vm->_events->currentPos().y - 170, 0, 17)
+ * inventoryList.size() / 10;
+ if (newIndex >= (int)inventoryList.size())
+ newIndex = inventoryList.size() - 1;
+
+ if (inventoryList.size() > 0) {
+ _inventoryChanged = newIndex != _inventoryTopIndex;
+ _inventoryTopIndex = newIndex;
+ }
+ break;
+ }
+
+ default:
+ break;
+ }
+
+ if (_inventoryChanged) {
+ int dummy;
+ updateSelection(CAT_INV_LIST, 0, &dummy);
+ }
+ }
+ }
+ }
+ }
+
+ if (_scrollbarActive != _scrollbarOldActive || _scrollbarElevator != _scrollbarOldElevator)
+ scrollbarChanged();
+
+ _scrollbarOldActive = _scrollbarActive;
+ _scrollbarOldElevator = _scrollbarElevator;
+}
+
+void UserInterface::scrollbarChanged() {
+ Common::Rect r(73, 4, 73 + 9, 4 + 38);
+ _uiSlots.add(r);
+ _uiSlots.draw(false, false);
+ drawScrolller();
+ updateRect(r);
+}
+
+void UserInterface::writeVocab(ScrCategory category, int id) {
+ Common::Rect bounds;
+ if (!getBounds(category, id, bounds))
+ return;
+
+ Scene &scene = _vm->_game->_scene;
+ Font *font = nullptr;
+
+ int vocabId;
+ Common::String vocabStr;
+ switch (category) {
+ case CAT_COMMAND:
+ font = _vm->_font->getFont(FONT_INTERFACE);
+ vocabId = scene._verbList[id]._id;
+ if (id == _highlightedCommandIndex) {
+ _vm->_font->setColorMode(SELMODE_HIGHLIGHTED);
+ } else {
+ _vm->_font->setColorMode(id == _selectedActionIndex ? SELMODE_SELECTED : SELMODE_UNSELECTED);
+ }
+ vocabStr = scene.getVocab(vocabId);
+ vocabStr.setChar(toupper(vocabStr[0]), 0);
+ font->writeString(this, vocabStr, Common::Point(bounds.left, bounds.top));
+ break;
+
+ case CAT_INV_LIST:
+ font = _vm->_font->getFont(FONT_INTERFACE);
+ vocabId = _vm->_game->_objects.getItem(id)._descId;
+ if (id == _highlightedInvIndex) {
+ _vm->_font->setColorMode(SELMODE_HIGHLIGHTED);
+ } else {
+ _vm->_font->setColorMode(id == _selectedInvIndex ? SELMODE_SELECTED : SELMODE_UNSELECTED);
+ }
+
+ vocabStr = scene.getVocab(vocabId);
+ vocabStr.setChar(toupper(vocabStr[0]), 0);
+ font->writeString(this, vocabStr, Common::Point(bounds.left, bounds.top));
+ break;
+
+ case CAT_TALK_ENTRY:
+ font = _vm->_font->getFont(FONT_INTERFACE);
+ font->setColorMode(id == _highlightedCommandIndex ? SELMODE_HIGHLIGHTED : SELMODE_UNSELECTED);
+ font->writeString(this, _talkStrings[id], Common::Point(bounds.left, bounds.top));
+ break;
+
+ case CAT_INV_SCROLLER:
+ font = _vm->_font->getFont(FONT_MISC);
+
+ switch (id) {
+ case 1:
+ vocabStr = "a";
+ break;
+ case 2:
+ vocabStr = "b";
+ break;
+ case 3:
+ vocabStr = "d";
+ break;
+ case 4:
+ vocabStr = "c";
+ break;
+ default:
+ break;
+ }
+
+ font->setColorMode((id == 4) || (_scrollbarActive == SCROLLBAR_ELEVATOR) ?
+ SELMODE_HIGHLIGHTED : SELMODE_UNSELECTED);
+ font->writeString(this, vocabStr, Common::Point(bounds.left, bounds.top));
+ break;
+ default:
+ // Item specific verbs
+ font = _vm->_font->getFont(FONT_INTERFACE);
+ vocabId = _vm->_game->_objects.getItem(_selectedInvIndex)._vocabList[id]._vocabId;
+ if (id == _highlightedItemVocabIndex) {
+ _vm->_font->setColorMode(SELMODE_HIGHLIGHTED);
+ } else {
+ _vm->_font->setColorMode(id == _selectedInvIndex ? SELMODE_SELECTED : SELMODE_UNSELECTED);
+ vocabStr = scene.getVocab(vocabId);
+ vocabStr.setChar(toupper(vocabStr[0]), 0);
+ font->writeString(this, vocabStr, Common::Point(bounds.left, bounds.top));
+ break;
+ }
+ break;
+ }
+}
+
+void UserInterface::loadElements() {
+ Scene &scene = _vm->_game->_scene;
+ Common::Rect bounds;
+ _vm->_game->_screenObjects.clear();
+
+ if (_vm->_game->_screenObjects._inputMode == kInputBuildingSentences) {
+ // Set up screen objects for the inventory scroller
+ for (int idx = 1; idx <= 3; ++idx) {
+ getBounds(CAT_INV_SCROLLER, idx, bounds);
+ moveRect(bounds);
+
+ _vm->_game->_screenObjects.add(bounds, LAYER_GUI, CAT_INV_SCROLLER, idx);
+ }
+
+ // Set up actions
+ _categoryIndexes[CAT_COMMAND - 1] = _vm->_game->_screenObjects.size() + 1;
+ for (int idx = 0; idx < 10; ++idx) {
+ getBounds(CAT_COMMAND, idx, bounds);
+ moveRect(bounds);
+
+ _vm->_game->_screenObjects.add(bounds, LAYER_GUI, CAT_COMMAND, idx);
+ }
+
+ // Set up inventory list
+ _categoryIndexes[CAT_INV_LIST - 1] = _vm->_game->_screenObjects.size() + 1;
+ for (int idx = 0; idx < 5; ++idx) {
+ getBounds(CAT_INV_LIST, idx, bounds);
+ moveRect(bounds);
+
+ _vm->_game->_screenObjects.add(bounds, LAYER_GUI, CAT_INV_LIST, idx);
+ }
+
+ // Set up the inventory vocab list
+ _categoryIndexes[CAT_INV_VOCAB - 1] = _vm->_game->_screenObjects.size() + 1;
+ for (int idx = 0; idx < 5; ++idx) {
+ getBounds(CAT_INV_VOCAB, idx, bounds);
+ moveRect(bounds);
+
+ _vm->_game->_screenObjects.add(bounds, LAYER_GUI, CAT_INV_VOCAB, idx);
+ }
+
+ // Set up the inventory item picture
+ _categoryIndexes[CAT_INV_ANIM - 1] = _vm->_game->_screenObjects.size() + 1;
+ _vm->_game->_screenObjects.add(Common::Rect(160, 159, 231, 194), LAYER_GUI,
+ CAT_INV_ANIM, 0);
+ }
+
+ if (_vm->_game->_screenObjects._inputMode == kInputBuildingSentences ||
+ _vm->_game->_screenObjects._inputMode == kInputLimitedSentences) {
+ _categoryIndexes[CAT_HOTSPOT - 1] = _vm->_game->_screenObjects.size() + 1;
+ for (int hotspotIdx = scene._hotspots.size() - 1; hotspotIdx >= 0; --hotspotIdx) {
+ Hotspot &hs = scene._hotspots[hotspotIdx];
+ _vm->_game->_screenObjects.add(hs._bounds, LAYER_GUI, CAT_HOTSPOT, hotspotIdx);
+ }
+ }
+
+ if (_vm->_game->_screenObjects._inputMode == kInputConversation) {
+ // setup areas for talk entries
+ _categoryIndexes[CAT_TALK_ENTRY - 1] = _vm->_game->_screenObjects.size() + 1;
+ for (int idx = 0; idx < 5; ++idx) {
+ getBounds(CAT_TALK_ENTRY, idx, bounds);
+ moveRect(bounds);
+
+ _vm->_game->_screenObjects.add(bounds, LAYER_GUI, CAT_TALK_ENTRY, idx);
+ }
+ }
+
+ // Store the number of UI elements loaded for easy nuking/refreshing hotspots added later
+ _vm->_game->_screenObjects._uiCount = _vm->_game->_screenObjects.size();
+}
+
+bool UserInterface::getBounds(ScrCategory category, int v, Common::Rect &bounds) {
+ int heightMultiplier, widthMultiplier;
+ int leftStart, yOffset, widthAmt;
+
+ switch (category) {
+ case CAT_COMMAND:
+ heightMultiplier = v % 5;
+ widthMultiplier = v / 5;
+ leftStart = 2;
+ yOffset = 3;
+ widthAmt = 32;
+ break;
+
+ case CAT_INV_LIST:
+ if (v < _inventoryTopIndex || v >= (_inventoryTopIndex + 5))
+ return false;
+
+ heightMultiplier = v - _inventoryTopIndex;
+ widthMultiplier = 0;
+ leftStart = 90;
+ yOffset = 3;
+ widthAmt = 69;
+ break;
+
+ case CAT_TALK_ENTRY:
+ heightMultiplier = v;
+ widthMultiplier = 0;
+ leftStart = 2;
+ yOffset = 3;
+ widthAmt = 310;
+ break;
+
+ case CAT_INV_SCROLLER:
+ heightMultiplier = 0;
+ widthMultiplier = 0;
+ yOffset = 0;
+ widthAmt = 9;
+ leftStart = (v != 73) ? 73 : 75;
+ break;
+
+ default:
+ heightMultiplier = v;
+ widthMultiplier = 0;
+ leftStart = 240;
+ yOffset = 3;
+ widthAmt = 80;
+ break;
+ }
+
+ bounds.left = (widthMultiplier > 0) ? widthMultiplier * widthAmt + leftStart : leftStart;
+ bounds.setWidth(widthAmt);
+ bounds.top = heightMultiplier * 8 + yOffset;
+ bounds.setHeight(8);
+
+ if (category == CAT_INV_SCROLLER) {
+ switch (v) {
+ case SCROLLBAR_UP:
+ // Arrow up
+ bounds.top = 4;
+ bounds.setHeight(7);
+ break;
+ case SCROLLBAR_DOWN:
+ // Arrow down
+ bounds.top = 35;
+ bounds.setHeight(7);
+ break;
+ case SCROLLBAR_ELEVATOR:
+ // Scroller
+ bounds.top = 12;
+ bounds.setHeight(22);
+ break;
+ case SCROLLBAR_THUMB:
+ // Thumb
+ bounds.top = _scrollbarElevator + 14;
+ bounds.setHeight(1);
+ break;
+ default:
+ break;
+ }
+ }
+
+ return true;
+}
+
+void UserInterface::moveRect(Common::Rect &bounds) {
+ bounds.translate(0, MADS_SCENE_HEIGHT);
+}
+
+void UserInterface::drawConversationList() {
+ for (uint idx = 0; idx < _talkStrings.size(); ++idx) {
+ writeVocab(CAT_TALK_ENTRY, idx);
+ }
+}
+
+void UserInterface::emptyConversationList() {
+ _talkStrings.clear();
+ _talkIds.clear();
+}
+
+void UserInterface::addConversationMessage(int vocabId, const Common::String &msg) {
+ assert(_talkStrings.size() < 5);
+
+ _talkStrings.push_back(msg);
+ _talkIds.push_back(vocabId);
+}
+
+void UserInterface::loadInventoryAnim(int objectId) {
+ Scene &scene = _vm->_game->_scene;
+ noInventoryAnim();
+
+ if (_vm->_invObjectsAnimated) {
+ Common::String resName = Common::String::format("*OB%.3dI", objectId);
+ SpriteAsset *asset = new SpriteAsset(_vm, resName, 8);
+ _invSpritesIndex = scene._sprites.add(asset, 1);
+ if (_invSpritesIndex >= 0) {
+ _invFrameNumber = 1;
+ }
+ }
+}
+
+void UserInterface::noInventoryAnim() {
+ Scene &scene = _vm->_game->_scene;
+
+ if (_invSpritesIndex >= 0) {
+ scene._sprites.remove(_invSpritesIndex);
+ _vm->_game->_screenObjects._baseTime = _vm->_events->getFrameCounter();
+ _invSpritesIndex = -1;
+ }
+
+ if (_vm->_game->_screenObjects._inputMode == kInputBuildingSentences)
+ refresh();
+}
+
+void UserInterface::refresh() {
+ _uiSlots.clear();
+ _uiSlots.fullRefresh();
+ _uiSlots.draw(false, false);
+
+ drawTextElements();
+}
+
+void UserInterface::inventoryAnim() {
+ Scene &scene = _vm->_game->_scene;
+ if (_vm->_game->_screenObjects._inputMode == kInputConversation ||
+ _vm->_game->_screenObjects._inputMode == kInputLimitedSentences ||
+ _invSpritesIndex < 0)
+ return;
+
+ // Move to the next frame number in the sequence, resetting if at the end
+ SpriteAsset *asset = scene._sprites[_invSpritesIndex];
+ if (++_invFrameNumber > asset->getCount())
+ _invFrameNumber = 1;
+
+ // Loop through the slots list for inventory animation entry
+ for (uint i = 0; i < _uiSlots.size(); ++i) {
+ if (_uiSlots[i]._segmentId == IMG_SPINNING_OBJECT)
+ _uiSlots[i]._flags = IMG_FULL_UPDATE;
+ }
+
+ // Add a new slot entry for the inventory animation
+ UISlot slot;
+ slot._flags = IMG_UPDATE;
+ slot._segmentId = IMG_SPINNING_OBJECT;
+ slot._frameNumber = _invFrameNumber;
+ slot._spritesIndex = _invSpritesIndex;
+ slot._position = Common::Point(160, 3);
+
+ _uiSlots.push_back(slot);
+}
+
+void UserInterface::doBackgroundAnimation() {
+ Scene &scene = _vm->_game->_scene;
+ Common::Array<AnimUIEntry> &uiEntries = scene._animationData->_uiEntries;
+ Common::Array<AnimFrameEntry> &frameEntries = scene._animationData->_frameEntries;
+
+ _noSegmentsActive = !_someSegmentsActive;
+ _someSegmentsActive = false;
+
+ for (int idx = 0; idx < (int)uiEntries.size(); ++idx) {
+ AnimUIEntry &uiEntry = uiEntries[idx];
+
+ if (uiEntry._counter < 0) {
+ if (uiEntry._counter == -1) {
+ int probabilityRandom = _vm->getRandomNumber(1, 30000);
+ int probability = uiEntry._probability;
+ if (uiEntry._probability > 30000) {
+ if (_noSegmentsActive) {
+ probability -= 30000;
+ } else {
+ probability = -1;
+ }
+ }
+ if (probabilityRandom <= probability) {
+ uiEntry._counter = uiEntry._firstImage;
+ _someSegmentsActive = true;
+ }
+ } else {
+ uiEntry._counter = uiEntry._firstImage;
+ _someSegmentsActive = true;
+ }
+ } else {
+ for (int idx2 = 0; idx2 < ANIM_SPAWN_COUNT; idx2++) {
+ if (uiEntry._spawnFrame[idx2] == (uiEntry._counter - uiEntry._firstImage)) {
+ int tempIndex = uiEntry._spawn[idx2];
+ if (idx >= tempIndex) {
+ uiEntries[tempIndex]._counter = uiEntries[tempIndex]._firstImage;
+ } else {
+ uiEntries[tempIndex]._counter = -2;
+ }
+ _someSegmentsActive = true;
+ }
+ }
+
+ ++uiEntry._counter;
+ if (uiEntry._counter > uiEntry._lastImage) {
+ uiEntry._counter = -1;
+ } else {
+ _someSegmentsActive = true;
+ }
+ }
+ }
+
+ for (uint idx = 0; idx < uiEntries.size(); ++idx) {
+ int imgScan = uiEntries[idx]._counter;
+ if (imgScan >= 0) {
+ _uiSlots.add(frameEntries[imgScan]);
+ }
+ }
+}
+
+void UserInterface::categoryChanged() {
+ _highlightedInvIndex = -1;
+ _vm->_events->initVars();
+ _category = CAT_NONE;
+}
+
+void UserInterface::selectObject(int invIndex) {
+ if (_selectedInvIndex != invIndex || _inventoryChanged) {
+ int oldVocabCount = _selectedInvIndex < 0 ? 0 : _vm->_game->_objects.getItem(_selectedInvIndex)._vocabCount;
+ int newVocabCount = invIndex < 0 ? 0 : _vm->_game->_objects.getItem(invIndex)._vocabCount;
+ int maxVocab = MAX(oldVocabCount, newVocabCount);
+
+ updateSelection(CAT_INV_LIST, invIndex, &_selectedInvIndex);
+ _highlightedItemVocabIndex = -1;
+ _selectedItemVocabIdx = -1;
+
+ if (maxVocab) {
+ assert(_uiSlots.size() < 50);
+ int vocabHeight = maxVocab * 8;
+
+ Common::Rect bounds(240, 3, 240 + 80, 3 + vocabHeight);
+ _uiSlots.add(bounds);
+ _uiSlots.draw(false, false);
+ drawItemVocabList();
+ updateRect(bounds);
+ }
+ }
+
+ if (invIndex == -1) {
+ noInventoryAnim();
+ } else {
+ loadInventoryAnim(_vm->_game->_objects._inventoryList[invIndex]);
+ _vm->_palette->setPalette(_vm->_palette->_mainPalette, 7, 1);
+ _vm->_palette->setPalette(_vm->_palette->_mainPalette, 246, 2);
+ }
+}
+
+void UserInterface::updateSelection(ScrCategory category, int newIndex, int *idx) {
+ Game &game = *_vm->_game;
+ Common::Array<int> &invList = game._objects._inventoryList;
+ Common::Rect bounds;
+
+ if (category == CAT_INV_LIST && _inventoryChanged) {
+ *idx = newIndex;
+ bounds = Common::Rect(90, 3, 90 + 69, 3 + 40);
+ _uiSlots.add(bounds);
+ _uiSlots.draw(false, false);
+ drawInventoryList();
+ updateRect(bounds);
+ _inventoryChanged = false;
+
+ if (invList.size() < 2) {
+ _scrollbarElevator = 0;
+ } else {
+ int v = _inventoryTopIndex * 18 / (invList.size() - 1);
+ _scrollbarElevator = MIN(v, 17);
+ }
+ } else {
+ int oldIndex = *idx;
+ *idx = newIndex;
+
+ if (oldIndex >= 0) {
+ writeVocab(category, oldIndex);
+
+ if (getBounds(category, oldIndex, bounds))
+ updateRect(bounds);
+ }
+
+ if (newIndex >= 0) {
+ writeVocab(category, newIndex);
+
+ if (getBounds(category, newIndex, bounds))
+ updateRect(bounds);
+ }
+ }
+}
+
+void UserInterface::updateRect(const Common::Rect &bounds) {
+ Common::Rect r = bounds;
+ r.translate(0, MADS_SCENE_HEIGHT);
+ _vm->_screen.copyRectToScreen(r);
+}
+
+void UserInterface::scrollerChanged() {
+ warning("TODO: scrollerChanged");
+}
+
+void UserInterface::scrollInventory() {
+ Common::Array<int> &invList = _vm->_game->_objects._inventoryList;
+
+ if (_vm->_events->_mouseButtons) {
+ int yp = _vm->_events->currentPos().y;
+ if (yp < MADS_SCENE_HEIGHT || yp == (MADS_SCREEN_HEIGHT - 1)) {
+ uint32 timeDiff = _scrollFlag ? 100 : 380;
+ uint32 currentMilli = g_system->getMillis();
+ _vm->_game->_screenObjects._v8332A = -1;
+
+ if (currentMilli >= (_scrollMilli + timeDiff)) {
+ _scrollMilli = currentMilli;
+ _scrollFlag = true;
+
+ if (yp == (MADS_SCREEN_HEIGHT - 1)) {
+ if (_inventoryTopIndex < ((int)invList.size() - 1)) {
+ ++_inventoryTopIndex;
+ _inventoryChanged = true;
+ }
+ } else {
+ if (_inventoryTopIndex > 0) {
+ --_inventoryTopIndex;
+ _inventoryChanged = true;
+ }
+ }
+ }
+ }
+ }
+
+ _vm->_game->_screenObjects._v8332A = 0;
+}
+
+void UserInterface::synchronize(Common::Serializer &s) {
+ InventoryObjects &invObjects = _vm->_game->_objects;
+
+ if (s.isLoading()) {
+ _selectedInvIndex = invObjects._inventoryList.empty() ? -1 : 0;
+ }
+
+ for (int i = 0; i < 8; ++i)
+ s.syncAsSint16LE(_categoryIndexes[i]);
+}
+
+} // End of namespace MADS
diff --git a/engines/mads/user_interface.h b/engines/mads/user_interface.h
new file mode 100644
index 0000000000..827fa3041f
--- /dev/null
+++ b/engines/mads/user_interface.h
@@ -0,0 +1,306 @@
+/* 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.
+ *
+ */
+
+#ifndef MADS_USER_INTERFACE_H
+#define MADS_USER_INTERFACE_H
+
+#include "common/scummsys.h"
+#include "common/rect.h"
+#include "common/str.h"
+#include "mads/msurface.h"
+#include "mads/screen.h"
+
+namespace MADS {
+
+enum { IMG_SPINNING_OBJECT = 200, IMG_TEXT_UPDATE = 201 };
+
+enum ScrollbarActive {
+ SCROLLBAR_NONE = 0, // No state
+ SCROLLBAR_UP = 1, // Up butotn
+ SCROLLBAR_DOWN = 2, // Down button
+ SCROLLBAR_ELEVATOR = 3, // Elevator bar
+ SCROLLBAR_THUMB = 4 // Scrollbar thumb
+};
+
+class AnimFrameEntry;
+class MADSEngine;
+
+class UISlot {
+public:
+ int _flags;
+ int _segmentId;
+ int _spritesIndex;
+ int _frameNumber;
+ Common::Point _position;
+
+ // Only used for IMG_OVERPRINT
+ int _width;
+ int _height;
+
+ UISlot();
+};
+
+/**
+ * Sprite list for the user interface
+ */
+class UISlots : public Common::Array<UISlot> {
+private:
+ MADSEngine *_vm;
+public:
+ /**
+ * Constructor
+ */
+ UISlots(MADSEngine *vm) : _vm(vm) {}
+
+ /**
+ * Add an overprint (text) entry to the list
+ */
+ void add(const Common::Rect &bounds);
+
+ /**
+ * Loads the data from an aimation frame entry
+ */
+ void add(const AnimFrameEntry &frameEntry);
+
+ /**
+ * Adds a special entry for full refresh of the user interface
+ */
+ void fullRefresh();
+
+ /**
+ * Draw all the sprites in the list on the user interface.
+ * @param updateFlag Flag drawn areas to be updated on physical screen
+ * @param delFlag Controls how used slots are deleted after drawing
+ */
+ void draw(bool updateFlag, bool delFlag);
+};
+
+class Conversation {
+private:
+ static MADSEngine *_vm;
+public:
+ static void init(MADSEngine *vm);
+public:
+ int _globalId;
+ Common::Array<int> _quotes;
+
+ /**
+ * Set up a conversation sequence
+ */
+ void setup(int globalId, ...);
+
+ /**
+ * Activates the passed set of quotes in the given conversation node
+ */
+ void set(int quoteId, ...);
+
+ /**
+ * Returns the bit for a given quote to indicate whether it's active or not or,
+ * if 0 is passed, returns the number of currently active quotes
+ */
+ int read(int quoteId);
+
+ /**
+ * Activates or deactivates the specified quote in the given conversation node
+ */
+ void write(int quoteId, bool flag);
+
+ /**
+ * Starts the conversation
+ */
+ void start();
+};
+
+class UserInterface : public MSurface {
+ friend class UISlots;
+private:
+ MADSEngine *_vm;
+ int _invSpritesIndex;
+ int _invFrameNumber;
+ uint32 _scrollMilli;
+ bool _scrollFlag;
+ int _noSegmentsActive;
+ int _someSegmentsActive;
+ ScrollbarActive _scrollbarStrokeType;
+
+ /**
+ * Loads the elements of the user interface
+ */
+ void loadElements();
+
+ /**
+ * Returns the area within the user interface a given element falls
+ */
+ bool getBounds(ScrCategory category, int invIndex, Common::Rect &bounds);
+
+ /**
+ * Reposition a bounding rectangle to physical co-ordinates
+ */
+ void moveRect(Common::Rect &bounds);
+
+ /**
+ * Draw options during a conversation.
+ */
+ void drawConversationList();
+
+ /**
+ * Draw the action list
+ */
+ void drawActions();
+
+ /**
+ * Draw the inventory list
+ */
+ void drawInventoryList();
+
+ /**
+ * Draw the inventory item vocab list
+ */
+ void drawItemVocabList();
+
+ /**
+ * Draw the inventory scroller
+ */
+ void drawScrolller();
+
+ /**
+ * Called when the inventory scrollbar has changed
+ */
+ void scrollbarChanged();
+
+ /**
+ * Draw a UI textual element
+ */
+ void writeVocab(ScrCategory category, int id);
+
+ void refresh();
+
+ void updateRect(const Common::Rect &bounds);
+public:
+ MSurface _surface;
+ UISlots _uiSlots;
+ DirtyAreas _dirtyAreas;
+ ScrCategory _category;
+ Common::Rect *_rectP;
+ int _inventoryTopIndex;
+ int _selectedInvIndex;
+ int _selectedActionIndex;
+ int _selectedItemVocabIdx;
+ ScrollbarActive _scrollbarActive, _scrollbarOldActive;
+ int _highlightedCommandIndex;
+ int _highlightedInvIndex;
+ int _highlightedItemVocabIndex;
+ bool _inventoryChanged;
+ int _categoryIndexes[8];
+ Common::StringArray _talkStrings;
+ Common::Array<int> _talkIds;
+ bool _scrollbarQuickly;
+ uint32 _scrollbarMilliTime;
+ int _scrollbarElevator, _scrollbarOldElevator;
+public:
+ /**
+ * Constructor
+ */
+ UserInterface(MADSEngine *vm);
+
+ /**
+ * Loads an interface from a specified resource
+ */
+ void load(const Common::String &resName);
+
+ /**
+ * Set up the interface
+ */
+ void setup(InputMode inputMode);
+
+ void drawTextElements();
+
+ /**
+ * Merges a sub-section of another surface into the user interface without
+ * destroying any on-screen text
+ * @param src Source surface
+ * @param srcBounds Area to copy/merge from
+ * @param destPos Destination position to draw in current surface
+ * @param transparencyIndex Transparency color
+ */
+ void mergeFrom(MSurface *src, const Common::Rect &srcBounds, const Common::Point &destPos,
+ int transparencyIndex = -1);
+
+ /**
+ * Loads the animation sprite data for a given inventory object
+ */
+ void loadInventoryAnim(int objectId);
+
+ /**
+ * Resets the inventory animation when no inventory item is selected
+ */
+ void noInventoryAnim();
+
+ /**
+ * Handles any animation that occurs in the background of the user interface
+ */
+ void doBackgroundAnimation();
+
+ /**
+ * Handles queuing a new frame of an inventory animation for drawing
+ */
+ void inventoryAnim();
+
+ void categoryChanged();
+
+ /**
+ * Select an item from the inventory list
+ * @param invIndex Index in the inventory list of the item to select
+ */
+ void selectObject(int invIndex);
+
+ void updateSelection(ScrCategory category, int newIndex, int *idx);
+
+ void scrollerChanged();
+
+ void scrollInventory();
+
+ /**
+ * Checks for the mouse being on the user interface inventory scroller,
+ * and update the scroller highlight and selected inventory object as necessary
+ */
+ void updateInventoryScroller();
+
+ /**
+ * Empties the current conversation talk list
+ */
+ void emptyConversationList();
+
+ /**
+ * Add a msesage to the list of conversation items to select from
+ */
+ void addConversationMessage(int vocabId, const Common::String &msg);
+
+ /**
+ * Synchronize the data
+ */
+ void synchronize(Common::Serializer &s);
+};
+
+} // End of namespace MADS
+
+#endif /* MADS_USER_INTERFACE_H */