From f5a1b626b710c368e79ab27c13cf2be4ccdcb30f Mon Sep 17 00:00:00 2001 From: Paul Gilbert Date: Mon, 8 Jun 2015 08:31:51 -0400 Subject: [PATCH] SHERLOCK: Move Scalpel map code to ScalpelMap --- engines/sherlock/map.cpp | 529 +------------------- engines/sherlock/map.h | 128 +---- engines/sherlock/objects.cpp | 11 +- engines/sherlock/people.cpp | 50 -- engines/sherlock/people.h | 12 +- engines/sherlock/scalpel/scalpel.cpp | 8 +- engines/sherlock/scalpel/scalpel_map.cpp | 528 +++++++++++++++++++ engines/sherlock/scalpel/scalpel_map.h | 130 ++++- engines/sherlock/scalpel/scalpel_people.cpp | 53 +- engines/sherlock/scalpel/scalpel_people.h | 6 + engines/sherlock/scalpel/scalpel_scene.cpp | 230 +++++++++ engines/sherlock/scalpel/scalpel_scene.h | 21 + engines/sherlock/scalpel/scalpel_talk.cpp | 6 +- engines/sherlock/scene.cpp | 224 --------- engines/sherlock/scene.h | 22 +- engines/sherlock/tattoo/tattoo_map.cpp | 4 + engines/sherlock/tattoo/tattoo_map.h | 5 + engines/sherlock/tattoo/tattoo_people.cpp | 4 + engines/sherlock/tattoo/tattoo_people.h | 6 + engines/sherlock/tattoo/tattoo_scene.cpp | 4 + engines/sherlock/tattoo/tattoo_scene.h | 9 + 21 files changed, 1038 insertions(+), 952 deletions(-) diff --git a/engines/sherlock/map.cpp b/engines/sherlock/map.cpp index 3f9c9f5e752f..fbccaf244fbb 100644 --- a/engines/sherlock/map.cpp +++ b/engines/sherlock/map.cpp @@ -28,31 +28,6 @@ namespace Sherlock { -MapPaths::MapPaths() { - _numLocations = 0; -} - -void MapPaths::load(int numLocations, Common::SeekableReadStream &s) { - _numLocations = numLocations; - _paths.resize(_numLocations * _numLocations); - - for (int idx = 0; idx < (numLocations * numLocations); ++idx) { - Common::Array &path = _paths[idx]; - int v; - - do { - v = s.readByte(); - path.push_back(v); - } while (v && v < 254); - } -} - -const byte *MapPaths::getPath(int srcLocation, int destLocation) { - return &_paths[srcLocation * _numLocations + destLocation][0]; -} - -/*----------------------------------------------------------------*/ - Map *Map::init(SherlockEngine *vm) { if (vm->getGameID() == GType_SerratedScalpel) return new Scalpel::ScalpelMap(vm); @@ -60,506 +35,9 @@ Map *Map::init(SherlockEngine *vm) { return new Tattoo::TattooMap(vm); } -Map::Map(SherlockEngine *vm): _vm(vm), _topLine(g_system->getWidth(), 12, vm->getPlatform()) { - _active = false; - _mapCursors = nullptr; - _shapes = nullptr; - _iconShapes = nullptr; - _point = 0; - _placesShown = false; - _cursorIndex = -1; - _drawMap = false; - _overPos = Point32(130 * FIXED_INT_MULTIPLIER, 126 * FIXED_INT_MULTIPLIER); - _charPoint = 0; - _oldCharPoint = 0; - _frameChangeFlag = false; - - // 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(); -} - -void Map::loadPoints(int count, const int *xList, const int *yList, const int *transList) { - for (int idx = 0; idx < count; ++idx, ++xList, ++yList, ++transList) { - _points.push_back(MapEntry(*xList, *yList, *transList)); - } -} - -void Map::loadSequences(int count, const byte *seq) { - for (int idx = 0; idx < count; ++idx, seq += MAX_FRAME) - Common::copy(seq, seq + MAX_FRAME, &_walkSequences[idx]._sequences[0]); -} - -void Map::loadData() { - // TODO: Remove this - if (_vm->getGameID() == GType_RoseTattoo) - return; - - // Load the list of location names - Common::SeekableReadStream *txtStream = _vm->_res->load( - _vm->getGameID() == GType_SerratedScalpel ? "chess.txt" : "map.txt"); - - int streamSize = txtStream->size(); - while (txtStream->pos() < streamSize) { - Common::String line; - char c; - while ((c = txtStream->readByte()) != '\0') - line += c; - - _locationNames.push_back(line); - } - - delete txtStream; - - // Load the path data - Common::SeekableReadStream *pathStream = _vm->_res->load("chess.pth"); - - // Get routes between different locations on the map - _paths.load(31, *pathStream); - - // Load in the co-ordinates that the paths refer to - _pathPoints.resize(208); - for (uint idx = 0; idx < _pathPoints.size(); ++idx) { - _pathPoints[idx].x = pathStream->readSint16LE(); - _pathPoints[idx].y = pathStream->readSint16LE(); - } - - delete pathStream; -} - -int Map::show() { - Events &events = *_vm->_events; - People &people = *_vm->_people; - Screen &screen = *_vm->_screen; - bool changed = false, exitFlag = false; - _active = true; - - // Set font and custom cursor for the map - int oldFont = screen.fontNumber(); - screen.setFont(0); - - // Initial screen clear - screen._backBuffer1.clear(); - screen.clear(); - - // Load the entire map - ImageFile bigMap("bigmap.vgs"); - screen.setPalette(bigMap._palette); - - // Load need sprites - setupSprites(); - - screen._backBuffer1.blitFrom(bigMap[0], Common::Point(-_bigPos.x, -_bigPos.y)); - screen._backBuffer1.blitFrom(bigMap[1], Common::Point(-_bigPos.x, SHERLOCK_SCREEN_HEIGHT - _bigPos.y)); - screen._backBuffer1.blitFrom(bigMap[2], Common::Point(SHERLOCK_SCREEN_WIDTH - _bigPos.x, -_bigPos.y)); - screen._backBuffer1.blitFrom(bigMap[3], Common::Point(SHERLOCK_SCREEN_WIDTH - _bigPos.x, SHERLOCK_SCREEN_HEIGHT - _bigPos.y)); - - _drawMap = true; - _charPoint = -1; - _point = -1; - people[AL]._position = _lDrawnPos = _overPos; - - // Show place icons - showPlaces(); - saveTopLine(); - _placesShown = true; - - // Keep looping until either a location is picked, or the game is ended - while (!_vm->shouldQuit() && !exitFlag) { - events.pollEventsAndWait(); - events.setButtonState(); - - // Keyboard handling - if (events.kbHit()) { - Common::KeyState keyState = events.getKey(); - - if (keyState.keycode == Common::KEYCODE_RETURN || keyState.keycode == Common::KEYCODE_SPACE) { - // Both space and enter simulate a mouse release - events._pressed = false; - events._released = true; - events._oldButtons = 0; - } - } - - // Ignore scrolling attempts until the screen is drawn - if (!_drawMap) { - Common::Point pt = events.mousePos(); - - // Check for vertical map scrolling - if ((pt.y > (SHERLOCK_SCREEN_HEIGHT - 10) && _bigPos.y < 200) || (pt.y < 10 && _bigPos.y > 0)) { - if (pt.y > (SHERLOCK_SCREEN_HEIGHT - 10)) - _bigPos.y += 10; - else - _bigPos.y -= 10; - - changed = true; - } - - // Check for horizontal map scrolling - if ((pt.x > (SHERLOCK_SCREEN_WIDTH - 10) && _bigPos.x < 315) || (pt.x < 10 && _bigPos.x > 0)) { - if (pt.x > (SHERLOCK_SCREEN_WIDTH - 10)) - _bigPos.x += 15; - else - _bigPos.x -= 15; - - changed = true; - } - } - - if (changed) { - // Map has scrolled, so redraw new map view - changed = false; - - screen._backBuffer1.blitFrom(bigMap[0], Common::Point(-_bigPos.x, -_bigPos.y)); - screen._backBuffer1.blitFrom(bigMap[1], Common::Point(-_bigPos.x, SHERLOCK_SCREEN_HEIGHT - _bigPos.y)); - screen._backBuffer1.blitFrom(bigMap[2], Common::Point(SHERLOCK_SCREEN_WIDTH - _bigPos.x, -_bigPos.y)); - screen._backBuffer1.blitFrom(bigMap[3], Common::Point(SHERLOCK_SCREEN_WIDTH - _bigPos.x, SHERLOCK_SCREEN_HEIGHT - _bigPos.y)); - - showPlaces(); - _placesShown = false; - - saveTopLine(); - _savedPos.x = -1; - updateMap(true); - } else if (!_drawMap) { - if (!_placesShown) { - showPlaces(); - _placesShown = true; - } - - if (_cursorIndex == 0) { - Common::Point pt = events.mousePos(); - highlightIcon(Common::Point(pt.x - 4 + _bigPos.x, pt.y + _bigPos.y)); - } - updateMap(false); - } - - if ((events._released || events._rightReleased) && _point != -1) { - if (people[AL]._walkCount == 0) { - people._walkDest = _points[_point] + Common::Point(4, 9); - _charPoint = _point; - - // Start walking to selected location - walkTheStreets(); - - // Show wait cursor - _cursorIndex = 1; - events.setCursor((*_mapCursors)[_cursorIndex]._frame); - } - } - - // Check if a scene has beeen selected and we've finished "moving" to it - if (people[AL]._walkCount == 0) { - if (_charPoint >= 1 && _charPoint < (int)_points.size()) - exitFlag = true; - } - - if (_drawMap) { - _drawMap = false; - - if (screen._fadeStyle) - screen.randomTransition(); - else - screen.slamArea(0, 0, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT); - } - - // Wait for a frame - events.wait(1); - } - - freeSprites(); - _overPos = people[AL]._position; - - // Reset font - screen.setFont(oldFont); - - _active = false; - return _charPoint; -} - -void Map::setupSprites() { - Events &events = *_vm->_events; - People &people = *_vm->_people; - Scene &scene = *_vm->_scene; - _savedPos.x = -1; - - _mapCursors = new ImageFile("omouse.vgs"); - _cursorIndex = 0; - events.setCursor((*_mapCursors)[_cursorIndex]._frame); - - _shapes = new ImageFile("mapicon.vgs"); - _iconShapes = new ImageFile("overicon.vgs"); - _iconSave.create((*_shapes)[4]._width, (*_shapes)[4]._height, _vm->getPlatform()); - Person &p = people[AL]; - p._description = " "; - p._type = CHARACTER; - p._position = Common::Point(12400, 5000); - p._sequenceNumber = 0; - p._images = _shapes; - p._imageFrame = nullptr; - p._frameNumber = 0; - p._delta = Common::Point(0, 0); - p._oldSize = Common::Point(0, 0); - p._oldSize = Common::Point(0, 0); - p._misc = 0; - p._walkCount = 0; - p._allow = 0; - p._noShapeSize = Common::Point(0, 0); - p._goto = Common::Point(28000, 15000); - p._status = 0; - p._walkSequences = _walkSequences; - p.setImageFrame(); - scene._bgShapes.clear(); -} - -void Map::freeSprites() { - delete _mapCursors; - delete _shapes; - delete _iconShapes; - _iconSave.free(); -} - -void Map::showPlaces() { - Screen &screen = *_vm->_screen; - - for (uint idx = 0; idx < _points.size(); ++idx) { - const MapEntry &pt = _points[idx]; - - if (pt.x != 0 && pt.y != 0) { - if (pt.x >= _bigPos.x && (pt.x - _bigPos.x) < SHERLOCK_SCREEN_WIDTH - && pt.y >= _bigPos.y && (pt.y - _bigPos.y) < SHERLOCK_SCREEN_HEIGHT) { - if (_vm->readFlags(idx)) { - screen._backBuffer1.transBlitFrom((*_iconShapes)[pt._translate], - Common::Point(pt.x - _bigPos.x - 6, pt.y - _bigPos.y - 12)); - } - } - } - } -} - -void Map::saveTopLine() { - _topLine.blitFrom(_vm->_screen->_backBuffer1, Common::Point(0, 0), Common::Rect(0, 0, SHERLOCK_SCREEN_WIDTH, 12)); -} - -void Map::eraseTopLine() { - Screen &screen = *_vm->_screen; - screen._backBuffer1.blitFrom(_topLine, Common::Point(0, 0)); - screen.slamArea(0, 0, SHERLOCK_SCREEN_WIDTH, _topLine.h()); -} - -void Map::showPlaceName(int idx, bool highlighted) { - People &people = *_vm->_people; - Screen &screen = *_vm->_screen; - - Common::String name = _locationNames[idx]; - int width = screen.stringWidth(name); - - if (!_cursorIndex) { - saveIcon(people[AL]._imageFrame, _lDrawnPos); - - bool flipped = people[AL]._sequenceNumber == MAP_DOWNLEFT || people[AL]._sequenceNumber == MAP_LEFT - || people[AL]._sequenceNumber == MAP_UPLEFT; - screen._backBuffer1.transBlitFrom(*people[AL]._imageFrame, _lDrawnPos, flipped); - } - - if (highlighted) { - int xp = (SHERLOCK_SCREEN_WIDTH - screen.stringWidth(name)) / 2; - screen.gPrint(Common::Point(xp + 2, 2), 0, "%s", name.c_str()); - screen.gPrint(Common::Point(xp + 1, 1), 0, "%s", name.c_str()); - screen.gPrint(Common::Point(xp, 0), 12, "%s", name.c_str()); - - screen.slamArea(xp, 0, width + 2, 15); - } -} - -void Map::updateMap(bool flushScreen) { - Events &events = *_vm->_events; - People &people = *_vm->_people; - Screen &screen = *_vm->_screen; - Common::Point osPos = _savedPos; - Common::Point osSize = _savedSize; - Common::Point hPos; - - if (_cursorIndex >= 1) { - if (++_cursorIndex > (1 + 8)) - _cursorIndex = 1; - - events.setCursor((*_mapCursors)[(_cursorIndex + 1) / 2]._frame); - } - - if (!_drawMap && !flushScreen) - restoreIcon(); - else - _savedPos.x = -1; - - people[AL].adjustSprite(); - - _lDrawnPos.x = hPos.x = people[AL]._position.x / FIXED_INT_MULTIPLIER - _bigPos.x; - _lDrawnPos.y = hPos.y = people[AL]._position.y / FIXED_INT_MULTIPLIER - people[AL].frameHeight() - _bigPos.y; - - // Draw the person icon - saveIcon(people[AL]._imageFrame, hPos); - if (people[AL]._sequenceNumber == MAP_DOWNLEFT || people[AL]._sequenceNumber == MAP_LEFT - || people[AL]._sequenceNumber == MAP_UPLEFT) - screen._backBuffer1.transBlitFrom(*people[AL]._imageFrame, hPos, true); - else - screen._backBuffer1.transBlitFrom(*people[AL]._imageFrame, hPos, false); - - if (flushScreen) { - screen.slamArea(0, 0, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT); - } else if (!_drawMap) { - if (hPos.x > 0 && hPos.y >= 0 && hPos.x < SHERLOCK_SCREEN_WIDTH && hPos.y < SHERLOCK_SCREEN_HEIGHT) - screen.flushImage(people[AL]._imageFrame, Common::Point(people[AL]._position.x / FIXED_INT_MULTIPLIER - _bigPos.x, - people[AL]._position.y / FIXED_INT_MULTIPLIER - people[AL].frameHeight() - _bigPos.y), - &people[AL]._oldPosition.x, &people[AL]._oldPosition.y, &people[AL]._oldSize.x, &people[AL]._oldSize.y); - - if (osPos.x != -1) - screen.slamArea(osPos.x, osPos.y, osSize.x, osSize.y); - } -} - -void Map::walkTheStreets() { - People &people = *_vm->_people; - Common::Array tempPath; - - // Get indexes into the path lists for the start and destination scenes - int start = _points[_oldCharPoint]._translate; - int dest = _points[_charPoint]._translate; - - // Get pointer to start of path - const byte *path = _paths.getPath(start, dest); - - // Add in destination position - people._walkTo.clear(); - Common::Point destPos = people._walkDest; - - // Check for any intermediate points between the two locations - if (path[0] || _charPoint > 50 || _oldCharPoint > 50) { - people[AL]._sequenceNumber = -1; - - if (_charPoint == 51 || _oldCharPoint == 51) { - people.setWalking(); - } else { - bool reversePath = false; - - // Check for moving the path backwards or forwards - if (path[0] == 255) { - reversePath = true; - SWAP(start, dest); - path = _paths.getPath(start, dest); - } - - do { - int idx = *path++; - tempPath.push_back(_pathPoints[idx - 1] + Common::Point(4, 4)); - } while (*path != 254); - - // Load up the path to use - people._walkTo.clear(); - - if (reversePath) { - for (int idx = (int)tempPath.size() - 1; idx >= 0; --idx) - people._walkTo.push(tempPath[idx]); - } else { - for (int idx = 0; idx < (int)tempPath.size(); ++idx) - people._walkTo.push(tempPath[idx]); - } - - people._walkDest = people._walkTo.pop() + Common::Point(12, 6); - people.setWalking(); - } - } else { - people[AL]._walkCount = 0; - } - - // Store the final destination icon position - people._walkTo.push(destPos); -} - -void Map::saveIcon(ImageFrame *src, const Common::Point &pt) { - Screen &screen = *_vm->_screen; - Common::Point size(src->_width, src->_height); - Common::Point pos = pt; - - if (pos.x < 0) { - size.x += pos.x; - pos.x = 0; - } - - if (pos.y < 0) { - size.y += pos.y; - pos.y = 0; - } - - if ((pos.x + size.x) > SHERLOCK_SCREEN_WIDTH) - size.x -= (pos.x + size.x) - SHERLOCK_SCREEN_WIDTH; - - if ((pos.y + size.y) > SHERLOCK_SCREEN_HEIGHT) - size.y -= (pos.y + size.y) - SHERLOCK_SCREEN_HEIGHT; - - if (size.x < 1 || size.y < 1 || pos.x >= SHERLOCK_SCREEN_WIDTH || pos.y >= SHERLOCK_SCREEN_HEIGHT || _drawMap) { - // Flag as the area not needing to be saved - _savedPos.x = -1; - return; - } - - assert(size.x <= _iconSave.w() && size.y <= _iconSave.h()); - _iconSave.blitFrom(screen._backBuffer1, Common::Point(0, 0), - Common::Rect(pos.x, pos.y, pos.x + size.x, pos.y + size.y)); - _savedPos = pos; - _savedSize = size; -} - -void Map::restoreIcon() { - Screen &screen = *_vm->_screen; - - if (_savedPos.x >= 0 && _savedPos.y >= 0 && _savedPos.x <= SHERLOCK_SCREEN_WIDTH - && _savedPos.y < SHERLOCK_SCREEN_HEIGHT) - screen._backBuffer1.blitFrom(_iconSave, _savedPos, Common::Rect(0, 0, _savedSize.x, _savedSize.y)); -} - -void Map::highlightIcon(const Common::Point &pt) { - int oldPoint = _point; - - // Iterate through the icon list - bool done = false; - for (int idx = 0; idx < (int)_points.size(); ++idx) { - const MapEntry &entry = _points[idx]; - - // Check whether the mouse is over a given icon - if (entry.x != 0 && entry.y != 0) { - if (Common::Rect(entry.x - 8, entry.y - 8, entry.x + 9, entry.y + 9).contains(pt)) { - done = true; - - if (_point != idx && _vm->readFlags(idx)) { - // Changed to a new valid (visible) location - eraseTopLine(); - showPlaceName(idx, true); - _point = idx; - } - } - } - } - - if (!done) { - // No icon was highlighted - if (_point != -1) { - // No longer highlighting previously highlighted icon, so erase it - showPlaceName(_point, false); - eraseTopLine(); - } - - _point = -1; - } else if (oldPoint != -1 && oldPoint != _point) { - showPlaceName(oldPoint, false); - eraseTopLine(); - } +Map::Map(SherlockEngine *vm) : _vm(vm) { + _charPoint = _oldCharPoint = 0; + _active = _frameChangeFlag = false; } void Map::synchronize(Serializer &s) { @@ -570,4 +48,5 @@ void Map::synchronize(Serializer &s) { s.syncAsSint16LE(_oldCharPoint); } + } // End of namespace Sherlock diff --git a/engines/sherlock/map.h b/engines/sherlock/map.h index d47edb299a80..2569e181875c 100644 --- a/engines/sherlock/map.h +++ b/engines/sherlock/map.h @@ -23,12 +23,6 @@ #ifndef SHERLOCK_MAP_H #define SHERLOCK_MAP_H -#include "common/scummsys.h" -#include "common/array.h" -#include "common/rect.h" -#include "common/str.h" -#include "common/str-array.h" -#include "sherlock/surface.h" #include "sherlock/objects.h" #include "sherlock/saveload.h" @@ -36,140 +30,24 @@ namespace Sherlock { class SherlockEngine; -struct MapEntry : Common::Point { - int _translate; - - MapEntry() : Common::Point(), _translate(-1) {} - - MapEntry(int posX, int posY, int translate) : Common::Point(posX, posY), _translate(translate) {} -}; - -class MapPaths { -private: - int _numLocations; - Common::Array< Common::Array > _paths; - -public: - MapPaths(); - - /** - * Load the data for the paths between locations on the map - */ - void load(int numLocations, Common::SeekableReadStream &s); - - /** - * Get the path between two locations on the map - */ - const byte *getPath(int srcLocation, int destLocation); -}; - class Map { protected: SherlockEngine *_vm; - Common::Array _points; // Map locations for each scene - Common::StringArray _locationNames; - MapPaths _paths; - Common::Array _pathPoints; - Common::Point _savedPos; - Common::Point _savedSize; - Surface _topLine; - ImageFile *_mapCursors; - ImageFile *_shapes; - ImageFile *_iconShapes; - WalkSequences _walkSequences; - Point32 _lDrawnPos; - int _point; - bool _placesShown; - int _cursorIndex; - bool _drawMap; - Surface _iconSave; -protected: - Map(SherlockEngine *vm); - - /** - * Load data needed for the map - */ - void loadData(); - - /** - * Load and initialize all the sprites that are needed for the map display - */ - void setupSprites(); - - /** - * Free the sprites and data used by the map - */ - void freeSprites(); - - /** - * Draws an icon for every place that's currently known - */ - void showPlaces(); - - /** - * Makes a copy of the top rows of the screen that are used to display location names - */ - void saveTopLine(); - /** - * Erases anything shown in the top line by restoring the previously saved original map background - */ - void eraseTopLine(); - - /** - * Prints the name of the specified icon - */ - void showPlaceName(int idx, bool highlighted); - - /** - * Update all on-screen sprites to account for any scrolling of the map - */ - void updateMap(bool flushScreen); - - /** - * Handle moving icon for player from their previous location on the map to a destination location - */ - void walkTheStreets(); - - /** - * Save the area under the player's icon - */ - void saveIcon(ImageFrame *src, const Common::Point &pt); - - /** - * Restore the area under the player's icon - */ - void restoreIcon(); - - /** - * Handles highlighting map icons, showing their names - */ - void highlightIcon(const Common::Point &pt); + Map(SherlockEngine *vm); public: - bool _active; Point32 _overPos; Point32 _bigPos; int _charPoint, _oldCharPoint; + bool _active; bool _frameChangeFlag; public: static Map *init(SherlockEngine *vm); - const MapEntry &operator[](int idx) { return _points[idx]; } - - /** - * Loads the list of points for locations on the map for each scene - */ - void loadPoints(int count, const int *xList, const int *yList, const int *transList); - - /** - * Load the sequence data for player icon animations - */ - void loadSequences(int count, const byte *seq); - /** * Show the map */ - int show(); + virtual int show() = 0; /** * Synchronize the data for a savegame diff --git a/engines/sherlock/objects.cpp b/engines/sherlock/objects.cpp index 1e57d0025316..d27cbeda2efe 100644 --- a/engines/sherlock/objects.cpp +++ b/engines/sherlock/objects.cpp @@ -25,6 +25,7 @@ #include "sherlock/objects.h" #include "sherlock/people.h" #include "sherlock/scene.h" +#include "sherlock/scalpel/scalpel_map.h" #include "sherlock/scalpel/scalpel_people.h" namespace Sherlock { @@ -1212,7 +1213,6 @@ void Object::setObjTalkSequence(int seq) { } int Object::checkNameForCodes(const Common::String &name, const char *const messages[]) { - Map &map = *_vm->_map; People &people = *_vm->_people; Scene &scene = *_vm->_scene; Screen &screen = *_vm->_screen; @@ -1257,9 +1257,12 @@ int Object::checkNameForCodes(const Common::String &name, const char *const mess if (ch >= '0' && ch <= '9') { scene._goToScene = atoi(name.c_str() + 1); - if (IS_SERRATED_SCALPEL && scene._goToScene < 97 && map[scene._goToScene].x) { - map._overPos.x = (map[scene._goToScene].x - 6) * FIXED_INT_MULTIPLIER; - map._overPos.y = (map[scene._goToScene].y + 9) * FIXED_INT_MULTIPLIER; + if (IS_SERRATED_SCALPEL && scene._goToScene < 97) { + Scalpel::ScalpelMap &map = *(Scalpel::ScalpelMap *)_vm->_map; + if (map[scene._goToScene].x) { + map._overPos.x = (map[scene._goToScene].x - 6) * FIXED_INT_MULTIPLIER; + map._overPos.y = (map[scene._goToScene].y + 9) * FIXED_INT_MULTIPLIER; + } } const char *p; diff --git a/engines/sherlock/people.cpp b/engines/sherlock/people.cpp index 9416ae91191f..143e53242e0a 100644 --- a/engines/sherlock/people.cpp +++ b/engines/sherlock/people.cpp @@ -425,56 +425,6 @@ assert(_player._position.y >= 10000);/***DEBUG****/ _player._frameNumber = oldFrame; } -void People::gotoStand(Sprite &sprite) { - Map &map = *_vm->_map; - _walkTo.clear(); - sprite._walkCount = 0; - - switch (sprite._sequenceNumber) { - case Scalpel::WALK_UP: - sprite._sequenceNumber = Scalpel::STOP_UP; - break; - case Scalpel::WALK_DOWN: - sprite._sequenceNumber = Scalpel::STOP_DOWN; - break; - case Scalpel::TALK_LEFT: - case Scalpel::WALK_LEFT: - sprite._sequenceNumber = Scalpel::STOP_LEFT; - break; - case Scalpel::TALK_RIGHT: - case Scalpel::WALK_RIGHT: - sprite._sequenceNumber = Scalpel::STOP_RIGHT; - break; - case Scalpel::WALK_UPRIGHT: - sprite._sequenceNumber = Scalpel::STOP_UPRIGHT; - break; - case Scalpel::WALK_UPLEFT: - sprite._sequenceNumber = Scalpel::STOP_UPLEFT; - break; - case Scalpel::WALK_DOWNRIGHT: - sprite._sequenceNumber = Scalpel::STOP_DOWNRIGHT; - break; - case Scalpel::WALK_DOWNLEFT: - sprite._sequenceNumber = Scalpel::STOP_DOWNLEFT; - break; - default: - break; - } - - // Only restart frame at 0 if the sequence number has changed - if (_oldWalkSequence != -1 || sprite._sequenceNumber == Scalpel::STOP_UP) - sprite._frameNumber = 0; - - if (map._active) { - sprite._sequenceNumber = 0; - _player._position.x = (map[map._charPoint].x - 6) * FIXED_INT_MULTIPLIER; - _player._position.y = (map[map._charPoint].y + 10) * FIXED_INT_MULTIPLIER; - } - - _oldWalkSequence = -1; - _allowWalkAbort = true; -} - void People::walkToCoords(const Point32 &destPos, int destDir) { Events &events = *_vm->_events; Scene &scene = *_vm->_scene; diff --git a/engines/sherlock/people.h b/engines/sherlock/people.h index c4abf397b249..c15248cc0283 100644 --- a/engines/sherlock/people.h +++ b/engines/sherlock/people.h @@ -158,12 +158,6 @@ class People { */ void setWalking(); - /** - * Bring a moving character to a standing position. If the Scalpel chessboard - * is being displayed, then the chraracter will always face down. - */ - void gotoStand(Sprite &sprite); - /** * Walk to the co-ordinates passed, and then face the given direction */ @@ -195,6 +189,12 @@ class People { * Change the sequence of the scene background object associated with the current speaker. */ virtual void setTalkSequence(int speaker, int sequenceNum = 1) = 0; + + /** + * Bring a moving character to a standing position. If the Scalpel chessboard + * is being displayed, then the chraracter will always face down. + */ + virtual void gotoStand(Sprite &sprite) = 0; }; } // End of namespace Sherlock diff --git a/engines/sherlock/scalpel/scalpel.cpp b/engines/sherlock/scalpel/scalpel.cpp index f6a6bc9cc241..abca2997f665 100644 --- a/engines/sherlock/scalpel/scalpel.cpp +++ b/engines/sherlock/scalpel/scalpel.cpp @@ -22,6 +22,7 @@ #include "engines/util.h" #include "sherlock/scalpel/scalpel.h" +#include "sherlock/scalpel/scalpel_map.h" #include "sherlock/scalpel/scalpel_people.h" #include "sherlock/scalpel/scalpel_scene.h" #include "sherlock/scalpel/tsage/logo.h" @@ -205,9 +206,10 @@ void ScalpelEngine::initialize() { if (!isDemo()) { // Load the map co-ordinates for each scene and sequence data - _map->loadPoints(NUM_PLACES, &MAP_X[0], &MAP_Y[0], &MAP_TRANSLATE[0]); - _map->loadSequences(3, &MAP_SEQUENCES[0][0]); - _map->_oldCharPoint = BAKER_ST_EXTERIOR; + ScalpelMap &map = *(ScalpelMap *)_map; + map.loadPoints(NUM_PLACES, &MAP_X[0], &MAP_Y[0], &MAP_TRANSLATE[0]); + map.loadSequences(3, &MAP_SEQUENCES[0][0]); + map._oldCharPoint = BAKER_ST_EXTERIOR; } // Load the inventory diff --git a/engines/sherlock/scalpel/scalpel_map.cpp b/engines/sherlock/scalpel/scalpel_map.cpp index 5c45302c5191..613587d2e527 100644 --- a/engines/sherlock/scalpel/scalpel_map.cpp +++ b/engines/sherlock/scalpel/scalpel_map.cpp @@ -20,12 +20,540 @@ * */ +#include "common/system.h" #include "sherlock/scalpel/scalpel_map.h" +#include "sherlock/events.h" +#include "sherlock/people.h" +#include "sherlock/screen.h" +#include "sherlock/sherlock.h" namespace Sherlock { namespace Scalpel { +MapPaths::MapPaths() { + _numLocations = 0; +} + +void MapPaths::load(int numLocations, Common::SeekableReadStream &s) { + _numLocations = numLocations; + _paths.resize(_numLocations * _numLocations); + + for (int idx = 0; idx < (numLocations * numLocations); ++idx) { + Common::Array &path = _paths[idx]; + int v; + + do { + v = s.readByte(); + path.push_back(v); + } while (v && v < 254); + } +} + +const byte *MapPaths::getPath(int srcLocation, int destLocation) { + return &_paths[srcLocation * _numLocations + destLocation][0]; +} + +/*----------------------------------------------------------------*/ + +ScalpelMap::ScalpelMap(SherlockEngine *vm): Map(vm), _topLine(g_system->getWidth(), 12, vm->getPlatform()) { + _mapCursors = nullptr; + _shapes = nullptr; + _iconShapes = nullptr; + _point = 0; + _placesShown = false; + _cursorIndex = -1; + _drawMap = false; + _overPos = Point32(130 * FIXED_INT_MULTIPLIER, 126 * FIXED_INT_MULTIPLIER); + _frameChangeFlag = false; + + // 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(); +} + +void ScalpelMap::loadPoints(int count, const int *xList, const int *yList, const int *transList) { + for (int idx = 0; idx < count; ++idx, ++xList, ++yList, ++transList) { + _points.push_back(MapEntry(*xList, *yList, *transList)); + } +} + +void ScalpelMap::loadSequences(int count, const byte *seq) { + for (int idx = 0; idx < count; ++idx, seq += MAX_FRAME) + Common::copy(seq, seq + MAX_FRAME, &_walkSequences[idx]._sequences[0]); +} + +void ScalpelMap::loadData() { + // TODO: Remove this + if (_vm->getGameID() == GType_RoseTattoo) + return; + + // Load the list of location names + Common::SeekableReadStream *txtStream = _vm->_res->load( + _vm->getGameID() == GType_SerratedScalpel ? "chess.txt" : "map.txt"); + + int streamSize = txtStream->size(); + while (txtStream->pos() < streamSize) { + Common::String line; + char c; + while ((c = txtStream->readByte()) != '\0') + line += c; + + _locationNames.push_back(line); + } + + delete txtStream; + + // Load the path data + Common::SeekableReadStream *pathStream = _vm->_res->load("chess.pth"); + + // Get routes between different locations on the map + _paths.load(31, *pathStream); + + // Load in the co-ordinates that the paths refer to + _pathPoints.resize(208); + for (uint idx = 0; idx < _pathPoints.size(); ++idx) { + _pathPoints[idx].x = pathStream->readSint16LE(); + _pathPoints[idx].y = pathStream->readSint16LE(); + } + + delete pathStream; +} + +int ScalpelMap::show() { + Events &events = *_vm->_events; + People &people = *_vm->_people; + Screen &screen = *_vm->_screen; + bool changed = false, exitFlag = false; + _active = true; + + // Set font and custom cursor for the map + int oldFont = screen.fontNumber(); + screen.setFont(0); + + // Initial screen clear + screen._backBuffer1.clear(); + screen.clear(); + + // Load the entire map + ImageFile bigMap("bigmap.vgs"); + screen.setPalette(bigMap._palette); + + // Load need sprites + setupSprites(); + + screen._backBuffer1.blitFrom(bigMap[0], Common::Point(-_bigPos.x, -_bigPos.y)); + screen._backBuffer1.blitFrom(bigMap[1], Common::Point(-_bigPos.x, SHERLOCK_SCREEN_HEIGHT - _bigPos.y)); + screen._backBuffer1.blitFrom(bigMap[2], Common::Point(SHERLOCK_SCREEN_WIDTH - _bigPos.x, -_bigPos.y)); + screen._backBuffer1.blitFrom(bigMap[3], Common::Point(SHERLOCK_SCREEN_WIDTH - _bigPos.x, SHERLOCK_SCREEN_HEIGHT - _bigPos.y)); + + _drawMap = true; + _charPoint = -1; + _point = -1; + people[AL]._position = _lDrawnPos = _overPos; + + // Show place icons + showPlaces(); + saveTopLine(); + _placesShown = true; + + // Keep looping until either a location is picked, or the game is ended + while (!_vm->shouldQuit() && !exitFlag) { + events.pollEventsAndWait(); + events.setButtonState(); + + // Keyboard handling + if (events.kbHit()) { + Common::KeyState keyState = events.getKey(); + + if (keyState.keycode == Common::KEYCODE_RETURN || keyState.keycode == Common::KEYCODE_SPACE) { + // Both space and enter simulate a mouse release + events._pressed = false; + events._released = true; + events._oldButtons = 0; + } + } + + // Ignore scrolling attempts until the screen is drawn + if (!_drawMap) { + Common::Point pt = events.mousePos(); + + // Check for vertical map scrolling + if ((pt.y > (SHERLOCK_SCREEN_HEIGHT - 10) && _bigPos.y < 200) || (pt.y < 10 && _bigPos.y > 0)) { + if (pt.y > (SHERLOCK_SCREEN_HEIGHT - 10)) + _bigPos.y += 10; + else + _bigPos.y -= 10; + + changed = true; + } + + // Check for horizontal map scrolling + if ((pt.x > (SHERLOCK_SCREEN_WIDTH - 10) && _bigPos.x < 315) || (pt.x < 10 && _bigPos.x > 0)) { + if (pt.x > (SHERLOCK_SCREEN_WIDTH - 10)) + _bigPos.x += 15; + else + _bigPos.x -= 15; + + changed = true; + } + } + + if (changed) { + // Map has scrolled, so redraw new map view + changed = false; + + screen._backBuffer1.blitFrom(bigMap[0], Common::Point(-_bigPos.x, -_bigPos.y)); + screen._backBuffer1.blitFrom(bigMap[1], Common::Point(-_bigPos.x, SHERLOCK_SCREEN_HEIGHT - _bigPos.y)); + screen._backBuffer1.blitFrom(bigMap[2], Common::Point(SHERLOCK_SCREEN_WIDTH - _bigPos.x, -_bigPos.y)); + screen._backBuffer1.blitFrom(bigMap[3], Common::Point(SHERLOCK_SCREEN_WIDTH - _bigPos.x, SHERLOCK_SCREEN_HEIGHT - _bigPos.y)); + + showPlaces(); + _placesShown = false; + + saveTopLine(); + _savedPos.x = -1; + updateMap(true); + } else if (!_drawMap) { + if (!_placesShown) { + showPlaces(); + _placesShown = true; + } + + if (_cursorIndex == 0) { + Common::Point pt = events.mousePos(); + highlightIcon(Common::Point(pt.x - 4 + _bigPos.x, pt.y + _bigPos.y)); + } + updateMap(false); + } + + if ((events._released || events._rightReleased) && _point != -1) { + if (people[AL]._walkCount == 0) { + people._walkDest = _points[_point] + Common::Point(4, 9); + _charPoint = _point; + + // Start walking to selected location + walkTheStreets(); + + // Show wait cursor + _cursorIndex = 1; + events.setCursor((*_mapCursors)[_cursorIndex]._frame); + } + } + + // Check if a scene has beeen selected and we've finished "moving" to it + if (people[AL]._walkCount == 0) { + if (_charPoint >= 1 && _charPoint < (int)_points.size()) + exitFlag = true; + } + + if (_drawMap) { + _drawMap = false; + + if (screen._fadeStyle) + screen.randomTransition(); + else + screen.slamArea(0, 0, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT); + } + + // Wait for a frame + events.wait(1); + } + + freeSprites(); + _overPos = people[AL]._position; + + // Reset font + screen.setFont(oldFont); + + _active = false; + return _charPoint; +} + +void ScalpelMap::setupSprites() { + Events &events = *_vm->_events; + People &people = *_vm->_people; + Scene &scene = *_vm->_scene; + _savedPos.x = -1; + + _mapCursors = new ImageFile("omouse.vgs"); + _cursorIndex = 0; + events.setCursor((*_mapCursors)[_cursorIndex]._frame); + + _shapes = new ImageFile("mapicon.vgs"); + _iconShapes = new ImageFile("overicon.vgs"); + _iconSave.create((*_shapes)[4]._width, (*_shapes)[4]._height, _vm->getPlatform()); + Person &p = people[AL]; + p._description = " "; + p._type = CHARACTER; + p._position = Common::Point(12400, 5000); + p._sequenceNumber = 0; + p._images = _shapes; + p._imageFrame = nullptr; + p._frameNumber = 0; + p._delta = Common::Point(0, 0); + p._oldSize = Common::Point(0, 0); + p._oldSize = Common::Point(0, 0); + p._misc = 0; + p._walkCount = 0; + p._allow = 0; + p._noShapeSize = Common::Point(0, 0); + p._goto = Common::Point(28000, 15000); + p._status = 0; + p._walkSequences = _walkSequences; + p.setImageFrame(); + scene._bgShapes.clear(); +} + +void ScalpelMap::freeSprites() { + delete _mapCursors; + delete _shapes; + delete _iconShapes; + _iconSave.free(); +} + +void ScalpelMap::showPlaces() { + Screen &screen = *_vm->_screen; + + for (uint idx = 0; idx < _points.size(); ++idx) { + const MapEntry &pt = _points[idx]; + + if (pt.x != 0 && pt.y != 0) { + if (pt.x >= _bigPos.x && (pt.x - _bigPos.x) < SHERLOCK_SCREEN_WIDTH + && pt.y >= _bigPos.y && (pt.y - _bigPos.y) < SHERLOCK_SCREEN_HEIGHT) { + if (_vm->readFlags(idx)) { + screen._backBuffer1.transBlitFrom((*_iconShapes)[pt._translate], + Common::Point(pt.x - _bigPos.x - 6, pt.y - _bigPos.y - 12)); + } + } + } + } +} + +void ScalpelMap::saveTopLine() { + _topLine.blitFrom(_vm->_screen->_backBuffer1, Common::Point(0, 0), Common::Rect(0, 0, SHERLOCK_SCREEN_WIDTH, 12)); +} + +void ScalpelMap::eraseTopLine() { + Screen &screen = *_vm->_screen; + screen._backBuffer1.blitFrom(_topLine, Common::Point(0, 0)); + screen.slamArea(0, 0, SHERLOCK_SCREEN_WIDTH, _topLine.h()); +} + +void ScalpelMap::showPlaceName(int idx, bool highlighted) { + People &people = *_vm->_people; + Screen &screen = *_vm->_screen; + + Common::String name = _locationNames[idx]; + int width = screen.stringWidth(name); + + if (!_cursorIndex) { + saveIcon(people[AL]._imageFrame, _lDrawnPos); + + bool flipped = people[AL]._sequenceNumber == MAP_DOWNLEFT || people[AL]._sequenceNumber == MAP_LEFT + || people[AL]._sequenceNumber == MAP_UPLEFT; + screen._backBuffer1.transBlitFrom(*people[AL]._imageFrame, _lDrawnPos, flipped); + } + + if (highlighted) { + int xp = (SHERLOCK_SCREEN_WIDTH - screen.stringWidth(name)) / 2; + screen.gPrint(Common::Point(xp + 2, 2), 0, "%s", name.c_str()); + screen.gPrint(Common::Point(xp + 1, 1), 0, "%s", name.c_str()); + screen.gPrint(Common::Point(xp, 0), 12, "%s", name.c_str()); + + screen.slamArea(xp, 0, width + 2, 15); + } +} + +void ScalpelMap::updateMap(bool flushScreen) { + Events &events = *_vm->_events; + People &people = *_vm->_people; + Screen &screen = *_vm->_screen; + Common::Point osPos = _savedPos; + Common::Point osSize = _savedSize; + Common::Point hPos; + + if (_cursorIndex >= 1) { + if (++_cursorIndex > (1 + 8)) + _cursorIndex = 1; + + events.setCursor((*_mapCursors)[(_cursorIndex + 1) / 2]._frame); + } + + if (!_drawMap && !flushScreen) + restoreIcon(); + else + _savedPos.x = -1; + + people[AL].adjustSprite(); + + _lDrawnPos.x = hPos.x = people[AL]._position.x / FIXED_INT_MULTIPLIER - _bigPos.x; + _lDrawnPos.y = hPos.y = people[AL]._position.y / FIXED_INT_MULTIPLIER - people[AL].frameHeight() - _bigPos.y; + + // Draw the person icon + saveIcon(people[AL]._imageFrame, hPos); + if (people[AL]._sequenceNumber == MAP_DOWNLEFT || people[AL]._sequenceNumber == MAP_LEFT + || people[AL]._sequenceNumber == MAP_UPLEFT) + screen._backBuffer1.transBlitFrom(*people[AL]._imageFrame, hPos, true); + else + screen._backBuffer1.transBlitFrom(*people[AL]._imageFrame, hPos, false); + + if (flushScreen) { + screen.slamArea(0, 0, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT); + } else if (!_drawMap) { + if (hPos.x > 0 && hPos.y >= 0 && hPos.x < SHERLOCK_SCREEN_WIDTH && hPos.y < SHERLOCK_SCREEN_HEIGHT) + screen.flushImage(people[AL]._imageFrame, Common::Point(people[AL]._position.x / FIXED_INT_MULTIPLIER - _bigPos.x, + people[AL]._position.y / FIXED_INT_MULTIPLIER - people[AL].frameHeight() - _bigPos.y), + &people[AL]._oldPosition.x, &people[AL]._oldPosition.y, &people[AL]._oldSize.x, &people[AL]._oldSize.y); + + if (osPos.x != -1) + screen.slamArea(osPos.x, osPos.y, osSize.x, osSize.y); + } +} + +void ScalpelMap::walkTheStreets() { + People &people = *_vm->_people; + Common::Array tempPath; + + // Get indexes into the path lists for the start and destination scenes + int start = _points[_oldCharPoint]._translate; + int dest = _points[_charPoint]._translate; + + // Get pointer to start of path + const byte *path = _paths.getPath(start, dest); + + // Add in destination position + people._walkTo.clear(); + Common::Point destPos = people._walkDest; + + // Check for any intermediate points between the two locations + if (path[0] || _charPoint > 50 || _oldCharPoint > 50) { + people[AL]._sequenceNumber = -1; + + if (_charPoint == 51 || _oldCharPoint == 51) { + people.setWalking(); + } else { + bool reversePath = false; + + // Check for moving the path backwards or forwards + if (path[0] == 255) { + reversePath = true; + SWAP(start, dest); + path = _paths.getPath(start, dest); + } + + do { + int idx = *path++; + tempPath.push_back(_pathPoints[idx - 1] + Common::Point(4, 4)); + } while (*path != 254); + + // Load up the path to use + people._walkTo.clear(); + + if (reversePath) { + for (int idx = (int)tempPath.size() - 1; idx >= 0; --idx) + people._walkTo.push(tempPath[idx]); + } else { + for (int idx = 0; idx < (int)tempPath.size(); ++idx) + people._walkTo.push(tempPath[idx]); + } + + people._walkDest = people._walkTo.pop() + Common::Point(12, 6); + people.setWalking(); + } + } else { + people[AL]._walkCount = 0; + } + + // Store the final destination icon position + people._walkTo.push(destPos); +} + +void ScalpelMap::saveIcon(ImageFrame *src, const Common::Point &pt) { + Screen &screen = *_vm->_screen; + Common::Point size(src->_width, src->_height); + Common::Point pos = pt; + + if (pos.x < 0) { + size.x += pos.x; + pos.x = 0; + } + + if (pos.y < 0) { + size.y += pos.y; + pos.y = 0; + } + + if ((pos.x + size.x) > SHERLOCK_SCREEN_WIDTH) + size.x -= (pos.x + size.x) - SHERLOCK_SCREEN_WIDTH; + + if ((pos.y + size.y) > SHERLOCK_SCREEN_HEIGHT) + size.y -= (pos.y + size.y) - SHERLOCK_SCREEN_HEIGHT; + + if (size.x < 1 || size.y < 1 || pos.x >= SHERLOCK_SCREEN_WIDTH || pos.y >= SHERLOCK_SCREEN_HEIGHT || _drawMap) { + // Flag as the area not needing to be saved + _savedPos.x = -1; + return; + } + + assert(size.x <= _iconSave.w() && size.y <= _iconSave.h()); + _iconSave.blitFrom(screen._backBuffer1, Common::Point(0, 0), + Common::Rect(pos.x, pos.y, pos.x + size.x, pos.y + size.y)); + _savedPos = pos; + _savedSize = size; +} + +void ScalpelMap::restoreIcon() { + Screen &screen = *_vm->_screen; + + if (_savedPos.x >= 0 && _savedPos.y >= 0 && _savedPos.x <= SHERLOCK_SCREEN_WIDTH + && _savedPos.y < SHERLOCK_SCREEN_HEIGHT) + screen._backBuffer1.blitFrom(_iconSave, _savedPos, Common::Rect(0, 0, _savedSize.x, _savedSize.y)); +} + +void ScalpelMap::highlightIcon(const Common::Point &pt) { + int oldPoint = _point; + + // Iterate through the icon list + bool done = false; + for (int idx = 0; idx < (int)_points.size(); ++idx) { + const MapEntry &entry = _points[idx]; + + // Check whether the mouse is over a given icon + if (entry.x != 0 && entry.y != 0) { + if (Common::Rect(entry.x - 8, entry.y - 8, entry.x + 9, entry.y + 9).contains(pt)) { + done = true; + + if (_point != idx && _vm->readFlags(idx)) { + // Changed to a new valid (visible) location + eraseTopLine(); + showPlaceName(idx, true); + _point = idx; + } + } + } + } + + if (!done) { + // No icon was highlighted + if (_point != -1) { + // No longer highlighting previously highlighted icon, so erase it + showPlaceName(_point, false); + eraseTopLine(); + } + + _point = -1; + } else if (oldPoint != -1 && oldPoint != _point) { + showPlaceName(oldPoint, false); + eraseTopLine(); + } +} } // End of namespace Scalpel diff --git a/engines/sherlock/scalpel/scalpel_map.h b/engines/sherlock/scalpel/scalpel_map.h index 4fb41421bb0d..e61375f116d5 100644 --- a/engines/sherlock/scalpel/scalpel_map.h +++ b/engines/sherlock/scalpel/scalpel_map.h @@ -24,7 +24,12 @@ #define SHERLOCK_SCALPEL_MAP_H #include "common/scummsys.h" +#include "common/array.h" +#include "common/rect.h" +#include "common/str-array.h" +#include "sherlock/surface.h" #include "sherlock/map.h" +#include "sherlock/resources.h" namespace Sherlock { @@ -32,9 +37,132 @@ class SherlockEngine; namespace Scalpel { + +struct MapEntry : Common::Point { + int _translate; + + MapEntry() : Common::Point(), _translate(-1) {} + + MapEntry(int posX, int posY, int translate) : Common::Point(posX, posY), _translate(translate) {} +}; + +class MapPaths { +private: + int _numLocations; + Common::Array< Common::Array > _paths; + +public: + MapPaths(); + + /** + * Load the data for the paths between locations on the map + */ + void load(int numLocations, Common::SeekableReadStream &s); + + /** + * Get the path between two locations on the map + */ + const byte *getPath(int srcLocation, int destLocation); +}; + class ScalpelMap: public Map { +private: + Common::Array _points; // Map locations for each scene + Common::StringArray _locationNames; + MapPaths _paths; + Common::Array _pathPoints; + Common::Point _savedPos; + Common::Point _savedSize; + Surface _topLine; + ImageFile *_mapCursors; + ImageFile *_shapes; + ImageFile *_iconShapes; + WalkSequences _walkSequences; + Point32 _lDrawnPos; + int _point; + bool _placesShown; + int _cursorIndex; + bool _drawMap; + Surface _iconSave; +protected: + /** + * Load data needed for the map + */ + void loadData(); + + /** + * Load and initialize all the sprites that are needed for the map display + */ + void setupSprites(); + + /** + * Free the sprites and data used by the map + */ + void freeSprites(); + + /** + * Draws an icon for every place that's currently known + */ + void showPlaces(); + + /** + * Makes a copy of the top rows of the screen that are used to display location names + */ + void saveTopLine(); + + /** + * Erases anything shown in the top line by restoring the previously saved original map background + */ + void eraseTopLine(); + + /** + * Prints the name of the specified icon + */ + void showPlaceName(int idx, bool highlighted); + + /** + * Update all on-screen sprites to account for any scrolling of the map + */ + void updateMap(bool flushScreen); + + /** + * Handle moving icon for player from their previous location on the map to a destination location + */ + void walkTheStreets(); + + /** + * Save the area under the player's icon + */ + void saveIcon(ImageFrame *src, const Common::Point &pt); + + /** + * Restore the area under the player's icon + */ + void restoreIcon(); + + /** + * Handles highlighting map icons, showing their names + */ + void highlightIcon(const Common::Point &pt); public: - ScalpelMap(SherlockEngine *vm) : Map(vm) {} + ScalpelMap(SherlockEngine *vm); + + const MapEntry &operator[](int idx) { return _points[idx]; } + + /** + * Loads the list of points for locations on the map for each scene + */ + void loadPoints(int count, const int *xList, const int *yList, const int *transList); + + /** + * Load the sequence data for player icon animations + */ + void loadSequences(int count, const byte *seq); + + /** + * Show the map + */ + virtual int show(); }; } // End of namespace Scalpel diff --git a/engines/sherlock/scalpel/scalpel_people.cpp b/engines/sherlock/scalpel/scalpel_people.cpp index 2b76eea55e76..80e6061e8b06 100644 --- a/engines/sherlock/scalpel/scalpel_people.cpp +++ b/engines/sherlock/scalpel/scalpel_people.cpp @@ -21,6 +21,7 @@ */ #include "sherlock/scalpel/scalpel_people.h" +#include "sherlock/scalpel/scalpel_map.h" #include "sherlock/sherlock.h" namespace Sherlock { @@ -86,7 +87,6 @@ void ScalpelPeople::setTalking(int speaker) { } } - void ScalpelPeople::synchronize(Serializer &s) { s.syncAsByte(_holmesOn); s.syncAsSint32LE(_player._position.x); @@ -130,6 +130,57 @@ void ScalpelPeople::setTalkSequence(int speaker, int sequenceNum) { } } +void ScalpelPeople::gotoStand(Sprite &sprite) { + ScalpelMap &map = *(ScalpelMap *)_vm->_map; + _walkTo.clear(); + sprite._walkCount = 0; + + switch (sprite._sequenceNumber) { + case Scalpel::WALK_UP: + sprite._sequenceNumber = STOP_UP; + break; + case WALK_DOWN: + sprite._sequenceNumber = STOP_DOWN; + break; + case TALK_LEFT: + case WALK_LEFT: + sprite._sequenceNumber = STOP_LEFT; + break; + case TALK_RIGHT: + case WALK_RIGHT: + sprite._sequenceNumber = STOP_RIGHT; + break; + case WALK_UPRIGHT: + sprite._sequenceNumber = STOP_UPRIGHT; + break; + case WALK_UPLEFT: + sprite._sequenceNumber = STOP_UPLEFT; + break; + case WALK_DOWNRIGHT: + sprite._sequenceNumber = STOP_DOWNRIGHT; + break; + case WALK_DOWNLEFT: + sprite._sequenceNumber = STOP_DOWNLEFT; + break; + default: + break; + } + + // Only restart frame at 0 if the sequence number has changed + if (_oldWalkSequence != -1 || sprite._sequenceNumber == Scalpel::STOP_UP) + sprite._frameNumber = 0; + + if (map._active) { + sprite._sequenceNumber = 0; + _player._position.x = (map[map._charPoint].x - 6) * FIXED_INT_MULTIPLIER; + _player._position.y = (map[map._charPoint].y + 10) * FIXED_INT_MULTIPLIER; + } + + _oldWalkSequence = -1; + _allowWalkAbort = true; +} + + } // End of namespace Scalpel } // End of namespace Sherlock diff --git a/engines/sherlock/scalpel/scalpel_people.h b/engines/sherlock/scalpel/scalpel_people.h index 698115710379..1f14ceee0eca 100644 --- a/engines/sherlock/scalpel/scalpel_people.h +++ b/engines/sherlock/scalpel/scalpel_people.h @@ -60,6 +60,12 @@ class ScalpelPeople : public People { * Change the sequence of the scene background object associated with the specified speaker. */ virtual void setTalkSequence(int speaker, int sequenceNum = 1); + + /** + * Bring a moving character to a standing position. If the Scalpel chessboard + * is being displayed, then the chraracter will always face down. + */ + virtual void gotoStand(Sprite &sprite); }; } // End of namespace Scalpel diff --git a/engines/sherlock/scalpel/scalpel_scene.cpp b/engines/sherlock/scalpel/scalpel_scene.cpp index e0ad3a7b6d37..95a58be99d11 100644 --- a/engines/sherlock/scalpel/scalpel_scene.cpp +++ b/engines/sherlock/scalpel/scalpel_scene.cpp @@ -21,16 +21,34 @@ */ #include "sherlock/scalpel/scalpel_scene.h" +#include "sherlock/scalpel/scalpel_map.h" #include "sherlock/scalpel/scalpel_people.h" #include "sherlock/scalpel/scalpel.h" #include "sherlock/events.h" #include "sherlock/people.h" #include "sherlock/screen.h" +#include "sherlock/sherlock.h" namespace Sherlock { namespace Scalpel { +bool ScalpelScene::loadScene(const Common::String &filename) { + ScalpelMap &map = *(ScalpelMap *)_vm->_map; + bool result = Scene::loadScene(filename); + + if (!_vm->isDemo()) { + // Reset the previous map location and position on overhead map + map._oldCharPoint = _currentScene; + + map._overPos.x = (map[_currentScene].x - 6) * FIXED_INT_MULTIPLIER; + map._overPos.y = (map[_currentScene].y + 9) * FIXED_INT_MULTIPLIER; + + } + + return result; +} + void ScalpelScene::drawAllShapes() { People &people = *_vm->_people; Screen &screen = *_vm->_screen; @@ -467,6 +485,218 @@ void ScalpelScene::doBgAnim() { } } +int ScalpelScene::startCAnim(int cAnimNum, int playRate) { + Events &events = *_vm->_events; + ScalpelMap &map = *(ScalpelMap *)_vm->_map; + People &people = *_vm->_people; + Resources &res = *_vm->_res; + Talk &talk = *_vm->_talk; + UserInterface &ui = *_vm->_ui; + Point32 tpPos, walkPos; + int tpDir, walkDir; + int tFrames = 0; + int gotoCode = -1; + + // Validation + if (cAnimNum >= (int)_cAnim.size()) + // number out of bounds + return -1; + if (_canimShapes.size() >= 3 || playRate == 0) + // Too many active animations, or invalid play rate + return 0; + + CAnim &cAnim = _cAnim[cAnimNum]; + if (playRate < 0) { + // Reverse direction + walkPos = cAnim._teleportPos; + walkDir = cAnim._teleportDir; + tpPos = cAnim._goto; + tpDir = cAnim._gotoDir; + } else { + // Forward direction + walkPos = cAnim._goto; + walkDir = cAnim._gotoDir; + tpPos = cAnim._teleportPos; + tpDir = cAnim._teleportDir; + } + + CursorId oldCursor = events.getCursor(); + events.setCursor(WAIT); + + if (walkPos.x != -1) { + // Holmes must walk to the walk point before the cAnimation is started + if (people[AL]._position != walkPos) + people.walkToCoords(walkPos, walkDir); + } + + if (talk._talkToAbort) + return 1; + + // Add new anim shape entry for displaying the animation + _canimShapes.push_back(Object()); + Object &cObj = _canimShapes[_canimShapes.size() - 1]; + + // Copy the canimation into the bgShapes type canimation structure so it can be played + cObj._allow = cAnimNum + 1; // Keep track of the parent structure + cObj._name = _cAnim[cAnimNum]._name; // Copy name + + // Remove any attempt to draw object frame + if (cAnim._type == NO_SHAPE && cAnim._sequences[0] < 100) + cAnim._sequences[0] = 0; + + cObj._sequences = cAnim._sequences; + cObj._images = nullptr; + cObj._position = cAnim._position; + cObj._delta = Common::Point(0, 0); + cObj._type = cAnim._type; + cObj._flags = cAnim._flags; + + cObj._maxFrames = 0; + cObj._frameNumber = -1; + cObj._sequenceNumber = cAnimNum; + cObj._oldPosition = Common::Point(0, 0); + cObj._oldSize = Common::Point(0, 0); + cObj._goto = Common::Point(0, 0); + cObj._status = 0; + cObj._misc = 0; + cObj._imageFrame = nullptr; + + if (cAnim._name.size() > 0 && cAnim._type != NO_SHAPE) { + if (tpPos.x != -1) + people[AL]._type = REMOVE; + + Common::String fname = cAnim._name + ".vgs"; + if (!res.isInCache(fname)) { + // Set up RRM scene data + Common::SeekableReadStream *rrmStream = res.load(_rrmName); + rrmStream->seek(44 + cAnimNum * 4); + rrmStream->seek(rrmStream->readUint32LE()); + + // Load the canimation into the cache + Common::SeekableReadStream *imgStream = !_lzwMode ? rrmStream->readStream(cAnim._size) : + Resources::decompressLZ(*rrmStream, cAnim._size); + res.addToCache(fname, *imgStream); + + delete imgStream; + delete rrmStream; + } + + // Now load the resource as an image + cObj._images = new ImageFile(fname); + cObj._imageFrame = &(*cObj._images)[0]; + cObj._maxFrames = cObj._images->size(); + + int frames = 0; + if (playRate < 0) { + // Reverse direction + // Count number of frames + while (cObj._sequences[frames] && frames < MAX_FRAME) + ++frames; + } else { + // Forward direction + Object::_countCAnimFrames = true; + + while (cObj._type == ACTIVE_BG_SHAPE) { + cObj.checkObject(); + ++frames; + + if (frames >= 1000) + error("CAnim has infinite loop sequence"); + } + + if (frames > 1) + --frames; + + Object::_countCAnimFrames = false; + + cObj._type = cAnim._type; + cObj._frameNumber = -1; + cObj._position = cAnim._position; + cObj._delta = Common::Point(0, 0); + } + + // Return if animation has no frames in it + if (frames == 0) + return -2; + + ++frames; + int repeat = ABS(playRate); + int dir; + + if (playRate < 0) { + // Play in reverse + dir = -2; + cObj._frameNumber = frames - 3; + } else { + dir = 0; + } + + tFrames = frames - 1; + int pauseFrame = (_cAnimFramePause) ? frames - _cAnimFramePause : -1; + + while (--frames) { + if (frames == pauseFrame) + ui.printObjectDesc(); + + doBgAnim(); + + // Repeat same frame + int temp = repeat; + while (--temp > 0) { + cObj._frameNumber--; + doBgAnim(); + + if (_vm->shouldQuit()) + return 0; + } + + cObj._frameNumber += dir; + } + + people[AL]._type = CHARACTER; + } + + // Teleport to ending coordinates if necessary + if (tpPos.x != -1) { + people[AL]._position = tpPos; // Place the player + people[AL]._sequenceNumber = tpDir; + people.gotoStand(people[AL]); + } + + if (playRate < 0) + // Reverse direction - set to end sequence + cObj._frameNumber = tFrames - 1; + + if (cObj._frameNumber <= 26) + gotoCode = cObj._sequences[cObj._frameNumber + 3]; + + // Unless anim shape has already been freed, set it to REMOVE so doBgAnim can free it + if (_canimShapes.indexOf(cObj) != -1) + cObj.checkObject(); + + if (gotoCode > 0 && !talk._talkToAbort) { + _goToScene = gotoCode; + + if (_goToScene < 97 && map[_goToScene].x) { + map._overPos = map[_goToScene]; + } + } + + people.loadWalk(); + + if (tpPos.x != -1 && !talk._talkToAbort) { + // Teleport to ending coordinates + people[AL]._position = tpPos; + people[AL]._sequenceNumber = tpDir; + + people.gotoStand(people[AL]); + } + + events.setCursor(oldCursor); + + return 1; +} + } // End of namespace Scalpel } // End of namespace Sherlock diff --git a/engines/sherlock/scalpel/scalpel_scene.h b/engines/sherlock/scalpel/scalpel_scene.h index 88c7581f5960..f79892e4e6d5 100644 --- a/engines/sherlock/scalpel/scalpel_scene.h +++ b/engines/sherlock/scalpel/scalpel_scene.h @@ -43,6 +43,17 @@ class ScalpelScene : public Scene { private: void doBgAnimCheckCursor(); protected: + /** + * Loads the data associated for a given scene. The room resource file's format is: + * BGHEADER: Holds an index for the rest of the file + * STRUCTS: The objects for the scene + * IMAGES: The graphic information for the structures + * + * The _misc field of the structures contains the number of the graphic image + * that it should point to after loading; _misc is then set to 0. + */ + virtual bool loadScene(const Common::String &filename); + /** * Checks all the background shapes. If a background shape is animating, * it will flag it as needing to be drawn. If a non-animating shape is @@ -61,6 +72,16 @@ class ScalpelScene : public Scene { * Draw all objects and characters. */ virtual void doBgAnim(); + + /** + * Attempt to start a canimation sequence. It will load the requisite graphics, and + * then copy the canim object into the _canimShapes array to start the animation. + * + * @param cAnimNum The canim object within the current scene + * @param playRate Play rate. 0 is invalid; 1=normal speed, 2=1/2 speed, etc. + * A negative playRate can also be specified to play the animation in reverse + */ + virtual int startCAnim(int cAnimNum, int playRate); }; } // End of namespace Scalpel diff --git a/engines/sherlock/scalpel/scalpel_talk.cpp b/engines/sherlock/scalpel/scalpel_talk.cpp index 217ed9b2a43b..3dc99c236b0d 100644 --- a/engines/sherlock/scalpel/scalpel_talk.cpp +++ b/engines/sherlock/scalpel/scalpel_talk.cpp @@ -21,7 +21,9 @@ */ #include "sherlock/scalpel/scalpel_talk.h" +#include "sherlock/scalpel/scalpel_map.h" #include "sherlock/scalpel/scalpel_people.h" +#include "sherlock/scalpel/scalpel_scene.h" #include "sherlock/scalpel/scalpel_user_interface.h" #include "sherlock/sherlock.h" #include "sherlock/screen.h" @@ -289,12 +291,12 @@ OpcodeReturn ScalpelTalk::cmdSwitchSpeaker(const byte *&str) { } OpcodeReturn ScalpelTalk::cmdGotoScene(const byte *&str) { - Map &map = *_vm->_map; + ScalpelMap &map = *(ScalpelMap *)_vm->_map; People &people = *_vm->_people; Scene &scene = *_vm->_scene; scene._goToScene = str[1] - 1; - if (scene._goToScene != 100) { + if (scene._goToScene != OVERHEAD_MAP) { // Not going to the map overview map._oldCharPoint = scene._goToScene; map._overPos.x = (map[scene._goToScene].x - 6) * FIXED_INT_MULTIPLIER; diff --git a/engines/sherlock/scene.cpp b/engines/sherlock/scene.cpp index c43887438ea8..9100d58e13c9 100644 --- a/engines/sherlock/scene.cpp +++ b/engines/sherlock/scene.cpp @@ -261,7 +261,6 @@ void Scene::freeScene() { bool Scene::loadScene(const Common::String &filename) { Events &events = *_vm->_events; - Map &map = *_vm->_map; Music &music = *_vm->_music; People &people = *_vm->_people; Resources &res = *_vm->_res; @@ -629,17 +628,6 @@ bool Scene::loadScene(const Common::String &filename) { _walkedInScene = false; saves._justLoaded = false; - if (!_vm->isDemo()) { - // Reset the previous map location and position on overhead map - map._oldCharPoint = _currentScene; - - if (IS_SERRATED_SCALPEL) { - map._overPos.x = (map[_currentScene].x - 6) * FIXED_INT_MULTIPLIER; - map._overPos.y = (map[_currentScene].y + 9) * FIXED_INT_MULTIPLIER; - - } - } - events.clearEvents(); return flag; } @@ -914,218 +902,6 @@ Exit *Scene::checkForExit(const Common::Rect &r) { return nullptr; } -int Scene::startCAnim(int cAnimNum, int playRate) { - Events &events = *_vm->_events; - Map &map = *_vm->_map; - People &people = *_vm->_people; - Resources &res = *_vm->_res; - Talk &talk = *_vm->_talk; - UserInterface &ui = *_vm->_ui; - Point32 tpPos, walkPos; - int tpDir, walkDir; - int tFrames = 0; - int gotoCode = -1; - - // Validation - if (cAnimNum >= (int)_cAnim.size()) - // number out of bounds - return -1; - if (_canimShapes.size() >= 3 || playRate == 0) - // Too many active animations, or invalid play rate - return 0; - - CAnim &cAnim = _cAnim[cAnimNum]; - if (playRate < 0) { - // Reverse direction - walkPos = cAnim._teleportPos; - walkDir = cAnim._teleportDir; - tpPos = cAnim._goto; - tpDir = cAnim._gotoDir; - } else { - // Forward direction - walkPos = cAnim._goto; - walkDir = cAnim._gotoDir; - tpPos = cAnim._teleportPos; - tpDir = cAnim._teleportDir; - } - - CursorId oldCursor = events.getCursor(); - events.setCursor(WAIT); - - if (walkPos.x != -1) { - // Holmes must walk to the walk point before the cAnimation is started - if (people[AL]._position != walkPos) - people.walkToCoords(walkPos, walkDir); - } - - if (talk._talkToAbort) - return 1; - - // Add new anim shape entry for displaying the animation - _canimShapes.push_back(Object()); - Object &cObj = _canimShapes[_canimShapes.size() - 1]; - - // Copy the canimation into the bgShapes type canimation structure so it can be played - cObj._allow = cAnimNum + 1; // Keep track of the parent structure - cObj._name = _cAnim[cAnimNum]._name; // Copy name - - // Remove any attempt to draw object frame - if (cAnim._type == NO_SHAPE && cAnim._sequences[0] < 100) - cAnim._sequences[0] = 0; - - cObj._sequences = cAnim._sequences; - cObj._images = nullptr; - cObj._position = cAnim._position; - cObj._delta = Common::Point(0, 0); - cObj._type = cAnim._type; - cObj._flags = cAnim._flags; - - cObj._maxFrames = 0; - cObj._frameNumber = -1; - cObj._sequenceNumber = cAnimNum; - cObj._oldPosition = Common::Point(0, 0); - cObj._oldSize = Common::Point(0, 0); - cObj._goto = Common::Point(0, 0); - cObj._status = 0; - cObj._misc = 0; - cObj._imageFrame = nullptr; - - if (cAnim._name.size() > 0 && cAnim._type != NO_SHAPE) { - if (tpPos.x != -1) - people[AL]._type = REMOVE; - - Common::String fname = cAnim._name + ".vgs"; - if (!res.isInCache(fname)) { - // Set up RRM scene data - Common::SeekableReadStream *rrmStream = res.load(_rrmName); - rrmStream->seek(44 + cAnimNum * 4); - rrmStream->seek(rrmStream->readUint32LE()); - - // Load the canimation into the cache - Common::SeekableReadStream *imgStream = !_lzwMode ? rrmStream->readStream(cAnim._size) : - Resources::decompressLZ(*rrmStream, cAnim._size); - res.addToCache(fname, *imgStream); - - delete imgStream; - delete rrmStream; - } - - // Now load the resource as an image - cObj._images = new ImageFile(fname); - cObj._imageFrame = &(*cObj._images)[0]; - cObj._maxFrames = cObj._images->size(); - - int frames = 0; - if (playRate < 0) { - // Reverse direction - // Count number of frames - while (cObj._sequences[frames] && frames < MAX_FRAME) - ++frames; - } else { - // Forward direction - Object::_countCAnimFrames = true; - - while (cObj._type == ACTIVE_BG_SHAPE) { - cObj.checkObject(); - ++frames; - - if (frames >= 1000) - error("CAnim has infinite loop sequence"); - } - - if (frames > 1) - --frames; - - Object::_countCAnimFrames = false; - - cObj._type = cAnim._type; - cObj._frameNumber = -1; - cObj._position = cAnim._position; - cObj._delta = Common::Point(0, 0); - } - - // Return if animation has no frames in it - if (frames == 0) - return -2; - - ++frames; - int repeat = ABS(playRate); - int dir; - - if (playRate < 0) { - // Play in reverse - dir = -2; - cObj._frameNumber = frames - 3; - } else { - dir = 0; - } - - tFrames = frames - 1; - int pauseFrame = (_cAnimFramePause) ? frames - _cAnimFramePause : -1; - - while (--frames) { - if (frames == pauseFrame) - ui.printObjectDesc(); - - doBgAnim(); - - // Repeat same frame - int temp = repeat; - while (--temp > 0) { - cObj._frameNumber--; - doBgAnim(); - - if (_vm->shouldQuit()) - return 0; - } - - cObj._frameNumber += dir; - } - - people[AL]._type = CHARACTER; - } - - // Teleport to ending coordinates if necessary - if (tpPos.x != -1) { - people[AL]._position = tpPos; // Place the player - people[AL]._sequenceNumber = tpDir; - people.gotoStand(people[AL]); - } - - if (playRate < 0) - // Reverse direction - set to end sequence - cObj._frameNumber = tFrames - 1; - - if (cObj._frameNumber <= 26) - gotoCode = cObj._sequences[cObj._frameNumber + 3]; - - // Unless anim shape has already been freed, set it to REMOVE so doBgAnim can free it - if (_canimShapes.indexOf(cObj) != -1) - cObj.checkObject(); - - if (gotoCode > 0 && !talk._talkToAbort) { - _goToScene = gotoCode; - - if (_goToScene < 97 && map[_goToScene].x) { - map._overPos = map[_goToScene]; - } - } - - people.loadWalk(); - - if (tpPos.x != -1 && !talk._talkToAbort) { - // Teleport to ending coordinates - people[AL]._position = tpPos; - people[AL]._sequenceNumber = tpDir; - - people.gotoStand(people[AL]); - } - - events.setCursor(oldCursor); - - return 1; -} - int Scene::findBgShape(const Common::Rect &r) { if (!_doBgAnimDone) // New frame hasn't been drawn yet diff --git a/engines/sherlock/scene.h b/engines/sherlock/scene.h index 11fd1da14933..ab636f7b731b 100644 --- a/engines/sherlock/scene.h +++ b/engines/sherlock/scene.h @@ -139,7 +139,6 @@ struct SceneTripEntry { class Scene { private: - Common::String _rrmName; bool _loadingSavedGame; /** @@ -173,6 +172,7 @@ class Scene { void saveSceneStatus(); protected: SherlockEngine *_vm; + Common::String _rrmName; /** * Loads the data associated for a given scene. The room resource file's format is: @@ -259,16 +259,6 @@ class Scene { */ Exit *checkForExit(const Common::Rect &r); - /** - * Attempt to start a canimation sequence. It will load the requisite graphics, and - * then copy the canim object into the _canimShapes array to start the animation. - * - * @param cAnimNum The canim object within the current scene - * @param playRate Play rate. 0 is invalid; 1=normal speed, 2=1/2 speed, etc. - * A negative playRate can also be specified to play the animation in reverse - */ - int startCAnim(int cAnimNum, int playRate); - /** * Scans through the object list to find one with a matching name, and will * call toggleHidden with all matches found. Returns the numer of matches found @@ -319,6 +309,16 @@ class Scene { * to be drawn */ virtual void updateBackground(); + + /** + * Attempt to start a canimation sequence. It will load the requisite graphics, and + * then copy the canim object into the _canimShapes array to start the animation. + * + * @param cAnimNum The canim object within the current scene + * @param playRate Play rate. 0 is invalid; 1=normal speed, 2=1/2 speed, etc. + * A negative playRate can also be specified to play the animation in reverse + */ + virtual int startCAnim(int cAnimNum, int playRate) = 0; }; } // End of namespace Sherlock diff --git a/engines/sherlock/tattoo/tattoo_map.cpp b/engines/sherlock/tattoo/tattoo_map.cpp index 9dd35a9de695..ced7ed9a5831 100644 --- a/engines/sherlock/tattoo/tattoo_map.cpp +++ b/engines/sherlock/tattoo/tattoo_map.cpp @@ -26,6 +26,10 @@ namespace Sherlock { namespace Tattoo { +int TattooMap::show() { + // TODO + return 61; +} } // End of namespace Tattoo diff --git a/engines/sherlock/tattoo/tattoo_map.h b/engines/sherlock/tattoo/tattoo_map.h index 97a330adab48..15dd90e78a48 100644 --- a/engines/sherlock/tattoo/tattoo_map.h +++ b/engines/sherlock/tattoo/tattoo_map.h @@ -35,6 +35,11 @@ namespace Tattoo { class TattooMap : public Map { public: TattooMap(SherlockEngine *vm) : Map(vm) {} + + /** + * Show the map + */ + virtual int show(); }; } // End of namespace Tattoo diff --git a/engines/sherlock/tattoo/tattoo_people.cpp b/engines/sherlock/tattoo/tattoo_people.cpp index 6952c876c00b..61f79c471c86 100644 --- a/engines/sherlock/tattoo/tattoo_people.cpp +++ b/engines/sherlock/tattoo/tattoo_people.cpp @@ -222,6 +222,10 @@ void TattooPeople::synchronize(Serializer &s) { } } +void TattooPeople::gotoStand(Sprite &sprite) { + error("TODO: gotoStand"); +} + } // End of namespace Tattoo } // End of namespace Sherlock diff --git a/engines/sherlock/tattoo/tattoo_people.h b/engines/sherlock/tattoo/tattoo_people.h index c4f0bfd3ed7e..e4216d080ec0 100644 --- a/engines/sherlock/tattoo/tattoo_people.h +++ b/engines/sherlock/tattoo/tattoo_people.h @@ -96,6 +96,12 @@ class TattooPeople : public People { * Change the sequence of the scene background object associated with the specified speaker. */ virtual void setTalkSequence(int speaker, int sequenceNum = 1); + + /** + * Bring a moving character to a standing position. If the Scalpel chessboard + * is being displayed, then the chraracter will always face down. + */ + virtual void gotoStand(Sprite &sprite); }; } // End of namespace Scalpel diff --git a/engines/sherlock/tattoo/tattoo_scene.cpp b/engines/sherlock/tattoo/tattoo_scene.cpp index 51e0eb11103f..6ef4d2fd7743 100644 --- a/engines/sherlock/tattoo/tattoo_scene.cpp +++ b/engines/sherlock/tattoo/tattoo_scene.cpp @@ -770,6 +770,10 @@ void TattooScene::setupBGArea(const byte cMap[PALETTE_SIZE]) { } } +int TattooScene::startCAnim(int cAnimNum, int playRate) { + error("TODO: startCAnim"); +} + } // End of namespace Tattoo } // End of namespace Sherlock diff --git a/engines/sherlock/tattoo/tattoo_scene.h b/engines/sherlock/tattoo/tattoo_scene.h index 78ab1e652177..3c4a3cd0e374 100644 --- a/engines/sherlock/tattoo/tattoo_scene.h +++ b/engines/sherlock/tattoo/tattoo_scene.h @@ -109,6 +109,15 @@ class TattooScene : public Scene { */ virtual void updateBackground(); + /** + * Attempt to start a canimation sequence. It will load the requisite graphics, and + * then copy the canim object into the _canimShapes array to start the animation. + * + * @param cAnimNum The canim object within the current scene + * @param playRate Play rate. 0 is invalid; 1=normal speed, 2=1/2 speed, etc. + * A negative playRate can also be specified to play the animation in reverse + */ + virtual int startCAnim(int cAnimNum, int playRate); }; } // End of namespace Tattoo