2 @Copyright Looking Glass Studios, Inc.
3 1996,1997,1998,1999,2000 Unpublished Work.
6 ///////////////////////////////////////////////////////////////////////////////
7 // $Header: r:/t2repos/thief2/src/shock/shkairca.cpp,v 1.1 1999/03/25 17:39:11 JON Exp $
39 // Must be last header
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
)
76 ///////////////////////////////////////
78 STDMETHODIMP_(void) cAIShockRangedSubcombat::Init()
82 SetNotifications(kAICN_ActionProgress
|
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
);
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
);
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
))
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
155 switch (pAction
->GetResult())
157 // We've succeeded and are done
160 SetState(kAIShockRangedNothing
);
168 SetState(kAIShockRangedNothing
);
173 case kAIR_NoResultSwitch
:
180 ////////////////////////////////////////
182 cAIAction
* cAIShockRangedSubcombat::SuggestRetreatAction(void)
184 cAIAction
* pAction
= NULL
;
188 ////////////////////////////////////////
190 cAIAction
* cAIShockRangedSubcombat::SuggestCloseAction(void)
192 cAIAction
* pAction
= NULL
;
196 ////////////////////////////////////////
198 cAIAction
* cAIShockRangedSubcombat::SuggestFireAction(void)
200 cAIAttackRangedAction
* pAttackAction
= NULL
;
203 if (m_selectedProjID
!= OBJ_NULL
)
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
;
232 case kAIShockRangedTooClose
:
233 pAction
= SuggestRetreatAction();
235 case kAIShockRangedOK
:
236 pAction
= SuggestFireAction();
238 case kAIShockRangedTooFar
:
239 pAction
= SuggestCloseAction();
244 pNew
->Append(pAction
);
249 ///////////////////////////////////////////
251 void cAIShockRangedSubcombat::EvaluatePosition(void)
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
;
270 m_range
= kAIShockRangedOK
;
273 ///////////////////////////////////////////
277 sSelection(ObjID _projectile
, sAIProjectileRel
*_projectile_data
, mxs_vector _targ_loc
)
278 : projectile(_projectile
),
279 projectile_data(_projectile_data
),
284 sAIProjectileRel
*projectile_data
;
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();
303 // Check if the target is hittable
305 if (!ProjectileHittable(pProjData
->targeting_method
, link
.dest
, m_pAIState
->GetID(),
306 GetTargetInfo()->id
))
309 sSelection
selection(link
.dest
, pProjData
, targ_loc
);
312 for (int i
=0; i
<pProjData
->selection_desire
+1; i
++)
313 selection_list
.Append(selection
);
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
;
324 m_selectedProjID
= OBJ_NULL
;
325 m_pSelectedProjData
= NULL
;
329 ////////////////////////////////////////
331 BOOL
cAIShockRangedSubcombat::ProjectileHittable(int targ_method
, ObjID projectile
, ObjID source
, ObjID target
)
333 if ((target
== OBJ_NULL
) || (source
== OBJ_NULL
))
336 mxs_vector
*source_loc
= &ObjPosGet(source
)->loc
.vec
;
337 const mxs_vector
*target_loc
= &GetTargetLoc();
339 Location start
, end
, hit
;
343 case kTM_StraightLine
:
345 MakeLocationFromVector(&start
, source_loc
);
346 MakeLocationFromVector(&end
, target_loc
);
348 ComputeCellForLocation(&start
);
349 if (PortalRaycast(&start
, &end
, &hit
, FALSE
))
357 mxs_vector
*pInitVel
;
361 if (!g_pPhysInitVelProp
->Get(projectile
, &pInitVel
))
363 Warning(("Projectile %d has no initial velocity\n", projectile
));
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);
374 mx_addeq_vec(&midpt
, source_loc
);
376 MakeLocationFromVector(&start
, &midpt
);
377 ComputeCellForLocation(&start
);
379 if (start
.cell
== CELL_INVALID
)
382 MakeLocationFromVector(&end
, source_loc
);
384 if (!PortalRaycast(&start
, &end
, &hit
, TRUE
))
387 MakeLocationFromVector(&end
, target_loc
);
389 if (!PortalRaycast(&start
, &end
, &hit
, TRUE
))
399 Warning(("Unknown targeting method: %d\n", targ_method
));
405 ////////////////////////////////////////
407 BOOL
cAIShockRangedSubcombat::HasTargetLOS(void)
409 if (GetTarget() == OBJ_NULL
)
412 const sAIAwareness
*pAwareness
= m_pAI
->GetAwareness(GetTarget());
414 return !!(pAwareness
->flags
& kAIAF_HaveLOS
);