Adjustment of pathfinders to give better performance
This commit is contained in:
parent
5a4a0714c7
commit
4edf25bf33
7 changed files with 175 additions and 244 deletions
|
@ -31,6 +31,7 @@
|
|||
<li>Future 1.19 Release<p>
|
||||
<ul>
|
||||
<li>+++
|
||||
<li>Adjustment of pathfinders to give better performance (from Russell Smith).
|
||||
<li>Added caching of complex paths (from Russell Smith).
|
||||
<li>Added a status bar for peasants chopping wood (from Jimmy Salmon).
|
||||
<li>Fixed Bug #731439: crashes on the attached pud, changing race (from Russell Smith).
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
//
|
||||
/**@name action_move.c - The move action. */
|
||||
//
|
||||
// (c) Copyright 1998,2001,2002 by Lutz Sammer
|
||||
// (c) Copyright 1998,2001,2002,2003 by Lutz Sammer
|
||||
//
|
||||
// FreeCraft is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published
|
||||
|
@ -48,12 +48,6 @@
|
|||
-- Variables
|
||||
----------------------------------------------------------------------------*/
|
||||
|
||||
//
|
||||
// Convert heading into direction.
|
||||
// // N NE E SE S SW W NW
|
||||
local const int Heading2X[8] = { 0,+1,+1,+1, 0,-1,-1,-1 };
|
||||
local const int Heading2Y[8] = { -1,-1, 0,+1,+1,+1, 0,-1 };
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
-- Function
|
||||
----------------------------------------------------------------------------*/
|
||||
|
@ -285,10 +279,6 @@ global void HandleActionMove(Unit* unit)
|
|||
//
|
||||
// FIXME: should use a reachable place to reduce pathfinder time.
|
||||
//
|
||||
IfDebug(
|
||||
if( !PlaceReachable(unit,unit->Orders[0].X,unit->Orders[0].Y,1) ) {
|
||||
DebugLevel0Fn("FIXME: should use other goal.\n");
|
||||
});
|
||||
DebugCheck( unit->State!=0 );
|
||||
}
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
//
|
||||
/**@name pathfinder.h - The path finder headerfile. */
|
||||
//
|
||||
// (c) Copyright 1998-2001 by Lutz Sammer
|
||||
// (c) Copyright 1998-2003 by Lutz Sammer,Russell Smith
|
||||
//
|
||||
// FreeCraft is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published
|
||||
|
@ -47,6 +47,9 @@
|
|||
** stop others how far to goal.
|
||||
*/
|
||||
enum _move_return_ {
|
||||
MUST_REACH_GOAL=-4,
|
||||
BEST_GOAL=-5,
|
||||
PF_FAILED=-3, /// This Pathfinder failed, try another
|
||||
PF_UNREACHABLE=-2, /// Unreachable stop
|
||||
PF_REACHED=-1, /// Reached goal stop
|
||||
PF_WAIT=0, /// Wait, no time or blocked
|
||||
|
@ -72,6 +75,13 @@ extern int AStarFixedUnitCrossingCost;
|
|||
/// cost associated to move on a tile occupied by a moving unit
|
||||
extern int AStarMovingUnitCrossingCost;
|
||||
|
||||
//
|
||||
// Convert heading into direction.
|
||||
// // N NE E SE S SW W NW
|
||||
extern const int Heading2X[8];
|
||||
extern const int Heading2Y[8];
|
||||
extern const int XY2Heading[3][3];
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
-- Functions
|
||||
----------------------------------------------------------------------------*/
|
||||
|
@ -81,11 +91,11 @@ extern unsigned char* CreateMatrix(void);
|
|||
/// Allocate a new matrix and initialize
|
||||
extern unsigned char* MakeMatrix(void);
|
||||
/// Get next element of the way to goal.
|
||||
extern int NewPath(Unit* unit,int* xdp,int* ydp);
|
||||
extern int NewPath(Unit* unit);
|
||||
/// Return distance to place.
|
||||
extern int PlaceReachable(const Unit* unit,int x,int y,int range);
|
||||
extern int PlaceReachable(Unit* unit,int x,int y,int range);
|
||||
/// Return distance to unit.
|
||||
extern int UnitReachable(const Unit* unit,const Unit* dest,int range);
|
||||
extern int UnitReachable(Unit* unit,const Unit* dest,int range);
|
||||
|
||||
//
|
||||
// in astar.c
|
||||
|
@ -99,6 +109,8 @@ extern void InitAStar(void);
|
|||
/// free the a* data structures
|
||||
extern void FreeAStar(void);
|
||||
|
||||
/// Find and a* path for a unit
|
||||
extern int AStarFindPath(Unit* unit, int x1, int y1, int x2, int y2, int best,char* path);
|
||||
//
|
||||
// in ccl_pathfinder.c
|
||||
//
|
||||
|
|
|
@ -968,11 +968,11 @@ extern Unit* OilDepositOnMap(int tx,int ty);
|
|||
extern Unit* WoodDepositOnMap(int tx,int ty);
|
||||
|
||||
/// Find best enemy in numeric range to attack
|
||||
extern Unit* AttackUnitsInDistance(const Unit* unit,int range);
|
||||
extern Unit* AttackUnitsInDistance(Unit* unit,int range);
|
||||
/// Find best enemy in attack range to attack
|
||||
extern Unit* AttackUnitsInRange(const Unit* unit);
|
||||
extern Unit* AttackUnitsInRange(Unit* unit);
|
||||
/// Find best enemy in reaction range to attack
|
||||
extern Unit* AttackUnitsInReactRange(const Unit* unit);
|
||||
extern Unit* AttackUnitsInReactRange(Unit* unit);
|
||||
|
||||
// in groups.c
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
//
|
||||
/**@name astar.c - The a* path finder routines. */
|
||||
//
|
||||
// (c) Copyright 1999-2001 by Lutz Sammer and Fabrice Rossi
|
||||
// (c) Copyright 1999-2003 by Lutz Sammer,Fabrice Rossi, Russell Smith
|
||||
//
|
||||
// FreeCraft is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published
|
||||
|
@ -63,6 +63,11 @@ typedef struct _open_ {
|
|||
-- Variables
|
||||
----------------------------------------------------------------------------*/
|
||||
|
||||
// Convert heading into direction.
|
||||
// // N NE E SE S SW W NW
|
||||
global const int Heading2X[8] = { 0,+1,+1,+1, 0,-1,-1,-1 };
|
||||
global const int Heading2Y[8] = { -1,-1, 0,+1,+1,+1, 0,-1 };
|
||||
global const int XY2Heading[3][3] = { {7,6,5},{0,0,4},{1,2,3}};
|
||||
/// cost matrix
|
||||
local Node *AStarMatrix;
|
||||
/// a list of close nodes, helps to speed up the matrix cleaning
|
||||
|
@ -185,8 +190,9 @@ local void AStarRemoveMinimum(int pos)
|
|||
|
||||
/**
|
||||
** Add a new node to the open set (and update the heap structure)
|
||||
** Returns Pathfinder failed
|
||||
*/
|
||||
local void AStarAddNode(int x,int y,int o,int costs)
|
||||
local int AStarAddNode(int x,int y,int o,int costs)
|
||||
{
|
||||
int i=OpenSetSize;
|
||||
int j;
|
||||
|
@ -195,7 +201,7 @@ local void AStarAddNode(int x,int y,int o,int costs)
|
|||
if(OpenSetSize>=OpenSetMaxSize) {
|
||||
fprintf(stderr, "A* internal error: raise Open Set Max Size "
|
||||
"(current value %d)\n",OpenSetMaxSize);
|
||||
Exit(-1);
|
||||
return PF_FAILED;
|
||||
}
|
||||
OpenSet[i].X=x;
|
||||
OpenSet[i].Y=y;
|
||||
|
@ -213,6 +219,8 @@ local void AStarAddNode(int x,int y,int o,int costs)
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -298,7 +306,7 @@ local int CostMoveTo(int ex,int ey,int mask,int current_cost) {
|
|||
/**
|
||||
** Find path.
|
||||
*/
|
||||
local int AStarFindPath(Unit* unit,int* pxd,int* pyd)
|
||||
global int AStarFindPath(Unit* unit, int x1, int y1, int x2, int y2, int best,char* path)
|
||||
{
|
||||
int i,j;
|
||||
int o;
|
||||
|
@ -306,64 +314,42 @@ local int AStarFindPath(Unit* unit,int* pxd,int* pyd)
|
|||
int y;
|
||||
int ex;
|
||||
int ey;
|
||||
int dx,dy;
|
||||
int eo,gx,gy,cx,cy,sx;
|
||||
int eo,gx,gy;
|
||||
int best_x,best_y,best_cost_to_goal,best_cost_from_start;
|
||||
int r;
|
||||
int shortest;
|
||||
int counter;
|
||||
int new_cost;
|
||||
int cost_to_goal;
|
||||
//int last_dir;
|
||||
int path_length;
|
||||
int num_in_close=0;
|
||||
int mask=UnitMovementMask(unit);
|
||||
int goal_reachable;
|
||||
//int base_mask=mask&~(MapFieldLandUnit|MapFieldAirUnit|MapFieldSeaUnit);
|
||||
Unit* goal;
|
||||
static int xoffset[]={ 0,-1,+1, 0, -1,+1,-1,+1 };
|
||||
static int yoffset[]={ -1, 0, 0,+1, -1,-1,+1,+1 };
|
||||
|
||||
DebugLevel3Fn("%d %d,%d->%d,%d\n" _C_
|
||||
UnitNumber(unit) _C_
|
||||
unit->X _C_ unit->Y _C_ unit->Orders[0].X _C_ unit->Orders[0].Y);
|
||||
|
||||
OpenSetSize=0;
|
||||
/* AStarPrepare();*/
|
||||
x=unit->X;
|
||||
y=unit->Y;
|
||||
goal_reachable=0;
|
||||
r=unit->Orders[0].RangeX;
|
||||
goal=unit->Orders[0].Goal;
|
||||
|
||||
// Let's first mark goal
|
||||
if(goal) {
|
||||
cx=goal->X;
|
||||
cy=goal->Y;
|
||||
ey=goal->Type->TileHeight+r-1;
|
||||
sx=goal->Type->TileWidth+r-1;
|
||||
// approximate goal for A*
|
||||
gx=goal->X+goal->Type->TileHeight/2;
|
||||
gy=goal->Y+goal->Type->TileWidth/2;
|
||||
} else {
|
||||
cx=gx=unit->Orders[0].X;
|
||||
cy=gy=unit->Orders[0].Y;
|
||||
ey=r;
|
||||
sx=r;
|
||||
r=0;
|
||||
}
|
||||
for(;ey>=-r;ey--){
|
||||
dy=cy+ey;
|
||||
if( dy<0 || dy>=TheMap.Height ) {
|
||||
continue;
|
||||
gx=(x1+x2)/2;
|
||||
gy=(y1+y2)/2;
|
||||
|
||||
// Mark Goal in Matrix
|
||||
for(ey=y1;ey<=y2;ey++){
|
||||
if( ey<0 || ey>=TheMap.Height ) {
|
||||
break;
|
||||
}
|
||||
for(ex=sx;ex>=-r;ex--) {
|
||||
dx=cx+ex;
|
||||
if( dx<0 || dx>=TheMap.Width ) {
|
||||
for(ex=x1;ex<=x2;ex++) {
|
||||
if( ex<0 || ex>=TheMap.Width ) {
|
||||
continue;
|
||||
}
|
||||
if(CostMoveTo(dx,dy,mask,AStarFixedUnitCrossingCost)>=0) {
|
||||
eo=dx*TheMap.Width+dy;
|
||||
if(CostMoveTo(ex,ey,mask,AStarFixedUnitCrossingCost)>=0) {
|
||||
eo=ex*TheMap.Width+ey;
|
||||
AStarMatrix[eo].InGoal=1;
|
||||
if(num_in_close<Threshold) {
|
||||
CloseSet[num_in_close++]=eo;
|
||||
|
@ -372,9 +358,12 @@ local int AStarFindPath(Unit* unit,int* pxd,int* pyd)
|
|||
}
|
||||
}
|
||||
}
|
||||
// the following test is removed, we path find even if the goal is not
|
||||
// directly reachable.
|
||||
// if(goal_reachable) {
|
||||
// if goal is not directory reachable, and we require that, punch out
|
||||
if( !goal_reachable && best==MUST_REACH_GOAL) {
|
||||
AStarCleanUp(num_in_close);
|
||||
return PF_UNREACHABLE;
|
||||
}
|
||||
|
||||
eo=x*TheMap.Width+y;
|
||||
// it is quite important to start from 1 rather than 0, because we use
|
||||
// 0 as a way to represent nodes that we have not visited yet.
|
||||
|
@ -383,8 +372,12 @@ local int AStarFindPath(Unit* unit,int* pxd,int* pyd)
|
|||
best_cost_to_goal=AStarCosts(x,y,gx,gy);
|
||||
best_x=x;
|
||||
best_y=y;
|
||||
// place start point in open
|
||||
AStarAddNode(x,y,eo,best_cost_to_goal+1);
|
||||
|
||||
// place start point in open, it that failed, try another pathfinder
|
||||
if( AStarAddNode(x,y,eo,best_cost_to_goal+1) == PF_FAILED ) {
|
||||
AStarCleanUp(num_in_close);
|
||||
return PF_FAILED;
|
||||
}
|
||||
if(num_in_close<Threshold) {
|
||||
CloseSet[num_in_close++]=OpenSet[0].O;
|
||||
}
|
||||
|
@ -393,7 +386,7 @@ local int AStarFindPath(Unit* unit,int* pxd,int* pyd)
|
|||
// return -2;
|
||||
// }
|
||||
|
||||
counter=TheMap.Width*TheMap.Height; // how many tries
|
||||
counter=TheMap.Width*TheMap.Height;
|
||||
|
||||
for( ;; ) {
|
||||
//
|
||||
|
@ -442,8 +435,8 @@ local int AStarFindPath(Unit* unit,int* pxd,int* pyd)
|
|||
// Generate successors of this node.
|
||||
//
|
||||
for( i=0; i<8; ++i ) {
|
||||
ex=x+xoffset[i];
|
||||
ey=y+yoffset[i];
|
||||
ex=x+Heading2X[i];
|
||||
ey=y+Heading2Y[i];
|
||||
|
||||
//
|
||||
// Outside the map or can't be entered.
|
||||
|
@ -468,8 +461,10 @@ local int AStarFindPath(Unit* unit,int* pxd,int* pyd)
|
|||
// we are sure the current node has not been already visited
|
||||
AStarMatrix[eo].CostFromStart=new_cost;
|
||||
AStarMatrix[eo].Direction=i;
|
||||
AStarAddNode(ex,ey,eo,
|
||||
AStarMatrix[eo].CostFromStart+AStarCosts(ex,ey,gx,gy));
|
||||
if( AStarAddNode(ex,ey,eo,AStarMatrix[eo].CostFromStart+AStarCosts(ex,ey,gx,gy) == PF_FAILED) ) {
|
||||
AStarCleanUp(num_in_close);
|
||||
return PF_FAILED;
|
||||
}
|
||||
// we add the point to the close set
|
||||
if(num_in_close<Threshold) {
|
||||
CloseSet[num_in_close++]=eo;
|
||||
|
@ -482,9 +477,12 @@ local int AStarFindPath(Unit* unit,int* pxd,int* pyd)
|
|||
// this point might be already in the OpenSet
|
||||
j=AStarFindNode(eo);
|
||||
if(j==-1) {
|
||||
AStarAddNode(ex,ey,eo,
|
||||
if( AStarAddNode(ex,ey,eo,
|
||||
AStarMatrix[eo].CostFromStart+
|
||||
AStarCosts(ex,ey,gx,gy));
|
||||
AStarCosts(ex,ey,gx,gy)) == PF_FAILED ) {
|
||||
AStarCleanUp(num_in_close);
|
||||
return PF_FAILED;
|
||||
}
|
||||
} else {
|
||||
AStarReplaceNode(j,AStarMatrix[eo].CostFromStart+
|
||||
AStarCosts(ex,ey,gx,gy));
|
||||
|
@ -499,121 +497,68 @@ local int AStarFindPath(Unit* unit,int* pxd,int* pyd)
|
|||
if(ex==unit->X && ey==unit->Y) {
|
||||
DebugLevel3Fn("%d unreachable\n" _C_ UnitNumber(unit));
|
||||
AStarCleanUp(num_in_close);
|
||||
return -2;
|
||||
return PF_UNREACHABLE;
|
||||
}
|
||||
DebugLevel3Fn("%d unreachable: going to closest\n" _C_ UnitNumber(unit));
|
||||
break;
|
||||
}
|
||||
}
|
||||
// if the goal was not reachable, we replace it by the best point
|
||||
// this will speed up next path finding
|
||||
if(!goal_reachable) {
|
||||
unit->Orders[0].Goal=0;
|
||||
unit->Orders[0].X=ex;
|
||||
unit->Orders[0].Y=ey;
|
||||
NewResetPath(unit);
|
||||
}
|
||||
// now we need to backtrack
|
||||
// FIXME: PATH caching goes here.
|
||||
path_length=0;
|
||||
x=unit->X;
|
||||
y=unit->Y;
|
||||
gx=ex;
|
||||
gy=ey;
|
||||
i=0;
|
||||
while(ex!=x||ey!=y) {
|
||||
DebugLevel3("%d %d %d %d\n" _C_ x _C_ y _C_ ex _C_ ey);
|
||||
eo=ex*TheMap.Width+ey;
|
||||
i=AStarMatrix[eo].Direction;
|
||||
ex-=xoffset[i];
|
||||
ey-=yoffset[i];
|
||||
ex-=Heading2X[i];
|
||||
ey-=Heading2Y[i];
|
||||
path_length++;
|
||||
}
|
||||
*pxd=xoffset[i];
|
||||
*pyd=yoffset[i];
|
||||
j=CostMoveTo(ex+*pxd,ey+*pyd,mask,0);
|
||||
ex=gx;
|
||||
ey=gy;
|
||||
gy=path_length;
|
||||
gx=path_length;
|
||||
if( gy > MAX_PATH_LENGTH ) {
|
||||
gy = MAX_PATH_LENGTH;
|
||||
}
|
||||
|
||||
while(ex!=x||ey!=y) {
|
||||
eo=ex*TheMap.Width+ey;
|
||||
i=AStarMatrix[eo].Direction;
|
||||
DebugLevel3("%d %d %d %d (%d,%d)\n" _C_ x _C_ y _C_ ex _C_ ey _C_ Heading2X[i] _C_ Heading2Y[i]);
|
||||
ex-=Heading2X[i];
|
||||
ey-=Heading2Y[i];
|
||||
gx--;
|
||||
if( gx<MAX_PATH_LENGTH && path != NULL) {
|
||||
path[gy-gx-1]=i;
|
||||
}
|
||||
}
|
||||
|
||||
j=CostMoveTo(ex+Heading2X[i],ey+Heading2Y[i],mask,0);
|
||||
if(j!=0) {
|
||||
if(j==AStarMovingUnitCrossingCost) {
|
||||
// we should wait, we are blocked by a moving unit
|
||||
//FIXME: this might lead to a deadlock, or something similar
|
||||
DebugLevel3("Unit %d waiting. Proposed move: %d %d\n" _C_
|
||||
UnitNumber(unit) _C_ *pxd _C_ *pyd);
|
||||
path_length=0;
|
||||
path_length=PF_WAIT;
|
||||
} else {
|
||||
// j==-1 is a bug, so we should have only
|
||||
// j==AStarFixedUnitCrossingCost, which means
|
||||
// the way is blocked by a non moving unit. Waiting is here
|
||||
// pointless.
|
||||
path_length=-2;
|
||||
path_length=PF_UNREACHABLE;
|
||||
}
|
||||
}
|
||||
// let's clean up the matrix now
|
||||
AStarCleanUp(num_in_close);
|
||||
DebugLevel3Fn("%d\n" _C_ UnitNumber(unit));
|
||||
DebugLevel3Fn("proposed move: %d %d (%d)\n" _C_ *pxd _C_ *pyd _C_ path_length);
|
||||
return path_length;
|
||||
}
|
||||
|
||||
/**
|
||||
** Returns the next element of a path with astar algo.
|
||||
**
|
||||
** @param unit Unit that wants the path element.
|
||||
** @param pxd Pointer for the x direction.
|
||||
** @param pyd Pointer for the y direction.
|
||||
**
|
||||
** @return >0 remaining path length, 0 wait for path, -1
|
||||
** reached goal, -2 can't reach the goal.
|
||||
*/
|
||||
global int AStarNextPathElement(Unit* unit,int* pxd,int *pyd)
|
||||
{
|
||||
// FIXME: Cache for often used pathes, like peons to goldmine.
|
||||
// FIXME: (fabrice) I've copied here the code from NewPath. Is it really
|
||||
// needed?
|
||||
int x;
|
||||
int y;
|
||||
int r;
|
||||
Unit* goal;
|
||||
UnitType* type;
|
||||
|
||||
DebugCheck( unit->Orders[0].RangeX!=unit->Orders[0].RangeY );
|
||||
|
||||
r=unit->Orders[0].RangeX;
|
||||
goal=unit->Orders[0].Goal;
|
||||
x=unit->X;
|
||||
y=unit->Y;
|
||||
if( goal ) { // goal unit
|
||||
type=goal->Type;
|
||||
DebugLevel3Fn("Unit %d,%d Goal %d,%d - %d,%d\n"
|
||||
_C_ x _C_ y
|
||||
_C_ goal->X-r _C_ goal->Y-r
|
||||
_C_ goal->X+type->TileWidth+r
|
||||
_C_ goal->Y+type->TileHeight+r);
|
||||
if( x>=goal->X-r && x<goal->X+type->TileWidth+r
|
||||
&& y>=goal->Y-r && y<goal->Y+type->TileHeight+r ) {
|
||||
DebugLevel3Fn("Goal reached\n");
|
||||
*pxd=*pyd=0;
|
||||
return -1;
|
||||
}
|
||||
} else { // goal map field
|
||||
if( x>=unit->Orders[0].X && x<=unit->Orders[0].X+r
|
||||
&& y>=unit->Orders[0].Y && y<=unit->Orders[0].Y+r ) {
|
||||
DebugLevel3Fn("Field reached\n");
|
||||
*pxd=*pyd=0;
|
||||
return -1;
|
||||
}
|
||||
// This reduces the processor use,
|
||||
// If target isn't reachable and were beside it
|
||||
if( r==0 && x>=unit->Orders[0].X-1 && x<=unit->Orders[0].X+1
|
||||
&& y>=unit->Orders[0].Y-1 && y<=unit->Orders[0].Y+1 ) {
|
||||
if( !CheckedCanMoveToMask(unit->Orders[0].X,unit->Orders[0].Y
|
||||
,UnitMovementMask(unit)) ) { // blocked
|
||||
DebugLevel3Fn("Field unreached\n");
|
||||
*pxd=*pyd=0;
|
||||
return -2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return AStarFindPath(unit,pxd,pyd);
|
||||
}
|
||||
|
||||
/**
|
||||
** Returns the next element of a path.
|
||||
**
|
||||
|
@ -630,12 +575,6 @@ global int NextPathElement(Unit* unit,int* pxd,int *pyd)
|
|||
static int UnreachableCounter;
|
||||
int result;
|
||||
|
||||
//
|
||||
// Convert heading into direction.
|
||||
// // N NE E SE S SW W NW
|
||||
local const int Heading2X[8] = { 0,+1,+1,+1, 0,-1,-1,-1 };
|
||||
local const int Heading2Y[8] = { -1,-1, 0,+1,+1,+1, 0,-1 };
|
||||
|
||||
|
||||
//
|
||||
// Reduce the load, stop handling pathes if too many UNREACHABLE results.
|
||||
|
@ -646,29 +585,34 @@ global int NextPathElement(Unit* unit,int* pxd,int *pyd)
|
|||
}
|
||||
// FIXME: Can use the time left in frame.
|
||||
if( !UnreachableCounter ) {
|
||||
DebugLevel0Fn("Done too much %d.\n" _C_ UnitNumber(unit));
|
||||
DebugLevel0Fn("Done too much, can't do path for %d.\n" _C_ UnitNumber(unit));
|
||||
return PF_WAIT;
|
||||
}
|
||||
|
||||
// Convert old version to new version
|
||||
if(AStarOn) {
|
||||
result=AStarNextPathElement(unit,pxd,pyd);
|
||||
} else {
|
||||
// Attempt to use path cache
|
||||
if( unit->Data.Move.Length > 0 ) {
|
||||
*pxd = Heading2X[(int)unit->Data.Move.Path[(int)unit->Data.Move.Length-1]];
|
||||
*pyd = Heading2Y[(int)unit->Data.Move.Path[(int)unit->Data.Move.Length-1]];
|
||||
result = unit->Data.Move.Length;
|
||||
unit->Data.Move.Length--;
|
||||
if( !CheckedCanMoveToMask(*pxd+unit->X,*pyd+unit->Y,UnitMovementMask(unit)) ) {
|
||||
result=NewPath(unit,pxd,pyd);
|
||||
}
|
||||
} else {
|
||||
result=NewPath(unit,pxd,pyd);
|
||||
// Attempt to use path cache
|
||||
// FIXME: If there is a goal, it may have moved, ruining the cache
|
||||
|
||||
if( unit->Data.Move.Length <= 0 ) {
|
||||
result = NewPath(unit);
|
||||
if( result==PF_UNREACHABLE ) {
|
||||
unit->Data.Move.Length = 0;
|
||||
--UnreachableCounter;
|
||||
return result;
|
||||
}
|
||||
if( result==PF_REACHED ) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
if( result==PF_UNREACHABLE ) {
|
||||
--UnreachableCounter;
|
||||
*pxd = Heading2X[(int)unit->Data.Move.Path[(int)unit->Data.Move.Length-1]];
|
||||
*pyd = Heading2Y[(int)unit->Data.Move.Path[(int)unit->Data.Move.Length-1]];
|
||||
result = unit->Data.Move.Length;
|
||||
unit->Data.Move.Length--;
|
||||
if( !CheckedCanMoveToMask(*pxd+unit->X,*pyd+unit->Y,UnitMovementMask(unit)) ) {
|
||||
result=NewPath(unit);
|
||||
*pxd = Heading2X[(int)unit->Data.Move.Path[(int)unit->Data.Move.Length-1]];
|
||||
*pyd = Heading2Y[(int)unit->Data.Move.Path[(int)unit->Data.Move.Length-1]];
|
||||
result = unit->Data.Move.Length;
|
||||
unit->Data.Move.Length--;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
//
|
||||
// I use breadth-first.
|
||||
//
|
||||
// (c) Copyright 1998,2000-2002 by Lutz Sammer
|
||||
// (c) Copyright 1998,2000-2003 by Lutz Sammer,Russell Smith
|
||||
//
|
||||
// FreeCraft is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published
|
||||
|
@ -76,6 +76,7 @@ global unsigned PfCounterDepth;
|
|||
global unsigned PfCounterNotReachable;
|
||||
);
|
||||
|
||||
local int ComplexNewPath(Unit* unit,int gx,int gy,int ox,int oy,int type,char* path);
|
||||
/*----------------------------------------------------------------------------
|
||||
-- Functions
|
||||
----------------------------------------------------------------------------*/
|
||||
|
@ -341,23 +342,18 @@ local int MarkPathInMatrix(const Unit* unit,unsigned char* matrix)
|
|||
**
|
||||
** @return Distance to place.
|
||||
*/
|
||||
global int PlaceReachable(const Unit* src,int x,int y,int range)
|
||||
global int PlaceReachable(Unit* src,int x,int y,int range)
|
||||
{
|
||||
unsigned char* matrix;
|
||||
int depth;
|
||||
|
||||
DebugLevel3Fn("%p -> %d,%d\n" _C_ src _C_ x _C_ y);
|
||||
|
||||
//
|
||||
// Setup movement.
|
||||
//
|
||||
matrix=CreateMatrix();
|
||||
MarkPlaceInMatrix(x,y,range,range,matrix);
|
||||
|
||||
//
|
||||
// Find a path to the place.
|
||||
//
|
||||
if( (depth=MarkPathInMatrix(src,matrix)) < 0 ) {
|
||||
depth=ComplexNewPath(src,x,y,x+range,y+range,MUST_REACH_GOAL,NULL);
|
||||
|
||||
if( depth < 0 ) {
|
||||
DebugLevel3("Can't move to destination\n");
|
||||
return 0;
|
||||
}
|
||||
|
@ -374,25 +370,19 @@ global int PlaceReachable(const Unit* src,int x,int y,int range)
|
|||
**
|
||||
** @return Distance to place.
|
||||
*/
|
||||
global int UnitReachable(const Unit* src,const Unit* dst,int range)
|
||||
global int UnitReachable(Unit* src,const Unit* dst,int range)
|
||||
{
|
||||
unsigned char* matrix;
|
||||
int depth;
|
||||
|
||||
DebugLevel3Fn("%d(%d,%d,%s)->%d(%d,%d,%s)+%d "
|
||||
_C_ UnitNumber(src) _C_ src->X _C_ src->Y _C_ src->Type->Ident
|
||||
_C_ UnitNumber(dst) _C_ dst->X _C_ dst->Y _C_ dst->Type->Ident _C_ range);
|
||||
|
||||
//
|
||||
// Setup movement.
|
||||
//
|
||||
matrix=CreateMatrix();
|
||||
MarkGoalInMatrix(dst,range,matrix);
|
||||
|
||||
//
|
||||
// Find a path to the goal.
|
||||
//
|
||||
if( (depth=MarkPathInMatrix(src,matrix))<0 ) {
|
||||
depth=ComplexNewPath(src,dst->X-range,dst->Y-range,dst->X+range,dst->Y+range,MUST_REACH_GOAL,NULL);
|
||||
if( depth <0 ) {
|
||||
DebugLevel3("NO WAY\n");
|
||||
return 0;
|
||||
}
|
||||
|
@ -420,8 +410,7 @@ global int UnitReachable(const Unit* src,const Unit* dst,int range)
|
|||
** @return >0 remaining path length, 0 wait for path, -1
|
||||
** reached goal, -2 can't reach the goal.
|
||||
*/
|
||||
local int FastNewPath(const Unit* unit,int gx,int gy,int ox,int oy
|
||||
,int *xdp,int* ydp)
|
||||
local int FastNewPath(Unit* unit,int gx,int gy,int ox,int oy)
|
||||
{
|
||||
int x;
|
||||
int y;
|
||||
|
@ -431,7 +420,7 @@ local int FastNewPath(const Unit* unit,int gx,int gy,int ox,int oy
|
|||
int mask;
|
||||
int steps;
|
||||
int add;
|
||||
|
||||
|
||||
//
|
||||
// Fast check if the way is blocked in sight.
|
||||
//
|
||||
|
@ -457,11 +446,11 @@ local int FastNewPath(const Unit* unit,int gx,int gy,int ox,int oy
|
|||
|
||||
// FIXME: johns: has anybody an idea how to write this faster?
|
||||
xd-=x;
|
||||
if( xd<0 ) xd=-add; else if( xd>0 ) xd=add;
|
||||
*xdp=xd;
|
||||
yd-=y;
|
||||
if( xd<0 ) xd=-add; else if( xd>0 ) xd=add;
|
||||
if( yd<0 ) yd=-add; else if( yd>0 ) yd=add;
|
||||
*ydp=yd;
|
||||
unit->Data.Move.Path[0]=XY2Heading[xd+1][yd+1];
|
||||
unit->Data.Move.Length=1;
|
||||
DebugLevel3Fn("%d,%d\n" _C_ xd _C_ yd);
|
||||
|
||||
while( (steps-=add)>0 ) {
|
||||
|
@ -526,11 +515,16 @@ local void PathTraceBack(const unsigned char* matrix,int add,int x,int y
|
|||
const unsigned char* m;
|
||||
int d;
|
||||
int n;
|
||||
int startdepth;
|
||||
|
||||
w=TheMap.Width+2;
|
||||
m=matrix+x+y*w; // End of path in matrix.
|
||||
w*=add;
|
||||
w2=w+w;
|
||||
startdepth=depth;
|
||||
if( startdepth > MAX_PATH_LENGTH ) {
|
||||
startdepth = MAX_PATH_LENGTH;
|
||||
}
|
||||
|
||||
//
|
||||
// Find the way back, nodes are numbered ascending.
|
||||
|
@ -579,8 +573,10 @@ local void PathTraceBack(const unsigned char* matrix,int add,int x,int y
|
|||
}
|
||||
}
|
||||
// found: continue
|
||||
if( depth<MAX_PATH_LENGTH ) {
|
||||
path[depth]=d;
|
||||
// Mart path if it's needed
|
||||
//
|
||||
if( depth<MAX_PATH_LENGTH && path != NULL) {
|
||||
path[startdepth-depth-1]=d;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -599,7 +595,7 @@ local void PathTraceBack(const unsigned char* matrix,int add,int x,int y
|
|||
** @return >0 remaining path length, 0 wait for path, -1
|
||||
** reached goal, -2 can't reach the goal.
|
||||
*/
|
||||
local int ComplexNewPath(Unit* unit,int gx,int gy,int ox,int oy,char* path)
|
||||
local int ComplexNewPath(Unit* unit,int gx,int gy,int ox,int oy,int type,char* path)
|
||||
{
|
||||
static const int xoffset[]={ 0,-1,+1, 0, -1,+1,-1,+1,
|
||||
0,-2,+2, 0, -2,+2,-2,+2 };
|
||||
|
@ -637,6 +633,17 @@ local int ComplexNewPath(Unit* unit,int gx,int gy,int ox,int oy,char* path)
|
|||
_C_ unit->Orders[0].Goal ? UnitNumber(unit->Orders[0].Goal) : 0
|
||||
_C_ gx _C_ gy _C_ ox _C_ oy);
|
||||
|
||||
//
|
||||
// Run AStar If it's enabled, I is faster for bigger maps.
|
||||
//
|
||||
if( AStarOn ) {
|
||||
// run AStar, if it returns PF_FAILED continue with Complex
|
||||
depth = AStarFindPath(unit,gx,gy,(gx+ox-1),(gy+oy-1),type,path);
|
||||
}
|
||||
if( AStarOn && depth != PF_FAILED ) {
|
||||
return depth;
|
||||
}
|
||||
|
||||
size=TheMap.Width*TheMap.Height;
|
||||
points=malloc(size);
|
||||
size/=sizeof(*points)*2;
|
||||
|
@ -870,7 +877,7 @@ local int ComplexNewPath(Unit* unit,int gx,int gy,int ox,int oy,char* path)
|
|||
** @return >0 remaining path length, 0 wait for path, -1
|
||||
** reached goal, -2 can't reach the goal.
|
||||
*/
|
||||
global int NewPath(Unit* unit,int* xdp,int* ydp)
|
||||
global int NewPath(Unit* unit)
|
||||
{
|
||||
int x;
|
||||
int y;
|
||||
|
@ -881,15 +888,7 @@ global int NewPath(Unit* unit,int* xdp,int* ydp)
|
|||
int rx;
|
||||
int ry;
|
||||
int i;
|
||||
int p;
|
||||
unsigned char path[MAX_PATH_LENGTH];
|
||||
|
||||
//
|
||||
// Convert heading into direction.
|
||||
// // N NE E SE S SW W NW
|
||||
local const int Heading2X[8] = { 0,+1,+1,+1, 0,-1,-1,-1 };
|
||||
local const int Heading2Y[8] = { -1,-1, 0,+1,+1,+1, 0,-1 };
|
||||
|
||||
char* path;
|
||||
|
||||
x=unit->X;
|
||||
y=unit->Y;
|
||||
|
@ -917,7 +916,6 @@ global int NewPath(Unit* unit,int* xdp,int* ydp)
|
|||
_C_ x _C_ y _C_ gx _C_ gy _C_ gx+rx _C_ gy+ry);
|
||||
if( x>=gx && x<gx+rx && y>=gy && y<gy+ry ) {
|
||||
DebugLevel3Fn("Goal reached\n");
|
||||
*xdp=*ydp=0;
|
||||
return PF_REACHED;
|
||||
}
|
||||
} else { // goal map field
|
||||
|
@ -927,7 +925,6 @@ global int NewPath(Unit* unit,int* xdp,int* ydp)
|
|||
++ry;
|
||||
if( x>=gx && x<gx+rx && y>=gy && y<gy+ry ) {
|
||||
DebugLevel3Fn("Field reached\n");
|
||||
*xdp=*ydp=0;
|
||||
return PF_REACHED;
|
||||
}
|
||||
// This reduces the processor use,
|
||||
|
@ -936,7 +933,6 @@ global int NewPath(Unit* unit,int* xdp,int* ydp)
|
|||
if( rx==1 && ry==1 && x>=gx-1 && x<=gx+1 && y>=gy-1 && y<=gy+1 ) {
|
||||
if( !CheckedCanMoveToMask(gx,gy,UnitMovementMask(unit)) ) {
|
||||
// target field blocked by something
|
||||
*xdp=*ydp=0;
|
||||
return PF_UNREACHABLE;
|
||||
}
|
||||
unit->Data.Move.Fast=1; // this could be handled fast
|
||||
|
@ -947,9 +943,9 @@ global int NewPath(Unit* unit,int* xdp,int* ydp)
|
|||
// If possible, try fast.
|
||||
//
|
||||
if( unit->Data.Move.Fast ) {
|
||||
if( (i=FastNewPath(unit,gx,gy,rx,ry,xdp,ydp))>=-1 ) {
|
||||
if( (i=FastNewPath(unit,gx,gy,rx,ry))>=-1 ) {
|
||||
// Fast works
|
||||
DebugCheck( *xdp==0 && *ydp==0 );
|
||||
// DebugCheck( *xdp==0 && *ydp==0 );
|
||||
return i;
|
||||
}
|
||||
DebugLevel3Fn("Fallback to slow method\n");
|
||||
|
@ -959,33 +955,21 @@ global int NewPath(Unit* unit,int* xdp,int* ydp)
|
|||
//
|
||||
// Fall back to slow complex method.
|
||||
//
|
||||
i=ComplexNewPath(unit,gx,gy,rx,ry,path);
|
||||
path = unit->Data.Move.Path;
|
||||
i=ComplexNewPath(unit,gx,gy,rx,ry,BEST_GOAL,path);
|
||||
|
||||
if( i>=0 ) {
|
||||
#ifdef NEW_SHIPS
|
||||
if( unit->Type->UnitType==UnitTypeLand ) {
|
||||
*xdp=Heading2X[*path];
|
||||
*ydp=Heading2Y[*path];
|
||||
} else {
|
||||
*xdp=Heading2X[*path]*2;
|
||||
*ydp=Heading2Y[*path]*2;
|
||||
}
|
||||
#else
|
||||
*xdp=Heading2X[*path];
|
||||
*ydp=Heading2Y[*path];
|
||||
// Build Path to follow later
|
||||
// -1 to include 0, -1 for 1 point will have been executed
|
||||
// Update path if it was requested. Otherwise we may only want
|
||||
// to know if there exists a path.
|
||||
|
||||
if( path != NULL ) {
|
||||
if( i >= MAX_PATH_LENGTH ) {
|
||||
p=MAX_PATH_LENGTH;
|
||||
unit->Data.Move.Length=MAX_PATH_LENGTH-1;
|
||||
unit->Data.Move.Length=MAX_PATH_LENGTH;
|
||||
} else {
|
||||
p=i;
|
||||
unit->Data.Move.Length=p-1;
|
||||
unit->Data.Move.Length=i;
|
||||
}
|
||||
for(; p > 0; p--) {
|
||||
unit->Data.Move.Path[p-1]=path[unit->Data.Move.Length-p+1];
|
||||
if( unit->Data.Move.Length == 0) {
|
||||
unit->Data.Move.Length++;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
//
|
||||
/**@name unit_find.c - The find/select for units. */
|
||||
//
|
||||
// (c) Copyright 1998-2002 by Lutz Sammer
|
||||
// (c) Copyright 1998-2003 by Lutz Sammer
|
||||
//
|
||||
// FreeCraft is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published
|
||||
|
@ -646,7 +646,7 @@ global Unit* WoodDepositOnMap(int tx,int ty)
|
|||
** @note Limited to attack range smaller than 16.
|
||||
** @note Will be moved to unit_ai.c soon.
|
||||
*/
|
||||
local Unit* FindRangeAttack(const Unit* u, int range)
|
||||
local Unit* FindRangeAttack(Unit* u, int range)
|
||||
{
|
||||
int x, y, n, cost,d,effective_hp,enemy_count;
|
||||
int missile_range,attackrange,hp_damage_evaluate;
|
||||
|
@ -898,7 +898,7 @@ local Unit* FindRangeAttack(const Unit* u, int range)
|
|||
**
|
||||
** @note This could be improved, for better performance.
|
||||
*/
|
||||
global Unit* AttackUnitsInDistance(const Unit* unit,int range)
|
||||
global Unit* AttackUnitsInDistance(Unit* unit,int range)
|
||||
{
|
||||
const Unit* dest;
|
||||
const UnitType* type;
|
||||
|
@ -1022,7 +1022,7 @@ global Unit* AttackUnitsInDistance(const Unit* unit,int range)
|
|||
**
|
||||
** @return Pointer to unit which should be attacked.
|
||||
*/
|
||||
global Unit* AttackUnitsInRange(const Unit* unit)
|
||||
global Unit* AttackUnitsInRange(Unit* unit)
|
||||
{
|
||||
//
|
||||
// Only units which can attack.
|
||||
|
@ -1046,7 +1046,7 @@ global Unit* AttackUnitsInRange(const Unit* unit)
|
|||
**
|
||||
** @return Pointer to unit which should be attacked.
|
||||
*/
|
||||
global Unit* AttackUnitsInReactRange(const Unit* unit)
|
||||
global Unit* AttackUnitsInReactRange(Unit* unit)
|
||||
{
|
||||
int range;
|
||||
const UnitType* type;
|
||||
|
|
Loading…
Reference in a new issue