Complete disaster-recovery snapshot: engine/game source, game data assets, VC6 toolchain + DX SDKs, build outputs, deployed game, and _UNUSED archive. Large binaries in Git LFS; text preserved byte-for-byte (core.autocrlf=false, no eol attributes). See RECOVERY.md for the one-clone rebuild procedure.
1048 lines
23 KiB
C++
1048 lines
23 KiB
C++
#include "MW4Headers.hpp"
|
|
#include "server\comline.hpp"
|
|
#include "adept\application.hpp"
|
|
#include "rail_move.hpp"
|
|
#include "ai.hpp"
|
|
|
|
#pragma warning (push)
|
|
#include <vector>
|
|
#include <map>
|
|
#pragma warning (pop)
|
|
|
|
namespace MW4AI
|
|
{
|
|
extern Stuff::Scalar MinZ, MaxZ, MinX, MaxX;
|
|
extern __int64 tPathTime,tGridPathTime;
|
|
};
|
|
namespace MechWarrior4
|
|
{
|
|
extern DWORD Path_Calcs_Count;
|
|
extern DWORD GridPath_Calcs_Count;
|
|
extern DWORD QuickPath_Calcs_Count;
|
|
extern DWORD QuickRail_Calcs_Count;
|
|
extern DWORD FailedPath_Calcs_Count;
|
|
}
|
|
|
|
using namespace MW4AI;
|
|
using namespace MechWarrior4;
|
|
|
|
|
|
unsigned int CGridPath::m_BlockGrid[BLOCK_GRID_SIZE][BLOCK_GRID_SIZE][2];
|
|
int CGridPath::m_BlockOriginX,CGridPath::m_BlockOriginY;
|
|
CGridPath *CGridPath::m_WorkingPath=NULL;
|
|
|
|
CGridPath::CGridPath (CRailGraph *graph,unsigned short mask,Stuff::Scalar sx,Stuff::Scalar sy,Stuff::Scalar dx,Stuff::Scalar dy,bool tenmeter)
|
|
{
|
|
m_Working = false;
|
|
m_WorkCount = 0;
|
|
m_TenMeterAllowed = tenmeter;
|
|
m_StartX = (int) (sx);
|
|
m_StartY = (int) (sy);
|
|
m_EndX = (int) (dx);
|
|
m_EndY = (int) (dy);
|
|
m_Calced = false;
|
|
m_DirList.clear ();
|
|
m_InDirPath = m_DirList.begin ();
|
|
m_Graph = graph;
|
|
m_QuickValid = false;
|
|
m_Mask = mask;
|
|
}
|
|
|
|
CGridPath::CGridPath (CRailGraph *graph)
|
|
{
|
|
m_Working = false;
|
|
m_WorkCount = 0;
|
|
m_TenMeterAllowed = false;
|
|
m_StartX = 0;
|
|
m_StartY = 0;
|
|
m_EndX = 0;
|
|
m_EndY = 0;
|
|
m_Calced = false;
|
|
m_DirList.clear ();
|
|
m_InDirPath = m_DirList.begin ();
|
|
m_Graph = graph;
|
|
m_QuickValid = false;
|
|
m_Mask = 0;
|
|
}
|
|
|
|
CGridPath::CGridPath (CRailGraph *graph,unsigned short mask,int sx,int sy,int dx,int dy,bool tenmeter)
|
|
{
|
|
m_Working = false;
|
|
m_WorkCount = 0;
|
|
m_TenMeterAllowed = tenmeter;
|
|
m_StartX = sx;
|
|
m_StartY = sy;
|
|
m_EndX = dx;
|
|
m_EndY = dy;
|
|
m_Calced = false;
|
|
m_DirList.clear ();
|
|
m_InDirPath = m_DirList.begin ();
|
|
m_Graph = graph;
|
|
m_QuickValid = false;
|
|
m_Mask = mask;
|
|
}
|
|
|
|
CGridPath::~CGridPath (void)
|
|
{
|
|
if (m_WorkingPath == this)
|
|
m_WorkingPath = NULL;
|
|
calc.clear ();
|
|
m_DirList.clear ();
|
|
}
|
|
|
|
void CGridPath::UpdateSrcDest (int sx,int sy,int dx,int dy)
|
|
{
|
|
if (m_Working)
|
|
return;
|
|
m_StartX = sx;
|
|
m_StartY = sy;
|
|
m_EndX = dx;
|
|
m_EndY = dy;
|
|
}
|
|
|
|
void CGridPath::UpdateSrcDest (Scalar sx,Scalar sy,Scalar dx,Scalar dy)
|
|
{
|
|
if (m_Working)
|
|
return;
|
|
m_StartX = (int) (sx);
|
|
m_StartY = (int) (sy);
|
|
m_EndX = (int) (dx);
|
|
m_EndY = (int) (dy);
|
|
}
|
|
|
|
void CGridPath::Save (MemoryStream *stream)
|
|
{
|
|
int count;
|
|
|
|
stlport::vector<DirElement>::iterator iter;
|
|
*stream << m_TenMeterAllowed;
|
|
*stream << m_StartX;
|
|
*stream << m_StartY;
|
|
*stream << m_EndX;
|
|
*stream << m_EndY;
|
|
*stream << m_Calced;
|
|
*stream << m_QuickValid;
|
|
*stream << m_Mask;
|
|
*stream << m_DirList.size ();
|
|
for (count = 0,iter = m_DirList.begin ();(iter != m_DirList.end ()) && (m_InDirPath != iter);iter++,count++);
|
|
*stream << count;
|
|
for (iter = m_DirList.begin ();iter != m_DirList.end ();iter++)
|
|
{
|
|
stream->WriteBytes (&(*iter),sizeof (*iter));
|
|
}
|
|
}
|
|
|
|
void CGridPath::Load (MemoryStream *stream)
|
|
{
|
|
int count,size,i;
|
|
|
|
*stream >> m_TenMeterAllowed;
|
|
*stream >> m_StartX;
|
|
*stream >> m_StartY;
|
|
*stream >> m_EndX;
|
|
*stream >> m_EndY;
|
|
*stream >> m_Calced;
|
|
*stream >> m_QuickValid;
|
|
*stream >> m_Mask;
|
|
*stream >> size;
|
|
*stream >> count;
|
|
m_DirList.assign (size,DirElement ());
|
|
for (i=0;i<size;i++)
|
|
{
|
|
stream->ReadBytes (&(m_DirList[i]),sizeof (DirElement));
|
|
}
|
|
m_InDirPath = m_DirList.begin ();
|
|
m_InDirPath += count;
|
|
}
|
|
|
|
void CGridPath::PointList (stlport::vector<Point3D>& dest)
|
|
{
|
|
stlport::vector<DirElement>::iterator iter;
|
|
|
|
AutoHeap local_heap (g_RailHeap);
|
|
for (iter = m_InDirPath;iter != m_DirList.end ();iter++)
|
|
{
|
|
Scalar x,y;
|
|
if (iter->locX < 0)
|
|
{
|
|
x = (iter->locX*BLOCK_GRID_RES) - (BLOCK_GRID_RES/2.0f);
|
|
}
|
|
else
|
|
{
|
|
x = (iter->locX*BLOCK_GRID_RES) + (BLOCK_GRID_RES/2.0f);
|
|
}
|
|
if (iter->locY < 0)
|
|
{
|
|
y = (iter->locY*BLOCK_GRID_RES) - (BLOCK_GRID_RES/2.0f);
|
|
}
|
|
else
|
|
{
|
|
y = (iter->locY*BLOCK_GRID_RES) + (BLOCK_GRID_RES/2.0f);
|
|
}
|
|
dest.push_back (Point3D (x,0,y));
|
|
}
|
|
}
|
|
|
|
void CGridPath::ConstructQuickPath (void)
|
|
{
|
|
m_DirList.clear ();
|
|
|
|
Stuff::Point3D extra;
|
|
float sx,sy,dx,dy;
|
|
int ix,iy,ex,ey;
|
|
int count,distcount;
|
|
int startx,starty,endx,endy;
|
|
|
|
AutoHeap local_heap (g_RailHeap);
|
|
startx = m_StartX/BLOCK_GRID_RES;
|
|
starty = m_StartY/BLOCK_GRID_RES;
|
|
endx = m_EndX/BLOCK_GRID_RES;
|
|
endy = m_EndY/BLOCK_GRID_RES;
|
|
Verify ((startx != endx) || (starty != endy));
|
|
|
|
dx = (float) endx - startx;
|
|
dy = (float) endy - starty;
|
|
sx = dx < 0 ? dx*-1.0f : dx;
|
|
sy = dy < 0 ? dy*-1.0f : dy;
|
|
|
|
if (sx > sy)
|
|
{
|
|
dy = dy / sx;
|
|
count = (int) ( (dx<0.0 ? dx*-1.0f : dx));
|
|
dx = dx<0 ? -1.0f : 1.0f;
|
|
}
|
|
else
|
|
{
|
|
dx = dx / sy;
|
|
count = (int) ( (dy<0.0 ? dy*-1.0f : dy));
|
|
dy = dy<0 ? -1.0f : 1.0f;
|
|
}
|
|
|
|
sx = (float) startx;
|
|
sy = (float) starty;
|
|
ex = endx;
|
|
ey = endy;
|
|
ix = (int) (sx);
|
|
iy = (int) (sy);
|
|
distcount = 0;
|
|
m_DirList.push_back (DirElement (ix,iy));
|
|
bool flag = false;
|
|
while (count)
|
|
{
|
|
count--;
|
|
sx += dx;
|
|
sy += dy;
|
|
ix = (int) (sx);
|
|
iy = (int) (sy);
|
|
distcount += BLOCK_GRID_RES;
|
|
|
|
flag = false;
|
|
m_DirList.push_back (DirElement (ix,iy));
|
|
flag = true;
|
|
}
|
|
if (!flag)
|
|
{
|
|
m_DirList.push_back (DirElement (ix,iy));
|
|
}
|
|
|
|
m_InDirPath = m_DirList.begin ();
|
|
m_Calced = true;
|
|
}
|
|
|
|
void CGridPath::DumpPath (void)
|
|
{
|
|
stlport::vector<DirElement>::iterator iter;
|
|
char text[100];
|
|
|
|
iter = m_DirList.begin ();
|
|
while (iter != m_DirList.end ())
|
|
{
|
|
sprintf (text,"Move Point %d,%d",iter->locX,iter->locY);
|
|
COMSPEW (text);
|
|
iter++;
|
|
}
|
|
COMSPEW ("");
|
|
}
|
|
|
|
|
|
void CGridPath::Calc30Path (void)
|
|
{
|
|
Verify (m_Graph);
|
|
int i;
|
|
GridPathElement temp;
|
|
bool done,hackflag=false;
|
|
bool allow10early=false;
|
|
bool did10early=false;
|
|
int startx,starty,endx,endy;
|
|
const int SIZEDELTA = 8;
|
|
static int delta[SIZEDELTA][5] = { // first, second, cost
|
|
{0,-1,7,1,10},
|
|
{1,-1,0,2,15},
|
|
{1,0,1,3,10},
|
|
{1,1,2,4,15},
|
|
{0,1,5,3,10},
|
|
{-1,1,6,4,15},
|
|
{-1,0,7,5,10},
|
|
{-1,-1,6,0,15}
|
|
};
|
|
AutoHeap local_heap (g_RailHeap);
|
|
|
|
PATH_LOGIC("Calc30Path");
|
|
#if !defined(NO_TIMERS)
|
|
my_AutoTimer fred ((void *) &tGridPathTime);
|
|
#endif
|
|
Set_Statistic(GridPath_Calcs_Count, GridPath_Calcs_Count+1);
|
|
|
|
m_QuickValid = false;
|
|
|
|
startx = m_StartX/BLOCK_GRID_RES;
|
|
starty = m_StartY/BLOCK_GRID_RES;
|
|
endx = m_EndX/BLOCK_GRID_RES;
|
|
endy = m_EndY/BLOCK_GRID_RES;
|
|
#if 0
|
|
Point3D srcpt,destpt,extra;
|
|
|
|
destpt.x = (float) m_EndX;
|
|
destpt.z = (float) m_EndY;
|
|
srcpt.x = (float) m_StartX;
|
|
srcpt.z = (float) m_StartY;
|
|
destpt.y = 0;
|
|
srcpt.y = 0;
|
|
extra = m_Graph->PullPointElementMask (srcpt,destpt,m_Mask);
|
|
Verify (extra != Point3D (-1,-1,-1));
|
|
endx = (int) (extra.x / BLOCK_GRID_RES);
|
|
endy = (int) (extra.z / BLOCK_GRID_RES);
|
|
|
|
memset (m_BlockGrid,0,sizeof (unsigned int) * BLOCK_GRID_SIZE * BLOCK_GRID_SIZE * 2);
|
|
|
|
int dx,dy;
|
|
dx = startx>endx ? startx - endx : endx - startx;
|
|
dy = starty>endy ? starty - endy : endy - starty;
|
|
|
|
Verify (dx < BLOCK_GRID_SIZE);
|
|
Verify (dy < BLOCK_GRID_SIZE);
|
|
|
|
m_BlockOriginX = startx - ((BLOCK_GRID_SIZE - dx) >> 1);
|
|
m_BlockOriginY = starty - ((BLOCK_GRID_SIZE - dy) >> 1);
|
|
if (m_BlockOriginX < MinX)
|
|
m_BlockOriginX = (int) MinX;
|
|
if (m_BlockOriginY < MinZ)
|
|
m_BlockOriginY = (int) MinZ;
|
|
|
|
if (m_BlockOriginX >= (MaxX - BLOCK_GRID_SIZE))
|
|
m_BlockOriginX = (int) ( MaxX - BLOCK_GRID_SIZE - 1);
|
|
if (m_BlockOriginY >= (MaxZ - BLOCK_GRID_SIZE))
|
|
m_BlockOriginY = (int) ( MaxZ - BLOCK_GRID_SIZE-1 - 1);
|
|
|
|
|
|
Cost (startx,starty,1,(unsigned short) CostGuess (startx,starty));
|
|
calc.Insert (GridPathElement (startx,starty));
|
|
#endif
|
|
GridPathElement end (endx,endy);
|
|
done = false;
|
|
m_Calced = false;
|
|
|
|
{
|
|
hackflag = false;
|
|
top:
|
|
int count = 0;
|
|
|
|
while (!done)
|
|
{
|
|
count++;
|
|
if (count > GRIDMOVE_FAIL_THRESHOLD)
|
|
break;
|
|
if (!calc.size ())
|
|
break;
|
|
temp = calc.ExtractMin ();
|
|
if (temp == end)
|
|
{
|
|
done = true;
|
|
break;
|
|
}
|
|
int cost;
|
|
|
|
cost = Cost (temp);
|
|
if (cost > 1)
|
|
allow10early = false;
|
|
for (i=0;i<SIZEDELTA;i++)
|
|
{
|
|
int newcost;
|
|
int newx,newy;
|
|
|
|
newx = temp.locX+delta[i][0];
|
|
newy = temp.locY+delta[i][1];
|
|
if (!m_Graph->MoveTo (newx,newy,i,m_Mask))
|
|
continue;
|
|
if (!allow10early)
|
|
{
|
|
int newx,newy;
|
|
{
|
|
newx = temp.locX+delta[delta[i][2]][0];
|
|
newy = temp.locY+delta[delta[i][2]][1];
|
|
if (!m_Graph->MoveTo (newx,newy,delta[i][2],m_Mask))
|
|
continue;
|
|
}
|
|
{
|
|
newx = temp.locX+delta[delta[i][3]][0];
|
|
newy = temp.locY+delta[delta[i][3]][1];
|
|
if (!m_Graph->MoveTo (newx,newy,delta[i][3],m_Mask))
|
|
continue;
|
|
}
|
|
}
|
|
int updown = m_Graph->UpDownTo (newx,newy,delta[i][3],m_Mask);
|
|
if (updown == 0)
|
|
{
|
|
newcost = delta[i][4];
|
|
}
|
|
else if (updown == 1)
|
|
{
|
|
if (delta[i][4] == 10)
|
|
newcost = 14;
|
|
else
|
|
newcost = 21;
|
|
}
|
|
else
|
|
{
|
|
if (delta[i][4] == 10)
|
|
newcost = 13;
|
|
else
|
|
newcost = 19;
|
|
}
|
|
newcost += cost;
|
|
newcost += AdjustCost (newx,newy);
|
|
if (Cost (newx,newy,(unsigned int) newcost,(unsigned int) CostGuess (newx,newy)))
|
|
{
|
|
GridPathElement newelement(newx,newy);
|
|
if (calc.Member (newelement))
|
|
{
|
|
calc.DecreaseKey (newelement);
|
|
}
|
|
else
|
|
{
|
|
calc.Insert (newelement);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if ((!hackflag) && (count <= 2) && (!done)) // all cells around itself are blocked
|
|
{
|
|
Cost (startx,starty,1,(unsigned short) CostGuess (startx,starty));
|
|
calc.clear ();
|
|
calc.Insert (GridPathElement (startx,starty));
|
|
allow10early = true;
|
|
did10early = true;
|
|
hackflag = true;
|
|
goto top;
|
|
}
|
|
|
|
if (!done && (count > GRIDMOVE_FAIL_THRESHOLD)) // check for can continue work later
|
|
{
|
|
m_WorkCount += count;
|
|
if (m_WorkCount > GRIDMOVE_MAX_CHECK_THRESHOLD)
|
|
{
|
|
calc.clear ();
|
|
m_Calced = false;
|
|
g_PathManager->m_FailedCalcFrame = true;
|
|
Set_Statistic(FailedPath_Calcs_Count, FailedPath_Calcs_Count+1);
|
|
m_Working = false;
|
|
}
|
|
return;
|
|
}
|
|
else if (!done) // visited all possible cells
|
|
{
|
|
calc.clear ();
|
|
m_Calced = false;
|
|
g_PathManager->m_FailedCalcFrame = true;
|
|
Set_Statistic(FailedPath_Calcs_Count, FailedPath_Calcs_Count+1);
|
|
m_Working = false;
|
|
return;
|
|
}
|
|
|
|
done = false;
|
|
GridPathElement cur;
|
|
int min;
|
|
unsigned int mincost;
|
|
int newx,newy;
|
|
int lastdir = -1;
|
|
GridPathElement start(startx,starty);
|
|
int t;
|
|
Stuff::Scalar dirdist = 0;
|
|
|
|
|
|
cur.locX = endx;
|
|
cur.locY = endy;
|
|
m_DirList.push_back (DirElement (cur.locX,cur.locY));
|
|
calc.clear ();
|
|
|
|
min = NULL;
|
|
count=0;
|
|
while (!done)
|
|
{
|
|
#if 1
|
|
count++;
|
|
if (count > (GRIDMOVE_MAX_CHECK_THRESHOLD/2))
|
|
{
|
|
Set_Statistic(FailedPath_Calcs_Count, FailedPath_Calcs_Count+1);
|
|
m_Calced = false;
|
|
g_PathManager->m_FailedCalcFrame = true;
|
|
break;
|
|
}
|
|
#endif
|
|
min = 0;
|
|
newx = cur.locX + delta[min][0];
|
|
newy = cur.locY + delta[min][1];
|
|
mincost = Cost (newx,newy);
|
|
for (i=1;i<SIZEDELTA;i++)
|
|
{
|
|
if ((newx == startx) && (newy == starty))
|
|
{
|
|
min = i-1;
|
|
mincost = 1;
|
|
break;
|
|
}
|
|
newx = cur.locX + delta[i][0];
|
|
newy = cur.locY + delta[i][1];
|
|
t= Cost (newx,newy);
|
|
|
|
if (t && !hackflag && (t <= 16))
|
|
{
|
|
int newx,newy;
|
|
|
|
{
|
|
{
|
|
newx = cur.locX+delta[delta[i][2]][0];
|
|
newy = cur.locY+delta[delta[i][2]][1];
|
|
if (!m_Graph->MoveTo (newx,newy,delta[i][2]+4,m_Mask))
|
|
t = 0;
|
|
}
|
|
{
|
|
newx = cur.locX+delta[delta[i][3]][0];
|
|
newy = cur.locY+delta[delta[i][3]][1];
|
|
if (!m_Graph->MoveTo (newx,newy,delta[i][3]+4,m_Mask))
|
|
t = 0;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
if (((t < mincost) && (t != 0)) || (mincost == 0))
|
|
{
|
|
mincost = t;
|
|
min = i;
|
|
}
|
|
}
|
|
if (mincost == 0)
|
|
{
|
|
min = 0;
|
|
newx = cur.locX + delta[min][0];
|
|
newy = cur.locY + delta[min][1];
|
|
mincost = Cost (newx,newy);
|
|
for (i=1;i<SIZEDELTA;i++)
|
|
{
|
|
newx = cur.locX + delta[i][0];
|
|
newy = cur.locY + delta[i][1];
|
|
t= Cost (newx,newy);
|
|
|
|
if (((t < mincost) && (t != 0)) || (mincost == 0))
|
|
{
|
|
mincost = t;
|
|
min = i;
|
|
}
|
|
}
|
|
}
|
|
Verify (mincost != 0);
|
|
cur.locX+=delta[min][0];
|
|
cur.locY+=delta[min][1];
|
|
dirdist += BLOCK_GRID_RES;
|
|
bool dirflag = false;
|
|
if (lastdir != min)
|
|
{
|
|
dirdist = 0;
|
|
m_DirList.push_back (DirElement (cur.locX,cur.locY));
|
|
dirflag = true;
|
|
lastdir = min;
|
|
}
|
|
if (cur == start)
|
|
{
|
|
if (!dirflag)
|
|
m_DirList.push_back (DirElement (cur.locX,cur.locY));
|
|
done = true;
|
|
m_Calced = true;
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
if (!m_Calced)
|
|
{
|
|
// STOP (("should not get here. We have already weighted cells from start to finish"));
|
|
Set_Statistic(FailedPath_Calcs_Count, FailedPath_Calcs_Count+1);
|
|
g_PathManager->m_FailedCalcFrame = true;
|
|
m_Working = false;
|
|
return;
|
|
}
|
|
ReverseList ();
|
|
Verify (m_DirList.size () >= 2);
|
|
// SmoothList ();
|
|
m_InDirPath = m_DirList.begin ();
|
|
if (m_InDirPath != m_DirList.end ())
|
|
{
|
|
m_InDirPath++;
|
|
}
|
|
m_Calced = true;
|
|
m_Working = false;
|
|
}
|
|
|
|
void CGridPath::Calc10Path (void)
|
|
{
|
|
Verify (m_Graph);
|
|
int i;
|
|
GridPathElement temp;
|
|
bool done,hackflag=false;
|
|
int startx,starty,endx,endy;
|
|
const int SIZEDELTA = 8;
|
|
static int delta[SIZEDELTA][5] = { // first, second, cost
|
|
{0,-1,7,1,10},
|
|
{1,-1,0,2,15},
|
|
{1,0,1,3,10},
|
|
{1,1,2,4,15},
|
|
{0,1,5,3,10},
|
|
{-1,1,6,4,15},
|
|
{-1,0,7,5,10},
|
|
{-1,-1,6,0,15}
|
|
};
|
|
AutoHeap local_heap (g_RailHeap);
|
|
|
|
PATH_LOGIC("Calc10Path");
|
|
#if !defined(NO_TIMERS)
|
|
my_AutoTimer fred ((void *) &tGridPathTime);
|
|
#endif
|
|
Set_Statistic(GridPath_Calcs_Count, GridPath_Calcs_Count+1);
|
|
|
|
m_QuickValid = false;
|
|
|
|
startx = m_StartX/BLOCK_GRID_RES;
|
|
starty = m_StartY/BLOCK_GRID_RES;
|
|
endx = m_EndX/BLOCK_GRID_RES;
|
|
endy = m_EndY/BLOCK_GRID_RES;
|
|
Point3D srcpt,destpt,extra;
|
|
#if 0
|
|
memset (m_BlockGrid,0,sizeof (unsigned int) * BLOCK_GRID_SIZE * BLOCK_GRID_SIZE * 2);
|
|
int dx,dy;
|
|
dx = startx>endx ? startx - endx : endx - startx;
|
|
dy = starty>endy ? starty - endy : endy - starty;
|
|
|
|
Verify (dx < BLOCK_GRID_SIZE);
|
|
Verify (dy < BLOCK_GRID_SIZE);
|
|
|
|
m_BlockOriginX = startx - ((BLOCK_GRID_SIZE - dx) >> 1);
|
|
m_BlockOriginY = starty - ((BLOCK_GRID_SIZE - dy) >> 1);
|
|
if (m_BlockOriginX < MinX)
|
|
m_BlockOriginX = (int) MinX;
|
|
if (m_BlockOriginY < MinZ)
|
|
m_BlockOriginY = (int) MinZ;
|
|
|
|
if (m_BlockOriginX >= (MaxX - BLOCK_GRID_SIZE))
|
|
m_BlockOriginX = (int) ( MaxX - BLOCK_GRID_SIZE - 1);
|
|
if (m_BlockOriginY >= (MaxZ - BLOCK_GRID_SIZE))
|
|
m_BlockOriginY = (int) ( MaxZ - BLOCK_GRID_SIZE-1 - 1);
|
|
|
|
Cost (startx,starty,1,(unsigned short) CostGuess (startx,starty));
|
|
calc.Insert (GridPathElement (startx,starty));
|
|
#endif
|
|
|
|
GridPathElement end (endx,endy);
|
|
done = false;
|
|
m_Calced = false;
|
|
|
|
{
|
|
hackflag = false;
|
|
top:
|
|
int count = 0;
|
|
|
|
while (!done)
|
|
{
|
|
count++;
|
|
if (count > GRIDMOVE_FAIL_THRESHOLD)
|
|
break;
|
|
if (!calc.size ())
|
|
break;
|
|
temp = calc.ExtractMin ();
|
|
if (temp == end)
|
|
{
|
|
done = true;
|
|
break;
|
|
}
|
|
int cost;
|
|
|
|
cost = Cost (temp);
|
|
for (i=0;i<SIZEDELTA;i++)
|
|
{
|
|
int newcost;
|
|
int newx,newy;
|
|
|
|
newx = temp.locX+delta[i][0];
|
|
newy = temp.locY+delta[i][1];
|
|
if (!m_Graph->MoveTo (newx,newy,i,m_Mask))
|
|
continue;
|
|
int updown = m_Graph->UpDownTo (newx,newy,delta[i][3],m_Mask);
|
|
if (updown == 0)
|
|
{
|
|
newcost = delta[i][4];
|
|
}
|
|
else if (updown == 1)
|
|
{
|
|
if (delta[i][4] == 10)
|
|
newcost = 14;
|
|
else
|
|
newcost = 21;
|
|
}
|
|
else
|
|
{
|
|
if (delta[i][4] == 10)
|
|
newcost = 13;
|
|
else
|
|
newcost = 19;
|
|
}
|
|
newcost += cost;
|
|
newcost += AdjustCost (newx,newy);
|
|
if (Cost (newx,newy,(unsigned int) newcost,(unsigned int) CostGuess (newx,newy)))
|
|
{
|
|
GridPathElement newelement(newx,newy);
|
|
if (calc.Member (newelement))
|
|
calc.DecreaseKey (newelement);
|
|
else
|
|
calc.Insert (newelement);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!done && (count > GRIDMOVE_FAIL_THRESHOLD)) // check for can continue work later
|
|
{
|
|
m_WorkCount += count;
|
|
if (m_WorkCount > GRIDMOVE_MAX_CHECK_THRESHOLD)
|
|
{
|
|
calc.clear ();
|
|
m_Calced = false;
|
|
g_PathManager->m_FailedCalcFrame = true;
|
|
Set_Statistic(FailedPath_Calcs_Count, FailedPath_Calcs_Count+1);
|
|
m_Working = false;
|
|
}
|
|
return;
|
|
}
|
|
else if (!done) // visited all possible cells
|
|
{
|
|
calc.clear ();
|
|
m_Calced = false;
|
|
g_PathManager->m_FailedCalcFrame = true;
|
|
Set_Statistic(FailedPath_Calcs_Count, FailedPath_Calcs_Count+1);
|
|
m_Working = false;
|
|
return;
|
|
}
|
|
|
|
calc.clear ();
|
|
done = false;
|
|
GridPathElement cur;
|
|
int min;
|
|
unsigned int mincost;
|
|
int newx,newy;
|
|
int lastdir = -1;
|
|
GridPathElement start(startx,starty);
|
|
int t;
|
|
Stuff::Scalar dirdist = 0;
|
|
|
|
cur.locX = endx;
|
|
cur.locY = endy;
|
|
m_DirList.push_back (DirElement (cur.locX,cur.locY));
|
|
|
|
min = NULL;
|
|
count=0;
|
|
while (!done)
|
|
{
|
|
#if 1
|
|
count++;
|
|
if (count > (GRIDMOVE_MAX_CHECK_THRESHOLD/2))
|
|
{
|
|
Set_Statistic(FailedPath_Calcs_Count, FailedPath_Calcs_Count+1);
|
|
m_Calced = false;
|
|
g_PathManager->m_FailedCalcFrame = true;
|
|
break;
|
|
}
|
|
#endif
|
|
min = 0;
|
|
newx = cur.locX + delta[min][0];
|
|
newy = cur.locY + delta[min][1];
|
|
mincost = Cost (newx,newy);
|
|
for (i=1;i<SIZEDELTA;i++)
|
|
{
|
|
if ((newx == startx) && (newy == starty))
|
|
{
|
|
min = i-1;
|
|
mincost = 1;
|
|
break;
|
|
}
|
|
newx = cur.locX + delta[i][0];
|
|
newy = cur.locY + delta[i][1];
|
|
t= Cost (newx,newy);
|
|
|
|
if (((t < mincost) && (t != 0)) || (mincost == 0))
|
|
{
|
|
mincost = t;
|
|
min = i;
|
|
}
|
|
}
|
|
if (mincost == 0)
|
|
{
|
|
min = 0;
|
|
newx = cur.locX + delta[min][0];
|
|
newy = cur.locY + delta[min][1];
|
|
mincost = Cost (newx,newy);
|
|
for (i=1;i<SIZEDELTA;i++)
|
|
{
|
|
newx = cur.locX + delta[i][0];
|
|
newy = cur.locY + delta[i][1];
|
|
t= Cost (newx,newy);
|
|
|
|
if (((t < mincost) && (t != 0)) || (mincost == 0))
|
|
{
|
|
mincost = t;
|
|
min = i;
|
|
}
|
|
}
|
|
}
|
|
Verify (mincost != 0);
|
|
cur.locX+=delta[min][0];
|
|
cur.locY+=delta[min][1];
|
|
dirdist += BLOCK_GRID_RES;
|
|
bool dirflag = false;
|
|
if (lastdir != min)
|
|
{
|
|
dirdist = 0;
|
|
m_DirList.push_back (DirElement (cur.locX,cur.locY));
|
|
dirflag = true;
|
|
lastdir = min;
|
|
}
|
|
if (cur == start)
|
|
{
|
|
if (!dirflag)
|
|
m_DirList.push_back (DirElement (cur.locX,cur.locY));
|
|
done = true;
|
|
m_Calced = true;
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
if (!m_Calced)
|
|
{
|
|
STOP (("should not get here. have already created costs from start to end"));
|
|
Set_Statistic(FailedPath_Calcs_Count, FailedPath_Calcs_Count+1);
|
|
g_PathManager->m_FailedCalcFrame = true;
|
|
m_Working = false;
|
|
return;
|
|
}
|
|
ReverseList ();
|
|
// SmoothList ();
|
|
Verify (m_DirList.size () >= 2);
|
|
m_InDirPath = m_DirList.begin ();
|
|
if (m_InDirPath != m_DirList.end ())
|
|
{
|
|
m_InDirPath++;
|
|
}
|
|
m_Calced = true;
|
|
m_Working = false;
|
|
}
|
|
|
|
void CGridPath::ContinueCalcPath (void)
|
|
{
|
|
Verify (m_Working);
|
|
Verify (m_WorkingPath == this);
|
|
if (m_TenMeterAllowed)
|
|
{
|
|
Calc10Path ();
|
|
}
|
|
else
|
|
{
|
|
Calc30Path ();
|
|
}
|
|
}
|
|
|
|
void CGridPath::DoCalcPath (void)
|
|
{
|
|
if (m_Working)
|
|
{
|
|
Verify (m_WorkingPath == this);
|
|
ContinueCalcPath ();
|
|
}
|
|
else
|
|
{
|
|
StartCalcPath ();
|
|
}
|
|
if (!m_Working)
|
|
m_WorkingPath = NULL;
|
|
}
|
|
|
|
void CGridPath::StartCalcPath (void)
|
|
{
|
|
Verify (m_Graph);
|
|
GridPathElement temp;
|
|
int startx,starty,endx,endy;
|
|
AutoHeap local_heap (g_RailHeap);
|
|
|
|
Verify (!m_Working);
|
|
Verify (m_WorkingPath == NULL);
|
|
PATH_LOGIC("CalcPath");
|
|
#if !defined(NO_TIMERS)
|
|
my_AutoTimer fred ((void *) &tGridPathTime);
|
|
#endif
|
|
Set_Statistic(GridPath_Calcs_Count, GridPath_Calcs_Count+1);
|
|
|
|
m_QuickValid = false;
|
|
|
|
startx = m_StartX/BLOCK_GRID_RES;
|
|
starty = m_StartY/BLOCK_GRID_RES;
|
|
endx = m_EndX/BLOCK_GRID_RES;
|
|
endy = m_EndY/BLOCK_GRID_RES;
|
|
if ((startx == endx) && (starty == endy))
|
|
{
|
|
m_Calced = true;
|
|
m_QuickValid = true;
|
|
return;
|
|
}
|
|
|
|
Point3D srcpt,destpt,extra;
|
|
|
|
destpt.x = (float) m_EndX;
|
|
destpt.z = (float) m_EndY;
|
|
srcpt.x = (float) m_StartX;
|
|
srcpt.z = (float) m_StartY;
|
|
destpt.y = 0;
|
|
srcpt.y = 0;
|
|
extra = m_Graph->PullPointElementMask (srcpt,destpt,m_Mask);
|
|
if (extra == Point3D (-1,-1,-1))
|
|
{
|
|
Set_Statistic(FailedPath_Calcs_Count, FailedPath_Calcs_Count+1);
|
|
m_Calced = false;
|
|
g_PathManager->m_FailedCalcFrame = true;
|
|
return;
|
|
}
|
|
m_EndX = (int) extra.x;
|
|
m_EndY = (int) extra.z;
|
|
endx = (int) (m_EndX / BLOCK_GRID_RES);
|
|
endy = (int) (m_EndY / BLOCK_GRID_RES);
|
|
if ((startx == endx) && (starty == endy))
|
|
{
|
|
m_Calced = true;
|
|
m_QuickValid = true;
|
|
return;
|
|
}
|
|
if (m_Graph->QuickCheck (m_StartX,m_StartY,m_EndX,m_EndY,m_Mask,!m_TenMeterAllowed))
|
|
{
|
|
Set_Statistic(QuickPath_Calcs_Count, QuickPath_Calcs_Count+1);
|
|
m_QuickValid = true;
|
|
m_Calced = true;
|
|
return;
|
|
}
|
|
|
|
memset (m_BlockGrid,0,sizeof (unsigned int) * BLOCK_GRID_SIZE * BLOCK_GRID_SIZE * 2);
|
|
|
|
int dx,dy;
|
|
dx = startx>endx ? startx - endx : endx - startx;
|
|
dy = starty>endy ? starty - endy : endy - starty;
|
|
|
|
if (dx >= BLOCK_GRID_SIZE)
|
|
{
|
|
Set_Statistic(FailedPath_Calcs_Count, FailedPath_Calcs_Count+1);
|
|
m_Calced = false;
|
|
g_PathManager->m_FailedCalcFrame = true;
|
|
return;
|
|
}
|
|
if (dy >= BLOCK_GRID_SIZE)
|
|
{
|
|
Set_Statistic(FailedPath_Calcs_Count, FailedPath_Calcs_Count+1);
|
|
m_Calced = false;
|
|
g_PathManager->m_FailedCalcFrame = true;
|
|
return;
|
|
}
|
|
|
|
m_BlockOriginX = startx - ((BLOCK_GRID_SIZE - dx) >> 1);
|
|
m_BlockOriginY = starty - ((BLOCK_GRID_SIZE - dy) >> 1);
|
|
if (m_BlockOriginX < MinX)
|
|
m_BlockOriginX = (int) MinX;
|
|
if (m_BlockOriginY < MinZ)
|
|
m_BlockOriginY = (int) MinZ;
|
|
|
|
if (m_BlockOriginX >= (MaxX - BLOCK_GRID_SIZE))
|
|
m_BlockOriginX = (int) ( MaxX - BLOCK_GRID_SIZE - 1);
|
|
if (m_BlockOriginY >= (MaxZ - BLOCK_GRID_SIZE))
|
|
m_BlockOriginY = (int) ( MaxZ - BLOCK_GRID_SIZE-1 - 1);
|
|
|
|
Cost (startx,starty,1,(unsigned short) CostGuess (startx,starty));
|
|
calc.Insert (GridPathElement (startx,starty));
|
|
|
|
m_WorkingPath = this;
|
|
m_WorkCount = 0;
|
|
m_Working = true;
|
|
ContinueCalcPath ();
|
|
}
|
|
|
|
void CGridPath::SmoothListHelper (stlport::vector<DirElement>& vec,int s,int e)
|
|
{
|
|
int x1,x2,y1,y2,middle;
|
|
|
|
AutoHeap local_heap (g_RailHeap);
|
|
x1 = m_DirList[s].locX;
|
|
y1 = m_DirList[s].locY;
|
|
x2 = m_DirList[e].locX;
|
|
y2 = m_DirList[e].locY;
|
|
if (s >= e)
|
|
{
|
|
vec.push_back (DirElement (x1,y1));
|
|
vec.push_back (DirElement (x2,y2));
|
|
return;
|
|
}
|
|
Verify (e<m_DirList.size ());
|
|
|
|
if (m_Graph->QuickCheck (x1,y1,x2,y2,m_Mask,!m_TenMeterAllowed))
|
|
{
|
|
vec.push_back (DirElement (x2,y2));
|
|
return;
|
|
}
|
|
middle = s+e;
|
|
middle >>= 1;
|
|
SmoothListHelper (vec,s,middle);
|
|
SmoothListHelper (vec,middle+1,e);
|
|
|
|
}
|
|
|
|
void CGridPath::SmoothList (void)
|
|
{
|
|
stlport::vector<DirElement> newlist;
|
|
int middle;
|
|
AutoHeap local_heap (g_RailHeap);
|
|
|
|
if (m_DirList.size () <=2 )
|
|
return;
|
|
|
|
newlist.clear ();
|
|
middle = m_DirList.size ();
|
|
middle >>= 1;
|
|
|
|
newlist.push_back (m_DirList[0]);
|
|
SmoothListHelper (newlist,0,middle-1);
|
|
SmoothListHelper (newlist,middle,m_DirList.size ()-1);
|
|
m_DirList = newlist;
|
|
}
|
|
|
|
void CGridPath::ReverseList (void)
|
|
{
|
|
stlport::vector<DirElement>::iterator s,e;
|
|
AutoHeap local_heap (g_RailHeap);
|
|
|
|
s = m_DirList.begin ();
|
|
e = m_DirList.end ();
|
|
stlport::reverse (s,e);
|
|
}
|
|
|
|
|