Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

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 authored December 12, 2011
42  src/astar.cpp
@@ -116,12 +116,30 @@ struct PathBlockingMap
116 116
 	std::vector<bool> dangerMap;	// using threatBits
117 117
 };
118 118
 
  119
+struct PathNonblockingArea
  120
+{
  121
+	PathNonblockingArea() {}
  122
+	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) {}
  123
+	bool operator ==(PathNonblockingArea const &z) const { return x1 == z.x1 && x2 == z.x2 && y1 == z.y1 && y2 == z.y2; }
  124
+	bool operator !=(PathNonblockingArea const &z) const { return !(*this == z); }
  125
+	bool isNonblocking(int x, int y) const
  126
+	{
  127
+		return x >= x1 && x < x2 && y >= y1 && y < y2;
  128
+	}
  129
+
  130
+	int16_t x1, x2, y1, y2;
  131
+};
  132
+
119 133
 // Data structures used for pathfinding, can contain cached results.
120 134
 struct PathfindContext
121 135
 {
122 136
 	PathfindContext() : myGameTime(0), iteration(0), blockingMap(NULL) {}
123 137
 	bool isBlocked(int x, int y) const
124 138
 	{
  139
+		if (srcIgnore.isNonblocking(x, y) || dstIgnore.isNonblocking(x, y))
  140
+		{
  141
+			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).
  142
+		}
125 143
 		// 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).
126 144
 		return x < 0 || y < 0 || x >= mapWidth || y >= mapHeight || blockingMap->map[x + y*mapWidth];
127 145
 	}
@@ -129,15 +147,17 @@ struct PathfindContext
129 147
 	{
130 148
 		return !blockingMap->dangerMap.empty() && blockingMap->dangerMap[x + y*mapWidth];
131 149
 	}
132  
-	bool matches(PathBlockingMap const *blockingMap_, PathCoord tileS_) const
  150
+	bool matches(PathBlockingMap const *blockingMap_, PathCoord tileS_, PathNonblockingArea srcIgnore_, PathNonblockingArea dstIgnore_) const
133 151
 	{
134  
-		// Must check myGameTime == blockingMap_->type.gameTime, otherwise blockingMap be a deleted pointer which coincidentally compares equal to the valid pointer blockingMap_.
135  
-		return myGameTime == blockingMap_->type.gameTime && blockingMap == blockingMap_ && tileS == tileS_;
  152
+		// Must check myGameTime == blockingMap_->type.gameTime, otherwise blockingMap could be a deleted pointer which coincidentally compares equal to the valid pointer blockingMap_.
  153
+		return myGameTime == blockingMap_->type.gameTime && blockingMap == blockingMap_ && tileS == tileS_ && srcIgnore == srcIgnore_ && dstIgnore == dstIgnore_;
136 154
 	}
137  
-	void assign(PathBlockingMap const *blockingMap_, PathCoord tileS_)
  155
+	void assign(PathBlockingMap const *blockingMap_, PathCoord tileS_, PathNonblockingArea srcIgnore_, PathNonblockingArea dstIgnore_)
138 156
 	{
139 157
 		blockingMap = blockingMap_;
140 158
 		tileS = tileS_;
  159
+		srcIgnore = srcIgnore_;
  160
+		dstIgnore = dstIgnore_;
141 161
 		myGameTime = blockingMap->type.gameTime;
142 162
 		nodes.clear();
143 163
 
@@ -164,6 +184,8 @@ struct PathfindContext
164 184
 	std::vector<PathNode> nodes;        ///< Edge of explored region of the map.
165 185
 	std::vector<PathExploredTile> map;  ///< Map, with paths leading back to tileS.
166 186
 	PathBlockingMap const *blockingMap; ///< Map of blocking tiles for the type of object which needs a path.
  187
+	PathNonblockingArea srcIgnore;      ///< Area of structure at source which should be considered nonblocking.
  188
+	PathNonblockingArea dstIgnore;      ///< Area of structure at destination which should be considered nonblocking.
167 189
 };
168 190
 
169 191
 /// Last recently used list of contexts.
@@ -344,9 +366,9 @@ static PathCoord fpathAStarExplore(PathfindContext &context, PathCoord tileF)
344 366
 	return nearestCoord;
345 367
 }
346 368
 
347  
-static void fpathInitContext(PathfindContext &context, PathBlockingMap const *blockingMap, PathCoord tileS, PathCoord tileRealS, PathCoord tileF)
  369
