From 60378fe22883387c9d116764dc631c5cd5a6d3f8 Mon Sep 17 00:00:00 2001 From: Paul Gilbert Date: Wed, 3 Jun 2015 21:03:44 -0400 Subject: SHERLOCK: Implemented setObjTalkSequence methods --- engines/sherlock/objects.cpp | 101 ++++++++++++++++++++++++++++++++++++++++++- engines/sherlock/objects.h | 15 +++++++ engines/sherlock/talk.cpp | 38 +++++++++++++--- engines/sherlock/talk.h | 25 ++++++++--- 4 files changed, 164 insertions(+), 15 deletions(-) diff --git a/engines/sherlock/objects.cpp b/engines/sherlock/objects.cpp index 124e7c5c1c..9e4a20f565 100644 --- a/engines/sherlock/objects.cpp +++ b/engines/sherlock/objects.cpp @@ -368,6 +368,24 @@ const Common::Rect Sprite::getOldBounds() const { return Common::Rect(_oldPosition.x, _oldPosition.y, _oldPosition.x + _oldSize.x, _oldPosition.y + _oldSize.y); } +void Sprite::setObjTalkSequence(int seq) { + assert(seq != -1 && _type == CHARACTER); + + if (_seqTo) { + // reset to previous value + _walkSequences[_sequenceNumber]._sequences[_frameNumber] = _seqTo; + _seqTo = 0; + } + + _sequenceNumber = _gotoSeq; + _frameNumber = 0; + checkWalkGraphics(); +} + +void Sprite::checkWalkGraphics() { + error("TODO: checkWalkGraphics"); +} + /*----------------------------------------------------------------*/ void WalkSequence::load(Common::SeekableReadStream &s) { @@ -493,7 +511,7 @@ Object::Object() { _requiredFlag1 = 0; _gotoSeq = 0; _talkSeq = 0; - _restoreSlot = 0; + _restoreSlot = -1; } void Object::load(Common::SeekableReadStream &s, bool isRoseTattoo) { @@ -888,7 +906,86 @@ void Object::setObjSequence(int seq, bool wait) { } void Object::setObjTalkSequence(int seq) { - error("TODO: setObjTalkSequence"); + Talk &talk = *_vm->_talk; + + // See if we're supposed to restore the object's sequence from the talk sequence stack + if (seq == -1) { + TalkSequence &ts = talk._talkSequenceStack[_restoreSlot]; + if (_seqTo != 0) + _sequences[_frameNumber] = _seqTo; + _frameNumber = ts._frameNumber; + _sequenceNumber = ts._sequenceNumber; + _seqStack = ts._seqStack; + _seqTo = ts._seqTo; + _seqCounter = ts._seqCounter; + _seqCounter2 = ts._seqCounter2; + _talkSeq = 0; + + // Flag this slot as free again + ts._obj = nullptr; + + return; + } + + assert(_type != CHARACTER); + + // If the object passed in is an NPC, set it's sequence through the sequence number rather + // than adjusting the frame number to a specific sub-sequence + /* + s = (SpriteType *)bg; + if (s->seqto) + { + // reset to previous value + s->WalkSeqs[s->fs]->Seq[s->fn] = s->seqto; + s->seqto = 0; + } + s->fs = s->GotoSeq; + s->fn = 0; + CheckWalkGraphics(s); + */ + + talk.pushTalkSequence(this); + int talkSeqNum = seq; + + // Find where the talk sequence data begins in the object + int idx = 0; + for (;;) { + // Get the Frame value + byte f = _sequences[idx++]; + + // See if we've found the beginning of a Talk Sequence + if ((f == TALK_SEQ_CODE && seq < 128) || (f == TALK_LISTEN_CODE && seq > 128)) { + --seq; + + // See if we're at the correct Talk Sequence Number + if (!(seq & 127)) + { + // Correct Sequence, Start Talking Here + if (_seqTo != 0) + _sequences[_frameNumber] = _seqTo; + _frameNumber = idx; + _seqTo = 0; + _seqStack = 0; + _seqCounter = 0; + _seqCounter2 = 0; + _talkSeq = talkSeqNum; + break; + } + } else { + // Move ahead any extra because of special control codes + switch (f) { + 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; + } + } + + // See if we're out of sequence data + if (idx >= (int)_seqSize) + break; + } } int Object::checkNameForCodes(const Common::String &name, const char *const messages[]) { diff --git a/engines/sherlock/objects.h b/engines/sherlock/objects.h index 936adc57d0..bd32948763 100644 --- a/engines/sherlock/objects.h +++ b/engines/sherlock/objects.h @@ -165,6 +165,12 @@ struct UseType { class Sprite { private: static SherlockEngine *_vm; + + /** + * Checks a sprite associated with an NPC to see if the frame sequence specified + * in the sequence number uses alternate graphics, and if so if they need to be loaded + */ + void checkWalkGraphics(); public: Common::String _name; Common::String _description; @@ -242,6 +248,15 @@ public: */ void checkSprite(); + /** + * 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); + /** * Return frame width */ diff --git a/engines/sherlock/talk.cpp b/engines/sherlock/talk.cpp index 319cb10850..bb5c11c81f 100644 --- a/engines/sherlock/talk.cpp +++ b/engines/sherlock/talk.cpp @@ -222,12 +222,13 @@ TalkHistoryEntry::TalkHistoryEntry() { /*----------------------------------------------------------------*/ -TalkSequences::TalkSequences(const byte *data) { - Common::copy(data, data + MAX_TALK_SEQUENCES, _data); -} - -void TalkSequences::clear() { - Common::fill(&_data[0], &_data[MAX_TALK_SEQUENCES], 0); +TalkSequence::TalkSequence() { + _obj = nullptr; + _frameNumber = 0; + _sequenceNumber = 0; + _seqStack = 0; + _seqTo = 0; + _seqCounter = _seqCounter2 = 0; } /*----------------------------------------------------------------*/ @@ -1022,6 +1023,31 @@ void Talk::pushSequence(int speaker) { error("script stack overflow"); } +void Talk::pushTalkSequence(Object *obj) { + // Check if the shape is already on the stack + for (uint idx = 0; idx < TALK_SEQUENCE_STACK_SIZE; ++idx) { + if (_talkSequenceStack[idx]._obj = obj) + return; + } + + // Find a free slot and save the details in it + for (uint idx = 0; idx < TALK_SEQUENCE_STACK_SIZE; ++idx) { + TalkSequence &ts = _talkSequenceStack[idx]; + if (ts._obj == nullptr) { + ts._obj = obj; + ts._frameNumber = obj->_frameNumber; + ts._sequenceNumber = obj->_sequenceNumber; + ts._seqStack = obj->_seqStack; + ts._seqTo = obj->_seqTo; + ts._seqCounter = obj->_seqCounter; + ts._seqCounter2 = obj->_seqCounter2; + return; + } + } + + error("Ran out of talk sequence stack space"); +} + void Talk::setSequence(int speaker) { People &people = *_vm->_people; Scene &scene = *_vm->_scene; diff --git a/engines/sherlock/talk.h b/engines/sherlock/talk.h index ebfe8f1732..79616b246b 100644 --- a/engines/sherlock/talk.h +++ b/engines/sherlock/talk.h @@ -29,11 +29,13 @@ #include "common/serializer.h" #include "common/stream.h" #include "common/stack.h" +#include "sherlock/objects.h" namespace Sherlock { #define MAX_TALK_SEQUENCES 11 #define MAX_TALK_FILES 500 +#define TALK_SEQUENCE_STACK_SIZE 20 enum { OP_SWITCH_SPEAKER = 0, @@ -153,16 +155,19 @@ struct TalkHistoryEntry { bool &operator[](int index) { return _data[index]; } }; -struct TalkSequences { - byte _data[MAX_TALK_SEQUENCES]; +struct TalkSequence { + Object *_obj; // Pointer to the bgshape that these values go to + short _frameNumber; // Frame number in frame sequence to draw + short _sequenceNumber; // Start frame of sequences that are repeated + int _seqStack; // Allows gosubs to return to calling frame + int _seqTo; // Allows 1-5, 8-3 type sequences encoded + int _seqCounter; // How many times this sequence has been executed + int _seqCounter2; - TalkSequences() { clear(); } - TalkSequences(const byte *data); - - byte &operator[](int idx) { return _data[idx]; } - void clear(); + TalkSequence(); }; + class Talk { friend class Scalpel::ScalpelUserInterface; private: @@ -248,6 +253,7 @@ protected: OpcodeReturn cmdWalkToCAnimation(const byte *&str); OpcodeReturn cmdWalkToCoords(const byte *&str); public: + TalkSequence _talkSequenceStack[TALK_SEQUENCE_STACK_SIZE]; bool _talkToAbort; int _talkCounter; int _talkTo; @@ -323,6 +329,11 @@ public: */ void pushSequence(int speaker); + /** + * Push a given shape's sequence data onto the Rose Tattoo talk sequence stack + */ + void pushTalkSequence(Object *obj); + /** * Change the sequence of the scene background object associated with the current speaker. */ -- cgit v1.2.3