Make AI ignore hostile structures for path-finding when using armed droids. This avoids a problem

getting to the enemy when the nearest point to the target is an impassable terrain obstacle. It
also avoids a pathological path-finding case that makes us search the entire map for a nearest 
point whenever we cannot go somewhere due to enemy structures (eg walls), which wastes a lot of 
CPU. Human players are unaffected by this change.


git-svn-id: https://warzone2100.svn.sourceforge.net/svnroot/warzone2100/trunk@7555 4a71c877-e1ca-e34f-864e-861f7616d084
master
Per Inge Mathisen 2009-05-26 18:55:12 +00:00 committed by Git SVN Gateway
parent f98926d94d
commit f1a946260e
4 changed files with 62 additions and 28 deletions

View File

@ -250,6 +250,8 @@ SDWORD aiBestNearestTarget(DROID *psDroid, BASE_OBJECT **ppsObj, int weapon_slot
}
else if (targetInQuestion->type == OBJ_STRUCTURE)
{
STRUCTURE *psStruct = (STRUCTURE *)targetInQuestion;
if (electronic)
{
/* don't want to target structures with resistance of zero if using electronic warfare */
@ -258,17 +260,13 @@ SDWORD aiBestNearestTarget(DROID *psDroid, BASE_OBJECT **ppsObj, int weapon_slot
psTarget = targetInQuestion;
}
}
else if (((STRUCTURE *)targetInQuestion)->asWeaps[weapon_slot].nStat > 0)
else if (psStruct->asWeaps[weapon_slot].nStat > 0)
{
// structure with weapons - go for this
psTarget = targetInQuestion;
}
else if ( ( ((STRUCTURE *)targetInQuestion)->pStructureType->type != REF_WALL
&&((STRUCTURE *)targetInQuestion)->pStructureType->type != REF_WALLCORNER
)
|| driveModeActive()
|| (bMultiPlayer && game.type == SKIRMISH && !isHumanPlayer(psDroid->player))
)
else if ((psStruct->pStructureType->type != REF_WALL && psStruct->pStructureType->type != REF_WALLCORNER)
|| driveModeActive() || (bMultiPlayer && !isHumanPlayer(psDroid->player)))
{
psTarget = targetInQuestion;
}

View File

@ -452,7 +452,7 @@ SDWORD fpathAStarRoute(MOVE_CONTROL *psMove, PATHJOB *psJob)
}
// If the tile hasn't been visited see if it is a blocking tile
if (!psFound && fpathBlockingTile(x, y, psJob->propulsion))
if (!psFound && fpathBaseBlockingTile(x, y, psJob->propulsion, psJob->owner, psJob->moveType))
{
// tile is blocked, skip it
continue;

View File

@ -35,7 +35,7 @@
#include "geometry.h"
#include "hci.h"
#include "order.h"
#include "multiplay.h"
#include "astar.h"
#include "action.h"
#include "formation.h"
@ -238,15 +238,12 @@ void fpathUpdate(void)
// Check if the map tile at a location blocks a droid
BOOL fpathBlockingTile(SDWORD x, SDWORD y, PROPULSION_TYPE propulsion)
BOOL fpathBaseBlockingTile(SDWORD x, SDWORD y, PROPULSION_TYPE propulsion, int player, FPATH_MOVETYPE moveType)
{
MAPTILE *psTile;
/* All tiles outside of the map and on map border are blocking. */
if (x < 1
|| y < 1
|| x > mapWidth - 1
|| y > mapHeight - 1)
if (x < 1 || y < 1 || x > mapWidth - 1 || y > mapHeight - 1)
{
return true;
}
@ -274,7 +271,22 @@ BOOL fpathBlockingTile(SDWORD x, SDWORD y, PROPULSION_TYPE propulsion)
return true;
}
if (psTile->tileInfoBits & BITS_FPATHBLOCK || (TileIsOccupied(psTile) && !TileIsNotBlocking(psTile))
if (TileIsOccupied(psTile) && !TileIsNotBlocking(psTile))
{
// If the type of movement order is simple movement (FMT_MOVE) then we treat all genuine obstacles as
// impassable. However, if it is an attack type order, we assume we can blast our way through enemy buildings.
if (moveType == FMT_MOVE)
{
return true;
}
else if (moveType == FMT_ATTACK
&& psTile->psObject->type == OBJ_STRUCTURE && aiCheckAlliances(psTile->psObject->player, player))
{
return true;
}
}
if (psTile->tileInfoBits & BITS_FPATHBLOCK
|| terrainType(psTile) == TER_CLIFFFACE
|| (terrainType(psTile) == TER_WATER && propulsion != PROPULSION_TYPE_HOVER && propulsion != PROPULSION_TYPE_PROPELLOR))
{
@ -284,6 +296,12 @@ BOOL fpathBlockingTile(SDWORD x, SDWORD y, PROPULSION_TYPE propulsion)
return false;
}
// Check if the map tile at a location blocks a droid
BOOL fpathBlockingTile(SDWORD x, SDWORD y, PROPULSION_TYPE propulsion)
{
return fpathBaseBlockingTile(x, y, propulsion, MAX_PLAYERS, FMT_MOVE);
}
/** Calculate the distance to a tile from a point
*
@ -384,11 +402,11 @@ void fpathRemoveDroidData(int id)
}
static FPATH_RETVAL fpathRoute(MOVE_CONTROL *psMove, int id, int startX, int startY, int tX, int tY, PROPULSION_TYPE propulsionType, DROID_TYPE droidType)
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)
{
PATHJOB *psJob = NULL;
objTrace(id, "called(,%d,%d,%d,%d,%d,,)", id, startX, startY, tX, tY);
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);
// don't have to do anything if already there
if (startX == tX && startY == tY)
@ -466,6 +484,8 @@ static FPATH_RETVAL fpathRoute(MOVE_CONTROL *psMove, int id, int startX, int sta
psJob->next = NULL;
psJob->droidType = droidType;
psJob->propulsion = propulsionType;
psJob->moveType = moveType;
psJob->owner = owner;
// Clear any results or jobs waiting already. It is a vital assumption that there is only one
// job or result for each droid in the system at any time.
@ -501,13 +521,16 @@ static FPATH_RETVAL fpathRoute(MOVE_CONTROL *psMove, int id, int startX, int sta
FPATH_RETVAL fpathDroidRoute(DROID* psDroid, SDWORD tX, SDWORD tY)
{
PROPULSION_STATS *psPropStats = asPropulsionStats + psDroid->asBits[COMP_PROPULSION].nStat;
FPATH_MOVETYPE moveType = isHumanPlayer(psDroid->player) ? FMT_MOVE : FMT_ATTACK;
ASSERT(psPropStats != NULL, "invalid propulsion stats pointer");
ASSERT(psDroid->type == OBJ_DROID, "We got passed an object that isn't a DROID!");
if (psDroid->type != OBJ_DROID || !psPropStats)
ASSERT_OR_RETURN(FPR_FAILED, psPropStats != NULL, "invalid propulsion stats pointer");
ASSERT_OR_RETURN(FPR_FAILED, psDroid->type == OBJ_DROID, "We got passed an object that isn't a DROID!");
if (psDroid->asWeaps[0].nStat == 0)
{
return FPR_FAILED;
moveType = FMT_MOVE; // cannot blast its way through walls, so don't even try
}
// check whether the end point of the route
// is a blocking tile and find an alternative if it is
if (psDroid->sMove.Status != MOVEWAITROUTE && fpathBlockingTile(map_coord(tX), map_coord(tY), psPropStats->propulsionType))
@ -554,7 +577,7 @@ FPATH_RETVAL fpathDroidRoute(DROID* psDroid, SDWORD tX, SDWORD tY)
objTrace(psDroid->id, "Workaround found at (%d, %d)", map_coord(tX), map_coord(tY));
}
}
return fpathRoute(&psDroid->sMove, psDroid->id, psDroid->pos.x, psDroid->pos.y, tX, tY, psPropStats->propulsionType, psDroid->droidType);
return fpathRoute(&psDroid->sMove, psDroid->id, psDroid->pos.x, psDroid->pos.y, tX, tY, psPropStats->propulsionType, psDroid->droidType, moveType, psDroid->player);
}
// Run only from path thread
@ -590,6 +613,10 @@ static void fpathExecute(PATHJOB *psJob, PATHRESULT *psResult)
}
}
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_MOVE, 0);
}
void fpathTest(int x, int y, int x2, int y2)
{
@ -617,7 +644,7 @@ void fpathTest(int x, int y, int x2, int y2)
/* Test one path */
sMove.Status = MOVEINACTIVE;
r = fpathRoute(&sMove, 1, x, y, x2, y2, PROPULSION_TYPE_WHEELED, DROID_WEAPON);
r = fpathSimpleRoute(&sMove, 1, x, y, x2, y2);
assert(r == FPR_WAIT);
sMove.Status = MOVEWAITROUTE;
assert(fpathJobQueueLength() == 1 || fpathResultQueueLength() == 1);
@ -626,7 +653,7 @@ void fpathTest(int x, int y, int x2, int y2)
while (fpathResultQueueLength() == 0) SDL_Delay(10);
assert(fpathJobQueueLength() == 0);
assert(fpathResultQueueLength() == 1);
r = fpathRoute(&sMove, 1, x, y, x2, y2, PROPULSION_TYPE_WHEELED, DROID_WEAPON);
r = fpathSimpleRoute(&sMove, 1, x, y, x2, y2);
assert(r == FPR_OK);
assert(sMove.numPoints > 0 && sMove.asPath);
assert(sMove.asPath[sMove.numPoints - 1].x == map_coord(x2));
@ -637,7 +664,7 @@ void fpathTest(int x, int y, int x2, int y2)
sMove.Status = MOVEINACTIVE;
for (i = 1; i <= 100; i++)
{
r = fpathRoute(&sMove, i, x, y, x2, y2, PROPULSION_TYPE_WHEELED, DROID_WEAPON);
r = fpathSimpleRoute(&sMove, i, x, y, x2, y2);
assert(r == FPR_WAIT);
}
while (fpathResultQueueLength() != 100) SDL_Delay(10);
@ -645,7 +672,7 @@ void fpathTest(int x, int y, int x2, int y2)
for (i = 1; i <= 100; i++)
{
sMove.Status = MOVEWAITROUTE;
r = fpathRoute(&sMove, i, x, y, x2, y2, PROPULSION_TYPE_WHEELED, DROID_WEAPON);
r = fpathSimpleRoute(&sMove, i, x, y, x2, y2);
assert(r == FPR_OK);
assert(sMove.numPoints > 0 && sMove.asPath);
assert(sMove.asPath[sMove.numPoints - 1].x == map_coord(x2));
@ -657,7 +684,7 @@ void fpathTest(int x, int y, int x2, int y2)
sMove.Status = MOVEINACTIVE;
for (i = 1; i <= 100; i++)
{
r = fpathRoute(&sMove, i, x, y, x2, y2, PROPULSION_TYPE_WHEELED, DROID_WEAPON);
r = fpathSimpleRoute(&sMove, i, x, y, x2, y2);
assert(r == FPR_WAIT);
}
for (i = 1; i <= 100; i++)

View File

@ -32,6 +32,12 @@
* @{
*/
typedef enum _fpath_movetype
{
FMT_MOVE, ///< Move around all obstacles
FMT_ATTACK, ///< Assume that we will destroy enemy obstacles
} FPATH_MOVETYPE;
typedef struct _jobNode
{
PROPULSION_TYPE propulsion;
@ -40,6 +46,8 @@ typedef struct _jobNode
int origX, origY;
UDWORD droidID;
struct _jobNode *next;
FPATH_MOVETYPE moveType;
int owner; ///< Player owner
} PATHJOB;
typedef enum _fpath_retval
@ -70,7 +78,8 @@ extern FPATH_RETVAL fpathDroidRoute(DROID* psDroid, SDWORD targetX, SDWORD targe
*
* @return true if the given tile is blocking for this droid
*/
extern BOOL fpathBlockingTile(SDWORD x, SDWORD y, PROPULSION_TYPE propulsion);
BOOL fpathBlockingTile(SDWORD x, SDWORD y, PROPULSION_TYPE propulsion);
BOOL fpathBaseBlockingTile(SDWORD x, SDWORD y, PROPULSION_TYPE propulsion, int player, FPATH_MOVETYPE moveType);
/** Set a direct path to position.
*