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.
1981 lines
45 KiB
C++
1981 lines
45 KiB
C++
#include "MW4Headers.hpp"
|
|
#include "adept\application.hpp"
|
|
#include "rail_move.hpp"
|
|
//#include "quadedge.h"
|
|
#include <MW4\MWMission.hpp>
|
|
#include <Adept\Map.hpp>
|
|
#include <Adept\CollisionGrid.hpp>
|
|
#include <ElementRenderer\StateChange.hpp>
|
|
#include <adept\collisionvolume.hpp>
|
|
#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 <vector>
|
|
#include <map>
|
|
#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;i<size;i++)
|
|
{
|
|
if (m_Nodes[i])
|
|
{
|
|
m_Nodes[i]->m_DistanceValid = true;
|
|
m_Nodes[i]->m_EditorDistance.reserve (size);
|
|
for (j=0;j<size;j++)
|
|
m_Nodes[i]->m_EditorDistance.push_back (FLT_MAX);
|
|
}
|
|
}
|
|
for (i=0;i<(size-1);i++)
|
|
{
|
|
for (j=i+1;j<size;j++)
|
|
{
|
|
Stuff::Point3D loc1,loc2,extra;
|
|
float dist;
|
|
|
|
if ((!m_Nodes[i]) && (!m_Nodes[j]))
|
|
{
|
|
continue;
|
|
}
|
|
if (!m_Nodes[i])
|
|
{
|
|
m_Nodes[j]->m_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<int> *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<int>::TraverseFunction (QuadTreeNode<int> *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<CRailSquare> 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;i<x;i++)
|
|
{
|
|
m_Grid[i].assign ((int) z,CRailSquare ());
|
|
}
|
|
|
|
curpercent = 0;
|
|
sizex = m_Grid.size ();
|
|
dpercent = maxpercent / sizex;
|
|
movegrid->Clear ();
|
|
airmovegrid->Clear ();
|
|
for (i=0;i<sizex;i++)
|
|
{
|
|
curpercent += dpercent;
|
|
if (callback)
|
|
callback (curpercent);
|
|
sizey = m_Grid[i].size ();
|
|
for (j=0;j<sizey;j++)
|
|
{
|
|
x = i*10.0f;
|
|
x += MinX;
|
|
z = j*10.0f;
|
|
z += MinZ;
|
|
m_Grid[i][j].Construct (x,z);
|
|
}
|
|
}
|
|
|
|
int offx = (int) (MinX / BLOCK_GRID_RES);
|
|
int offz = (int) (MinZ / BLOCK_GRID_RES);
|
|
for (i=0;i<sizex;i++)
|
|
{
|
|
sizey = m_Grid[i].size ();
|
|
for (j=0;j<sizey;j++)
|
|
{
|
|
switch (m_Grid[i][j].material)
|
|
{
|
|
case FakeShallowWaterMaterial:
|
|
movegrid->PassableLocalOverride (i+offx,j+offz,SHALLOW_WATER<<WATER_SHIFT);
|
|
movegrid->PassableLocal (i+offx,j+offz,TRACKPASS_FLAG+WHEELPASS_FLAG+WATERPASS_FLAG);
|
|
break;
|
|
case FakeMidWaterMaterial:
|
|
movegrid->PassableLocalOverride (i+offx,j+offz,MEDIUM_WATER<<WATER_SHIFT);
|
|
movegrid->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<<WATER_SHIFT);
|
|
movegrid->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<sizex;i++)
|
|
{
|
|
sizey = m_Grid[i].size ();
|
|
for (j=0;j<sizey;j++)
|
|
{
|
|
float nx,nz,ny;
|
|
nx = m_Grid[i][j].normal.x;
|
|
nz = m_Grid[i][j].normal.z;
|
|
ny = m_Grid[i][j].normal.y;
|
|
if ((nz <= 0) && (nx >= -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<<STEEP_SHIFT);
|
|
}
|
|
if ((ny < constants->Get (UserConstants::track_up_slope)) && (ny > constants->Get (UserConstants::track_down_slope)))
|
|
{
|
|
movegrid->PassableLocal (i+offx,j+offz,TRACKDOWN_SLOPE<<STEEP_SHIFT);
|
|
}
|
|
if ((ny < constants->Get (UserConstants::wheel_up_slope)) && (ny > constants->Get (UserConstants::wheel_down_slope)))
|
|
{
|
|
movegrid->PassableLocal (i+offx,j+offz,WHEELDOWN_SLOPE<<STEEP_SHIFT);
|
|
}
|
|
if ((ny < constants->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;i<sizeof (tablescan)/sizeof (int);i++)
|
|
{
|
|
size = table->nameTableArray[tablescan[i]].GetLength ();
|
|
for (j=0;j<size;j++)
|
|
{
|
|
NameTableEntry *data;
|
|
Entity *who;
|
|
|
|
data = &table->nameTableArray [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;i<sizex;i++)
|
|
{
|
|
curpercent += dpercent;
|
|
if (callback)
|
|
callback (curpercent);
|
|
sizey = m_Grid[i].size ();
|
|
for (j=0;j<sizey;j++)
|
|
{
|
|
x = i*10.0f;
|
|
x += MinX;
|
|
z = j*10.0f;
|
|
z += MinZ;
|
|
x += 5.0f;
|
|
z += 5.0f;
|
|
if (m_Grid[i][j].bridge != -1)
|
|
{
|
|
// movegrid->PassableLocal (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<CRailNode *>::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;i<size;i++)
|
|
{
|
|
if ((*iter)->m_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;i<size;i++)
|
|
DeleteNode (i);
|
|
m_Nodes.clear ();
|
|
|
|
CreateGrid (callback,80.0f);
|
|
Check_Pointer (m_WorkGrid);
|
|
|
|
temp = (float) sqrt (num);
|
|
width = temp;
|
|
height = ((float) num)/temp;
|
|
|
|
dx = maxx / (width+1);
|
|
dy = maxy / (height+1);
|
|
if (dx < 100.0f)
|
|
{
|
|
dx = 100.0f;
|
|
width = maxx / dx;
|
|
}
|
|
if (dy < 100.0f)
|
|
{
|
|
dy = 100.0f;
|
|
height = maxy / dy;
|
|
}
|
|
width-=1;
|
|
height -=1;
|
|
curx = MinX + dx + 5.0f;
|
|
cury = MinZ + dy + 5.0f;
|
|
curpercent = 80.0f;
|
|
dpercent = 10.0f / height;
|
|
offx = MinX;
|
|
offy = MinZ;
|
|
gos_PushCurrentHeap (g_RailHeap);
|
|
for (y=0;y<=height;y++)
|
|
{
|
|
curx = MinX + dx + 5.0f;
|
|
curpercent += dpercent;
|
|
if (callback)
|
|
callback (curpercent);
|
|
for (x=0;x<=width;x++)
|
|
{
|
|
CRailNode *node;
|
|
|
|
if (!m_WorkGrid->BuildingAt (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<gridpoint>& 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<gridpoint> points;
|
|
stlport::map<int,bool> objects;
|
|
stlport::stack<gridpoint> 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<gridpoint>::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;i<size;i++)
|
|
{
|
|
stream->ReadBytes (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<bottom;j++)
|
|
PassableLocal (i,j,BLOCKED_FLAGS);
|
|
|
|
for (i=(right-5);i<right;i++)
|
|
for (j=top;j<bottom;j++)
|
|
PassableLocal (i,j,BLOCKED_FLAGS);
|
|
|
|
for (i=left;i<right;i++)
|
|
for (j=top;j<(top+5);j++)
|
|
PassableLocal (i,j,BLOCKED_FLAGS);
|
|
|
|
for (i=left;i<right;i++)
|
|
for (j=(bottom-5);j<bottom;j++)
|
|
PassableLocal (i,j,BLOCKED_FLAGS);
|
|
|
|
}
|
|
CreateMacroData ();
|
|
}
|
|
|
|
void CMoveGrid::CreateMacroData (void)
|
|
{
|
|
int width,height;
|
|
int i,j;
|
|
|
|
width = m_Width;
|
|
height = m_Height;
|
|
width /= MACROBLOCK_GRID_RES;
|
|
height /= MACROBLOCK_GRID_RES;
|
|
|
|
m_MacroAllocWidth = width;
|
|
m_MacroAllocHeight = height;
|
|
|
|
gos_PushCurrentHeap(g_RailHeap);
|
|
m_MacroData = new unsigned char *[height];
|
|
for (i=0;i<height;i++)
|
|
{
|
|
m_MacroData[i] = new unsigned char[width];
|
|
}
|
|
gos_PopCurrentHeap ();
|
|
|
|
for (i=0;i<width;i++)
|
|
{
|
|
for (j=0;j<height;j++)
|
|
{
|
|
m_MacroData[j][i] = 0;
|
|
}
|
|
}
|
|
unsigned short mask;
|
|
for (i=0;i<m_AllocWidth;i++)
|
|
{
|
|
for (j=0;j<m_AllocHeight;j++)
|
|
{
|
|
mask = m_Data[(j*m_AllocWidth)+i];
|
|
if ((mask & BLOCKED_FLAGS) == BLOCKED_FLAGS)
|
|
{
|
|
m_MacroData[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<height;i++)
|
|
{
|
|
delete[] m_MacroData[i];
|
|
}
|
|
|
|
delete[] m_MacroData;
|
|
|
|
m_MacroData = NULL;
|
|
}
|
|
}
|
|
|
|
void CMoveGrid::SaveData (const char *filename)
|
|
{
|
|
int i,size,chunksize;
|
|
int temp;
|
|
unsigned char *data;
|
|
|
|
Stuff::FileStream stream(filename,Stuff::FileStream::WriteOnly);
|
|
|
|
temp = m_Width;
|
|
temp *= -1;
|
|
stream << temp;
|
|
|
|
temp = m_Height;
|
|
temp *= -1;
|
|
stream << temp;
|
|
|
|
size = m_Height / 10;
|
|
chunksize = m_Width /10;
|
|
chunksize <<= 1;
|
|
|
|
data = (unsigned char *) &(m_Data[0]);
|
|
stream << (DWORD) (chunksize * size);
|
|
for (i=0;i<size;i++)
|
|
{
|
|
stream.WriteBytes (data,chunksize);
|
|
data += chunksize;
|
|
}
|
|
}
|
|
|
|
bool CMoveGrid::ConstructStream (Stuff::MemoryStream *stream,const char *filename)
|
|
{
|
|
DWORD *file;
|
|
DWORD filesize;
|
|
DWORD *data;
|
|
unsigned char *dataptr;
|
|
int twidth,theight;
|
|
|
|
if (filename)
|
|
{
|
|
gos_GetFile (filename,(unsigned char **) &file,&filesize);
|
|
data = file;
|
|
twidth = *((int*) data);
|
|
if (twidth > 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;y<deltay;y++)
|
|
{
|
|
stream->WriteBytes(blankline,512*2);
|
|
}
|
|
for (y=deltay;y<(512-deltay);y++)
|
|
{
|
|
// for (x=0;x<deltax;x++)
|
|
{
|
|
if (deltax != 0)
|
|
stream->WriteBytes (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_AllocHeight;i++)
|
|
for (j=0;j<m_AllocWidth;j++)
|
|
m_Data [(i*m_AllocWidth)+j] = BLOCKED_FLAGS;
|
|
}
|
|
CAirMoveGrid::CAirMoveGrid (void)
|
|
{
|
|
m_Data = NULL;
|
|
m_Width = 0;
|
|
m_Height = 0;
|
|
m_AllocWidth = 0;
|
|
m_AllocHeight = 0;
|
|
}
|
|
|
|
CAirMoveGrid::CAirMoveGrid (Stuff::MemoryStream *stream)
|
|
{
|
|
int i,size,chunksize;
|
|
DWORD datasize;
|
|
|
|
m_Data = NULL;
|
|
m_AllocWidth = 0;
|
|
m_AllocHeight = 0;
|
|
*stream >> 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;i<size;i++)
|
|
{
|
|
stream->ReadBytes (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;i<size;i++)
|
|
{
|
|
stream.WriteBytes (m_Data[i],chunksize);
|
|
}
|
|
}
|
|
|
|
void CAirMoveGrid::ConstructStream (Stuff::MemoryStream *stream,const char *filename)
|
|
{
|
|
DWORD *file;
|
|
DWORD filesize;
|
|
DWORD *data;
|
|
int twidth,theight;
|
|
|
|
if (filename)
|
|
{
|
|
gos_GetFile (filename,(unsigned char **) &file,&filesize);
|
|
data = file;
|
|
twidth = *((int*) data);
|
|
data++;
|
|
theight = *((int*) data);
|
|
*stream << twidth; // width
|
|
*stream << theight; // height
|
|
data++;
|
|
filesize -= (sizeof (DWORD) * 3);
|
|
*stream << filesize;
|
|
data++;
|
|
if (filesize)
|
|
stream->WriteBytes (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;i<m_AllocHeight;i++)
|
|
for (j=0;j<m_AllocWidth;j++)
|
|
m_Data [i][j] = 0;
|
|
}
|
|
|
|
void CRailGraph::AnalyzePaths (void)
|
|
{
|
|
int size;
|
|
NameTable *table = NameTable::GetInstance();
|
|
char text[255];
|
|
int index,j;
|
|
|
|
Check_Object (table);
|
|
{
|
|
size = table->nameTableArray[NameTable::PathArray].GetLength ();
|
|
for (j=0;j<size;j++)
|
|
{
|
|
NameTableEntry *data;
|
|
Entity *who;
|
|
Path *path;
|
|
|
|
data = &table->nameTableArray [NameTable::PathArray][j];
|
|
|
|
who = data->dataPointer->GetCurrent ();
|
|
if (!who)
|
|
continue;
|
|
Verify (who->IsDerivedFrom (Path::DefaultData));
|
|
path = (Path *) who;
|
|
stlport::vector<Stuff::Point3D>::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--;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|