convert line ends
[canaan.git] / prj / cam / src / ai / aiutils.h
blob7f6d880c6a108451612196594ac789a52bc07fd9
1 /*
2 @Copyright Looking Glass Studios, Inc.
3 1996,1997,1998,1999,2000 Unpublished Work.
4 */
6 ///////////////////////////////////////////////////////////////////////////////
7 // $Header: r:/t2repos/thief2/src/ai/aiutils.h,v 1.20 2000/02/28 19:35:19 bfarquha Exp $
8 //
9 // Utility functions and wrappers to the outside world
12 #ifndef __AIUTILS_H
13 #define __AIUTILS_H
15 #pragma once
17 #include <dynarray.h>
19 #include <aitype.h>
20 #include <aidist.h>
21 #include <rand.h>
22 #include <simtime.h>
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
47 #define kLineIdent 2
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 ///////////////////////////////////////////////////////////////////////////////
83 // Door manipulation
86 enum eAIDoorFlags
88 kAIDF_BlocksVision = 0x01,
89 kAIDF_LargeDoor = 0x02
92 struct sAIDoorInfo
94 ObjID obj;
95 unsigned flags;
98 const cDynArray<sAIDoorInfo> & AIGetDoors();
99 void AIUpdateDoors();
101 ///////////////////
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);
108 ///////////////////
110 struct sAIDoorBBox
112 ObjID object;
113 tAIFloorBBox bbox;
116 void AIGetDoorFloorBBoxes(cDynArray<sAIDoorBBox> *);
118 ///////////////////////////////////////////////////////////////////////////////
120 #define AIGetTime() GetSimTime()
121 #define AIGetFrameTime() GetSimFrameTime()
123 ///////////////////////////////////////////////////////////////////////////////
125 #define AIRandom(low, high) \
126 RandRange(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>
154 inline
155 tOption * _AIDecide(tOption ** ppOptions,
156 tCount nOptions,
157 tAICompareFunc pfnCompare,
158 void * pTieBreakVoid)
160 tOption ** ppFirstBest;
161 tOption ** ppLastBest;
162 tOption * pTieBreak = (tOption *) pTieBreakVoid;
164 // Quick outs...
165 if (!nOptions)
166 return NULL;
168 if (nOptions == 1)
169 return *ppOptions;
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)
178 return pTieBreak;
180 // Now, check if we have equal options...
181 ppFirstBest = ppLastBest;
183 while (ppFirstBest > ppOptions)
185 if ((*pfnCompare)(ppFirstBest - 1, ppLastBest) == 0)
186 ppFirstBest--;
187 else
188 break;
191 // If we have equal options, pick one at random
192 int range = ppLastBest - ppFirstBest;
194 if (range == 0)
195 return *ppLastBest;
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.
207 enum eAITimerPeriod
209 kAIT_Min = 1,
211 kAIT_40Hz = 25,
212 kAIT_20Hz = 50,
213 kAIT_10Hz = 100,
214 kAIT_2Hz = 500,
216 kAIT_1Sec = 1000,
217 kAIT_2Sec = 2000,
218 kAIT_10Sec = 10000,
219 kAIT_20Sec = 20000,
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))
234 class cAITimer
236 public:
237 cAITimer(eAITimerPeriod period = kAIT_Default);
239 void Set(eAITimerPeriod period);
240 void Reset();
242 BOOL Expired() const;
244 unsigned Remaining() const;
246 void Force();
247 void Delay(unsigned delay);
249 void Save(ITagFile *);
250 void Load(ITagFile *);
252 private:
253 unsigned m_Expiration;
254 unsigned m_Period;
257 ///////////////////////////////////////////////////////////////////////////////
259 // Variant of timer used for "random" activity
262 class cAIRandomTimer
264 public:
265 cAIRandomTimer(unsigned low, unsigned high);
267 void Set(unsigned low, unsigned high);
268 void Reset();
270 BOOL Expired() const;
272 unsigned Remaining() const;
274 void Force();
275 void Delay(unsigned delay);
277 void Save(ITagFile *);
278 void Load(ITagFile *);
280 private:
281 unsigned m_Expiration;
282 ushort m_Low;
283 ushort m_High;
286 ///////////////////////////////////////////////////////////////////////////////
288 // cAITimer inline functions
291 inline cAITimer::cAITimer(eAITimerPeriod period)
292 : m_Expiration(0),
293 m_Period(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)
314 return 0;
316 return m_Expiration - time;
319 ///////////////////////////////////////
321 inline void cAITimer::Reset()
323 m_Expiration = AIGetTime() + m_Period;
326 ///////////////////////////////////////
328 inline void cAITimer::Force()
330 m_Expiration = 0;
333 ///////////////////////////////////////
335 inline void cAITimer::Set(eAITimerPeriod period)
337 m_Period = 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)
354 : m_Expiration(0),
355 m_Low((ushort)low),
356 m_High((ushort)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)
377 return 0;
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()
393 m_Expiration = 0;
396 ///////////////////////////////////////
398 inline void cAIRandomTimer::Set(unsigned low, unsigned high)
400 m_Low = (ushort)low;
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 */