Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Ignore buildings on source or destination when pathfinding.

Droids should now go to the nearest point instead of a point which might not even be accessible, when trying to build modules or derricks.

Fixes ticket:2978.
  • Loading branch information...
commit 0119eda53f11d2aa5d3e3ccc82203c6657812039 1 parent 322bbc6
@Cyp Cyp authored
Showing with 78 additions and 14 deletions.
  1. +33 −9 src/astar.cpp
  2. +37 −5 src/fpath.cpp
  3. +8 −0 src/fpath.h
View
42 src/astar.cpp
@@ -116,12 +116,30 @@ struct PathBlockingMap
std::vector<bool> dangerMap; // using threatBits
};
+struct PathNonblockingArea
+{
+ PathNonblockingArea() {}
+ PathNonblockingArea(StructureTiles const &st) : x1(st.map.x), x2(st.map.x + st.size.x), y1(st.map.y), y2(st.map.y + st.size.y) {}
+ bool operator ==(PathNonblockingArea const &z) const { return x1 == z.x1 && x2 == z.x2 && y1 == z.y1 && y2 == z.y2; }
+ bool operator !=(PathNonblockingArea const &z) const { return !(*this == z); }
+ bool isNonblocking(int x, int y) const
+ {
+ return x >= x1 && x < x2 && y >= y1 && y < y2;
+ }
+
+ int16_t x1, x2, y1, y2;
+};
+
// Data structures used for pathfinding, can contain cached results.
struct PathfindContext
{
PathfindContext() : myGameTime(0), iteration(0), blockingMap(NULL) {}
bool isBlocked(int x, int y) const
{
+ if (srcIgnore.isNonblocking(x, y) || dstIgnore.isNonblocking(x, y))
+ {
+ return false; // The path is actually blocked here by a structure, but ignore it since it's where we want to go (or where we came from).
+ }
// Not sure whether the out-of-bounds check is needed, can only happen if pathfinding is started on a blocking tile (or off the map).
return x < 0 || y < 0 || x >= mapWidth || y >= mapHeight || blockingMap->map[x + y*mapWidth];
}
@@ -129,15 +147,17 @@ struct PathfindContext
{
return !blockingMap->dangerMap.empty() && blockingMap->dangerMap[x + y*mapWidth];
}
- bool matches(PathBlockingMap const *blockingMap_, PathCoord tileS_) const
+ bool matches(PathBlockingMap const *blockingMap_, PathCoord tileS_, PathNonblockingArea srcIgnore_, PathNonblockingArea dstIgnore_) const
{
- // Must check myGameTime == blockingMap_->type.gameTime, otherwise blockingMap be a deleted pointer which coincidentally compares equal to the valid pointer blockingMap_.
- return myGameTime == blockingMap_->type.gameTime && blockingMap == blockingMap_ && tileS == tileS_;
+ // Must check myGameTime == blockingMap_->type.gameTime, otherwise blockingMap could be a deleted pointer which coincidentally compares equal to the valid pointer blockingMap_.
+ return myGameTime == blockingMap_->type.gameTime && blockingMap == blockingMap_ && tileS == tileS_ && srcIgnore == srcIgnore_ && dstIgnore == dstIgnore_;
}
- void assign(PathBlockingMap const *blockingMap_, PathCoord tileS_)
+ void assign(PathBlockingMap const *blockingMap_, PathCoord tileS_, PathNonblockingArea srcIgnore_, PathNonblockingArea dstIgnore_)
{
blockingMap = blockingMap_;
tileS = tileS_;
+ srcIgnore = srcIgnore_;
+ dstIgnore = dstIgnore_;
myGameTime = blockingMap->type.gameTime;
nodes.clear();
@@ -164,6 +184,8 @@ struct PathfindContext
std::vector<PathNode> nodes; ///< Edge of explored region of the map.
std::vector<PathExploredTile> map; ///< Map, with paths leading back to tileS.
PathBlockingMap const *blockingMap; ///< Map of blocking tiles for the type of object which needs a path.
+ PathNonblockingArea srcIgnore; ///< Area of structure at source which should be considered nonblocking.
+ PathNonblockingArea dstIgnore; ///< Area of structure at destination which should be considered nonblocking.
};
/// Last recently used list of contexts.
@@ -344,9 +366,9 @@ static PathCoord fpathAStarExplore(PathfindContext &context, PathCoord tileF)
return nearestCoord;
}
-static void fpathInitContext(PathfindContext &context, PathBlockingMap const *blockingMap, PathCoord tileS, PathCoord tileRealS, PathCoord tileF)
+static void fpathInitContext(PathfindContext &context, PathBlockingMap const *blockingMap, PathCoord tileS, PathCoord tileRealS, PathCoord tileF, PathNonblockingArea srcIgnore, PathNonblockingArea dstIgnore)
{
- context.assign(blockingMap, tileS);
+ context.assign(blockingMap, tileS, srcIgnore, dstIgnore);
// Add the start point to the open list
fpathNewNode(context, tileF, tileRealS, 0, tileRealS);
@@ -361,13 +383,15 @@ ASR_RETVAL fpathAStarRoute(MOVE_CONTROL *psMove, PATHJOB *psJob)
const PathCoord tileOrig(map_coord(psJob->origX), map_coord(psJob->origY));
const PathCoord tileDest(map_coord(psJob->destX), map_coord(psJob->destY));
+ const PathNonblockingArea srcIgnore(psJob->srcStructure);
+ const PathNonblockingArea dstIgnore(psJob->dstStructure);
PathCoord endCoord; // Either nearest coord (mustReverse = true) or orig (mustReverse = false).
std::list<PathfindContext>::iterator contextIterator = fpathContexts.begin();
for (contextIterator = fpathContexts.begin(); contextIterator != fpathContexts.end(); ++contextIterator)
{
- if (!contextIterator->matches(psJob->blockingMap, tileDest))
+ if (!contextIterator->matches(psJob->blockingMap, tileDest, srcIgnore, dstIgnore))
{
// This context is not for the same droid type and same destination.
continue;
@@ -410,7 +434,7 @@ ASR_RETVAL fpathAStarRoute(MOVE_CONTROL *psMove, PATHJOB *psJob)
// Init a new context, overwriting the oldest one if we are caching too many.
// We will be searching from orig to dest, since we don't know where the nearest reachable tile to dest is.
- fpathInitContext(*contextIterator, psJob->blockingMap, tileOrig, tileOrig, tileDest);
+ fpathInitContext(*contextIterator, psJob->blockingMap, tileOrig, tileOrig, tileDest, srcIgnore, dstIgnore);
endCoord = fpathAStarExplore(*contextIterator, tileDest);
contextIterator->nearestCoord = endCoord;
}
@@ -492,7 +516,7 @@ ASR_RETVAL fpathAStarRoute(MOVE_CONTROL *psMove, PATHJOB *psJob)
if (!context.isBlocked(tileOrig.x, tileOrig.y)) // If blocked, searching from tileDest to tileOrig wouldn't find the tileOrig tile.
{
// Next time, search starting from nearest reachable tile to the destination.
- fpathInitContext(context, psJob->blockingMap, tileDest, context.nearestCoord, tileOrig);
+ fpathInitContext(context, psJob->blockingMap, tileDest, context.nearestCoord, tileOrig, srcIgnore, dstIgnore);
}
}
else
View
42 src/fpath.cpp
@@ -350,9 +350,31 @@ void fpathRemoveDroidData(int id)
wzMutexUnlock(fpathMutex);
}
+static StructureTiles getTilesOfStructure(BASE_OBJECT *object)
+{
+ StructureTiles ret;
+ ret.size = Vector2i(-65535, -65535); // Default to an invalid area.
+ ret.map = Vector2i(32767, 32767);
+
+ STRUCTURE *psStructure = castStructure(object);
+ FEATURE *psFeature = castFeature(object);
+
+ if (psStructure != NULL)
+ {
+ ret.size = getStructureSize(psStructure);
+ ret.map = map_coord(removeZ(psStructure->pos)) - ret.size/2;
+ }
+ else if (psFeature != NULL)
+ {
+ ret.size = Vector2i(psFeature->psStats->baseWidth, psFeature->psStats->baseBreadth);
+ ret.map = map_coord(removeZ(psFeature->pos)) - ret.size/2;
+ }
+
+ return ret;
+}
static FPATH_RETVAL fpathRoute(MOVE_CONTROL *psMove, int id, int startX, int startY, int tX, int tY, PROPULSION_TYPE propulsionType,
- DROID_TYPE droidType, FPATH_MOVETYPE moveType, int owner, bool acceptNearest)
+ DROID_TYPE droidType, FPATH_MOVETYPE moveType, int owner, bool acceptNearest, BASE_OBJECT *srcStructure, BASE_OBJECT *dstStructure)
{
objTrace(id, "called(*,id=%d,sx=%d,sy=%d,ex=%d,ey=%d,prop=%d,type=%d,move=%d,owner=%d)", id, startX, startY, tX, tY, (int)propulsionType, (int)droidType, (int)moveType, owner);
@@ -424,6 +446,8 @@ static FPATH_RETVAL fpathRoute(MOVE_CONTROL *psMove, int id, int startX, int sta
job.droidID = id;
job.destX = tX;
job.destY = tY;
+ job.srcStructure = getTilesOfStructure(srcStructure);
+ job.dstStructure = getTilesOfStructure(dstStructure);
job.droidType = droidType;
job.propulsion = propulsionType;
job.moveType = moveType;
@@ -472,10 +496,18 @@ FPATH_RETVAL fpathDroidRoute(DROID* psDroid, SDWORD tX, SDWORD tY, FPATH_MOVETYP
// Check whether the start and end points of the route are blocking tiles and find an alternative if they are.
Position startPos = psDroid->pos;
Position endPos = Position(tX, tY, 0);
+ BASE_OBJECT *srcStructure = worldTile(startPos)->psObject;
+ BASE_OBJECT *dstStructure = worldTile(endPos)->psObject;
if (psDroid->sMove.Status != MOVEWAITROUTE)
{
- startPos = findNonblockingPosition(startPos, getPropulsionStats(psDroid)->propulsionType, psDroid->player, moveType);
- endPos = findNonblockingPosition(endPos, getPropulsionStats(psDroid)->propulsionType, psDroid->player, moveType);
+ if (srcStructure == NULL) // If there's a structure over the source, ignore it, otherwise pathfind from somewhere around the obstruction.
+ {
+ startPos = findNonblockingPosition(startPos, getPropulsionStats(psDroid)->propulsionType, psDroid->player, moveType);
+ }
+ if (dstStructure == NULL) // If there's a structure over the destination, ignore it, otherwise pathfind from somewhere around the obstruction.
+ {
+ endPos = findNonblockingPosition(endPos, getPropulsionStats(psDroid)->propulsionType, psDroid->player, moveType);
+ }
objTrace(psDroid->id, "Want to go to (%d, %d) -> (%d, %d), going (%d, %d) -> (%d, %d)", map_coord(psDroid->pos.x), map_coord(psDroid->pos.y), map_coord(tX), map_coord(tY), map_coord(startPos.x), map_coord(startPos.y), map_coord(endPos.x), map_coord(endPos.y));
}
switch (psDroid->order)
@@ -492,7 +524,7 @@ FPATH_RETVAL fpathDroidRoute(DROID* psDroid, SDWORD tX, SDWORD tY, FPATH_MOVETYP
break;
}
return fpathRoute(&psDroid->sMove, psDroid->id, startPos.x, startPos.y, endPos.x, endPos.y, psPropStats->propulsionType,
- psDroid->droidType, moveType, psDroid->player, acceptNearest);
+ psDroid->droidType, moveType, psDroid->player, acceptNearest, srcStructure, dstStructure);
}
// Run only from path thread
@@ -595,7 +627,7 @@ static int fpathResultQueueLength(void)
// Only used by fpathTest.
static FPATH_RETVAL fpathSimpleRoute(MOVE_CONTROL *psMove, int id, int startX, int startY, int tX, int tY)
{
- return fpathRoute(psMove, id, startX, startY, tX, tY, PROPULSION_TYPE_WHEELED, DROID_WEAPON, FMT_BLOCK, 0, true);
+ return fpathRoute(psMove, id, startX, startY, tX, tY, PROPULSION_TYPE_WHEELED, DROID_WEAPON, FMT_BLOCK, 0, true, NULL, NULL);
}
void fpathTest(int x, int y, int x2, int y2)
View
8 src/fpath.h
@@ -41,12 +41,20 @@ enum FPATH_MOVETYPE
struct PathBlockingMap;
+struct StructureTiles
+{
+ Vector2i map; ///< Map coordinates of upper left corner of structure.
+ Vector2i size; ///< Size (in map coordinates) of the structure.
+};
+
struct PATHJOB
{
PROPULSION_TYPE propulsion;
DROID_TYPE droidType;
int destX, destY;
int origX, origY;
+ StructureTiles srcStructure;
+ StructureTiles dstStructure;
UDWORD droidID;
FPATH_MOVETYPE moveType;
int owner; ///< Player owner
Please sign in to comment.
Something went wrong with that request. Please try again.