SHERLOCK: Created common base class for Sprite and Object
This commit is contained in:
parent
75610e7119
commit
3511f30a26
10 changed files with 382 additions and 193 deletions
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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() {}
|
||||||
|
|
|
@ -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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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() {}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue