[Scummvm-cvs-logs] SF.net SVN: scummvm:[40378] scummvm/trunk/engines/sci/engine/kpathing.cpp

waltervn at users.sourceforge.net waltervn at users.sourceforge.net
Fri May 8 13:08:53 CEST 2009


Revision: 40378
          http://scummvm.svn.sourceforge.net/scummvm/?rev=40378&view=rev
Author:   waltervn
Date:     2009-05-08 11:08:53 +0000 (Fri, 08 May 2009)

Log Message:
-----------
SCI: AvoidPath: added support for multiple contained-access polygons (ECO1).

Modified Paths:
--------------
    scummvm/trunk/engines/sci/engine/kpathing.cpp

Modified: scummvm/trunk/engines/sci/engine/kpathing.cpp
===================================================================
--- scummvm/trunk/engines/sci/engine/kpathing.cpp	2009-05-08 09:54:24 UTC (rev 40377)
+++ scummvm/trunk/engines/sci/engine/kpathing.cpp	2009-05-08 11:08:53 UTC (rev 40378)
@@ -1054,52 +1054,118 @@
 	return find_free_point(isec, ipolygon, ret);
 }
 
-static int fix_point(PathfindingState *s, const Common::Point &p, Common::Point *ret, Polygon **ret_pol) {
-	// Checks a point for containment in any of the polygons in the polygon set.
-	// If the point is contained in a totally accessible polygon that polygon
-	// is removed from the set. If the point is contained in a polygon of another
-	// type the near point is returned. Otherwise the original point is returned
-	// Parameters: (const Common::Point &) p: The point
-	// Returns   : (int) PF_OK on success, PF_FATAL otherwise
-	//             (Common::Point) *ret: A valid input point for pathfinding
-	//             (Polygon *) *ret_pol: The polygon p was contained in if p
-	//                                     != *ret, NULL otherwise
-	PolygonList::iterator it;
-	*ret_pol = NULL;
+/**
+ * Checks that the start point is in a valid position, and takes appropriate action if it's not.
+ * @param s				the pathfinding state
+ * @param start			the start point
+ * @return a valid start point on success, NULL otherwise
+ */
+static Common::Point *fixup_start_point(PathfindingState *s, const Common::Point &start) {
+	PolygonList::iterator it = s->polygons.begin();
+	Common::Point *new_start = new Common::Point(start);
 
-	// Check for polygon containment
-	for (it = s->polygons.begin(); it != s->polygons.end(); ++it) {
-		if (contained(p, *it) != CONT_OUTSIDE)
+	while (it != s->polygons.end()) {
+		int cont = contained(start, *it);
+		int type = (*it)->type;
+
+		switch (type) {
+		case POLY_TOTAL_ACCESS:
+			// Remove totally accessible polygons that contain the start point
+			if (cont != CONT_OUTSIDE) {
+				delete *it;
+				it = s->polygons.erase(it);
+				continue;
+			}
 			break;
-	}
+		case POLY_CONTAINED_ACCESS:
+			// Remove contained access polygons that do not contain
+			// the start point (containment test is inverted here).
+			if (cont == CONT_INSIDE) {
+				delete *it;
+				it = s->polygons.erase(it);
+				continue;
+			}
+			break;
+		case POLY_BARRED_ACCESS:
+		case POLY_NEAREST_ACCESS:
+			if (cont == CONT_INSIDE) {
+				if (s->_prependPoint != NULL) {
+					// We shouldn't get here twice
+					warning("AvoidPath: start point is contained in multiple polygons");
+					continue;
+				}
 
-	if (it != s->polygons.end()) {
-		Common::Point near_p;
+				if (near_point(start, (*it), new_start) != PF_OK) {
+					delete new_start;
+					return NULL;
+				}
 
-		if ((*it)->type == POLY_TOTAL_ACCESS) {
-			// Remove totally accessible polygon if it contains p
-			
-			s->polygons.erase(it);
-			*ret = p;
-			return PF_OK;
+				if (type == POLY_BARRED_ACCESS)
+					warning("AvoidPath: start position at unreachable location");
+
+				// The original start position is in an invalid location, so we
+				// use the moved point and add the original one to the final path
+				// later on.
+				s->_prependPoint = new Common::Point(start);
+			}
 		}
 
-		// Otherwise, compute near point
-		if (near_point(p, (*it), &near_p) == PF_OK) {
-			*ret = near_p;
+		++it;
+	}
 
-			if (p != *ret)
-				*ret_pol = *it;
+	return new_start;
+}
 
-			return PF_OK;
+/**
+ * Checks that the end point is in a valid position, and takes appropriate action if it's not.
+ * @param s				the pathfinding state
+ * @param end			the end point
+ * @return a valid end point on success, NULL otherwise
+ */
+static Common::Point *fixup_end_point(PathfindingState *s, const Common::Point &end) {
+	PolygonList::iterator it = s->polygons.begin();
+	Common::Point *new_end = new Common::Point(end);
+
+	while (it != s->polygons.end()) {
+		int cont = contained(end, *it);
+		int type = (*it)->type;
+
+		switch (type) {
+		case POLY_TOTAL_ACCESS:
+			// Remove totally accessible polygons that contain the end point
+			if (cont != CONT_OUTSIDE) {
+				delete *it;
+				it = s->polygons.erase(it);
+				continue;
+			}
+			break;
+		case POLY_CONTAINED_ACCESS:
+		case POLY_BARRED_ACCESS:
+		case POLY_NEAREST_ACCESS:
+			if (cont == CONT_INSIDE) {
+				if (s->_appendPoint != NULL) {
+					// We shouldn't get here twice
+					warning("AvoidPath: end point is contained in multiple polygons");
+					continue;
+				}
+
+				// The original end position is in an invalid location, so we move the point
+				if (near_point(end, (*it), new_end) != PF_OK) {
+					delete new_end;
+					return NULL;
+				}
+
+				// For near-point access polygons we need to add the original end point
+				// to the path after pathfinding.
+				if (type == POLY_NEAREST_ACCESS)
+					s->_appendPoint = new Common::Point(end);
+			}
 		}
 
-		return PF_FATAL;
+		++it;
 	}
 
-	// p is not contained in any polygon
-	*ret = p;
-	return PF_OK;
+	return new_end;
 }
 
 static Vertex *merge_point(PathfindingState *s, const Common::Point &v) {
@@ -1268,8 +1334,6 @@
 	int err;
 	int count = 0;
 	PathfindingState *pf_s = new PathfindingState();
-	Common::Point new_start = start;
-	Common::Point new_end = end;
 
 	// Convert all polygons
 	if (poly_list.segment) {
@@ -1300,53 +1364,63 @@
 	}
 
 	if (opt == 0) {
+		Common::Point intersection;
+
 		// Keyboard support
+		// FIXME: We don't need to dijkstra for keyboard support as we currently do
 		change_polygons_opt_0(pf_s);
 
 		// Find nearest intersection
-		err = nearest_intersection(pf_s, start, end, &new_start);
+		err = nearest_intersection(pf_s, start, end, &intersection);
 
 		if (err == PF_FATAL) {
-			sciprintf("[avoidpath] Error: fatal error finding nearest intersecton\n");
+			warning("AvoidPath: fatal error finding nearest intersecton");
 			delete pf_s;
 			return NULL;
-		} else if (err == PF_OK)
-			// Keep original start position if intersection was found
+		}
+
+		if (err == PF_OK) {
+			// Intersection was found, prepend original start position after pathfinding
 			pf_s->_prependPoint = new Common::Point(start);
+			// Merge new start point into polygon set
+			pf_s->vertex_start = merge_point(pf_s, intersection);
+		} else {
+			// Otherwise we proceed with the original start point
+			pf_s->vertex_start = merge_point(pf_s, start);
+		}
+		// Merge end point into polygon set
+		pf_s->vertex_end = merge_point(pf_s, end);
 	} else {
-		if (fix_point(pf_s, start, &new_start, &polygon) != PF_OK) {
-			sciprintf("[avoidpath] Error: couldn't fix start position for pathfinding\n");
+		Common::Point *new_start = fixup_start_point(pf_s, start);
+
+		if (!new_start) {
+			warning("AvoidPath: Couldn't fixup start position for pathfinding");
 			delete pf_s;
 			return NULL;
-		} else if (polygon) {
-			// Start position has moved
-			pf_s->_prependPoint = new Common::Point(start);
-			if ((polygon->type != POLY_NEAREST_ACCESS))
-				sciprintf("[avoidpath] Warning: start position at unreachable location\n");
 		}
-	}
 
-	if (fix_point(pf_s, end, &new_end, &polygon) != PF_OK) {
-		sciprintf("[avoidpath] Error: couldn't fix end position for pathfinding\n");
-		delete pf_s;
-		return NULL;
-	} else {
-		// Keep original end position if it is contained in a
-		// near-point accessible polygon
-		if (polygon && (polygon->type == POLY_NEAREST_ACCESS))
-			pf_s->_appendPoint = new Common::Point(end);
-	}
+		Common::Point *new_end = fixup_end_point(pf_s, end);
 
-	if (s->_gameName == "Longbow") {
-		// FIXME: implement function to get current room number
-		if ((KP_UINT(s->script_000->locals_block->locals[13]) == 210))
-			fixLongbowRoom210(pf_s, new_start, new_end);
+		if (!new_end) {
+			warning("AvoidPath: Couldn't fixup end position for pathfinding");
+			delete pf_s;
+			return NULL;
+		}
+
+		if (s->_gameName == "Longbow") {
+			// FIXME: implement function to get current room number
+			if ((KP_UINT(s->script_000->locals_block->locals[13]) == 210))
+				fixLongbowRoom210(pf_s, *new_start, *new_end);
+		}
+
+		// Merge start and end points into polygon set
+		pf_s->vertex_start = merge_point(pf_s, *new_start);
+		pf_s->vertex_end = merge_point(pf_s, *new_end);
+
+		delete new_start;
+		delete new_end;
 	}
 
-	// Merge start and end points into polygon set
-	pf_s->vertex_start = merge_point(pf_s, new_start);
-	pf_s->vertex_end = merge_point(pf_s, new_end);
-
 	// Allocate and build vertex index
 	pf_s->vertex_index = (Vertex**)sci_malloc(sizeof(Vertex *) * (count + 2));
 


This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.




More information about the Scummvm-git-logs mailing list