2 @Copyright Looking Glass Studios, Inc.
3 1996,1997,1998,1999,2000 Unpublished Work.
6 ///////////////////////////////////////////////////////////////////////////////
7 // $Header: r:/t2repos/thief2/src/ai/aidetect.cpp,v 1.21 2000/02/28 18:32:54 adurant Exp $
10 // #define PROFILE_ON 1
50 // Must be last header
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 ///////////////////////////////////////////////////////////////////////////////
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
);
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
);
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
);
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();
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
;
155 //since only Thief2 has robots at the moment (at least for bodies), then
156 //clearly the bodies aren't robots if not Thief2
161 ObjPos
*ourLoc
=ObjPosGet(GetID());
162 BOOL bOnlyNoticesPlayer
;
165 if (m_SeenBody
|| m_pAIState
->GetMode() != kAIM_Normal
)
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
);
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
&&
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
);
197 mx_sub_vec(&relfac
,&themLoc
->loc
.vec
,&ourLoc
->loc
.vec
);
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
205 if (PortalRaycast(&themLoc
->loc
,&ourLoc
->loc
,&hit
,0))
206 { // should check verse objects
207 float light
= AIGetObjectLighting(targ
);
209 if (light
> kBodyLighting
)
214 //if not a robot, then clearly we found a non robot
215 if (!DarkStatCheckBit(targ
,kDarkStatBitRobot
))
224 pAI
=pAIManager
->GetNext(&iAIIter
);
226 pAIManager
->GetDone(&iAIIter
);
230 if (!DarkStatCheckBit(m_LastSeen
,kDarkStatBitFoundBody
))
232 DarkStatInc(kDarkStatBodiesFound
);
233 DarkStatSetBit(m_LastSeen
,kDarkStatBitFoundBody
,TRUE
);
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
);
244 m_pAI
->AccessSoundEnactor()->RequestConcept(kAISC_FoundRobot
);
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
)
269 // AutoAppIPtr(ObjectSystem);
271 // IObjectQuery* objquery = pObjectSystem->Iter(kObjectConcrete);
273 sPropertyObjIter iter
;
275 StartSuspiciousIter(&iter
);
278 BOOL iscurrentsuspicious
;
280 // NextSuspiciousIter(&iter,&targ,&iscurrentsuspicious);
282 // for (; !objquery->Done(); objquery->Next())
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
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;
311 if (!GetSuspiciousLightLevel(targ
,&minlightlevel
))
312 minlightlevel
= kSuspiciousLighting
;
315 mx_sub_vec(&relfac
,&themLoc
->loc
.vec
,&ourLoc
->loc
.vec
);
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
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
);
339 //we were suspicious of it, but shouldn't
340 //be now... so become unsuspicious of it.
341 AIClearSuspiciousLinks(GetID(),targ
);
346 } //end if suspicious/not suspicious
348 // objquery->Release();
350 StopSuspiciousIter(&iter
);
353 m_pAI
->NotifyFoundSuspicious(m_LastSuspicious
);