diff options
author | Paul Gilbert | 2015-04-20 01:07:54 -0500 |
---|---|---|
committer | Paul Gilbert | 2015-04-20 01:07:54 -0500 |
commit | bfb86a99db6358043a4c16371c5a927411b4e8cb (patch) | |
tree | b17ecdee21503b65641cc9be87c25f685d229390 | |
parent | 19142ef58a3e632b31a87a99b817e261f47c1bc4 (diff) | |
download | scummvm-rg350-bfb86a99db6358043a4c16371c5a927411b4e8cb.tar.gz scummvm-rg350-bfb86a99db6358043a4c16371c5a927411b4e8cb.tar.bz2 scummvm-rg350-bfb86a99db6358043a4c16371c5a927411b4e8cb.zip |
SHERLOCK: Map path walking, beginnings of darts game
-rw-r--r-- | engines/sherlock/map.cpp | 74 | ||||
-rw-r--r-- | engines/sherlock/map.h | 19 | ||||
-rw-r--r-- | engines/sherlock/scalpel/darts.cpp | 385 | ||||
-rw-r--r-- | engines/sherlock/scalpel/darts.h | 33 | ||||
-rw-r--r-- | engines/sherlock/scalpel/scalpel.cpp | 8 |
5 files changed, 504 insertions, 15 deletions
diff --git a/engines/sherlock/map.cpp b/engines/sherlock/map.cpp index fa3bf99cab..6fd169f43a 100644 --- a/engines/sherlock/map.cpp +++ b/engines/sherlock/map.cpp @@ -31,7 +31,7 @@ Map::Map(SherlockEngine *vm): _vm(vm), _topLine(SHERLOCK_SCREEN_WIDTH, 12) { _iconShapes = nullptr; _point = 0; _placesShown = false; - _charPoint = -1; + _charPoint = _oldCharPoint = -1; _cursorIndex = -1; _drawMap = false; for (int idx = 0; idx < 3; ++idx) @@ -43,9 +43,9 @@ Map::Map(SherlockEngine *vm): _vm(vm), _topLine(SHERLOCK_SCREEN_WIDTH, 12) { /** * Loads the list of points for locations on the map for each scene */ -void Map::loadPoints(int count, const int *xList, const int *yList) { - for (int idx = 0; idx < count; ++idx, ++xList, ++yList) { - _points.push_back(Common::Point(*xList, *yList)); +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)); } } @@ -79,9 +79,11 @@ void Map::loadData() { } // Load in the path point information - _pathPoints.resize(416); - for (uint idx = 0; idx < _pathPoints.size(); ++idx) - _pathPoints[idx] = pathStream->readSint16LE(); + _pathPoints.resize(208); + for (uint idx = 0; idx < _pathPoints.size(); ++idx) { + _pathPoints[idx].x = pathStream->readSint16LE(); + _pathPoints[idx].y = pathStream->readSint16LE(); + } delete pathStream; } @@ -303,6 +305,14 @@ void Map::saveTopLine() { } /** + * Erases anything shown in the top line by restoring the previously saved original map background + */ +void Map::eraseTopLine() { + Screen &screen = *_vm->_screen; + screen.blitFrom(_topLine, Common::Point(0, 0)); +} + +/** * Update all on-screen sprites to account for any scrolling of the map */ void Map::updateMap(bool flushScreen) { @@ -355,7 +365,55 @@ void Map::updateMap(bool flushScreen) { * Handle moving icon for player from their previous location on the map to a destination location */ void Map::walkTheStreets() { - // TODO + People &people = *_vm->_people; + bool reversePath = false; + Common::Array<Common::Point> 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 int *ptr = &_paths[start][dest]; + + // Check for any intermediate points between the two locations + if (*ptr || _charPoint > 50 || _oldCharPoint > 50) { + people[AL]._sequenceNumber = -1; + + if (_charPoint == 51 || _oldCharPoint == 51) { + people.setWalking(); + } else { + // Check for moving the path backwards or forwards + if (*ptr == 255) { + reversePath = true; + SWAP(start, dest); + ptr = &_paths[start][dest]; + } + + do { + int idx = *ptr++; + tempPath.push_back(_pathPoints[idx - 1] + Common::Point(4, 4)); + } while (*ptr != 254); + + // Load up the path to use + people._walkTo.clear(); + + if (!reversePath) { + people._walkTo = tempPath; + people._walkDest = tempPath[0]; + } else { + for (int idx = 0; idx < ((int)tempPath.size() - 1); ++idx) + people._walkTo.push(tempPath[idx]); + people._walkDest = tempPath[tempPath.size() - 1]; + } + + people._walkDest.x += 12; + people._walkDest.y += 6; + people.setWalking(); + } + } else { + people[AL]._walkCount = 0; + } } /** diff --git a/engines/sherlock/map.h b/engines/sherlock/map.h index 653d8c0084..f324160bce 100644 --- a/engines/sherlock/map.h +++ b/engines/sherlock/map.h @@ -35,13 +35,21 @@ namespace Sherlock { class SherlockEngine; +struct MapEntry : Common::Point { + int _translate; + + MapEntry() : Common::Point(), _translate(-1) {} + + MapEntry(int x, int y, int translate) : Common::Point(x, y), _translate(translate) {} +}; + class Map { private: SherlockEngine *_vm; - Common::Array<Common::Point> _points; // Map locations for each scene + Common::Array<MapEntry> _points; // Map locations for each scene Common::StringArray _locationNames; Common::Array< Common::Array<int> > _paths; - Common::Array<int> _pathPoints; + Common::Array<Common::Point> _pathPoints; Common::Point _savedPos; Common::Point _savedSize; Surface _topLine; @@ -54,7 +62,7 @@ private: Common::Point _lDrawnPos; int _point; bool _placesShown; - int _charPoint; + int _charPoint, _oldCharPoint; int _cursorIndex; bool _drawMap; Surface _iconSave; @@ -67,6 +75,7 @@ private: void showPlaces(); void saveTopLine(); + void eraseTopLine(); void updateMap(bool flushScreen); @@ -77,9 +86,9 @@ private: public: Map(SherlockEngine *vm); - const Common::Point &operator[](int idx) { return _points[idx]; } + const MapEntry &operator[](int idx) { return _points[idx]; } - void loadPoints(int count, const int *xList, const int *yList); + void loadPoints(int count, const int *xList, const int *yList, const int *transList); int show(); }; diff --git a/engines/sherlock/scalpel/darts.cpp b/engines/sherlock/scalpel/darts.cpp index 857ac63f8c..c975cb1086 100644 --- a/engines/sherlock/scalpel/darts.cpp +++ b/engines/sherlock/scalpel/darts.cpp @@ -27,10 +27,395 @@ namespace Sherlock { namespace Scalpel { +enum { + STATUS_INFO_X = 218, + STATUS_INFO_Y = 53, + DART_INFO_X = 218, + DART_INFO_Y = 103, + DARTBARHX = 35, + DARTHORIZY = 190, + DARTBARVX = 1, + DARTHEIGHTY = 25, + DARTBARSIZE = 150, + DART_BAR_FORE = 8 +}; + +enum { + DART_COL_FORE = 5, + PLAYER_COLOR = 11 +}; + +const char *const OPPONENT_NAMES[5] = { + "Skipper", "Willy", "Micky", "Tom", "Bartender" +}; + +/*----------------------------------------------------------------*/ + +Darts::Darts(ScalpelEngine *vm) : _vm(vm) { + _dartImages = nullptr; + _level = 0; + _computerPlayer = 1; + _playerDartMode = false; + _dartScore1 = _dartScore2 = 0; + _roundNumber = 0; + _playerDartMode = false; + _roundScore = 0; + _oldDartButtons = 0; +} + +/** + * Main method for playing darts game + */ void Darts::playDarts() { + Screen &screen = *_vm->_screen; + int score, roundStartScore; + int playerNumber = 0; + int lastDart; + + // Change the font + int oldFont = screen.fontNumber(); + screen.setFont(4); + + loadDarts(); + initDarts(); + + do { + roundStartScore = score = playerNumber == 0 ? _dartScore1 : _dartScore2; + + // Show player details + showNames(playerNumber); + showStatus(playerNumber); + _roundScore = 0; + + for (int idx = 0; idx < 3; ++idx) { + // Throw a single dart + if (_computerPlayer == 1) + lastDart = throwDart(idx + 1, playerNumber * 2); + else if (_computerPlayer == 2) + lastDart = throwDart(idx + 1, playerNumber + 1); + else + lastDart = throwDart(idx + 1, 0); + + score -= lastDart; + _roundScore += lastDart; + + + } + + // todo + } while (!_vm->shouldQuit()); + // TODO } +/** + * Load the graphics needed for the dart game + */ +void Darts::loadDarts() { + Screen &screen = *_vm->_screen; + + _dartImages = new ImageFile("darts.vgs"); + screen._backBuffer1.blitFrom((*_dartImages)[1], Common::Point(0, 0)); + screen.slamArea(0, 0, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT); +} + +/** + * Initializes the variables needed for the dart game + */ +void Darts::initDarts() { + _dartScore1 = _dartScore2 = 301; + _roundNumber = 1; + + if (_level == 9) { + // No computer players + _computerPlayer = 0; + _level = 0; + } else if (_level == 8) { + _level = _vm->getRandomNumber(3); + _computerPlayer = 2; + } else { + // Check flags for opponents + for (int idx = 0; idx < 4; ++idx) { + if (_vm->readFlags(314 + idx)) + _level = idx; + } + } + + _opponent = OPPONENT_NAMES[_level]; +} + +/** + * Show the player names + */ +void Darts::showNames(int playerNum) { + Screen &screen = *_vm->_screen; + byte color = playerNum == 0 ? PLAYER_COLOR : DART_COL_FORE; + + // Print Holmes first + if (playerNum == 0) + screen.print(Common::Point(STATUS_INFO_X, STATUS_INFO_Y), PLAYER_COLOR + 3, "Holmes"); + else + screen.print(Common::Point(STATUS_INFO_X, STATUS_INFO_Y), color, "Holmes"); + + screen._backBuffer1.fillRect(Common::Rect(STATUS_INFO_X, STATUS_INFO_Y + 10, + STATUS_INFO_X + 31, STATUS_INFO_Y + 12), color); + screen.slamArea(STATUS_INFO_X, STATUS_INFO_Y + 10, 31, 12); + + // Second player + color = playerNum == 1 ? PLAYER_COLOR : DART_COL_FORE; + + if (playerNum != 0) + screen.print(Common::Point(STATUS_INFO_X + 50, STATUS_INFO_Y + 10), PLAYER_COLOR + 3, + _opponent.c_str()); + else + screen.print(Common::Point(STATUS_INFO_X + 50, STATUS_INFO_Y + 10), color, + _opponent.c_str()); + + screen._backBuffer1.fillRect(Common::Rect(STATUS_INFO_X + 50, STATUS_INFO_Y + 10, + STATUS_INFO_Y + 81, STATUS_INFO_Y + 12), color); + screen.slamArea(STATUS_INFO_X + 50, STATUS_INFO_Y + 10, 81, 12); + + // Make a copy of the back buffer to the secondary one + screen._backBuffer2.blitFrom(screen._backBuffer1); +} + +/** + * Show the player score and game status + */ +void Darts::showStatus(int playerNum) { + Screen &screen = *_vm->_screen; + byte color; + + screen._backBuffer1.blitFrom(screen._backBuffer2, Common::Point(STATUS_INFO_X, STATUS_INFO_Y + 10), + Common::Rect(STATUS_INFO_X, STATUS_INFO_Y + 10, SHERLOCK_SCREEN_WIDTH, STATUS_INFO_Y + 38)); + + color = (playerNum == 0) ? PLAYER_COLOR : DART_COL_FORE; + screen.print(Common::Point(STATUS_INFO_X + 6, STATUS_INFO_Y + 13), color, "%d", _dartScore1); + + color = (playerNum == 1) ? PLAYER_COLOR : DART_COL_FORE; + screen.print(Common::Point(STATUS_INFO_X + 56, STATUS_INFO_Y + 13), color, "%d", _dartScore2); + screen.print(Common::Point(STATUS_INFO_X, STATUS_INFO_Y + 25), PLAYER_COLOR, "Round: %d", _roundNumber); + screen.print(Common::Point(STATUS_INFO_X, STATUS_INFO_Y + 35), PLAYER_COLOR, "Turn Total: %d", _roundScore); + screen.slamRect(Common::Rect(STATUS_INFO_X, STATUS_INFO_Y + 10, SHERLOCK_SCREEN_WIDTH, STATUS_INFO_Y + 48)); +} + +/** + * Throws a single dart. + * @param dartNum Dart number + * @param computer 0 = Player, 1 = 1st player computer, 2 = 2nd player computer + * @returns Score for what dart hit + */ +int Darts::throwDart(int dartNum, int computer) { + Events &events = *_vm->_events; + Screen &screen = *_vm->_screen; + Common::Point targetNum; + int width, height; + + events.clearKeyboard(); + + erasePowerBars(); + screen.print(Common::Point(DART_INFO_X, DART_INFO_Y), DART_COL_FORE, "Dart # %d", dartNum); + + if (!computer) { + screen.print(Common::Point(DART_INFO_X, DART_INFO_Y + 10), DART_COL_FORE, "Hit a key"); + screen.print(Common::Point(DART_INFO_X, DART_INFO_Y + 18), DART_COL_FORE, "to start"); + } + + if (!computer) { + while (!_vm->shouldQuit() && !dartHit()) + ; + } else { + events.delay(10); + } + + screen._backBuffer1.blitFrom(screen._backBuffer2, Common::Point(DART_INFO_X, DART_INFO_Y - 1), + Common::Rect(DART_INFO_X, DART_INFO_Y - 1, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT)); + screen.slamRect(Common::Rect(DART_INFO_X, DART_INFO_Y - 1, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT)); + + // If it's a computer player, choose a dart destination + if (computer) + targetNum = getComputerDartDest(computer - 1); + + width = doPowerBar(Common::Point(DARTBARHX, DARTHORIZY), DART_BAR_FORE, targetNum.x, 0); + height = 101 - doPowerBar(Common::Point(DARTBARVX, DARTHEIGHTY), DART_BAR_FORE, targetNum.y, 0); + + // For human players, slight y adjustment + if (computer == 0) + height = 2; + + // Copy the bars to the secondary back buffer + screen._backBuffer2.blitFrom(screen._backBuffer1, Common::Point(DARTBARHX - 1, DARTHORIZY - 1), + Common::Rect(DARTBARHX - 1, DARTHORIZY - 1, DARTBARHX + DARTBARSIZE + 3, DARTHORIZY + 10)); + screen._backBuffer2.blitFrom(screen._backBuffer1, Common::Point(DARTBARVX - 1, DARTHEIGHTY - 1), + Common::Rect(DARTBARVX - 1, DARTHEIGHTY - 1, DARTBARVX + 11, DARTHEIGHTY + DARTBARSIZE + 3)); + + // Convert to relative range from -49 to 150 + height -= 50; + width -= 50; + + Common::Point dartPos(111 + width * 2, 99 + height * 2); + drawDartThrow(dartPos); + + return dartScore(dartPos); +} + +/** + * Draw a dart moving towards the board + */ +void Darts::drawDartThrow(const Common::Point &pt) { + // TODO +} + +/** + * Erases the power bars + */ +void Darts::erasePowerBars() { + Screen &screen = *_vm->_screen; + + screen._backBuffer1.fillRect(Common::Rect(DARTBARHX, DARTHORIZY, DARTBARHX + DARTBARSIZE, DARTHORIZY + 10), 0); + screen._backBuffer1.fillRect(Common::Rect(DARTBARVX, DARTHEIGHTY, DARTBARVX + 10, DARTHEIGHTY + DARTBARSIZE), 0); + screen._backBuffer1.transBlitFrom((*_dartImages)[3], Common::Point(DARTBARHX - 1, DARTHORIZY - 1)); + screen._backBuffer1.transBlitFrom((*_dartImages)[4], Common::Point(DARTBARVX - 1, DARTHEIGHTY - 1)); + screen.slamArea(DARTBARHX - 1, DARTHORIZY - 1, DARTBARSIZE + 3, 11); + screen.slamArea(DARTBARVX - 1, DARTHEIGHTY - 1, 11, DARTBARSIZE + 3); +} + +/** + * Show a gradually incrementing incrementing power that bar. If goToPower is provided, it will + * increment to that power level ignoring all keyboard input (ie. for computer throws). + * Otherwise, it will increment until either a key/mouse button is pressed, or it reaches the end + */ +int Darts::doPowerBar(const Common::Point &pt, byte color, int goToPower, int orientation) { + // TODO + return 0; +} + +/** + * Returns true if a mouse button or key is pressed. + */ +bool Darts::dartHit() { + Events &events = *_vm->_events; + + if (events.kbHit()) { + events.clearKeyboard(); + return true; + } + + events.setButtonState(); + return events._pressed && !_oldDartButtons; +} + +/** + * Return the score of the given location on the dart-board + */ +int Darts::dartScore(const Common::Point &pt) { + // TODO + return 0; +} + +/** + * Calculates where a computer player is trying to throw their dart, and choose the actual + * point that was hit with some margin of error + */ +Common::Point Darts::getComputerDartDest(int playerNum) { + Common::Point target; + int aim; + int score = playerNum == 0 ? _dartScore1 : _dartScore2; + + if (score > 50) { + // Aim for the bullseye + target.x = target.y = 76; + + if (_level <= 1 && _vm->getRandomNumber(1) == 1) { + // Introduce margin of error + target.x += _vm->getRandomNumber(21) - 10; + target.y += _vm->getRandomNumber(21) - 10; + } + } else { + aim = score; + + bool done; + Common::Point pt; + do { + done = findNumberOnBoard(aim, pt); + --aim; + } while (!done); + + target.x = 75 + ((target.x - 75) * 20 / 27); + target.y = 75 + ((target.y - 75) * 2 / 3); + } + + // Pick a level of accuracy. The higher the level, the more accurate their throw will be + int accuracy = _vm->getRandomNumber(10) + _level * 2; + + if (accuracy <= 2) { + target.x += _vm->getRandomNumber(71) - 35; + target.y += _vm->getRandomNumber(71) - 35; + } else if (accuracy <= 4) { + target.x += _vm->getRandomNumber(51) - 25; + target.y += _vm->getRandomNumber(51) - 25; + } else if (accuracy <= 6) { + target.x += _vm->getRandomNumber(31) - 15; + target.y += _vm->getRandomNumber(31) - 15; + } else if (accuracy <= 8) { + target.x += _vm->getRandomNumber(21) - 10; + target.y += _vm->getRandomNumber(21) - 10; + } else if (accuracy <= 10) { + target.x += _vm->getRandomNumber(11) - 5; + target.y += _vm->getRandomNumber(11) - 5; + } + + if (target.x < 1) + target.x = 1; + if (target.y < 1) + target.y = 1; + + return target; +} + +/** + * Returns the center position for the area of the dartboard with a given number + */ +bool Darts::findNumberOnBoard(int aim, Common::Point &pt) { + ImageFrame &board = (*_dartImages)[2]; + + // Scan board image for the special "center" pixels + bool done = false; + for (int yp = 0; yp < 132 && !done; ++yp) { + const byte *srcP = (const byte *)board._frame.getBasePtr(0, yp); + for (int xp = 0; xp < 147 && !done; ++xp, ++srcP) { + int score = *srcP; + + // Check for match + if (score == aim) { + done = true; + + // Aim at non-double/triple numbers where possible + if (aim < 21) { + pt.x = xp + 5; + pt.y = yp + 5; + + score = *(const byte *)board._frame.getBasePtr(xp + 10, yp + 10); + if (score != aim) + // Not aiming at non-double/triple number yet + done = false; + } else { + // Aiming at a double or triple + pt.x = xp + 3; + pt.y = yp + 3; + } + } + } + } + + if (aim == 3) + pt.x += 15; + pt.y = 132 - pt.y; + + return done; +} + + } // End of namespace Scalpel } // End of namespace Scalpel diff --git a/engines/sherlock/scalpel/darts.h b/engines/sherlock/scalpel/darts.h index 22164156c9..2fbdc3d7e2 100644 --- a/engines/sherlock/scalpel/darts.h +++ b/engines/sherlock/scalpel/darts.h @@ -23,6 +23,8 @@ #ifndef SHERLOCK_DARTS_H #define SHERLOCK_DARTS_H +#include "sherlock/resources.h" + namespace Sherlock { namespace Scalpel { @@ -32,8 +34,37 @@ class ScalpelEngine; class Darts { private: ScalpelEngine *_vm; + ImageFile *_dartImages; + int _dartScore1, _dartScore2; + int _roundNumber; + int _level; + int _computerPlayer; + Common::String _opponent; + bool _playerDartMode; + int _roundScore; + int _oldDartButtons; + + void loadDarts(); + void initDarts(); + + void showNames(int playerNum); + void showStatus(int playerNum); + + int throwDart(int dartNum, int computer); + void drawDartThrow(const Common::Point &pt); + + void erasePowerBars(); + int doPowerBar(const Common::Point &pt, byte color, int goToPower, int orientation); + + bool dartHit(); + int dartScore(const Common::Point &pt); + + Common::Point getComputerDartDest(int playerNum); + + bool findNumberOnBoard(int aim, Common::Point &pt); + public: - Darts(ScalpelEngine *vm) : _vm(vm) {} + Darts(ScalpelEngine *vm); void playDarts(); }; diff --git a/engines/sherlock/scalpel/scalpel.cpp b/engines/sherlock/scalpel/scalpel.cpp index 0742d05366..eba6626c53 100644 --- a/engines/sherlock/scalpel/scalpel.cpp +++ b/engines/sherlock/scalpel/scalpel.cpp @@ -39,6 +39,12 @@ const int MAP_Y[NUM_PLACES] = { 37, 0, 70, 0, 116, 0, 0, 0, 50, 21, 0, 303, 0, 0, 229, 0, 0 }; +int MAP_TRANSLATE[NUM_PLACES] = { + 0, 0, 0, 1, 0, 2, 0, 3, 4, 0, 4, 6, 0, 0, 0, 8, 9, 10, 11, 0, 12, 13, 14, 7, + 15, 16, 17, 18, 19, 0, 20, 21, 22, 23, 0, 24, 0, 25, 0, 26, 0, 0, 0, 27, + 28, 0, 29, 0, 0, 30, 0 +}; + #define MAX_PEOPLE 66 const byte STILL_SEQUENCES[MAX_PEOPLE][MAX_TALK_SEQUENCES] = { @@ -204,7 +210,7 @@ void ScalpelEngine::initialize() { _flags[39] = true; // Turn on Baker Street // Load the map co-ordinates for each scene - _map->loadPoints(NUM_PLACES, &MAP_X[0], &MAP_Y[0]); + _map->loadPoints(NUM_PLACES, &MAP_X[0], &MAP_Y[0], &MAP_TRANSLATE[0]); // Load the inventory loadInventory(); |