Starshatter_Open
Open source Starshatter engine
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
CarrierAI.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: CarrierAI.cpp
7  AUTHOR: John DiCamillo
8 
9 
10  OVERVIEW
11  ========
12  "Air Boss" AI class for managing carrier fighter squadrons
13 */
14 
15 #include "MemDebug.h"
16 #include "CarrierAI.h"
17 #include "ShipAI.h"
18 #include "Ship.h"
19 #include "ShipDesign.h"
20 #include "Element.h"
21 #include "FlightPlanner.h"
22 #include "Instruction.h"
23 #include "RadioMessage.h"
24 #include "RadioTraffic.h"
25 #include "Hangar.h"
26 #include "FlightDeck.h"
27 #include "Mission.h"
28 #include "Contact.h"
29 #include "Sim.h"
30 #include "StarSystem.h"
31 #include "Callsign.h"
32 #include "NetUtil.h"
33 
34 #include "Game.h"
35 #include "Random.h"
36 
37 // +----------------------------------------------------------------------+
38 
39 CarrierAI::CarrierAI(Ship* s, int level)
40 : sim(0), ship(s), hangar(0), exec_time(0), flight_planner(0),
41 hold_time(0), ai_level(level)
42 {
43  if (ship) {
44  sim = Sim::GetSim();
45  hangar = ship->GetHangar();
46 
47  for (int i = 0; i < 4; i++)
48  patrol_elem[i] = 0;
49 
50  if (ship)
51  flight_planner = new(__FILE__,__LINE__) FlightPlanner(ship);
52 
53  hold_time = (int) Game::GameTime();
54  }
55 }
56 
58 {
59  delete flight_planner;
60 }
61 
62 // +--------------------------------------------------------------------+
63 
64 void
66 {
67  const int INIT_HOLD = 15000;
68  const int EXEC_PERIOD = 3000;
69 
70  if (!sim || !ship || !hangar)
71  return;
72 
73  if (((int) Game::GameTime() - hold_time >= INIT_HOLD) &&
74  ((int) Game::GameTime() - exec_time > EXEC_PERIOD)) {
75 
78 
79  exec_time = (int) Game::GameTime();
80  }
81 }
82 
83 // +--------------------------------------------------------------------+
84 
85 bool
87 {
88  const DWORD PATROL_PERIOD = 900 * 1000;
89 
90  // pick up existing patrol elements:
91 
93  while (++iter) {
94  Element* elem = iter.value();
95 
96  if (elem->GetCarrier() == ship &&
97  (elem->Type() == Mission::PATROL ||
98  elem->Type() == Mission::SWEEP ||
99  elem->Type() == Mission::AIR_PATROL ||
100  elem->Type() == Mission::AIR_SWEEP) &&
101  !elem->IsSquadron() &&
102  !elem->IsFinished()) {
103 
104  bool found = false;
105  int open = -1;
106 
107  for (int i = 0; i < 4; i++) {
108  if (patrol_elem[i] == elem)
109  found = true;
110 
111  else if (patrol_elem[i] == 0 && open < 0)
112  open = i;
113  }
114 
115  if (!found && open >= 0) {
116  patrol_elem[open] = elem;
117  }
118  }
119  }
120 
121  // manage the four screening patrols:
122 
123  for (int i = 0; i < 4; i++) {
124  Element* elem = patrol_elem[i];
125 
126  if (elem) {
127  if (elem->IsFinished()) {
128  patrol_elem[i] = 0;
129  }
130 
131  else {
132  LaunchElement(elem);
133  }
134  }
135 
136  else if (Game::GameTime() - hangar->GetLastPatrolLaunch() > PATROL_PERIOD ||
137  hangar->GetLastPatrolLaunch() == 0) {
138  Element* patrol = CreatePackage(0, 2, Mission::PATROL, 0, "ACM Medium Range");
139  if (patrol) {
140  patrol_elem[i] = patrol;
141 
142  if (flight_planner)
143  flight_planner->CreatePatrolRoute(patrol, i);
144 
146  return true;
147  }
148  }
149  }
150 
151  return false;
152 }
153 
154 // +--------------------------------------------------------------------+
155 
156 bool
158 {
159  List<Element> assigned;
161  while (++iter) {
162  Element* elem = iter.value();
163 
164  // if this element is hostile to us
165  // or if the element is a target objective
166  // of the carrier, or is hostile to any
167  // of our squadrons...
168 
169  bool hostile = false;
170 
171  if (elem->IsHostileTo(ship) || elem->IsObjectiveTargetOf(ship)) {
172  hostile = true;
173  }
174  else {
175  for (int i = 0; i < hangar->NumSquadrons() && !hostile; i++) {
176  int squadron_iff = hangar->SquadronIFF(i);
177 
178  if (elem->IsHostileTo(squadron_iff))
179  hostile = true;
180  }
181  }
182 
183  if (hostile) {
184  sim->GetAssignedElements(elem, assigned);
185 
186  // is one of our fighter elements already assigned to this target?
187  bool found = false;
188  ListIter<Element> a_iter = assigned;
189  while (++a_iter && !found) {
190  Element* a = a_iter.value();
191 
192  if (a->GetCarrier() == ship)
193  found = true;
194  }
195 
196  // nobody is assigned yet, create an attack package
197  if (!found && CreateStrike(elem)) {
198  hold_time = (int) Game::GameTime() + 30000;
199  return true;
200  }
201  }
202  }
203 
204  return false;
205 }
206 
207 bool
209 {
210  Element* strike = 0;
211  Ship* target = elem->GetShip(1);
212 
213  if (target && !target->IsGroundUnit()) {
214  Contact* contact = ship->FindContact(target);
215  if (contact && contact->GetIFF(ship) > 0) {
216 
217  // fighter intercept
218  if (target->IsDropship()) {
219  int squadron = 0;
220  if (hangar->NumShipsReady(1) >= hangar->NumShipsReady(0))
221  squadron = 1;
222 
223  int count = 2;
224 
225  if (count < elem->NumShips())
226  count = elem->NumShips();
227 
228  strike = CreatePackage(squadron, count, Mission::INTERCEPT, elem->Name(), "ACM Medium Range");
229 
230  if (strike) {
231  strike->SetAssignment(elem);
232 
233  if (flight_planner)
234  flight_planner->CreateStrikeRoute(strike, elem);
235  }
236  }
237 
238  // starship or station assault
239  else {
240  int squadron = 0;
241  if (hangar->NumSquadrons() > 1)
242  squadron = 1;
243  if (hangar->NumSquadrons() > 2)
244  squadron = 2;
245 
246  int count = 2;
247 
248  if (target->Class() > Ship::FRIGATE) {
249  count = 4;
250  strike = CreatePackage(squadron, count, Mission::ASSAULT, elem->Name(), "Hvy Ship Strike");
251  }
252  else {
253  count = 2;
254  strike = CreatePackage(squadron, count, Mission::ASSAULT, elem->Name(), "Ship Strike");
255  }
256 
257  if (strike) {
258  strike->SetAssignment(elem);
259 
260  if (flight_planner)
261  flight_planner->CreateStrikeRoute(strike, elem);
262 
263  // strike escort if target has fighter protection:
264  if (target->GetHangar()) {
265  if (squadron > 1) squadron--;
266  Element* escort = CreatePackage(squadron, 2, Mission::ESCORT_STRIKE, strike->Name(), "ACM Short Range");
267 
268  if (escort && flight_planner)
269  flight_planner->CreateEscortRoute(escort, strike);
270  }
271  }
272  }
273  }
274  }
275 
276  return strike != 0;
277 }
278 
279 // +--------------------------------------------------------------------+
280 
281 Element*
282 CarrierAI::CreatePackage(int squadron, int size, int code, const char* target, const char* loadname)
283 {
284  if (squadron < 0 || size < 1 || code < Mission::PATROL || hangar->NumShipsReady(squadron) < size)
285  return 0;
286 
287  Sim* sim = Sim::GetSim();
288  const char* call = sim->FindAvailCallsign(ship->GetIFF());
289  Element* elem = sim->CreateElement(call, ship->GetIFF(), code);
290  FlightDeck* deck = 0;
291  int queue = 1000;
292  int* load = 0;
293  const ShipDesign*
294  design = hangar->SquadronDesign(squadron);
295 
296  elem->SetSquadron(hangar->SquadronName(squadron));
297  elem->SetCarrier(ship);
298 
299  if (target) {
300  int i_code = 0;
301 
302  switch (code) {
303  case Mission::ASSAULT: i_code = Instruction::ASSAULT; break;
304  case Mission::STRIKE: i_code = Instruction::STRIKE; break;
305 
307  case Mission::INTERCEPT: i_code = Instruction::INTERCEPT; break;
308 
309  case Mission::ESCORT:
312  i_code = Instruction::ESCORT; break;
313 
314  case Mission::DEFEND: i_code = Instruction::DEFEND; break;
315  }
316 
317  Instruction* objective = new(__FILE__,__LINE__) Instruction(i_code, target);
318  if (objective)
319  elem->AddObjective(objective);
320  }
321 
322  if (design && loadname) {
323  Text name = loadname;
324  name.setSensitive(false);
325 
327  while (++sl) {
328  if (name == sl->name) {
329  load = sl->load;
330  elem->SetLoadout(load);
331  }
332  }
333  }
334 
335  for (int i = 0; i < ship->NumFlightDecks(); i++) {
336  FlightDeck* d = ship->GetFlightDeck(i);
337 
338  if (d && d->IsLaunchDeck()) {
339  int dq = hangar->PreflightQueue(d);
340 
341  if (dq < queue) {
342  queue = dq;
343  deck = d;
344  }
345  }
346  }
347 
348  int npackage = 0;
349  int slots[4];
350 
351  for (int i = 0; i < 4; i++)
352  slots[i] = -1;
353 
354  for (int slot = 0; slot < hangar->SquadronSize(squadron); slot++) {
355  const HangarSlot* s = hangar->GetSlot(squadron, slot);
356 
357  if (hangar->GetState(s) == Hangar::STORAGE) {
358  if (npackage < 4)
359  slots[npackage] = slot;
360 
361  hangar->GotoAlert(squadron, slot, deck, elem, load, code > Mission::SWEEP);
362  npackage++;
363 
364  if (npackage >= size)
365  break;
366  }
367  }
368 
369  NetUtil::SendElemCreate(elem, squadron, slots, code <= Mission::SWEEP);
370 
371  return elem;
372 }
373 
374 // +--------------------------------------------------------------------+
375 
376 bool
378 {
379  bool result = false;
380 
381  if (!elem)
382  return result;
383 
384  for (int squadron = 0; squadron < hangar->NumSquadrons(); squadron++) {
385  for (int slot = 0; slot < hangar->SquadronSize(squadron); slot++) {
386  const HangarSlot* s = hangar->GetSlot(squadron, slot);
387 
388  if (hangar->GetState(s) == Hangar::ALERT &&
389  hangar->GetPackageElement(s) == elem) {
390 
391  hangar->Launch(squadron, slot);
392  NetUtil::SendShipLaunch(ship, squadron, slot);
393 
394  result = true;
395  }
396  }
397  }
398 
399  return result;
400 }