aboutsummaryrefslogtreecommitdiff
path: root/engines/teenagent
diff options
context:
space:
mode:
authorVladimir Menshakov2009-11-14 11:32:58 +0000
committerVladimir Menshakov2009-11-14 11:32:58 +0000
commitcc1119940c833f7b61a977306c0a1a9cdf98cd6f (patch)
tree57eb9eda40ac2114fe3a3c705448341224ec8db6 /engines/teenagent
parent772ac8ca709771fde478513addce3eec2eb4bbff (diff)
downloadscummvm-rg350-cc1119940c833f7b61a977306c0a1a9cdf98cd6f.tar.gz
scummvm-rg350-cc1119940c833f7b61a977306c0a1a9cdf98cd6f.tar.bz2
scummvm-rg350-cc1119940c833f7b61a977306c0a1a9cdf98cd6f.zip
added pathfinding
svn-id: r45892
Diffstat (limited to 'engines/teenagent')
-rw-r--r--engines/teenagent/scene.cpp226
-rw-r--r--engines/teenagent/scene.h7
2 files changed, 211 insertions, 22 deletions
diff --git a/engines/teenagent/scene.cpp b/engines/teenagent/scene.cpp
index ed0de66be9..79ce6b1b66 100644
--- a/engines/teenagent/scene.cpp
+++ b/engines/teenagent/scene.cpp
@@ -42,16 +42,174 @@ Scene::Scene() : intro(false), _engine(NULL),
void Scene::warp(const Common::Point &_point, byte o) {
Common::Point point(_point);
- destination = position = point;
+ position = point;
+ path.clear();
if (o)
orientation = o;
}
+struct Splitter {
+ typedef Common::List<int> ListType;
+ ListType values;
+ uint _size;
+
+ Splitter(): values(), _size(0) {}
+
+ void insert(int v) {
+ ListType::iterator i;
+ for(i = values.begin(); i != values.end(); ++i) {
+ if (v == *i)
+ return;
+
+ if (v < *i)
+ break;
+ }
+ values.insert(i, v);
+ ++_size;
+ }
+ uint size() const { return _size; }
+};
+
+struct Node {
+ Rect rect;
+ int step;
+ int prev;
+
+ Node(): step(0), prev(0) {}
+};
+
+
+static void search(Node *nodes, int n, int m, int i, int j, int prev_idx, int end, int level) {
+ if (i < 0 || i >= n || j < 0 || j >= m)
+ return;
+ int idx = j + i * m;
+ int v = nodes[idx].step;
+ //debug(1, "search (%d, %d) %d, value = %d", i, j, level, v);
+ if (v != 0 && (v == -1 || v <= level))
+ return;
+
+ nodes[idx].step = level; //mark as visited
+ nodes[idx].prev = prev_idx;
+
+ ++level;
+
+ search(nodes, n, m, i - 1, j, idx, end, level);
+ search(nodes, n, m, i + 1, j, idx, end, level);
+ search(nodes, n, m, i, j - 1, idx, end, level);
+ search(nodes, n, m, i, j + 1, idx, end, level);
+}
+
+
+bool Scene::findPath(Scene::Path &p, const Common::Point &src, const Common::Point &dst) const {
+ const Common::Array<Walkbox> &scene_walkboxes = walkboxes[_id - 1];
+ if (dst.x < 0 || dst.x > 319 || dst.y < 0 || dst.y > 199)
+ return false;
+
+ debug(1, "findPath %d,%d -> %d,%d", src.x, src.y, dst.x, dst.y);
+
+ Splitter hsplit, vsplit;
+ for(byte i = 0; i < scene_walkboxes.size(); ++i) {
+ const Walkbox &w = scene_walkboxes[i];
+ if (w.rect.valid()) {
+ hsplit.insert(w.rect.left);
+ hsplit.insert(w.rect.right);
+ vsplit.insert(w.rect.top);
+ vsplit.insert(w.rect.bottom);
+ }
+ }
+
+ int n = (int)vsplit.size() - 1, m = (int)hsplit.size() - 1;
+ debug(1, "split: %ux%u", n, m);
+ if (n <= 0 || m <= 0) {
+ p.push_back(Common::Point(src.x, dst.y));
+ p.push_back(dst);
+ return true;
+ }
+
+ Node *nodes = new Node[n * m];
+ int start = -1, end = -1;
+ {
+ int idx = 0;
+ for(Splitter::ListType::const_iterator i = vsplit.values.begin(); i != vsplit.values.end(); ++i) {
+ Splitter::ListType::const_iterator in = i; ++in;
+ if (in == vsplit.values.end())
+ break;
+
+ for(Splitter::ListType::const_iterator j = hsplit.values.begin(); j != hsplit.values.end(); ++j) {
+ Splitter::ListType::const_iterator jn = j; ++jn;
+ if (jn == hsplit.values.end())
+ break;
+
+ Rect &r = nodes[idx].rect;
+ r = Rect(*j, *i, *jn, *in);
+ if (r.in(src))
+ start = idx;
+ if (r.in(dst))
+ end = idx;
+
+ byte k = 0;
+ for(k = 0; k < scene_walkboxes.size(); ++k) {
+ const Walkbox &w = scene_walkboxes[k];
+ if (w.rect.contains(r))
+ break;
+ }
+ nodes[idx++].step = k >= scene_walkboxes.size()? 0: -1;
+ }
+ }
+ }
+
+ debug(1, "%d -> %d", start, end);
+
+ if (start == -1 || end == -1)
+ return false;
+
+ search(nodes, n, m, start / m, start % m, -1, end, 1);
+ int v = end;
+ do {
+ debug(1, "backtrace %d", v);
+ Common::Point c = nodes[v].rect.center();
+ if (end / m == v / m) { //same y
+ c.y = dst.y;
+ }
+ if (end % m == v % m) {
+ c.x = dst.x;
+ }
+ p.push_front(c);
+ if (v == start)
+ break;
+
+ v = nodes[v].prev;
+ } while(v >= 0);
+
+ debug(1, "end vertex = %d", v);
+
+ if (v != start)
+ return false;
+
+#if 0
+ {
+ int idx = 0;
+ for(int i = 0; i < n; ++i) {
+ Common::String line;
+ for(int j = 0; j < m; ++j) {
+ line += Common::String::printf("%2d.%2d ", nodes[idx].step, nodes[idx].prev);
+ ++idx;
+ }
+ debug(1, "map: %s", line.c_str());
+ }
+ }
+#endif
+
+ delete[] nodes;
+ return true;
+}
+
void Scene::moveTo(const Common::Point &_point, byte orient, bool validate) {
Common::Point point(_point);
debug(0, "moveTo(%d, %d, %u)", point.x, point.y, orient);
+ const Common::Array<Walkbox> &scene_walkboxes = walkboxes[_id - 1];
+
if (validate) {
- const Common::Array<Walkbox> &scene_walkboxes = walkboxes[_id - 1];
for (byte i = 0; i < scene_walkboxes.size(); ++i) {
const Walkbox &w = scene_walkboxes[i];
if (w.rect.in(point)) {
@@ -83,7 +241,18 @@ void Scene::moveTo(const Common::Point &_point, byte orient, bool validate) {
nextEvent();
return;
}
- destination = point;
+
+ path.clear();
+ if (scene_walkboxes.empty()) {
+ path.push_back(point);
+ return;
+ }
+
+ if (!findPath(path, position, point)) {
+ _engine->cancel();
+ return;
+ }
+
orientation = orient;
}
@@ -465,8 +634,9 @@ bool Scene::render(OSystem *system) {
} else if (!hide_actor) {
actor_animation.free();
- if (position != destination) {
+ if (!path.empty()) {
const int speed_x = 10, speed_y = 5;
+ const Common::Point &destination = path.front();
Common::Point dp(destination.x - position.x, destination.y - position.y);
switch(orientation) {
case 2: //left or right
@@ -490,12 +660,15 @@ bool Scene::render(OSystem *system) {
actor_animation_position = teenagent.render(surface, position, o, 1);
if (position == destination) {
- position = destination;
- if (orientation == 0)
- orientation = o; //save last orientation
- nextEvent();
- got_any_animation = true;
- restart = true;
+ path.pop_front();
+ if (path.empty()) {
+ if (orientation == 0)
+ orientation = o; //save last orientation
+ nextEvent();
+ got_any_animation = true;
+ restart = true;
+ }
+ busy = true;
} else
busy = true;
} else
@@ -530,31 +703,42 @@ bool Scene::render(OSystem *system) {
}
}
- system->unlockScreen();
-
- if (!restart && current_event.type == SceneEvent::kWaitForAnimation && !got_any_animation) {
- debug(0, "no animations, nextevent");
- nextEvent();
- restart = true;
- }
-
+#if 0
//if (!current_event.empty())
// current_event.dump();
- /*
+
{
const Common::Array<Walkbox> & scene_walkboxes = walkboxes[_id - 1];
for (uint i = 0; i < scene_walkboxes.size(); ++i) {
scene_walkboxes[i].rect.render(surface, 0xd0 + i);
}
+
+ Common::Point last_p = position;
+ for(Path::const_iterator p = path.begin(); p != path.end(); ++p) {
+ const Common::Point dp(p->x - last_p.x, p->y - last_p.y);
+ if (dp.x != 0) {
+ surface->hLine(last_p.x, last_p.y, p->x, 0xfe);
+ } else if (dp.y != 0) {
+ surface->vLine(last_p.x, last_p.y, p->y, 0xfe);
+ }
+ last_p = *p;
+ }
}
- */
+#endif
+ system->unlockScreen();
+
+ if (!restart && current_event.type == SceneEvent::kWaitForAnimation && !got_any_animation) {
+ debug(0, "no animations, nextevent");
+ nextEvent();
+ restart = true;
+ }
} while (restart);
for (Sounds::iterator i = sounds.begin(); i != sounds.end();) {
Sound &sound = *i;
if (sound.delay == 0) {
- debug(0, "sound %u started", sound.id);
+ debug(1, "sound %u started", sound.id);
_engine->playSoundNow(sound.id);
i = sounds.erase(i);
} else {
diff --git a/engines/teenagent/scene.h b/engines/teenagent/scene.h
index 897b883fae..8ca1646448 100644
--- a/engines/teenagent/scene.h
+++ b/engines/teenagent/scene.h
@@ -182,9 +182,14 @@ private:
Common::Rect actor_animation_position, animation_position[4];
Actor teenagent, teenagent_idle;
- Common::Point position, destination;
+ Common::Point position;
+
+ typedef Common::List<Common::Point> Path;
+ Path path;
uint8 orientation;
+ bool findPath(Path &p, const Common::Point &src, const Common::Point &dst) const;
+
Common::Array<Common::Array<Object> > objects;
Common::Array<Common::Array<Walkbox> > walkboxes;