From 3511f30a2621af4773df5271cdffb6275b9e829e Mon Sep 17 00:00:00 2001 From: Paul Gilbert Date: Sat, 6 Jun 2015 21:31:48 -0400 Subject: SHERLOCK: Created common base class for Sprite and Object --- engines/sherlock/objects.cpp | 132 +++++++++++++++++-------- engines/sherlock/objects.h | 155 +++++++++++++----------------- engines/sherlock/people.cpp | 6 ++ engines/sherlock/people.h | 44 ++++++++- engines/sherlock/scalpel/scalpel_talk.cpp | 29 ++++++ engines/sherlock/scalpel/scalpel_talk.h | 7 +- engines/sherlock/talk.cpp | 99 ++++++++----------- engines/sherlock/talk.h | 10 +- engines/sherlock/tattoo/tattoo_talk.cpp | 86 +++++++++++++++++ engines/sherlock/tattoo/tattoo_talk.h | 7 +- 10 files changed, 382 insertions(+), 193 deletions(-) (limited to 'engines/sherlock') diff --git a/engines/sherlock/objects.cpp b/engines/sherlock/objects.cpp index 52c13d8a44..2131626bc9 100644 --- a/engines/sherlock/objects.cpp +++ b/engines/sherlock/objects.cpp @@ -74,13 +74,99 @@ static const AdjustWalk ADJUST_WALKS[NUM_ADJUSTED_WALKS] = { SherlockEngine *Sprite::_vm; +/*----------------------------------------------------------------*/ + +BaseObject::BaseObject() { + _type = INVALID; + _sequences = nullptr; + _images = nullptr; + _imageFrame = nullptr; + _walkCount = 0; + _allow = 0; + _frameNumber = 0; + _lookFlag = 0; + _requiredFlag = 0; + _status = 0; + _misc = 0; + _maxFrames = 0; + _flags = 0; + _aType = OBJECT; + _lookFrames = 0; + _seqCounter = 0; + _lookFacing = 0; + _lookcAnim = 0; + _seqStack = 0; + _seqTo = 0; + _descOffset = 0; + _seqCounter2 = 0; + _seqSize = 0; + _quickDraw = 0; + _scaleVal = 0; + _requiredFlags1 = 0; + _gotoSeq = 0; + _talkSeq = 0; + _restoreSlot = 0; +} + +bool BaseObject::hasAborts() const { + int seqNum = _talkSeq; + + // See if the object is in it's regular sequence + bool startChecking = !seqNum || _type == CHARACTER; + + uint idx = 0; + do + { + // Get the Frame value + int v = _sequences[idx++]; + + // See if we found an Allow Talk Interrupt Code + if (startChecking && v == ALLOW_TALK_CODE) + return true; + + // If we've started checking and we've encountered another Talk or Listen Sequence Code, + // then we're done checking this sequence because this is where it would repeat + if (startChecking && (v == TALK_SEQ_CODE || v == TALK_LISTEN_CODE)) + return false; + + // See if we've found the beginning of a Talk Sequence + if ((v == TALK_SEQ_CODE && seqNum < 128) || (v == TALK_LISTEN_CODE && seqNum >= 128)) { + // If checking was already on and we came across one of these codes, then there couldn't + // have been an Allow Talk Interrupt code in the sequence we were checking, so we're done. + if (startChecking) + return false; + + seqNum--; + // See if we're at the correct Talk Sequence Number + if (!(seqNum & 127)) + { + // Correct Sequence, Start Checking Now + startChecking = true; + } + } else { + // Move ahead any extra because of special control codes + switch (v) { + case 0: idx++; break; + case MOVE_CODE: + case TELEPORT_CODE: idx += 4; break; + case CALL_TALK_CODE:idx += 8; break; + case HIDE_CODE: idx += 2; break; + } + } + } while (idx < _seqSize); + + return true; +} + +/*----------------------------------------------------------------*/ + void Sprite::clear() { _name = ""; _description = ""; _examine.clear(); _pickUp = ""; _walkSequences.clear(); - _seq = nullptr; + _sequences = nullptr; _images = nullptr; _imageFrame = nullptr; _walkCount = 0; @@ -482,9 +568,9 @@ void Sprite::checkWalkGraphics() { } // If this is a different seqeunce from the current sequence, reset the appropriate variables - if (_seq != &_walkSequences[_sequenceNumber]._sequences[0]) { + if (_sequences != &_walkSequences[_sequenceNumber]._sequences[0]) { _seqTo = _seqCounter = _seqCounter2 = _seqStack = _startSeq = 0; - _seq = &_walkSequences[_sequenceNumber]._sequences[0]; + _sequences = &_walkSequences[_sequenceNumber]._sequences[0]; _seqSize = _walkSequences[_sequenceNumber]._sequences.size(); } @@ -588,44 +674,12 @@ void Object::setVm(SherlockEngine *vm) { _countCAnimFrames = false; } -Object::Object() { - _sequenceOffset = 0; - _sequences = nullptr; - _images = nullptr; - _imageFrame = nullptr; - _walkCount = 0; - _allow = 0; - _frameNumber = 0; +Object::Object(): BaseObject() { _sequenceNumber = 0; - _type = INVALID; + _sequenceOffset = 0; _pickup = 0; _defaultCommand = 0; - _lookFlag = 0; _pickupFlag = 0; - _requiredFlag = 0; - _status = 0; - _misc = 0; - _maxFrames = 0; - _flags = 0; - _aOpen._cAnimNum = 0; - _aOpen._cAnimSpeed = 0; - _aType = OBJECT; - _lookFrames = 0; - _seqCounter = 0; - _lookFacing = 0; - _lookcAnim = 0; - _seqStack = 0; - _seqTo = 0; - _descOffset = 0; - _seqCounter2 = 0; - _seqSize = 0; - - _quickDraw = 0; - _scaleVal = 0; - _requiredFlag1 = 0; - _gotoSeq = 0; - _talkSeq = 0; - _restoreSlot = -1; } void Object::load(Common::SeekableReadStream &s, bool isRoseTattoo) { @@ -703,7 +757,7 @@ void Object::load(Common::SeekableReadStream &s, bool isRoseTattoo) { _quickDraw = s.readByte(); _scaleVal = s.readUint16LE(); - _requiredFlag1 = s.readSint16LE(); + _requiredFlags1 = s.readSint16LE(); _gotoSeq = s.readByte(); _talkSeq = s.readByte(); _restoreSlot = s.readByte(); @@ -1392,7 +1446,7 @@ int Object::pickUpObject(const char *const messages[]) { } const Common::Rect Object::getNewBounds() const { - Common::Point pt = _position; + Point32 pt = _position; if (_imageFrame) pt += _imageFrame->_offset; diff --git a/engines/sherlock/objects.h b/engines/sherlock/objects.h index c35b777be1..a21a37e580 100644 --- a/engines/sherlock/objects.h +++ b/engines/sherlock/objects.h @@ -161,8 +161,61 @@ struct UseType { void load(Common::SeekableReadStream &s, bool isRoseTattoo); }; +class BaseObject { +public: + SpriteType _type; // Type of object/sprite + Common::String _description; // Description lines + byte *_sequences; // Holds animation sequences + ImageFile *_images; // Sprite images + ImageFrame *_imageFrame; // Pointer to shape in the images + int _walkCount; // Walk counter + int _allow; // Allowed UI commands + int _frameNumber; // Frame number in rame sequence to draw + Point32 _position; // Current position + Point32 _delta; // Momvement amount + Common::Point _oldPosition; // Old position + Common::Point _oldSize; // Image's old size + Point32 _goto; // Walk destination -class Sprite { + int _lookFlag; // Which flag LOOK will set (if any) + int _requiredFlag; // Object will be hidden if not set + Common::Point _noShapeSize; // Size of a NO_SHAPE + int _status; // Status (open/closed, moved/not) + int8 _misc; // Misc field -- use varies with type + int _maxFrames; // Number of frames + int _flags; // Tells if object can be walked behind + AType _aType; // Tells if this is an object, person, talk, etc. + int _lookFrames; // How many frames to play of the look anim before pausing + int _seqCounter; // How many times this sequence has been executed + Point32 _lookPosition; // Where to walk when examining object + int _lookFacing; // Direction to face when examining object + int _lookcAnim; + int _seqStack; // Allows gosubs to return to calling frame + int _seqTo; // Allows 1-5, 8-3 type sequences encoded in 2 bytes + uint _descOffset; // Tells where description starts in DescText + int _seqCounter2; // Counter of calling frame sequence + uint _seqSize; // Tells where description starts + UseType _use[6]; // Serrated Scalpel uses 4, Rose Tattoo 6 + int _quickDraw; // Flag telling whether to use quick draw routine or not + int _scaleVal; // Tells how to scale the sprite + int _requiredFlags1; // This flag must also be set, or the sprite is hidden + int _gotoSeq; // Used by Talk to tell which sequence to goto when able + int _talkSeq; // Tells which talk sequence currently in use (Talk or Listen) + int _restoreSlot; // Used when talk returns to the previous sequence +public: + BaseObject(); + virtual ~BaseObject() {} + + /** + * Returns true if the the object has an Allow Talk Code in the sequence that it's + * currently running, specified by the _talkSeq field of the object. If it's 0, + * then it's a regular sequence. If it's not 0 but below 128, then it's a Talk Sequence. + * If it's above 128, then it's one of the Listen sequences. + */ + bool hasAborts() const; +}; + +class Sprite: public BaseObject { private: static SherlockEngine *_vm; @@ -172,24 +225,11 @@ private: void freeAltGraphics(); public: Common::String _name; - Common::String _description; Common::String _examine; // Examine in-depth description Common::String _pickUp; // Message for if you can't pick up object WalkSequences _walkSequences; // Holds animation sequences - byte *_seq; - ImageFile *_images; // Sprite images - ImageFrame *_imageFrame; // Pointer to shape in the images - int _walkCount; // Character walk counter - int _allow; // Allowed menu commands - ObjectAllow - int _frameNumber; // Frame number in rame sequence to draw int _sequenceNumber; // Sequence being used - Point32 _position; // Current position - Point32 _delta; // Momvement delta - Common::Point _oldPosition; // Old position - Common::Point _oldSize; // Image's old size - Common::Point _goto; // Walk destination - SpriteType _type; // Type of object Common::Point _noShapeSize; // Size of a NO_SHAPE int _status; // Status: open/closed, moved/not moved int8 _misc; // Miscellaneous use @@ -197,26 +237,6 @@ public: // Rose Tattoo fields int _startSeq; // Frame sequence starts at - int _flags; // Flags for the sprite - int _aType; // Tells if this is an object, person, talk, etc. - int _lookFrames; // How many frames to play of a canim before pausing - int _seqCounter; // How many times the sequence has been run - Common::Point _lookPosition; // Where to look when examining object - int _lookFacing; // Direction to face when examining object - int _lookCAnim; - int _seqStack; // Allow gosubs to return to calling frame - int _seqTo; // Allows 1-5, 8-3 type sequences encoded in 2 bytes - uint _descOffset; // Tells where description starts in description text for scene - int _seqCounter2; // Counter of calling frame sequence - uint _seqSize; // Size of sequence - UseType _use[6]; - int _quickDraw; // Flag telling whether to use quick draw routine or not - int _scaleVal; // Tells how to scale the sprite - int _requiredFlags1; // This flag must also be set, or the sprite is hidden - int _gotoSeq; // Used by Talk to tell which sequence to goto when able - int _talkSeq; // Tells which talk sequence currently in use (Talk or Listen) - int _restoreSlot; // Used when talk returns to the previous sequence - ImageFrame *_stopFrames[8]; // Stop/rest frame for each direction ImageFile *_altImages; // Images used for alternate NPC sequences int _altSeq; // Which of the sequences the alt graphics apply to (0: main, 1=NPC seq) @@ -224,7 +244,8 @@ public: Common::Point _adjust; // Fine tuning adjustment to position when drawn int _oldWalkSequence; public: - Sprite() { clear(); } + Sprite(): BaseObject() { clear(); } + virtual ~Sprite() {} static void setVm(SherlockEngine *vm) { _vm = vm; } @@ -282,7 +303,7 @@ public: enum { OBJ_BEHIND = 1, OBJ_FLIPPED = 2, OBJ_FORWARD = 4, TURNON_OBJ = 0x20, TURNOFF_OBJ = 0x40 }; #define USE_COUNT 4 -class Object { +class Object: public BaseObject { private: static SherlockEngine *_vm; @@ -298,59 +319,17 @@ private: * It then sets the frame number of the start of that sequence */ void setObjSequence(int seq, bool wait); - - /** - * Adjusts the frame and sequence variables of a sprite that corresponds to the current speaker - * so that it points to the beginning of the sequence number's talk sequence in the object's - * sequence buffer - * @param seq Which sequence to use (if there's more than 1) - * @remarks 1: First talk seq, 2: second talk seq, etc. - */ - void setObjTalkSequence(int seq); public: static bool _countCAnimFrames; static void setVm(SherlockEngine *vm); public: Common::String _name; // Name - Common::String _description; // Description lines Common::String _examine; // Examine in-depth description + int _sequenceNumber; int _sequenceOffset; - uint8 *_sequences; // Holds animation sequences - ImageFile *_images; // Sprite images - ImageFrame *_imageFrame; // Pointer to shape in the images - int _walkCount; // Character walk counter - int _allow; // Allowed menu commands - ObjectAllow - int _frameNumber; // Frame number in rame sequence to draw - int _sequenceNumber; // Sequence being used - SpriteType _type; // Object type - Common::Point _position; // Current position - Common::Point _delta; // Momvement amount - Common::Point _oldPosition; // Old position - Common::Point _oldSize; // Image's old size - Point32 _goto; // Walk destination - int _pickup; int _defaultCommand; // Default right-click command - int _lookFlag; // Which flag LOOK will set (if any) - int _requiredFlag; // Object will be hidden if not set - Common::Point _noShapeSize; // Size of a NO_SHAPE - int _status; // Status (open/closed, moved/not) - int8 _misc; // Misc field -- use varies with type - int _maxFrames; // Number of frames - int _flags; // Tells if object can be walked behind - AType _aType; // Tells if this is an object, person, talk, etc. - int _lookFrames; // How many frames to play of the look anim before pausing - int _seqCounter; // How many times this sequence has been executed - Point32 _lookPosition; // Where to walk when examining object - int _lookFacing; // Direction to face when examining object - int _lookcAnim; - int _seqStack; // Allows gosubs to return to calling frame - int _seqTo; // Allows 1-5, 8-3 type sequences encoded in 2 bytes - uint _descOffset; // Tells where description starts in DescText - int _seqCounter2; // Counter of calling frame sequence - uint _seqSize; // Tells where description starts - UseType _use[6]; // Serrated Scalpel uses 4, Rose Tattoo 6 // Serrated Scalpel fields int _pickupFlag; // Which flag PICKUP will set (if any) @@ -358,15 +337,8 @@ public: ActionType _aClose; ActionType _aMove; - // Rose Tattoo fields - int _quickDraw; - int _scaleVal; - int _requiredFlag1; - int _gotoSeq; - int _talkSeq; - int _restoreSlot; - Object(); + virtual ~Object() {} /** * Load the data for the object @@ -432,6 +404,15 @@ public: * Returns the old bounsd for the sprite from the previous frame */ const Common::Rect getOldBounds() const; + + /** + * Adjusts the frame and sequence variables of a sprite that corresponds to the current speaker + * so that it points to the beginning of the sequence number's talk sequence in the object's + * sequence buffer + * @param seq Which sequence to use (if there's more than 1) + * @remarks 1: First talk seq, 2: second talk seq, etc. + */ + void setObjTalkSequence(int seq); }; struct CAnim { diff --git a/engines/sherlock/people.cpp b/engines/sherlock/people.cpp index e59a90e5f8..0113e80f22 100644 --- a/engines/sherlock/people.cpp +++ b/engines/sherlock/people.cpp @@ -71,6 +71,12 @@ Person::Person() : Sprite(), _walkLoaded(false), _npcIndex(0), _npcStack(0), _np Common::fill(&_npcPath[0], &_npcPath[MAX_NPC_PATH], 0); _tempX = _tempScaleVal = 0; _updateNPCPath = false; + _npcIndex = 0; + _npcStack = 0; + _savedNpcSequence = 0; + _savedNpcFrame = 0; + _updateNPCPath = false; + _npcPause = false; } void Person::clearNPC() { diff --git a/engines/sherlock/people.h b/engines/sherlock/people.h index c26630c431..9d42afd6e7 100644 --- a/engines/sherlock/people.h +++ b/engines/sherlock/people.h @@ -40,12 +40,50 @@ enum PeopleId { }; // Animation sequence identifiers for characters -enum { +enum { WALK_RIGHT = 0, WALK_DOWN = 1, WALK_LEFT = 2, WALK_UP = 3, STOP_LEFT = 4, STOP_DOWN = 5, STOP_RIGHT = 6, STOP_UP = 7, WALK_UPRIGHT = 8, WALK_DOWNRIGHT = 9, WALK_UPLEFT = 10, WALK_DOWNLEFT = 11, STOP_UPRIGHT = 12, STOP_UPLEFT = 13, STOP_DOWNRIGHT = 14, - STOP_DOWNLEFT = 15, TALK_RIGHT = 6, TALK_LEFT = 4 + STOP_DOWNLEFT = 15, TALK_RIGHT = 6, TALK_LEFT = 4, +}; + +enum TattooSequences { + // Walk Sequences Numbers for NPCs + RT_WALK_UP = 0, + RT_WALK_UPRIGHT = 1, + RT_WALK_RIGHT = 2, + RT_WALK_DOWNRIGHT = 3, + RT_WALK_DOWN = 4, + RT_WALK_DOWNLEFT = 5, + RT_WALK_LEFT = 6, + RT_WALK_UPLEFT = 7, + + // Stop Sequences Numbers for NPCs + RT_STOP_UP = 8, + RT_STOP_UPRIGHT = 9, + RT_STOP_RIGHT = 10, + RT_STOP_DOWNRIGHT = 11, + RT_STOP_DOWN = 12, + RT_STOP_DOWNLEFT = 13, + RT_STOP_LEFT = 14, + RT_STOP_UPLEFT = 15, + + // NPC Talk Sequence Numbers + RT_TALK_UPRIGHT = 16, + RT_TALK_RIGHT = 17, + RT_TALK_DOWNRIGHT = 18, + RT_TALK_DOWNLEFT = 19, + RT_TALK_LEFT = 20, + RT_TALK_UPLEFT = 21, + + // NPC Listen Sequence Numbers + RT_LISTEN_UPRIGHT = 22, + RT_LISTEN_RIGHT = 23, + RT_LISTEN_DOWNRIGHT = 24, + RT_LISTEN_DOWNLEFT = 25, + RT_LISTEN_LEFT = 26, + RT_LISTEN_UPLEFT = 27 }; enum { @@ -78,6 +116,8 @@ public: bool _npcPause; byte _npcPath[MAX_NPC_PATH]; Common::String _npcName; + int _savedNpcSequence; + int _savedNpcFrame; int _tempX; int _tempScaleVal; bool _updateNPCPath; diff --git a/engines/sherlock/scalpel/scalpel_talk.cpp b/engines/sherlock/scalpel/scalpel_talk.cpp index 0b0259ce0f..65f7a76049 100644 --- a/engines/sherlock/scalpel/scalpel_talk.cpp +++ b/engines/sherlock/scalpel/scalpel_talk.cpp @@ -325,6 +325,35 @@ OpcodeReturn ScalpelTalk::cmdCarriageReturn(const byte *&str) { return RET_SUCCESS; } +void ScalpelTalk::setSequence(int speaker, int sequenceNum) { + People &people = *_vm->_people; + Scene &scene = *_vm->_scene; + + // If no speaker is specified, then nothing needs to be done + if (speaker == -1) + return; + + if (speaker) { + int objNum = people.findSpeaker(speaker); + if (objNum != -1) { + Object &obj = scene._bgShapes[objNum]; + + if (obj._seqSize < MAX_TALK_SEQUENCES) { + warning("Tried to copy too many talk frames"); + } else { + for (int idx = 0; idx < MAX_TALK_SEQUENCES; ++idx) { + obj._sequences[idx] = people._characters[speaker]._talkSequences[idx]; + if (idx > 0 && !obj._sequences[idx] && !obj._sequences[idx - 1]) + return; + + obj._frameNumber = 0; + obj._sequenceNumber = 0; + } + } + } + } +} + } // End of namespace Scalpel } // End of namespace Sherlock diff --git a/engines/sherlock/scalpel/scalpel_talk.h b/engines/sherlock/scalpel/scalpel_talk.h index 8121e1985e..1947e2cd79 100644 --- a/engines/sherlock/scalpel/scalpel_talk.h +++ b/engines/sherlock/scalpel/scalpel_talk.h @@ -36,7 +36,7 @@ namespace Sherlock { namespace Scalpel { class ScalpelTalk : public Talk { -protected: +private: OpcodeReturn cmdAssignPortraitLocation(const byte *&str); OpcodeReturn cmdClearInfoLine(const byte *&str); OpcodeReturn cmdClearWindow(const byte *&str); @@ -49,6 +49,11 @@ protected: OpcodeReturn cmdSfxCommand(const byte *&str); OpcodeReturn cmdSummonWindow(const byte *&str); OpcodeReturn cmdCarriageReturn(const byte *&str); +protected: + /** + * Change the sequence of the scene background object associated with the current speaker. + */ + virtual void setSequence(int speaker, int sequenceNum = 1); public: ScalpelTalk(SherlockEngine *vm); virtual ~ScalpelTalk() {} diff --git a/engines/sherlock/talk.cpp b/engines/sherlock/talk.cpp index dd2a2a93ca..9d67e024b3 100644 --- a/engines/sherlock/talk.cpp +++ b/engines/sherlock/talk.cpp @@ -834,7 +834,7 @@ void Talk::clearSequences() { void Talk::pullSequence() { Scene &scene = *_vm->_scene; - if (_sequenceStack.empty()) + if (_sequenceStack.empty() || IS_ROSE_TATTOO) return; SequenceEntry seq = _sequenceStack.pop(); @@ -858,7 +858,7 @@ void Talk::pushSequence(int speaker) { Scene &scene = *_vm->_scene; // Only proceed if a speaker is specified - if (speaker == -1) + if (speaker == -1 || IS_ROSE_TATTOO) return; SequenceEntry seqEntry; @@ -907,35 +907,6 @@ void Talk::pushTalkSequence(Object *obj) { error("Ran out of talk sequence stack space"); } -void Talk::setSequence(int speaker) { - People &people = *_vm->_people; - Scene &scene = *_vm->_scene; - - // If no speaker is specified, then nothing needs to be done - if (speaker == -1) - return; - - if (speaker) { - int objNum = people.findSpeaker(speaker); - if (objNum != -1) { - Object &obj = scene._bgShapes[objNum]; - - if (obj._seqSize < MAX_TALK_SEQUENCES) { - warning("Tried to copy too many talk frames"); - } else { - for (int idx = 0; idx < MAX_TALK_SEQUENCES; ++idx) { - obj._sequences[idx] = people._characters[speaker]._talkSequences[idx]; - if (idx > 0 && !obj._sequences[idx] && !obj._sequences[idx - 1]) - return; - - obj._frameNumber = 0; - obj._sequenceNumber = 0; - } - } - } - } -} - void Talk::setStillSeq(int speaker) { People &people = *_vm->_people; Scene &scene = *_vm->_scene; @@ -987,6 +958,14 @@ void Talk::doScript(const Common::String &script) { _noTextYet = true; _endStr = false; + if (IS_ROSE_TATTOO) { + for (uint idx = 0; idx < MAX_CHARACTERS; ++idx) { + Person &p = people[idx]; + p._savedNpcSequence = p._sequenceNumber; + p._savedNpcFrame = p._frameNumber; + } + } + if (_scriptMoreFlag) { _scriptMoreFlag = 0; str = _scriptStart + _scriptSaveIndex; @@ -998,12 +977,14 @@ void Talk::doScript(const Common::String &script) { _speaker |= SPEAKER_REMOVE; } else { pushSequence(_speaker); - ui.clearWindow(); + if (IS_SERRATED_SCALPEL || ui._windowOpen) + ui.clearWindow(); // Need to switch speakers? if (str[0] == _opcodes[OP_SWITCH_SPEAKER]) { _speaker = str[1] - 1; - str += 2; + str += IS_SERRATED_SCALPEL ? 2 : 3; + pullSequence(); pushSequence(_speaker); setSequence(_speaker); @@ -1011,34 +992,36 @@ void Talk::doScript(const Common::String &script) { setSequence(_speaker); } - // Assign portrait location? - if (str[0] == _opcodes[OP_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 (IS_SERRATED_SCALPEL) { + // Assign portrait location? + if (str[0] == _opcodes[OP_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; - } + if (str[1] > 15) + people._speakerFlip = true; + str += 2; + } - // Remove portrait? - if (str[0] == _opcodes[OP_REMOVE_PORTRAIT]) { - _speaker = 255; - } else { - // Nope, so set the first speaker - people.setTalking(_speaker); + // Remove portrait? + if (str[0] == _opcodes[OP_REMOVE_PORTRAIT]) { + _speaker = -1; + } else { + // Nope, so set the first speaker + people.setTalking(_speaker); + } } } diff --git a/engines/sherlock/talk.h b/engines/sherlock/talk.h index ccd09aee66..6c33bc72a9 100644 --- a/engines/sherlock/talk.h +++ b/engines/sherlock/talk.h @@ -252,6 +252,11 @@ protected: OpcodeReturn cmdToggleObject(const byte *&str); OpcodeReturn cmdWalkToCAnimation(const byte *&str); OpcodeReturn cmdWalkToCoords(const byte *&str); +protected: + /** + * Change the sequence of the scene background object associated with the current speaker. + */ + virtual void setSequence(int speaker, int sequenceNum = 1) = 0; public: TalkSequence _talkSequenceStack[TALK_SEQUENCE_STACK_SIZE]; bool _talkToAbort; @@ -334,11 +339,6 @@ public: */ void pushTalkSequence(Object *obj); - /** - * Change the sequence of the scene background object associated with the current speaker. - */ - void setSequence(int speaker); - /** * Returns true if the script stack is empty */ diff --git a/engines/sherlock/tattoo/tattoo_talk.cpp b/engines/sherlock/tattoo/tattoo_talk.cpp index 4075450c2e..c31b80fbfa 100644 --- a/engines/sherlock/tattoo/tattoo_talk.cpp +++ b/engines/sherlock/tattoo/tattoo_talk.cpp @@ -182,6 +182,92 @@ TattooTalk::TattooTalk(SherlockEngine *vm) : Talk(vm) { _opcodeTable = OPCODE_METHODS; } +void TattooTalk::setSequence(int speaker, int sequenceNum) { + People &people = *_vm->_people; + Scene &scene = *_vm->_scene; + + // If no speaker is specified, then nothing needs to be done + if (speaker == -1) + return; + + int objNum = people.findSpeaker(speaker); + if (objNum != -1 && objNum < 256) { + Object &obj = scene._bgShapes[objNum]; + + // See if the Object has to wait for an Abort Talk Code + if (obj.hasAborts()) { + pushTalkSequence(&obj); + obj._gotoSeq = sequenceNum; + } else { + obj.setObjTalkSequence(sequenceNum); + } + } else if (objNum != -1) { + objNum -= 256; + Person &person = people[objNum]; + int newDir = person._sequenceNumber; + + switch (newDir) { + case RT_WALK_UP: + case RT_STOP_UP: + case RT_WALK_UPRIGHT: + case RT_STOP_UPRIGHT: + case RT_TALK_UPRIGHT: + case RT_LISTEN_UPRIGHT: + newDir = RT_TALK_UPRIGHT; + break; + case RT_WALK_RIGHT: + case RT_STOP_RIGHT: + case RT_TALK_RIGHT: + case RT_LISTEN_RIGHT: + newDir = RT_TALK_RIGHT; + break; + case RT_WALK_DOWNRIGHT: + case RT_STOP_DOWNRIGHT: + case RT_TALK_DOWNRIGHT: + case RT_LISTEN_DOWNRIGHT: + newDir = RT_TALK_DOWNRIGHT; + break; + case RT_WALK_DOWN: + case RT_STOP_DOWN: + case RT_WALK_DOWNLEFT: + case RT_STOP_DOWNLEFT: + case RT_TALK_DOWNLEFT: + case RT_LISTEN_DOWNLEFT: + newDir = RT_TALK_DOWNLEFT; + break; + case RT_WALK_LEFT: + case RT_STOP_LEFT: + case RT_TALK_LEFT: + case RT_LISTEN_LEFT: + newDir = RT_TALK_LEFT; + break; + case RT_WALK_UPLEFT: + case RT_STOP_UPLEFT: + case RT_TALK_UPLEFT: + case RT_LISTEN_UPLEFT: + newDir = RT_TALK_UPLEFT; + break; + default: + break; + } + + // See if the NPC's sequence has to wait for an Abort Talk Code + if (person.hasAborts()) { + person._gotoSeq = newDir; + } else { + if (person._seqTo) { + // Reset to previous value + person._walkSequences[person._sequenceNumber]._sequences[person._frameNumber] = person._seqTo; + person._seqTo = 0; + } + + person._sequenceNumber = newDir; + person._frameNumber = 0; + person.checkWalkGraphics(); + } + } +} + OpcodeReturn TattooTalk::cmdMouseOnOff(const byte *&str) { Events &events = *_vm->_events; bool mouseOn = *++str == 2; diff --git a/engines/sherlock/tattoo/tattoo_talk.h b/engines/sherlock/tattoo/tattoo_talk.h index 9290a244c9..eb858c09bc 100644 --- a/engines/sherlock/tattoo/tattoo_talk.h +++ b/engines/sherlock/tattoo/tattoo_talk.h @@ -36,7 +36,7 @@ namespace Sherlock { namespace Tattoo { class TattooTalk : public Talk { -protected: +private: OpcodeReturn cmdMouseOnOff(const byte *&str); OpcodeReturn cmdNextSong(const byte *&str); OpcodeReturn cmdPassword(const byte *&str); @@ -70,6 +70,11 @@ protected: OpcodeReturn cmdWalkNPCToCAnimation(const byte *&str); OpcodeReturn cmdWalkNPCToCoords(const byte *&str); OpcodeReturn cmdWalkHomesAndNPCToCoords(const byte *&str); +protected: + /** + * Change the sequence of the scene background object associated with the current speaker. + */ + virtual void setSequence(int speaker, int sequenceNum = 1); public: TattooTalk(SherlockEngine *vm); virtual ~TattooTalk() {} -- cgit v1.2.3