Files
firestorm/Gameleap/code/mw4/Code/MW4/aiutils.hpp
T
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

759 lines
17 KiB
C++

#pragma once
#ifndef __AIUTILSHPP__
#define __AIUTILSHPP__
#include <stuff\stuff.hpp>
#include <adept\entity.hpp>
#pragma warning (disable:4284)
#pragma warning (push)
#include <stlport\vector>
#include <stlport\stack>
#include <stlport\string>
#pragma warning (pop)
namespace MW4AI
{
extern HGOSHEAP g_AIHeap,g_MoverAIHeap,g_CombatAIHeap,g_RailHeap;
struct AutoHeap
{
AutoHeap (HGOSHEAP p1)
{
gos_PushCurrentHeap (p1);
}
~AutoHeap (void)
{
gos_PopCurrentHeap ();
}
};
#if !defined(NO_TIMERS)
extern std::stack<__int64 *> *g_TimerStack;
struct my_AutoTimer
{
__int64 starttime;
my_AutoTimer (void *p1)
{
Verify (g_TimerStack);
starttime = GetCycles ();
g_TimerStack->push ((__int64 *) p1);
}
~my_AutoTimer (void)
{
Verify (g_TimerStack->size ());
starttime = GetCycles () - starttime;
*(g_TimerStack->top ()) += starttime;
g_TimerStack->pop ();
if (g_TimerStack->size ())
{
*(g_TimerStack->top ()) -= starttime;
}
}
};
#endif
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// bunch of random helper functions below ...
#define NOT_YET_IMPLEMENTED Verify(!"Not yet implemented.");
inline Stuff::Scalar NormalizedValue(Stuff::Scalar value, Stuff::Scalar min, Stuff::Scalar max, bool invert = false)
{
Stuff::Scalar rv((value - min) / (max - min));
if (invert == true)
{
rv = 1 - rv;
}
Clamp(rv,0,1);
return (rv);
}
inline Stuff::Scalar RandomlySkewScalar(Stuff::Scalar value, Stuff::Scalar skew_amount)
{
Stuff::Scalar skew = (Stuff::Random::GetFraction() * 2) - 1.0f;
return (value + (skew * skew_amount));
}
inline void OffsetTargetPoint(Stuff::Point3D& p, Stuff::Scalar amount)
{
p.x = RandomlySkewScalar(p.x,amount);
p.y = RandomlySkewScalar(p.y,amount * 1.2f);
p.z = RandomlySkewScalar(p.z,amount);
}
inline Stuff::Scalar NormalizedInterpolation(Stuff::Scalar normalized_value, Stuff::Scalar min, Stuff::Scalar max)
{
Verify(normalized_value >= 0);
Verify(normalized_value <= 1);
return ((normalized_value * max) + ((1 - normalized_value) * min));
}
template <class T>
inline T& RandomElement(std::vector<T>& v)
{
return (v[gos_rand() % v.size()]);
}
template <class T>
inline const T& RandomElement(const std::vector<T>& v)
{
return (v[gos_rand() % v.size()]);
}
#if !defined(NO_TIMERS)
class GOSTimer
{
public:
GOSTimer(__int64& time_variable)
: m_Variable(time_variable)
, m_StartTime(GetCycles())
{ }
~GOSTimer()
{
m_Variable += GetCycles() - m_StartTime;
}
private:
__int64& m_Variable;
__int64 m_StartTime;
};
#define TIME_FUNCTION(variable_name) GOSTimer gos_timer##variable_name(variable_name)
#else
#define TIME_FUNCTION(variable_name)
#endif
inline Stuff::Scalar GetLengthSquared(const Stuff::Vector3D& vector1, const Stuff::Vector3D& vector2)
{
Stuff::Vector3D delta;
delta.Subtract(vector1,vector2);
return (delta.GetLengthSquared());
}
inline Stuff::Scalar GetApproximateLength(const Stuff::Vector3D& vector1, const Stuff::Vector3D& vector2)
{
Stuff::Vector3D delta;
delta.Subtract(vector1,vector2);
return (delta.GetApproximateLength());
}
inline Stuff::Scalar Sign(Stuff::Scalar value)
{
if (value < 0)
{
return (-1);
}
return (1);
}
inline Stuff::Vector3D RotateVector(const Stuff::Point3D& point_to_rotate, const Stuff::Point3D& relative_to, Stuff::Scalar radians, Stuff::Scalar length_multiplier = 1)
{
Stuff::Vector3D delta;
delta.Subtract(point_to_rotate,relative_to);
delta.y = 0;
delta *= length_multiplier;
Stuff::YawPitchRoll ypr(radians,0,0);
Stuff::AffineMatrix4D rotation_matrix(ypr);
Stuff::Vector3D rv;
rv.Multiply(delta,rotation_matrix);
rv += relative_to;
return (rv);
}
inline Stuff::Scalar GetSquaredDistToMatrixForward(const Stuff::Point3D& point, const Stuff::LinearMatrix4D& matrix)
{
Stuff::UnitVector3D forward_vector;
matrix.GetLocalForwardInWorld(&forward_vector);
Stuff::Point3D forward(forward_vector);
forward += (Stuff::Point3D)matrix;
return (GetLengthSquared(point,forward));
}
inline Stuff::Scalar GetSquaredDistToMatrixBackward(const Stuff::Point3D& point, const Stuff::LinearMatrix4D& matrix)
{
Stuff::UnitVector3D backward_vector;
matrix.GetLocalBackwardInWorld(&backward_vector);
Stuff::Point3D backward(backward_vector);
backward += (Stuff::Point3D)matrix;
return (GetLengthSquared(point,backward));
}
inline Stuff::Scalar GetSquaredDistToMatrixLeft(const Stuff::Point3D& point, const Stuff::LinearMatrix4D& matrix)
{
Stuff::UnitVector3D left_vector;
matrix.GetLocalLeftInWorld(&left_vector);
Stuff::Point3D left(left_vector);
left += (Stuff::Point3D)matrix;
return (GetLengthSquared(point,left));
}
inline Stuff::Scalar GetSquaredDistToMatrixRight(const Stuff::Point3D& point, const Stuff::LinearMatrix4D& matrix)
{
Stuff::UnitVector3D right_vector;
matrix.GetLocalRightInWorld(&right_vector);
Stuff::Point3D right(right_vector);
right += (Stuff::Point3D)matrix;
return (GetLengthSquared(point,right));
}
inline Stuff::Scalar YawToPoint(const Stuff::LinearMatrix4D& matrix, const Stuff::Point3D& point)
{
Stuff::Point3D matrix_to_point;
matrix_to_point.MultiplyByInverse(point,matrix);
// the following code adapted from YawPitchRange::operator=()
Stuff::Scalar sub_range(matrix_to_point.x*matrix_to_point.x + matrix_to_point.z*matrix_to_point.z);
Stuff::Scalar range(SqrtApproximate(sub_range + matrix_to_point.y*matrix_to_point.y));
if (Stuff::Small_Enough(range))
{
return (0.0f);
}
sub_range = SqrtApproximate(sub_range);
if (Stuff::Small_Enough(sub_range))
{
return (0.0f);
}
return (Stuff::Arctan(matrix_to_point.x, matrix_to_point.z));
}
inline bool MatrixFacesPoint(const Stuff::LinearMatrix4D& matrix, const Stuff::Point3D& point, Stuff::Scalar angle)
{
Stuff::Point3D matrix_to_point;
matrix_to_point.MultiplyByInverse(point,matrix);
angle = Stuff::Fabs(angle);
// the following code adapted from YawPitchRange::operator=()
Verify((Vector3D::Forward.z == 1.0f) && (Vector3D::Left.x == 1.0f) && (Vector3D::Up.y == 1.0f));
Stuff::Scalar sub_range(matrix_to_point.x*matrix_to_point.x + matrix_to_point.z*matrix_to_point.z);
Stuff::Scalar range(Stuff::SqrtApproximate(sub_range + matrix_to_point.y*matrix_to_point.y));
if (Stuff::Small_Enough(range))
{
return (true);
}
sub_range = Stuff::SqrtApproximate(sub_range);
if (Stuff::Small_Enough(sub_range))
{
return (angle < Stuff::Pi_Over_2);
}
if (Stuff::Fabs(Stuff::Arctan(matrix_to_point.x, matrix_to_point.z)) > angle)
{
return (false);
}
return (Stuff::Arctan(matrix_to_point.y, sub_range) < angle);
}
inline bool MatrixFacesPoint_PitchOnly(const Stuff::LinearMatrix4D& matrix, const Stuff::Point3D& point, Stuff::Scalar angle)
{
Stuff::Point3D matrix_to_point;
matrix_to_point.MultiplyByInverse(point,matrix);
angle = Stuff::Fabs(angle);
// the following code adapted from YawPitchRange::operator=()
Verify((Vector3D::Forward.z == 1.0f) && (Vector3D::Left.x == 1.0f) && (Vector3D::Up.y == 1.0f));
Stuff::Scalar sub_range(matrix_to_point.x*matrix_to_point.x + matrix_to_point.z*matrix_to_point.z);
Stuff::Scalar range(Stuff::SqrtApproximate(sub_range + matrix_to_point.y*matrix_to_point.y));
if (Stuff::Small_Enough(range))
{
return (true);
}
sub_range = Stuff::SqrtApproximate(sub_range);
if (Stuff::Small_Enough(sub_range))
{
return (angle < Stuff::Pi_Over_2);
}
return (Stuff::Arctan(matrix_to_point.y, sub_range) < angle);
}
inline Stuff::Scalar TimeToCollide(const Stuff::LinearMatrix4D& collidee_matrix,
Stuff::Scalar collidee_speed,
const Stuff::Point3D& collider_pos,
Stuff::Scalar collider_speed)
{
Stuff::UnitVector3D _his_forward;
collidee_matrix.GetLocalForwardInWorld(&_his_forward);
Stuff::Point3D his_forward(_his_forward);
his_forward *= collidee_speed;
Stuff::Point3D my_forward;
my_forward.Subtract((Stuff::Point3D)collidee_matrix,collider_pos);
if (Stuff::Small_Enough(my_forward.GetLengthSquared()) == true)
{
return (0);
}
my_forward.Normalize(my_forward);
my_forward *= collider_speed;
Stuff::Point3D delta;
delta.Subtract(his_forward,my_forward);
delta.y = 0;
Stuff::Scalar denominator = delta.GetApproximateLength();
if (Stuff::Small_Enough(denominator) == true)
{
return (0);
}
Stuff::Point3D distance;
distance.Subtract((Stuff::Point3D)collidee_matrix,collider_pos);
distance.y = 0;
return (distance.GetApproximateLength() / denominator);
}
inline std::string ScalarToString(Stuff::Scalar scalar)
{
char buf[40];
sprintf(buf,"%.1f",scalar);
return (buf);
}
inline std::string Point3DToString(const Stuff::Point3D& point)
{
char buf[100];
sprintf(buf,"(%.1f %.1f %.1f)",point.x,point.y,point.z);
return (buf);
}
inline std::string IntToString(int i)
{
char buf[100];
sprintf(buf,"%d",i);
return (buf);
}
inline std::string BoolToString(bool b)
{
if (b == true)
{
return ("true");
}
return ("false");
}
template <class InputIterator, class EqualityComparable>
__STL_DIFFERENCE_TYPE(InputIterator)
index_of(InputIterator first, InputIterator last, const EqualityComparable& value)
{
__STL_DIFFERENCE_TYPE(InputIterator) n = 0;
{for (;
first != last;
++first)
{
if (*first == value)
{
break;
}
++n;
}}
return (n);
}
inline bool LinePenetrates(const Stuff::Line3D& line, const Stuff::Point3D& point, Stuff::Scalar radius)
{
Stuff::Sphere sphere(point,radius);
Stuff::Scalar penetration;
if (line.GetDistanceTo(sphere,&penetration) < 0)
{
return (false);
}
return (true);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
namespace MW4AI
{
Stuff::Scalar GetMapY(Stuff::Scalar x, Stuff::Scalar z,Adept::Entity *who,BYTE& material,Stuff::Scalar basey=-1.0f, Adept::Entity** entity_hit = 0);
inline void ConvertPointToGrid (Stuff::Point3D& pt)
{
/*
pt.x /= 10.0f;
pt.y /= 10.0f;
pt.z /= 10.0f;
pt.x *= 10.0f;
pt.y *= 10.0f;
pt.z *= 10.0f;
pt.x += 5.0f;
pt.y += 5.0f;
pt.z += 5.0f;
*/
}
inline long ConvertKPHtoMPS (long value)
{
Stuff::Scalar temp;
temp = (Stuff::Scalar) value;
temp = (temp * 1000.0f)/ (60.0f*60.0f);
return (long) temp;
}
inline float ConvertKPHtoMPSFloat (long value)
{
Stuff::Scalar temp;
temp = (Stuff::Scalar) value;
temp = (temp * 1000.0f)/ (60.0f*60.0f);
return temp;
}
class CTimeServer
{
protected:
Stuff::Time m_StartTime;
Stuff::Time m_MarkTime;
Stuff::Time m_PauseTime;
Stuff::Time m_PauseStartTime;
Stuff::Time m_StopTime;
unsigned int m_Paused;
bool m_Running;
public:
CTimeServer (void);
~CTimeServer (void);
void Tick (Stuff::Time till);
void Start (void);
void Stop (void);
void Pause (bool on);
void Mark (void)
{ m_MarkTime = gos_GetElapsedTime (); }
bool Running (void) const
{ return m_Running; }
Stuff::Time Elapsed (void)
{ return ElapsedRaw (); }
Stuff::Time CurrTime (void)
{ return CurrTimeRaw (); }
Stuff::Time ElapsedRaw (void); // since last mark point
Stuff::Time CurrTimeRaw (void); // since start time
Stuff::Time StartTime (void) const
{ return m_StartTime; }
Stuff::Time StopTime (void) const
{ return m_StopTime; }
Stuff::Time PauseTime (void) const
{ return m_PauseTime; }
void SetTime (Stuff::Time amount)
{
Verify (m_Running);
m_StartTime = 0;
m_MarkTime = 0;
if (m_Paused)
{
m_PauseStartTime = gos_GetElapsedTime ();
}
m_StopTime = 0;
m_PauseTime = 0;
m_StartTime = gos_GetElapsedTime () - amount;
}
void AddTime (Stuff::Time amount)
{ m_StartTime -= amount; }
};
inline double Normalize (const double& value,const double& min,const double& max)
{
Verify ((max-min) != 0);
return ((value-min) / (max-min));
}
template<class _A1, class _A2, class _R>
struct binary_function {
typedef _A1 first_argument_type;
typedef _A2 second_argument_type;
typedef _R result_type;
};
template<class _A1, class _R>
struct unary_function {
typedef _A1 first_argument_type;
typedef _R result_type;
};
template<class _Ty>
struct less : binary_function<_Ty, _Ty, bool> {
bool operator()(const _Ty& _X, const _Ty& _Y) const
{return (_X < _Y); }
};
template <class _Type,bool insertoptimize=true , class _Cmp = less <_Type> >
class my_heap
{
private:
struct my_heapNode
{
my_heapNode *m_Next,*m_Prev;
_Type m_Data;
my_heapNode(const _Type& data)
{ m_Data = data; m_Next = m_Prev = NULL;}
~my_heapNode(void)
{ m_Next = m_Prev = NULL;}
const _Type& Data (void) const
{ return m_Data; }
_Type& Data (void)
{ return m_Data; }
};
my_heapNode *m_Root;
int m_NumNodes;
public:
my_heap(void)
{ m_Root = NULL; m_NumNodes=0;}
virtual ~my_heap()
{
my_heapNode *cur,*temp;
cur = m_Root;
while (cur)
{
temp = cur->m_Next;
delete cur;
cur = temp;
}
m_Root = NULL;
}
void clear (void)
{
my_heapNode *cur,*temp;
cur = m_Root;
while (cur)
{
temp = cur->m_Next;
delete cur;
cur = temp;
}
m_Root = NULL;
m_NumNodes = 0;
}
// The Standard Heap Operations
void Insert(const _Type& NodeData)
{
my_heapNode *NewNode;
NewNode = new my_heapNode (NodeData);
my_heapNode *cur,*prev;
NewNode->m_Next = NewNode->m_Prev = NULL;
m_NumNodes++;
if (insertoptimize)
{
NewNode->m_Next = m_Root;
if (m_Root)
m_Root->m_Prev = NewNode;
m_Root = NewNode;
}
else
{
_Cmp value_compare;
if (!m_Root)
{
m_Root = NewNode;
m_Root->m_Next = m_Root->m_Prev = NULL;
return;
}
cur = m_Root->m_Next;
prev = m_Root;
while (cur)
{
if ( value_compare (cur->Data () , NewNode->Data ()))
{
NewNode->m_Prev = cur->m_Prev;
NewNode->m_Next = cur;
if (cur->m_Prev)
cur->m_Prev->m_Next = NewNode;
cur->m_Prev = NewNode;
return;
}
prev = cur;
cur = cur->m_Next;
}
Verify (prev->m_Next == NULL);
prev->m_Next = NewNode;
NewNode->m_Prev = prev;
NewNode->m_Next = NULL;
}
}
void Union(my_heap<_Type> *OtherHeap)
{
_Type& cur;
while (OtherHeap->size ())
{
cur = OtherHeap->ExtractMin ();
Insert (cur);
}
}
const _Type& Minimum(void) const
{
_Type toret;
my_heapNode *cur;
Verify (m_Root);
Verify (m_NumNodes);
if (insertoptimize)
{
_Cmp value_compare;
my_heapNode *min;
cur = m_Root;
min = cur;
cur = cur->m_Next;
while (cur)
{
if ( value_compare (cur->Data () , min->Data ()))
min = cur;
cur = cur->m_Next;
}
return min->Data ();
}
else
{
return m_Root->Data ();
}
}
_Type ExtractMin(void)
{
_Type toret;
my_heapNode *cur;
Verify (m_Root);
Verify (m_NumNodes);
m_NumNodes--;
if (insertoptimize)
{
_Cmp value_compare;
my_heapNode *min;
cur = m_Root;
min = cur;
cur = cur->m_Next;
while (cur)
{
if ( value_compare (cur->Data () , min->Data ()))
min = cur;
cur = cur->m_Next;
}
if (min->m_Prev)
min->m_Prev->m_Next = min->m_Next;
if (min->m_Next)
min->m_Next->m_Prev = min->m_Prev;
if (m_Root == min)
m_Root = min->m_Next;
toret = min->Data ();
delete min;
}
else
{
cur = m_Root;
m_Root = m_Root->m_Next;
m_Root->m_Prev = NULL;
toret = cur->Data ();
delete cur;
}
return toret;
}
void DecreaseKey(const _Type& theNode)
{
if (Delete (theNode))
Insert (theNode);
}
bool Member (const _Type& theNode)
{
my_heapNode *cur;
cur = m_Root;
while (cur)
{
if (cur->Data () == theNode)
return true;
cur = cur->m_Next;
}
return false;
}
bool Delete(const _Type& theNode)
{
my_heapNode *cur;
cur = m_Root;
while (cur)
{
if (cur->Data () == theNode)
break;
cur = cur->m_Next;
}
if (!cur)
return false;
m_NumNodes--;
if (cur->m_Next)
cur->m_Next->m_Prev = cur->m_Prev;
if (cur->m_Prev)
cur->m_Prev->m_Next = cur->m_Next;
if (cur == m_Root)
m_Root = m_Root->m_Next;
cur->m_Next = NULL;
cur->m_Prev = NULL;
delete cur;
return true;
}
// Extra utility functions
long size(void) { return m_NumNodes; }
};
}
#endif