#include "MW4Headers.hpp" #include "server\comline.hpp" #include "adept\application.hpp" #include "rail_move.hpp" #include "ai.hpp" #pragma warning (push) #include #include #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::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;iReadBytes (&(m_DirList[i]),sizeof (DirElement)); } m_InDirPath = m_DirList.begin (); m_InDirPath += count; } void CGridPath::PointList (stlport::vector& dest) { stlport::vector::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::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;iMoveTo (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;iMoveTo (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;im_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;iMoveTo (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;im_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& 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 (eQuickCheck (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 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::iterator s,e; AutoHeap local_heap (g_RailHeap); s = m_DirList.begin (); e = m_DirList.end (); stlport::reverse (s,e); }