Files
Cyd 2b8ca921cb Initial full mirror of c:\VWE (source + assets + toolchain + outputs) via Git LFS
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.
2026-06-24 21:28:16 -05:00

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
};