SHERLOCK: Created common base class for Sprite and Object

This commit is contained in:
Paul Gilbert 2015-06-06 21:31:48 -04:00
parent 75610e7119
commit 3511f30a26
10 changed files with 382 additions and 193 deletions

View file

@ -74,13 +74,99 @@ static const AdjustWalk ADJUST_WALKS[NUM_ADJUSTED_WALKS] = {
SherlockEngine *Sprite::_vm; 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() { void Sprite::clear() {
_name = ""; _name = "";
_description = ""; _description = "";
_examine.clear(); _examine.clear();
_pickUp = ""; _pickUp = "";
_walkSequences.clear(); _walkSequences.clear();
_seq = nullptr; _sequences = nullptr;
_images = nullptr; _images = nullptr;
_imageFrame = nullptr; _imageFrame = nullptr;
_walkCount = 0; _walkCount = 0;
@ -482,9 +568,9 @@ void Sprite::checkWalkGraphics() {
} }
// If this is a different seqeunce from the current sequence, reset the appropriate variables // 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; _seqTo = _seqCounter = _seqCounter2 = _seqStack = _startSeq = 0;
_seq = &_walkSequences[_sequenceNumber]._sequences[0]; _sequences = &_walkSequences[_sequenceNumber]._sequences[0];
_seqSize = _walkSequences[_sequenceNumber]._sequences.size(); _seqSize = _walkSequences[_sequenceNumber]._sequences.size();
} }
@ -588,44 +674,12 @@ void Object::setVm(SherlockEngine *vm) {
_countCAnimFrames = false; _countCAnimFrames = false;
} }
Object::Object() { Object::Object(): BaseObject() {
_sequenceOffset = 0;
_sequences = nullptr;
_images = nullptr;
_imageFrame = nullptr;
_walkCount = 0;
_allow = 0;
_frameNumber = 0;
_sequenceNumber = 0; _sequenceNumber = 0;
_type = INVALID; _sequenceOffset = 0;
_pickup = 0; _pickup = 0;
_defaultCommand = 0; _defaultCommand = 0;
_lookFlag = 0;
_pickupFlag = 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) { void Object::load(Common::SeekableReadStream &s, bool isRoseTattoo) {
@ -703,7 +757,7 @@ void Object::load(Common::SeekableReadStream &s, bool isRoseTattoo) {
_quickDraw = s.readByte(); _quickDraw = s.readByte();
_scaleVal = s.readUint16LE(); _scaleVal = s.readUint16LE();
_requiredFlag1 = s.readSint16LE(); _requiredFlags1 = s.readSint16LE();
_gotoSeq = s.readByte(); _gotoSeq = s.readByte();
_talkSeq = s.readByte(); _talkSeq = s.readByte();
_restoreSlot = s.readByte(); _restoreSlot = s.readByte();
@ -1392,7 +1446,7 @@ int Object::pickUpObject(const char *const messages[]) {
} }
const Common::Rect Object::getNewBounds() const { const Common::Rect Object::getNewBounds() const {
Common::Point pt = _position; Point32 pt = _position;
if (_imageFrame) if (_imageFrame)
pt += _imageFrame->_offset; pt += _imageFrame->_offset;

View file

@ -161,8 +161,61 @@ struct UseType {
void load(Common::SeekableReadStream &s, bool isRoseTattoo); 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: private:
static SherlockEngine *_vm; static SherlockEngine *_vm;
@ -172,24 +225,11 @@ private:
void freeAltGraphics(); void freeAltGraphics();
public: public:
Common::String _name; Common::String _name;
Common::String _description;
Common::String _examine; // Examine in-depth description Common::String _examine; // Examine in-depth description
Common::String _pickUp; // Message for if you can't pick up object Common::String _pickUp; // Message for if you can't pick up object
WalkSequences _walkSequences; // Holds animation sequences 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 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 Common::Point _noShapeSize; // Size of a NO_SHAPE
int _status; // Status: open/closed, moved/not moved int _status; // Status: open/closed, moved/not moved
int8 _misc; // Miscellaneous use int8 _misc; // Miscellaneous use
@ -197,26 +237,6 @@ public:
// Rose Tattoo fields // Rose Tattoo fields
int _startSeq; // Frame sequence starts at 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 ImageFrame *_stopFrames[8]; // Stop/rest frame for each direction
ImageFile *_altImages; // Images used for alternate NPC sequences ImageFile *_altImages; // Images used for alternate NPC sequences
int _altSeq; // Which of the sequences the alt graphics apply to (0: main, 1=NPC seq) 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 Common::Point _adjust; // Fine tuning adjustment to position when drawn
int _oldWalkSequence; int _oldWalkSequence;
public: public:
Sprite() { clear(); } Sprite(): BaseObject() { clear(); }
virtual ~Sprite() {}
static void setVm(SherlockEngine *vm) { _vm = vm; } 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 }; enum { OBJ_BEHIND = 1, OBJ_FLIPPED = 2, OBJ_FORWARD = 4, TURNON_OBJ = 0x20, TURNOFF_OBJ = 0x40 };
#define USE_COUNT 4 #define USE_COUNT 4
class Object { class Object: public BaseObject {
private: private:
static SherlockEngine *_vm; static SherlockEngine *_vm;
@ -298,59 +319,17 @@ private:
* It then sets the frame number of the start of that sequence * It then sets the frame number of the start of that sequence
*/ */
void setObjSequence(int seq, bool wait); 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: public:
static bool _countCAnimFrames; static bool _countCAnimFrames;
static void setVm(SherlockEngine *vm); static void setVm(SherlockEngine *vm);
public: public:
Common::String _name; // Name Common::String _name; // Name
Common::String _description; // Description lines
Common::String _examine; // Examine in-depth description Common::String _examine; // Examine in-depth description
int _sequenceNumber;
int _sequenceOffset; 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 _pickup;
int _defaultCommand; // Default right-click command 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 // Serrated Scalpel fields
int _pickupFlag; // Which flag PICKUP will set (if any) int _pickupFlag; // Which flag PICKUP will set (if any)
@ -358,15 +337,8 @@ public:
ActionType _aClose; ActionType _aClose;
ActionType _aMove; ActionType _aMove;
// Rose Tattoo fields
int _quickDraw;
int _scaleVal;
int _requiredFlag1;
int _gotoSeq;
int _talkSeq;
int _restoreSlot;
Object(); Object();
virtual ~Object() {}
/** /**
* Load the data for the object * Load the data for the object
@ -432,6 +404,15 @@ public:
* Returns the old bounsd for the sprite from the previous frame * Returns the old bounsd for the sprite from the previous frame
*/ */
const Common::Rect getOldBounds() const; 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 { struct CAnim {

View file

@ -71,6 +71,12 @@ Person::Person() : Sprite(), _walkLoaded(false), _npcIndex(0), _npcStack(0), _np
Common::fill(&_npcPath[0], &_npcPath[MAX_NPC_PATH], 0); Common::fill(&_npcPath[0], &_npcPath[MAX_NPC_PATH], 0);
_tempX = _tempScaleVal = 0; _tempX = _tempScaleVal = 0;
_updateNPCPath = false; _updateNPCPath = false;
_npcIndex = 0;
_npcStack = 0;
_savedNpcSequence = 0;
_savedNpcFrame = 0;
_updateNPCPath = false;
_npcPause = false;
} }
void Person::clearNPC() { void Person::clearNPC() {

View file

@ -40,12 +40,50 @@ enum PeopleId {
}; };
// Animation sequence identifiers for characters // Animation sequence identifiers for characters
enum { enum {
WALK_RIGHT = 0, WALK_DOWN = 1, WALK_LEFT = 2, WALK_UP = 3, STOP_LEFT = 4, 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, STOP_DOWN = 5, STOP_RIGHT = 6, STOP_UP = 7, WALK_UPRIGHT = 8,
WALK_DOWNRIGHT = 9, WALK_UPLEFT = 10, WALK_DOWNLEFT = 11, WALK_DOWNRIGHT = 9, WALK_UPLEFT = 10, WALK_DOWNLEFT = 11,
STOP_UPRIGHT = 12, STOP_UPLEFT = 13, STOP_DOWNRIGHT = 14, 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 { enum {
@ -78,6 +116,8 @@ public:
bool _npcPause; bool _npcPause;
byte _npcPath[MAX_NPC_PATH]; byte _npcPath[MAX_NPC_PATH];
Common::String _npcName; Common::String _npcName;
int _savedNpcSequence;
int _savedNpcFrame;
int _tempX; int _tempX;
int _tempScaleVal; int _tempScaleVal;
bool _updateNPCPath; bool _updateNPCPath;

View file

@ -325,6 +325,35 @@ OpcodeReturn ScalpelTalk::cmdCarriageReturn(const byte *&str) {
return RET_SUCCESS; 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 Scalpel
} // End of namespace Sherlock } // End of namespace Sherlock

View file

@ -36,7 +36,7 @@ namespace Sherlock {
namespace Scalpel { namespace Scalpel {
class ScalpelTalk : public Talk { class ScalpelTalk : public Talk {
protected: private:
OpcodeReturn cmdAssignPortraitLocation(const byte *&str); OpcodeReturn cmdAssignPortraitLocation(const byte *&str);
OpcodeReturn cmdClearInfoLine(const byte *&str); OpcodeReturn cmdClearInfoLine(const byte *&str);
OpcodeReturn cmdClearWindow(const byte *&str); OpcodeReturn cmdClearWindow(const byte *&str);
@ -49,6 +49,11 @@ protected:
OpcodeReturn cmdSfxCommand(const byte *&str); OpcodeReturn cmdSfxCommand(const byte *&str);
OpcodeReturn cmdSummonWindow(const byte *&str); OpcodeReturn cmdSummonWindow(const byte *&str);
OpcodeReturn cmdCarriageReturn(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: public:
ScalpelTalk(SherlockEngine *vm); ScalpelTalk(SherlockEngine *vm);
virtual ~ScalpelTalk() {} virtual ~ScalpelTalk() {}

View file

@ -834,7 +834,7 @@ void Talk::clearSequences() {
void Talk::pullSequence() { void Talk::pullSequence() {
Scene &scene = *_vm->_scene; Scene &scene = *_vm->_scene;
if (_sequenceStack.empty()) if (_sequenceStack.empty() || IS_ROSE_TATTOO)
return; return;
SequenceEntry seq = _sequenceStack.pop(); SequenceEntry seq = _sequenceStack.pop();
@ -858,7 +858,7 @@ void Talk::pushSequence(int speaker) {
Scene &scene = *_vm->_scene; Scene &scene = *_vm->_scene;
// Only proceed if a speaker is specified // Only proceed if a speaker is specified
if (speaker == -1) if (speaker == -1 || IS_ROSE_TATTOO)
return; return;
SequenceEntry seqEntry; SequenceEntry seqEntry;
@ -907,35 +907,6 @@ void Talk::pushTalkSequence(Object *obj) {
error("Ran out of talk sequence stack space"); 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) { void Talk::setStillSeq(int speaker) {
People &people = *_vm->_people; People &people = *_vm->_people;
Scene &scene = *_vm->_scene; Scene &scene = *_vm->_scene;
@ -987,6 +958,14 @@ void Talk::doScript(const Common::String &script) {
_noTextYet = true; _noTextYet = true;
_endStr = false; _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) { if (_scriptMoreFlag) {
_scriptMoreFlag = 0; _scriptMoreFlag = 0;
str = _scriptStart + _scriptSaveIndex; str = _scriptStart + _scriptSaveIndex;
@ -998,12 +977,14 @@ void Talk::doScript(const Common::String &script) {
_speaker |= SPEAKER_REMOVE; _speaker |= SPEAKER_REMOVE;
} else { } else {
pushSequence(_speaker); pushSequence(_speaker);
ui.clearWindow(); if (IS_SERRATED_SCALPEL || ui._windowOpen)
ui.clearWindow();
// Need to switch speakers? // Need to switch speakers?
if (str[0] == _opcodes[OP_SWITCH_SPEAKER]) { if (str[0] == _opcodes[OP_SWITCH_SPEAKER]) {
_speaker = str[1] - 1; _speaker = str[1] - 1;
str += 2; str += IS_SERRATED_SCALPEL ? 2 : 3;
pullSequence(); pullSequence();
pushSequence(_speaker); pushSequence(_speaker);
setSequence(_speaker); setSequence(_speaker);
@ -1011,34 +992,36 @@ void Talk::doScript(const Common::String &script) {
setSequence(_speaker); setSequence(_speaker);
} }
// Assign portrait location? if (IS_SERRATED_SCALPEL) {
if (str[0] == _opcodes[OP_ASSIGN_PORTRAIT_LOCATION]) { // Assign portrait location?
switch (str[1] & 15) { if (str[0] == _opcodes[OP_ASSIGN_PORTRAIT_LOCATION]) {
case 1: switch (str[1] & 15) {
people._portraitSide = 20; case 1:
break; people._portraitSide = 20;
case 2: break;
people._portraitSide = 220; case 2:
break; people._portraitSide = 220;
case 3: break;
people._portraitSide = 120; case 3:
break; people._portraitSide = 120;
default: break;
break; default:
break;
}
if (str[1] > 15)
people._speakerFlip = true;
str += 2;
} }
if (str[1] > 15) // Remove portrait?
people._speakerFlip = true; if (str[0] == _opcodes[OP_REMOVE_PORTRAIT]) {
str += 2; _speaker = -1;
} } else {
// Nope, so set the first speaker
// Remove portrait? people.setTalking(_speaker);
if (str[0] == _opcodes[OP_REMOVE_PORTRAIT]) { }
_speaker = 255;
} else {
// Nope, so set the first speaker
people.setTalking(_speaker);
} }
} }

View file

@ -252,6 +252,11 @@ protected:
OpcodeReturn cmdToggleObject(const byte *&str); OpcodeReturn cmdToggleObject(const byte *&str);
OpcodeReturn cmdWalkToCAnimation(const byte *&str); OpcodeReturn cmdWalkToCAnimation(const byte *&str);
OpcodeReturn cmdWalkToCoords(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: public:
TalkSequence _talkSequenceStack[TALK_SEQUENCE_STACK_SIZE]; TalkSequence _talkSequenceStack[TALK_SEQUENCE_STACK_SIZE];
bool _talkToAbort; bool _talkToAbort;
@ -334,11 +339,6 @@ public:
*/ */
void pushTalkSequence(Object *obj); 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 * Returns true if the script stack is empty
*/ */

View file

@ -182,6 +182,92 @@ TattooTalk::TattooTalk(SherlockEngine *vm) : Talk(vm) {
_opcodeTable = OPCODE_METHODS; _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) { OpcodeReturn TattooTalk::cmdMouseOnOff(const byte *&str) {
Events &events = *_vm->_events; Events &events = *_vm->_events;
bool mouseOn = *++str == 2; bool mouseOn = *++str == 2;

View file

@ -36,7 +36,7 @@ namespace Sherlock {
namespace Tattoo { namespace Tattoo {
class TattooTalk : public Talk { class TattooTalk : public Talk {
protected: private:
OpcodeReturn cmdMouseOnOff(const byte *&str); OpcodeReturn cmdMouseOnOff(const byte *&str);
OpcodeReturn cmdNextSong(const byte *&str); OpcodeReturn cmdNextSong(const byte *&str);
OpcodeReturn cmdPassword(const byte *&str); OpcodeReturn cmdPassword(const byte *&str);
@ -70,6 +70,11 @@ protected:
OpcodeReturn cmdWalkNPCToCAnimation(const byte *&str); OpcodeReturn cmdWalkNPCToCAnimation(const byte *&str);
OpcodeReturn cmdWalkNPCToCoords(const byte *&str); OpcodeReturn cmdWalkNPCToCoords(const byte *&str);
OpcodeReturn cmdWalkHomesAndNPCToCoords(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: public:
TattooTalk(SherlockEngine *vm); TattooTalk(SherlockEngine *vm);
virtual ~TattooTalk() {} virtual ~TattooTalk() {}