convert line ends
[canaan.git] / prj / cam / src / ai / aicbrsht.cpp
blob97b5d5430d6653c50325f6bb98e04a05d242f5f4
1 /*
2 @Copyright Looking Glass Studios, Inc.
3 1996,1997,1998,1999,2000 Unpublished Work.
4 */
6 ///////////////////////////////////////////////////////////////////////////////
7 // $Header: r:/t2repos/thief2/src/ai/aicbrsht.cpp,v 1.9 2000/02/03 16:36:39 bfarquha Exp $
8 //
9 // AI Combat - ranged
12 #include <aicbrsht.h>
14 #include <appagg.h>
15 #include <comtools.h>
17 #include <contain.h>
18 #include <iobjsys.h>
19 #include <objdef.h>
20 #include <phprop.h>
21 #include <rendprop.h>
23 #include <aiactrng.h>
24 #include <aiapisnd.h>
25 #include <aicbrmpr.h>
26 #include <aidebug.h>
27 #include <aiprops.h>
28 #include <aiprrngd.h>
29 #include <aisndtyp.h>
30 #include <aitrginf.h>
31 #include <aiutils.h>
33 // Must be last header
34 #include <dbmem.h>
36 ////////////////////////////////////////
38 const float kAIRS_HeadingTolerance = 0.25;
40 ////////////////////////////////////////
42 void cAIRangedShoot::Reset(void)
44 projectile = OBJ_NULL;
45 proj_link_data = NULL;
48 ////////////////////////////////////////
50 int cAIRangedShoot::SuggestApplicability(void)
52 // wsf: timer causing problems. When we're ready to fire (new ranged combat), the question
53 // is asked if this mode (long range shoot) wants to continue. It responds 'no' because the
54 // timer hasn't kicked off yet (still have .7 seconds to go for frogmen - the timer stars when action is
55 // selected), which makes this mode come to a premature end, and be replaced with frustration.
57 // if (m_pOwner->m_FiringDelay.Expired() && GetCurrentLocation()->GetLOF())
59 if (GetCurrentLocation()->GetLOF())
60 return g_AIRangedCombatModeWeights[AIGetRangedShoot(GetID())->m_rangeApplicability[GetRangeClass()]];
61 else
62 return 0;
65 ////////////////////////////////////////
67 BOOL cAIRangedShoot::CheckContinuation(void)
69 sAIRangedShootParams *pParams = AIGetRangedShoot(GetID());
71 if ((pParams->m_confirmRange) && (pParams->m_rangeApplicability[GetRangeClass()]==kAIRC_AppNone))
72 return FALSE;
73 if ((pParams->m_confirmLOF) && !m_pOwner->GetCurrentLocation()->TestLOF())
74 return FALSE;
75 return TRUE;
78 ////////////////////////////////////////
80 int cAIRangedShoot::SuggestInterrupt(void)
82 // @TODO: interrupt should look at property & how far off our facing is
83 return SuggestApplicability();
86 ////////////////////////////////////////
88 BOOL cAIRangedShoot::CheckPreconditions(void)
90 m_pOwner->SelectProjectile(&projectile, &proj_link_data, &targeting_location);
91 return (projectile != OBJ_NULL);
94 ////////////////////////////////////////
96 cAIAction* cAIRangedShoot::SuggestAction(void)
98 cAIAction * pAction = NULL;
100 Assert_(projectile != OBJ_NULL);
101 AIWatch1(Ranged, GetID(), "Launching projectile: %d", projectile);
103 // Tell all the other projectiles that they weren't selected
104 m_pOwner->RefreshProjectilesProj(projectile);
106 // Pull one out of the inventory
107 AutoAppIPtr(ContainSys);
108 AutoAppIPtr_(ObjectSystem, pObjSys);
109 ObjID firing_projectile;
111 // We want to delete the object if we run out of ammo, but we also
112 // want its link around until we're done creating the action, so
113 // we defer deletions until then.
114 pObjSys->Lock();
116 // Clone it
117 firing_projectile = pObjSys->Create(projectile, kObjectConcrete);
119 // Remove its physics and make it invisible
120 g_pPhysTypeProp->Delete(firing_projectile);
121 ObjSetHasRefs(firing_projectile, FALSE);
123 // Decrement stack count
124 int fire_count;
125 int burst_count;
127 if (proj_link_data->burst_count > 0)
128 burst_count = proj_link_data->burst_count;
129 else
130 burst_count = 1;
132 if (proj_link_data->ammo > 0)
134 IIntProperty *pStackCountProp = pContainSys->StackCountProp();
135 int count;
137 if (pStackCountProp->Get(projectile, &count))
139 if (count < burst_count)
140 fire_count = count;
141 else
142 fire_count = burst_count;
144 count -= fire_count;
146 if (count > 0)
147 pStackCountProp->Set(projectile, count);
148 else
149 pObjSys->Destroy(projectile);
151 else
152 CriticalMsg("Selected projectile w/o ammo!");
154 else
155 fire_count = burst_count;
157 // @TODO: handle specifying launch point
159 cAIAttackRangedAction *pAttackAction = new cAIAttackRangedAction(m_pOwner);
161 if (m_pOwner->m_ReactShootTimer.Expired())
163 if (GetInternalAI()->AccessSoundEnactor())
164 GetInternalAI()->AccessSoundEnactor()->RequestConcept(kAISC_ReactShoot);
165 m_pOwner->m_ReactShootTimer.Reset();
168 if ((proj_link_data->targeting_method == kTM_StraightLine) ||
169 (proj_link_data->targeting_method == kTM_Arcing))
171 if (GetCurrentLocation()->GetTargetSubModel()>=0)
172 pAttackAction->Set(GetTargetInfo()->id, GetCurrentLocation()->GetTargetSubModel(), firing_projectile, proj_link_data->leads_target,
173 proj_link_data->accuracy, fire_count, proj_link_data->launch_joint);
174 else
175 pAttackAction->Set(GetTargetInfo()->id, firing_projectile, proj_link_data->leads_target,
176 proj_link_data->accuracy, fire_count, proj_link_data->launch_joint);
178 else
180 pAttackAction->Set(targeting_location, firing_projectile, proj_link_data->accuracy,
181 fire_count, proj_link_data->launch_joint);
183 // Tell the action how fast to rotate and how close is close enough (in heading)
184 pAttackAction->SetRotationParams(AIGetRangedShoot(GetID())->m_rotationSpeed, kAIRS_HeadingTolerance);
186 pObjSys->Unlock();
188 #define kRandVar 15
189 float randVar = 1.0 + (AIRandom(0, kRandVar * 2) - kRandVar) / 100.0;
190 m_pOwner->m_FiringDelay.Set((eAITimerPeriod)(unsigned)(GetRangedCombatProp()->firing_delay * 1000 * randVar));
192 return pAttackAction;