From b829170121d3657369904ec62d8065606777a9ce Mon Sep 17 00:00:00 2001 From: Aki Date: Fri, 1 Oct 2021 18:54:04 +0200 Subject: Removed doxygen generated docs They can be rebuild anytime and are considered a build artifact/binary. --- Doc/doxygen/html/_fighter_a_i_8cpp_source.html | 1948 ------------------------ 1 file changed, 1948 deletions(-) delete mode 100644 Doc/doxygen/html/_fighter_a_i_8cpp_source.html (limited to 'Doc/doxygen/html/_fighter_a_i_8cpp_source.html') diff --git a/Doc/doxygen/html/_fighter_a_i_8cpp_source.html b/Doc/doxygen/html/_fighter_a_i_8cpp_source.html deleted file mode 100644 index d622805..0000000 --- a/Doc/doxygen/html/_fighter_a_i_8cpp_source.html +++ /dev/null @@ -1,1948 +0,0 @@ - - - - - -Starshatter_Open: D:/SRC/StarshatterSVN/Stars45/FighterAI.cpp Source File - - - - - - - - - - - - - -
-
- - - - - - -
-
Starshatter_Open -
-
Open source Starshatter engine
-
-
- - - - - -
-
- -
-
-
- -
- - - - -
- -
- -
-
-
FighterAI.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: FighterAI.cpp
-
7  AUTHOR: John DiCamillo
-
8 
-
9 
-
10  OVERVIEW
-
11  ========
-
12  Fighter (low-level) Artificial Intelligence class
-
13 */
-
14 
-
15 #include "MemDebug.h"
-
16 #include "FighterAI.h"
-
17 #include "FighterTacticalAI.h"
-
18 #include "Ship.h"
-
19 #include "Shot.h"
-
20 #include "Sensor.h"
-
21 #include "Element.h"
-
22 #include "ShipDesign.h"
-
23 #include "Instruction.h"
-
24 #include "Weapon.h"
-
25 #include "WeaponGroup.h"
-
26 #include "Drive.h"
-
27 #include "QuantumDrive.h"
-
28 #include "Farcaster.h"
-
29 #include "FlightComp.h"
-
30 #include "FlightDeck.h"
-
31 #include "Hangar.h"
-
32 #include "Sim.h"
-
33 #include "StarSystem.h"
-
34 #include "RadioMessage.h"
-
35 #include "RadioTraffic.h"
-
36 
-
37 #include "Game.h"
-
38 
-
39 static const double TIME_TO_DOCK = 30;
-
40 
-
41 // +----------------------------------------------------------------------+
-
42 
- -
44 : ShipAI(s), brakes(0), drop_state(0), jink_time(0), evading(false),
-
45 decoy_missile(0), missile_time(0), terrain_warning(false), inbound(0),
-
46 rtb_code(0), form_up(false), over_threshold(false), time_to_dock(0),
-
47 go_manual(false)
-
48 {
-
49  ai_type = FIGHTER;
-
50  seek_gain = 22;
-
51  seek_damp = 0.55;
-
52  brakes = 0;
-
53  z_shift = 0;
-
54 
-
55  tactical = new(__FILE__,__LINE__) FighterTacticalAI(this);
-
56 }
-
57 
-
58 
-
59 // +--------------------------------------------------------------------+
-
60 
- -
62 { }
-
63 
-
64 // +--------------------------------------------------------------------+
-
65 
-
66 static double frame_time = 0;
-
67 
-
68 void
- -
70 {
-
71  if (!ship) return;
-
72 
-
73  evading = false;
-
74  inbound = ship->GetInbound();
-
75  missile_time -= s;
-
76 
-
77  int order = 0;
-
78 
-
79  if (navpt)
-
80  order = navpt->Action();
-
81 
-
82  if (inbound) {
-
83  form_up = false;
-
84  rtb_code = 1;
-
85 
-
86  // CHEAT LANDING:
-
87  if (inbound->Final() && time_to_dock > 0) {
-
88  FlightDeck* deck = inbound->GetDeck();
-
89  if (deck) {
-
90  Point dst = deck->EndPoint();
-
91  Point approach = deck->StartPoint() - dst;
-
92 
-
93  const Ship* carrier = deck->GetCarrier();
-
94 
-
95  Camera landing_cam;
-
96  landing_cam.Clone(carrier->Cam());
-
97  landing_cam.Yaw(deck->Azimuth());
-
98 
-
99  if (time_to_dock > TIME_TO_DOCK/2) {
-
100  double lr, lp, lw;
-
101  double sr, sp, sw;
-
102 
-
103  landing_cam.Orientation().ComputeEulerAngles(lr, lp, lw);
-
104  ship->Cam().Orientation().ComputeEulerAngles(sr, sp, sw);
-
105 
-
106  double nr = sr + s*(lr-sr);
-
107  double np = sp + s*(lp-sp);
-
108  double nw = sw + s*(lw-sw)*0.5;
-
109 
-
110  Camera work;
-
111  work.Aim(nr,np,nw);
-
112  landing_cam.Clone(work);
-
113  }
-
114 
-
115  ship->CloneCam(landing_cam);
-
116  ship->MoveTo(dst + approach * (time_to_dock / TIME_TO_DOCK));
-
117  ship->SetVelocity(carrier->Velocity() + ship->Heading() * 50);
-
118  ship->SetThrottle(50);
-
119  ship->ExecFLCSFrame();
-
120 
-
121  time_to_dock -= s;
-
122 
-
123  if (time_to_dock <= 0) {
-
124  deck->Dock(ship);
-
125  time_to_dock = 0;
-
126  }
-
127 
-
128  return;
-
129  }
-
130  }
-
131 
-
132  else if (ship->GetFlightPhase() == Ship::DOCKING) {
-
133  // deal with (pathological) moving carrier deck:
-
134 
-
135  FlightDeck* deck = inbound->GetDeck();
-
136  if (deck) {
-
137  Point dst = deck->EndPoint();
-
138 
-
139  if (ship->IsAirborne()) {
-
140  double alt = dst.y;
-
141  dst = ship->Location();
-
142  dst.y = alt;
-
143  }
-
144 
-
145  const Ship* carrier = deck->GetCarrier();
-
146 
-
147  Camera landing_cam;
-
148  landing_cam.Clone(carrier->Cam());
-
149  landing_cam.Yaw(deck->Azimuth());
-
150 
-
151  ship->CloneCam(landing_cam);
-
152  ship->MoveTo(dst);
-
153 
-
154  if (!ship->IsAirborne()) {
-
155  ship->SetVelocity(carrier->Velocity());
-
156  }
-
157  else {
-
158  Point taxi(landing_cam.vpn());
-
159  ship->SetVelocity(taxi * 95);
-
160  }
-
161 
-
162  ship->SetThrottle(0);
-
163  ship->ExecFLCSFrame();
-
164  }
-
165 
-
166  return;
-
167  }
-
168  }
-
169  else {
-
170  Instruction* orders = ship->GetRadioOrders();
-
171 
-
172  if (orders &&
-
173  (orders->Action() == RadioMessage::WEP_HOLD ||
-
174  orders->Action() == RadioMessage::FORM_UP)) {
-
175  form_up = true;
-
176  rtb_code = 0;
-
177  }
-
178  else {
-
179  form_up = false;
-
180  }
-
181  }
-
182 
-
183  if (!target && order != Instruction::STRIKE)
- -
185 
-
186  ShipAI::ExecFrame(s); // this must be the last line of this method
-
187 
-
188  // IT IS NOT SAFE TO PLACE CODE HERE
-
189  // if this class decides to break orbit,
-
190  // this object will be deleted during
-
191  // ShipAI::ExecFrame() (which calls
-
192  // FighterAI::Navigator() - see below)
-
193 }
-
194 
-
195 // +--------------------------------------------------------------------+
-
196 
-
197 void
- -
199 {
-
200  distance = 0;
-
201 
-
202  // ALWAYS complete initial launch navpt:
-
203  if (!navpt) {
- - -
206  navpt = 0;
-
207  }
-
208 
-
209  if (navpt && navpt->Action() == Instruction::LAUNCH) {
-
210  if (navpt->Status() != Instruction::COMPLETE) {
- -
212 
-
213  // transform into camera coords:
- -
215  ship->SetDirectorInfo(Game::GetText("ai.launch"));
-
216  return;
-
217  }
-
218  else {
-
219  navpt = 0;
-
220  }
-
221  }
-
222 
-
223  // runway takeoff:
-
224  else if (takeoff) {
-
225  obj_w = ship->Location() + ship->Heading() * 10e3;
-
226  obj_w.y = ship->Location().y + 2e3;
-
227 
-
228  // transform into camera coords:
- -
230  ship->SetDirectorInfo(Game::GetText("ai.takeoff"));
-
231  return;
-
232  }
-
233 
-
234  // approaching a carrier or runway:
-
235  else if (inbound) {
-
236  FlightDeck* deck = inbound->GetDeck();
-
237 
-
238  if (!deck) {
-
239  objective = Point();
-
240  return;
-
241  }
-
242 
-
243  // initial approach
-
244  if (inbound->Approach() > 0 || !inbound->Cleared()) {
- -
246 
-
247  distance = (obj_w - ship->Location()).length();
-
248 
-
249  // transform into camera coords:
- -
251  ship->SetDirectorInfo(Game::GetText("ai.inbound"));
-
252 
-
253  return;
-
254  }
-
255 
-
256  // final approach
-
257  else {
-
258  ship->SetDirectorInfo(Game::GetText("ai.finals"));
-
259 
-
260  obj_w = deck->StartPoint();
-
261  if (inbound->Final()) {
-
262  obj_w = deck->EndPoint();
-
263 
-
264  if (deck->OverThreshold(ship)) {
-
265  obj_w = deck->MountLocation();
-
266  over_threshold = true;
-
267  }
-
268  }
-
269 
-
270  distance = (obj_w - ship->Location()).length();
-
271 
-
272  // transform into camera coords:
- -
274 
-
275  return;
-
276  }
-
277  }
-
278 
-
279  // not inbound yet, check for RTB order:
-
280  else {
-
281  Instruction* orders = (Instruction*) ship->GetRadioOrders();
-
282  int action = 0;
-
283 
-
284  if (orders)
-
285  action = orders->Action();
-
286 
-
287  if (navpt && !action) {
- -
289  if (distance < 5e3) {
-
290  action = navpt->Action();
-
291  }
-
292  }
-
293 
-
294  if (action == RadioMessage::RTB ||
-
295  action == RadioMessage::DOCK_WITH) {
-
296 
-
297  Ship* controller = ship->GetController();
-
298 
-
299  if (orders && orders->Action() == RadioMessage::DOCK_WITH && orders->GetTarget()) {
-
300  controller = (Ship*) orders->GetTarget();
-
301  }
-
302 
-
303  else if (navpt && navpt->Action() == RadioMessage::DOCK_WITH && navpt->GetTarget()) {
-
304  controller = (Ship*) navpt->GetTarget();
-
305  }
-
306 
-
307  ReturnToBase(controller);
-
308 
-
309  if (rtb_code)
-
310  return;
-
311  }
-
312  }
-
313 
- -
315 }
-
316 
-
317 void
- -
319 {
-
320  rtb_code = 0;
-
321 
-
322  if (controller) {
-
323  SimRegion* self_rgn = ship->GetRegion();
-
324  SimRegion* rtb_rgn = controller->GetRegion();
-
325 
-
326  if (self_rgn && !rtb_rgn) {
-
327  rtb_rgn = self_rgn;
-
328  }
-
329 
-
330  if (self_rgn && rtb_rgn && self_rgn != rtb_rgn) {
-
331  // is the carrier in orbit above us
-
332  // (or on the ground below us)?
-
333 
-
334  if (rtb_rgn->GetOrbitalRegion()->Primary() ==
-
335  self_rgn->GetOrbitalRegion()->Primary()) {
-
336 
-
337  Point npt = rtb_rgn->Location() - self_rgn->Location();
-
338  obj_w = npt.OtherHand();
-
339 
-
340  // distance from self to navpt:
-
341  distance = Point(obj_w - ship->Location()).length();
-
342 
-
343  // transform into camera coords:
- -
345 
-
346  if (rtb_rgn->IsAirSpace()) {
-
347  drop_state = -1;
-
348  }
-
349  else if (rtb_rgn->IsOrbital()) {
-
350  drop_state = 1;
-
351  }
-
352 
-
353  rtb_code = 2;
-
354  }
-
355 
-
356  // try to find a jumpgate that will take us home:
-
357  else {
-
358  QuantumDrive* qdrive = ship->GetQuantumDrive();
-
359  bool use_farcaster = !qdrive ||
-
360  !qdrive->IsPowerOn() ||
-
361  qdrive->Status() < System::DEGRADED;
-
362 
-
363  if (use_farcaster) {
-
364  if (!farcaster) {
-
365  ListIter<Ship> s = self_rgn->Ships();
-
366  while (++s && !farcaster) {
-
367  if (s->GetFarcaster()) {
-
368  const Ship* dest = s->GetFarcaster()->GetDest();
-
369  if (dest && dest->GetRegion() == rtb_rgn) {
-
370  farcaster = s->GetFarcaster();
-
371  }
-
372  }
-
373  }
-
374  }
-
375 
-
376  if (farcaster) {
-
377  Point apt = farcaster->ApproachPoint(0);
-
378  Point npt = farcaster->StartPoint();
-
379  double r1 = (ship->Location() - npt).length();
-
380 
-
381  if (r1 > 50e3) {
-
382  obj_w = apt;
-
383  distance = r1;
- -
385  }
-
386 
-
387  else {
-
388  double r2 = (ship->Location() - apt).length();
-
389  double r3 = (npt - apt).length();
-
390 
-
391  if (r1+r2 < 1.2*r3) {
-
392  obj_w = npt;
-
393  distance = r1;
- -
395  }
-
396  else {
-
397  obj_w = apt;
-
398  distance = r2;
- -
400  }
-
401  }
-
402 
-
403  rtb_code = 3;
-
404  }
-
405 
-
406  // can't find a way back home, ignore the RTB order:
-
407  else {
- -
409  rtb_code = 0;
-
410  return;
-
411  }
-
412  }
-
413  else if (qdrive) {
-
414  if (qdrive->ActiveState() == QuantumDrive::ACTIVE_READY) {
-
415  qdrive->SetDestination(rtb_rgn, controller->Location());
-
416  qdrive->Engage();
-
417  }
-
418 
-
419  rtb_code = 3;
-
420  }
-
421  }
-
422  }
-
423 
-
424  else {
-
425  obj_w = controller->Location();
-
426 
-
427  distance = (obj_w - ship->Location()).length();
-
428 
-
429  // transform into camera coords:
- -
431  ship->SetDirectorInfo(Game::GetText("ai.return-to-base"));
-
432 
-
433  rtb_code = 1;
-
434  }
-
435  }
-
436 }
-
437 
-
438 // +--------------------------------------------------------------------+
-
439 
-
440 void
- -
442 {
-
443  SimRegion* self_rgn = ship->GetRegion();
-
444  SimRegion* nav_rgn = navpt->Region();
-
445 
-
446  if (self_rgn && !nav_rgn) {
-
447  nav_rgn = self_rgn;
-
448  navpt->SetRegion(nav_rgn);
-
449  }
-
450 
-
451  if (self_rgn && nav_rgn && self_rgn != nav_rgn) {
-
452  if (nav_rgn->GetOrbitalRegion()->Primary() ==
-
453  self_rgn->GetOrbitalRegion()->Primary()) {
-
454 
-
455  Point npt = nav_rgn->Location() - self_rgn->Location();
-
456  obj_w = npt.OtherHand();
-
457 
-
458  // distance from self to navpt:
-
459  distance = Point(obj_w - ship->Location()).length();
-
460 
-
461  // transform into camera coords:
- -
463 
-
464  if (nav_rgn->IsAirSpace()) {
-
465  drop_state = -1;
-
466  }
-
467  else if (nav_rgn->IsOrbital()) {
-
468  drop_state = 1;
-
469  }
-
470 
-
471  return;
-
472  }
-
473 
-
474  else {
- -
476 
-
477  if (q) {
- - -
480  q->Engage();
-
481  return;
-
482  }
-
483  }
-
484  }
-
485  }
-
486 
- -
488 }
-
489 
-
490 // +--------------------------------------------------------------------+
-
491 
-
492 Point
- -
494 {
-
495  if (ship) {
-
496  WeaponDesign* wep_design = ship->GetPrimaryDesign();
-
497 
-
498  if (target && wep_design) {
-
499  Point aim_vec = ship->Heading();
-
500  aim_vec.Normalize();
-
501 
-
502  Point shot_vel = ship->Velocity() + aim_vec * wep_design->speed;
-
503  return shot_vel - target->Velocity();
-
504  }
-
505 
-
506  else if (target) {
-
507  return ship->Velocity() - target->Velocity();
-
508  }
-
509 
-
510  else {
-
511  return ship->Velocity();
-
512  }
-
513  }
-
514 
-
515  return Point(1,0,0);
-
516 }
-
517 
-
518 // +--------------------------------------------------------------------+
-
519 
-
520 void
- -
522 {
-
523  go_manual = false;
-
524 
-
525  if (takeoff) {
-
526  accumulator.Clear();
-
527  magnitude = 0;
-
528  brakes = 0;
-
529  z_shift = 0;
-
530 
- -
532  HelmControl();
-
533  ThrottleControl();
-
534  ship->ExecFLCSFrame();
-
535  return;
-
536  }
-
537 
-
538  Element* elem = ship->GetElement();
-
539 
-
540  if (elem) {
-
541  Ship* lead = elem->GetShip(1);
-
542 
-
543  if (lead && lead != ship) {
-
544  if (lead->IsDropping() && !ship->IsDropping()) {
-
545  ship->DropOrbit();
-
546  // careful: this object has just been deleted!
-
547  return;
-
548  }
-
549 
-
550  if (lead->IsAttaining() && !ship->IsAttaining()) {
-
551  ship->MakeOrbit();
-
552  // careful: this object has just been deleted!
-
553  return;
-
554  }
-
555  }
-
556 
-
557  else {
-
558  if (drop_state < 0) {
-
559  ship->DropOrbit();
-
560  // careful: this object has just been deleted!
-
561  return;
-
562  }
-
563 
-
564  if (drop_state > 0) {
-
565  ship->MakeOrbit();
-
566  // careful: this object has just been deleted!
-
567  return;
-
568  }
-
569  }
-
570  }
-
571 
-
572  int order = 0;
-
573 
-
574  if (navpt)
-
575  order = navpt->Action();
-
576 
-
577  if (rtb_code == 1 && navpt && navpt->Status() < Instruction::SKIPPED &&
-
578  !inbound && distance < 35e3) { // (this should be distance to the ship)
-
579 
-
580  if (order == Instruction::RTB) {
-
581  Ship* controller = ship->GetController();
-
582  Hangar* hangar = controller ? controller->GetHangar() : 0;
-
583 
-
584  if (hangar && hangar->CanStow(ship)) {
-
585  for (int i = 0; i < elem->NumShips(); i++) {
-
586  Ship* s = elem->GetShip(i+1);
-
587 
-
588  if (s && s->GetDirector() && s->GetDirector()->Type() >= ShipAI::FIGHTER)
- -
590  }
-
591 
-
592  if (element_index == 1)
- -
594  }
-
595 
-
596  else {
-
597  if (element_index == 1) {
-
598  ::Print("WARNING: FighterAI NAVPT RTB, but no controller or hangar found for ship '%s'\n", ship->Name());
- -
600  }
-
601  }
-
602  }
-
603 
-
604  else {
-
605  Ship* dock_target = (Ship*) navpt->GetTarget();
-
606  if (dock_target) {
-
607  for (int i = 0; i < elem->NumShips(); i++) {
-
608  Ship* s = elem->GetShip(i+1);
-
609 
-
610  if (s) {
-
611  RadioMessage* msg = new(__FILE__,__LINE__) RadioMessage(dock_target, s, RadioMessage::CALL_INBOUND);
- -
613  }
-
614  }
-
615 
-
616  if (element_index == 1)
- -
618  }
-
619 
-
620  else {
-
621  if (element_index == 1) {
-
622  ::Print("WARNING: FighterAI NAVPT DOCK, but no dock target found for ship '%s'\n", ship->Name());
- -
624  }
-
625  }
-
626  }
-
627  }
-
628 
-
629  if (target)
-
630  ship->SetDirectorInfo(Game::GetText("ai.seek-target"));
-
631 
-
632  accumulator.Clear();
-
633  magnitude = 0;
-
634  brakes = 0;
-
635  z_shift = 0;
-
636 
-
637  hold = false;
-
638  if ((ship->GetElement() && ship->GetElement()->GetHoldTime() > 0) ||
-
639  (navpt && navpt->Status() == Instruction::COMPLETE && navpt->HoldTime() > 0))
-
640  hold = true;
-
641 
-
642  if (ship->MissionClock() < 10000) {
-
643  if (ship->IsAirborne())
- -
645  }
-
646 
-
647  else if ((farcaster && distance < 20e3) || (inbound && inbound->Final())) {
- -
649  }
-
650 
-
651  else {
-
652  if (!ship->IsAirborne() || ship->AltitudeAGL() > 100)
-
653  ship->RaiseGear();
-
654 
- -
656  Steer avoid = AvoidCollision();
-
657 
-
658  if (other && inbound && inbound->GetDeck() && inbound->Cleared()) {
-
659  if (other != (SimObject*) inbound->GetDeck()->GetCarrier())
-
660  Accumulate(avoid);
-
661  }
-
662  else {
-
663  Accumulate(avoid);
-
664  }
-
665 
-
666  if (!too_close && !hold && !terrain_warning) {
- - -
669  }
-
670  }
-
671 
-
672  HelmControl();
-
673  ThrottleControl();
-
674  FireControl();
-
675  AdjustDefenses();
-
676 
-
677  ship->ExecFLCSFrame();
-
678 }
-
679 
-
680 // +--------------------------------------------------------------------+
-
681 
-
682 void
- -
684 {
-
685  Camera* cam = ((Camera*) &(ship->Cam()));
-
686  Point vrt = cam->vrt();
-
687  double deflection = vrt.y;
-
688  double theta = 0;
-
689  bool formation = element_index > 1;
-
690  bool station_keeping = distance < 0;
-
691  bool inverted = cam->vup().y < -0.5;
-
692  Ship* ward = ship->GetWard();
-
693 
-
694  if (takeoff || inbound || station_keeping)
-
695  formation = false;
-
696 
-
697  if (takeoff || navpt || farcaster || patrol || inbound || rtb_code || target || ward || threat || formation) {
-
698  // are we being asked to flee?
-
699  if (fabs(accumulator.yaw) == 1.0 && accumulator.pitch == 0.0) {
-
700  accumulator.pitch = -0.7f;
-
701  accumulator.yaw *= 0.25f;
-
702 
-
703  if (ship->IsAirborne() && ship->GetFlightModel() == 0)
-
704  accumulator.pitch = -0.45f;
-
705 
-
706  // low ai -> lower turning rate
-
707  accumulator.pitch += 0.1f * (2-ai_level);
-
708  }
-
709 
-
710  ship->ApplyRoll((float) (accumulator.yaw * -0.7));
-
711  ship->ApplyYaw((float) (accumulator.yaw * 0.2));
-
712 
-
713  if (fabs(accumulator.yaw) > 0.5 && fabs(accumulator.pitch) < 0.1)
-
714  accumulator.pitch -= 0.1f;
-
715 
-
716  ship->ApplyPitch((float) accumulator.pitch);
-
717  }
-
718 
-
719  else {
-
720  ship->SetDirectorInfo(Game::GetText("ai.station-keeping"));
-
721  station_keeping = true;
-
722 
-
723  // go into a slow orbit if airborne:
-
724  if (ship->IsAirborne() && ship->Class() < Ship::LCA) {
-
725  accumulator.brake = 0.2;
-
726  accumulator.stop = 0;
-
727 
-
728  double compass_pitch = ship->CompassPitch();
-
729  double desired_bank = -PI/4;
-
730  double current_bank = asin(deflection);
-
731  double theta = desired_bank - current_bank;
-
732  ship->ApplyRoll(theta);
-
733 
-
734  double coord_pitch = compass_pitch - 0.2 * fabs(current_bank);
-
735  ship->ApplyPitch(coord_pitch);
-
736  }
-
737  else {
-
738  accumulator.brake = 1;
-
739  accumulator.stop = 1;
-
740  }
-
741  }
-
742 
-
743  // if not turning, roll to orient with world coords:
-
744  if (ship->Design()->auto_roll > 0) {
-
745  if (fabs(accumulator.pitch) < 0.1 && fabs(accumulator.yaw) < 0.25) {
-
746  // zolon spiral behavior:
-
747  if (ship->Design()->auto_roll > 1) {
-
748  if ((element_index + (ship->MissionClock()>>10)) & 0x4)
-
749  ship->ApplyRoll( 0.60);
-
750  else
-
751  ship->ApplyRoll(-0.35);
-
752  }
-
753 
-
754  // normal behavior - roll to upright:
-
755  else if (fabs(deflection) > 0.1 || inverted) {
-
756  double theta = asin(deflection/vrt.length()) * 0.5;
-
757  ship->ApplyRoll(-theta);
-
758  }
-
759  }
-
760  }
-
761 
-
762  // if not otherwise occupied, pitch to orient with world coords:
-
763  if (station_keeping && (!ship->IsAirborne() || ship->Class() < Ship::LCA)) {
-
764  Point heading = ship->Heading();
-
765  double pitch_deflection = heading.y;
-
766 
-
767  if (fabs(pitch_deflection) > 0.05) {
-
768  double rho = asin(pitch_deflection) * 3;
-
769  ship->ApplyPitch(rho);
-
770  }
-
771  }
-
772 
-
773  ship->SetTransX(0);
-
774  ship->SetTransY(0);
- - -
777 }
-
778 
-
779 void
- -
781 {
-
782  Element* elem = ship->GetElement();
-
783  double ship_speed = ship->Velocity() * ship->Heading();
-
784  double desired = 1000;
-
785  bool formation = element_index > 1;
-
786  bool station_keeping = distance < 0;
-
787  bool augmenter = false;
-
788  Ship* ward = ship->GetWard();
-
789 
-
790  if (inbound || station_keeping)
-
791  formation = false;
-
792 
-
793  // LAUNCH / TAKEOFF
-
794  if (ship->MissionClock() < 10000) {
-
795  formation = false;
-
796  throttle = 100;
-
797  brakes = 0;
-
798  }
-
799 
-
800  // STATION KEEPING
-
801  else if (station_keeping) {
-
802  // go into a slow orbit if airborne:
-
803  if (ship->IsAirborne() && ship->Class() < Ship::LCA) {
-
804  throttle = 30;
-
805  brakes = 0;
-
806  }
-
807  else {
-
808  throttle = 0;
-
809  brakes = 1;
-
810  }
-
811  }
-
812 
-
813  // TRY TO STAY AIRBORNE, YES?
-
814  else if (ship->IsAirborne() && ship_speed < 250 && ship->Class() < Ship::LCA) {
-
815  throttle = 100;
-
816  brakes = 0;
-
817 
-
818  if (ship_speed < 200)
-
819  augmenter = true;
-
820  }
-
821 
-
822  // INBOUND
-
823  else if (inbound) {
-
824  double carrier_speed = inbound->GetDeck()->GetCarrier()->Velocity().length();
-
825  desired = 250 + carrier_speed;
-
826 
-
827  if (distance > 25.0e3)
-
828  desired = 750 + carrier_speed;
-
829 
-
830  else if (ship->IsAirborne())
-
831  desired = 300;
-
832 
-
833  else if (inbound->Final())
-
834  desired = 75 + carrier_speed;
-
835 
-
836  throttle = 0;
-
837 
-
838  // holding short?
-
839  if (inbound->Approach() == 0 && !inbound->Cleared() &&
-
840  distance < 2000 && !ship->IsAirborne())
-
841  desired = 0;
-
842 
-
843  if (ship_speed > desired+5)
-
844  brakes = 0.25;
-
845 
-
846  else if (ship->IsAirborne() || Ship::GetFlightModel() > 0) {
-
847  throttle = old_throttle + 1;
-
848  }
-
849 
-
850  else if (ship_speed < 0.85 * desired) {
-
851  throttle = 100;
-
852 
-
853  if (ship_speed < 0 && ship->GetFuelLevel() > 10)
-
854  augmenter = true;
-
855  }
-
856 
-
857  else if (ship_speed < desired-5) {
-
858  throttle = 30;
-
859  }
-
860  }
-
861 
-
862  else if (rtb_code || farcaster) {
-
863  desired = 750;
-
864 
-
865  if (threat || threat_missile) {
-
866  throttle = 100;
-
867 
-
868  if (!threat_missile && ship->GetFuelLevel() > 15)
-
869  augmenter = true;
-
870  }
-
871 
-
872  else {
-
873  throttle = 0;
-
874 
-
875  if (ship_speed > desired+5)
-
876  brakes = 0.25;
-
877 
-
878  else if (Ship::GetFlightModel() > 0) {
-
879  throttle = old_throttle + 1;
-
880  }
-
881 
-
882  else if (ship_speed < 0.85 * desired) {
-
883  throttle = 100;
-
884 
-
885  if (ship_speed < 0 && ship->GetFuelLevel() > 10)
-
886  augmenter = true;
-
887  }
-
888 
-
889  else if (ship_speed < desired-5) {
-
890  throttle = 30;
-
891  }
-
892  }
-
893  }
-
894 
-
895  // RUN AWAY!!!
-
896  else if (evading) {
-
897  throttle = 100;
-
898 
-
899  if (!threat_missile && ship->GetFuelLevel() > 15)
-
900  augmenter = true;
-
901  }
-
902 
-
903  // PATROL AND FORMATION
-
904  else if (!navpt && !target && !ward) {
-
905  if (!elem || !formation) { // element lead
-
906  if (patrol) {
-
907  desired = 250;
-
908 
-
909  if (distance > 10e3)
-
910  desired = 750;
-
911 
-
912  if (ship_speed > desired+5) {
-
913  brakes = 0.25;
-
914  throttle = old_throttle - 5;
-
915  }
-
916 
-
917  else if (ship_speed < 0.85 * desired) {
-
918  throttle = 100;
-
919 
-
920  if (ship_speed < 0 && ship->GetFuelLevel() > 10)
-
921  augmenter = true;
-
922  }
-
923 
-
924  else if (ship_speed < desired-5)
-
925  throttle = old_throttle + 5;
-
926  }
-
927 
-
928  else {
-
929  throttle = 35;
-
930 
-
931  if (threat)
-
932  throttle = 100;
-
933 
- -
935 
-
936  if (brakes > 0.1)
-
937  throttle = 0;
-
938  }
-
939  }
-
940 
-
941  else { // wingman
-
942  Ship* lead = elem->GetShip(1);
-
943  double zone = ship->Radius() * 3;
-
944 
-
945  if (lead)
-
946  desired = lead->Velocity() * lead->Heading();
-
947 
-
948  if (fabs(slot_dist) < distance/4) // try to prevent porpoising
- -
950 
-
951  else if (slot_dist > zone*2) {
-
952  throttle = 100;
-
953 
-
954  if (objective.z > 10e3 && ship_speed < desired && ship->GetFuelLevel() > 25)
-
955  augmenter = true;
-
956  }
-
957 
-
958  else if (slot_dist > zone)
-
959  throttle = lead->Throttle() + 10;
-
960 
-
961  else if (slot_dist < -zone*2) {
-
962  throttle = old_throttle - 10;
-
963  brakes = 1;
-
964  }
-
965 
-
966  else if (slot_dist < -zone) {
- -
968  brakes = 0.5;
-
969  }
-
970 
-
971  else if (lead) {
-
972  double lv = lead->Velocity().length();
-
973  double sv = ship_speed;
-
974  double dv = lv-sv;
-
975  double dt = 0;
-
976 
-
977  if (dv > 0) dt = dv * 1e-5 * frame_time;
-
978  else if (dv < 0) dt = dv * 1e-2 * frame_time;
-
979 
-
980  throttle = old_throttle + dt;
-
981  }
-
982 
-
983  else {
- -
985  }
-
986  }
-
987  }
-
988 
-
989  // TARGET/WARD/NAVPOINT SEEKING
-
990  else {
- -
992 
-
993  if (target) {
-
994  desired = 1250;
-
995 
-
996  if (ai_level < 1) {
-
997  throttle = 70;
-
998  }
-
999 
-
1000  else if (ship->IsAirborne()) {
-
1001  throttle = 100;
-
1002 
-
1003  if (!threat_missile && fabs(objective.z) > 6e3 && ship->GetFuelLevel() > 25)
-
1004  augmenter = true;
-
1005  }
-
1006 
-
1007  else {
-
1008  throttle = 100;
-
1009 
-
1010  if (objective.z > 20e3 && ship_speed < desired && ship->GetFuelLevel() > 35)
-
1011  augmenter = true;
-
1012 
-
1013  else if (objective.z > 0 && objective.z < 10e3)
-
1014  throttle = 50;
-
1015  }
-
1016  }
-
1017 
-
1018  else if (ward) {
-
1019  double d = (ship->Location() - ward->Location()).length();
-
1020 
-
1021  if (d > 5000) {
-
1022  if (ai_level < 1)
-
1023  throttle = 50;
-
1024  else
-
1025  throttle = 80;
-
1026  }
-
1027  else {
-
1028  double speed = ward->Velocity().length();
-
1029 
-
1030  if (speed > 0) {
-
1031  if (ship_speed > speed) {
-
1032  throttle = old_throttle - 5;
-
1033  brakes = 0.25;
-
1034  }
-
1035  else if (ship_speed < speed - 10) {
-
1036  throttle = old_throttle + 1;
-
1037  }
-
1038  }
-
1039  }
-
1040  }
-
1041 
-
1042  else if (navpt) {
-
1043  desired = navpt->Speed();
-
1044 
-
1045  if (hold) {
-
1046  // go into a slow orbit if airborne:
-
1047  if (ship->IsAirborne() && ship->Class() < Ship::LCA) {
-
1048  throttle = 25;
-
1049  brakes = 0;
-
1050  }
-
1051  else {
-
1052  throttle = 0;
-
1053  brakes = 1;
-
1054  }
-
1055  }
-
1056 
-
1057  else if (desired > 0) {
-
1058  if (ship_speed > desired) {
-
1059  throttle = old_throttle - 5;
-
1060  brakes = 0.25;
-
1061  }
-
1062 
-
1063  else if (ship_speed < 0.85 * desired) {
-
1064  throttle = 100;
-
1065 
-
1066  if ((ship->IsAirborne() || ship_speed < 0.35 * desired) && ship->GetFuelLevel() > 30)
-
1067  augmenter = true;
-
1068  }
-
1069 
-
1070  else if (ship_speed < desired - 10) {
-
1071  throttle = old_throttle + 1;
-
1072  }
-
1073 
-
1074  else if (Ship::GetFlightModel() > 0) {
- -
1076  }
-
1077  }
-
1078  }
-
1079 
-
1080  else {
-
1081  throttle = 0;
-
1082  brakes = 1;
-
1083  }
-
1084  }
-
1085 
-
1086  if (ship->IsAirborne() && throttle < 20 && ship->Class() < Ship::LCA)
-
1087  throttle = 20;
-
1088  else if (ship->Design()->auto_roll > 1 && throttle < 5)
-
1089  throttle = 5;
-
1090  else if (throttle < 0)
-
1091  throttle = 0;
-
1092 
- -
1094  ship->SetThrottle((int) throttle);
-
1095  ship->SetAugmenter(augmenter);
-
1096 
-
1097  if (accumulator.stop && ship->GetFLCS() != 0)
-
1098  ship->GetFLCS()->FullStop();
-
1099 
-
1100  else if (ship_speed > 1 && brakes > 0)
- -
1102 
-
1103  else if (throttle > 10 && (ship->GetEMCON() < 2 || ship->GetFuelLevel() < 10))
- -
1105 }
-
1106 
-
1107 // +--------------------------------------------------------------------+
-
1108 
-
1109 Steer
- -
1111 {
-
1112  Steer avoid;
-
1113 
-
1114  terrain_warning = false;
-
1115 
-
1116  if (!ship || !ship->GetRegion() || !ship->GetRegion()->IsActive() ||
- -
1118  return avoid;
-
1119 
-
1120  if (ship->IsAirborne() && ship->GetFlightPhase() == Ship::ACTIVE) {
-
1121  // too high?
-
1122  if (ship->AltitudeMSL() > 25e3) {
-
1123  if (!navpt || (navpt->Region() == ship->GetRegion() && navpt->Location().z < 27e3)) {
-
1124  terrain_warning = true;
-
1125  ship->SetDirectorInfo(Game::GetText("ai.too-high"));
-
1126 
-
1127  // where will we be?
-
1128  Point selfpt = ship->Location() + ship->Velocity() + Point(0, -15e3, 0);
-
1129 
-
1130  // transform into camera coords:
-
1131  Point obj = Transform(selfpt);
-
1132 
-
1133  // head down!
-
1134  avoid = Seek(obj);
-
1135  }
-
1136  }
-
1137 
-
1138  // too low?
-
1139  else if (ship->AltitudeAGL() < 2500) {
-
1140  terrain_warning = true;
-
1141  ship->SetDirectorInfo(Game::GetText("ai.too-low"));
-
1142 
-
1143  // way too low?
-
1144  if (ship->AltitudeAGL() < 1500) {
-
1145  ship->SetDirectorInfo(Game::GetText("ai.way-too-low"));
-
1146  target = 0;
-
1147  drop_time = 5;
-
1148  }
-
1149 
-
1150  // where will we be?
-
1151  Point selfpt = ship->Location() + ship->Velocity() + Point(0, 10e3, 0);
-
1152 
-
1153  // transform into camera coords:
-
1154  Point obj = Transform(selfpt);
-
1155 
-
1156  // pull up!
-
1157  avoid = Seek(obj);
-
1158  }
-
1159  }
-
1160 
-
1161  return avoid;
-
1162 }
-
1163 
-
1164 // +--------------------------------------------------------------------+
-
1165 
-
1166 Steer
- -
1168 {
-
1169  if (ship->GetFlightPhase() < Ship::ACTIVE)
-
1170  return Seek(objective);
-
1171 
-
1172  Ship* ward = ship->GetWard();
-
1173 
-
1174  if ((!target && !ward && !navpt && !farcaster && !patrol && !inbound && !rtb_code) || ship->MissionClock() < 10000) {
-
1175  if (element_index > 1) {
-
1176  // break formation if threatened:
-
1177  if (threat_missile)
-
1178  return Steer();
-
1179 
-
1180  else if (threat && !form_up)
-
1181  return Steer();
-
1182 
-
1183  // otherwise, keep in formation:
-
1184  return SeekFormationSlot();
-
1185  }
-
1186  else {
-
1187  return Steer();
-
1188  }
-
1189  }
-
1190 
-
1191  if (patrol) {
-
1192  Steer result = Seek(objective);
-
1193  ship->SetDirectorInfo(Game::GetText("ai.seek-patrol-point"));
-
1194 
-
1195  if (distance < 10 * self->Radius()) {
-
1196  patrol = 0;
-
1197  result.brake = 1;
-
1198  result.stop = 1;
-
1199  }
-
1200 
-
1201  return result;
-
1202  }
-
1203 
-
1204  if (inbound) {
-
1205  Steer result = Seek(objective);
-
1206 
-
1207  if (over_threshold && objective.z < 0) {
-
1208  result = Steer();
-
1209  result.brake = 1;
-
1210  result.stop = 1;
-
1211  }
-
1212  else {
-
1213  ship->SetDirectorInfo(Game::GetText("ai.seek-inbound"));
-
1214 
-
1215  // approach legs:
-
1216  if (inbound->Approach() > 0) {
-
1217  if (distance < 20 * self->Radius())
- -
1219  }
-
1220 
-
1221  // marshall point and finals:
-
1222  else {
-
1223  if (inbound->Cleared() && distance < 10 * self->Radius()) {
-
1224  if (!inbound->Final()) {
-
1225  time_to_dock = TIME_TO_DOCK;
-
1226 
-
1227  FlightDeck* deck = inbound->GetDeck();
-
1228  if (deck) {
-
1229  double total_dist = Point(deck->EndPoint() - deck->StartPoint()).length();
-
1230  double current_dist = Point(deck->EndPoint() - ship->Location()).length();
-
1231 
-
1232  time_to_dock *= (current_dist / total_dist);
-
1233  }
-
1234 
- -
1236  }
-
1237 
-
1238  inbound->SetFinal(true);
-
1239  ship->LowerGear();
-
1240  result.brake = 1;
-
1241  result.stop = 1;
-
1242  }
-
1243 
-
1244  else if (!inbound->Cleared() && distance < 2000) {
-
1245  ship->SetDirectorInfo(Game::GetText("ai.hold-final"));
-
1246  result = Steer();
-
1247  result.brake = 1;
-
1248  result.stop = 1;
-
1249  }
-
1250  }
-
1251  }
-
1252 
-
1253  return result;
-
1254  }
-
1255 
-
1256  else if (rtb_code) {
-
1257  return Seek(objective);
-
1258  }
-
1259 
-
1260  SimObject* tgt = target;
-
1261 
-
1262  if (ward && !tgt)
-
1263  tgt = ward;
-
1264 
-
1265  if (tgt && too_close == tgt->Identity()) {
-
1266  drop_time = 4;
-
1267  return Steer();
-
1268  }
-
1269 
-
1270  else if (navpt && navpt->Action() == Instruction::LAUNCH) {
-
1271  ship->SetDirectorInfo(Game::GetText("ai.launch"));
-
1272  return Seek(objective);
-
1273  }
-
1274 
-
1275  else if (farcaster) {
-
1276  // wingmen should
-
1277  if (element_index > 1)
-
1278  return SeekFormationSlot();
-
1279 
-
1280  ship->SetDirectorInfo(Game::GetText("ai.seek-farcaster"));
-
1281  return Seek(objective);
-
1282  }
-
1283 
-
1284  else if (drop_time > 0) {
-
1285  return Steer();
-
1286  }
-
1287 
-
1288  if (tgt) {
-
1289  double basis = self->Radius() + tgt->Radius();
-
1290  double gap = distance - basis;
-
1291 
-
1292  // target behind:
-
1293  if (objective.z < 0) {
-
1294  // leave some room for an attack run:
-
1295  if (gap < 8000) {
-
1296  Steer s;
-
1297 
-
1298  s.pitch = -0.1;
-
1299  if (objective.x > 0) s.yaw = 0.1;
-
1300  else s.yaw = -0.1;
-
1301 
-
1302  return s;
-
1303  }
-
1304 
-
1305  // start the attack run:
-
1306  else {
-
1307  return Seek(objective);
-
1308  }
-
1309  }
-
1310 
-
1311  // target in front:
-
1312  else {
-
1313  if (tgt->Type() == SimObject::SIM_SHIP) {
-
1314  Ship* tgt_ship = (Ship*) tgt;
-
1315 
-
1316  // capital target strike:
-
1317  if (tgt_ship->IsStatic()) {
-
1318  if (gap < 2500)
-
1319  return Flee(objective);
-
1320  }
-
1321 
-
1322  else if (tgt_ship->IsStarship()) {
-
1323  if (gap < 1000)
-
1324  return Flee(objective);
-
1325 
-
1326  else if (ship->GetFlightModel() == Ship::FM_STANDARD && gap < 20e3)
-
1327  go_manual = true;
-
1328  }
-
1329  }
-
1330 
-
1331  // fighter melee:
-
1332  if (tgt->Velocity() * ship->Velocity() < 0) {
-
1333  // head-to-head pass:
-
1334  if (gap < 1250)
-
1335  return Flee(objective);
-
1336  }
-
1337 
-
1338  else if (gap < 250) {
-
1339  return Steer();
-
1340  }
-
1341 
-
1342  ship->SetDirectorInfo(Game::GetText("ai.seek-target"));
-
1343  return Seek(objective);
-
1344  }
-
1345  }
-
1346 
-
1347  if (navpt) {
-
1348  ship->SetDirectorInfo(Game::GetText("ai.seek-navpt"));
-
1349  }
-
1350 
-
1351  return Seek(objective);
-
1352 }
-
1353 
-
1354 // +--------------------------------------------------------------------+
-
1355 
-
1356 Steer
- -
1358 {
-
1359  Steer s;
-
1360 
-
1361  // advance memory pipeline:
-
1362  az[2] = az[1]; az[1] = az[0];
-
1363  el[2] = el[1]; el[1] = el[0];
-
1364 
-
1365  Element* elem = ship->GetElement();
-
1366  Ship* lead = elem->GetShip(1);
-
1367 
-
1368  if (lead) {
-
1369  SimRegion* self_rgn = ship->GetRegion();
-
1370  SimRegion* lead_rgn = lead->GetRegion();
-
1371 
-
1372  if (self_rgn != lead_rgn) {
-
1373  QuantumDrive* qdrive = ship->GetQuantumDrive();
-
1374  bool use_farcaster = !qdrive ||
-
1375  !qdrive->IsPowerOn() ||
-
1376  qdrive->Status() < System::DEGRADED;
-
1377 
-
1378  if (use_farcaster) {
-
1379  FindObjectiveFarcaster(self_rgn, lead_rgn);
-
1380  }
-
1381 
-
1382  else if (qdrive) {
-
1383  if (qdrive->ActiveState() == QuantumDrive::ACTIVE_READY) {
-
1384  qdrive->SetDestination(lead_rgn, lead->Location());
-
1385  qdrive->Engage();
-
1386  }
-
1387  }
-
1388  }
-
1389  }
-
1390 
-
1391  // do station keeping?
-
1392  if (distance < ship->Radius() * 10 && lead->Velocity().length() < 50) {
-
1393  distance = -1;
-
1394  return s;
-
1395  }
-
1396 
-
1397  // approach
-
1398  if (objective.z > ship->Radius() * -4) {
-
1399  az[0] = atan2(fabs(objective.x), objective.z) * 50;
-
1400  el[0] = atan2(fabs(objective.y), objective.z) * 50;
-
1401 
-
1402  if (objective.x < 0) az[0] = -az[0];
-
1403  if (objective.y > 0) el[0] = -el[0];
-
1404 
-
1405  s.yaw = az[0] - seek_damp * (az[1] + az[2] * 0.5);
-
1406  s.pitch = el[0] - seek_damp * (el[1] + el[2] * 0.5);
-
1407  }
-
1408 
-
1409  // reverse
-
1410  else {
-
1411  if (objective.x > 0) s.yaw = 1.0f;
-
1412  else s.yaw = -1.0f;
-
1413 
-
1414  s.pitch = -objective.y * 0.5f;
-
1415  }
-
1416 
-
1417  seeking = 1;
-
1418  ship->SetDirectorInfo(Game::GetText("ai.seek-formation"));
-
1419 
-
1420  return s;
-
1421 }
-
1422 
-
1423 // +--------------------------------------------------------------------+
-
1424 
-
1425 Steer
-
1426 FighterAI::Seek(const Point& point)
-
1427 {
-
1428  Steer s;
-
1429 
-
1430  // advance memory pipeline:
-
1431  az[2] = az[1]; az[1] = az[0];
-
1432  el[2] = el[1]; el[1] = el[0];
-
1433 
-
1434  // approach
-
1435  if (point.z > 0.0f) {
-
1436  az[0] = atan2(fabs(point.x), point.z) * seek_gain;
-
1437  el[0] = atan2(fabs(point.y), point.z) * seek_gain;
-
1438 
-
1439  if (point.x < 0) az[0] = -az[0];
-
1440  if (point.y > 0) el[0] = -el[0];
-
1441 
-
1442  s.yaw = az[0] - seek_damp * (az[1] + az[2] * 0.5);
-
1443  s.pitch = el[0] - seek_damp * (el[1] + el[2] * 0.5);
-
1444 
-
1445  // pull up:
-
1446  if (ship->IsAirborne() && point.y > 5e3)
-
1447  s.pitch = -1.0f;
-
1448  }
-
1449 
-
1450  // reverse
-
1451  else {
-
1452  if (ship->IsAirborne()) {
-
1453  // pull up:
-
1454  if (point.y > 5e3) {
-
1455  s.pitch = -1.0f;
-
1456  }
-
1457 
-
1458  // head down:
-
1459  else if (point.y < -5e3) {
-
1460  s.pitch = 1.0f;
-
1461  }
-
1462 
-
1463  // level turn:
-
1464  else {
-
1465  if (point.x > 0) s.yaw = 1.0f;
-
1466  else s.yaw = -1.0f;
-
1467 
-
1468  s.brake = 0.5f;
-
1469  }
-
1470  }
-
1471 
-
1472  else {
-
1473  if (point.x > 0) s.yaw = 1.0f;
-
1474  else s.yaw = -1.0f;
-
1475  }
-
1476  }
-
1477 
-
1478  seeking = 1;
-
1479 
-
1480  return s;
-
1481 }
-
1482 
-
1483 // +--------------------------------------------------------------------+
-
1484 
-
1485 Steer
- -
1487 {
-
1488  // MISSILE THREAT REACTION:
-
1489  if (threat_missile) {
-
1490  evading = true;
-
1491  SetTarget(0);
-
1492  drop_time = 3 * (3-ai_level);
-
1493 
-
1494  // dropped a decoy for this missile yet?
-
1495  if (decoy_missile != threat_missile) {
-
1496  ship->FireDecoy();
- -
1498  }
-
1499 
-
1500  // beam the missile
-
1501  ship->SetDirectorInfo(Game::GetText("ai.evade-missile"));
-
1502 
-
1503  Point beam_line = threat_missile->Velocity().cross(Point(0,1,0));
-
1504  beam_line.Normalize();
-
1505  beam_line *= 1e6;
-
1506 
-
1507  Point evade_p;
-
1508  Point evade_w1 = threat_missile->Location() + beam_line;
-
1509  Point evade_w2 = threat_missile->Location() - beam_line;
-
1510 
-
1511  double d1 = Point(evade_w1 - ship->Location()).length();
-
1512  double d2 = Point(evade_w2 - ship->Location()).length();
-
1513 
-
1514  if (d1 > d2)
-
1515  evade_p = Transform(evade_w1);
-
1516  else
-
1517  evade_p = Transform(evade_w2);
-
1518 
-
1519  return Seek(evade_p);
-
1520  }
-
1521 
-
1522  // GENERAL THREAT EVASION:
-
1523  if (threat && !form_up) {
-
1524  double threat_range = 20e3;
-
1525 
-
1526  Ship* threat_ship = (Ship*) threat;
-
1527  double threat_dist = Point(threat->Location() - ship->Location()).length();
-
1528 
-
1529  if (threat_ship->IsStarship()) {
-
1530  threat_range = CalcDefensePerimeter(threat_ship);
-
1531  }
-
1532 
-
1533  if (threat_dist <= threat_range) {
-
1534  ship->SetDirectorInfo(Game::GetText("ai.evade-threat"));
-
1535 
-
1536  if (ship->IsAirborne()) {
-
1537  evading = true;
-
1538  Point beam_line = threat->Velocity().cross(Point(0,1,0));
-
1539  beam_line.Normalize();
-
1540  beam_line *= threat_range;
-
1541 
-
1542  Point evade_w = threat->Location() + beam_line;
-
1543  Point evade_p = Transform(evade_w);
-
1544 
-
1545  return Seek(evade_p);
-
1546  }
-
1547 
-
1548  else if (threat_ship->IsStarship()) {
-
1549  evading = true;
-
1550 
-
1551  if (target == threat_ship && threat_dist < threat_range / 4) {
-
1552  SetTarget(0);
-
1553  drop_time = 5;
-
1554  }
-
1555 
-
1556  if (!target) {
-
1557  ship->SetDirectorInfo(Game::GetText("ai.evade-starship"));
-
1558 
-
1559  // flee for three seconds:
-
1560  if ((ship->MissionClock() & 3) != 3) {
-
1561  return Flee(Transform(threat->Location()));
-
1562  }
-
1563 
-
1564  // jink for one second:
-
1565  else {
-
1566  if (Game::GameTime() - jink_time > 1500) {
- -
1568  jink = Point(rand() - 16384,
-
1569  rand() - 16384,
-
1570  rand() - 16384) * 15e3;
-
1571  }
-
1572 
-
1573  Point evade_w = ship->Location() + jink;
-
1574  Point evade_p = Transform(evade_w);
-
1575 
-
1576  return Seek(evade_p);
-
1577  }
-
1578  }
-
1579 
-
1580  else {
-
1581  ship->SetDirectorInfo(Game::GetText("ai.evade-and-seek"));
-
1582 
-
1583  // seek for three seconds:
-
1584  if ((ship->MissionClock() & 3) < 3) {
-
1585  return Steer(); // no evasion
-
1586  }
-
1587 
-
1588  // jink for one second:
-
1589  else {
-
1590  if (Game::GameTime() - jink_time > 1000) {
- -
1592  jink = Point(rand() - 16384,
-
1593  rand() - 16384,
-
1594  rand() - 16384);
-
1595  }
-
1596 
-
1597  Point evade_w = target->Location() + jink;
-
1598  Point evade_p = Transform(evade_w);
-
1599 
-
1600  return Seek(evade_p);
-
1601  }
-
1602  }
-
1603  }
-
1604 
-
1605  else {
-
1606  evading = true;
-
1607 
-
1608  if (target == threat) {
-
1609  if (target->Type() == SimObject::SIM_SHIP) {
-
1610  Ship* tgt_ship = (Ship*) target;
-
1611  if (tgt_ship->GetTrigger(0)) {
-
1612  SetTarget(0);
-
1613  drop_time = 3;
-
1614  }
-
1615  }
-
1616  }
-
1617 
-
1618  else if (target && threat_dist < threat_range / 2) {
-
1619  SetTarget(0);
-
1620  drop_time = 3;
-
1621  }
-
1622 
-
1623  if (target)
-
1624  ship->SetDirectorInfo(Game::GetText("ai.evade-and-seek"));
-
1625  else
-
1626  ship->SetDirectorInfo(Game::GetText("ai.random-evade"));
-
1627 
-
1628  // beam the threat
-
1629  Point beam_line = threat->Velocity().cross(Point(0,1,0));
-
1630  beam_line.Normalize();
-
1631  beam_line *= 1e6;
-
1632 
-
1633  Point evade_p;
-
1634  Point evade_w1 = threat->Location() + beam_line;
-
1635  Point evade_w2 = threat->Location() - beam_line;
-
1636 
-
1637  double d1 = Point(evade_w1 - ship->Location()).length();
-
1638  double d2 = Point(evade_w2 - ship->Location()).length();
-
1639 
-
1640  if (d1 > d2)
-
1641  evade_p = Transform(evade_w1);
-
1642  else
-
1643  evade_p = Transform(evade_w2);
-
1644 
-
1645  if (!target) {
-
1646  DWORD jink_rate = 400 + 200 * (3-ai_level);
-
1647 
-
1648  if (Game::GameTime() - jink_time > jink_rate) {
- -
1650  jink = Point(rand() - 16384,
-
1651  rand() - 16384,
-
1652  rand() - 16384) * 2000;
-
1653  }
-
1654 
-
1655  evade_p += jink;
-
1656  }
-
1657 
-
1658  Steer steer = Seek(evade_p);
-
1659 
-
1660  if (target)
-
1661  return steer / 4;
-
1662 
-
1663  return steer;
-
1664  }
-
1665  }
-
1666  }
-
1667 
-
1668  return Steer();
-
1669 }
-
1670 
-
1671 // +--------------------------------------------------------------------+
-
1672 
-
1673 void
- -
1675 {
-
1676  // if nothing to shoot at, forget it:
-
1677  if (!target || target->Integrity() < 1)
-
1678  return;
-
1679 
-
1680  // if the objective is a navpt or landing bay (not a target), then don't shoot!
- -
1682  return;
-
1683 
-
1684  // object behind us, or too close:
-
1685  if (objective.z < 0 || distance < 4 * self->Radius())
-
1686  return;
-
1687 
-
1688  // compute the firing cone:
-
1689  double cross_section = 2 * target->Radius() / distance;
-
1690  double gun_basket = cross_section * 2;
-
1691 
-
1692  Weapon* primary = ship->GetPrimary();
-
1693  Weapon* secondary = ship->GetSecondary();
-
1694  const WeaponDesign* dsgn_primary = 0;
-
1695  const WeaponDesign* dsgn_secondary = 0;
-
1696  bool use_primary = true;
-
1697  Ship* tgt_ship = 0;
-
1698 
-
1699  if (target->Type() == SimObject::SIM_SHIP) {
-
1700  tgt_ship = (Ship*) target;
-
1701 
-
1702  if (tgt_ship->InTransition())
-
1703  return;
-
1704  }
-
1705 
-
1706  if (primary) {
-
1707  dsgn_primary = primary->Design();
-
1708 
-
1709  if (dsgn_primary->aim_az_max > 5*DEGREES && distance > dsgn_primary->max_range/2)
-
1710  gun_basket = cross_section * 4;
-
1711 
-
1712  gun_basket *= (3-ai_level);
-
1713 
-
1714  if (tgt_ship) {
-
1715  if (!primary->CanTarget(tgt_ship->Class()))
-
1716  use_primary = false;
-
1717 
-
1718  /*** XXX NEED TO SUBTARGET SYSTEMS IF TARGET IS STARSHIP...
-
1719  else if (tgt_ship->ShieldStrength() > 10)
-
1720  use_primary = false;
-
1721  ***/
-
1722  }
-
1723 
-
1724  if (use_primary) {
-
1725  // is target in the basket?
-
1726  double dx = fabs(objective.x / distance);
-
1727  double dy = fabs(objective.y / distance);
-
1728 
-
1729  if (primary->GetFiringOrders() == Weapon::MANUAL &&
-
1730  dx < gun_basket && dy < gun_basket &&
-
1731  distance > dsgn_primary->min_range &&
-
1732  distance < dsgn_primary->max_range &&
-
1733  !primary->IsBlockedFriendly())
-
1734  {
-
1735  ship->FirePrimary();
-
1736  }
-
1737  }
-
1738  }
-
1739 
-
1740  if (secondary && secondary->GetFiringOrders() == Weapon::MANUAL) {
-
1741  dsgn_secondary = secondary->Design();
-
1742 
-
1743  if (missile_time <= 0 && secondary->Ammo() && !secondary->IsBlockedFriendly()) {
-
1744  if (secondary->Locked() || !dsgn_secondary->self_aiming) {
-
1745  // is target in basket?
-
1746  Point tgt = AimTransform(target->Location());
-
1747  double tgt_range = tgt.Normalize();
-
1748 
-
1749  int factor = 2-ai_level;
-
1750  double s_range = 0.5 + 0.2 * factor;
-
1751  double s_basket = 0.3 + 0.2 * factor;
-
1752  double extra_time = 10 * factor * factor + 5;
-
1753 
-
1754  if (!dsgn_secondary->self_aiming)
-
1755  s_basket *= 0.33;
-
1756 
-
1757  if (tgt_ship) {
-
1758  if (tgt_ship->Class() == Ship::MINE) {
-
1759  extra_time = 10;
-
1760  s_range = 0.75;
-
1761  }
-
1762 
-
1763  else if (!tgt_ship->IsDropship()) {
-
1764  extra_time = 0.5 * factor + 0.5;
-
1765  s_range = 0.9;
-
1766  }
-
1767  }
-
1768 
-
1769  // is target in decent range?
-
1770  if (tgt_range < secondary->Design()->max_range * s_range) {
-
1771  double dx = fabs(tgt.x);
-
1772  double dy = fabs(tgt.y);
-
1773 
-
1774  if (dx < s_basket && dy < s_basket && tgt.z > 0) {
-
1775  if (ship->FireSecondary()) {
-
1776  missile_time = secondary->Design()->salvo_delay + extra_time;
-
1777 
-
1778  if (Game::GameTime() - last_call_time > 6000) {
-
1779  // call fox:
-
1780  int call = RadioMessage::FOX_3; // A2A
-
1781 
-
1782  if (secondary->CanTarget(Ship::GROUND_UNITS)) // AGM
-
1783  call = RadioMessage::FOX_1;
-
1784 
-
1785  else if (secondary->CanTarget(Ship::DESTROYER)) // ASM
-
1786  call = RadioMessage::FOX_2;
-
1787 
- - -
1790  }
-
1791  }
-
1792  }
-
1793  }
-
1794  }
-
1795  }
-
1796  }
-
1797 }
-
1798 
-
1799 // +--------------------------------------------------------------------+
-
1800 
-
1801 double
- -
1803 {
-
1804  double perimeter = 15e3;
-
1805 
-
1806  if (starship) {
-
1807  ListIter<WeaponGroup> g_iter = starship->Weapons();
-
1808  while (++g_iter) {
-
1809  WeaponGroup* group = g_iter.value();
-
1810 
-
1811  ListIter<Weapon> w_iter = group->GetWeapons();
-
1812  while (++w_iter) {
-
1813  Weapon* weapon = w_iter.value();
-
1814 
-
1815  if (weapon->Ammo() &&
-
1816  weapon->GetTarget() == ship &&
-
1817  !weapon->IsBlockedFriendly()) {
-
1818 
-
1819  double range = weapon->Design()->max_range * 1.2;
-
1820  if (range > perimeter)
-
1821  perimeter = range;
-
1822  }
-
1823  }
-
1824  }
-
1825  }
-
1826 
-
1827  return perimeter;
-
1828 }
-
1829 
-
1830 
-
1831 
-
-
- - - - -- cgit v1.1