+static void fpathInitContext(PathfindContext &context, PathBlockingMap const *blockingMap, PathCoord tileS, PathCoord tileRealS, PathCoord tileF, PathNonblockingArea srcIgnore, PathNonblockingArea dstIgnore)
348 370
 {
349  
-	context.assign(blockingMap, tileS);
  371
+	context.assign(blockingMap, tileS, srcIgnore, dstIgnore);
350 372
 
351 373
 	// Add the start point to the open list
352 374
 	fpathNewNode(context, tileF, tileRealS, 0, tileRealS);
@@ -361,13 +383,15 @@ ASR_RETVAL fpathAStarRoute(MOVE_CONTROL *psMove, PATHJOB *psJob)
361 383
 
362 384
 	const PathCoord tileOrig(map_coord(psJob->origX), map_coord(psJob->origY));
363 385
 	const PathCoord tileDest(map_coord(psJob->destX), map_coord(psJob->destY));
  386
+	const PathNonblockingArea srcIgnore(psJob->srcStructure);
  387
+	const PathNonblockingArea dstIgnore(psJob->dstStructure);
364 388
 
365 389
 	PathCoord endCoord;  // Either nearest coord (mustReverse = true) or orig (mustReverse = false).
366 390
 
367 391
 	std::list<PathfindContext>::iterator contextIterator = fpathContexts.begin();
368 392
 	for (contextIterator = fpathContexts.begin(); contextIterator != fpathContexts.end(); ++contextIterator)
369 393
 	{
370  
-		if (!contextIterator->matches(psJob->blockingMap, tileDest))
  394
+		if (!contextIterator->matches(psJob->blockingMap, tileDest, srcIgnore, dstIgnore))
371 395
 		{
372 396
 			// This context is not for the same droid type and same destination.
373 397
 			continue;
@@ -410,7 +434,7 @@ ASR_RETVAL fpathAStarRoute(MOVE_CONTROL *psMove, PATHJOB *psJob)
410 434
 
411 435
 		// Init a new context, overwriting the oldest one if we are caching too many.
412 436
 		// We will be searching from orig to dest, since we don't know where the nearest reachable tile to dest is.
413  
-		fpathInitContext(*contextIterator, psJob->blockingMap, tileOrig, tileOrig, tileDest);
  437
+		fpathInitContext(*contextIterator, psJob->blockingMap, tileOrig, tileOrig, tileDest, srcIgnore, dstIgnore);
414 438
 		endCoord = fpathAStarExplore(*contextIterator, tileDest);
415 439
 		contextIterator->nearestCoord = endCoord;
416 440
 	}
@@ -492,7 +516,7 @@ ASR_RETVAL fpathAStarRoute(MOVE_CONTROL *psMove, PATHJOB *psJob)
492 516
 		if (!context.isBlocked(tileOrig.x, tileOrig.y))  // If blocked, searching from tileDest to tileOrig wouldn't find the tileOrig tile.
493 517
 		{
494 518
 			// Next time, search starting from nearest reachable tile to the destination.
495  
-			fpathInitContext(context, psJob->blockingMap, tileDest, context.nearestCoord, tileOrig);
  519
+			fpathInitContext(context, psJob->blockingMap, tileDest, context.nearestCoord, tileOrig, srcIgnore, dstIgnore);
496 520
 		}
497 521
 	}
498 522
 	else
42  src/fpath.cpp
@@ -350,9 +350,31 @@ void fpathRemoveDroidData(int id)
350 350
 	wzMutexUnlock(fpathMutex);
351 351
 }
352 352
 
  353
+static StructureTiles getTilesOfStructure(BASE_OBJECT *object)
  354
+{
  355
+	StructureTiles ret;
  356
+	ret.size = Vector2i(-65535, -65535);  // Default to an invalid area.
  357
+	ret.map = Vector2i(32767, 32767);
  358
+
  359
+	STRUCTURE *psStructure = castStructure(object);
  360
+	FEATURE *psFeature = castFeature(object);
  361
+
  362
+	if (psStructure != NULL)
  363
+	{
  364
+		ret.size = getStructureSize(psStructure);
  365
+		ret.map = map_coord(removeZ(psStructure->pos)) - ret.size/2;
  366
+	}
  367
+	else if (psFeature != NULL)
  368
+	{
  369
+		ret.size = Vector2i(psFeature->psStats->baseWidth, psFeature->psStats->baseBreadth);
  370
+		ret.map = map_coord(removeZ(psFeature->pos)) - ret.size/2;
  371
+	}
  372
+
  373
+	return ret;
  374
+}
353 375
 
354 376
 static FPATH_RETVAL fpathRoute(MOVE_CONTROL *psMove, int id, int startX, int startY, int tX, int tY, PROPULSION_TYPE propulsionType, 
355  
-                               DROID_TYPE droidType, FPATH_MOVETYPE moveType, int owner, bool acceptNearest)
  377
+                               DROID_TYPE droidType, FPATH_MOVETYPE moveType, int owner, bool acceptNearest, BASE_OBJECT *srcStructure, BASE_OBJECT *dstStructure)
356 378
 {
357 379
 	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);
