aboutsummaryrefslogtreecommitdiff
path: root/engines
diff options
context:
space:
mode:
authorPaul Gilbert2015-03-24 22:24:45 -0400
committerPaul Gilbert2015-03-24 22:24:45 -0400
commit03a969bd0f696f9a7fa0dc56c47c2b05d28a5a47 (patch)
treedd1a84a328984d0d53f598168371575e9b87cd29 /engines
parent97e58fb0171af885019d997493db33fab9af0091 (diff)
downloadscummvm-rg350-03a969bd0f696f9a7fa0dc56c47c2b05d28a5a47.tar.gz
scummvm-rg350-03a969bd0f696f9a7fa0dc56c47c2b05d28a5a47.tar.bz2
scummvm-rg350-03a969bd0f696f9a7fa0dc56c47c2b05d28a5a47.zip
SHERLOCK: Implementing walk code
Diffstat (limited to 'engines')
-rw-r--r--engines/sherlock/people.cpp127
-rw-r--r--engines/sherlock/people.h1
-rw-r--r--engines/sherlock/scene.cpp56
-rw-r--r--engines/sherlock/scene.h6
-rw-r--r--engines/sherlock/sherlock.cpp3
-rw-r--r--engines/sherlock/user_interface.cpp6
-rw-r--r--engines/sherlock/user_interface.h2
7 files changed, 185 insertions, 16 deletions
diff --git a/engines/sherlock/people.cpp b/engines/sherlock/people.cpp
index 8a8dcb5245..ca840bb5b1 100644
--- a/engines/sherlock/people.cpp
+++ b/engines/sherlock/people.cpp
@@ -58,6 +58,7 @@ People::People(SherlockEngine *vm) : _vm(vm), _player(_data[0]) {
_allowWalkAbort = false;
_portraitLoaded = false;
_clearingThePortrait = false;
+ _srcZone = _destZone = 0;
}
People::~People() {
@@ -143,7 +144,7 @@ void People::setWalking() {
// If the player is already close to the given destination that no
// walking is needed, move to the next straight line segment in the
// overall walking route, if there is one
- for (;;) {
+ do {
// Since we want the player to be centered on the destination they
// clicked, but characters draw positions start at their left, move
// the destination half the character width to draw him centered
@@ -306,13 +307,131 @@ void People::gotoStand(Sprite &sprite) {
_allowWalkAbort = true;
}
+/**
+ * Walk to the co-ordinates passed, and then face the given direction
+ */
void People::walkToCoords(const Common::Point &destPos, int destDir) {
- // TODO
- warning("TODO: walkToCoords");
+ Events &events = *_vm->_events;
+ Scene &scene = *_vm->_scene;
+ Talk &talk = *_vm->_talk;
+
+ CursorId oldCursor = events.getCursor();
+ events.setCursor(WAIT);
+
+ _walkDest = Common::Point(destPos.x / 100 + 10, destPos.y / 100);
+ _allowWalkAbort = true;
+ goAllTheWay();
+
+ // Keep calling doBgAnim until the walk is done
+ do {
+ events.pollEventsAndWait();
+ scene.doBgAnim();
+ } while (!_vm->shouldQuit() && _player._walkCount);
+
+ if (!talk._talkToAbort) {
+ // Put player exactly on destination position, and set direction
+ _player._position = destPos;
+ _player._sequenceNumber = destDir;
+ gotoStand(_player);
+
+ // Draw Holmes facing the new direction
+ scene.doBgAnim();
+
+ if (!talk._talkToAbort)
+ events.setCursor(oldCursor);
+ }
}
+/**
+ * Called to set the character walking to the current cursor location.
+ * It uses the zones and the inter-zone points to determine a series
+ * of steps to walk to get to that position.
+ */
void People::goAllTheWay() {
- // TODO
+ Scene &scene = *_vm->_scene;
+ Common::Point srcPt(_player._position.x / 100 + _player.frameWidth() / 2,
+ _player._position.y / 100);
+
+ // Get the zone the player is currently in
+ _srcZone = scene.whichZone(srcPt);
+ if (_srcZone == -1)
+ _srcZone = scene.closestZone(srcPt);
+
+ // Get the zone of the destination
+ _destZone = scene.whichZone(_walkDest);
+ if (_destZone == -1) {
+ _destZone = scene.closestZone(_walkDest);
+
+ // The destination isn't in a zone
+ if (_walkDest.x >= (SHERLOCK_SCREEN_WIDTH - 1))
+ _walkDest.x = SHERLOCK_SCREEN_WIDTH - 2;
+
+ // Trace a line between the centroid of the found closest zone to
+ // the destination, to find the point at which the zone will be left
+ const Common::Rect &destRect = scene._zones[_destZone];
+ const Common::Point destCenter((destRect.left + destRect.right) / 2,
+ (destRect.top + destRect.bottom) / 2);
+ const Common::Point delta = _walkDest - destCenter;
+ Common::Point pt(destCenter.x * 100, destCenter.y * 100);
+
+ // Move along the line until the zone is left
+ do {
+ pt += delta;
+ } while (destRect.contains(pt.x / 100, pt.y / 100));
+
+ // Set the new walk destination to the last point that was in the
+ // zone just before it was left
+ _walkDest = Common::Point((pt.x - delta.x * 2) / 100,
+ (pt.y - delta.y * 2) / 100);
+ }
+
+ // Only do a walk if both zones are acceptable
+ if (_srcZone == -2 || _destZone == -2)
+ return;
+
+ // If the start and dest zones are the same, walk directly to the dest point
+ if (_srcZone == _destZone) {
+ setWalking();
+ } else {
+ // Otherwise a path needs to be formed from the path information
+ int i = scene._walkDirectory[_srcZone][_destZone];
+
+ // See if we need to use a reverse path
+ if (i == -1)
+ i = scene._walkDirectory[_destZone][_srcZone];
+
+ int count = scene._walkData[i];
+ ++i;
+
+ // See how many points there are between the src and dest zones
+ if (!count || count == 255) {
+ // There are none, so just walk to the new zone
+ setWalking();
+ } else {
+ // There are points, so set up a multi-step path between points
+ // to reach the given destination
+ _walkTo.clear();
+
+ if (scene._walkDirectory[_srcZone][_destZone] != -1) {
+ for (int idx = 0; idx < count; ++idx, i += 3) {
+ _walkTo.push(Common::Point(READ_LE_UINT16(&scene._walkData[i]),
+ scene._walkData[i + 2]));
+ }
+ } else {
+ for (int idx = 0; idx < count; ++idx)
+ _walkTo.push(Common::Point());
+
+ for (int idx = count - 1; idx >= 0; --idx, i += 3) {
+ _walkTo[idx].x = READ_LE_UINT16(&scene._walkData[i]);
+ _walkTo[idx].y = scene._walkData[i + 2];
+ }
+ }
+
+ // Start walking
+ _walkDest = _walkTo.top();
+ setWalking();
+ }
+ }
}
} // End of namespace Sherlock
diff --git a/engines/sherlock/people.h b/engines/sherlock/people.h
index 8d1953ee20..0393528095 100644
--- a/engines/sherlock/people.h
+++ b/engines/sherlock/people.h
@@ -59,6 +59,7 @@ private:
Sprite &_player;
bool _walkLoaded;
int _oldWalkSequence;
+ int _srcZone, _destZone;
public:
Common::Point _walkDest;
Common::Stack<Common::Point> _walkTo;
diff --git a/engines/sherlock/scene.cpp b/engines/sherlock/scene.cpp
index 95e8355957..c5cba1b5cd 100644
--- a/engines/sherlock/scene.cpp
+++ b/engines/sherlock/scene.cpp
@@ -176,7 +176,7 @@ void Scene::freeScene() {
_walkData.clear();
_cAnim.clear();
_bgShapes.clear();
- _bounds.clear();
+ _zones.clear();
_canimShapes.clear();
for (uint idx = 0; idx < _images.size(); ++idx)
@@ -205,8 +205,8 @@ bool Scene::loadScene(const Common::String &filename) {
_ongoingCans = 0;
// Reset the list of walkable areas
- _bounds.clear();
- _bounds.push_back(Common::Rect(0, 0, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT));
+ _zones.clear();
+ _zones.push_back(Common::Rect(0, 0, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT));
_descText.clear();
_comments = "";
@@ -311,12 +311,12 @@ bool Scene::loadScene(const Common::String &filename) {
Common::SeekableReadStream *boundsStream = !_lzwMode ? rrmStream :
decompressLZ(*rrmStream, size);
- _bounds.resize(size / 10);
- for (uint idx = 0; idx < _bounds.size(); ++idx) {
- _bounds[idx].left = boundsStream->readSint16LE();
- _bounds[idx].top = boundsStream->readSint16LE();
- _bounds[idx].setWidth(boundsStream->readSint16LE());
- _bounds[idx].setHeight(boundsStream->readSint16LE());
+ _zones.resize(size / 10);
+ for (uint idx = 0; idx < _zones.size(); ++idx) {
+ _zones[idx].left = boundsStream->readSint16LE();
+ _zones[idx].top = boundsStream->readSint16LE();
+ _zones[idx].setWidth(boundsStream->readSint16LE());
+ _zones[idx].setHeight(boundsStream->readSint16LE());
boundsStream->skip(2); // Skip unused scene number field
}
@@ -328,8 +328,8 @@ bool Scene::loadScene(const Common::String &filename) {
error("Invalid scene path data");
// Load the walk directory
- for (uint idx1 = 0; idx1 < _bounds.size(); ++idx1) {
- for (uint idx2 = 0; idx2 < _bounds.size(); ++idx2)
+ for (uint idx1 = 0; idx1 < _zones.size(); ++idx1) {
+ for (uint idx2 = 0; idx2 < _zones.size(); ++idx2)
_walkDirectory[idx1][idx2] = rrmStream->readSint16LE();
}
@@ -1450,4 +1450,38 @@ int Scene::checkForZones(const Common::Point &pt, int zoneType) {
return matches;
}
+/**
+ * Check which zone the the given position is located in.
+ */
+int Scene::whichZone(const Common::Point &pt) {
+ for (uint idx = 0; idx < _zones.size(); ++idx) {
+ if (_zones[idx].contains(pt))
+ return idx;
+ }
+
+ return -1;
+}
+
+/**
+ * Returns the index of the closest zone to a given point.
+ */
+int Scene::closestZone(const Common::Point &pt) {
+ int dist = 1000;
+ int zone = -1;
+
+ for (uint idx = 0; idx < _zones.size(); ++idx) {
+ Common::Point zc((_zones[idx].left + _zones[idx].right) / 2,
+ (_zones[idx].top + _zones[idx].bottom) / 2);
+ int d = ABS(zc.x - pt.x) + ABS(zc.y - pt.y);
+
+ if (d < dist) {
+ // Found a closer zone
+ dist = d;
+ zone = idx;
+ }
+ }
+
+ return zone;
+}
+
} // End of namespace Sherlock
diff --git a/engines/sherlock/scene.h b/engines/sherlock/scene.h
index 1a9fe7b02c..1b3a730179 100644
--- a/engines/sherlock/scene.h
+++ b/engines/sherlock/scene.h
@@ -137,7 +137,7 @@ public:
int _invGraphicItems;
Common::String _comments;
Common::Array<char> _descText;
- Common::Array<Common::Rect> _bounds;
+ Common::Array<Common::Rect> _zones;
Common::Array<Object> _bgShapes;
Common::Array<CAnim> _cAnim;
Common::Array<byte> _sequenceBuffer;
@@ -179,6 +179,10 @@ public:
int findBgShape(const Common::Rect &r);
int checkForZones(const Common::Point &pt, int zoneType);
+
+ int whichZone(const Common::Point &pt);
+
+ int closestZone(const Common::Point &pt);
};
} // End of namespace Sherlock
diff --git a/engines/sherlock/sherlock.cpp b/engines/sherlock/sherlock.cpp
index a9de32972f..107dee5a41 100644
--- a/engines/sherlock/sherlock.cpp
+++ b/engines/sherlock/sherlock.cpp
@@ -100,6 +100,9 @@ Common::Error SherlockEngine::run() {
if (shouldQuit())
break;
+ // Reset UI flags
+ _ui->reset();
+
// Reset the active characters to initially just Sherlock
_people->reset();
diff --git a/engines/sherlock/user_interface.cpp b/engines/sherlock/user_interface.cpp
index 661604e4bf..fc94cc5a5c 100644
--- a/engines/sherlock/user_interface.cpp
+++ b/engines/sherlock/user_interface.cpp
@@ -82,6 +82,12 @@ UserInterface::~UserInterface() {
delete _controls;
}
+void UserInterface::reset() {
+ _oldKey = -1;
+ _help = _oldHelp = -1;
+ _oldTemp = _temp = -1;
+}
+
/**
* Main input handler for the user interface
*/
diff --git a/engines/sherlock/user_interface.h b/engines/sherlock/user_interface.h
index d312ff919c..d2ef8942c3 100644
--- a/engines/sherlock/user_interface.h
+++ b/engines/sherlock/user_interface.h
@@ -95,6 +95,8 @@ public:
UserInterface(SherlockEngine *vm);
~UserInterface();
+ void reset();
+
void handleInput();
void clearInfo();