convert line ends
[canaan.git] / prj / cam / src / ai / aidetect.cpp
blob5568e80609aeeda0e4d385f9ba6523e88d5e4f80
1 /*
2 @Copyright Looking Glass Studios, Inc.
3 1996,1997,1998,1999,2000 Unpublished Work.
4 */
6 ///////////////////////////////////////////////////////////////////////////////
7 // $Header: r:/t2repos/thief2/src/ai/aidetect.cpp,v 1.21 2000/02/28 18:32:54 adurant Exp $
8 //
10 // #define PROFILE_ON 1
12 #include <lg.h>
13 #include <mprintf.h>
15 #include <appagg.h>
17 #include <mtagvals.h>
19 #include <aiactmot.h>
20 #include <aiapibhv.h>
21 #include <aibasabl.h>
22 #include <aigoal.h>
23 #include <aiutils.h>
24 #include <aiactloc.h>
25 #include <aidetect.h>
26 #include <aiapiiai.h>
27 #include <aiman.h>
28 #include <aisndtyp.h>
29 #include <aisound.h>
30 #include <aisuslnk.h>
31 #include <aitagtyp.h>
32 #include <aiteams.h>
33 #include <aiwr.h>
34 #include <susprop.h>
35 #include <rendprop.h>
36 #include <iobjsys.h>
37 #include <objdef.h>
38 #include <objquery.h>
40 //#define DARK
41 #ifdef THIEF
42 #include <drkstats.h>
43 #endif
45 #include <objpos.h>
46 #include <portal.h>
48 #include <aiprops.h>
50 // Must be last header
51 #include <dbmem.h>
55 // From aibassns.cpp:
56 extern IBoolProperty * g_pAIOnlyNoticesPlayerProperty;
57 #define AIGetOnlyNoticesPlayer(obj) AIGetProperty(g_pAIOnlyNoticesPlayerProperty, (obj), (BOOL)FALSE)
59 extern IBoolProperty * g_pAINoticesBodiesProperty;
60 #define AIGetNoticesBodies(obj) AIGetProperty(g_pAINoticesBodiesProperty, (obj), (BOOL)TRUE)
63 ///////////////////////////////////////////////////////////////////////////////
65 // CLASS: cAIDetect
68 STDMETHODIMP_(const char *) cAIDetect::GetName()
70 return "Detect ability";
73 ///////////////////////////////////////
75 // constructor and destructor
76 cAIDetect::cAIDetect()
77 : m_SeenBody(FALSE), m_LastSeen(OBJ_NULL), m_Timer(kAIT_2Sec)
81 STDMETHODIMP_(void) cAIDetect::Init()
83 // YO!! if you want to try working on this, uncomment this line
84 SetNotifications(kAICN_ActionProgress);
85 m_Timer.Reset();
88 ///////////////////////////////////////
90 STDMETHODIMP_(BOOL) cAIDetect::Save(ITagFile * pTagFile)
92 if (AIOpenTagBlock(GetID(), kAISL_Detect, 0, 0, pTagFile))
94 SaveNotifications(pTagFile);
96 m_Timer.Save(pTagFile);
97 AITagMove(pTagFile, &m_SeenBody);
98 AITagMove(pTagFile, &m_LastSeen);
99 AICloseTagBlock(pTagFile);
101 return TRUE;
104 ///////////////////////////////////////
106 STDMETHODIMP_(BOOL) cAIDetect::Load(ITagFile * pTagFile)
108 if (AIOpenTagBlock(GetID(), kAISL_Detect, 0, 0, pTagFile))
110 LoadNotifications(pTagFile);
112 m_Timer.Load(pTagFile);
113 AITagMove(pTagFile, &m_SeenBody);
114 AITagMove(pTagFile, &m_LastSeen);
115 AICloseTagBlock(pTagFile);
117 return TRUE;
120 ///////////////////////////////////////
122 DECLARE_TIMER(cAIDetect_OnActionProgress, Average);
124 // see if it is time for a new action
125 STDMETHODIMP_(void) cAIDetect::OnActionProgress(IAIAction * pAction)
126 { // If we're in a good position to interrupt...
127 AUTO_TIMER(cAIDetect_OnActionProgress);
129 if (pAction->GetResult() > kAIR_NoResult)
130 if (m_Timer.Expired())
131 { // lets check again
132 if (SearchForBodies())
134 m_SeenBody=TRUE; // for now, each AI can see one body ever
136 SearchForSuspicious();
137 m_Timer.Reset();
141 ///////////////////////////////////////
143 // actually do the work
145 DECLARE_TIMER(cAIDetect_SearchForBodies, Average);
147 BOOL cAIDetect::SearchForBodies(void)
149 AUTO_TIMER(cAIDetect_SearchForBodies);
151 BOOL found_any=FALSE;
152 BOOL all_robot=TRUE;
154 #ifndef THIEF
155 //since only Thief2 has robots at the moment (at least for bodies), then
156 //clearly the bodies aren't robots if not Thief2
157 all_robot = FALSE;
158 #endif
160 tAIIter iAIIter;
161 ObjPos *ourLoc=ObjPosGet(GetID());
162 BOOL bOnlyNoticesPlayer;
163 BOOL bNoticesBodies;
165 if (m_SeenBody || m_pAIState->GetMode() != kAIM_Normal)
166 return FALSE;
168 mxs_matrix tempmatrix;
169 mx_ang2mat(&tempmatrix,&ourLoc->fac);
170 const mxs_vector ourvecfac = tempmatrix.vec[0];
172 bOnlyNoticesPlayer = AIGetOnlyNoticesPlayer(GetID());
173 bNoticesBodies = AIGetNoticesBodies(GetID());
175 /// mprintf("Body Count\n");
176 AutoAppIPtr(AIManager);
177 IAI *pAI=pAIManager->GetFirst(&iAIIter);
178 while (pAI)
180 ObjID targ=pAI->GetObjID();
181 const cAIState *pAIState=((IInternalAI *)pAI)->GetState();
182 if (ObjHasRefs(targ) && pAIState->IsDead())
184 if ((GetID() != targ) &&
185 (AITeamCompare(GetID(), targ) == kAI_Teammates) &&
186 !bOnlyNoticesPlayer &&
187 bNoticesBodies)
189 #define kBodyLookDistSq sq(15.0)
190 #define kBodyLighting 0.15
192 //make sure they are in front of us, roughly.
193 #define kBodyDotMinimum 0.0
194 ObjPos *themLoc=ObjPosGet(targ);
195 float distSq;
196 mxs_vector relfac;
197 mx_sub_vec(&relfac,&themLoc->loc.vec,&ourLoc->loc.vec);
199 // check distSqance
200 distSq=m_pAIState->DistSq(themLoc->loc.vec);
202 if ((distSq < kBodyLookDistSq) && (mx_dot_vec(&relfac,&ourvecfac) >= kBodyDotMinimum))
203 { // need to check lighting and raycast
204 Location hit;
205 if (PortalRaycast(&themLoc->loc,&ourLoc->loc,&hit,0))
206 { // should check verse objects
207 float light = AIGetObjectLighting(targ);
209 if (light > kBodyLighting)
211 m_LastSeen=targ;
212 found_any=TRUE;
213 #ifdef THIEF
214 //if not a robot, then clearly we found a non robot
215 if (!DarkStatCheckBit(targ,kDarkStatBitRobot))
216 all_robot=FALSE;
217 #endif
223 pAI->Release();
224 pAI=pAIManager->GetNext(&iAIIter);
226 pAIManager->GetDone(&iAIIter);
227 if (found_any)
229 #ifdef THIEF
230 if (!DarkStatCheckBit(m_LastSeen,kDarkStatBitFoundBody))
232 DarkStatInc(kDarkStatBodiesFound);
233 DarkStatSetBit(m_LastSeen,kDarkStatBitFoundBody,TRUE);
235 #endif
236 m_pAI->NotifyFoundBody(m_LastSeen);
237 if (m_pAI->AccessSoundEnactor())
238 //real people take priority over robots (well, maybe not for Karras), but
239 //in general. So if not every corpse is a robot, scream bloody murder.
240 //only if every corpse is a robot should we scream oily vandalism.
241 if (all_robot==FALSE)
242 m_pAI->AccessSoundEnactor()->RequestConcept(kAISC_FoundBody);
243 else
244 m_pAI->AccessSoundEnactor()->RequestConcept(kAISC_FoundRobot);
247 return found_any;
250 DECLARE_TIMER(cAIDetect_SearchForSuspicious, Average);
252 BOOL cAIDetect::SearchForSuspicious(void)
254 AUTO_TIMER(cAIDetect_SearchForSuspicious);
256 BOOL found_any=FALSE;
258 ObjPos *ourLoc=ObjPosGet(GetID());
259 ObjID m_LastSuspicious = OBJ_NULL;
261 mxs_matrix tempmatrix;
262 mx_ang2mat(&tempmatrix,&ourLoc->fac);
263 const mxs_vector ourvecfac = tempmatrix.vec[0];
266 if (m_pAIState->GetMode() != kAIM_Normal)
267 return FALSE;
269 // AutoAppIPtr(ObjectSystem);
271 // IObjectQuery* objquery = pObjectSystem->Iter(kObjectConcrete);
273 sPropertyObjIter iter;
275 StartSuspiciousIter(&iter);
277 ObjID targ;
278 BOOL iscurrentsuspicious;
280 // NextSuspiciousIter(&iter,&targ,&iscurrentsuspicious);
282 // for (; !objquery->Done(); objquery->Next())
283 // {
284 // ObjID targ = objquery->Object();
287 for (; (NextSuspiciousIter(&iter,&targ,&iscurrentsuspicious));)
289 if (!OBJ_IS_CONCRETE(targ)) continue; //only concrete objs.
291 if ((iscurrentsuspicious && (ObjHasRefs(targ)) &&
292 (!AIIsSuspiciousOfObj(GetID(),targ)))
294 ((!iscurrentsuspicious && (ObjHasRefs(targ)) &&
295 (AIIsSuspiciousOfObj(GetID(),targ)))))
296 //is it a suspicious object? (and I'm not already suspicious of it)
297 //or, alternatively, it isn't a suspicious object, and I AM
298 //suspicious of it... (which means I shouldn't be suspicious of it
299 //anymore).
301 #define kSuspiciousLookDistSq sq(15.0)
302 #define kSuspiciousLighting 0.15
303 #define kSuspiciousDotMinimum 0.0
304 ObjPos *themLoc=ObjPosGet(targ);
306 if (!themLoc) continue;
308 float distSq;
309 float minlightlevel;
311 if (!GetSuspiciousLightLevel(targ,&minlightlevel))
312 minlightlevel = kSuspiciousLighting;
314 mxs_vector relfac;
315 mx_sub_vec(&relfac,&themLoc->loc.vec,&ourLoc->loc.vec);
317 // check distSqance
318 distSq=m_pAIState->DistSq(themLoc->loc.vec);
319 //close enough, and facing the right way.
320 if ((distSq < kSuspiciousLookDistSq) &&
321 (mx_dot_vec(&relfac,&ourvecfac) >= kSuspiciousDotMinimum))
322 { // need to check lighting and raycast
323 Location hit;
324 if (PortalRaycast(&themLoc->loc,&ourLoc->loc,&hit,0))
325 { // should check verse objects
326 float light = AIGetObjectLighting(targ);
328 if (light > minlightlevel)
330 if (!AIIsSuspiciousOfObj(GetID(),targ))
332 m_LastSuspicious=targ;
333 //ok, remember that I'm suspicious of it.
334 AICreateSuspiciousLink(GetID(),targ);
335 found_any = TRUE;
337 else
339 //we were suspicious of it, but shouldn't
340 //be now... so become unsuspicious of it.
341 AIClearSuspiciousLinks(GetID(),targ);
345 }//end dist check
346 } //end if suspicious/not suspicious
347 } //end for
348 // objquery->Release();
350 StopSuspiciousIter(&iter);
352 if (found_any)
353 m_pAI->NotifyFoundSuspicious(m_LastSuspicious);
355 return found_any;