358 380
 
@@ -424,6 +446,8 @@ static FPATH_RETVAL fpathRoute(MOVE_CONTROL *psMove, int id, int startX, int sta
424 446
 	job.droidID = id;
425 447
 	job.destX = tX;
426 448
 	job.destY = tY;
  449
+	job.srcStructure = getTilesOfStructure(srcStructure);
  450
+	job.dstStructure = getTilesOfStructure(dstStructure);
427 451
 	job.droidType = droidType;
428 452
 	job.propulsion = propulsionType;
429 453
 	job.moveType = moveType;
@@ -472,10 +496,18 @@ FPATH_RETVAL fpathDroidRoute(DROID* psDroid, SDWORD tX, SDWORD tY, FPATH_MOVETYP
472 496
 	// Check whether the start and end points of the route are blocking tiles and find an alternative if they are.
473 497
 	Position startPos = psDroid->pos;
474 498
 	Position endPos = Position(tX, tY, 0);
  499
+	BASE_OBJECT *srcStructure = worldTile(startPos)->psObject;
  500
+	BASE_OBJECT *dstStructure = worldTile(endPos)->psObject;
475 501
 	if (psDroid->sMove.Status != MOVEWAITROUTE)
476 502
 	{
477  
-		startPos = findNonblockingPosition(startPos, getPropulsionStats(psDroid)->propulsionType, psDroid->player, moveType);
478  
-		endPos   = findNonblockingPosition(endPos,   getPropulsionStats(psDroid)->propulsionType, psDroid->player, moveType);
  503
+		if (srcStructure == NULL)  // If there's a structure over the source, ignore it, otherwise pathfind from somewhere around the obstruction.
  504
+		{
  505
+			startPos = findNonblockingPosition(startPos, getPropulsionStats(psDroid)->propulsionType, psDroid->player, moveType);
  506
+		}
  507
+		if (dstStructure == NULL)  // If there's a structure over the destination, ignore it, otherwise pathfind from somewhere around the obstruction.
  508
+		{
  509
+			endPos   = findNonblockingPosition(endPos,   getPropulsionStats(psDroid)->propulsionType, psDroid->player, moveType);
  510
+		}
479 511
 		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));
480 512
 	}
481 513
 	switch (psDroid->order)
@@ -492,7 +524,7 @@ FPATH_RETVAL fpathDroidRoute(DROID* psDroid, SDWORD tX, SDWORD tY, FPATH_MOVETYP
492 524
 		break;
493 525
 	}
494 526
 	return fpathRoute(&psDroid->sMove, psDroid->id, startPos.x, startPos.y, endPos.x, endPos.y, psPropStats->propulsionType, 
495  
-	                  psDroid->droidType, moveType, psDroid->player, acceptNearest);
  527
+	                  psDroid->droidType, moveType, psDroid->player, acceptNearest, srcStructure, dstStructure);
496 528
 }
497 529
 
498 530
 // Run only from path thread
@@ -595,7 +627,7 @@ static int fpathResultQueueLength(void)
595 627
 // Only used by fpathTest.
596 628
 static FPATH_RETVAL fpathSimpleRoute(MOVE_CONTROL *psMove, int id, int startX, int startY, int tX, int tY)
597 629
 {
598  
-	return fpathRoute(psMove, id, startX, startY, tX, tY, PROPULSION_TYPE_WHEELED, DROID_WEAPON, FMT_BLOCK, 0, true);
  630
+	return fpathRoute(psMove, id, startX, startY, tX, tY, PROPULSION_TYPE_WHEELED, DROID_WEAPON, FMT_BLOCK, 0, true, NULL, NULL);
599 631
 }
600 632
 
601 633
 void fpathTest(int x, int y, int x2, int y2)
8  src/fpath.h
@@ -41,12 +41,20 @@ enum FPATH_MOVETYPE
41 41
 
42 42
 struct PathBlockingMap;
43 43
 
  44
+struct StructureTiles
  45
+{
  46
+	Vector2i map;           ///< Map coordinates of upper left corner of structure.
  47
+	Vector2i size;          ///< Size (in map coordinates) of the structure.
  48
+};
  49
+
44 50
 struct PATHJOB
45 51
 {
46 52
 	PROPULSION_TYPE	propulsion;
47 53
 	DROID_TYPE	droidType;
48 54
 	int		destX, destY;
49 55
 	int		origX, origY;
  56
+	StructureTiles  srcStructure;
  57
+	StructureTiles  dstStructure;
50 58
 	UDWORD		droidID;
51 59
 	FPATH_MOVETYPE	moveType;
52 60
 	int		owner;		///< Player owner

0 notes on commit 0119eda

Please sign in to comment.
Something went wrong with that request. Please try again.