From bcc31b2a663545ec448d886d8ed16546593f849e Mon Sep 17 00:00:00 2001 From: Paul Gilbert Date: Sat, 23 May 2015 16:06:29 -0400 Subject: SHERLOCK: Implemented Tattoo loadWalk changes --- engines/sherlock/map.cpp | 12 ++- engines/sherlock/map.h | 2 +- engines/sherlock/objects.cpp | 19 +++-- engines/sherlock/objects.h | 28 +++++- engines/sherlock/people.cpp | 160 ++++++++++++++++++++++++++++++----- engines/sherlock/people.h | 22 +++-- engines/sherlock/scalpel/scalpel.cpp | 6 +- engines/sherlock/scene.cpp | 4 +- 8 files changed, 207 insertions(+), 46 deletions(-) (limited to 'engines') 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 _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 _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 _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 _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(); } -- cgit v1.2.3