#include "MW4Headers.hpp" #include "adept\application.hpp" #include "rail_move.hpp" //#include "quadedge.h" #include #include #include #include #include #include "path.hpp" #include "bridge.hpp" #include "cultural.hpp" #include "mwplayer.hpp" #include "move_rect.hpp" #include "windows.h" #include "shooterai.hpp" #pragma warning (push) #include #include #pragma warning (pop) using namespace MW4AI; using namespace MechWarrior4; using namespace ElementRenderer; #define BADSLOPE 0.707f namespace MW4AI { void GetMapData(Stuff::Scalar x, Stuff::Scalar z,CRailSquare *who) // void GetMapData(Stuff::Scalar x, Stuff::Scalar z,Stuff::Scalar &y,Normal3D& normal,BYTE& material,int& objectid) { Stuff::Scalar i,j; Stuff::Line3D line; Point3D point; Stuff::Scalar water_depth=0.0f; who->normal.x = FLT_MAX; who->normal.y = FLT_MAX; who->normal.z = FLT_MAX; for (i=-5.0f;i<=5.0f;i+=1.0f) { for (j=-5.0f;j<=5.0f;j+=1.0f) { point.x = x+i; point.z = z+j; point.y = 800.0f; line.m_length = 1000.0f; line.m_direction = Vector3D::Down; line.SetOrigin(point); // // Prepare query // Stuff::Normal3D inormal; Stuff::Line3D iline; Stuff::Normal3D fred; Entity::CollisionQuery *query; // // Cast ray for map surface // query = new Entity::CollisionQuery (&line, &fred, Entity::CanBeWalkedOnFlag, NULL); Adept::Entity *entity_hit; Check_Object(CollisionGrid::Instance); entity_hit = CollisionGrid::Instance->ProjectLine(query); if (entity_hit != NULL) { line.FindEnd(&point); who->height = point.y; Check_Object (Map::GetInstance()); Check_Object (Map::GetInstance()->GetGameModel ()); if ((Map::GetInstance()->GetGameModel ()->m_waterLevel - point.y) > water_depth) water_depth = (Map::GetInstance()->GetGameModel ()->m_waterLevel - point.y); who->material = query->m_material; if (query->m_normal->y < who->normal.y) { who->normal.x = query->m_normal->x; who->normal.y = query->m_normal->y; who->normal.z = query->m_normal->z; } Check_Object (&who->normal); } delete query; } } if ((water_depth >= ShallowWaterDepth) && (water_depth < MidWaterDepth)) { who->material = FakeShallowWaterMaterial; } else if ((water_depth >= MidWaterDepth) && (water_depth < DeepWaterDepth)) { who->material = FakeMidWaterMaterial; } else if (water_depth >= DeepWaterDepth) { who->material = FakeOceanicWaterMaterial; } who->objectid = -1; } Stuff::Scalar MinZ, MaxZ, MinX, MaxX; } void CRailNode::CheckRadius() { if (m_Radius < 1.0f) m_Radius = 1.0f; if (m_Location.x < MinX + 5.0f) m_Location.x = MinX + 5.0f; if (m_Location.z < MinZ + 5.0f) m_Location.z = MinZ + 5.0f; if (m_Location.x > MaxX - 5.0f) m_Location.x = MaxX - 5.0f; if (m_Location.z > MaxZ - 5.0f) m_Location.z = MaxZ - 5.0f; if (m_Location.x - m_Radius < MinX) m_Radius = m_Location.x - MinX - 1.0f; if (m_Location.z - m_Radius < MinZ) m_Radius = m_Location.z - MinZ - 1.0f; if (m_Location.x + m_Radius > MaxX) m_Radius = MaxX - m_Location.x - 1.0f; if (m_Location.z + m_Radius > MaxZ) m_Radius = MaxZ - m_Location.z - 1.0f; Verify(m_Radius > 0); } void CRailGraph::CalcEditorDistances (void) { int i,j,size; gos_PushCurrentHeap (g_RailHeap); size = m_Nodes.size (); for (i=0;im_DistanceValid = true; m_Nodes[i]->m_EditorDistance.reserve (size); for (j=0;jm_EditorDistance.push_back (FLT_MAX); } } for (i=0;i<(size-1);i++) { for (j=i+1;jm_EditorDistance[i] = FLT_MAX; continue; } if (!m_Nodes[j]) { m_Nodes[i]->m_EditorDistance[j] = FLT_MAX; continue; } loc1 = m_Nodes[i]->Location (); loc2 = m_Nodes[j]->Location (); loc1.y = 0; loc2.y = 0; extra.Subtract (loc1,loc2); dist = extra.GetLength (); m_Nodes[i]->m_EditorDistance[j] = dist; m_Nodes[j]->m_EditorDistance[i] = dist; } } gos_PopCurrentHeap (); } CRailSquare::CRailSquare (void) { height = 0; material = 0; objectid = -1; objectheight = 1.0f; waterlevel = 0; normal = Normal3D (0,0,1); bridge = -1; } void CRailSquare::Construct (Stuff::Scalar x,Stuff::Scalar z) { // GetMapData (x+5.0f,z+5.0f,height,normal,material,objectid); GetMapData (x+5.0f,z+5.0f,this); #if defined(LAB_ONLY) switch (material) { case WaterMaterial: PAUSE (("ran into a water material, should be a water depth based material")); break; case NoMaterial: case LavaMaterial: case GreyDirtMaterial: case BrownDirtMaterial: case DarkGreyDirtMaterial: case DarkBrownDirtMaterial: case RockMaterial: case DarkRockMaterial: case SteelMaterial: case BlacktopMaterial: case UsMaterial: case ThemMaterial: case GlassMaterial: case GrassMaterial: case WoodMaterial: case ConcreteMaterial: case DarkConcreteMaterial: case SnowMaterial: case FakeShallowWaterMaterial: case FakeMidWaterMaterial: case FakeOceanicWaterMaterial: // MSL 5.03 Lava case LightMineralMaterial: case DarkMineralMaterial: case AshMaterial: case CrackedLavaMaterial: case OpenLavaMaterial: break; default: PAUSE (("ran into an unknown material")); break; } #endif } CRailWorkGrid::CRailWorkGrid (void) { m_Grid.clear (); } void CRailWorkGrid::MarkBuilding (ExtentBox& box,int id,bool bridge,CMoveGrid *movegrid,CAirMoveGrid *airmovegrid,bool walkthruflag) { int x,z; int minx,maxx,minz,maxz; int offx,offz; minx = (int) box.minX; maxx = (int) box.maxX; minz = (int) box.minZ; maxz = (int) box.maxZ; if (minx < MinX) minx = (int) MinX; if (minz < MinZ) minz = (int) MinZ; if (maxx >= (MaxX)) maxx = (int) (MaxX)-1; if (maxz >= (MaxZ)) maxz = (int) (MaxZ)-1; minx /= BLOCK_GRID_RES; maxx /= BLOCK_GRID_RES; minz /= BLOCK_GRID_RES; maxz /= BLOCK_GRID_RES; offx = (int) MinX/BLOCK_GRID_RES; offz = (int) MinZ/BLOCK_GRID_RES; if (bridge) { for (x=minx;x<=maxx;x++) { for (z=minz;z<=maxz;z++) { m_Grid[x-offx][z-offz].objectid = id; if (bridge) m_Grid[x-offx][z-offz].bridge = id; m_Grid[x-offx][z-offz].objectheight = box.maxY; movegrid->PassableLocalOverride (x,z,0); } } if ((maxx-minx) > (maxz-minz)) { for (z=minz;z<=maxz;z++) { movegrid->PassableLocalOverride (minx-3,z,0); movegrid->PassableLocalOverride (maxx+3,z,0); movegrid->PassableLocalOverride (minx-2,z,0); movegrid->PassableLocalOverride (maxx+2,z,0); movegrid->PassableLocalOverride (minx-1,z,0); movegrid->PassableLocalOverride (maxx+1,z,0); } for (x=minx;x<=maxx;x++) { movegrid->PassableLocalOverride (x,minz-2,BLOCKED_FLAGS); movegrid->PassableLocalOverride (x,maxz+2,BLOCKED_FLAGS); movegrid->PassableLocalOverride (x,minz-3,BLOCKED_FLAGS); movegrid->PassableLocalOverride (x,maxz+3,BLOCKED_FLAGS); movegrid->PassableLocalOverride (x,minz-1,BLOCKED_FLAGS); movegrid->PassableLocalOverride (x,maxz+1,BLOCKED_FLAGS); movegrid->PassableLocalOverride (x,minz,BLOCKED_FLAGS); movegrid->PassableLocalOverride (x,maxz,BLOCKED_FLAGS); } } else { for (x=minx;x<=maxx;x++) { movegrid->PassableLocalOverride (x,minz-2,0); movegrid->PassableLocalOverride (x,maxz+2,0); movegrid->PassableLocalOverride (x,minz-3,0); movegrid->PassableLocalOverride (x,maxz+3,0); movegrid->PassableLocalOverride (x,minz-1,0); movegrid->PassableLocalOverride (x,maxz+1,0); } for (z=minz;z<=maxz;z++) { movegrid->PassableLocalOverride (minx-3,z,BLOCKED_FLAGS); movegrid->PassableLocalOverride (maxx+3,z,BLOCKED_FLAGS); movegrid->PassableLocalOverride (minx-2,z,BLOCKED_FLAGS); movegrid->PassableLocalOverride (maxx+2,z,BLOCKED_FLAGS); movegrid->PassableLocalOverride (minx-1,z,BLOCKED_FLAGS); movegrid->PassableLocalOverride (maxx+1,z,BLOCKED_FLAGS); } } } else { for (x=minx;x<=maxx;x++) { for (z=minz;z<=maxz;z++) { m_Grid[x-offx][z-offz].walkthruflag = walkthruflag; m_Grid[x-offx][z-offz].objectid = id; m_Grid[x-offx][z-offz].objectheight = box.maxY - box.minY; } } } } bool CRailWorkGrid::AnalyzeNode (QuadTreeNode *node) { int sx,ex,sy,ey,cx,cy; bool flag; sx = node->Left (); ex = node->Right (); sy = node->Top (); ey = node->Bottom (); flag = false; if (m_Grid[sx][sy].objectid != -1) flag = true; for (cx = sx;cx<=ex;cx++) { for (cy = sy;cy<=ey;cy++) { if (flag) { if (m_Grid[cx][cy].objectid == -1) return true; } else { if (m_Grid[cx][cy].objectid != -1) return true; } } } return false; } bool QuadTree::TraverseFunction (QuadTreeNode *node,int level,DWORD param) { CRailWorkGrid *grid; if (param) { grid = (CRailWorkGrid *) param; if (grid->AnalyzeNode (node)) { node->Subdivide (); } } return true; } void CRailWorkGrid::Construct (WorkCallBack callback,float maxpercent,CMoveGrid *movegrid,CAirMoveGrid *airmovegrid) { int i,j,sizex,sizey; Stuff::Scalar x,z; stlport::vector fred; float curpercent; float dpercent; x = MaxX - MinX; x /= 10.0f; z = MaxZ - MinZ; z /= 10.0f; m_Grid.assign ((int) x,fred); for (i=0;iClear (); airmovegrid->Clear (); for (i=0;iPassableLocalOverride (i+offx,j+offz,SHALLOW_WATER<PassableLocal (i+offx,j+offz,TRACKPASS_FLAG+WHEELPASS_FLAG+WATERPASS_FLAG); break; case FakeMidWaterMaterial: movegrid->PassableLocalOverride (i+offx,j+offz,MEDIUM_WATER<PassableLocal (i+offx,j+offz,TRACKPASS_FLAG+WHEELPASS_FLAG); break; // MSL 5.03 Lava case CrackedLavaMaterial: case OpenLavaMaterial: case FakeOceanicWaterMaterial: movegrid->PassableLocalOverride (i+offx,j+offz,DEEP_WATER<PassableLocal (i+offx,j+offz,LEGPASS_FLAG+TRACKPASS_FLAG+WHEELPASS_FLAG); break; default: movegrid->PassableLocalOverride (i+offx,j+offz,WATERPASS_FLAG); break; } } } UserConstants *constants; constants = UserConstants::Instance (); Check_Pointer (constants); for (i=0;i= -Pi_Over_8) && (nx <= Pi_Over_8)) { movegrid->PassableLocal (i+offx,j+offz,0 << SLOPEDIR_SHIFT); } else if ((nz <= 0) && (nx >= Pi_Over_8) && (nx <= (Pi_Over_2-Pi_Over_8))) { movegrid->PassableLocal (i+offx,j+offz,1 << SLOPEDIR_SHIFT); } else if ((nx >= 0) && (nz>=-Pi_Over_8) && (nz <= Pi_Over_8)) { movegrid->PassableLocal (i+offx,j+offz,2 << SLOPEDIR_SHIFT); } else if ((nz >= 0) && (nx >= Pi_Over_8) && (nx <= (Pi_Over_2-Pi_Over_8))) { movegrid->PassableLocal (i+offx,j+offz,3 << SLOPEDIR_SHIFT); } else if ((nz >= 0) && (nx >= -Pi_Over_8) && (nx <= Pi_Over_8)) { movegrid->PassableLocal (i+offx,j+offz,4 << SLOPEDIR_SHIFT); } else if ((nz >= 0) && (nx <= -Pi_Over_8) && (nx >= (-Pi_Over_2+Pi_Over_8))) { movegrid->PassableLocal (i+offx,j+offz,5 << SLOPEDIR_SHIFT); } else if ((nx <= 0) && (nz>=-Pi_Over_8) && (nz <= Pi_Over_8)) { movegrid->PassableLocal (i+offx,j+offz,6 << SLOPEDIR_SHIFT); } else if ((nz <= 0) && (nx <= -Pi_Over_8) && (nx >= (-Pi_Over_2+Pi_Over_8))) { movegrid->PassableLocal (i+offx,j+offz,7 << SLOPEDIR_SHIFT); } else { STOP (("unknown slope direction value")); } if (ny < constants->Get (UserConstants::leg_down_slope)) { movegrid->PassableLocal (i+offx,j+offz,LEGPASS_FLAG); } if (ny < constants->Get (UserConstants::track_down_slope)) { movegrid->PassableLocal (i+offx,j+offz,TRACKPASS_FLAG); } if (ny < constants->Get (UserConstants::wheel_down_slope)) { movegrid->PassableLocal (i+offx,j+offz,WHEELPASS_FLAG); } if (ny < constants->Get (UserConstants::hover_down_slope)) { if (((movegrid->PassableLocal (i+offx,j+offz) & WATER_MASK) >> WATER_SHIFT) == NO_WATER) { movegrid->PassableLocal (i+offx,j+offz,HOVERPASS_FLAG); } } if ((ny < constants->Get (UserConstants::leg_up_slope)) && (ny > constants->Get (UserConstants::leg_down_slope))) { movegrid->PassableLocal (i+offx,j+offz,LEGDOWN_SLOPE<Get (UserConstants::track_up_slope)) && (ny > constants->Get (UserConstants::track_down_slope))) { movegrid->PassableLocal (i+offx,j+offz,TRACKDOWN_SLOPE<Get (UserConstants::wheel_up_slope)) && (ny > constants->Get (UserConstants::wheel_down_slope))) { movegrid->PassableLocal (i+offx,j+offz,WHEELDOWN_SLOPE<Get (UserConstants::hover_up_slope)) && (ny > constants->Get (UserConstants::hover_down_slope))) { if (((movegrid->PassableLocal (i+offx,j+offz) & WATER_MASK) >> WATER_SHIFT) == NO_WATER) { movegrid->PassableLocal (i+offx,j+offz,HOVERPASS_FLAG); } } } } int tablescan[] = { NameTable::CulturalArray, NameTable::BuildingArray, NameTable::TurretArray, NameTable::VehicleArray }; int size; Scalar maxheight=0; NameTable *table = NameTable::GetInstance(); Check_Object (table); for (i=0;inameTableArray[tablescan[i]].GetLength (); for (j=0;jnameTableArray [tablescan[i]][j]; if (!strnicmp (data->objectName,"water",5)) { continue; } who = data->dataPointer->GetCurrent (); if (!who) continue; if ((!who->GetSolidVolume ()) && (!who->GetHierarchicalVolume ())) continue; OBB *obb; CollisionVolume *col; col = who->GetHierarchicalVolume (); if (!col) col = who->GetSolidVolume (); OBB world_bounds; world_bounds.Multiply(col->m_localSpaceBounds, who->GetLocalToWorld()); obb = &(world_bounds); ExtentBox box (*obb); if (who->IsDerivedFrom (Vehicle::DefaultData)) { if (maxheight < (box.maxY - box.minY)) { maxheight = (box.maxY - box.minY); } } bool walkthruflag = false; { MWObject *obj; obj = Cast_Object (MWObject *,who); if (obj->GetWalkThruType () == Entity::AnythingCanWalkThruType) continue; if ((obj->GetAI ()) && (tablescan[i] == NameTable::VehicleArray)) { if (!obj->GetAI ()->IsDerivedFrom (ShooterAI::DefaultData)) continue; } if (!obj->CanOBBCollide ()) continue; } Point3D loc = (Point3D) obb->localToParent; if (who->IsDerivedFrom (Bridge::DefaultData)) MarkBuilding (box,data->GetObjectID (),true,movegrid,airmovegrid,walkthruflag); else MarkBuilding (box,data->GetObjectID (),false,movegrid,airmovegrid,walkthruflag); } } maxheight += 5.0f; offx = (int) (MinX / BLOCK_GRID_RES); offz = (int) (MinZ / BLOCK_GRID_RES); for (i=0;iPassableLocal (i+offx,j+offx,BRIDGE_FLAG); } else if (m_Grid[i][j].objectid != -1) { // if (!m_Grid[i][j].walkthruflag) movegrid->PassableLocal (i+offx,j+offx,BLOCKED_FLAGS); // else // movegrid->PassableLocal (i+offx,j+offx,0x3e); //mechs can move through if (m_Grid[i][j].objectheight >= maxheight) { airmovegrid->Passable (x,z,AIRPASS_FLAG); } } } } } void CRailGraph::UpdateNodes (WorkCallBack callback,float percentstart) { stlport::vector::iterator iter; int i,size,min; Stuff::Scalar max; float curpercent,dpercent; CreateGrid (callback,80.0f); Check_Pointer (m_WorkGrid); CalcEditorDistances (); curpercent = percentstart; dpercent = 10.0f / m_Nodes.size (); iter = m_Nodes.begin (); while (iter != m_Nodes.end ()) { if (!(*iter)) { iter++; continue; } curpercent += dpercent; if (callback) callback (curpercent); size = (*iter)->m_EditorDistance.size (); min = 0; for (i=1;im_EditorDistance[i] < (*iter)->m_EditorDistance[min]) min = i; } max = (*iter)->m_EditorDistance[min]; if (((*iter)->Location ().x - MinX) < max) max = (*iter)->Location ().x - MinX; if (((*iter)->Location ().z - MinZ) < max) max = (*iter)->Location ().z - MinZ; if ((MaxX - (*iter)->Location ().x) < max) max = MaxX - (*iter)->Location ().x; if ((MaxZ - (*iter)->Location ().z) < max) max = MaxZ - (*iter)->Location ().z; max -= 1.0f; (*iter)->m_Radius = m_WorkGrid->CalcRadius ((*iter)->Location (),max); if ((*iter)->m_Radius < 20.0) { DeleteNode ((*iter)->ID ()); } else { (*iter)->m_MaxRadius = (*iter)->m_Radius; (*iter)->m_RadiusSquared = (*iter)->m_Radius * (*iter)->m_Radius; } iter++; } KillGrid (); } void CRailGraph::CreateRectData (WorkCallBack callback) { delete m_RectList; gos_PushCurrentHeap (g_RailHeap); m_RectList = new CMoveRectList (); gos_PopCurrentHeap (); m_RectList->Create (callback); } void CRailGraph::CreateBasicNodes (int num,WorkCallBack callback) { float curx,cury; float offx,offy; float dx,dy; float temp; int x,y; float width,height; int i,size; float maxx,maxy; float curpercent,dpercent; if (num >= MAXNODES) num = (MAXNODES-1); maxx = MaxX - MinX - 10.0f; maxy = MaxZ - MinZ - 10.0f; size = m_Nodes.size (); for (i=0;iBuildingAt (Stuff::Point3D (curx-offx,0,cury-offy))) { node = new CRailNode (Stuff::Point3D (curx,0,cury),50); AddNode (node); } curx += dx; } cury += dy; } gos_PopCurrentHeap (); UpdateNodes (callback,90); KillGrid (); } bool CRailWorkGrid::BuildingAt (const Stuff::Point3D& pt) { float cx,cy; int ix,iy; cx = pt.x; cy = pt.z; cx /= 10.0f; cy /= 10.0f; ix = (int) cx; iy = (int) cy; return m_Grid[ix][iy].objectid != -1; } Stuff::Scalar CRailWorkGrid::Slope (int ix,int iy) { Stuff::Scalar toret; toret = m_Grid[ix][iy].normal.y; // since straight up line is 0,1,0 and length 1 return (toret); } Stuff::Scalar CRailWorkGrid::Slope (const Stuff::Point3D& loc) { float cx,cy; int ix,iy; Stuff::Scalar toret; cx = loc.x; cy = loc.z; cx /= 10.0f; cy /= 10.0f; ix = (int) cx; iy = (int) cy; toret = m_Grid[ix][iy].normal.y; // since straight up line is 0,1,0 and length 1 return (toret); } void MW4AI::FillCircle (stlport::vector& points,Stuff::Point3D center,Stuff::Scalar radcomp) { float cx,cy; float curx,cury,maxx,maxy; gos_PushCurrentHeap (g_RailHeap); cx = center.x/10.0f; cy = center.z/10.0f; maxx = radcomp/10.0f; maxy = radcomp/10.0f; radcomp /=10.0f; radcomp *= radcomp; for (curx = 0;curx<=maxx;curx++) { for (cury = 0;cury<=maxy;cury++) { if (((curx*curx) + (cury*cury)) <= radcomp) { points.push_back (gridpoint((cx-curx),(cy-cury))); points.push_back (gridpoint((cx-curx),(cy+cury))); points.push_back (gridpoint((cx+curx),(cy-cury))); points.push_back (gridpoint((cx+curx),(cy+cury))); } } } gos_PopCurrentHeap (); } Stuff::Scalar CRailWorkGrid::CalcRadius (const Stuff::Point3D& center, Stuff::Scalar maxrad) { float radcomp; float currad; int cellcount,filledcount; bool flag; bool bridgeflag; // int minx,miny,maxx,maxy; int offx = (int) MinX/BLOCK_GRID_RES; int offz = (int) MinZ/BLOCK_GRID_RES; gos_PushCurrentHeap (g_RailHeap); stlport::vector points; stlport::map objects; stlport::stack fillstack; if (maxrad > 500.0f) maxrad = 500.0f; for (currad = maxrad;currad >= 10;currad-=5) { cellcount = filledcount = 0; radcomp = currad; points.clear (); objects.clear (); // FillCircle (points,center,radcomp,minx,miny,maxx,maxy); FillCircle (points,center,radcomp); int x,y; for (x=0;x<2048;x++) { for (y=0;y<2048;y++) { workarray[x][y] = true; } } stlport::vector::iterator iter; iter = points.begin (); while (iter != points.end ()) { workarray[iter->x-offx][iter->y-offz] = false; iter++; } bridgeflag = false; iter = points.begin (); while (iter != points.end ()) { cellcount++; int obj; // if (m_Grid[iter->x-offx][iter->y-offz].bridge != -1) // bridgeflag = true; obj = m_Grid[iter->x-offx][iter->y-offz].objectid; if (obj != -1) { objects[obj] = true; filledcount++; workarray[iter->x-offx][iter->y-offz] = true; } else if (Slope (iter->x-offx,iter->y-offz) < BADSLOPE) { filledcount++; workarray[iter->x-offx][iter->y-offz] = true; } iter++; } if (bridgeflag) continue; flag = false; float t; float step; step = 2.0f*(currad/10.0f)*Pi; step = 1.0f/step; step /= 1.5f; for (t=0;t<1.0f;t+=step) { float x,y; x = currad * (float) cos (2.0f*Pi*t); y = currad * (float) sin (2.0f*Pi*t); x += center.x; y += center.z; x /= 10.0f; y /= 10.0f; Verify (x>=(MinX/10)); Verify (y>=(MinZ/10)); Verify (x<(float) m_Grid.size ()); Verify (y<(float) m_Grid[(unsigned int) (x-offx)].size ()); // if (m_Grid[(unsigned int) (x-offx)][(unsigned int) (y-offz)].bridge>=0) // flag = true; // if (m_Grid[(unsigned int) x][(unsigned int) y].objectid>=0) // flag = true; if (Slope ((int) x-offx,(int) y-offz) < BADSLOPE) flag = true; if (flag) break; } if (flag) { continue; } while (!fillstack.empty ()) fillstack.pop (); fillstack.push(gridpoint (center.x/10,center.z/10)); while (!fillstack.empty ()) { gridpoint t = fillstack.top (); fillstack.pop (); if (workarray[t.x-offx][t.y-offz]) continue; workarray[t.x-offx][t.y-offz] = true; if (t.x-1>=MinX/10) fillstack.push (gridpoint (t.x-1,t.y)); if (t.y-1>=MinZ/10) fillstack.push (gridpoint (t.x,t.y-1)); if (t.x+1<(MaxX/10)) fillstack.push (gridpoint (t.x+1,t.y)); if (t.y+1<(MaxZ/10)) fillstack.push (gridpoint (t.x,t.y+1)); } while (!fillstack.empty ()) fillstack.pop (); iter = points.begin (); while (iter != points.end ()) { if (!workarray[iter->x-offx][iter->y-offz]) flag = true; iter++; } float ratio; ratio = (float) filledcount / (float) cellcount; if ((ratio <= 0.5f) && !flag) break; } gos_PopCurrentHeap (); return currad; } float CRailWorkGrid::CheckSquare (int cx,int cy,int movetype) { int sqrindex[8][2] = { {-1,-1}, {0,-1}, {1,-1}, {-1,0}, {1,0}, {-1,1}, {0,1}, {1,1} }; int i; for (i=0;i<8;i++) { int ix,iy; ix = cx+sqrindex[i][0]; iy = cy+sqrindex[i][1]; if (MaterialMode (ix,iy,movetype) == FLT_MAX) return -1.0f; if (m_Grid[ix][iy].objectid != -1) { switch (movetype) { case JUMPINDEX: break; case TRACKINDEX: case WHEELINDEX: case LEGINDEX: case HOVERINDEX: case WATERINDEX: if (m_Grid[ix][iy].objectheight > 0) return -1.0f; break; case HELIINDEX: case FLYINDEX: if (m_Grid[ix][iy].objectheight > 50.0) return -1.0f; break; case BRIDGEINDEX: break; default: Verify (false); break; } } } return 0; } Stuff::Scalar CRailWorkGrid::CalcWeight (Stuff::Point3D src, Stuff::Point3D dest,int movetype) { Stuff::Point3D extra; Stuff::Scalar sx,sy,dx,dy; int ix,iy,ex,ey; Stuff::Scalar curweight,tempweight; Stuff::Scalar lastheight,curheight,dh; int dir; int count,mask; if (movetype == FLYINDEX) return -1.0f; if (movetype == HELIINDEX) return -1.0f; int offx = (int) MinX; int offz = (int) MinZ; src.x -= offx; src.z -= offz; dest.x -= offx; dest.z -= offz; dx = (float) dest.x - src.x; dy = (float) dest.z - src.z; 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; if (dx == 1.0f) { if (dy < -0.25f) dir = 1; else if (dy > 0.25f) dir = 3; else dir = 2; } else { if (dy < -0.25f) dir = 7; else if (dy > 0.25f) dir = 5; else dir = 6; } } else { dx = dx / sy; count = (int) (dy<0.0 ? dy*-1.0f : dy); dy = dy<0 ? -1.0f : 1.0f; if (dy == 1.0f) { if (dx < -0.25f) dir = 5; else if (dx > 0.25f) dir = 3; else dir = 4; } else { if (dx < -0.25f) dir = 7; else if (dx > 0.25f) dir = 1; else dir = 0; } } extra.Subtract (dest,src); dest.x /= 10.0f; dest.z /= 10.0f; src.x /= 10.0f; src.z /= 10.0f; Verify (dest.x >= 0); Verify (dest.z >= 0); Verify (src.x >= 0); Verify (src.z >= 0); dx = dest.x - src.x; dy = dest.z - src.z; 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; } mask = BLOCKED_FLAGS; switch (movetype) { case JUMPINDEX: mask = JUMPPASS_FLAG; break; case TRACKINDEX: mask = TRACKPASS_FLAG; break; case WHEELINDEX: mask = WHEELPASS_FLAG; break; case LEGINDEX: mask = LEGPASS_FLAG; break; case HOVERINDEX: mask = HOVERPASS_FLAG; break; case WATERINDEX: mask = WATERPASS_FLAG; break; } sx = src.x; sy = src.z; ex = (int) dest.x; ey = (int) dest.z; ix = (int) sx; iy = (int) sy; lastheight = m_Grid[ix][iy].height; curweight = 0; while (count) { count--; sx += dx; sy += dy; ix = (int) sx; iy = (int) sy; Verify (ix >= 0); Verify (iy >= 0); if (!g_MissionGraph->MoveTo (ix+(offx/BLOCK_GRID_RES),iy+(offz/BLOCK_GRID_RES),dir,mask)) return -1.0f; // if (m_Grid[ix][iy].bridge != -1) // return -1.0f; if (m_Grid[ix][iy].objectid != -1) { switch (movetype) { case JUMPINDEX: if (m_Grid[ix][iy].objectheight > 12.0) return -1.0f; break; case BRIDGEINDEX: break; case TRACKINDEX: case WHEELINDEX: case LEGINDEX: case HOVERINDEX: if (m_Grid[ix][iy].objectheight > 0) return -1.0f; break; case HELIINDEX: case FLYINDEX: if (m_Grid[ix][iy].objectheight > 50.0) return -1.0f; break; case WATERINDEX: if (m_Grid[ix][iy].objectheight > 0) return -1.0f; break; default: Verify (false); break; } } if (movetype != JUMPINDEX) { curheight = m_Grid[ix][iy].height; dh = lastheight - curheight; dh = dh < 0 ? dh*-1.0f : dh; dh /= 10.0f; curweight += (1.0f + dh); } tempweight = MaterialMode (ix,iy,movetype); if (tempweight == FLT_MAX) { return -1.0f; } if (CheckSquare (ix,iy,movetype) == -1) return -1.0f; curweight += tempweight; } if (movetype == JUMPINDEX) curweight *= 1.25f; return curweight*10.0f; } Stuff::Scalar CRailWorkGrid::MaterialMode (int ix,int iy,int movetype) { BYTE mat; UserConstants *data; data = UserConstants::Instance (); Check_Pointer (data); Verify (ix >= 0); Verify (iy >= 0); mat = m_Grid[ix][iy].material; if (movetype == WATERINDEX) { switch (mat) { case FakeShallowWaterMaterial: return FLT_MAX; case FakeMidWaterMaterial: return 0.25; case FakeOceanicWaterMaterial: return 0; default: return FLT_MAX; } } if (movetype == JUMPINDEX) return 0; if ((movetype == FLYINDEX) || (movetype == HELIINDEX)) return 0; if (movetype == BRIDGEINDEX) return 0; Verify ((movetype == TRACKINDEX) || (movetype == WHEELINDEX) || (movetype == LEGINDEX) || (movetype == HOVERINDEX)); switch (mat) { case WaterMaterial: gosREPORT (false,"ran into a water material"); return 0; case NoMaterial: case GreyDirtMaterial: case BrownDirtMaterial: case DarkGreyDirtMaterial: case DarkBrownDirtMaterial: switch (movetype) { case TRACKINDEX: return data->Get (UserConstants::track_dirt_cost); case WHEELINDEX: return data->Get (UserConstants::wheel_dirt_cost); case LEGINDEX: return data->Get (UserConstants::leg_dirt_cost); case HOVERINDEX: return data->Get (UserConstants::hover_dirt_cost); } // MSL 5.03 Lava case CrackedLavaMaterial: switch (movetype) { case TRACKINDEX: return FLT_MAX; case WHEELINDEX: return FLT_MAX; case LEGINDEX: return data->Get (UserConstants::leg_crackedlava_cost); case HOVERINDEX: return FLT_MAX; } break; case OpenLavaMaterial: switch (movetype) { case TRACKINDEX: return FLT_MAX; case WHEELINDEX: return FLT_MAX; case LEGINDEX: return data->Get (UserConstants::leg_openlava_cost); case HOVERINDEX: return FLT_MAX; } break; case AshMaterial: case LightMineralMaterial: case DarkMineralMaterial: case DarkRockMaterial: case LavaMaterial: case RockMaterial: switch (movetype) { case TRACKINDEX: return data->Get (UserConstants::track_rock_cost); case WHEELINDEX: return data->Get (UserConstants::wheel_rock_cost); case LEGINDEX: return data->Get (UserConstants::leg_rock_cost); case HOVERINDEX: return data->Get (UserConstants::hover_rock_cost); } case SteelMaterial: switch (movetype) { case TRACKINDEX: return data->Get (UserConstants::track_steel_cost); case WHEELINDEX: return data->Get (UserConstants::wheel_steel_cost); case LEGINDEX: return data->Get (UserConstants::leg_steel_cost); case HOVERINDEX: return data->Get (UserConstants::hover_steel_cost); } case BlacktopMaterial: switch (movetype) { case TRACKINDEX: return data->Get (UserConstants::track_blacktop_cost); case WHEELINDEX: return data->Get (UserConstants::wheel_blacktop_cost); case LEGINDEX: return data->Get (UserConstants::leg_blacktop_cost); case HOVERINDEX: return data->Get (UserConstants::hover_blacktop_cost); } case GlassMaterial: switch (movetype) { case TRACKINDEX: return data->Get (UserConstants::track_glass_cost); case WHEELINDEX: return data->Get (UserConstants::wheel_glass_cost); case LEGINDEX: return data->Get (UserConstants::leg_glass_cost); case HOVERINDEX: return data->Get (UserConstants::hover_glass_cost); } case GrassMaterial: switch (movetype) { case TRACKINDEX: return data->Get (UserConstants::track_grass_cost); case WHEELINDEX: return data->Get (UserConstants::wheel_grass_cost); case LEGINDEX: return data->Get (UserConstants::leg_grass_cost); case HOVERINDEX: return data->Get (UserConstants::hover_grass_cost); } case WoodMaterial: switch (movetype) { case TRACKINDEX: return data->Get (UserConstants::track_wood_cost); case WHEELINDEX: return data->Get (UserConstants::wheel_wood_cost); case LEGINDEX: return data->Get (UserConstants::leg_wood_cost); case HOVERINDEX: return data->Get (UserConstants::hover_wood_cost); } case DarkConcreteMaterial: case ConcreteMaterial: switch (movetype) { case TRACKINDEX: return data->Get (UserConstants::track_concrete_cost); case WHEELINDEX: return data->Get (UserConstants::wheel_concrete_cost); case LEGINDEX: return data->Get (UserConstants::leg_concrete_cost); case HOVERINDEX: return data->Get (UserConstants::hover_concrete_cost); } case SnowMaterial: switch (movetype) { case TRACKINDEX: return data->Get (UserConstants::track_snow_cost); case WHEELINDEX: return data->Get (UserConstants::wheel_snow_cost); case LEGINDEX: return data->Get (UserConstants::leg_snow_cost); case HOVERINDEX: return data->Get (UserConstants::hover_snow_cost); } case FakeShallowWaterMaterial: switch (movetype) { case TRACKINDEX: return data->Get (UserConstants::track_shallowwater_cost); case WHEELINDEX: return data->Get (UserConstants::wheel_shallowwater_cost); case LEGINDEX: return data->Get (UserConstants::leg_shallowwater_cost); case HOVERINDEX: return data->Get (UserConstants::hover_shallowwater_cost); } break; case FakeMidWaterMaterial: switch (movetype) { case TRACKINDEX: return data->Get (UserConstants::track_midwater_cost); case WHEELINDEX: return data->Get (UserConstants::wheel_midwater_cost); case LEGINDEX: return data->Get (UserConstants::leg_midwater_cost); case HOVERINDEX: return data->Get (UserConstants::hover_midwater_cost); } case FakeOceanicWaterMaterial: switch (movetype) { case TRACKINDEX: return data->Get (UserConstants::track_oceanicwater_cost); case WHEELINDEX: return data->Get (UserConstants::wheel_oceanicwater_cost); case LEGINDEX: return data->Get (UserConstants::leg_oceanicwater_cost); case HOVERINDEX: return data->Get (UserConstants::hover_oceanicwater_cost); } default: #if defined(LAB_ONLY) PAUSE (("ran into an unknown material type")); #endif return 0; break; } return 0; } CMoveGrid::CMoveGrid (void) { m_Data = NULL; m_MacroData = NULL; m_Width = 0; m_Height = 0; m_AllocWidth = 0; m_AllocHeight = 0; } CMoveGrid::CMoveGrid (Stuff::MemoryStream *stream) { DWORD datasize; m_Data = NULL; m_MacroData = NULL; m_AllocWidth = 0; m_AllocHeight = 0; *stream >> m_Width; *stream >> m_Height; *stream >> datasize; if ((m_Width == 0) && (m_Height == 0) && (datasize == 0)) STOP (("No Move grid created for this map, must exit now")); // Verify (m_Width == MaxX); // Verify (m_Height == MaxZ); Construct (m_Width,m_Height); Verify (datasize == (512*512*2)); stream->ReadBytes (m_Data,(512*512*2)); #if 0 int i,size,chunksize; size = m_Height / 10; chunksize = m_Width /10; chunksize <<= 1; for (i=0;iReadBytes (m_Data[i],chunksize); datasize -= chunksize; } #endif { int i,j; int left,right,top,bottom; left = (int) (MinX / BLOCK_GRID_RES); top = (int) (MinZ / BLOCK_GRID_RES); right = (int) (MaxX / BLOCK_GRID_RES); bottom = (int) (MaxZ / BLOCK_GRID_RES); for (i=left;i<(left+5);i++) for (j=top;j>3][i>>3] += 1; } } } } void CMoveGrid::DeleteMacroData (void) { int i,width,height; width = m_Width; height = m_Height; width /= MACROBLOCK_GRID_RES; height /= MACROBLOCK_GRID_RES; if (m_MacroData != NULL) { for (i=0;i 0) { char str[255]; sprintf (str,"need to recreate lattice for %s, very old data",filename); STOP ((str)); } data++; theight = *((int*) data); if (theight > 0) { char str[255]; sprintf (str,"need to recreate lattice for %s, very old data",filename); STOP ((str)); } // *stream << (-1*twidth); // width negative for new style // *stream << (-1*theight); // height negative for 2 byte format *stream << (5120); // width negative for new style *stream << (5120); // height negative for 2 byte format data++; filesize -= (sizeof (DWORD) * 3); // *stream << filesize; *stream << (512*512*2); data++; int deltax=0,deltay=0; switch (twidth) { case -1280: deltax = 192; break; case -2560: deltax = 128; break; case -3840: deltax = 64; break; case -5120: deltax = 0; break; default: return false; // STOP (("Unsupported map width in cmovegrid::constructstream")); break; } switch (theight) { case -1280: deltay = 192; break; case -2560: deltay = 128; break; case -3840: deltay = 64; break; case -5120: deltay = 0; break; default: return false; // STOP (("Unsupported map height in cmovegrid::constructstream")); break; } if (!filesize) STOP (("no data in cmovegrid::constructstream")); int x,y,linesize; int byteswritten=0; unsigned short blankline[512]; linesize = twidth/-10; dataptr = (unsigned char *) data; stream->AllocateBytes (512*512*2); for (x=0;x<512;x++) { blankline[x] = BLOCKED_FLAGS; } for (y=0;yWriteBytes(blankline,512*2); } for (y=deltay;y<(512-deltay);y++) { // for (x=0;xWriteBytes (blankline,deltax*2); } // for (x=deltax;x<(512-deltax);x++) { stream->WriteBytes (dataptr,linesize*2); dataptr += linesize*2; byteswritten += linesize*2; } // for (x=(512-deltax);x<512;x++) { if (deltax != 0) stream->WriteBytes (blankline,deltax*2); } } for (y=(512-deltay);y<512;y++) { stream->WriteBytes(blankline,512*2); } // stream->WriteBytes (dataptr =,filesize); gos_Free (file); } else { // PAUSE (("constructing passability map for unknown map, defaulting to impassable")); int x,y; unsigned short blankline[512]; stream->AllocateBytes (512*512*2); for (x=0;x<512;x++) { blankline[x] = BLOCKED_FLAGS; } *stream << (5120); // width negative for new style *stream << (5120); // height negative for 2 byte format *stream << (512*512*2); for (y=0;y<512;y++) { stream->WriteBytes(blankline,512*2); } return false; } return true; } void CMoveGrid::Clear (void) { int i,j; for (i=0;i> m_Width; *stream >> m_Height; *stream >> datasize; if ((m_Width == 0) && (m_Height == 0) && (datasize == 0)) return; Verify (m_Width == MaxX-MinX); Verify (m_Height == MaxZ-MinZ); Construct (m_Width,m_Height); size = m_Height / AIR_BLOCK_GRID_RES; chunksize = m_Width / AIR_BLOCK_GRID_RES; for (i=0;iReadBytes (m_Data[i],chunksize); datasize -= chunksize; } // Verify (datasize == 0); } void CAirMoveGrid::SaveData (const char *filename) { int i,size,chunksize; int temp; Stuff::FileStream stream(filename,Stuff::FileStream::WriteOnly); temp = m_Width; stream << temp; temp = m_Height; stream << temp; size = m_Height / AIR_BLOCK_GRID_RES; chunksize = m_Width /AIR_BLOCK_GRID_RES; stream << (DWORD) (chunksize * size); for (i=0;iWriteBytes (data,filesize); gos_Free (file); } else { *stream << (DWORD) 0; // for width *stream << (DWORD) 0; // for height *stream << (DWORD) 0; // for datasize } } void CAirMoveGrid::Clear (void) { int i,j; for (i=0;inameTableArray[NameTable::PathArray].GetLength (); for (j=0;jnameTableArray [NameTable::PathArray][j]; who = data->dataPointer->GetCurrent (); if (!who) continue; Verify (who->IsDerivedFrom (Path::DefaultData)); path = (Path *) who; stlport::vector::iterator iter; for (index=0,iter = path->pathPoints.begin ();iter != path->pathPoints.end ();iter++,index++) { int x,y; x = (int) iter->x; y = (int) iter->z; x /= BLOCK_GRID_RES; y /= BLOCK_GRID_RES; if ((m_MoveGrid->PassableLocal (x,y) & BLOCKED_FLAGS) != BLOCKED_FLAGS) continue; { sprintf (text,"Path %s, index %d is invalid. Do you wish to remove this point?",(char *) data->objectName,index); if (MessageBox (NULL,text,"Path error",MB_YESNO) == IDYES) { iter = path->pathPoints.erase (iter); iter--; } } } } } }