diff options
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 */  | 
