Starshatter_Open
Open source Starshatter engine
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
StarshipTacticalAI.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: StarshipTacticalAI.cpp
7  AUTHOR: John DiCamillo
8 
9 
10  OVERVIEW
11  ========
12  Starship-specific mid-level (tactical) AI
13 */
14 
15 #include "MemDebug.h"
16 #include "StarshipTacticalAI.h"
17 #include "ShipAI.h"
18 #include "Ship.h"
19 #include "ShipDesign.h"
20 #include "Shot.h"
21 #include "Element.h"
22 #include "Instruction.h"
23 #include "RadioMessage.h"
24 #include "RadioTraffic.h"
25 #include "Contact.h"
26 #include "WeaponGroup.h"
27 #include "Drive.h"
28 #include "QuantumDrive.h"
29 #include "Sim.h"
30 #include "StarSystem.h"
31 #include "Starshatter.h"
32 #include "Random.h"
33 
34 #include "Game.h"
35 
36 const double STARSHIP_TACTICAL_DROP_TIME = 15;
37 
38 // +----------------------------------------------------------------------+
39 
41 : TacticalAI(ai), drop_time(1.0e9), bugout(false), ai_level(0), initial_integrity(0)
42 {
43  if (ai && ai->GetShip()) {
44  ai_level = ai->GetAILevel();
46  }
47 
48  switch (ai_level) {
49  default:
50  case 2: THREAT_REACTION_TIME = 500; break;
51  case 1: THREAT_REACTION_TIME = 1000; break;
52  case 0: THREAT_REACTION_TIME = 2500;
55  break;
56  }
57 }
58 
59 
60 // +--------------------------------------------------------------------+
61 
63 { }
64 
65 // +--------------------------------------------------------------------+
66 
67 void
69 {
70  TacticalAI::ExecFrame(seconds);
71 
72  drop_time -= seconds;
73 
74  if (drop_time <= 0) {
76 
78  }
79 }
80 
81 // +--------------------------------------------------------------------+
82 
83 void
85 {
86  // pick the closest contact on Threat Warning System:
87  Ship* threat_ship = 0;
88  Shot* threat_missile = 0;
89  Ship* rumor = 0;
90  double threat_dist = 1e9;
91  double CELL_SIZE = 20e3;
92 
93  threat_level = 0;
94  support_level = ship->AIValue() / CELL_SIZE;
95 
97 
98  while (++iter) {
99  Contact* contact = iter.value();
100  Ship* c_ship = contact->GetShip();
101  Shot* c_shot = contact->GetShot();
102 
103  if (!c_ship && !c_shot)
104  continue;
105 
106  if (c_ship && c_ship != ship) {
107  double basis = max(contact->Range(ship), CELL_SIZE);
108  double ai_value = c_ship->AIValue() / basis;
109 
110  if (c_ship->GetIFF() == ship->GetIFF()) {
111  support_level += ai_value;
112  }
113  else if (ship->GetIFF() > 0 && c_ship->GetIFF() > 0) {
114  threat_level += ai_value;
115  }
116  else if (c_ship->GetIFF() > 1) { // neutrals should not be afraid of alliance
117  threat_level += ai_value;
118  }
119  }
120 
121  if (contact->Threat(ship) &&
123 
124  if (c_shot) {
125  threat_missile = c_shot;
126  rumor = (Ship* ) threat_missile->Owner();
127  }
128  else {
129  double rng = contact->Range(ship);
130 
131  if (c_ship &&
132  c_ship->Class() != Ship::FREIGHTER &&
133  c_ship->Class() != Ship::FARCASTER) {
134 
135 
136  if (c_ship->GetTarget() == ship) {
137  if (!threat_ship || c_ship->Class() > threat_ship->Class()) {
138  threat_ship = c_ship;
139  threat_dist = 0;
140  }
141  }
142  else if (rng < threat_dist) {
143  threat_ship = c_ship;
144  threat_dist = rng;
145  }
146 
147  CheckBugOut(c_ship, rng);
148  }
149  }
150  }
151  }
152 
153  if (rumor) {
154  iter.reset();
155 
156  while (++iter) {
157  if (iter->GetShip() == rumor) {
158  rumor = 0;
159  ship_ai->ClearRumor();
160  break;
161  }
162  }
163  }
164 
165  ship_ai->SetRumor(rumor);
166  ship_ai->SetThreat(threat_ship);
167  ship_ai->SetThreatMissile(threat_missile);
168 }
169 
170 // +--------------------------------------------------------------------+
171 
172 void
174 {
175  if (threat_level < 0.01) {
176  ship_ai->SetSupport(0);
177  return;
178  }
179 
180  // pick the biggest friendly contact in the sector:
181  Ship* support = 0;
182  double support_dist = 1e9;
183 
184  ListIter<Contact> c_iter = ship->ContactList();
185 
186  while (++c_iter) {
187  Contact* contact = c_iter.value();
188  if (contact->GetShip() && contact->GetIFF(ship) == ship->GetIFF()) {
189  Ship* c_ship = contact->GetShip();
190 
191  if (c_ship != ship && c_ship->Class() >= ship->Class()) {
192  if (!support || c_ship->Class() > support->Class())
193  support = c_ship;
194  }
195  }
196  }
197 
198  ship_ai->SetSupport(support);
199 }
200 
201 void
203 {
204  // see if carrier should bug out...
205  if (!ship || !c_ship || ship->Class() != Ship::CARRIER)
206  return;
207 
208  if (bugout)
209  return;
210 
211  if (ship->GetElement() && ship->GetElement()->GetZoneLock())
212  return;
213 
214  if (c_ship->Class() < Ship::DESTROYER || c_ship->Class() > Ship::STATION)
215  return;
216 
218  if (stars && stars->InCutscene())
219  return;
220 
221  double sustained_damage = initial_integrity - ship->Integrity();
222  double allowable_damage = ship->Design()->integrity * 0.25;
223 
224  if (rng > 50e3 && sustained_damage < allowable_damage)
225  return;
226 
227  // still here? we must need to bug out!
228 
229  Sim* sim = Sim::GetSim();
230  SimRegion* dst = 0;
231 
232  List<SimRegion>& regions = sim->GetRegions();
233 
234  if (regions.size() > 1) {
235  int tries = 10;
236  while (!dst && tries--) {
237  int n = RandomIndex() % regions.size();
238  dst = regions[n];
239 
240  if (dst == ship->GetRegion() || dst->IsAirSpace())
241  dst = 0;
242  }
243  }
244 
245  if (dst) {
246  // bug out!
247  QuantumDrive* quantum = ship->GetQuantumDrive();
248  if (quantum) {
249  quantum->SetDestination(dst, Point(0,0,0));
250  quantum->Engage();
251  }
252 
253  // ask highest ranking escort to go with you:
254  Element* escort = 0;
255 
256  ListIter<Element> iter = sim->GetElements();
257  while (++iter) {
258  Element* elem = iter.value();
259 
260  if (!escort || elem->GetShipClass() > escort->GetShipClass()) {
261  if (ship->GetElement()->CanCommand(elem))
262  escort = elem;
263  }
264  }
265 
266  if (escort) {
267  RadioMessage* msg = new(__FILE__,__LINE__) RadioMessage(escort, ship, RadioMessage::QUANTUM_TO);
268  if (msg) {
269  msg->SetInfo(dst->Name());
271  }
272  }
273 
274  bugout = true;
275  }
276 }