Linux makefiles
[canaan.git] / prj / cam / src / shock / shkairca.cpp
blobc348693bef76492157611f8a494c033d23b86804
1 /*
2 @Copyright Looking Glass Studios, Inc.
3 1996,1997,1998,1999,2000 Unpublished Work.
4 */
6 ///////////////////////////////////////////////////////////////////////////////
7 // $Header: r:/t2repos/thief2/src/shock/shkairca.cpp,v 1.1 1999/03/25 17:39:11 JON Exp $
8 //
9 // AI Combat - ranged
12 #include <shkairca.h>
14 #include <appagg.h>
15 #include <comtools.h>
17 #include <shkaircp.h>
19 #include <aiactrng.h>
20 #include <aiaware.h>
21 #include <aibasabl.h>
22 #include <aibasact.h>
23 #include <aiprcore.h>
24 #include <aitagtyp.h>
25 #include <aitrginf.h>
27 #include <iobjsys.h>
28 #include <linkbase.h>
29 #include <lnkquery.h>
30 #include <objdef.h>
31 #include <objpos.h>
32 #include <phconst.h>
33 #include <phoprop.h>
34 #include <phprop.h>
35 #include <port.h>
36 #include <rendprop.h>
37 #include <traitman.h>
39 // Must be last header
40 #include <dbmem.h>
42 enum eAIShockRangedRange_ {kAIShockRangedTooClose, kAIShockRangedClose, kAIShockRangedOK, kAIShockRangedFar, kAIShockRangedTooFar};
44 enum eAIShockRangedState_ {kAIShockRangedNothing, kAIShockRangedFiring, kAIShockRangedClosing, kAIShockRangedRetreating};
46 ///////////////////////////////////////////////////////////////////////////////
48 // CLASS: cAIShockRangedSubcombat
51 cAIShockRangedSubcombat::cAIShockRangedSubcombat():
52 m_pShockRangedProp(NULL)
56 ///////////////////////////////////////
58 cAIShockRangedSubcombat::~cAIShockRangedSubcombat()
62 ///////////////////////////////////////
64 void cAIShockRangedSubcombat::Reset()
66 m_pShockRangedProp = ShockAIGetRangedProp(m_pAIState->GetID());
69 ///////////////////////////////////////
71 void cAIShockRangedSubcombat::SetState(eAIShockRangedState state)
73 m_state = state;
76 ///////////////////////////////////////
78 STDMETHODIMP_(void) cAIShockRangedSubcombat::Init()
80 cAISubcombat::Init();
82 SetNotifications(kAICN_ActionProgress |
83 kAICN_Damage |
84 kAICN_GoalChange |
85 kAICN_ModeChange);
87 Reset();
90 ///////////////////////////////////////
92 STDMETHODIMP_(const char *) cAIShockRangedSubcombat::GetName()
94 return "Shock Ranged";
97 ///////////////////////////////////////
99 STDMETHODIMP_(BOOL) cAIShockRangedSubcombat::Save(ITagFile * pTagFile)
101 if (cAISubcombat::Save(pTagFile))
103 if (AIOpenTagBlock(GetID(), kAISL_ShockRanged, 0, 1, pTagFile))
105 AITagMove(pTagFile, &m_state);
106 AICloseTagBlock(pTagFile);
109 return TRUE;
112 ///////////////////////////////////////
114 STDMETHODIMP_(BOOL) cAIShockRangedSubcombat::Load(ITagFile * pTagFile)
116 if (cAISubcombat::Load(pTagFile))
118 if (AIOpenTagBlock(GetID(), kAISL_ShockRanged, 0, 1, pTagFile))
120 AITagMove(pTagFile, &m_state);
121 AICloseTagBlock(pTagFile);
124 return TRUE;
127 ///////////////////////////////////////
129 STDMETHODIMP_(void) cAIShockRangedSubcombat::OnGoalChange(const cAIGoal * pPrevious, const cAIGoal * pGoal)
131 cAISubcombat::OnGoalChange(pPrevious, pGoal);
132 // @TBD (toml 03-04-99): check this
133 if (IsOwnerLosingControl(pPrevious, pGoal))
134 Reset();
137 ///////////////////////////////////////
139 STDMETHODIMP_(void) cAIShockRangedSubcombat::OnDamage(const sDamageMsg *pMsg)
141 cAISubcombat::OnDamage(pMsg);
144 ///////////////////////////////////////
146 STDMETHODIMP_(void) cAIShockRangedSubcombat::OnActionProgress(IAIAction * pAction)
148 cAISubcombat::OnActionProgress(pAction);
150 pAction = pAction->GetTrueAction(); // get our action in case proxied
152 if (!IsOwn(pAction))
153 return;
155 switch (pAction->GetResult())
157 // We've succeeded and are done
158 case kAIR_Success:
160 SetState(kAIShockRangedNothing);
161 SignalAction();
162 break;
165 // Failure!
166 case kAIR_Fail:
168 SetState(kAIShockRangedNothing);
169 SignalAction();
170 break;
173 case kAIR_NoResultSwitch:
175 break;
180 ////////////////////////////////////////
182 cAIAction * cAIShockRangedSubcombat::SuggestRetreatAction(void)
184 cAIAction * pAction = NULL;
185 return pAction;
188 ////////////////////////////////////////
190 cAIAction * cAIShockRangedSubcombat::SuggestCloseAction(void)
192 cAIAction * pAction = NULL;
193 return pAction;
196 ////////////////////////////////////////
198 cAIAction* cAIShockRangedSubcombat::SuggestFireAction(void)
200 cAIAttackRangedAction* pAttackAction = NULL;
202 // Start an attack
203 if (m_selectedProjID != OBJ_NULL)
205 // Clone it
206 AutoAppIPtr(ObjectSystem);
207 ObjID projID = pObjectSystem->Create(m_selectedProjID, kObjectConcrete);
209 // Remove its physics and make it invisible
210 g_pPhysTypeProp->Delete(projID);
211 ObjSetHasRefs(projID, FALSE);
213 pAttackAction = new cAIAttackRangedAction(this);
215 pAttackAction->Set(GetTargetInfo()->id, projID, m_pSelectedProjData->leads_target,
216 m_pSelectedProjData->accuracy, 1, m_pSelectedProjData->launch_joint);
218 return pAttackAction;
222 ////////////////////////////////////////
224 STDMETHODIMP cAIShockRangedSubcombat::SuggestActions(cAIGoal * pGoal, const cAIActions & previous, cAIActions * pNew)
226 cAIAction *pAction = NULL;
228 EvaluatePosition();
230 switch (m_range)
232 case kAIShockRangedTooClose:
233 pAction = SuggestRetreatAction();
234 break;
235 case kAIShockRangedOK:
236 pAction = SuggestFireAction();
237 break;
238 case kAIShockRangedTooFar:
239 pAction = SuggestCloseAction();
240 break;
243 if (pAction != NULL)
244 pNew->Append(pAction);
246 return S_OK;
249 ///////////////////////////////////////////
251 void cAIShockRangedSubcombat::EvaluatePosition(void)
253 EvaluateRange();
254 SelectProjectile();
257 ///////////////////////////////////////////
259 // This should be based on the projectile and folded into SelectProjectile
262 void cAIShockRangedSubcombat::EvaluateRange(void)
264 m_dist = sqrt(GetTargetInfo()->distSq);
265 if (m_dist<m_pShockRangedProp->m_minimumDist)
266 m_range = kAIShockRangedTooClose;
267 else if (m_dist>m_pShockRangedProp->m_maximumDist)
268 m_range = kAIShockRangedTooFar;
269 else
270 m_range = kAIShockRangedOK;
273 ///////////////////////////////////////////
275 struct sSelection
277 sSelection(ObjID _projectile, sAIProjectileRel *_projectile_data, mxs_vector _targ_loc)
278 : projectile(_projectile),
279 projectile_data(_projectile_data),
280 targ_loc(_targ_loc)
283 ObjID projectile;
284 sAIProjectileRel *projectile_data;
285 mxs_vector targ_loc;
288 ////////////////////////////////////////////////////////
290 BOOL cAIShockRangedSubcombat::SelectProjectile(void)
292 cDynArray<sSelection> selection_list;
294 AutoAppIPtr(TraitManager);
295 ILinkQuery *query = g_pAIProjectileRelation->Query(pTraitManager->GetArchetype(m_pAIState->GetID()), LINKOBJ_WILDCARD);
296 for (; !query->Done(); query->Next())
298 sAIProjectileRel *pProjData = (sAIProjectileRel *)query->Data();
299 sLink link;
301 query->Link(&link);
303 // Check if the target is hittable
304 mxs_vector targ_loc;
305 if (!ProjectileHittable(pProjData->targeting_method, link.dest, m_pAIState->GetID(),
306 GetTargetInfo()->id))
307 continue;
309 sSelection selection(link.dest, pProjData, targ_loc);
311 // Bias selection
312 for (int i=0; i<pProjData->selection_desire+1; i++)
313 selection_list.Append(selection);
315 SafeRelease(query);
317 if (selection_list.Size() > 0)
319 int index = AIRandom(0, selection_list.Size() - 1);
320 m_selectedProjID = selection_list[index].projectile;
321 m_pSelectedProjData = selection_list[index].projectile_data;
322 return TRUE;
324 m_selectedProjID = OBJ_NULL;
325 m_pSelectedProjData = NULL;
326 return FALSE;
329 ////////////////////////////////////////
331 BOOL cAIShockRangedSubcombat::ProjectileHittable(int targ_method, ObjID projectile, ObjID source, ObjID target)
333 if ((target == OBJ_NULL) || (source == OBJ_NULL))
334 return FALSE;
336 mxs_vector *source_loc = &ObjPosGet(source)->loc.vec;
337 const mxs_vector *target_loc = &GetTargetLoc();
339 Location start, end, hit;
341 switch (targ_method)
343 case kTM_StraightLine:
345 MakeLocationFromVector(&start, source_loc);
346 MakeLocationFromVector(&end, target_loc);
348 ComputeCellForLocation(&start);
349 if (PortalRaycast(&start, &end, &hit, FALSE))
350 return TRUE;
351 else
352 return FALSE;
355 case kTM_Arcing:
357 mxs_vector *pInitVel;
358 mxs_real height;
359 mxs_vector midpt;
361 if (!g_pPhysInitVelProp->Get(projectile, &pInitVel))
363 Warning(("Projectile %d has no initial velocity\n", projectile));
364 return FALSE;
367 for (float mult = 0.2; mult <= 1.0; mult += 0.2)
369 height = (0.5 * sq(pInitVel->x * mult)) / (2 * kGravityAmt);
371 mx_sub_vec(&midpt, target_loc, source_loc);
372 mx_scaleeq_vec(&midpt, 0.5);
373 midpt.z += height;
374 mx_addeq_vec(&midpt, source_loc);
376 MakeLocationFromVector(&start, &midpt);
377 ComputeCellForLocation(&start);
379 if (start.cell == CELL_INVALID)
380 continue;
382 MakeLocationFromVector(&end, source_loc);
384 if (!PortalRaycast(&start, &end, &hit, TRUE))
385 continue;
387 MakeLocationFromVector(&end, target_loc);
389 if (!PortalRaycast(&start, &end, &hit, TRUE))
390 continue;
392 return TRUE;
395 return FALSE;
397 default:
399 Warning(("Unknown targeting method: %d\n", targ_method));
400 return FALSE;
405 ////////////////////////////////////////
407 BOOL cAIShockRangedSubcombat::HasTargetLOS(void)
409 if (GetTarget() == OBJ_NULL)
410 return FALSE;
412 const sAIAwareness *pAwareness = m_pAI->GetAwareness(GetTarget());
414 return !!(pAwareness->flags & kAIAF_HaveLOS);