diff options
author | Eugene Sandulenko | 2014-05-26 15:37:26 +0300 |
---|---|---|
committer | Eugene Sandulenko | 2014-05-26 15:37:26 +0300 |
commit | ef22b7d449b66a7b953e0584c6ab5db9bdd948b9 (patch) | |
tree | 253fd1cb8ebb005dc8b04ce8aee633c7c1070f52 /engines | |
parent | f7269dd7dc8418b014670c71681899db33c8bbcc (diff) | |
parent | dfe6ae9d593a17acfe5bd9bb68d44ce497eeea20 (diff) | |
download | scummvm-rg350-ef22b7d449b66a7b953e0584c6ab5db9bdd948b9.tar.gz scummvm-rg350-ef22b7d449b66a7b953e0584c6ab5db9bdd948b9.tar.bz2 scummvm-rg350-ef22b7d449b66a7b953e0584c6ab5db9bdd948b9.zip |
Merge pull request #464 from dreammaster/mads
MADS: Merge of Rex Nebular game engine
Diffstat (limited to 'engines')
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 = ¶m2; + } else { + str = ¶m1; + + 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 ¤tNode = _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 */ |