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.
505 lines
11 KiB
C++
505 lines
11 KiB
C++
#include "MW4Headers.hpp"
|
|
#include "Adept\AdeptHeaders.hpp"
|
|
#include <Adept\CollisionGrid.hpp>
|
|
#include <adept\collisionvolume.hpp>
|
|
#include "moverai.hpp"
|
|
#include "obstacle.hpp"
|
|
#include "bridge.hpp"
|
|
#include "cultural.hpp"
|
|
#include "airplane.hpp"
|
|
#include "building.hpp"
|
|
#include "mwplayer.hpp"
|
|
|
|
namespace MW4AI
|
|
{
|
|
|
|
struct LineData
|
|
{
|
|
LockData *root;
|
|
};
|
|
const int MAXLINES = 1024;
|
|
LineData *g_Obstacles;
|
|
Rect4DHashTable *g_Rect4DHash,*g_AirRect4DHash;
|
|
Stuff::Scalar g_MaxBuildingHeight = 0;
|
|
Stuff::Scalar g_MaxAirHeight = 0;
|
|
Stuff::MemoryBlockOf<Rect4D> *Rect4D::m_EmptyRect=NULL;
|
|
Stuff::MemoryBlockOf<LockData> *LockData::m_EmptyData = NULL;
|
|
DWORD Obstacle_Size = 0;
|
|
|
|
void InitObstacle (void)
|
|
{
|
|
int i;
|
|
|
|
Rect4D::m_EmptyRect = new MemoryBlockOf<Rect4D> (1000,100,"Temporal Rects");
|
|
LockData::m_EmptyData = new MemoryBlockOf<LockData> (1000,100,"Path lock Data");
|
|
g_Rect4DHash = new Rect4DHashTable (200);
|
|
g_AirRect4DHash = new Rect4DHashTable(200);
|
|
g_Obstacles = new LineData[MAXLINES];
|
|
Check_Pointer (g_Obstacles);
|
|
for (i=0;i<MAXLINES;i++)
|
|
{
|
|
g_Obstacles[i].root = NULL;
|
|
}
|
|
}
|
|
void CleanObstacle (void)
|
|
{
|
|
int i;
|
|
for (i=0;i<MAXLINES;i++)
|
|
{
|
|
while (g_Obstacles[i].root)
|
|
{
|
|
LockData *temp;
|
|
|
|
temp = g_Obstacles[i].root;
|
|
Check_Pointer (temp);
|
|
g_Obstacles[i].root = g_Obstacles[i].root->next;
|
|
delete temp;
|
|
}
|
|
}
|
|
delete g_Obstacles;
|
|
g_Obstacles = NULL;
|
|
delete g_Rect4DHash;
|
|
g_Rect4DHash = NULL;
|
|
delete g_AirRect4DHash;
|
|
g_AirRect4DHash = NULL;
|
|
delete Rect4D::m_EmptyRect;
|
|
Rect4D::m_EmptyRect = NULL;
|
|
delete LockData::m_EmptyData;
|
|
LockData::m_EmptyData = NULL;
|
|
}
|
|
|
|
void MW4AI::KillPermRects (void)
|
|
{
|
|
g_Rect4DHash->KillRectList ();
|
|
}
|
|
|
|
void SetupPermRects (void)
|
|
{
|
|
Verify (g_Rect4DHash);
|
|
|
|
int tablescan[] =
|
|
{
|
|
NameTable::BuildingArray,
|
|
NameTable::TurretArray,
|
|
NameTable::VehicleArray
|
|
};
|
|
g_MaxBuildingHeight = 0;
|
|
g_MaxAirHeight = 0;
|
|
int size,i,j;
|
|
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 (data->objectName && !strnicmp (data->objectName,"water",5))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
who = data->dataPointer->GetCurrent ();
|
|
|
|
if (!who)
|
|
continue;
|
|
if ((!who->GetHierarchicalVolume ()) && (!who->GetSolidVolume ()))
|
|
continue;
|
|
|
|
MWObject *obj=NULL;
|
|
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 ((box.maxY - box.minY) > g_MaxAirHeight)
|
|
{
|
|
g_MaxAirHeight = box.maxY - box.minY;
|
|
}
|
|
}
|
|
else // must be a building
|
|
{
|
|
if ((box.maxY - box.minY) > g_MaxBuildingHeight)
|
|
{
|
|
g_MaxBuildingHeight = box.maxY - box.minY;
|
|
}
|
|
}
|
|
|
|
if (!who->IsDerivedFrom (MechWarrior4::Cultural::DefaultData))
|
|
{
|
|
obj = Cast_Object (MWObject *,who);
|
|
AI *ai;
|
|
ai = obj->GetAI ();
|
|
if (ai && ai->IsDerivedFrom (MoverAI::DefaultData))
|
|
continue;
|
|
}
|
|
if (who->IsDerivedFrom (Bridge::DefaultData))
|
|
continue;
|
|
// if ((obj->GetAI ()) && (tablescan[i] != NameTable::BuildingArray))
|
|
// continue;
|
|
|
|
Point3D loc = (Point3D) obb->localToParent;
|
|
|
|
Rect4D temprect;
|
|
temprect.left = box.minX;
|
|
temprect.right = box.maxX;
|
|
temprect.top = box.minZ;
|
|
temprect.bottom = box.maxZ;
|
|
temprect.who = who;
|
|
g_Rect4DHash->AddPermRect (temprect);
|
|
}
|
|
}
|
|
|
|
g_MaxAirHeight += 5.0f;
|
|
g_MaxBuildingHeight += 10.0f;
|
|
if (g_MaxBuildingHeight < 20.0f)
|
|
{
|
|
g_MaxBuildingHeight = 20.0f;
|
|
}
|
|
Check_Object (table);
|
|
size = table->nameTableArray[NameTable::VehicleArray].GetLength ();
|
|
for (j=0;j<size;j++)
|
|
{
|
|
NameTableEntry *data;
|
|
Entity *who;
|
|
Airplane *air;
|
|
|
|
data = &table->nameTableArray [NameTable::VehicleArray][j];
|
|
who = data->dataPointer->GetCurrent ();
|
|
if (!who)
|
|
continue;
|
|
if (!who->IsDerivedFrom (Airplane::DefaultData))
|
|
{
|
|
continue;
|
|
}
|
|
air = Cast_Object (Airplane *,who);
|
|
air->AdjustAltitude ();
|
|
}
|
|
}
|
|
|
|
MWObject *BlockerLocal (int x,int z)
|
|
{
|
|
LockData *temp;
|
|
|
|
x -= (int) (MinX/BLOCK_GRID_RES);
|
|
z -= (int) (MinZ/BLOCK_GRID_RES);
|
|
Clamp (x,0,(int) (2*(MaxX/BLOCK_GRID_RES)));
|
|
Clamp (z,0,MAXLINES-1);
|
|
Verify (z>=0);
|
|
Verify (z<MAXLINES);
|
|
Verify (g_Obstacles);
|
|
temp = g_Obstacles[z].root;
|
|
while (temp)
|
|
{
|
|
Check_Pointer (temp);
|
|
if ((temp->locx == x) && (temp->locz == z))
|
|
return temp->who;
|
|
temp = temp->next;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
bool AddBlockLocal (int x,int z,MWObject *who)
|
|
{
|
|
if (BlockerLocal (x,z))
|
|
{
|
|
return false;
|
|
}
|
|
x -= (int) (MinX/BLOCK_GRID_RES);
|
|
z -= (int) (MinZ/BLOCK_GRID_RES);
|
|
Verify (z>=0);
|
|
Verify (z<MAXLINES);
|
|
Verify (g_Obstacles);
|
|
|
|
LockData *temp;
|
|
temp = new LockData (x,z,who);
|
|
temp->next = g_Obstacles[z].root;
|
|
g_Obstacles[z].root = temp;
|
|
Set_Statistic(Obstacle_Size, Obstacle_Size+1);
|
|
return true;
|
|
}
|
|
|
|
void RemoveBlockLocal (int x,int z,MWObject *who)
|
|
{
|
|
x -= (int) (MinX/BLOCK_GRID_RES);
|
|
z -= (int) (MinZ/BLOCK_GRID_RES);
|
|
Verify (z>=0);
|
|
Verify (z<MAXLINES);
|
|
Verify (g_Obstacles);
|
|
LockData *temp;
|
|
|
|
temp = g_Obstacles[z].root;
|
|
//
|
|
// Very non-repro bug occassionally results in this being NULL. Theory is math order causes Z to fall just slightly
|
|
// above or below truncation point, so the same Z passed in, results in a different index.
|
|
//
|
|
if (!temp)
|
|
return;
|
|
if ((temp->locx == x) && (temp->locz == z) && (temp->who == who))
|
|
{
|
|
g_Obstacles[z].root = temp->next;
|
|
if (g_Obstacles[z].root)
|
|
Check_Pointer (g_Obstacles[z].root);
|
|
delete temp;
|
|
Set_Statistic(Obstacle_Size, Obstacle_Size-1);
|
|
return;
|
|
}
|
|
while (temp->next)
|
|
{
|
|
LockData *fred;
|
|
fred = temp->next;
|
|
if ((fred->locx == x) && (fred->locz == z) && (fred->who == who))
|
|
{
|
|
temp->next = fred->next;
|
|
if (temp->next)
|
|
Check_Pointer (temp->next);
|
|
delete fred;
|
|
Set_Statistic(Obstacle_Size, Obstacle_Size-1);
|
|
return;
|
|
}
|
|
|
|
temp = temp->next;
|
|
}
|
|
|
|
Verify (false);
|
|
}
|
|
|
|
|
|
|
|
|
|
void Rect4DHashTable::KillHashLine (int i)
|
|
{
|
|
ablREPORT (i>=0,"");
|
|
ablREPORT (i < m_ListSize,"");
|
|
m_List[i] = NULL; // everybody else is responsible for freeing themselvs
|
|
}
|
|
|
|
void Rect4DHashTable::KillRectList (void)
|
|
{
|
|
Rect4D *current,*temp;
|
|
|
|
current = m_PermList;
|
|
while (current)
|
|
{
|
|
temp = current;
|
|
current = current->next;
|
|
temp->next = temp->prev = NULL;
|
|
|
|
delete temp;
|
|
}
|
|
m_PermList = NULL;
|
|
}
|
|
|
|
void Rect4DHashTable::AddRect (Rect4D* p1)
|
|
{
|
|
Verify (false);
|
|
int loc;
|
|
ablREPORT (p1,"");
|
|
ablREPORT (p1->who,"");
|
|
ablREPORT (p1->who->IsDerivedFrom (Entity::DefaultData),"");
|
|
// Verify (p1->who->IsDerivedFrom (MWObject::DefaultData));
|
|
ablREPORT (p1->who->IsDerivedFrom (MechWarrior4::MWPlayer::DefaultData) || p1->who->IsDerivedFrom (AI::DefaultData) || p1->who->IsDerivedFrom (Vehicle::DefaultData) || p1->who->IsDerivedFrom (Building::DefaultData),"");
|
|
if (p1->left < MinX)
|
|
p1->left = MinX;
|
|
if (p1->top < MinZ)
|
|
p1->top = MinZ;
|
|
if (p1->right < MinX)
|
|
p1->right = MinX;
|
|
if (p1->bottom < MinZ)
|
|
p1->bottom = MinZ;
|
|
|
|
if (p1->top >= (MaxZ-1))
|
|
p1->top = MaxZ-1;
|
|
if (p1->left >= (MaxX-1))
|
|
p1->left = MaxX-1;
|
|
if (p1->bottom >= (MaxZ-1))
|
|
p1->bottom = MaxZ-1;
|
|
if (p1->right >= (MaxX-1))
|
|
p1->right = MaxX-1;
|
|
|
|
ablREPORT (p1->left <= p1->right,"");
|
|
ablREPORT (p1->top <= p1->bottom,"");
|
|
loc = FindHashLine (*p1);
|
|
if (loc==-1)
|
|
return;
|
|
ablREPORT (loc>=0,"");
|
|
ablREPORT (loc < m_ListSize,"");
|
|
|
|
ablREPORT (p1->prev == NULL,"");
|
|
ablREPORT (p1->next == NULL,"");
|
|
p1->prev = NULL;
|
|
p1->next = m_List[loc];
|
|
if (m_List[loc])
|
|
{
|
|
ablREPORT (m_List[loc],"");
|
|
m_List[loc]->prev = p1;
|
|
}
|
|
m_List[loc] = p1;
|
|
}
|
|
|
|
Rect4DHashTable::Rect4DHashTable (int size)
|
|
{
|
|
int i;
|
|
m_List = (Rect4D **) gos_Malloc (sizeof (Rect4D *) * size);
|
|
for (i=0;i<size;i++)
|
|
m_List[i] = NULL;
|
|
m_TopList = 0;
|
|
m_PermList = NULL;
|
|
m_CurrentTime = 0;
|
|
m_ListSize = size;
|
|
}
|
|
Rect4DHashTable::~Rect4DHashTable (void)
|
|
{
|
|
int i;
|
|
for (i=0;i<m_ListSize;i++)
|
|
{
|
|
KillHashLine (i);
|
|
}
|
|
gos_Free (m_List);
|
|
Rect4D *current,*temp;
|
|
current = m_PermList;
|
|
while (current)
|
|
{
|
|
temp = current;
|
|
current = current->next;
|
|
delete temp;
|
|
}
|
|
}
|
|
|
|
void Rect4DHashTable::UpdateTime (Stuff::Time curtime)
|
|
{
|
|
int temptime;
|
|
|
|
curtime *= Rect4DTimeDelta;
|
|
temptime = (int) ((float) curtime);
|
|
// temptime = Truncate_Float_To_Word ((float) curtime);
|
|
while (m_CurrentTime < temptime)
|
|
{
|
|
IncrementTime ();
|
|
}
|
|
}
|
|
|
|
void Rect4DHashTable::IncrementTime (void)
|
|
{
|
|
KillHashLine (m_TopList);
|
|
m_TopList++;
|
|
m_CurrentTime += 1;
|
|
if (m_TopList == m_ListSize)
|
|
m_TopList = 0;
|
|
}
|
|
|
|
void Rect4DHashTable::RemovePermRect (Entity *who)
|
|
{
|
|
Rect4D *current;
|
|
|
|
current = m_PermList;
|
|
while (current)
|
|
{
|
|
if (current->who == who)
|
|
{
|
|
RemovePermRect (current);
|
|
return;
|
|
}
|
|
current = current->next;
|
|
}
|
|
}
|
|
|
|
Rect4D *Rect4DHashTable::Collide (const Rect4D& p1) const
|
|
{
|
|
Verify (false);
|
|
int loc;
|
|
Rect4D *current;
|
|
// Stuff::Scalar left,right,top,bottom;
|
|
|
|
current = m_PermList;
|
|
for (current=m_PermList;current;current = current->next)
|
|
{
|
|
if (p1.who != current->who)
|
|
{
|
|
if (p1.right < current->left)
|
|
continue;
|
|
if (p1.left > current->right)
|
|
continue;
|
|
if (p1.bottom < current->top)
|
|
continue;
|
|
if (p1.top > current->bottom)
|
|
continue;
|
|
return current;
|
|
}
|
|
}
|
|
|
|
if (p1.time < m_CurrentTime)
|
|
return NULL;
|
|
|
|
if (p1.time >= (m_CurrentTime + m_ListSize))
|
|
return NULL;
|
|
|
|
loc = FindHashLine (p1);
|
|
if (loc==-1)
|
|
return NULL;
|
|
Verify (loc>=0);
|
|
Verify (loc < m_ListSize);
|
|
|
|
|
|
current = m_List[loc];
|
|
for (current=m_List[loc];current;current = current->next)
|
|
{
|
|
if (p1.who != current->who)
|
|
{
|
|
if (p1.right < current->left)
|
|
continue;
|
|
if (p1.left > current->right)
|
|
continue;
|
|
if (p1.bottom < current->top)
|
|
continue;
|
|
if (p1.top > current->bottom)
|
|
continue;
|
|
return current;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
#ifdef _ARMOR
|
|
|
|
void Rect4DHashTable::VerifyRectGone (Rect4D *p1)
|
|
{
|
|
int i;
|
|
Rect4D *current;
|
|
|
|
for (i=0;i<m_ListSize;i++)
|
|
{
|
|
current = m_List[i];
|
|
while (current)
|
|
{
|
|
Verify (current != p1);
|
|
current = current->next;
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|