diff options
| author | Paul Gilbert | 2015-04-10 23:35:26 -0500 | 
|---|---|---|
| committer | Paul Gilbert | 2015-04-10 23:35:26 -0500 | 
| commit | 96e04ab797253bbe853f172ea1d734ebe812d419 (patch) | |
| tree | 4647c733d4d3684e6c722c3f84d7fbef9c660ba8 | |
| parent | d45d1672137843d028c4ddf63ccf9b62d5d72976 (diff) | |
| download | scummvm-rg350-96e04ab797253bbe853f172ea1d734ebe812d419.tar.gz scummvm-rg350-96e04ab797253bbe853f172ea1d734ebe812d419.tar.bz2 scummvm-rg350-96e04ab797253bbe853f172ea1d734ebe812d419.zip | |
SHERLOCK: Implemented doScript and support methods
| -rw-r--r-- | engines/sherlock/animation.cpp | 2 | ||||
| -rw-r--r-- | engines/sherlock/events.cpp | 8 | ||||
| -rw-r--r-- | engines/sherlock/events.h | 2 | ||||
| -rw-r--r-- | engines/sherlock/inventory.cpp | 112 | ||||
| -rw-r--r-- | engines/sherlock/inventory.h | 9 | ||||
| -rw-r--r-- | engines/sherlock/people.cpp | 2 | ||||
| -rw-r--r-- | engines/sherlock/people.h | 2 | ||||
| -rw-r--r-- | engines/sherlock/scene.cpp | 16 | ||||
| -rw-r--r-- | engines/sherlock/scripts.cpp | 11 | ||||
| -rw-r--r-- | engines/sherlock/scripts.h | 6 | ||||
| -rw-r--r-- | engines/sherlock/sherlock.cpp | 6 | ||||
| -rw-r--r-- | engines/sherlock/sound.cpp | 7 | ||||
| -rw-r--r-- | engines/sherlock/sound.h | 4 | ||||
| -rw-r--r-- | engines/sherlock/talk.cpp | 833 | ||||
| -rw-r--r-- | engines/sherlock/talk.h | 31 | ||||
| -rw-r--r-- | engines/sherlock/user_interface.cpp | 10 | 
16 files changed, 1002 insertions, 59 deletions
| diff --git a/engines/sherlock/animation.cpp b/engines/sherlock/animation.cpp index e1687b5238..4674151ec7 100644 --- a/engines/sherlock/animation.cpp +++ b/engines/sherlock/animation.cpp @@ -144,7 +144,7 @@ bool Animation::playPrologue(const Common::String &filename, int minDelay, int f  					Common::String::format("%s%01d", baseName.c_str(), soundNumber) :  					Common::String::format("%s%02d", baseName.c_str(), soundNumber); -				if (sound._voicesOn) +				if (sound._voices)  					sound.playSound(fname);  			} diff --git a/engines/sherlock/events.cpp b/engines/sherlock/events.cpp index d147fe1f4c..67d09e52b2 100644 --- a/engines/sherlock/events.cpp +++ b/engines/sherlock/events.cpp @@ -101,6 +101,14 @@ bool Events::isCursorVisible() const {  }  /** + * Move the mouse + */ +void Events::moveMouse(const Common::Point &pt) { +	g_system->warpMouse(pt.x, pt.y); +} + + +/**   * Check for any pending events   */  void Events::pollEvents() { diff --git a/engines/sherlock/events.h b/engines/sherlock/events.h index c3bdaf5a93..71f7623002 100644 --- a/engines/sherlock/events.h +++ b/engines/sherlock/events.h @@ -72,6 +72,8 @@ public:  	bool isCursorVisible() const; +	void moveMouse(const Common::Point &pt); +  	void pollEvents();  	void pollEventsAndWait(); diff --git a/engines/sherlock/inventory.cpp b/engines/sherlock/inventory.cpp index e58c4ddac6..0ea85f32fc 100644 --- a/engines/sherlock/inventory.cpp +++ b/engines/sherlock/inventory.cpp @@ -366,4 +366,116 @@ void Inventory::doInvJF() {  	}  } +/** + * Adds a shape from the scene to the player's inventory + */ +int Inventory::putNameInInventory(const Common::String &name) { +	Scene &scene = *_vm->_scene; +	int matches = 0; + +	for (uint idx = 0; idx < scene._bgShapes.size(); ++idx) { +		Object &o = scene._bgShapes[idx]; +		if (scumm_stricmp(name.c_str(), o._name.c_str()) == 0 && o._type != INVALID) { +			putItemInInventory(o); +			++matches; +		} +	} + +	return matches; +} + +/** + * Moves a specified item into the player's inventory If the item has a *PICKUP* use action, + * then the item in the use action are added to the inventory. + */ +int Inventory::putItemInInventory(Object &obj) { +	Scene &scene = *_vm->_scene; +	int matches = 0; +	bool pickupFound = false; + +	if (obj._pickupFlag) +		_vm->setFlags(obj._pickupFlag); + +	for (int useNum = 0; useNum < 4; ++useNum) { +		if (scumm_stricmp(obj._use[useNum]._target.c_str(), "*PICKUP*") == 0) { +			pickupFound = true; + +			for (int namesNum = 0; namesNum < 4; ++namesNum) { +				for (uint bgNum = 0; bgNum < scene._bgShapes.size(); ++bgNum) { +					Object &bgObj = scene._bgShapes[bgNum]; +					if (scumm_stricmp(obj._use[useNum]._names[namesNum].c_str(), bgObj._name.c_str()) == 0) { +						copyToInventory(bgObj); +						if (bgObj._pickupFlag) +							_vm->setFlags(bgObj._pickupFlag); + +						if (bgObj._type == ACTIVE_BG_SHAPE || bgObj._type == NO_SHAPE || bgObj._type == HIDE_SHAPE) { +							if (bgObj._imageFrame == nullptr || bgObj._frameNumber < 0) +								// No shape to erase, so flag as hidden +								bgObj._type = INVALID; +							else +								bgObj._type = REMOVE; +						} else if (bgObj._type == HIDDEN) { +							bgObj._type = INVALID; +						} + +						++matches; +					} +				} +			} +		} +	} + +	if (!pickupFound) { +		// No pickup item found, so add the passed item +		copyToInventory(obj); +		matches = 0; +	} + +	if (matches == 0) { +		if (!pickupFound) +			matches = 1; + +		if (obj._type == ACTIVE_BG_SHAPE || obj._type == NO_SHAPE || obj._type == HIDE_SHAPE) { +			if (obj._imageFrame == nullptr || obj._frameNumber < 0) +				// No shape to erase, so flag as hidden +				obj._type = INVALID; +			else +				obj._type = REMOVE; +		} else if (obj._type == HIDDEN) { +			obj._type = INVALID; +		} +	} + +	return matches; +} + +/** + * Copy the passed object into the inventory + */ +void Inventory::copyToInventory(Object &obj) { +	// TODO +} + +/** + * Deletes a specified item from the player's inventory + */ +int Inventory::deleteItemFromInventory(const Common::String &name) { +	int invNum = -1; + +	for (int idx = 0; idx < (int)size() && invNum == -1; ++idx) { +		if (scumm_stricmp(name.c_str(), (*this)[idx]._name.c_str()) == 0) +			invNum = idx; +	} + +	if (invNum == -1) +		// Item not present +		return 0; + +	// Item found, so delete it +	remove_at(invNum); +	--_holdings; + +	return 1; +} +  } // End of namespace Sherlock diff --git a/engines/sherlock/inventory.h b/engines/sherlock/inventory.h index 55abc4c960..722692a3b2 100644 --- a/engines/sherlock/inventory.h +++ b/engines/sherlock/inventory.h @@ -26,6 +26,7 @@  #include "common/scummsys.h"  #include "common/array.h"  #include "common/str-array.h" +#include "sherlock/objects.h"  #include "sherlock/resources.h"  namespace Sherlock { @@ -59,6 +60,10 @@ struct InventoryItem {  class Inventory : public Common::Array<InventoryItem> {  private:  	SherlockEngine *_vm; + +	int putItemInInventory(Object &obj); + +	void copyToInventory(Object &obj);  public:  	ImageFile *_invShapes[MAX_VISIBLE_INVENTORY];  	Common::StringArray _names; @@ -90,6 +95,10 @@ public:  	void highlight(int index, byte color);  	void doInvJF(); + +	int putNameInInventory(const Common::String &name); + +	int deleteItemFromInventory(const Common::String &name);  };  } // End of namespace Sherlock diff --git a/engines/sherlock/people.cpp b/engines/sherlock/people.cpp index 3da35f2fec..9319fbb79d 100644 --- a/engines/sherlock/people.cpp +++ b/engines/sherlock/people.cpp @@ -61,6 +61,8 @@ People::People(SherlockEngine *vm) : _vm(vm), _player(_data[0]) {  	_clearingThePortrait = false;  	_srcZone = _destZone = 0;  	_talkPics = nullptr; +	_portraitSide = 0; +	_speakerFlip = false;  }  People::~People() { diff --git a/engines/sherlock/people.h b/engines/sherlock/people.h index a1fad019c8..1a846dded1 100644 --- a/engines/sherlock/people.h +++ b/engines/sherlock/people.h @@ -77,6 +77,8 @@ public:  	Object _portrait;  	bool _clearingThePortrait;  	bool _allowWalkAbort; +	int _portraitSide; +	bool _speakerFlip;  public:  	People(SherlockEngine *vm);  	~People(); diff --git a/engines/sherlock/scene.cpp b/engines/sherlock/scene.cpp index 7c66a1dc62..3d5f566164 100644 --- a/engines/sherlock/scene.cpp +++ b/engines/sherlock/scene.cpp @@ -89,7 +89,8 @@ Scene::Scene(SherlockEngine *vm): _vm(vm) {  	_currentScene = -1;  	_goToScene = -1;  	_changes = false; -	_charPoint = _oldCharPoint = 0; +	_charPoint = 0; +	_oldCharPoint = 39;  	_keyboardInput = 0;  	_walkedInScene = false;  	_ongoingCans = 0; @@ -118,7 +119,7 @@ void Scene::selectScene() {  	Events &events = *_vm->_events;  	People &people = *_vm->_people;  	Screen &screen = *_vm->_screen; -	Scripts &scripts = *_vm->_scripts; +	Talk &talk = *_vm->_talk;  	UserInterface &ui = *_vm->_ui;  	// Reset fields @@ -150,8 +151,8 @@ void Scene::selectScene() {  	// If there were any scripst waiting to be run, but were interrupt by a running  	// canimation (probably the last scene's exit canim), clear the _scriptMoreFlag -	if (scripts._scriptMoreFlag == 3) -		scripts._scriptMoreFlag = 0; +	if (talk._scriptMoreFlag == 3) +		talk._scriptMoreFlag = 0;  }  /** @@ -1053,7 +1054,6 @@ void Scene::doBgAnim() {  	Inventory &inv = *_vm->_inventory;  	People &people = *_vm->_people;  	Screen &screen = *_vm->_screen; -	Scripts &scripts = *_vm->_scripts;  	Sound &sound = *_vm->_sound;  	Talk &talk = *_vm->_talk;  	UserInterface &ui = *_vm->_ui; @@ -1359,10 +1359,10 @@ void Scene::doBgAnim() {  	// Check if the method was called for calling a portrait, and a talk was  	// interrupting it. This talk file would not have been executed at the time,   	// since we needed to finish the 'doBgAnim' to finish clearing the portrait -	if (people._clearingThePortrait && scripts._scriptMoreFlag == 3) { +	if (people._clearingThePortrait && talk._scriptMoreFlag == 3) {  		// Reset the flags and call to talk -		people._clearingThePortrait = scripts._scriptMoreFlag = 0; -		talk.talkTo(scripts._scriptName); +		people._clearingThePortrait = talk._scriptMoreFlag = 0; +		talk.talkTo(talk._scriptName);  	}  } diff --git a/engines/sherlock/scripts.cpp b/engines/sherlock/scripts.cpp index d337030bae..02dcfa6f0b 100644 --- a/engines/sherlock/scripts.cpp +++ b/engines/sherlock/scripts.cpp @@ -26,21 +26,16 @@  namespace Sherlock {  Scripts::Scripts(SherlockEngine *vm): _vm(vm) { -	_scriptMoreFlag = 0; -	_scriptSaveIndex = 0; -	_scriptSelect = 0; -} -void Scripts::doScript(const Common::String &str) { -	// TODO  }  void Scripts::popStack() { +	/*  	ScriptEntry script = _scriptStack.pop();  	_scriptName = script._name; -	_scriptSaveIndex = script._index; +//	_scriptSaveIndex = script._index;  	_scriptSelect = script._select; -	_scriptMoreFlag = true; +	*/  } diff --git a/engines/sherlock/scripts.h b/engines/sherlock/scripts.h index 6765687bcf..beea726c8d 100644 --- a/engines/sherlock/scripts.h +++ b/engines/sherlock/scripts.h @@ -40,11 +40,7 @@ class Scripts {  private:  	SherlockEngine *_vm;  public: -	Common::Stack<ScriptEntry> _scriptStack; -	int _scriptMoreFlag; -	Common::String _scriptName; -	int _scriptSaveIndex; -	int _scriptSelect; +  public:  	Scripts(SherlockEngine *vm); diff --git a/engines/sherlock/sherlock.cpp b/engines/sherlock/sherlock.cpp index 20a805594e..2a1b456b76 100644 --- a/engines/sherlock/sherlock.cpp +++ b/engines/sherlock/sherlock.cpp @@ -122,10 +122,10 @@ void SherlockEngine::sceneLoop() {  	while (!shouldQuit() && _scene->_goToScene == -1) {  		// See if a script needs to be completed from either a goto room code,  		// or a script that was interrupted by another script -		if (_scripts->_scriptMoreFlag == 1 || _scripts->_scriptMoreFlag == 3) -			_talk->talkTo(_scripts->_scriptName); +		if (_talk->_scriptMoreFlag == 1 || _talk->_scriptMoreFlag == 3) +			_talk->talkTo(_talk->_scriptName);  		else -			_scripts->_scriptMoreFlag = 0; +			_talk->_scriptMoreFlag = 0;  		// Handle any input from the keyboard or mouse  		handleInput(); diff --git a/engines/sherlock/sound.cpp b/engines/sherlock/sound.cpp index 5e7df5607f..771d5db9d5 100644 --- a/engines/sherlock/sound.cpp +++ b/engines/sherlock/sound.cpp @@ -27,7 +27,8 @@ namespace Sherlock {  Sound::Sound(SherlockEngine *vm): _vm(vm) {  	_soundOn = true;  	_musicOn = true; -	_voicesOn = true; +	_speechOn = true; +	_voices = 0;  	_playingEpilogue = false;  	_music = false;  	_digitized = false; @@ -89,5 +90,9 @@ void Sound::freeSong() {  	// TODO  } +void Sound::stopSndFuncPtr(int v1, int v2) { +	// TODO +} +  } // End of namespace Sherlock diff --git a/engines/sherlock/sound.h b/engines/sherlock/sound.h index 74e8db3611..22d5a5c221 100644 --- a/engines/sherlock/sound.h +++ b/engines/sherlock/sound.h @@ -40,7 +40,8 @@ private:  public:  	bool _soundOn;  	bool _musicOn; -	bool _voicesOn; +	bool _speechOn; +	int _voices;  	bool _playingEpilogue;  	bool _music;  	bool _digitized; @@ -64,6 +65,7 @@ public:  	void playMusic(const Common::String &name);  	void stopMusic(); +	void stopSndFuncPtr(int v1, int v2);  };  } // End of namespace Sherlock diff --git a/engines/sherlock/talk.cpp b/engines/sherlock/talk.cpp index d284ace8b8..193c0f9a19 100644 --- a/engines/sherlock/talk.cpp +++ b/engines/sherlock/talk.cpp @@ -26,7 +26,42 @@  namespace Sherlock { -#define SFX_COMMAND 140 +enum { +	SWITCH_SPEAKER				= 128, +	RUN_CANIMATION				= 129, +	ASSIGN_PORTRAIT_LOCATION	= 130, +	PAUSE						= 131, +	REMOVE_PORTRAIT				= 132, +	CLEAR_WINDOW				= 133, +	ADJUST_OBJ_SEQUENCE			= 134, +	WALK_TO_COORDS				= 135, +	PAUSE_WITHOUT_CONTROL		= 136, +	BANISH_WINDOW				= 137, +	SUMMON_WINDOW				= 138, +	SET_FLAG					= 139, +	SFX_COMMAND					= 140, +	TOGGLE_OBJECT				= 141, +	STEALTH_MODE_ACTIVE			= 142, +	IF_STATEMENT				= 143, +	ELSE_STATEMENT				= 144, +	END_IF_STATEMENT			= 145, +	STEALTH_MODE_DEACTIVATE		= 146, +	TURN_HOLMES_OFF				= 147, +	TURN_HOLMES_ON				= 148, +	GOTO_SCENE					= 149, +	PLAY_PROLOGUE				= 150, +	ADD_ITEM_TO_INVENTORY		= 151, +	SET_OBJECT					= 152, +	CALL_TALK_FILE				= 153, +	MOVE_MOUSE					= 154, +	DISPLAY_INFO_LINE			= 155, +	CLEAR_INFO_LINE				= 156, +	WALK_TO_CANIMATION			= 157, +	REMOVE_ITEM_FROM_INVENTORY	= 158, +	ENABLE_END_KEY				= 159, +	DISABLE_END_KEY				= 160, +	COMMAND_161					= 161 +};  /*----------------------------------------------------------------*/ @@ -99,6 +134,9 @@ Talk::Talk(SherlockEngine *vm): _vm(vm) {  	_talkStealth = 0;  	_talkToFlag = -1;  	_moreTalkDown = _moreTalkUp = false; +	_scriptMoreFlag = 1; +	_scriptSaveIndex = -1; +	_scriptCurrentIndex = -1;  }  void Talk::setSequences(const byte *talkSequences, const byte *stillSequences, int maxPeople) { @@ -136,13 +174,13 @@ void Talk::talkTo(const Common::String &filename) {  	// save the filename for later executing when the canimation is done  	if (scene._ongoingCans || people._clearingThePortrait) {  		// Make sure we're not in the middle of a script -		if (!scripts._scriptMoreFlag) { -			scripts._scriptName = filename; -			scripts._scriptSaveIndex = 0; +		if (!_scriptMoreFlag) { +			_scriptName = filename; +			_scriptSaveIndex = 0;  			// Flag the selection, since we don't yet know which statement yet -			scripts._scriptSelect = 100; -			scripts._scriptMoreFlag = 3; +			_scriptSelect = 100; +			_scriptMoreFlag = 3;  		}  		return; @@ -172,7 +210,7 @@ void Talk::talkTo(const Common::String &filename) {  	// If any sequences have changed in the prior talk file, restore them  	if (_savedSequences.size() > 0) {  		for (uint idx = 0; idx < _savedSequences.size(); ++idx) { -			SavedSequence &ss = _savedSequences[idx]; +			SequenceEntry &ss = _savedSequences[idx];  			for (uint idx2 = 0; idx2 < _savedSequences.size(); ++idx2)  				scene._bgShapes[ss._objNum]._sequences[idx2] = ss._sequences[idx2]; @@ -181,7 +219,7 @@ void Talk::talkTo(const Common::String &filename) {  		}  	} -	while (!_sequenceStack.empty()) +	while (!_scriptStack.empty())  		pullSequence();  	// Restore any pressed button @@ -276,7 +314,7 @@ void Talk::talkTo(const Common::String &filename) {  			select = _talkIndex = idx;  	} -	if (scripts._scriptMoreFlag && _scriptSelect != 0) +	if (_scriptMoreFlag && _scriptSelect != 0)  		select = _scriptSelect;  	if (select == -1) @@ -288,7 +326,7 @@ void Talk::talkTo(const Common::String &filename) {  	_talkHistory[_converseNum][select] = true;  	// Check if the talk file is meant to be a non-seen comment -	if (filename[7] != '*') { +	if (filename.size() < 8 || filename[7] != '*') {  		// Should we start in stealth mode?  		if (_statements[select]._statement.hasPrefix("^")) {  			_talkStealth = 2; @@ -305,13 +343,13 @@ void Talk::talkTo(const Common::String &filename) {  		// Handle replies until there's no further linked file,   		// or the link file isn't a reply first cnversation -		for (;;) { +		while (!_vm->shouldQuit()) {  			clearSequences();  			_scriptSelect = select;  			_speaker = _talkTo;  			Statement &statement = _statements[select]; -			scripts.doScript(_statements[select]._reply); +			doScript(_statements[select]._reply);  			if (_talkToAbort)  				return; @@ -327,7 +365,7 @@ void Talk::talkTo(const Common::String &filename) {  			}  			// Check for a linked file -			if (!statement._linkFile.empty() && !scripts._scriptMoreFlag) { +			if (!statement._linkFile.empty() && !_scriptMoreFlag) {  				freeTalkVars();  				loadTalkFile(statement._linkFile); @@ -422,7 +460,7 @@ void Talk::talkTo(const Common::String &filename) {  	// If a script was added to the script stack, restore state so that the  	// previous script can continue -	if (!scripts._scriptStack.empty()) { +	if (!_scriptStack.empty()) {  		scripts.popStack();  	} @@ -547,7 +585,7 @@ void Talk::loadTalkFile(const Common::String &filename) {  	// Check for an existing person being talked to  	_talkTo = -1;  	for (int idx = 0; idx < MAX_PEOPLE; ++idx) { -		if (scumm_strnicmp(filename.c_str(), people[(PeopleId)idx]._portrait.c_str(), 4)) { +		if (!scumm_strnicmp(filename.c_str(), people[(PeopleId)idx]._portrait.c_str(), 4)) {  			_talkTo = idx;  			break;  		} @@ -568,7 +606,7 @@ void Talk::loadTalkFile(const Common::String &filename) {  	delete talkStream; -	if (!sound._voicesOn) +	if (!sound._voices)  		stripVoiceCommands();  	setTalkMap();  } @@ -833,7 +871,7 @@ int Talk::talkLine(int lineNum, int stateNum, byte color, int lineY, bool slamIt   * Clears the stack of pending object sequences associated with speakers in the scene   */  void Talk::clearSequences() { -	_sequenceStack.clear(); +	_scriptStack.clear();  }  /** @@ -843,7 +881,7 @@ void Talk::clearSequences() {  void Talk::pullSequence() {  	Scene &scene = *_vm->_scene; -	SequenceEntry seq = _sequenceStack.pop(); +	SequenceEntry seq = _scriptStack.pop();  	if (seq._objNum != -1) {  		Object &obj = scene._bgShapes[seq._objNum]; @@ -871,7 +909,7 @@ void Talk::pushSequence(int speaker) {  	if (speaker == -1)  		return; -	SequenceEntry seqEntry; +	ScriptStackEntry seqEntry;  	if (!speaker) {  		seqEntry._objNum = -1;  	} else { @@ -885,9 +923,13 @@ void Talk::pushSequence(int speaker) {  		seqEntry._seqTo = obj._seqTo;  	} -	_sequenceStack.push(seqEntry); -	if (_sequenceStack.size() >= 5) -		error("sequence stack overflow"); +	_scriptStack.push(seqEntry); +	if (_scriptStack.size() >= 5) +		error("script stack overflow"); +} + +void Talk::setSequence(int speaker) { +	// TODO  }  /** @@ -923,4 +965,751 @@ void Talk::setStillSeq(int speaker) {  	}  } +/** + * Parses a reply for control codes and display text. The found text is printed within + * the text window, handles delays, animations, and animating portraits. + */ +void Talk::doScript(const Common::String &script) { +	Animation &anim = *_vm->_animation; +	Events &events = *_vm->_events; +	Inventory &inv = *_vm->_inventory; +	People &people = *_vm->_people; +	Scene &scene = *_vm->_scene; +	Screen &screen = *_vm->_screen; +	Sound &sound = *_vm->_sound; +	UserInterface &ui = *_vm->_ui; +	int wait = 0; +	bool pauseFlag = false; +	bool endStr = false; +	int yp = CONTROLS_Y + 12; +	int charCount = 0; +	int line = 0; +	bool noTextYet = true; +	bool openTalkWindow = false; +	int obj; +	int seqCount; + +	_saveSeqNum = 0; + +	const char *str = script.c_str(); +	if (_scriptMoreFlag) { +		_scriptMoreFlag = 0; +		str = script.c_str() + _scriptSaveIndex; +	} + +	// Check if the script begins with a Stealh Mode Active command +	if (str[0] == STEALTH_MODE_ACTIVE || _talkStealth) { +		_talkStealth = 2; +		_speaker |= 128; +	} else { +		pushSequence(_speaker); +		ui.clearWindow(); + +		// Need to switch speakers? +		if (str[0] == SWITCH_SPEAKER) { +			_speaker = str[1] - 1; +			str += 2; +			pullSequence(); +			pushSequence(_speaker); +			setSequence(_speaker); +		} +		else { +			setSequence(_speaker); +		} + +		// Assign portrait location? +		if (str[0] == ASSIGN_PORTRAIT_LOCATION) { +			switch (str[1] & 15) { +			case 1: +				people._portraitSide = 20; +				break; +			case 2: +				people._portraitSide = 220; +				break; +			case 3: +				people._portraitSide = 120; +				break; +			default: +				break; + +			} + +			if (str[1] > 15) +				people._speakerFlip = true; +			str += 2; +		} + +		// Remove portrait? +		if (str[0] == REMOVE_PORTRAIT) { +			_speaker = 255; +		} +		else { +			// Nope, so set the first speaker +			setTalking(_speaker); +		} +	} + +	do { +		Common::String tempString; +		wait = 0; + +		if (!str[0]) { +			endStr = true; +		} else if (str[0] == '{') { +			// Start of comment, so skip over it +			while (*str++ != '}') +				; +		} else if (str[0] >= 128) { +			// Handle control code +			switch (str[0]) { +			case SWITCH_SPEAKER: +				// Save the current point in the script, since it might be intterupted by +				// doing bg anims in the next call, so we need to know where to return to +				_scriptCurrentIndex = str - script.c_str(); + +				if (!(_speaker & 128)) +					clearTalking(); +				if (_talkToAbort) +					return; + +				ui.clearWindow(); +				yp = CONTROLS_Y + 12; +				charCount = line = 0; + +				_speaker = *++str - 1; +				setTalking(_speaker); +				pullSequence(); +				pushSequence(_speaker); +				setSequence(_speaker); +				break; + +			case RUN_CANIMATION: +				// Save the current point in the script, since it might be intterupted by +				// doing bg anims in the next call, so we need to know where to return to +				_scriptCurrentIndex = str - script.c_str(); +				scene.startCAnim((str[0] - 1) & 127, 1 + (str[0] & 128)); +				if (_talkToAbort) +					return; + +				// Check if next character is changing side or changing portrait +				if (charCount && (str[1] == SWITCH_SPEAKER || str[1] == ASSIGN_PORTRAIT_LOCATION)) +					wait = 1; +				break; + +			case ASSIGN_PORTRAIT_LOCATION: +				++str; +				switch (str[0] & 15) { +				case 1: +					people._portraitSide = 20; +					break; +				case 2: +					people._portraitSide = 220; +					break; +				case 3: +					people._portraitSide = 120; +					break; +				default: +					break; +				} + +				if (str[0] > 15) +					people._speakerFlip = true; +				break; + +			case PAUSE: +				// Pause +				charCount = *++str; +				wait = pauseFlag = true; +				break; + +			case REMOVE_PORTRAIT: +				// Save the current point in the script, since it might be intterupted by +				// doing bg anims in the next call, so we need to know where to return to +				_scriptCurrentIndex = str - script.c_str(); + +				if (_speaker < 128) +					clearTalking(); +				pullSequence(); +				if (_talkToAbort) +					return; + +				_speaker |= 128; +				break; + +			case CLEAR_WINDOW: +				ui.clearWindow(); +				yp = CONTROLS_Y + 12; +				charCount = line = 0; +				break; + +			case ADJUST_OBJ_SEQUENCE: +				// Get the name of the object to adjust +				++str; +				for (int idx = 0; idx < (str[0] & 127); ++idx) +					tempString += str[idx + 2]; + +				// Scan for object +				obj = -1; +				for (uint idx = 0; idx < scene._bgShapes.size(); ++idx) { +					if (scumm_stricmp(tempString.c_str(), scene._bgShapes[idx]._name.c_str()) == 0) +						obj = idx; +				} +				if (obj == -1) +					error("Could not find object %s to change", tempString.c_str()); + +				// Should the script be overwritten? +				if (str[0] > 128) { +					// Save the current sequence +					_savedSequences.push(SequenceEntry()); +					SequenceEntry &seqEntry = _savedSequences.top(); +					seqEntry._objNum = obj; +					seqEntry._seqTo = scene._bgShapes[obj]._seqTo; +					for (uint idx = 0; idx < scene._bgShapes[obj]._seqSize; ++idx) +						seqEntry._sequences.push_back(scene._bgShapes[obj]._sequences[idx]); +				} + +				// Get number of bytes to change +				seqCount = str[1]; +				str += (str[0] & 127) + 2; + +				// Copy in the new sequence +				for (int idx = 0; idx < seqCount; ++idx, ++str) +					scene._bgShapes[obj]._sequences[idx] = str[0] - 1; + +				// Reset object back to beginning of new sequence +				scene._bgShapes[obj]._frameNumber = 0; +				continue; + +			case WALK_TO_COORDS: +				// Save the current point in the script, since it might be intterupted by +				// doing bg anims in the next call, so we need to know where to return to +				_scriptCurrentIndex = str - script.c_str(); + +				people.walkToCoords(Common::Point(((str[0] - 1) * 256 + str[1] - 1) * 100, str[2] * 100), str[3] - 1); +				if (_talkToAbort) +					return; + +				str += 3; +				break; + +			case PAUSE_WITHOUT_CONTROL: +				// Save the current point in the script, since it might be intterupted by +				// doing bg anims in the next call, so we need to know where to return to +				_scriptCurrentIndex = str - script.c_str(); + +				for (int idx = 0; idx < (str[0] - 1); ++idx) { +					scene.doBgAnim(); +					if (_talkToAbort) +						return; + +					// Check for button press +					events.pollEvents(); +					events.setButtonState(); +				} +				break; + +			case BANISH_WINDOW: +				// Save the current point in the script, since it might be intterupted by +				// doing bg anims in the next call, so we need to know where to return to +				_scriptCurrentIndex = str - script.c_str(); + +				if (!(_speaker & 128)) +					clearTalking(); +				pullSequence(); + +				if (_talkToAbort) +					return; + +				_speaker |= 128; +				ui.banishWindow(); +				ui._menuMode = TALK_MODE; +				noTextYet = true; +				break; + +			case SUMMON_WINDOW: +				drawInterface(); +				events._pressed = events._released = false; +				events.clearKeyboard(); +				noTextYet = false; + +				if (_speaker != -1) { +					screen.buttonPrint(Common::Point(119, CONTROLS_Y), COMMAND_NULL, false, "Exit"); +					screen.buttonPrint(Common::Point(159, CONTROLS_Y), COMMAND_NULL, false, "Up"); +					screen.buttonPrint(Common::Point(200, CONTROLS_Y), COMMAND_NULL, false, "Down"); +				} +				break; + +			case SET_FLAG: { +				++str; +				int flag1 = (str[0] - 1) * 256 + str[1] - 1 - (str[1] == 1 ? 1 : 0); +				int flag = (flag1 & 0x7fff) * (flag1 >= 0x8000 ? -1 : 1); +				_vm->setFlags(flag); +				++str; +				break; +			} +				 +			case SFX_COMMAND: +				++str; +				if (sound._voices) { +					for (int idx = 0; idx < 8 && str[idx] != '~'; ++idx) +						tempString += str[idx]; +					sound.playSound(tempString); + +					// Set voices to wait for more +					sound._voices = 2; +					sound._speechOn = (*sound._soundIsOn); +				} + +				wait = 1; +				str += 7; +				break; + +			case TOGGLE_OBJECT: +				for (int idx = 0; idx < str[0]; ++idx) +					tempString += str[idx + 1]; + +				scene.toggleObject(tempString); +				str += str[0]; +				break; + +			case STEALTH_MODE_ACTIVE: +				_talkStealth = 2; +				break; + +			case IF_STATEMENT: { +				++str; +				int flag = (str[0] - 1) * 256 + str[1] - 1 - (str[1] == 1 ? 1 : 0); +				++str; +				wait = 0; +				 +				bool result = flag < 0x8000; +				if (_vm->readFlags(flag & 0x7fff) != result) { +					do { +						++str; +					} while (str[0] && str[0] != ELSE_STATEMENT && str[0] != END_IF_STATEMENT); + +					if (!str[0]) +						endStr = true; +				} +				break; +			} + +			case ELSE_STATEMENT: +				// If this is encountered here, it means that a preceeding IF statement was found, +				// and evaluated to true. Now all the statements for the true block are finished, +				// so skip over the block of code that would have executed if the result was false +				wait = 0; +				do { +					++str; +				} while (str[0] && str[0] != END_IF_STATEMENT); +				break; + +			case STEALTH_MODE_DEACTIVATE: +				_talkStealth = 0; +				events.clearKeyboard(); +				break; + +			case TURN_HOLMES_OFF: +				people._holmesOn = false; +				break; + +			case TURN_HOLMES_ON: +				people._holmesOn = true; +				break; + +			case GOTO_SCENE: +				scene._goToScene = str[1] - 1; + +				if (scene._goToScene != 100) { +					// Not going to the map overview +					scene._oldCharPoint = scene._goToScene; +					scene._overPos.x = _vm->_map[scene._goToScene].x * 100 - 600; +					scene._overPos.y = _vm->_map[scene._goToScene].y * 100 + 900; + +					// Run a canimation? +					if (str[2] > 100) { +						scene._hsavedFs = str[2]; +						scene._hsavedPos = Common::Point(160, 100); +					} +				} +				str += 6; + +				_scriptMoreFlag = (scene._goToScene == 100) ? 2 : 1; +				_scriptSaveIndex = str - script.c_str(); +				endStr = true; +				wait = 0; +				break; + +			case PLAY_PROLOGUE: +				++str; +				for (int idx = 0; idx < 8 && str[idx] != '~'; ++idx) +					tempString += str[idx]; + +				anim.playPrologue(tempString, 1, 3, true, 4); +				break; + +			case ADD_ITEM_TO_INVENTORY: +				++str; +				for (int idx = 0; idx < str[0]; ++idx) +					tempString += str[idx]; +				str += str[0]; + +				inv.putNameInInventory(tempString); +				break; + +			case SET_OBJECT: { +				++str; +				for (int idx = 0; idx < (str[0] & 127); ++idx) +					tempString += str[idx + 1]; +				str += str[0]; + +				// Set comparison state according to if we want to hide or unhide +				bool state = (str[0] >= 128); + +				for (uint idx = 0; idx < scene._bgShapes.size(); ++idx) { +					Object &obj = scene._bgShapes[idx]; +					if (scumm_stricmp(tempString.c_str(), obj._name.c_str()) == 0) { +						// Only toggle the object if it's not in the desired state already +						if ((obj._type == HIDDEN && state) || (obj._type != HIDDEN && !state)) +							obj.toggleHidden(); +					} +				} +				break; +			} + +			case CALL_TALK_FILE: +				++str; +				for (int idx = 0; idx < 8 && str[idx] != '~'; ++idx) +					tempString += str[idx]; +				str += 8; + +				_scriptCurrentIndex = str - script.c_str(); + +				// Save the current script position and new talk file +				if (_scriptStack.size() < 10) { +					ScriptStackEntry rec; +					rec._name = _scriptName; +					rec._currentIndex = _scriptCurrentIndex; +					rec._select = _scriptSelect; +				} else { +					error("Script stack overflow"); +				} + +				_scriptMoreFlag = true; +				endStr = true; +				wait = 0; +				break; + +			case MOVE_MOUSE: +				// Save the current point in the script, since it might be intterupted by +				// doing bg anims in the next call, so we need to know where to return to +				_scriptCurrentIndex = str - script.c_str(); +				events.moveMouse(Common::Point((str[0] - 1) * 256 + str[1] - 1, str[2])); +				if (_talkToAbort) +					return; +				str += 3; +				break; + +			case DISPLAY_INFO_LINE: +				++str; +				for (int idx = 0; idx < str[0]; ++idx) +					tempString += str[idx + 1]; +				str += str[0]; + +				screen.print(Common::Point(0, INFO_LINE + 1), INFO_FOREGROUND, tempString.c_str()); +				break; + +			case CLEAR_INFO_LINE: +				ui._infoFlag = true; +				ui.clearInfo(); +				break; + +			case WALK_TO_CANIMATION: { +				++str; +				int animIndex = str[0] - 1; + +				// Save the current point in the script, since it might be intterupted by +				// doing bg anims in the next call, so we need to know where to return to +				_scriptCurrentIndex = (str + 1) - script.c_str(); +				if (_talkToAbort) +					return; +				break; +			} + +			case REMOVE_ITEM_FROM_INVENTORY: +				++str; +				for (int idx = 0; idx < str[0]; ++idx) +					tempString += str[idx + 1]; +				str += str[0]; + +				inv.deleteItemFromInventory(tempString); +				break; + +			case ENABLE_END_KEY: +				ui._endKeyActive = true; +				break; + +			case DISABLE_END_KEY: +				ui._endKeyActive = false; +				break; + +			default: +				break; +			} + +			++str; +		} else { +			// If the window isn't yet open, draw the window before printing starts +			if (!ui._windowOpen && noTextYet) { +				noTextYet = false; +				drawInterface(); + +				if (_talkTo != -1) { +					screen.buttonPrint(Common::Point(119, CONTROLS_Y), COMMAND_NULL, false, "Exit"); +					screen.buttonPrint(Common::Point(159, CONTROLS_Y), COMMAND_NULL, false, "Up"); +					screen.buttonPrint(Common::Point(200, CONTROLS_Y), COMMAND_NULL, false, "Down"); +				} +			} + +			// If it's the first line, display the speaker +			if (!line && _speaker >= 0 && _speaker < MAX_PEOPLE) { +				// If the window is open, display the name directly on-screen. +				// Otherwise, simply draw it on the back buffer +				if (ui._windowOpen) { +					screen.print(Common::Point(16, yp), TALK_FOREGROUND, inv._names[_speaker & 127].c_str()); +				} else { +					screen.gPrint(Common::Point(16, yp - 1), TALK_FOREGROUND, inv._names[_speaker & 127].c_str()); +					openTalkWindow = true; +				} + +				yp += 9; +			} + +			// Find amound of text that will fit on the line +			int width = 0, idx = 0; +			do { +				width += screen.charWidth(str[idx]); +			} while (width < 298 && str[idx] && str[idx] != '{' && str[idx] < 128); + +			if (str[idx] || width >= 298) { +				if (str[idx] < 128 && str[idx] != '{') { +					--idx; +					--charCount; +				} +			} else { +				endStr = true; +			} + +			// If word wrap is needed, find the start of the current word +			if (width >= 298) { +				while (str[idx] != ' ') { +					--idx; +					--charCount; +				} +			} + +			// Print the line +			Common::String lineStr(str, str + idx); + +			// If the speaker indicates a description file, print it in yellow +			if (_speaker != -1) { +				if (ui._windowOpen) { +					screen.print(Common::Point(16, yp), INV_FOREGROUND, lineStr.c_str()); +				} else { +					screen.gPrint(Common::Point(16, yp - 1), INV_FOREGROUND, lineStr.c_str()); +				} +			} else { +				if (ui._windowOpen) { +					screen.print(Common::Point(16, yp), COMMAND_FOREGROUND, lineStr.c_str()); +				} +				else { +					screen.gPrint(Common::Point(16, yp - 1), COMMAND_FOREGROUND, lineStr.c_str()); +				} +			} + +			// Move to end of displayed line +			str += idx; + +			// If line wrap occurred, then move to after the separating space between the words +			if (str[0] < 128 && str[0] != '{') +				++str; + +			yp += 9; +			++line; + +			// Certain different conditions require a wait +			if ((line == 4 && str[0] != SFX_COMMAND && str[0] != PAUSE && _speaker != -1) || +					(line == 5 && str[0] != PAUSE && _speaker != -1) || +					endStr) { +				wait = 1; +			} + +			switch (str[0]) { +			case SWITCH_SPEAKER: +			case ASSIGN_PORTRAIT_LOCATION: +			case BANISH_WINDOW: +			case IF_STATEMENT: +			case ELSE_STATEMENT: +			case END_IF_STATEMENT: +			case GOTO_SCENE: +			case CALL_TALK_FILE: +				wait = 1; +				break; +			default: +				break; +			} +		} + +		// Open window if it wasn't already open, and text has already been printed +		if ((openTalkWindow && wait) || (openTalkWindow && str[0] >= 128 && str[0] != COMMAND_161)) { +			if (!ui._windowStyle) { +				screen.slamRect(Common::Rect(0, CONTROLS_Y, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT)); +			} else { +				ui.summonWindow(); +			} + +			ui._windowOpen = true; +			openTalkWindow = false; +		} + +		if (wait) { +			// Save the current point in the script, since it might be intterupted by +			// doing bg anims in the next call, so we need to know where to return to +			_scriptCurrentIndex = str - script.c_str(); + +			// Handling pausing +			if (!pauseFlag && charCount < 160) +				charCount = 160; + +			wait = waitForMore(charCount); +			if (wait == -1) +				endStr = true; + +			// If a key was pressed to finish the window, see if further voice files should be skipped +			if (wait >= 0 && wait < 254) { +				if (str[0] == SFX_COMMAND) +					str += 9; +			} + +			// Clear the window unless the wait was due to a PAUSE command +			if (!pauseFlag && wait != -1 && str[0] != SFX_COMMAND) { +				if (!_talkStealth) +					ui.clearWindow(); +				yp = CONTROLS_Y + 12; +				charCount = line = 0; +			} + +			pauseFlag = false; +		} +	} while (!_vm->shouldQuit() && !endStr); + +	if (wait != -1) { +		for (int ssIndex = 0; ssIndex < (int)_savedSequences.size(); ++ssIndex) { +			SequenceEntry &seq = _savedSequences[ssIndex]; +			Object &obj = scene._bgShapes[seq._objNum]; + +			for (uint idx = 0; idx < seq._sequences.size(); ++idx) +				obj._sequences[idx] = seq._sequences[idx]; +			obj._frameNumber = seq._frameNumber; +			obj._seqTo = seq._seqTo; +		} + +		pullSequence(); +		if (_speaker < 128) +			clearTalking(); +	} +} + +void Talk::clearTalking() { +	// TODO +} + +void Talk::setTalking(int speaker) { +	// TODO +} + +/** + * When the talk window has been displayed, waits a period of time proportional to + * the amount of text that's been displayed + */ +int Talk::waitForMore(int delay) { +	Events &events = *_vm->_events; +	People &people = *_vm->_people; +	Scene &scene = *_vm->_scene; +	Sound &sound = *_vm->_sound; +	UserInterface &ui = *_vm->_ui; +	CursorId oldCursor = events.getCursor(); +	int key2 = 254; + +	// Unless we're in stealth mode, show the appropriate cursor +	if (!_talkStealth) { +		events.setCursor(ui._lookScriptFlag ? MAGNIFY : ARROW); +	} + +	do { +		if (sound._speechOn && !*sound._soundIsOn) +			people._portrait._frameNumber = -1; + +		scene.doBgAnim(); + +		// If talkTo call was done via doBgAnim, abort out of talk quietly +		if (_talkToAbort) { +			key2 = -1; +			events._released = true; +		} else { +			// See if there's been a button press +			events.setButtonState(); + +			if (events.kbHit()) { +				Common::KeyState keyState = events.getKey(); +				if (keyState.keycode >= 32 && keyState.keycode < 128) +					key2 = keyState.keycode; +			} + +			if (_talkStealth) { +				key2 = 254; +				events._released = false; +			} +		} + +		// Count down the delay +		if ((delay > 0 && !ui._invLookFlag && !ui._lookScriptFlag) || _talkStealth) +			--delay; + +		// If there are voices playing, reset delay so that they keep playing +		if (sound._voices == 2 && *sound._soundIsOn) +			delay = 0; +	} while (!_vm->shouldQuit() && key2 == 254 && (delay || (sound._voices == 2 && *sound._soundIsOn)) +		&& !events._released && !events._rightReleased); + +	// If voices was set 2 to indicate a voice file was place, then reset it back to 1 +	if (sound._voices == 2) +		sound._voices = 1; + +	if (delay > 0 && sound._diskSoundPlaying) +		sound.stopSndFuncPtr(0, 0); + +	// Adjust _talkStealth mode: +	// mode 1 - It was by a pause without stealth being on before the pause, so reset back to 0 +	// mode 3 - It was set by a pause with stealth being on before the pause, to set it to active +	// mode 0/2 (Inactive/active) No change +	switch (_talkStealth) { +	case 1: +		_talkStealth = 0; +		break; +	case 2: +		_talkStealth = 2; +		break; +	default: +		break; +	} + +	sound._speechOn = false; +	events.setCursor(_talkToAbort ? ARROW : oldCursor); +	events._pressed = events._released = false; + +	return key2; +} + +  } // End of namespace Sherlock diff --git a/engines/sherlock/talk.h b/engines/sherlock/talk.h index 48cdd2b5b2..1b679a47bd 100644 --- a/engines/sherlock/talk.h +++ b/engines/sherlock/talk.h @@ -33,16 +33,19 @@ namespace Sherlock {  #define MAX_TALK_SEQUENCES 11 -struct SavedSequence { +struct SequenceEntry {  	int _objNum;  	Common::Array<byte> _sequences; -}; - -struct SequenceEntry : public SavedSequence {  	int _frameNumber;  	int _seqTo;  }; +struct ScriptStackEntry : public SequenceEntry { +	Common::String _name; +	int _currentIndex; +	int _select; +}; +  struct Statement {  	Common::String _statement;  	Common::String _reply; @@ -84,8 +87,8 @@ private:  private:  	SherlockEngine *_vm;  	int _saveSeqNum; -	Common::Array<SavedSequence> _savedSequences; -	Common::Stack<SequenceEntry> _sequenceStack; +	Common::Stack<SequenceEntry> _savedSequences; +	Common::Stack<ScriptStackEntry> _scriptStack;  	Common::Array<Statement> _statements;  	TalkHistoryEntry _talkHistory[500];  	int _speaker; @@ -95,17 +98,28 @@ private:  	int _talkStealth;  	int _talkToFlag;  	bool _moreTalkUp, _moreTalkDown; - +	int _scriptSaveIndex; +	int _scriptCurrentIndex; +private:  	void stripVoiceCommands();  	void setTalkMap();  	bool displayTalk(bool slamIt);  	int talkLine(int lineNum, int stateNum, byte color, int lineY, bool slamIt); + +	void doScript(const Common::String &script); + +	void clearTalking(); +	void setTalking(int speaker); + +	int waitForMore(int delay);  public:  	bool _talkToAbort;  	int _talkCounter;  	int _talkTo; +	int _scriptMoreFlag; +	Common::String _scriptName;  public:  	Talk(SherlockEngine *vm);  	void setSequences(const byte *talkSequences, const byte *stillSequences, @@ -127,7 +141,8 @@ public:  	void clearSequences();  	void pullSequence();  	void pushSequence(int speaker); -	bool isSequencesEmpty() const { return _sequenceStack.empty(); } +	void setSequence(int speaker); +	bool isSequencesEmpty() const { return _scriptStack.empty(); }  };  } // End of namespace Sherlock diff --git a/engines/sherlock/user_interface.cpp b/engines/sherlock/user_interface.cpp index 289bff814f..88265f6a19 100644 --- a/engines/sherlock/user_interface.cpp +++ b/engines/sherlock/user_interface.cpp @@ -122,7 +122,6 @@ void UserInterface::handleInput() {  	People &people = *_vm->_people;  	Scene &scene = *_vm->_scene;  	Screen &screen = *_vm->_screen; -	Scripts &scripts = *_vm->_scripts;  	Talk &talk = *_vm->_talk;  	if (_menuCounter) @@ -148,7 +147,7 @@ void UserInterface::handleInput() {  	}  	// Do button highlighting check -	if (!scripts._scriptMoreFlag) {	// Don't if scripts are running +	if (!talk._scriptMoreFlag) {	// Don't if scripts are running  		if (((events._rightPressed || events._rightReleased) && _helpStyle) ||  				(!_helpStyle && !_menuCounter)) {  			// Handle any default commands if we're in STD_MODE @@ -532,6 +531,13 @@ void UserInterface::examine() {  			_vm->setFlags(inv[_selector]._lookFlag);  	} +	if (_invLookFlag) { +		// Dont close the inventory window when starting an examine display, since it's +		// window will slide up to replace the inventory display +		_windowOpen = false; +		_menuMode = LOOK_MODE; +	} +  	if (!talk._talkToAbort) {  		if (!scene._cAnimFramePause)  			printObjectDesc(_cAnimStr, true); | 
