#include "MW4Headers.hpp" #include "server\comline.hpp" #include "adept\application.hpp" #include "rail_move.hpp" #include "move_rect.hpp" #include "ai.hpp" #pragma warning (push) #include #include #pragma warning (pop) namespace MechWarrior4 { extern DWORD Path_Calcs_Count; extern DWORD GridPath_Calcs_Count; extern DWORD QuickPath_Calcs_Count; extern DWORD QuickRail_Calcs_Count; } namespace MW4AI { extern __int64 tCalcPathTime; extern __int64 tQuickCheckTime; extern __int64 tCreatePathRequestsTime; extern __int64 tPathCalc1Time; extern __int64 tPathCalc2Time; extern __int64 tNodeToPathTime; }; using namespace MW4AI; using namespace MechWarrior4; CRailPath::CRailPath (CRailGraph *graph,MoverAI *ai) : m_Start(-1,-1,-1) , m_End(-1,-1,-1) { m_SubPathRequest = NULL; m_NearLastFrame = false; m_TenMeterAllowed = false; m_AI = ai; m_SubPath = NULL; m_Graph = graph; m_Strict = false; m_StartNode = NULL; m_EndNode = NULL; m_Calced = false; m_InNodePath = 0; m_Path.clear (); m_NodePath.clear (); m_InPath = m_Path.begin ();; } CRailPath::CRailPath (CRailGraph *graph,const Stuff::Point3D& start,const Stuff::Point3D& end,bool strict,MoverAI *ai,bool tenmeter) : m_Start(start) , m_End(end) { m_NearLastFrame = false; m_TenMeterAllowed = tenmeter; m_AI = ai; m_SubPathRequest = NULL; m_SubPath = NULL; m_Graph = graph; m_Strict = strict; m_Graph->FindBestNode (m_Start,m_End,false,m_StartNode,m_EndNode); m_Calced = false; m_InNodePath = 0; m_Path.clear (); m_NodePath.clear (); m_InPath = m_Path.begin ();; } CRailPath::CRailPath (CRailGraph *graph,CRailNode *start,CRailNode *end,MoverAI *ai,bool tenmeter) { m_NearLastFrame = false; m_TenMeterAllowed = tenmeter; m_AI = ai; m_SubPathRequest = NULL; m_SubPath = NULL; m_Graph = graph; m_StartNode = start; m_EndNode = end; m_Strict = true; m_Start = m_StartNode->Location (); m_End = m_EndNode->Location (); m_Calced = false; m_InNodePath = 0; m_Path.clear (); m_NodePath.clear (); m_InPath = m_Path.begin (); // m_GridRequests.clear (); } CRailPath::~CRailPath (void) { m_NodePath.clear (); m_Path.clear (); delete m_SubPath; m_SubPath = NULL; delete m_SubPathRequest; m_SubPathRequest = NULL; } void CRailPath::UpdateSrcDest (CRailNode *src,CRailNode *dest) { Verify (dest); m_StartNode = src; m_EndNode = dest; m_End = m_EndNode->Location (); m_Start = m_StartNode->Location (); } void CRailPath::UpdateSrcDest (const Stuff::Point3D& src,const Stuff::Point3D& dest) { m_Start = src; m_End = dest; m_Graph->FindBestNode (m_Start,m_End,false,m_StartNode,m_EndNode); } void CRailPath::Save (MemoryStream *stream) { stlport::vector::iterator iter1; stlport::vector::iterator iter2; *stream << m_TenMeterAllowed; *stream << m_Start; *stream << m_End; *stream << m_HeadPoint; *stream << m_UsageAllowed; *stream << m_Calced; *stream << m_Strict; if (m_StartNode) { *stream << true; *stream << m_StartNode->ID (); } else *stream << false; if (m_EndNode) { *stream << true; *stream << m_EndNode->ID (); } else *stream << false; *stream << m_InNodePath; *stream << ((int) m_State); *stream << m_NodePath.size (); *stream << m_Path.size (); int count; for (iter2 = m_Path.begin (),count = 0;(iter2 != m_Path.end ()) && (m_InPath != iter2);iter2++,count++); *stream << count; for (iter1 = m_NodePath.begin ();iter1 != m_NodePath.end ();iter1++) { iter1->Save (stream); } for (iter2 = m_Path.begin ();iter2 != m_Path.end ();iter2++) { iter2->Save (stream); } } void CRailPath::Load (MemoryStream *stream) { bool flag; int temp; int size1,size2; *stream >> m_TenMeterAllowed; *stream >> m_Start; *stream >> m_End; *stream >> m_HeadPoint; *stream >> m_UsageAllowed; *stream >> m_Calced; *stream >> m_Strict; *stream >> flag; m_StartNode = NULL; if (flag) { int id; *stream >> id; m_StartNode = m_Graph->Node (id); } *stream >> flag; m_EndNode = NULL; if (flag) { int id; *stream >> id; m_EndNode = m_Graph->Node (id); } *stream >> m_InNodePath; *stream >> temp; m_State = (PATHSTATES) temp; *stream >> size1; *stream >> size2; int count,i; *stream >> count; m_NodePath.assign (size1,NodePathElement ()); for (i=0;i> loc; *stream >> usage; *stream >> onrail; *stream >> linkid; } void CRailPath::NodePathElement::Save (MemoryStream *stream) { *stream << usage; if (link) { *stream << true; *stream << link->ID (); } else *stream << false; if (destnode) { *stream << true; *stream << destnode->ID (); } else *stream << false; } void CRailPath::NodePathElement::Load (MemoryStream *stream) { bool flag; int id; *stream >> usage; destnode = NULL; link = NULL; *stream >> flag; if (flag) { *stream >> id; link = g_MissionGraph->Link (id); } *stream >> flag; if (flag) { *stream >> id; destnode = g_MissionGraph->Node (id); } } float CRailPath::CostGuess (CRailNode *src) { Stuff::Point3D start; Stuff::Point3D end; start = src->Location (); end = m_End; float t1,t2; t1 = end.x - start.x; t2 = end.z - start.z; t1 = t1<0 ? t1*-1.0f : t1; t2 = t2<0 ? t2*-1.0f : t2; return 0; // return t2 < t1 ? (t1+(t2/2.0f)) : (t2+(t1/2.0f)); } void CRailPath::CalcOutVec (Stuff::Point3D& outvec) { outvec = NextPoint (); // outvec = Stuff::Point3D (-1,-1,-1); } bool CRailPath::NewSubPath (const Stuff::Point3D& loc) { if (m_InPath == m_Path.end ()) return false; int mask=0; if (m_InPath->usage & JUMPFLAG) { Verify (!m_SubPathRequest); return true; } if (m_InPath->onrail) { Verify (!m_SubPathRequest); return true; } delete m_SubPath; m_SubPath = NULL; if (m_SubPathRequest) { m_SubPath = m_SubPathRequest->GridPath (); if (!m_SubPathRequest->Done ()) { return true; } m_SubPathRequest->DetachGridPath (); delete m_SubPathRequest; m_SubPathRequest = NULL; if (!m_SubPath->Calced ()) { if (m_InPath->linkid != -1) m_Graph->DeleteLink (m_InPath->linkid); delete m_SubPath; m_SubPath = NULL; m_Calced = false; return false; } if (m_SubPath->QuickValid ()) { delete m_SubPath; m_SubPath = NULL; } } else { mask = ConvertUsagetoMovePass (m_InPath->usage); m_SubPathRequest = g_PathManager->AddRequest (gos_GetElapsedTime (),m_Graph,(unsigned short) mask,loc.x,loc.z,m_InPath->loc.x,m_InPath->loc.z,m_AI,m_TenMeterAllowed); return true; #if 0 gos_PushCurrentHeap (g_RailHeap); m_SubPath = new CGridPath (m_Graph,(unsigned short) mask,loc.x,loc.z,m_InPath->loc.x,m_InPath->loc.z,m_TenMeterAllowed); gos_PopCurrentHeap (); Verify (m_SubPath); m_SubPath->CalcPath(); #endif } #if 0 if (!m_SubPath->Calced ()) { if (m_InPath->linkid != -1) m_Graph->DeleteLink (m_InPath->linkid); delete m_SubPath; m_SubPath = NULL; m_Calced = false; return false; } if (m_SubPath->QuickValid ()) { delete m_SubPath; m_SubPath = NULL; } #endif return true; } bool CRailPath::Next (const Stuff::Point3D& loc) { if (m_SubPath) { if (m_SubPath->Next ()) { return true; } delete m_SubPath; m_SubPath = NULL; if (m_InPath != m_Path.end ()) { m_InPath++; return NewSubPath (loc); } } if (m_InPath != m_Path.end ()) { m_InPath++; return NewSubPath (loc); } return false; } Stuff::Point3D CRailPath::CurrentPoint (void) const { if (!m_Calced) return Stuff::Point3D (-1,-1,-1); if (m_State == RAIL_FINISH) return Stuff::Point3D (-1,-1,-1); if (m_InPath == m_Path.end () && (m_SubPath == NULL)) return Stuff::Point3D (-1,-1,-1); if (m_SubPath) return m_SubPath->CurrentPoint (); else return m_InPath->loc; } bool CRailPath::PointBehind (const Stuff::Point3D& loc,const Stuff::Point3D& dest) { Stuff::Point3D nextdest,destextra,nextdestextra; Scalar dist1,dist2,dot; nextdest = NextPoint (); if (nextdest == Point3D (-1,-1,-1)) return false; int x,y,mask; x = (int) (loc.x/10); y = (int) (loc.z/10); mask = ConvertUsagetoMovePass (m_UsageAllowed&(~JUMPFLAG)); if ((!m_Graph->MoveTo (x+1,y,0,mask)) || (!m_Graph->MoveTo (x-1,y,0,mask)) || (!m_Graph->MoveTo (x,y-1,0,mask)) || (!m_Graph->MoveTo (x,y+1,0,mask))) { return false; } destextra.Subtract (dest,loc); dist1 = destextra.GetLengthSquared (); nextdestextra.Subtract (nextdest,loc); dist2 = nextdestextra.GetLengthSquared (); if (dist2 < dist1) return true; dot = (nextdestextra.x*destextra.x) + (nextdestextra.z*destextra.z); dot /= (nextdestextra.GetLength () * destextra.GetLength ()); if ((m_Graph->Passable (loc.x,loc.z) & BRIDGE_FLAG) && (dot <= 0.0f)) return true; if ((dot <= 0.0f) && (dist1 < 400)) return true; return false; } void CRailPath::PointList (stlport::vector& dest) { dest.clear (); if (!m_Calced) return; if (m_InPath == m_Path.end () && (m_SubPath == NULL)) return; gos_PushCurrentHeap (g_RailHeap); if (m_SubPath) { m_SubPath->PointList (dest); } stlport::vector::iterator iter; for (iter = m_InPath;iter != m_Path.end ();iter++) { dest.push_back (iter->loc); } gos_PopCurrentHeap (); } void CRailPath::Tick (const Stuff::Point3D& loc,Stuff::Time till,Stuff::Scalar speed,Stuff::Point3D& outvec,bool& jump,bool& prejump) { m_HeadPoint = Stuff::Point3D (-1,-1,-1); Verify (m_Calced); jump = false; prejump = false; if (m_State == RAIL_FINISH) return; if (m_SubPathRequest) { if (m_SubPathRequest->Done ()) { m_SubPath = m_SubPathRequest->DetachGridPath (); delete m_SubPathRequest; m_SubPathRequest = NULL; if (!m_SubPath->Calced ()) { if (m_InPath->linkid != -1) m_Graph->DeleteLink (m_InPath->linkid); delete m_SubPath; m_SubPath = NULL; m_Calced = false; m_State = RAIL_FINISH; return; } if (m_SubPath->QuickValid ()) { delete m_SubPath; m_SubPath = NULL; } } else { m_State = RAIL_MOVE_WAITING; return; } } m_State = RAIL_MOVE_ENDPOINT; CalcOutVec (outvec); Stuff::Point3D destloc,extra,fakeloc; Stuff::Scalar dist,move; destloc = CurrentPoint (); destloc.y = 0; fakeloc = loc; fakeloc.y = 0; extra.Subtract (destloc,fakeloc); dist = extra.GetLengthSquared (); if (speed < 0) move = (float) (speed * till * 6); // use 6 frame buffer else move = (float) (speed * till * 6); // use 6 frame buffer move *= move; // if ((dist<49.0) || (dist < move) || PointBehind (loc,destloc)) if (m_NearLastFrame) { m_NearLastFrame = false; if (!Next (loc)) { m_State = RAIL_FINISH; return; } if (!m_Calced) return; Tick (loc,till,speed,outvec,jump,prejump); return; } #if 1 if ((dist<16.0) || (dist < move) || PointBehind (loc,destloc)) { m_NearLastFrame = true; } #endif m_HeadPoint = CurrentPoint (); destloc = CurrentPoint (); destloc.y = 0; fakeloc = loc; fakeloc.y = 0; extra.Subtract (destloc,fakeloc); dist = extra.GetLengthSquared (); CalcOutVec (outvec); stlport::vector::iterator iter; iter = m_InPath; if (m_InPath != m_Path.end ()) iter++; if (m_InPath->usage & JUMPFLAG) jump = true; else jump = false; if ((iter != m_Path.end ()) && (iter->usage & JUMPFLAG)) prejump = true; bool flag = false; if ((!m_SubPath) && (iter == m_Path.end () && (m_State != RAIL_FINISH))) flag = true; if ((m_SubPath) && (iter == m_Path.end () && (m_State != RAIL_FINISH))) { if (m_SubPath->OneFromEnd ()) flag = true; } } bool CRailGraph::PointOpen (Scalar x,Scalar y,int movepass) { const int SIZEDELTA = 8; int delta[SIZEDELTA][2] = { {-1*BLOCK_GRID_RES,0*BLOCK_GRID_RES}, {0*BLOCK_GRID_RES,-1*BLOCK_GRID_RES}, {1*BLOCK_GRID_RES,0*BLOCK_GRID_RES}, {0*BLOCK_GRID_RES,1*BLOCK_GRID_RES}, #if 1 {-1*BLOCK_GRID_RES,-1*BLOCK_GRID_RES}, {-1*BLOCK_GRID_RES,1*BLOCK_GRID_RES}, {1*BLOCK_GRID_RES,-1*BLOCK_GRID_RES}, {1*BLOCK_GRID_RES,1*BLOCK_GRID_RES} #endif }; int i; if (CheckCanPass (Passable (x,y),movepass)) return false; for (i=0;i::iterator iter; char text[100]; iter = m_Path.begin (); while (iter != m_Path.end ()) { sprintf (text,"Move Point %f,%f",iter->loc.x,iter->loc.z); COMSPEW (text); iter++; } COMSPEW (""); } void CRailPath::ReverseList (void) { stlport::vector::iterator start,end; // COMSPEW ("reversing path list"); start = m_NodePath.begin (); end = m_NodePath.end (); stlport::reverse (start,end); } void CRailPath::Reverify (int usage) { return; #if 0 if (!m_QuickPath) return; unsigned short usa = (unsigned short) (m_UsageAllowed&(~JUMPFLAG)); if (m_Graph->QuickCheck ((int) m_Start.x,(int) m_Start.z,(int) m_End.x,(int) m_End.z,(unsigned short) ConvertUsagetoMovePass (usa))) return; m_Calced = false; m_NodePath.clear (); m_Path.clear (); CalcPath (usage); #endif } void CRailPath::CalcPath (int usage) { PATH_LOGIC("Calc"); TIME_FUNCTION(tCalcPathTime); Verify (m_Graph); int i; int type; my_heap calc; CRailNode *temp; bool done; Scalar dist; Point3D extra; m_NearLastFrame = false; m_SubPathRequest = NULL; Set_Statistic(Path_Calcs_Count, Path_Calcs_Count+1); // usage &= ~JUMPFLAG; Verify (m_Graph->CountNodes ()); Verify (m_Graph->CountLinks ()); Verify (usage >0); m_UsageAllowed = usage & (~JUMPFLAG); AutoHeap local_heap (g_RailHeap); unsigned short usa = (unsigned short) (m_UsageAllowed&(~JUMPFLAG)); extra = m_Graph->PullPointElement (m_Start,m_End,usa); if (extra == Point3D (-1,-1,-1)) { m_Calced = false; return; } m_End = extra; m_QuickPath = false; if (m_Graph->QuickCheck ((int) m_Start.x,(int) m_Start.z,(int) m_End.x,(int) m_End.z,(unsigned short) ConvertUsagetoMovePass (usa))) { Set_Statistic(QuickRail_Calcs_Count, QuickRail_Calcs_Count+1); m_Calced = true; m_Path.push_back (PathElement (m_Start,usa,false,-1)); m_Path.push_back (PathElement (m_End,usa,true,-1)); m_InPath = m_Path.begin (); m_QuickPath = true; return; } if ((m_StartNode == NULL) || (m_EndNode == NULL)) { m_Calced = false; m_State = RAIL_START_PATH; return; } m_Start.y = m_End.y = 0; extra.Subtract (m_Start,m_End); dist = extra.GetLengthSquared (); if ((m_StartNode == m_EndNode) || ((dist < (250.0f*250.0f)) && (!m_Graph->BridgeNear (m_Start,m_End)))) { m_Calced = true; m_Path.push_back (PathElement (m_Start,usa,false,-1)); Point3D temp; temp = m_Graph->PullPointElement (m_Start,m_End,usa); if (temp != Point3D (-1,-1,-1)) { m_Path.push_back (PathElement (temp,usa,false,-1)); m_InPath = m_Path.begin (); m_InPath++; gos_PushCurrentHeap (g_RailHeap); unsigned short mask = (unsigned short) ConvertUsagetoMovePass (m_InPath->usage); m_SubPath = new CGridPath (m_Graph,mask,m_Start.x,m_Start.z,m_End.x,m_End.z,m_TenMeterAllowed); gos_PopCurrentHeap (); Verify (m_SubPath); m_SubPath->DoCalcPath(); if (m_SubPath->Calced ()) { if (m_SubPath->QuickValid ()) { delete m_SubPath; m_SubPath = NULL; m_Calced = true; m_Path.clear (); m_Path.push_back (PathElement (m_Start,usa,false,-1)); m_Path.push_back (PathElement (m_End,usa,false,-1)); m_InPath = m_Path.begin (); m_QuickPath = true; return; } return; } else if (m_StartNode == m_EndNode) { delete m_SubPath; m_SubPath = NULL; CreatePathRequests (); return; } else { m_Calced = false; delete m_SubPath; m_SubPath = NULL; } #if 0 if ((m_Calced) || (m_StartNode == m_EndNode)) { Set_Statistic(QuickRail_Calcs_Count, QuickRail_Calcs_Count+1); m_QuickPath = true; return; } #endif } else m_Calced = false; if (m_StartNode == m_EndNode) { m_QuickPath = true; m_State = RAIL_FINISH; m_Calced = true; m_Path.push_back (PathElement (m_End,usa,false,-1)); m_InPath = m_Path.end (); return; } } m_Graph->ClearPathFlags (); m_StartNode->PathWeight (1,CostGuess (m_EndNode),usa); calc.Insert (m_StartNode); done = false; m_Calced = false; int count = 0; { PATH_LOGIC("RailPath phase 1"); TIME_FUNCTION(tPathCalc1Time); { while (!done) { count++; if (count > (m_Graph->NumNodes ()*2)) { break; } if (!calc.size ()) break; temp = calc.ExtractMin (); if (temp == NULL) break; if (temp == m_EndNode) { done = true; break; } int size; float cost; cost = temp->PathWeight (); size = temp->NumLinks (); for (i=0;iLink (i); dest = curlink->OtherLocation (temp); newcost = curlink->LowestWeight (usage,type,temp); if (newcost == -1) continue; if (type == 0) continue; newcost += cost; if (dest->PathWeight (newcost,CostGuess (dest),type)) { if (calc.Member (dest)) calc.DecreaseKey (dest); else calc.Insert (dest); } } } } if (!done) return; done = false; CRailNode *cur; int min; float mincost; cur = m_EndNode; min = NULL; count =0; { PATH_LOGIC("RailPath phase 2"); TIME_FUNCTION(tPathCalc2Time); { while (!done) { count++; if (count > (m_Graph->NumNodes ()*2)) { m_Calced = false; return; } min = 0; mincost = cur->Link (min)->OtherLocation (cur)->PathWeight (); if (cur->Link (min)->LowestWeight (usage,type,cur->Link (min)->OtherLocation (cur)) == -1.0f) mincost = 0; for (i=1;iNumLinks ();i++) { float t; t= cur->Link (i)->OtherLocation (cur)->PathWeight (); if (cur->Link (i)->LowestWeight (usage,type,cur->Link (i)->OtherLocation (cur)) == -1.0f) t = 0; if (((t < mincost) && (t != 0)) || (mincost == 0)) { mincost = t; min = i; } } m_NodePath.push_back (NodePathElement (cur->Link (min),cur,cur->PathType ())); cur = cur->Link (min)->OtherLocation (cur); if (cur == m_StartNode) { int fred = 0; if (usage & LEGFLAG) fred = LEGFLAG; else if (usage & JUMPFLAG) fred = JUMPFLAG; else if (usage & TRACKFLAG) fred = TRACKFLAG; else if (usage & WHEELFLAG) fred = WHEELFLAG; else if (usage & FLYFLAG) fred = FLYFLAG; else if (usage & HOVERFLAG) fred = HOVERFLAG; else if (usage & HELIFLAG) fred = HELIFLAG; else if (usage & WATERFLAG) fred = WATERFLAG; #if defined(LAB_ONLY) else PAUSE (("unknown movetype in calcpath")); #endif m_NodePath.push_back (NodePathElement (NULL,cur,fred)); ReverseList (); done = true; continue; } } } } m_Calced = true; m_State = RAIL_START_PATH; m_HeadPoint = Stuff::Point3D (-1,-1,-1); m_InNodePath = 0; ConvertNodeToPath (); if (m_Calced) CreatePathRequests (); } } void CRailPath::CreatePathRequests (void) { TIME_FUNCTION(tCreatePathRequestsTime); if (m_Calced) NewSubPath (m_Start); }