diff options
Diffstat (limited to 'engines')
-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; |