aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--engines/sherlock/map.cpp12
-rw-r--r--engines/sherlock/map.h2
-rw-r--r--engines/sherlock/objects.cpp19
-rw-r--r--engines/sherlock/objects.h28
-rw-r--r--engines/sherlock/people.cpp160
-rw-r--r--engines/sherlock/people.h22
-rw-r--r--engines/sherlock/scalpel/scalpel.cpp6
-rw-r--r--engines/sherlock/scene.cpp4
8 files changed, 207 insertions, 46 deletions
diff --git a/engines/sherlock/map.cpp b/engines/sherlock/map.cpp
index 44ca7cd44c..4f034d8889 100644
--- a/engines/sherlock/map.cpp
+++ b/engines/sherlock/map.cpp
@@ -65,8 +65,12 @@ Map::Map(SherlockEngine *vm): _vm(vm), _topLine(g_system->getWidth(), 12) {
_oldCharPoint = 0;
_frameChangeFlag = false;
- for (int idx = 0; idx < MAX_HOLMES_SEQUENCE; ++idx)
- Common::fill(&_sequences[idx][0], &_sequences[idx][MAX_FRAME], 0);
+ // Initialise the initial walk sequence set
+ _walkSequences.resize(MAX_HOLMES_SEQUENCE);
+ for (int idx = 0; idx < MAX_HOLMES_SEQUENCE; ++idx) {
+ _walkSequences[idx]._sequences.resize(MAX_FRAME);
+ Common::fill(&_walkSequences[idx]._sequences[0], &_walkSequences[idx]._sequences[0] + MAX_FRAME, 0);
+ }
if (!_vm->isDemo())
loadData();
@@ -80,7 +84,7 @@ void Map::loadPoints(int count, const int *xList, const int *yList, const int *t
void Map::loadSequences(int count, const byte *seq) {
for (int idx = 0; idx < count; ++idx, seq += MAX_FRAME)
- Common::copy(seq, seq + MAX_FRAME, &_sequences[idx][0]);
+ Common::copy(seq, seq + MAX_FRAME, &_walkSequences[idx]._sequences[0]);
}
void Map::loadData() {
@@ -289,7 +293,7 @@ void Map::setupSprites() {
p._type = CHARACTER;
p._position = Common::Point(12400, 5000);
p._sequenceNumber = 0;
- p._sequences = &_sequences;
+ p._walkSequences = _walkSequences;
p._images = _shapes;
p._imageFrame = nullptr;
p._frameNumber = 0;
diff --git a/engines/sherlock/map.h b/engines/sherlock/map.h
index ab70b0885f..198b31e7d3 100644
--- a/engines/sherlock/map.h
+++ b/engines/sherlock/map.h
@@ -76,7 +76,7 @@ private:
ImageFile *_mapCursors;
ImageFile *_shapes;
ImageFile *_iconShapes;
- byte _sequences[MAX_HOLMES_SEQUENCE][MAX_FRAME];
+ Common::Array<WalkSequence> _walkSequences;
Point32 _lDrawnPos;
int _point;
bool _placesShown;
diff --git a/engines/sherlock/objects.cpp b/engines/sherlock/objects.cpp
index f3803518ee..0709f6b7a9 100644
--- a/engines/sherlock/objects.cpp
+++ b/engines/sherlock/objects.cpp
@@ -46,7 +46,7 @@ void Sprite::clear() {
_description = "";
_examine.clear();
_pickUp = "";
- _sequences = nullptr;
+ _walkSequences.clear();
_images = nullptr;
_imageFrame = nullptr;
_walkCount = 0;
@@ -63,12 +63,21 @@ void Sprite::clear() {
_status = 0;
_misc = 0;
_numFrames = 0;
+ _altImages = nullptr;
+ _altSequences = false;
+ Common::fill(&_stopFrames[0], &_stopFrames[8], (ImageFrame *)nullptr);
}
void Sprite::setImageFrame() {
- int imageNumber = (*_sequences)[_sequenceNumber][_frameNumber] +
- (*_sequences)[_sequenceNumber][0] - 2;
- _imageFrame = &(*_images)[imageNumber];
+ int frameNum = MAX(_frameNumber, 0);
+ int imageNumber = _walkSequences[_sequenceNumber][frameNum];
+
+ if (IS_SERRATED_SCALPEL)
+ imageNumber = imageNumber + +_walkSequences[_sequenceNumber][0] - 2;
+ else if (imageNumber > _numFrames)
+ imageNumber = 1;
+
+ _imageFrame = &(_altSequences ? *_altImages : *_images)[imageNumber];
}
void Sprite::adjustSprite() {
@@ -120,7 +129,7 @@ void Sprite::adjustSprite() {
if (!map._active || (map._frameChangeFlag = !map._frameChangeFlag))
++_frameNumber;
- if ((*_sequences)[_sequenceNumber][_frameNumber] == 0) {
+ if (_walkSequences[_sequenceNumber][_frameNumber] == 0) {
switch (_sequenceNumber) {
case STOP_UP:
case STOP_DOWN:
diff --git a/engines/sherlock/objects.h b/engines/sherlock/objects.h
index b61e7e24fe..761c03d501 100644
--- a/engines/sherlock/objects.h
+++ b/engines/sherlock/objects.h
@@ -46,7 +46,10 @@ enum SpriteType {
REMOVE = 5, // Object should be removed next frame
NO_SHAPE = 6, // Background object with no shape
HIDDEN = 7, // Hidden backgruond object
- HIDE_SHAPE = 8 // Object needs to be hidden
+ HIDE_SHAPE = 8, // Object needs to be hidden
+
+ // Rose Tattoo
+ HIDDEN_CHARACTER = 128
};
enum AType {
@@ -98,16 +101,31 @@ public:
void operator-=(const Point32 &delta) { x -= delta.x; y -= delta.y; }
};
+
+struct WalkSequence {
+ Common::String _vgsName;
+ bool _horizFlip;
+ Common::Array<byte> _sequences;
+
+ WalkSequence() : _vgsName(nullptr), _horizFlip(false) {}
+ const byte &operator[](int idx) { return _sequences[idx]; }
+
+ /**
+ * Load data for the sequence from a stream
+ */
+ void load(Common::SeekableReadStream &s);
+};
+
class Sprite {
private:
static SherlockEngine *_vm;
public:
Common::String _name;
Common::String _description;
- Common::StringArray _examine; // Examine in-depth description
+ Common::String _examine; // Examine in-depth description
Common::String _pickUp; // Message for if you can't pick up object
- const uint8 (*_sequences)[MAX_HOLMES_SEQUENCE][MAX_FRAME]; // Holds animation sequences
+ Common::Array<WalkSequence> _walkSequences; // Holds animation sequences
ImageFile *_images; // Sprite images
ImageFrame *_imageFrame; // Pointer to shape in the images
int _walkCount; // Character walk counter
@@ -124,8 +142,12 @@ public:
int _status; // Status: open/closed, moved/not moved
int8 _misc; // Miscellaneous use
int _numFrames; // How many frames the object has
+ ImageFile *_altImages;
+ bool _altSequences;
+ ImageFrame *_stopFrames[8]; // Stop/rest frame for each direction
public:
Sprite() { clear(); }
+
static void setVm(SherlockEngine *vm) { _vm = vm; }
/**
diff --git a/engines/sherlock/people.cpp b/engines/sherlock/people.cpp
index 3a630fdd99..638cbf662b 100644
--- a/engines/sherlock/people.cpp
+++ b/engines/sherlock/people.cpp
@@ -50,10 +50,37 @@ static const uint8 CHARACTER_SEQUENCES[MAX_HOLMES_SEQUENCE][MAX_FRAME] = {
{ 52, 1, 2, 3, 4, 0 } // Goto Stand Down Left
};
+// Rose Tattoo walk image libraries
+// Walk resources within WALK.LIB
+#define NUM_IN_WALK_LIB 10
+const char *const WALK_LIB_NAMES[10] = {
+ "SVGAWALK.VGS",
+ "COATWALK.VGS",
+ "WATSON.VGS",
+ "NOHAT.VGS",
+ "TUPRIGHT.VGS",
+ "TRIGHT.VGS",
+ "TDOWNRG.VGS",
+ "TWUPRIGH.VGS",
+ "TWRIGHT.VGS",
+ "TWDOWNRG.VGS"
+};
+
+/*----------------------------------------------------------------*/
+
+void WalkSequence::load(Common::SeekableReadStream &s) {
+ char buffer[9];
+ s.read(buffer, 9);
+ _vgsName = Common::String(buffer);
+ _horizFlip = s.readByte() != 0;
+
+ _sequences.resize(s.readUint16LE());
+ s.read(&_sequences[0], _sequences.size());
+}
+
/*----------------------------------------------------------------*/
People::People(SherlockEngine *vm) : _vm(vm), _player(_data[0]) {
- _walkLoaded = false;
_holmesOn = true;
_oldWalkSequence = -1;
_allowWalkAbort = false;
@@ -68,13 +95,18 @@ People::People(SherlockEngine *vm) : _vm(vm), _player(_data[0]) {
_holmesQuotient = 0;
_hSavedPos = Common::Point(-1, -1);
_hSavedFacing = -1;
+ _forceWalkReload = false;
+ _useWalkLib = false;
_portrait._sequences = new byte[32];
}
People::~People() {
- if (_walkLoaded)
- delete _data[PLAYER]._images;
+ for (int idx = 0; idx < MAX_PLAYERS; ++idx) {
+ if (_data[idx]._walkLoaded)
+ delete _data[PLAYER]._images;
+ }
+
delete _talkPics;
delete[] _portrait._sequences;
}
@@ -88,7 +120,6 @@ void People::reset() {
p._type = CHARACTER;
p._position = Common::Point(10000, 11000);
p._sequenceNumber = STOP_DOWNRIGHT;
- p._sequences = &CHARACTER_SEQUENCES;
p._imageFrame = nullptr;
p._frameNumber = 1;
p._delta = Common::Point(0, 0);
@@ -102,32 +133,106 @@ void People::reset() {
p._goto = Common::Point(0, 0);
p._status = 0;
+ // Load the default walk sequences
+ p._walkSequences.resize(MAX_HOLMES_SEQUENCE);
+ for (int idx = 0; idx < MAX_HOLMES_SEQUENCE; ++idx) {
+ p._walkSequences[idx]._sequences.clear();
+
+ const byte *pSrc = &CHARACTER_SEQUENCES[idx][0];
+ do {
+ p._walkSequences[idx]._sequences.push_back(*pSrc);
+ } while (*pSrc++);
+ }
+
// Reset any walk path in progress when Sherlock leaves scenes
_walkTo.clear();
}
bool People::loadWalk() {
- if (_walkLoaded) {
- return false;
+ Resources &res = *_vm->_res;
+ bool result = false;
+
+ if (IS_SERRATED_SCALPEL) {
+ if (_data[PLAYER]._walkLoaded) {
+ return false;
+ } else {
+ _data[PLAYER]._images = new ImageFile("walk.vgs");
+ _data[PLAYER].setImageFrame();
+ _data[PLAYER]._walkLoaded = true;
+
+ result = true;
+ }
} else {
- _data[PLAYER]._images = new ImageFile("walk.vgs");
- _data[PLAYER].setImageFrame();
- _walkLoaded = true;
+ for (int idx = 0; idx < MAX_PLAYERS; ++idx) {
+ if (!_data[idx]._walkLoaded && (_data[idx]._type == CHARACTER || _data[idx]._type == HIDDEN_CHARACTER)) {
+ if (_data[idx]._type == HIDDEN_CHARACTER)
+ _data[idx]._type = INVALID;
+
+ // See if this is one of the more used Walk Graphics stored in WALK.LIB
+ for (int libNum = 0; libNum < NUM_IN_WALK_LIB; ++libNum) {
+ if (!_data[0]._walkVGSName.compareToIgnoreCase(WALK_LIB_NAMES[libNum])) {
+ _useWalkLib = true;
+ break;
+ }
+ }
+
+ // Load the images for the character
+ _data[idx]._images = new ImageFile(_data[idx]._walkVGSName, false);
+ _data[idx]._numFrames = _data[idx]._images->size();
+
+ // Load walk sequence data
+ Common::String fname = Common::String(_data[idx]._walkVGSName.c_str(), strchr(_data[idx]._walkVGSName.c_str(), '.'));
+ fname += ".SEQ";
+
+ // Load the walk sequence data
+ Common::SeekableReadStream *stream = res.load(fname, _useWalkLib ? "walk.lib" : "vgs.lib");
+
+ _data[idx]._walkSequences.resize(stream->readByte());
+
+ for (uint seqNum = 0; seqNum < _data[idx]._walkSequences.size(); ++seqNum)
+ _data[idx]._walkSequences[seqNum].load(*stream);
+
+ // Close the sequences resource
+ delete stream;
+ _useWalkLib = false;
+
+ _data[idx]._frameNumber = 0;
+ _data[idx].setImageFrame();
+
+ // Set the stop Frames pointers
+ for (int dirNum = 0; dirNum < 8; ++dirNum) {
+ int count = 0;
+ while (_data[idx]._walkSequences[dirNum + 8][count] != 0)
+ ++count;
+ count += 2;
+ count = _data[idx]._walkSequences[dirNum + 8][count] - 1;
+ _data[idx]._stopFrames[dirNum] = &(*_data[idx]._images)[count];
+ }
- return true;
+ result = true;
+ _data[idx]._walkLoaded = true;
+ } else if (_data[idx]._type != CHARACTER) {
+ _data[idx]._walkLoaded = false;
+ }
+ }
}
+
+ _forceWalkReload = false;
+ return result;
}
bool People::freeWalk() {
- if (_walkLoaded) {
- delete _player._images;
- _player._images = nullptr;
+ bool result = false;
- _walkLoaded = false;
- return true;
- } else {
- return false;
+ for (int idx = 0; idx < MAX_PLAYERS; ++idx) {
+ if (_data[idx]._walkLoaded) {
+ delete _data[idx]._images;
+ _data[idx]._images = nullptr;
+ result = true;
+ }
}
+
+ return result;
}
void People::setWalking() {
@@ -553,9 +658,24 @@ void People::setTalking(int speaker) {
void People::synchronize(Common::Serializer &s) {
s.syncAsByte(_holmesOn);
- s.syncAsSint16LE(_player._position.x);
- s.syncAsSint16LE(_player._position.y);
- s.syncAsSint16LE(_player._sequenceNumber);
+
+ if (IS_SERRATED_SCALPEL) {
+ s.syncAsSint16LE(_player._position.x);
+ s.syncAsSint16LE(_player._position.y);
+ s.syncAsSint16LE(_player._sequenceNumber);
+ } else {
+ for (int idx = 0; idx < MAX_PLAYERS; ++idx) {
+ Person &p = _data[idx];
+ s.syncAsSint16LE(p._position.x);
+ s.syncAsSint16LE(p._position.y);
+ s.syncAsSint16LE(p._sequenceNumber);
+ s.syncAsSint16LE(p._type);
+ s.syncString(p._walkVGSName);
+ s.syncString(p._description);
+ s.syncString(p._examine);
+ }
+ }
+
s.syncAsSint16LE(_holmesQuotient);
if (s.isLoading()) {
diff --git a/engines/sherlock/people.h b/engines/sherlock/people.h
index 8244fd9b59..f3e7950400 100644
--- a/engines/sherlock/people.h
+++ b/engines/sherlock/people.h
@@ -30,13 +30,11 @@
namespace Sherlock {
-// Player definitions. The game has theoretical support for two player characters but only the first one is used.
-// Watson is, instead, handled by a different sprite in each scene, with a very simple initial movement, if any
enum PeopleId {
PLAYER = 0,
AL = 0,
PEG = 1,
- MAX_PLAYERS = 2
+ MAX_PLAYERS = 6
};
// Animation sequence identifiers for characters
@@ -63,20 +61,24 @@ struct PersonData {
_name(name), _portrait(portrait), _stillSequences(stillSequences), _talkSequences(talkSequences) {}
};
-class SherlockEngine;
-
class Person : public Sprite {
public:
- Person() : Sprite() {}
-
+ bool _walkLoaded;
Common::String _portrait;
+
+ // Rose Tattoo fields
+ Common::String _walkVGSName; // Name of walk library person is using
+ Common::Array<WalkSequence> _walkSequences;
+public:
+ Person() : Sprite(), _walkLoaded(false) {}
};
+class SherlockEngine;
+
class People {
private:
SherlockEngine *_vm;
Person _data[MAX_PLAYERS];
- bool _walkLoaded;
int _oldWalkSequence;
int _srcZone, _destZone;
public:
@@ -97,6 +99,8 @@ public:
bool _speakerFlip;
bool _holmesFlip;
int _holmesQuotient;
+ bool _forceWalkReload;
+ bool _useWalkLib;
public:
People(SherlockEngine *vm);
~People();
@@ -113,7 +117,7 @@ public:
/**
* Returns true if Sherlock is visible on the screen and enabled
*/
- bool isHolmesActive() const { return _walkLoaded && _holmesOn; }
+ bool isHolmesActive() const { return _data[0]._walkLoaded && _holmesOn; }
/**
* Reset the player data
diff --git a/engines/sherlock/scalpel/scalpel.cpp b/engines/sherlock/scalpel/scalpel.cpp
index 7209c34218..2a107b4d5e 100644
--- a/engines/sherlock/scalpel/scalpel.cpp
+++ b/engines/sherlock/scalpel/scalpel.cpp
@@ -837,9 +837,11 @@ void ScalpelEngine::eraseMirror12() {
void ScalpelEngine::doMirror12() {
People &people = *_people;
+ Person &player = people._player;
+
Common::Point pt((*_people)[AL]._position.x / 100, (*_people)[AL]._position.y / 100);
- int frameNum = (*people[AL]._sequences)[people[AL]._sequenceNumber][people[AL]._frameNumber] +
- (*people[AL]._sequences)[people[AL]._sequenceNumber][0] - 2;
+ int frameNum = player._walkSequences[player._sequenceNumber][player._frameNumber] +
+ player._walkSequences[player._sequenceNumber][0] - 2;
switch ((*_people)[AL]._sequenceNumber) {
case WALK_DOWN:
diff --git a/engines/sherlock/scene.cpp b/engines/sherlock/scene.cpp
index 933e60d96d..4672e3e7b1 100644
--- a/engines/sherlock/scene.cpp
+++ b/engines/sherlock/scene.cpp
@@ -536,7 +536,7 @@ bool Scene::loadScene(const Common::String &filename) {
delete rrmStream;
}
- // Clear user interface area and draw controls
+ // Handle drawing any on-screen interface
ui.drawInterface();
checkSceneStatus();
@@ -568,7 +568,7 @@ bool Scene::loadScene(const Common::String &filename) {
checkInventory();
// Handle starting any music for the scene
- if (sound._musicOn && sound.loadSong(_currentScene)) {
+ if (IS_SERRATED_SCALPEL && sound._musicOn && sound.loadSong(_currentScene)) {
if (sound._music)
sound.startSong();
}