Adjustment of pathfinders to give better performance

This commit is contained in:
mr-russ 2003-05-11 06:04:13 +00:00
parent 5a4a0714c7
commit 4edf25bf33
7 changed files with 175 additions and 244 deletions

View file

@ -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).

View file

@ -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 );
}

View file

@ -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
//

View file

@ -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

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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;