diff options
| -rw-r--r-- | engines/sherlock/objects.cpp | 40 | ||||
| -rw-r--r-- | engines/sherlock/objects.h | 8 | ||||
| -rw-r--r-- | engines/sherlock/people.h | 15 | ||||
| -rw-r--r-- | engines/sherlock/scene.cpp | 15 | ||||
| -rw-r--r-- | engines/sherlock/talk.cpp | 2 | ||||
| -rw-r--r-- | engines/sherlock/user_interface.cpp | 197 | ||||
| -rw-r--r-- | engines/sherlock/user_interface.h | 1 | 
7 files changed, 254 insertions, 24 deletions
| diff --git a/engines/sherlock/objects.cpp b/engines/sherlock/objects.cpp index e4730ef207..dc57322bd4 100644 --- a/engines/sherlock/objects.cpp +++ b/engines/sherlock/objects.cpp @@ -248,7 +248,7 @@ void Sprite::checkSprite() {  					case TALK:  					case TALK_EVERY: -						_type = HIDDEN; +						obj._type = HIDDEN;  						obj.setFlagsAndToggles();  						talk.talkTo(obj._use[0]._target);  						break; @@ -400,6 +400,36 @@ void Object::setVm(SherlockEngine *vm) {  	_countCAnimFrames = false;  } +Object::Object() { +	_sequenceOffset = 0; +	_sequences = nullptr; +	_images = nullptr; +	_imageFrame = nullptr; +	_walkCount = 0; +	_allow = 0; +	_frameNumber = 0; +	_sequenceNumber = 0; +	_type = INVALID; +	_pickup = 0; +	_defaultCommand = 0; +	_lookFlag = 0; +	_pickupFlag = 0; +	_requiredFlag = 0; +	_status = 0; +	_misc = 0; +	_maxFrames = 0; +	_flags = 0; +	_lookFrames = 0; +	_seqCounter = 0; +	_lookFacing = 0; +	_lookcAnim = 0; +	_seqStack = 0; +	_seqTo = 0; +	_descOffset = 0; +	_seqCounter2 = 0; +	_seqSize = 0; +} +  /**   * Load the object data from the passed stream   */ @@ -770,7 +800,7 @@ void Object::setObjSequence(int seq, bool wait) {  * @param messages	Provides a lookup list of messages that can be printed  * @returns		0 if no codes are found, 1 if codes were found  */ -int Object::checkNameForCodes(const Common::String &name, Common::StringArray *messages) { +int Object::checkNameForCodes(const Common::String &name, const char *const messages[]) {  	People &people = *_vm->_people;  	Scene &scene = *_vm->_scene;  	Screen &screen = *_vm->_screen; @@ -851,15 +881,13 @@ int Object::checkNameForCodes(const Common::String &name, Common::StringArray *m  		int messageNum = atoi(name.c_str() + 1);  		ui._infoFlag++;  		ui.clearInfo(); -		screen.print(Common::Point(0, INFO_LINE + 1), INFO_FOREGROUND, -			(*messages)[messageNum].c_str()); +		screen.print(Common::Point(0, INFO_LINE + 1), INFO_FOREGROUND, messages[messageNum]);  		ui._menuCounter = 25;  	} else if (name.hasPrefix("@")) {  		// Message attached to canimation  		ui._infoFlag++;  		ui.clearInfo(); -		screen.print(Common::Point(0, INFO_LINE + 1), INFO_FOREGROUND, -			"%s", name.c_str() + 1); +		screen.print(Common::Point(0, INFO_LINE + 1), INFO_FOREGROUND, name.c_str() + 1);  		printed = true;  		ui._menuCounter = 25;  	} diff --git a/engines/sherlock/objects.h b/engines/sherlock/objects.h index 26ad1d3900..2c642b5a58 100644 --- a/engines/sherlock/objects.h +++ b/engines/sherlock/objects.h @@ -34,7 +34,7 @@ namespace Sherlock {  class SherlockEngine;  enum ObjectAllow { -	ALLOW_MOVEMENT = 1, ALLOW_OPEN = 2, ALLOW_CLOSE = 4 +	ALLOW_MOVE = 1, ALLOW_OPEN = 2, ALLOW_CLOSE = 4  };  enum SpriteType { @@ -122,6 +122,8 @@ public:  	int frameHeight() const { return _imageFrame ? _imageFrame->_frame.h : 0; }  }; +enum { REVERSE_DIRECTION = 0x80 }; +  struct ActionType {  	int8 _cAnimNum;  	uint8 _cAnimSpeed;				// if high bit set, play in reverse @@ -198,13 +200,15 @@ public:  	ActionType _aMove;  	UseType _use[4]; +	Object(); +  	void synchronize(Common::SeekableReadStream &s);  	void toggleHidden();  	void checkObject(Object &o); -	int checkNameForCodes(const Common::String &name, Common::StringArray *messages); +	int checkNameForCodes(const Common::String &name, const char *const messages[]);  	void setFlagsAndToggles(); diff --git a/engines/sherlock/people.h b/engines/sherlock/people.h index bec078d11e..ba870d041d 100644 --- a/engines/sherlock/people.h +++ b/engines/sherlock/people.h @@ -34,7 +34,8 @@ enum PeopleId {  	PLAYER	= 0,  	AL		= 0,  	PEG		= 1, -	MAX_PEOPLE = 66 +	NUM_OF_PEOPLE = 2,		// Holmes and Watson +	MAX_PEOPLE = 66			// Total of all NPCs  };  // Animation sequence identifiers for characters @@ -62,7 +63,7 @@ public:  class People {  private:  	SherlockEngine *_vm; -	Person _data[MAX_PEOPLE]; +	Person _data[NUM_OF_PEOPLE];  	bool _walkLoaded;  	int _oldWalkSequence;  	int _srcZone, _destZone; @@ -84,8 +85,14 @@ public:  	People(SherlockEngine *vm);  	~People(); -	Person &operator[](PeopleId id) { return _data[id]; } -	Person &operator[](int idx) { return _data[idx]; } +	Person &operator[](PeopleId id) {  +		assert(id < NUM_OF_PEOPLE); +		return _data[id];  +	} +	Person &operator[](int idx) {  +		assert(idx < NUM_OF_PEOPLE); +		return _data[idx];  +	}  	bool isHolmesActive() const { return _walkLoaded && _holmesOn; } diff --git a/engines/sherlock/scene.cpp b/engines/sherlock/scene.cpp index 3d5f566164..1cad2506e5 100644 --- a/engines/sherlock/scene.cpp +++ b/engines/sherlock/scene.cpp @@ -314,8 +314,8 @@ bool Scene::loadScene(const Common::String &filename) {  		for (uint idx = 0; idx < _zones.size(); ++idx) {  			_zones[idx].left = boundsStream->readSint16LE();  			_zones[idx].top = boundsStream->readSint16LE(); -			_zones[idx].setWidth(boundsStream->readSint16LE()); -			_zones[idx].setHeight(boundsStream->readSint16LE()); +			_zones[idx].setWidth(boundsStream->readSint16LE() + 1); +			_zones[idx].setHeight(boundsStream->readSint16LE() + 1);  			boundsStream->skip(2);	// Skip unused scene number field  		} @@ -925,20 +925,18 @@ int Scene::startCAnim(int cAnimNum, int playRate) {  			rrmStream->seek(rrmStream->readUint32LE());  			// Load the canimation into the cache -			Common::SeekableReadStream *imgStream = !_lzwMode ? rrmStream : +			Common::SeekableReadStream *imgStream = !_lzwMode ? rrmStream->readStream(cAnim._size) :   				decompressLZ(*rrmStream, cAnim._size);  			res.addToCache(fname, *imgStream); -			if (_lzwMode) -				delete imgStream; - +			delete imgStream;  			delete rrmStream;  		}  		// Now load the resource as an image -		cObj._maxFrames = cObj._images->size();  		cObj._images = new ImageFile(fname);  		cObj._imageFrame = &(*cObj._images)[0]; +		cObj._maxFrames = cObj._images->size();  		int frames = 0;  		if (playRate < 0) { @@ -946,8 +944,7 @@ int Scene::startCAnim(int cAnimNum, int playRate) {  			// Count number of frames  			while (cObj._sequences[frames] && frames < MAX_FRAME)  				++frames; -		} -		else { +		} else {  			// Forward direction  			Object::_countCAnimFrames = true; diff --git a/engines/sherlock/talk.cpp b/engines/sherlock/talk.cpp index ec3f67bd84..281b6b4672 100644 --- a/engines/sherlock/talk.cpp +++ b/engines/sherlock/talk.cpp @@ -583,7 +583,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) { +	for (int idx = 0; idx < NUM_OF_PEOPLE; ++idx) {  		if (!scumm_strnicmp(filename.c_str(), people[(PeopleId)idx]._portrait.c_str(), 4)) {  			_talkTo = idx;  			break; diff --git a/engines/sherlock/user_interface.cpp b/engines/sherlock/user_interface.cpp index 2b808a085a..ebbe00ffbc 100644 --- a/engines/sherlock/user_interface.cpp +++ b/engines/sherlock/user_interface.cpp @@ -58,6 +58,25 @@ const char INVENTORY_COMMANDS[9] = { "ELUG-+,." };  const char *const PRESS_KEY_FOR_MORE = "Press any Key for More.";  const char *const PRESS_KEY_TO_CONTINUE = "Press any Key to Continue."; +const char *const MOPEN[] = {  +	"This cannot be opened", "It is already open", "It is locked", "Wait for Watson", " ", "."  +}; +const char *const MCLOSE[] = {  +	"This cannot be closed", "It is already closed", "The safe door is in the way"  +}; +const char *const MMOVE[] = {  +	"This cannot be moved", "It is bolted to the floor", "It is too heavy", "The other crate is in the way" +}; +const char *const MPICK[] = { +	"Nothing of interest here", "It is bolted down", "It is too big to carry", "It is too heavy", +	"I think a girl would be more your type", "Those flowers belong to Penny", "She's far too young for you!",  +	"I think a girl would be more your type!", "Government property for official use only"  +}; +const char *const MUSE[] = {  +	"You can't do that", "It had no effect", "You can't reach it", "OK, the door looks bigger! Happy?",  +	"Doors don't smoke"  +}; +  /*----------------------------------------------------------------*/  UserInterface::UserInterface(SherlockEngine *vm) : _vm(vm) { @@ -327,7 +346,7 @@ void UserInterface::handleInput() {  			break;  		case MOVE_MODE: -			doMiscControl(ALLOW_MOVEMENT); +			doMiscControl(ALLOW_MOVE);  			break;  		case TALK_MODE: @@ -1122,8 +1141,56 @@ void UserInterface::doMainControl() {  	}  } +/** + * Handles the input for the MOVE, OPEN, and CLOSE commands + */  void UserInterface::doMiscControl(int allowed) { -	// TODO +	Events &events = *_vm->_events; +	Scene &scene = *_vm->_scene; +	Talk &talk = *_vm->_talk; + +	if (events._released) { +		_temp = _bgFound; +		if (_bgFound != -1) { +			// Only allow pointing to objects, not people +			if (_bgFound < 1000) { +				events.clearEvents(); +				Object &obj = scene._bgShapes[_bgFound]; + +				switch (allowed) { +				case ALLOW_OPEN: +					checkAction(obj._aOpen, MOPEN, _temp); +					if (_menuMode && !talk._talkToAbort) { +						_menuMode = STD_MODE; +						restoreButton(OPEN_MODE - 1); +						_key = _oldKey = -1; +					} +					break; + +				case ALLOW_CLOSE: +					checkAction(obj._aClose, MCLOSE, _temp); +					if (_menuMode != TALK_MODE && !talk._talkToAbort) { +						_menuMode = STD_MODE; +						restoreButton(CLOSE_MODE - 1); +						_key = _oldKey = -1; +					} +					break; + +				case ALLOW_MOVE: +					checkAction(obj._aMove, MMOVE, _temp); +					if (_menuMode != TALK_MODE && !talk._talkToAbort) { +						_menuMode = STD_MODE; +						restoreButton(MOVE_MODE - 1); +						_key = _oldKey = -1; +					} +					break; + +				default: +					break; +				} +			} +		} +	}  }  void UserInterface::doPickControl() { @@ -1503,5 +1570,131 @@ void UserInterface::checkUseAction(UseType &use, const Common::String &invName,  	// TODO  } +/** + * Called for OPEN, CLOSE, and MOVE actions are being done + */ +void UserInterface::checkAction(ActionType &action, const char *const messages[], int objNum) { +	Events &events = *_vm->_events; +	People &people = *_vm->_people; +	Scene &scene = *_vm->_scene; +	Screen &screen = *_vm->_screen; +	Talk &talk = *_vm->_talk; +	bool printed = false; +	bool doCAnim = true; +	int cAnimNum; +	Common::Point pt(-1, -1); +	int dir = -1; + +	if (objNum >= 1000) +		// Ignore actions done on characters +		return; +	Object &obj = scene._bgShapes[objNum]; + +	if (action._cAnimNum == 0) +		// Really a 10 +		cAnimNum = 9; +	else +		cAnimNum = action._cAnimNum - 1; +	CAnim &anim = scene._cAnim[cAnimNum]; + +	if (action._cAnimNum != 99) { +		if (action._cAnimSpeed & REVERSE_DIRECTION) { +			pt = anim._teleportPos; +			dir = anim._teleportDir; +		} else { +			pt = anim._goto; +			dir = anim._gotoDir; +		} +	} + +	if (action._cAnimSpeed) { +		// Has a value, so do action +		// Show wait cursor whilst walking to object and doing action +		events.setCursor(WAIT); + +		for (int nameIdx = 0; nameIdx < 4; ++nameIdx) { +			if (action._names[nameIdx].hasPrefix("*") && toupper(action._names[nameIdx][1]) == 'W') { +				if (obj.checkNameForCodes(Common::String(action._names[nameIdx].c_str() + 2), messages)) { +					if (!talk._talkToAbort) +						printed = true; +				} +			} +		} + +		for (int nameIdx = 0; nameIdx < 4; ++nameIdx) { +			if (action._names[nameIdx].hasPrefix("*")) { +				char ch = toupper(action._names[nameIdx][1]); + +				if (ch == 'T' || ch == 'B') { +					printed = true; +					if (pt.x != -1) +						// Holmes needs to walk to object before the action is done +						people.walkToCoords(pt, dir); + +					if (!talk._talkToAbort) { +						// Ensure Holmes is on the exact intended location +						people[AL]._position = pt; +						people[AL]._sequenceNumber = dir; +						people.gotoStand(people[AL]); + +						talk.talkTo(action._names[nameIdx] + 2); +						if (ch == 'T') +							doCAnim = false; +					} +				} +			} +		} + +		if (doCAnim && !talk._talkToAbort) { +			if (pt.x != -1) +				// Holmes needs to walk to object before the action is done +				people.walkToCoords(pt, dir); +		} + +		for (int nameIdx = 0; nameIdx < 4; ++nameIdx) { +			if (action._names[nameIdx].hasPrefix("*") && toupper(action._names[nameIdx][1]) == 'F') { +				if (obj.checkNameForCodes(action._names[nameIdx].c_str() + 2, messages)) { +					if (!talk._talkToAbort) +						printed = true; +				} +			} +		} + +		if (doCAnim && !talk._talkToAbort && action._cAnimNum != 99) +			scene.startCAnim(cAnimNum, action._cAnimSpeed); + +		if (!talk._talkToAbort) { +			for (int nameIdx = 0; nameIdx < 4 && !talk._talkToAbort; ++nameIdx) { +				if (obj.checkNameForCodes(action._names[nameIdx], messages)) { +					if (!talk._talkToAbort) +						printed = true; +				} +			} + +			// Unless we're leaving the scene, print a "Done" message unless the printed flag has been set +			if (scene._goToScene != 1 && !printed && !talk._talkToAbort) { +				_infoFlag = true; +				clearInfo(); +				screen.print(Common::Point(0, INFO_LINE + 1), INFO_FOREGROUND, messages[action._cAnimNum]); + +				// Set how long to show the message +				_menuCounter = 30;	 +			} +		} +	} else { +		// Invalid action, to print error message +		_infoFlag = true; +		clearInfo(); +		screen.print(Common::Point(0, INFO_LINE + 1), INFO_FOREGROUND, messages[action._cAnimNum]); +		_infoFlag = true; + +		// Set how long to show the message +		_menuCounter = 30; +	} + +	// Reset cursor back to arrow +	events.setCursor(ARROW); +} +  } // End of namespace Sherlock diff --git a/engines/sherlock/user_interface.h b/engines/sherlock/user_interface.h index f80fe48b2d..9b104465cf 100644 --- a/engines/sherlock/user_interface.h +++ b/engines/sherlock/user_interface.h @@ -117,6 +117,7 @@ private:  	void checkUseAction(UseType &use, const Common::String &invName, const Common::String &msg,  		int objNum, int giveMode); +	void checkAction(ActionType &action, const char *const messages[], int objNum);  public:  	MenuMode _menuMode;  	int _menuCounter; | 
