diff options
| author | Paul Gilbert | 2015-05-24 18:59:25 -0400 | 
|---|---|---|
| committer | Paul Gilbert | 2015-05-24 18:59:25 -0400 | 
| commit | 8a808654c8a342711fa34bdfbee29296496902d8 (patch) | |
| tree | 5d3e904a6b24669bc68dd4c03d8b9b73dca86648 /engines/sherlock/talk.cpp | |
| parent | 55ab34b981cf58e3e650926713bf72729adaa311 (diff) | |
| download | scummvm-rg350-8a808654c8a342711fa34bdfbee29296496902d8.tar.gz scummvm-rg350-8a808654c8a342711fa34bdfbee29296496902d8.tar.bz2 scummvm-rg350-8a808654c8a342711fa34bdfbee29296496902d8.zip  | |
SHERLOCK: Splitting Talk up to implement individual opcode methods
Diffstat (limited to 'engines/sherlock/talk.cpp')
| -rw-r--r-- | engines/sherlock/talk.cpp | 1029 | 
1 files changed, 627 insertions, 402 deletions
diff --git a/engines/sherlock/talk.cpp b/engines/sherlock/talk.cpp index bc473f755f..9b22ee1c82 100644 --- a/engines/sherlock/talk.cpp +++ b/engines/sherlock/talk.cpp @@ -231,6 +231,13 @@ void TalkSequences::clear() {  /*----------------------------------------------------------------*/ +Talk *Talk::init(SherlockEngine *vm) { +	if (vm->getGameID() == GType_SerratedScalpel) +		return new ScalpelTalk(vm); +	else +		return new TattooTalk(vm); +} +  Talk::Talk(SherlockEngine *vm) : _vm(vm) {  	_talkCounter = 0;  	_talkToAbort = false; @@ -245,6 +252,14 @@ Talk::Talk(SherlockEngine *vm) : _vm(vm) {  	_scriptMoreFlag = 0;  	_scriptSaveIndex = -1;  	_opcodes = IS_SERRATED_SCALPEL ? SCALPEL_OPCODES : TATTOO_OPCODES; + +	_charCount = 0; +	_line = 0; +	_yp = 0; +	_wait = 0; +	_pauseFlag = false; +	_seqCount = 0; +	_scriptStart = _scriptEnd = nullptr;  }  void Talk::talkTo(const Common::String &filename) { @@ -1063,34 +1078,29 @@ void Talk::setStillSeq(int speaker) {  }  void Talk::doScript(const Common::String &script) { -	Animation &anim = *_vm->_animation; -	Events &events = *_vm->_events; -	Inventory &inv = *_vm->_inventory; -	Map &map = *_vm->_map;  	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 seqCount;  	_savedSequences.clear(); -	const byte *scriptStart = (const byte *)script.c_str(); -	const byte *scriptEnd = scriptStart + script.size(); -	const byte *str = scriptStart; +	_scriptStart = (const byte *)script.c_str(); +	_scriptEnd = _scriptStart + script.size(); +	const byte *str = _scriptStart; +	_yp = CONTROLS_Y + 12; +	_charCount = 0; +	_line = 0; +	_wait = 0; +	_pauseFlag = false; +	_seqCount = 0; +	_noTextYet = true; +	_endStr = false;  	if (_scriptMoreFlag) {  		_scriptMoreFlag = 0; -		str = scriptStart + _scriptSaveIndex; +		str = _scriptStart + _scriptSaveIndex;  	}  	// Check if the script begins with a Stealh Mode Active command @@ -1145,371 +1155,31 @@ void Talk::doScript(const Common::String &script) {  	do {  		Common::String tempString; -		wait = 0; +		_wait = 0;  		byte c = str[0];  		if (!c) { -			endStr = true; +			_endStr = true;  		} else if (c == '{') {  			// Start of comment, so skip over it  			while (*str++ != '}')  				; -		} else if (c >= _opcodes[0]) { +		} else if (_opcodeTable[c]) {  			// Handle control code -			if (c == _opcodes[OP_SWITCH_SPEAKER]) { -				if (!(_speaker & SPEAKER_REMOVE)) -					people.clearTalking(); -				if (_talkToAbort) -					return; - -				ui.clearWindow(); -				yp = CONTROLS_Y + 12; -				charCount = line = 0; - -				_speaker = *++str - 1; -				people.setTalking(_speaker); -				pullSequence(); -				pushSequence(_speaker); -				setSequence(_speaker); - -			} else if (c == _opcodes[OP_RUN_CANIMATION]) { -				++str; -				scene.startCAnim((str[0] - 1) & 127, (str[0] & 0x80) ? -1 : 1); -				if (_talkToAbort) -					return; - -				// Check if next character is changing side or changing portrait -				if (charCount && (str[1] == _opcodes[OP_SWITCH_SPEAKER] || str[1] == _opcodes[OP_ASSIGN_PORTRAIT_LOCATION])) -					wait = 1; - -			} else if (c == _opcodes[OP_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; - -			} else if (c == _opcodes[OP_PAUSE]) { -				// Pause -				charCount = *++str; -				wait = pauseFlag = true; - -			} else if (c == _opcodes[OP_REMOVE_PORTRAIT]) { -				if (_speaker >= 0 && _speaker < SPEAKER_REMOVE) -					people.clearTalking(); -				pullSequence(); -				if (_talkToAbort) -					return; - -				_speaker |= SPEAKER_REMOVE; - -			} else if (c == _opcodes[OP_CLEAR_WINDOW]) { -				ui.clearWindow(); -				yp = CONTROLS_Y + 12; -				charCount = line = 0; - -			} else if (c == _opcodes[OP_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 -				int objId = -1; -				for (uint idx = 0; idx < scene._bgShapes.size(); ++idx) { -					if (tempString.equalsIgnoreCase(scene._bgShapes[idx]._name)) -						objId = idx; -				} -				if (objId == -1) -					error("Could not find object %s to change", tempString.c_str()); - -				// Should the script be overwritten? -				if (str[0] > 0x80) { -					// Save the current sequence -					_savedSequences.push(SequenceEntry()); -					SequenceEntry &seqEntry = _savedSequences.top(); -					seqEntry._objNum = objId; -					seqEntry._seqTo = scene._bgShapes[objId]._seqTo; -					for (uint idx = 0; idx < scene._bgShapes[objId]._seqSize; ++idx) -						seqEntry._sequences.push_back(scene._bgShapes[objId]._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[objId]._sequences[idx] = str[0] - 1; - -				// Reset object back to beginning of new sequence -				scene._bgShapes[objId]._frameNumber = 0; +			switch ((this->*_opcodeTable[c - 128])(str)) { +			case RET_EXIT: +				return; +			case RET_CONTINUE:  				continue; - -			} else if (c == _opcodes[OP_WALK_TO_COORDS]) { -				++str; - -				people.walkToCoords(Common::Point(((str[0] - 1) * 256 + str[1] - 1) * 100, -					str[2] * 100), str[3] - 1); -				if (_talkToAbort) -					return; - -				str += 3; -			 -			} else if (c == _opcodes[OP_PAUSE_WITHOUT_CONTROL]) { -				++str; - -				for (int idx = 0; idx < (str[0] - 1); ++idx) { -					scene.doBgAnim(); -					if (_talkToAbort) -						return; - -					// Check for button press -					events.pollEvents(); -					events.setButtonState(); -				} - -			} else if (c == _opcodes[OP_BANISH_WINDOW]) { -				if (!(_speaker & SPEAKER_REMOVE)) -					people.clearTalking(); -				pullSequence(); - -				if (_talkToAbort) -					return; - -				_speaker |= SPEAKER_REMOVE; -				ui.banishWindow(); -				ui._menuMode = TALK_MODE; -				noTextYet = true; -				 -			} else if (c == _opcodes[OP_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"); -				} - -			} else if (c == _opcodes[OP_SET_FLAG]) { -				++str; -				int flag1 = (str[0] - 1) * 256 + str[1] - 1 - (str[1] == 1 ? 1 : 0); -				int flag = (flag1 & 0x3fff) * (flag1 >= 0x4000 ? -1 : 1); -				_vm->setFlags(flag); -				++str; - -			} else if (c == _opcodes[OP_SFX_COMMAND]) { -				++str; -				if (sound._voices) { -					for (int idx = 0; idx < 8 && str[idx] != '~'; ++idx) -						tempString += str[idx]; -					sound.playSound(tempString, WAIT_RETURN_IMMEDIATELY); - -					// Set voices to wait for more -					sound._voices = 2; -					sound._speechOn = (*sound._soundIsOn); -				} - -				wait = 1; -				str += 7; -				 -			} else if (c == _opcodes[OP_TOGGLE_OBJECT]) { -				++str; -				for (int idx = 0; idx < str[0]; ++idx) -					tempString += str[idx + 1]; - -				scene.toggleObject(tempString); -				str += str[0]; -				 -			} else if (c == _opcodes[OP_STEALTH_MODE_ACTIVE]) { -				_talkStealth = 2; - -			} else if (c == _opcodes[OP_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] != _opcodes[OP_ELSE_STATEMENT] && str[0] != _opcodes[OP_END_IF_STATEMENT]); - -					if (!str[0]) -						endStr = true; -				} - -			} else if (c == _opcodes[OP_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] != _opcodes[OP_END_IF_STATEMENT]); - -			} else if (c == _opcodes[OP_STEALTH_MODE_DEACTIVATE]) { -				_talkStealth = 0; -				events.clearKeyboard(); -				 -			} else if (c == _opcodes[OP_TURN_HOLMES_OFF]) { -				people._holmesOn = false; -				 -			} else if (c == _opcodes[OP_TURN_HOLMES_ON]) { -				people._holmesOn = true; - -			} else if (c == _opcodes[OP_GOTO_SCENE]) { -				scene._goToScene = str[1] - 1; - -				if (scene._goToScene != 100) { -					// Not going to the map overview -					map._oldCharPoint = scene._goToScene; -					map._overPos.x = map[scene._goToScene].x * 100 - 600; -					map._overPos.y = map[scene._goToScene].y * 100 + 900; - -					// Run a canimation? -					if (str[2] > 100) { -						people._hSavedFacing = str[2]; -						people._hSavedPos = Common::Point(160, 100); -					} -				} -				str += 6; - -				_scriptMoreFlag = (scene._goToScene == 100) ? 2 : 1; -				_scriptSaveIndex = str - scriptStart; -				endStr = true; -				wait = 0; -				 -			} else if (c == _opcodes[OP_PLAY_PROLOGUE]) { -				++str; -				for (int idx = 0; idx < 8 && str[idx] != '~'; ++idx) -					tempString += str[idx]; - -				anim.play(tempString, 1, 3, true, 4); -				 -			} else if (c == _opcodes[OP_ADD_ITEM_TO_INVENTORY]) { -				++str; -				for (int idx = 0; idx < str[0]; ++idx) -					tempString += str[idx + 1]; -				str += str[0]; - -				inv.putNameInInventory(tempString); -				 -			} else if (c == _opcodes[OP_SET_OBJECT]) { -				++str; -				for (int idx = 0; idx < (str[0] & 127); ++idx) -					tempString += str[idx + 1]; - -				// Set comparison state according to if we want to hide or unhide -				bool state = (str[0] >= SPEAKER_REMOVE); -				str += str[0] & 127; - -				for (uint idx = 0; idx < scene._bgShapes.size(); ++idx) { -					Object &object = scene._bgShapes[idx]; -					if (tempString.equalsIgnoreCase(object._name)) { -						// Only toggle the object if it's not in the desired state already -						if ((object._type == HIDDEN && state) || (object._type != HIDDEN && !state)) -							object.toggleHidden(); -					} -				} -				 -			} else if (c == _opcodes[OP_CALL_TALK_FILE]) { -				++str; -				for (int idx = 0; idx < 8 && str[idx] != '~'; ++idx) -					tempString += str[idx]; -				str += 8; - -				int scriptCurrentIndex = str - scriptStart; - -				// Save the current script position and new talk file -				if (_scriptStack.size() < 9) { -					ScriptStackEntry rec1; -					rec1._name = _scriptName; -					rec1._currentIndex = scriptCurrentIndex; -					rec1._select = _scriptSelect; -					_scriptStack.push(rec1); - -					// Push the new talk file onto the stack -					ScriptStackEntry rec2; -					rec2._name = tempString; -					rec2._currentIndex = 0; -					rec2._select = 100; -					_scriptStack.push(rec2); -				} else { -					error("Script stack overflow"); -				} - -				_scriptMoreFlag = 1; -				endStr = true; -				wait = 0; -				 -			} else if (c == _opcodes[OP_MOVE_MOUSE]) { -				++str; -				events.moveMouse(Common::Point((str[0] - 1) * 256 + str[1] - 1, str[2])); -				if (_talkToAbort) -					return; -				str += 3; -				 -			} else if (c == _opcodes[OP_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, "%s", tempString.c_str()); -				ui._menuCounter = 30; -				 -			} else if (c == _opcodes[OP_CLEAR_INFO_LINE]) { -				ui._infoFlag = true; -				ui.clearInfo(); -				 -			} else if (c == _opcodes[OP_WALK_TO_CANIMATION]) { -				++str; -				CAnim &animation = scene._cAnim[str[0] - 1]; - -				people.walkToCoords(animation._goto, animation._gotoDir); -				if (_talkToAbort) -					return; -				 -			} else if (c == _opcodes[OP_REMOVE_ITEM_FROM_INVENTORY]) { -				++str; -				for (int idx = 0; idx < str[0]; ++idx) -					tempString += str[idx + 1]; -				str += str[0]; - -				inv.deleteItemFromInventory(tempString); -				 -			} else if (c == _opcodes[OP_ENABLE_END_KEY]) { -				ui._endKeyActive = true; -				 -			} else if (c == _opcodes[OP_DISABLE_END_KEY]) { -				ui._endKeyActive = false; -				 -			} else { -				error("Unknown opcode encountered"); +			default: +				break;  			}  			++str;  		} else {  			// If the window isn't yet open, draw the window before printing starts -			if (!ui._windowOpen && noTextYet) { -				noTextYet = false; +			if (!ui._windowOpen && _noTextYet) { +				_noTextYet = false;  				drawInterface();  				if (_talkTo != -1) { @@ -1520,19 +1190,19 @@ void Talk::doScript(const Common::String &script) {  			}  			// If it's the first line, display the speaker -			if (!line && _speaker >= 0 && _speaker < (int)people._characters.size()) { +			if (!_line && _speaker >= 0 && _speaker < (int)people._characters.size()) {  				// 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, "%s", +					screen.print(Common::Point(16, _yp), TALK_FOREGROUND, "%s",  						people._characters[_speaker & 127]._name);  				} else { -					screen.gPrint(Common::Point(16, yp - 1), TALK_FOREGROUND, "%s",  +					screen.gPrint(Common::Point(16, _yp - 1), TALK_FOREGROUND, "%s",   						people._characters[_speaker & 127]._name);  					openTalkWindow = true;  				} -				yp += 9; +				_yp += 9;  			}  			// Find amount of text that will fit on the line @@ -1540,23 +1210,23 @@ void Talk::doScript(const Common::String &script) {  			do {  				width += screen.charWidth(str[idx]);  				++idx; -				++charCount; +				++_charCount;  			} while (width < 298 && str[idx] && str[idx] != '{' && str[idx] < _opcodes[0]);  			if (str[idx] || width >= 298) {  				if (str[idx] < _opcodes[0] && str[idx] != '{') {  					--idx; -					--charCount; +					--_charCount;  				}  			} else { -				endStr = true; +				_endStr = true;  			}  			// If word wrap is needed, find the start of the current word  			if (width >= 298) {  				while (str[idx] != ' ') {  					--idx; -					--charCount; +					--_charCount;  				}  			} @@ -1566,16 +1236,16 @@ void Talk::doScript(const Common::String &script) {  			// If the speaker indicates a description file, print it in yellow  			if (_speaker != -1) {  				if (ui._windowOpen) { -					screen.print(Common::Point(16, yp), COMMAND_FOREGROUND, "%s", lineStr.c_str()); +					screen.print(Common::Point(16, _yp), COMMAND_FOREGROUND, "%s", lineStr.c_str());  				} else { -					screen.gPrint(Common::Point(16, yp - 1), COMMAND_FOREGROUND, "%s", lineStr.c_str()); +					screen.gPrint(Common::Point(16, _yp - 1), COMMAND_FOREGROUND, "%s", lineStr.c_str());  					openTalkWindow = true;  				}  			} else {  				if (ui._windowOpen) { -					screen.print(Common::Point(16, yp), COMMAND_FOREGROUND, "%s", lineStr.c_str()); +					screen.print(Common::Point(16, _yp), COMMAND_FOREGROUND, "%s", lineStr.c_str());  				} else { -					screen.gPrint(Common::Point(16, yp - 1), COMMAND_FOREGROUND, "%s", lineStr.c_str()); +					screen.gPrint(Common::Point(16, _yp - 1), COMMAND_FOREGROUND, "%s", lineStr.c_str());  					openTalkWindow = true;  				}  			} @@ -1587,24 +1257,24 @@ void Talk::doScript(const Common::String &script) {  			if (str[0] < _opcodes[0] && str[0] != '{')  				++str; -			yp += 9; -			++line; +			_yp += 9; +			++_line;  			// Certain different conditions require a wait -			if ((line == 4 && str < scriptEnd && str[0] != _opcodes[OP_SFX_COMMAND] && str[0] != _opcodes[OP_PAUSE] && _speaker != -1) || -					(line == 5 && str < scriptEnd && str[0] != _opcodes[OP_PAUSE] && _speaker == -1) || -					endStr) { -				wait = 1; +			if ((_line == 4 && str < _scriptEnd && str[0] != _opcodes[OP_SFX_COMMAND] && str[0] != _opcodes[OP_PAUSE] && _speaker != -1) || +					(_line == 5 && str < _scriptEnd && str[0] != _opcodes[OP_PAUSE] && _speaker == -1) || +					_endStr) { +				_wait = 1;  			} -			byte v = (str >= scriptEnd ? 0 : str[0]); -			wait = v == _opcodes[OP_SWITCH_SPEAKER] || v == _opcodes[OP_ASSIGN_PORTRAIT_LOCATION] || +			byte v = (str >= _scriptEnd ? 0 : str[0]); +			_wait = v == _opcodes[OP_SWITCH_SPEAKER] || v == _opcodes[OP_ASSIGN_PORTRAIT_LOCATION] ||  				v == _opcodes[OP_BANISH_WINDOW] || _opcodes[OP_IF_STATEMENT] || v == _opcodes[OP_ELSE_STATEMENT] ||  				v == _opcodes[OP_END_IF_STATEMENT] || v == _opcodes[OP_GOTO_SCENE] || v == _opcodes[OP_CALL_TALK_FILE];  		}  		// Open window if it wasn't already open, and text has already been printed -		if ((openTalkWindow && wait) || (openTalkWindow && str[0] >= _opcodes[0] && str[0] != _opcodes[OP_CARRIAGE_RETURN])) { +		if ((openTalkWindow && _wait) || (openTalkWindow && str[0] >= _opcodes[0] && str[0] != _opcodes[OP_CARRIAGE_RETURN])) {  			if (!ui._slideWindows) {  				screen.slamRect(Common::Rect(0, CONTROLS_Y, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT));  			} else { @@ -1615,34 +1285,34 @@ void Talk::doScript(const Common::String &script) {  			openTalkWindow = false;  		} -		if (wait) { +		if (_wait) {  			// Handling pausing -			if (!pauseFlag && charCount < 160) -				charCount = 160; +			if (!_pauseFlag && _charCount < 160) +				_charCount = 160; -			wait = waitForMore(charCount); -			if (wait == -1) -				endStr = true; +			_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 (_wait >= 0 && _wait < 254) {  				if (str[0] == _opcodes[OP_SFX_COMMAND])  					str += 9;  			}  			// Clear the window unless the wait was due to a PAUSE command -			if (!pauseFlag && wait != -1 && str < scriptEnd && str[0] != _opcodes[OP_SFX_COMMAND]) { +			if (!_pauseFlag && _wait != -1 && str < _scriptEnd && str[0] != _opcodes[OP_SFX_COMMAND]) {  				if (!_talkStealth)  					ui.clearWindow(); -				yp = CONTROLS_Y + 12; -				charCount = line = 0; +				_yp = CONTROLS_Y + 12; +				_charCount = _line = 0;  			} -			pauseFlag = false; +			_pauseFlag = false;  		} -	} while (!_vm->shouldQuit() && !endStr); +	} while (!_vm->shouldQuit() && !_endStr); -	if (wait != -1) { +	if (_wait != -1) {  		for (int ssIndex = 0; ssIndex < (int)_savedSequences.size(); ++ssIndex) {  			SequenceEntry &seq = _savedSequences[ssIndex];  			Object &object = scene._bgShapes[seq._objNum]; @@ -1757,4 +1427,559 @@ void Talk::synchronize(Common::Serializer &s) {  	}  } +OpcodeReturn Talk::cmdAddItemToInventory(const byte *&str) { +	Inventory &inv = *_vm->_inventory; +	Common::String tempString; + +	++str; +	for (int idx = 0; idx < str[0]; ++idx) +		tempString += str[idx + 1]; +	str += str[0]; + +	inv.putNameInInventory(tempString); +	return RET_SUCCESS; +} + +OpcodeReturn Talk::cmdAdjustObjectSequence(const byte *&str) { +	Scene &scene = *_vm->_scene; +	Common::String tempString; + +	// 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 +	int objId = -1; +	for (uint idx = 0; idx < scene._bgShapes.size(); ++idx) { +		if (tempString.equalsIgnoreCase(scene._bgShapes[idx]._name)) +			objId = idx; +	} +	if (objId == -1) +		error("Could not find object %s to change", tempString.c_str()); + +	// Should the script be overwritten? +	if (str[0] > 0x80) { +		// Save the current sequence +		_savedSequences.push(SequenceEntry()); +		SequenceEntry &seqEntry = _savedSequences.top(); +		seqEntry._objNum = objId; +		seqEntry._seqTo = scene._bgShapes[objId]._seqTo; +		for (uint idx = 0; idx < scene._bgShapes[objId]._seqSize; ++idx) +			seqEntry._sequences.push_back(scene._bgShapes[objId]._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[objId]._sequences[idx] = str[0] - 1; + +	// Reset object back to beginning of new sequence +	scene._bgShapes[objId]._frameNumber = 0; + +	return RET_CONTINUE; +} + +OpcodeReturn Talk::cmdBanishWindow(const byte *&str) { +	People &people = *_vm->_people; +	UserInterface &ui = *_vm->_ui; + +	if (!(_speaker & SPEAKER_REMOVE)) +		people.clearTalking(); +	pullSequence(); + +	if (_talkToAbort) +		return RET_EXIT; + +	_speaker |= SPEAKER_REMOVE; +	ui.banishWindow(); +	ui._menuMode = TALK_MODE; +	_noTextYet = true; + +	return RET_SUCCESS; +} + +OpcodeReturn Talk::cmdDisableEndKey(const byte *&str) { +	_vm->_ui->_endKeyActive = false; +	return RET_SUCCESS; +} + +OpcodeReturn Talk::cmdEnableEndKey(const byte *&str) { +	_vm->_ui->_endKeyActive = true; +	return RET_SUCCESS; +} + +OpcodeReturn Talk::cmdGotoScene(const byte *&str) { +	Map &map = *_vm->_map; +	People &people = *_vm->_people; +	Scene &scene = *_vm->_scene; +	scene._goToScene = str[1] - 1; + +	if (scene._goToScene != 100) { +		// Not going to the map overview +		map._oldCharPoint = scene._goToScene; +		map._overPos.x = map[scene._goToScene].x * 100 - 600; +		map._overPos.y = map[scene._goToScene].y * 100 + 900; + +		// Run a canimation? +		if (str[2] > 100) { +			people._hSavedFacing = str[2]; +			people._hSavedPos = Common::Point(160, 100); +		} +	} +	str += 6; + +	_scriptMoreFlag = (scene._goToScene == 100) ? 2 : 1; +	_scriptSaveIndex = str - _scriptStart; +	_endStr = true; +	_wait = 0; + +	return RET_SUCCESS; +} + +OpcodeReturn Talk::cmdHolmesOff(const byte *&str) { +	_vm->_people->_holmesOn = false; +	return RET_SUCCESS; +} + +OpcodeReturn Talk::cmdHolmesOn(const byte *&str) { +	_vm->_people->_holmesOn = true; +	return RET_SUCCESS; +} + +OpcodeReturn Talk::cmdPause(const byte *&str) { +	_charCount = *++str; +	_wait = _pauseFlag = true; + +	return RET_SUCCESS; +} + +OpcodeReturn Talk::cmdPauseWithoutControl(const byte *&str) { +	Events &events = *_vm->_events; +	Scene &scene = *_vm->_scene; +	++str; + +	for (int idx = 0; idx < (str[0] - 1); ++idx) { +		scene.doBgAnim(); +		if (_talkToAbort) +			return RET_EXIT; + +		// Check for button press +		events.pollEvents(); +		events.setButtonState(); +	} + +	return RET_SUCCESS; +} + +OpcodeReturn Talk::cmdRemoveItemFromInventory(const byte *&str) { +	Inventory &inv = *_vm->_inventory; +	Common::String tempString; + +	++str; +	for (int idx = 0; idx < str[0]; ++idx) +		tempString += str[idx + 1]; +	str += str[0]; + +	inv.deleteItemFromInventory(tempString); + +	return RET_SUCCESS; +} + +OpcodeReturn Talk::cmdRunCAnimation(const byte *&str) { +	Scene &scene = *_vm->_scene; + +	++str; +	scene.startCAnim((str[0] - 1) & 127, (str[0] & 0x80) ? -1 : 1); +	if (_talkToAbort) +		return RET_EXIT; + +	// Check if next character is changing side or changing portrait +	if (_charCount && (str[1] == _opcodes[OP_SWITCH_SPEAKER] || str[1] == _opcodes[OP_ASSIGN_PORTRAIT_LOCATION])) +		_wait = 1; + +	return RET_SUCCESS; +} + +OpcodeReturn Talk::cmdSetFlag(const byte *&str) { +	++str; +	int flag1 = (str[0] - 1) * 256 + str[1] - 1 - (str[1] == 1 ? 1 : 0); +	int flag = (flag1 & 0x3fff) * (flag1 >= 0x4000 ? -1 : 1); +	_vm->setFlags(flag); +	++str; + +	return RET_SUCCESS; +} + +OpcodeReturn Talk::cmdSetObject(const byte *&str) { +	Scene &scene = *_vm->_scene; +	Common::String tempString; + +	++str; +	for (int idx = 0; idx < (str[0] & 127); ++idx) +		tempString += str[idx + 1]; + +	// Set comparison state according to if we want to hide or unhide +	bool state = (str[0] >= SPEAKER_REMOVE); +	str += str[0] & 127; + +	for (uint idx = 0; idx < scene._bgShapes.size(); ++idx) { +		Object &object = scene._bgShapes[idx]; +		if (tempString.equalsIgnoreCase(object._name)) { +			// Only toggle the object if it's not in the desired state already +			if ((object._type == HIDDEN && state) || (object._type != HIDDEN && !state)) +				object.toggleHidden(); +		} +	} + +	return RET_SUCCESS; +} + +OpcodeReturn Talk::cmdStealthModeActivate(const byte *&str) { +	_talkStealth = 2; +	return RET_SUCCESS; +} + +OpcodeReturn Talk::cmdStealthModeDeactivate(const byte *&str) { +	Events &events = *_vm->_events; + +	_talkStealth = 0; +	events.clearKeyboard(); + +	return RET_SUCCESS; +} + +OpcodeReturn Talk::cmdSwitchSpeaker(const byte *&str) { +	People &people = *_vm->_people; +	UserInterface &ui = *_vm->_ui; + +	if (!(_speaker & SPEAKER_REMOVE)) +		people.clearTalking(); +	if (_talkToAbort) +		return RET_EXIT; + +	ui.clearWindow(); +	_yp = CONTROLS_Y + 12; +	_charCount = _line = 0; + +	_speaker = *++str - 1; +	people.setTalking(_speaker); +	pullSequence(); +	pushSequence(_speaker); +	setSequence(_speaker); + +	return RET_SUCCESS; +} + +OpcodeReturn Talk::cmdToggleObject(const byte *&str) { +	Scene &scene = *_vm->_scene; +	Common::String tempString; + +	++str; +	for (int idx = 0; idx < str[0]; ++idx) +		tempString += str[idx + 1]; + +	scene.toggleObject(tempString); +	str += str[0]; + +	return RET_SUCCESS; +} + +OpcodeReturn Talk::cmdWalkToCAnimation(const byte *&str) { +	People &people = *_vm->_people; +	Scene &scene = *_vm->_scene; + +	++str; +	CAnim &animation = scene._cAnim[str[0] - 1]; +	people.walkToCoords(animation._goto, animation._gotoDir); +	 +	return _talkToAbort ? RET_EXIT : RET_SUCCESS; +} + +OpcodeReturn Talk::cmdWalkToCoords(const byte *&str) { +	People &people = *_vm->_people; +	++str; + +	people.walkToCoords(Common::Point(((str[0] - 1) * 256 + str[1] - 1) * 100, +		str[2] * 100), str[3] - 1); +	if (_talkToAbort) +		return RET_EXIT; + +	str += 3; +	return RET_SUCCESS; +} + +/*----------------------------------------------------------------*/ + +ScalpelTalk::ScalpelTalk(SherlockEngine *vm) : Talk(vm) { +	static OpcodeMethod OPCODE_METHODS[] = { +		(OpcodeMethod)&ScalpelTalk::cmdSwitchSpeaker, +		(OpcodeMethod)&ScalpelTalk::cmdRunCAnimation, +		(OpcodeMethod)&ScalpelTalk::cmdAssignPortraitLocation, + +		(OpcodeMethod)&ScalpelTalk::cmdPause, +		(OpcodeMethod)&ScalpelTalk::cmdRemovePortrait, +		(OpcodeMethod)&ScalpelTalk::cmdClearWindow, +		(OpcodeMethod)&ScalpelTalk::cmdAdjustObjectSequence, +		(OpcodeMethod)&ScalpelTalk::cmdWalkToCoords, +		(OpcodeMethod)&ScalpelTalk::cmdPauseWithoutControl, +		(OpcodeMethod)&ScalpelTalk::cmdBanishWindow, +		(OpcodeMethod)&ScalpelTalk::cmdSummonWindow, +		(OpcodeMethod)&ScalpelTalk::cmdSetFlag, +		(OpcodeMethod)&ScalpelTalk::cmdSfxCommand, + +		(OpcodeMethod)&ScalpelTalk::cmdToggleObject, +		(OpcodeMethod)&ScalpelTalk::cmdStealthModeActivate, +		(OpcodeMethod)&ScalpelTalk::cmdIf, +		(OpcodeMethod)&ScalpelTalk::cmdElse, +		nullptr, +		(OpcodeMethod)&ScalpelTalk::cmdStealthModeDeactivate, +		(OpcodeMethod)&ScalpelTalk::cmdHolmesOff, +		(OpcodeMethod)&ScalpelTalk::cmdHolmesOn, +		(OpcodeMethod)&ScalpelTalk::cmdGotoScene, +		(OpcodeMethod)&ScalpelTalk::cmdPlayPrologue, +		 +		(OpcodeMethod)&ScalpelTalk::cmdAddItemToInventory, +		(OpcodeMethod)&ScalpelTalk::cmdSetObject, +		(OpcodeMethod)&ScalpelTalk::cmdCallTalkFile, +		(OpcodeMethod)&ScalpelTalk::cmdMoveMouse, +		(OpcodeMethod)&ScalpelTalk::cmdDisplayInfoLine, +		(OpcodeMethod)&ScalpelTalk::cmdClearInfoLine, +		(OpcodeMethod)&ScalpelTalk::cmdWalkToCAnimation, +		(OpcodeMethod)&ScalpelTalk::cmdRemoveItemFromInventory, +		(OpcodeMethod)&ScalpelTalk::cmdEnableEndKey, +		(OpcodeMethod)&ScalpelTalk::cmdDisableEndKey, +		 +		(OpcodeMethod)&ScalpelTalk::cmdCarriageReturn +	}; + +	_opcodeTable = OPCODE_METHODS; +} + +OpcodeReturn ScalpelTalk::cmdAssignPortraitLocation(const byte *&str) { +	People &people = *_vm->_people; + +	++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; + +	return RET_SUCCESS; +} + +OpcodeReturn ScalpelTalk::cmdCallTalkFile(const byte *&str) { +	Common::String tempString; + +	++str; +	for (int idx = 0; idx < 8 && str[idx] != '~'; ++idx) +		tempString += str[idx]; +	str += 8; + +	int scriptCurrentIndex = str - _scriptStart; + +	// Save the current script position and new talk file +	if (_scriptStack.size() < 9) { +		ScriptStackEntry rec1; +		rec1._name = _scriptName; +		rec1._currentIndex = scriptCurrentIndex; +		rec1._select = _scriptSelect; +		_scriptStack.push(rec1); + +		// Push the new talk file onto the stack +		ScriptStackEntry rec2; +		rec2._name = tempString; +		rec2._currentIndex = 0; +		rec2._select = 100; +		_scriptStack.push(rec2); +	} else { +		error("Script stack overflow"); +	} + +	_scriptMoreFlag = 1; +	_endStr = true; +	_wait = 0; + +	return RET_SUCCESS; +} + +OpcodeReturn ScalpelTalk::cmdClearInfoLine(const byte *&str) { +	UserInterface &ui = *_vm->_ui; + +	ui._infoFlag = true; +	ui.clearInfo(); + +	return RET_SUCCESS; +} + +OpcodeReturn ScalpelTalk::cmdClearWindow(const byte *&str) { +	UserInterface &ui = *_vm->_ui; +	 +	ui.clearWindow(); +	_yp = CONTROLS_Y + 12; +	_charCount = _line = 0; + +	return RET_SUCCESS; +} + +OpcodeReturn ScalpelTalk::cmdDisplayInfoLine(const byte *&str) { +	Screen &screen = *_vm->_screen; +	UserInterface &ui = *_vm->_ui; +	Common::String tempString; + +	++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, "%s", tempString.c_str()); +	ui._menuCounter = 30; + +	return RET_SUCCESS; +} + +OpcodeReturn ScalpelTalk::cmdElse(const byte *&str) { +	// 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] != _opcodes[OP_END_IF_STATEMENT]); + +	return RET_SUCCESS; +} + +OpcodeReturn ScalpelTalk::cmdIf(const byte *&str) { +	++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] != _opcodes[OP_ELSE_STATEMENT] && str[0] != _opcodes[OP_END_IF_STATEMENT]); + +		if (!str[0]) +			_endStr = true; +	} + +	return RET_SUCCESS; +} + +OpcodeReturn ScalpelTalk::cmdMoveMouse(const byte *&str) { +	Events &events = *_vm->_events; + +	++str; +	events.moveMouse(Common::Point((str[0] - 1) * 256 + str[1] - 1, str[2])); +	if (_talkToAbort) +		return RET_EXIT; +	str += 3; +	 +	return RET_SUCCESS; +} + +OpcodeReturn ScalpelTalk::cmdPlayPrologue(const byte *&str) { +	Animation &anim = *_vm->_animation; +	Common::String tempString; + +	++str; +	for (int idx = 0; idx < 8 && str[idx] != '~'; ++idx) +		tempString += str[idx]; + +	anim.play(tempString, 1, 3, true, 4); + +	return RET_SUCCESS; +} + +OpcodeReturn ScalpelTalk::cmdRemovePortrait(const byte *&str) { +	People &people = *_vm->_people; + +	if (_speaker >= 0 && _speaker < SPEAKER_REMOVE) +		people.clearTalking(); +	pullSequence(); +	if (_talkToAbort) +		return RET_EXIT; + +	_speaker |= SPEAKER_REMOVE; +	return RET_SUCCESS; +} + +OpcodeReturn ScalpelTalk::cmdSfxCommand(const byte *&str) { +	Sound &sound = *_vm->_sound; +	Common::String tempString; + +	++str; +	if (sound._voices) { +		for (int idx = 0; idx < 8 && str[idx] != '~'; ++idx) +			tempString += str[idx]; +		sound.playSound(tempString, WAIT_RETURN_IMMEDIATELY); + +		// Set voices to wait for more +		sound._voices = 2; +		sound._speechOn = (*sound._soundIsOn); +	} + +	_wait = 1; +	str += 7; + +	return RET_SUCCESS; +} + +OpcodeReturn ScalpelTalk::cmdSummonWindow(const byte *&str) { +	Events &events = *_vm->_events; +	Screen &screen = *_vm->_screen; + +	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"); +	} + +	return RET_SUCCESS; +} + +OpcodeReturn ScalpelTalk::cmdCarriageReturn(const byte *&str) { +	return RET_SUCCESS; +} + +/*----------------------------------------------------------------*/ + +TattooTalk::TattooTalk(SherlockEngine *vm) : Talk(vm) { +	static OpcodeMethod OPCODE_METHODS[] = { +		nullptr, nullptr, +		nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, +		nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, +		nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, +		nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, +		(OpcodeMethod)&TattooTalk::cmdSwitchSpeaker, +		(OpcodeMethod)&TattooTalk::cmdRunCAnimation, +		// TODO: Implement opcode methods for new Tattoo opcodes +	}; + +	_opcodeTable = OPCODE_METHODS; +} +  } // End of namespace Sherlock  | 
