Starshatter_Open
Open source Starshatter engine
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
SeekerAI.cpp
Go to the documentation of this file.
1 /* Project Starshatter 4.5
2  Destroyer Studios LLC
3  Copyright © 1997-2004. All Rights Reserved.
4 
5  SUBSYSTEM: Stars.exe
6  FILE: SeekerAI.cpp
7  AUTHOR: John DiCamillo
8 
9 
10  OVERVIEW
11  ========
12  Seeker Missile (low-level) Artificial Intelligence class
13 */
14 
15 #include "MemDebug.h"
16 #include "SeekerAI.h"
17 #include "Ship.h"
18 #include "Shot.h"
19 #include "System.h"
20 #include "WeaponDesign.h"
21 
22 #include "Game.h"
23 
24 // +----------------------------------------------------------------------+
25 
27 : SteerAI(s), shot((Shot*) s), orig_target(0),
28 pursuit(1), delay(0), overshot(false)
29 {
30  ai_type = SEEKER;
31 
32  seek_gain = 25;
33  seek_damp = 0.55;
34 }
35 
36 
37 // +--------------------------------------------------------------------+
38 
40 {
41  if (shot) {
42  if (shot->Owner())
43  ((Ship*) shot->Owner())->SetMissileEta(shot->Identity(), 0);
44  }
45 }
46 
47 // +--------------------------------------------------------------------+
48 
49 void
50 SeekerAI::ExecFrame(double seconds)
51 {
52  // setup:
53  FindObjective();
54 
55  // adaptive behavior:
56  Navigator();
57 }
58 
59 // +--------------------------------------------------------------------+
60 
61 void
63 {
64  if (delay > 0) {
66  }
67  else {
68  Steer s = SeekTarget();
69  self->ApplyYaw((float) s.yaw);
70  self->ApplyPitch((float) s.pitch);
71  }
72 }
73 
74 void
76 {
77  if (!orig_target && targ && targ->Type() == SimObject::SIM_SHIP) {
78  orig_target = (Ship*) targ;
80  }
81 
82  SteerAI::SetTarget(targ, sub);
83 
84  if (!target) {
85  shot->SetEta(0);
86 
87  if (shot->Owner())
88  ((Ship*) shot->Owner())->SetMissileEta(shot->Identity(), 0);
89  }
90 }
91 
92 void
94 {
95  if (!shot || !target) return;
96 
97  if (target->Life() == 0) {
98  if (target != orig_target)
100  else
101  SetTarget(0,0);
102 
103  return;
104  }
105 
106  Point tloc = target->Location();
107  tloc = Transform(tloc);
108 
109  // seeker head limit of 45 degrees:
110  if (tloc.z < 0 || tloc.z < fabs(tloc.x) || tloc.z < fabs(tloc.y)) {
111  overshot = true;
112  SetTarget(0,0);
113  return;
114  }
115 
116  // distance from self to target:
117  distance = Point(target->Location() - self->Location()).length();
118 
119  // are we being spoofed?
121 
122  Point cv = ClosingVelocity();
123 
124  // time to reach target:
125  double time = distance / cv.length();
126  double predict = time;
127  if (predict > 15)
128  predict = 15;
129 
130  // pure pursuit:
131  if (pursuit == 1 || time < 0.1) {
132  obj_w = target->Location();
133  }
134 
135  // lead pursuit:
136  else {
137  // where the target will be when we reach it:
138  Point run_vec = target->Velocity();
139  obj_w = target->Location() + (run_vec * predict);
140  }
141 
142  // subsystem offset:
143  if (subtarget) {
144  Point offset = target->Location() - subtarget->MountLocation();
145  obj_w -= offset;
146  }
147  else if (target->Type() == SimObject::SIM_SHIP) {
148  Ship* tgt_ship = (Ship*) target;
149 
150  if (tgt_ship->IsGroundUnit())
151  obj_w += Point(0,150,0);
152  }
153 
154 
155  distance = Point(obj_w - self->Location()).length();
156  time = distance / cv.length();
157 
158  // where we will be when the target gets there:
159  if (predict > 0.1 && predict < 15) {
160  Point self_dest = self->Location() + cv * predict;
161  Point err = obj_w - self_dest;
162 
163  obj_w += err;
164  }
165 
166  // transform into camera coords:
169 
170  shot->SetEta((int) time);
171 
172  if (shot->Owner())
173  ((Ship*) shot->Owner())->SetMissileEta(shot->Identity(), (int) time);
174 }
175 
176 // +--------------------------------------------------------------------+
177 
178 void
179 SeekerAI::CheckDecoys(double target_distance)
180 {
181  // if the assigned target has the burner lit,
182  // ignore the decoys:
183  if (orig_target && orig_target->Augmenter()) {
185  return;
186  }
187 
188  if (target &&
189  target == orig_target &&
191 
193 
194  while (++decoy) {
195  double decoy_distance = Point(decoy->Location() - self->Location()).length();
196 
197  if (decoy_distance < target_distance) {
198  if (rand() < 1600) {
199  SetTarget(decoy.value(), 0);
200  return;
201  }
202  }
203  }
204  }
205 }
206 
207 // +--------------------------------------------------------------------+
208 
209 bool
211 {
212  return overshot;
213 }
214 
215 // +--------------------------------------------------------------------+
216 
217 Steer
219 {
220  return Steer();
221 }
222 
223 // +--------------------------------------------------------------------+
224 
225 Steer
227 {
228  if (!self || !target || Overshot())
229  return Steer();
230 
231  return Seek(objective);
232 }
233 
234 // +--------------------------------------------------------------------+
235 
236 bool
238 {
239  if (obj == target) {
240  if (obj->Type() == SimObject::SIM_SHOT && orig_target != 0)
242  }
243 
244  if (obj == orig_target)
245  orig_target = 0;
246 
247  return SteerAI::Update(obj);
248 }
249 
250 const char*
252 {
253  static char name[64];
254  sprintf_s(name, "SeekerAI(%s)", self->Name());
255  return name;
256 }
257