2 @Copyright Looking Glass Studios, Inc.
3 1996,1997,1998,1999,2000 Unpublished Work.
6 ///////////////////////////////////////////////////////////////////////////////
7 // $Header: r:/t2repos/thief2/src/ai/aiutils.h,v 1.20 2000/02/28 19:35:19 bfarquha Exp $
9 // Utility functions and wrappers to the outside world
24 F_DECLARE_INTERFACE(ITagFile
);
26 ///////////////////////////////////////////////////////////////////////////////
28 inline void ProjectFromLocationOnZPlane(const mxs_vector
& startLoc
, float distance
, floatang angle
, mxs_vector
* pResult
)
30 pResult
->x
= startLoc
.x
+ cos(angle
.value
) * distance
;
31 pResult
->y
= startLoc
.y
+ sin(angle
.value
) * distance
;
32 pResult
->z
= startLoc
.z
;
35 ///////////////////////////////////////////////////////////////////////////////
37 inline float AICompueZAngle(const mxs_vector
& fromLoc
, const mxs_vector
& toLoc
)
39 floatang
result(0, 0, AIXYDistance(fromLoc
, toLoc
), ffabsf(fromLoc
.z
- toLoc
.z
));
40 return ffabsf(result
.value
);
43 ///////////////////////////////////////////////////////////////////////////////
45 #define kLineIntersect 0
46 #define kLineNoIntersect 1
49 int GetXYIntersection(const mxs_vector
& line1a
, const mxs_vector
& line1b
,
50 const mxs_vector
& line2a
, const mxs_vector
& line2b
,
51 mxs_vector
* pResult
);
53 int GetXYSegmentIntersect(const mxs_vector
& seg1a
, const mxs_vector
& seg1b
,
54 const mxs_vector
& seg2a
, const mxs_vector
& seg2b
,
55 mxs_vector
* pResult
);
57 int GetXYLineSegIntersect(const mxs_vector
& line1a
, const mxs_vector
& line1b
,
58 const mxs_vector
& seg2a
, const mxs_vector
& seg2b
,
59 mxs_vector
* pResult
);
61 ///////////////////////////////////////////////////////////////////////////////
63 // Object manipulation
66 typedef struct Position Position
;
68 BOOL
GetObjPosition(ObjID obj
, Position
* p
);
69 BOOL
GetObjLocation(ObjID obj
, mxs_vector
* p
);
70 const mxs_vector
* GetObjLocation(ObjID obj
);
71 BOOL
GetObjFacing(ObjID obj
, floatang
* pFacing
);
72 void GetObjVelocity(ObjID obj
, mxs_vector
* p
);
73 void GetObjAngVelocity(ObjID obj
, mxs_vector
* p
);
74 void SetObjImpulse(ObjID obj
, float x
, float y
, float z
, float facing
, BOOL rotating
= TRUE
);
76 typedef mxs_vector tAIFloorBBox
[4];
77 BOOL
AIGetObjFloorBBox(ObjID object
, tAIFloorBBox
* pBBox
, const mxs_vector
* pAltLoc
= NULL
, const mxs_angvec
* pAltFac
= NULL
);
79 BOOL
AIGetPhysSphereZMinMax(ObjID object
, float *pMinZ
, float *pMaxZ
);
81 ///////////////////////////////////////////////////////////////////////////////
88 kAIDF_BlocksVision
= 0x01,
89 kAIDF_LargeDoor
= 0x02
98 const cDynArray
<sAIDoorInfo
> & AIGetDoors();
103 BOOL
AICanOpenDoor(ObjID ai
, ObjID obj
);
104 BOOL
AIDoorIsOpen(ObjID obj
);
105 void AIOpenDoor(ObjID ai
, ObjID door
);
106 void AICloseDoor(ObjID ai
, ObjID door
, BOOL all
=TRUE
);
116 void AIGetDoorFloorBBoxes(cDynArray
<sAIDoorBBox
> *);
118 ///////////////////////////////////////////////////////////////////////////////
120 #define AIGetTime() GetSimTime()
121 #define AIGetFrameTime() GetSimFrameTime()
123 ///////////////////////////////////////////////////////////////////////////////
125 #define AIRandom(low, high) \
128 ///////////////////////////////////////////////////////////////////////////////
130 // FUNCTION: AIDecide
132 // Most Dark AI decisions are intended to be based on simple comparisons
133 // of choices with clear tie-breaking rules. In the case of a perfect tie,
134 // the choice is random. This template function standardizes this process
135 // for anyone in the AI who needs to make such decisions. To use it, you'll
136 // simply need to write a sort function.
138 // Note the macro use and voids are here only to allow both Microsoft and
139 // Watcom to both compile.
141 // The compare function prototype is:
142 // int MyCompare(tOption **, tOption **)
144 typedef int (*tAICompareFunc
)(const void *, const void *);
146 ///////////////////////////////////////
148 #define AIDecide(ppOptions, nOptions, pfnCompare, pTieBreak) \
149 _AIDecide(ppOptions, nOptions, ((tAICompareFunc)pfnCompare), (void *)(pTieBreak))
151 ///////////////////////////////////////
153 template <class tOption
, class tCount
>
155 tOption
* _AIDecide(tOption
** ppOptions
,
157 tAICompareFunc pfnCompare
,
158 void * pTieBreakVoid
)
160 tOption
** ppFirstBest
;
161 tOption
** ppLastBest
;
162 tOption
* pTieBreak
= (tOption
*) pTieBreakVoid
;
171 // First, sort the array. The best options will be at the end...
172 qsort(ppOptions
, nOptions
, sizeof(tOption
*), pfnCompare
);
174 ppLastBest
= ppOptions
+ (nOptions
- 1);
176 // If the current activity is of equal value as the best, just keep on with that
177 if (pTieBreak
&& (*pfnCompare
)((const void *)(&pTieBreak
), (const void *)(ppLastBest
)) == 0)
180 // Now, check if we have equal options...
181 ppFirstBest
= ppLastBest
;
183 while (ppFirstBest
> ppOptions
)
185 if ((*pfnCompare
)(ppFirstBest
- 1, ppLastBest
) == 0)
191 // If we have equal options, pick one at random
192 int range
= ppLastBest
- ppFirstBest
;
197 return *(ppFirstBest
+ AIRandom(0, range
));
200 ///////////////////////////////////////////////////////////////////////////////
202 // CLASS: cAITimer; consolodation of AI's simple scheduling mechanism
204 // Times are set out as an enum to reduce phase shifting issues somewhat.
221 kAIT_Infinite
= 0x7fffffff,
223 // AI elements run 20 by default
224 kAIT_Default
= kAIT_20Hz
,
225 kAIT_Max
= 0xffffffff,
229 // This is a type violation, but a mild one. If you really
230 // want a nonstandard time, use this to make it
232 #define AICustomTime(t) ((eAITimerPeriod)(t))
237 cAITimer(eAITimerPeriod period
= kAIT_Default
);
239 void Set(eAITimerPeriod period
);
242 BOOL
Expired() const;
244 unsigned Remaining() const;
247 void Delay(unsigned delay
);
249 void Save(ITagFile
*);
250 void Load(ITagFile
*);
253 unsigned m_Expiration
;
257 ///////////////////////////////////////////////////////////////////////////////
259 // Variant of timer used for "random" activity
265 cAIRandomTimer(unsigned low
, unsigned high
);
267 void Set(unsigned low
, unsigned high
);
270 BOOL
Expired() const;
272 unsigned Remaining() const;
275 void Delay(unsigned delay
);
277 void Save(ITagFile
*);
278 void Load(ITagFile
*);
281 unsigned m_Expiration
;
286 ///////////////////////////////////////////////////////////////////////////////
288 // cAITimer inline functions
291 inline cAITimer::cAITimer(eAITimerPeriod period
)
297 ///////////////////////////////////////
299 inline BOOL
cAITimer::Expired() const
301 return (!m_Expiration
|| AIGetTime() > m_Expiration
);
304 ///////////////////////////////////////
306 inline unsigned cAITimer::Remaining() const
308 if (m_Expiration
== kAIT_Infinite
)
309 return kAIT_Infinite
;
311 unsigned time
= AIGetTime();
313 if (!m_Expiration
|| time
> m_Expiration
)
316 return m_Expiration
- time
;
319 ///////////////////////////////////////
321 inline void cAITimer::Reset()
323 m_Expiration
= AIGetTime() + m_Period
;
326 ///////////////////////////////////////
328 inline void cAITimer::Force()
333 ///////////////////////////////////////
335 inline void cAITimer::Set(eAITimerPeriod period
)
338 m_Expiration
= AIGetTime() + m_Period
;
341 ///////////////////////////////////////
343 inline void cAITimer::Delay(unsigned delay
)
345 m_Expiration
= (delay
== kAIT_Infinite
) ? kAIT_Infinite
: AIGetTime() + delay
;
348 ///////////////////////////////////////////////////////////////////////////////
350 // cAIRandomTimer inline functions
353 inline cAIRandomTimer::cAIRandomTimer(unsigned low
, unsigned high
)
360 ///////////////////////////////////////
362 inline BOOL
cAIRandomTimer::Expired() const
364 return (m_High
&& (!m_Expiration
|| AIGetTime() > m_Expiration
));
367 ///////////////////////////////////////
369 inline unsigned cAIRandomTimer::Remaining() const
371 if (m_Expiration
== kAIT_Infinite
)
372 return kAIT_Infinite
;
374 unsigned time
= AIGetTime();
376 if (!m_Expiration
|| time
> m_Expiration
)
379 return m_Expiration
- time
;
382 ///////////////////////////////////////
384 inline void cAIRandomTimer::Reset()
386 m_Expiration
= AIGetTime() + AIRandom(m_Low
, m_High
);
389 ///////////////////////////////////////
391 inline void cAIRandomTimer::Force()
396 ///////////////////////////////////////
398 inline void cAIRandomTimer::Set(unsigned low
, unsigned high
)
401 m_High
= (ushort
)high
;
402 m_Expiration
= AIGetTime() + AIRandom(m_Low
, m_High
);
405 ///////////////////////////////////////
407 inline void cAIRandomTimer::Delay(unsigned delay
)
409 m_Expiration
= (delay
== kAIT_Infinite
) ? kAIT_Infinite
: AIGetTime() + delay
;
412 ///////////////////////////////////////////////////////////////////////////////
414 void CalcArc(mxs_vector
* pDir
, float initVelocity
, float gravity
);
416 ///////////////////////////////////////////////////////////////////////////////
418 BOOL
DoorIsBig(ObjID door
);
420 #endif /* !__AIUTILS_H */