Starshatter_Open
Open source Starshatter engine
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
NavAI.cpp
Go to the documentation of this file.
1 /* Project Starshatter 5.0
2  Destroyer Studios LLC
3  Copyright © 1997-2007. All Rights Reserved.
4 
5  SUBSYSTEM: Stars.exe
6  FILE: NavAI.cpp
7  AUTHOR: John DiCamillo
8 
9 
10  OVERVIEW
11  ========
12  Automatic Navigator Artificial Intelligence class
13 */
14 
15 #include "MemDebug.h"
16 #include "NavAI.h"
17 #include "TacticalAI.h"
18 #include "Instruction.h"
19 #include "NavSystem.h"
20 #include "QuantumDrive.h"
21 #include "Ship.h"
22 #include "ShipDesign.h"
23 #include "ShipCtrl.h"
24 #include "Drive.h"
25 #include "Farcaster.h"
26 #include "Shield.h"
27 #include "Sim.h"
28 #include "StarSystem.h"
29 #include "KeyMap.h"
30 #include "HUDView.h"
31 #include "HUDSounds.h"
32 
33 #include "Game.h"
34 
35 // +----------------------------------------------------------------------+
36 
38 : ShipAI(s), complete(false), brakes(0),
39 drop_state(0), quantum_state(0), farcaster(0), terrain_warning(false)
40 {
41  seek_gain = 20;
42  seek_damp = 0.55;
43 
44  delete tactical;
45  tactical = 0;
46 }
47 
48 // +--------------------------------------------------------------------+
49 
51 { }
52 
53 // +--------------------------------------------------------------------+
54 
55 void
57 {
58  if (!ship) return;
59 
60  seconds = s;
61 
62  ship->SetDirectorInfo(" ");
63 
65  takeoff = true;
66 
67  else if (takeoff && ship->MissionClock() > 10000)
68  takeoff = false;
69 
70  FindObjective();
71  Navigator();
72 
73  // watch for disconnect:
75  NavSystem* navsys = ship->GetNavSystem();
76  if (navsys) {
78  navsys->DisengageAutoNav();
79 
80  Sim* sim = Sim::GetSim();
81  if (sim) {
82  ship->SetControls(sim->GetControls());
83  return;
84  }
85  }
86  }
87 
88  static double time_til_change = 0.0;
89 
90  if (time_til_change < 0.001) {
91  if (ship->GetShield()) {
92  Shield* shield = ship->GetShield();
93  double level = shield->GetPowerLevel();
94 
97  shield->SetPowerLevel(100);
98  time_til_change = 0.5f;
99  }
100 
103  shield->SetPowerLevel(0);
104  time_til_change = 0.5f;
105  }
106 
107  else if (ShipCtrl::KeyDown(KEY_SHIELDS_UP)) {
108  if (level < 25) level = 25;
109  else if (level < 50) level = 50;
110  else if (level < 75) level = 75;
111  else level = 100;
112 
114  shield->SetPowerLevel(level);
115  time_til_change = 0.5f;
116  }
117 
119  if (level > 75) level = 75;
120  else if (level > 50) level = 50;
121  else if (level > 25) level = 25;
122  else level = 0;
123 
125  shield->SetPowerLevel(level);
126  time_til_change = 0.5f;
127  }
128 
129  }
130  }
131  else {
132  time_til_change -= seconds;
133  }
134 
136  ship->FireDecoy();
137 
139  ship->LaunchProbe();
140 
142  ship->ToggleGear();
143 
146 
147  if (drop_state < 0) {
148  ship->DropOrbit();
149  return;
150  }
151 
152  if (drop_state > 0) {
153  ship->MakeOrbit();
154  return;
155  }
156 }
157 
158 // +--------------------------------------------------------------------+
159 
160 void
162 {
163  navpt = 0;
164  distance = 0;
165 
166  // runway takeoff:
167  if (takeoff) {
168  obj_w = ship->Location() + ship->Heading() * 10e3;
169  obj_w.y = ship->Location().y + 2e3;
170 
171  // transform into camera coords:
173  ship->SetDirectorInfo(Game::GetText("ai.takeoff"));
174  return;
175  }
176 
177  // PART I: Find next NavPoint:
178  if (ship->GetNavSystem())
180 
181  complete = !navpt;
182  if (complete) return;
183 
184  // PART II: Compute Objective from NavPoint:
185  Point npt = navpt->Location();
186  Sim* sim = Sim::GetSim();
187  SimRegion* self_rgn = ship->GetRegion();
188  SimRegion* nav_rgn = navpt->Region();
189 
190  if (self_rgn && !nav_rgn) {
191  nav_rgn = self_rgn;
192  navpt->SetRegion(nav_rgn);
193  }
194 
195  if (self_rgn == nav_rgn) {
196  if (farcaster) {
197  if (farcaster->GetShip()->GetRegion() != self_rgn)
199 
200  obj_w = farcaster->EndPoint();
201  }
202 
203  else {
204  obj_w = npt.OtherHand();
205  }
206 
207  // distance from self to navpt:
208  distance = Point(obj_w - self->Location()).length();
209 
210  // transform into camera coords:
212 
213  if (!ship->IsStarship())
215 
216  if (farcaster && distance < 1000)
217  farcaster = 0;
218  }
219 
220  // PART III: Deal with orbital transitions:
221  else if (ship->IsDropship()) {
222  if (nav_rgn->GetOrbitalRegion()->Primary() ==
223  self_rgn->GetOrbitalRegion()->Primary()) {
224 
225  Point npt = nav_rgn->Location() - self_rgn->Location();
226  obj_w = npt.OtherHand();
227 
228  // distance from self to navpt:
229  distance = Point(obj_w - ship->Location()).length();
230 
231  // transform into camera coords:
233 
234  if (nav_rgn->IsAirSpace()) {
235  drop_state = -1;
236  }
237  else if (nav_rgn->IsOrbital()) {
238  drop_state = 1;
239  }
240  }
241 
242  // PART IIIa: Deal with farcaster jumps:
243  else if (nav_rgn->IsOrbital() && self_rgn->IsOrbital()) {
244  ListIter<Ship> s = self_rgn->Ships();
245  while (++s && !farcaster) {
246  if (s->GetFarcaster()) {
247  const Ship* dest = s->GetFarcaster()->GetDest();
248  if (dest && dest->GetRegion() == nav_rgn) {
249  farcaster = s->GetFarcaster();
250  }
251  }
252  }
253 
254  if (farcaster) {
255  Point apt = farcaster->ApproachPoint(0);
256  Point npt = farcaster->StartPoint();
257  double r1 = (ship->Location() - npt).length();
258 
259  if (r1 > 50e3) {
260  obj_w = apt;
261  distance = r1;
263  }
264 
265  else {
266  double r2 = (ship->Location() - apt).length();
267  double r3 = (npt - apt).length();
268 
269  if (r1+r2 < 1.2*r3) {
270  obj_w = npt;
271  distance = r1;
273  }
274  else {
275  obj_w = apt;
276  distance = r2;
278  }
279  }
280  }
281  }
282  }
283 
284  // PART IV: Deal with quantum jumps:
285  else if (ship->IsStarship()) {
286  quantum_state = 1;
287 
288  Point npt = nav_rgn->Location() + navpt->Location();
289  npt -= self_rgn->Location();
290  obj_w = npt.OtherHand();
291 
292  // distance from self to navpt:
293  distance = Point(obj_w - ship->Location()).length();
294 
295  // transform into camera coords:
297  }
298 }
299 
300 // +--------------------------------------------------------------------+
301 
302 void
304 {
305  accumulator.Clear();
306  magnitude = 0;
307  brakes = 0;
308  hold = false;
309 
310  if (navpt) {
311  if (navpt->Status() == Instruction::COMPLETE && navpt->HoldTime() > 0) {
312  ship->SetDirectorInfo(Game::GetText("ai.auto-hold"));
313  hold = true;
314  }
315  else {
316  ship->SetDirectorInfo(Game::GetText("ai.auto-nav"));
317  }
318  }
319  else {
320  ship->SetDirectorInfo(Game::GetText("ai.auto-stop"));
321  }
322 
325 
326  if (!hold)
328 
329  HelmControl();
330  ThrottleControl();
331 }
332 
333 // +--------------------------------------------------------------------+
334 
335 void
337 {
338  // ----------------------------------------------------------
339  // STARSHIP HELM MODE
340  // ----------------------------------------------------------
341 
342  if (ship->IsStarship()) {
345 
346  if (accumulator.pitch > 45*DEGREES)
348 
349  else if (accumulator.pitch < -45*DEGREES)
350  ship->SetHelmPitch(-45*DEGREES);
351 
352  else
354  }
355 
356  // ----------------------------------------------------------
357  // FIGHTER FLCS AUTO MODE
358  // ----------------------------------------------------------
359 
360  else {
362 
363  // are we being asked to flee?
364  if (fabs(accumulator.yaw) == 1.0 && accumulator.pitch == 0.0) {
365  accumulator.pitch = -0.7f;
366  accumulator.yaw *= 0.25f;
367  }
368 
369  self->ApplyRoll((float) (accumulator.yaw * -0.4));
370  self->ApplyYaw((float) (accumulator.yaw * 0.2));
371 
372  if (fabs(accumulator.yaw) > 0.5 && fabs(accumulator.pitch) < 0.1)
373  accumulator.pitch -= 0.1f;
374 
375  if (accumulator.pitch != 0)
376  self->ApplyPitch((float) accumulator.pitch);
377 
378  // if not turning, roll to orient with world coords:
379  if (fabs(accumulator.yaw) < 0.1) {
380  Point vrt = ((Camera*) &(self->Cam()))->vrt();
381  double deflection = vrt.y;
382  if (deflection != 0) {
383  double theta = asin(deflection/vrt.length());
384  self->ApplyRoll(-theta);
385  }
386  }
387 
388  if (!ship->IsAirborne() || ship->AltitudeAGL() > 100)
389  ship->RaiseGear();
390  }
391 
392  ship->SetTransX(0);
393  ship->SetTransY(0);
394  ship->SetTransZ(0);
395  ship->ExecFLCSFrame();
396 }
397 
398 // +--------------------------------------------------------------------+
399 
400 void
402 {
403  double ship_speed = ship->Velocity() * ship->Heading();
404  bool augmenter = false;
405 
406  if (hold) {
407  throttle = 0;
408  brakes = 1;
409  }
410 
411  else if (navpt) {
412  double speed = navpt->Speed();
413 
414  if (speed < 10)
415  speed = 250;
416 
417  throttle = 0;
418 
419  if (Ship::GetFlightModel() > 0) {
420  if (ship_speed > speed + 10)
421  throttle = old_throttle - 0.25;
422 
423  else if (ship_speed < speed - 10)
424  throttle = old_throttle + 0.25;
425 
426  else
428  }
429 
430  else {
431  if (ship_speed > speed+5)
432  brakes = 0.25;
433 
434  else if (ship_speed < speed-5)
435  throttle = 50;
436  }
437  }
438  else {
439  throttle = 0;
440  brakes = 0.25;
441  }
442 
443  if (ship->IsAirborne() && ship->Class() < Ship::LCA) {
444  if (ship_speed < 250) {
445  throttle = 100;
446  brakes = 0;
447 
448  if (ship_speed < 200)
449  augmenter = true;
450  }
451 
452  else if (throttle < 20) {
453  throttle = 20;
454  }
455  }
456 
459  ship->SetAugmenter(augmenter);
460 
461  if (ship_speed > 1 && brakes > 0)
463 }
464 
465 // +--------------------------------------------------------------------+
466 
467 Steer
469 {
470  if (!ship)
471  return Steer();
472 
473  if (takeoff)
474  return Seek(objective);
475 
476  if (navpt) {
477  if (quantum_state == 1) {
479 
480  if (q) {
483  q->Engage();
484  }
485 
486  else if (q->ActiveState() == QuantumDrive::ACTIVE_POSTWARP) {
487  quantum_state = 0;
488  }
489  }
490  }
491 
492  if (distance < 2 * self->Radius()) {
494 
495  return Steer();
496  }
497  else {
498  return Seek(objective);
499  }
500  }
501 
502  return Steer();
503 }
504 
505 // +--------------------------------------------------------------------+
506 
507 void
509 {
510  throttle = 0;
511 }
512 
513 // +--------------------------------------------------------------------+
514 
515 Point
516 NavAI::Transform(const Point& point)
517 {
518  if (ship && ship->IsStarship())
519  return point - self->Location();
520 
521  return SteerAI::Transform(point);
522 }
523 
524 Steer
525 NavAI::Seek(const Point& point)
526 {
527  // if ship is starship, the point is in relative world coordinates
528  // x: distance east(-) / west(+)
529  // y: altitude down(-) / up(+)
530  // z: distance north(-) / south(+)
531 
532  if (ship && ship->IsStarship()) {
533  Steer result;
534 
535  result.yaw = atan2(point.x, point.z) + PI;
536 
537  double adjacent = sqrt(point.x * point.x + point.z * point.z);
538  if (fabs(point.y) > ship->Radius() && adjacent > ship->Radius())
539  result.pitch = atan(point.y / adjacent);
540 
541  if (_isnan(result.yaw))
542  result.yaw = 0;
543 
544  if (_isnan(result.pitch))
545  result.pitch = 0;
546 
547  return result;
548  }
549 
550  return SteerAI::Seek(point);
551 }
552 
553 Steer
554 NavAI::Flee(const Point& point)
555 {
556  if (ship && ship->IsStarship()) {
557  Steer result = Seek(point);
558  result.yaw += PI;
559  result.pitch *= -1;
560  return result;
561  }
562 
563  return SteerAI::Flee(point);
564 }
565 
566 Steer
567 NavAI::Avoid(const Point& point, float radius)
568 {
569  if (ship && ship->IsStarship()) {
570  Steer result = Seek(point);
571 
572  if (point * ship->BeamLine() > 0)
573  result.yaw -= PI/2;
574  else
575  result.yaw += PI/2;
576 
577  return result;
578  }
579 
580  return SteerAI::Avoid(point, radius);
581 }
582 
583 // +--------------------------------------------------------------------+
584 
585 Steer
587 {
588  Steer avoid;
589 
590  terrain_warning = false;
591 
592  if (!ship || !ship->GetRegion() || !ship->GetRegion()->IsActive() ||
594  return avoid;
595 
596  if (ship->IsAirborne() && ship->GetFlightPhase() == Ship::ACTIVE) {
597  // too low?
598  if (ship->AltitudeAGL() < 1000) {
599  terrain_warning = true;
600  ship->SetDirectorInfo(Game::GetText("ai.too-low"));
601 
602  // way too low?
603  if (ship->AltitudeAGL() < 750) {
604  ship->SetDirectorInfo(Game::GetText("ai.way-too-low"));
605  }
606 
607  // where will we be?
608  Point selfpt = ship->Location() + ship->Velocity() + Point(0, 10e3, 0);
609 
610  // transform into camera coords:
611  Point obj = Transform(selfpt);
612 
613  // pull up!
614  avoid = Seek(obj);
615  }
616  }
617 
618  return avoid;
619 }
620 
621 
622