From 8898ad9b25fca6afe2374d293a981db02a83d7e9 Mon Sep 17 00:00:00 2001 From: "FWoltermann@gmail.com" Date: Thu, 31 May 2012 14:46:27 +0000 Subject: Committing the documentation to svn to have it accessible online --- Doc/doxygen/html/_ship_a_i_8cpp_source.html | 1476 +++++++++++++++++++++++++++ 1 file changed, 1476 insertions(+) create mode 100644 Doc/doxygen/html/_ship_a_i_8cpp_source.html (limited to 'Doc/doxygen/html/_ship_a_i_8cpp_source.html') diff --git a/Doc/doxygen/html/_ship_a_i_8cpp_source.html b/Doc/doxygen/html/_ship_a_i_8cpp_source.html new file mode 100644 index 0000000..7405c13 --- /dev/null +++ b/Doc/doxygen/html/_ship_a_i_8cpp_source.html @@ -0,0 +1,1476 @@ + + + + + +Starshatter_Open: D:/SRC/StarshatterSVN/Stars45/ShipAI.cpp Source File + + + + + + + + + + + + + +
+
+ + + + + + +
+
Starshatter_Open +
+
Open source Starshatter engine
+
+
+ + + + + +
+
+ +
+
+
+ +
+ + + + +
+ +
+ +
+
+
ShipAI.cpp
+
+
+Go to the documentation of this file.
1 /* Project Starshatter 5.0
+
2  Destroyer Studios LLC
+
3  Copyright (C) 1997-2007. All Rights Reserved.
+
4 
+
5  SUBSYSTEM: Stars.exe
+
6  FILE: ShipAI.cpp
+
7  AUTHOR: John DiCamillo
+
8 
+
9 
+
10  OVERVIEW
+
11  ========
+
12  Starship (low-level) Artificial Intelligence class
+
13 */
+
14 
+
15 #include "MemDebug.h"
+
16 #include "ShipAI.h"
+
17 #include "TacticalAI.h"
+
18 #include "Ship.h"
+
19 #include "ShipDesign.h"
+
20 #include "Shot.h"
+
21 #include "Element.h"
+
22 #include "NavLight.h"
+
23 #include "Instruction.h"
+
24 #include "RadioMessage.h"
+
25 #include "RadioTraffic.h"
+
26 #include "Contact.h"
+
27 #include "WeaponGroup.h"
+
28 #include "Drive.h"
+
29 #include "Shield.h"
+
30 #include "Sim.h"
+
31 #include "Player.h"
+
32 #include "StarSystem.h"
+
33 #include "FlightComp.h"
+
34 #include "Farcaster.h"
+
35 #include "QuantumDrive.h"
+
36 #include "Debris.h"
+
37 #include "Asteroid.h"
+
38 
+
39 #include "Game.h"
+
40 #include "Random.h"
+
41 
+
42 // +----------------------------------------------------------------------+
+
43 
+ +
45 : SteerAI(s),
+
46 support(0), rumor(0), threat(0), threat_missile(0), drop_time(0),
+
47 too_close(0), navpt(0), patrol(0), engaged_ship_id(0),
+
48 bracket(false), identify(false), hold(false), takeoff(false),
+
49 throttle(0), old_throttle(0), element_index(1), splash_count(0),
+
50 tactical(0), farcaster(0), ai_level(2), last_avoid_time(0),
+
51 last_call_time(0)
+
52 {
+
53  ship = (Ship*) self;
+
54 
+
55  Sim* sim = Sim::GetSim();
+
56  Ship* pship = sim->GetPlayerShip();
+
57  int player_team = 1;
+
58 
+
59  if (pship)
+
60  player_team = pship->GetIFF();
+
61 
+
62  Player* player = Player::GetCurrentPlayer();
+
63  if (player) {
+
64  if (ship && ship->GetIFF() && ship->GetIFF() != player_team) {
+
65  ai_level = player->AILevel();
+
66  }
+
67  else if (player->AILevel() == 0) {
+
68  ai_level = 1;
+
69  }
+
70  }
+
71 
+
72  // evil alien ships are *always* smart:
+
73  if (ship && ship->GetIFF() > 1 && ship->Design()->auto_roll > 1) {
+
74  ai_level = 2;
+
75  }
+
76 }
+
77 
+
78 
+
79 // +--------------------------------------------------------------------+
+
80 
+ +
82 {
+
83  delete tactical;
+
84 }
+
85 
+
86 void
+ +
88 {
+
89  delete tactical;
+
90  tactical = 0;
+
91 }
+
92 
+
93 // +--------------------------------------------------------------------+
+
94 
+
95 Ship*
+ +
97 {
+
98  return ship->GetWard();
+
99 }
+
100 
+
101 void
+ +
103 {
+
104  if (s == ship->GetWard())
+
105  return;
+
106 
+
107  if (ship)
+
108  ship->SetWard(s);
+
109 
+
110  Point form = RandomDirection();
+
111  form.SwapYZ();
+
112 
+
113  if (fabs(form.x) < 0.5) {
+
114  if (form.x < 0)
+
115  form.x = -0.5;
+
116  else
+
117  form.x = 0.5;
+
118  }
+
119 
+
120  if (ship && ship->IsStarship()) {
+
121  form *= 30e3;
+
122  }
+
123  else {
+
124  form *= 15e3;
+
125  form.y = 500;
+
126  }
+
127 
+
128  SetFormationDelta(form);
+
129 }
+
130 
+
131 void
+ +
133 {
+
134  if (support == s)
+
135  return;
+
136 
+
137  support = s;
+
138 
+
139  if (support)
+
140  Observe(support);
+
141 }
+
142 
+
143 void
+ +
145 {
+
146  if (!s || rumor == s)
+
147  return;
+
148 
+
149  rumor = s;
+
150 
+
151  if (rumor)
+
152  Observe(rumor);
+
153 }
+
154 
+
155 void
+ +
157 {
+
158  rumor = 0;
+
159 }
+
160 
+
161 void
+ +
163 {
+
164  if (threat == s)
+
165  return;
+
166 
+
167  threat = s;
+
168 
+
169  if (threat)
+
170  Observe(threat);
+
171 }
+
172 
+
173 void
+ +
175 {
+
176  if (threat_missile == s)
+
177  return;
+
178 
+
179  threat_missile = s;
+
180 
+
181  if (threat_missile)
+ +
183 }
+
184 
+
185 bool
+ +
187 {
+
188  if (obj == support)
+
189  support = 0;
+
190 
+
191  if (obj == threat)
+
192  threat = 0;
+
193 
+
194  if (obj == threat_missile)
+
195  threat_missile = 0;
+
196 
+
197  if (obj == rumor)
+
198  rumor = 0;
+
199 
+
200  return SteerAI::Update(obj);
+
201 }
+
202 
+
203 const char*
+ +
205 {
+
206  static char name[64];
+
207  sprintf_s(name, "ShipAI(%s)", self->Name());
+
208  return name;
+
209 }
+
210 
+
211 // +--------------------------------------------------------------------+
+
212 
+
213 Point
+ +
215 {
+
216  return patrol_loc;
+
217 }
+
218 
+
219 void
+ +
221 {
+
222  patrol = 1;
+
223  patrol_loc = p;
+
224 }
+
225 
+
226 void
+ +
228 {
+
229  patrol = 0;
+
230 }
+
231 
+
232 // +--------------------------------------------------------------------+
+
233 
+
234 void
+
235 ShipAI::ExecFrame(double secs)
+
236 {
+
237  seconds = secs;
+
238 
+
239  if (drop_time > 0) drop_time -= seconds;
+
240  if (!ship) return;
+
241 
+
242  ship->SetDirectorInfo(" ");
+
243 
+
244  // check to make sure current navpt is still valid:
+
245  if (navpt)
+ +
247 
+ +
249  takeoff = true;
+
250 
+
251  if (takeoff) {
+
252  FindObjective();
+
253  Navigator();
+
254 
+
255  if (ship->MissionClock() > 10000)
+
256  takeoff = false;
+
257 
+
258  return;
+
259  }
+
260 
+
261  // initial assessment:
+
262  if (ship->MissionClock() < 5000)
+
263  return;
+
264 
+ +
266 
+
267  NavlightControl();
+
268  CheckTarget();
+
269 
+
270  if (tactical)
+ +
272 
+
273  if (target && target != ship->GetTarget()) {
+ +
275 
+
276  // if able to lock target, and target is a ship (not a shot)...
+
277  if (target == ship->GetTarget() && target->Type() == SimObject::SIM_SHIP) {
+
278 
+
279  // if this isn't the same ship we last called out:
+
280  if (target->Identity() != engaged_ship_id && Game::GameTime() - last_call_time > 10000) {
+
281  // call engaging:
+
282  RadioMessage* msg = new(__FILE__,__LINE__) RadioMessage(ship->GetElement(), ship, RadioMessage::CALL_ENGAGING);
+
283  msg->AddTarget(target);
+ + +
286 
+ +
288  }
+
289  }
+
290  }
+
291 
+
292  else if (!target) {
+
293  target = ship->GetTarget();
+
294 
+
295  if (engaged_ship_id && !target) {
+
296  engaged_ship_id = 0;
+
297 
+
298  /***
+
299  *** XXX
+
300  *** Not the right place to make this decision.
+
301  ***
+
302  *** There is a brief wait between killing a target and
+
303  *** selecting a new one, so this message is sent after
+
304  *** every kill.
+
305  ***
+
306  *** Need to track when the entire element has been
+
307  *** put down.
+
308 
+
309  if (element_index == 1) {
+
310  RadioMessage* msg = new(__FILE__,__LINE__) RadioMessage(ship->GetElement(), ship, RadioMessage::RESUME_MISSION);
+
311  RadioTraffic::Transmit(msg);
+
312  }
+
313 
+
314  ***
+
315  ***/
+
316  }
+
317  }
+
318 
+
319  FindObjective();
+
320  Navigator();
+
321 }
+
322 
+
323 // +--------------------------------------------------------------------+
+
324 
+
325 Point
+ +
327 {
+
328  if (ship && target) {
+
329  if (ship->GetPrimaryDesign()) {
+ +
331  Point delta = target->Location() - ship->Location();
+
332 
+
333  // fighters need to aim the ship so that the guns will hit the target
+
334  if (guns->firing_cone < 10*DEGREES && guns->max_range <= delta.length()) {
+
335  Point aim_vec = ship->Heading();
+
336  aim_vec.Normalize();
+
337 
+
338  Point shot_vel = ship->Velocity() + aim_vec * guns->speed;
+
339  return shot_vel - target->Velocity();
+
340  }
+
341 
+
342  // ships with turreted weapons just need to worry about actual closing speed
+
343  else {
+
344  return ship->Velocity() - target->Velocity();
+
345  }
+
346  }
+
347 
+
348  else {
+
349  return ship->Velocity();
+
350  }
+
351  }
+
352 
+
353  return Point(1,0,0);
+
354 }
+
355 
+
356 // +--------------------------------------------------------------------+
+
357 
+
358 void
+ +
360 {
+
361  distance = 0;
+
362 
+
363  int order = ship->GetRadioOrders()->Action();
+
364 
+
365  if (order == RadioMessage::QUANTUM_TO ||
+
366  order == RadioMessage::FARCAST_TO) {
+
367 
+ + +
370  return;
+
371  }
+
372 
+
373  bool form = (order == RadioMessage::WEP_HOLD) ||
+
374  (order == RadioMessage::FORM_UP) ||
+
375  (order == RadioMessage::MOVE_PATROL) ||
+
376  (order == RadioMessage::RTB) ||
+
377  (order == RadioMessage::DOCK_WITH) ||
+
378  (!order && !target) ||
+
379  (farcaster);
+
380 
+
381  Ship* ward = ship->GetWard();
+
382 
+
383  // if not the element leader, stay in formation:
+
384  if (form && element_index > 1) {
+
385  ship->SetDirectorInfo(Game::GetText("ai.formation"));
+
386 
+
387  if (navpt && navpt->Action() == Instruction::LAUNCH) {
+ +
389  }
+
390  else {
+
391  navpt = 0;
+ +
393  }
+
394 
+
395  // transform into camera coords:
+ +
397  return;
+
398  }
+
399 
+
400  // under orders?
+
401  bool directed = false;
+
402  if (tactical)
+ +
404 
+
405  // threat processing:
+
406  if (threat && !directed) {
+
407  double d_threat = Point(threat->Location() - ship->Location()).length();
+
408 
+
409  // seek support:
+
410  if (support) {
+
411  double d_support = Point(support->Location() - ship->Location()).length();
+
412  if (d_support > 35e3) {
+
413  ship->SetDirectorInfo(Game::GetText("ai.regroup"));
+ + +
416  return;
+
417  }
+
418  }
+
419 
+
420  // run away:
+
421  else if (threat != target) {
+
422  ship->SetDirectorInfo(Game::GetText("ai.retreat"));
+
423  obj_w = ship->Location() + Point(ship->Location() - threat->Location()) * 100;
+ +
425  return;
+
426  }
+
427  }
+
428 
+
429  // normal processing:
+
430  if (target) {
+
431  ship->SetDirectorInfo(Game::GetText("ai.seek-target"));
+ + +
434  }
+
435 
+
436  else if (patrol) {
+
437  ship->SetDirectorInfo(Game::GetText("ai.patrol"));
+ + +
440  }
+
441 
+
442  else if (ward) {
+
443  ship->SetDirectorInfo(Game::GetText("ai.seek-ward"));
+ + +
446  }
+
447 
+
448  else if (navpt && form) {
+
449  ship->SetDirectorInfo(Game::GetText("ai.seek-navpt"));
+ + +
452  }
+
453 
+
454  else if (rumor) {
+
455  ship->SetDirectorInfo(Game::GetText("ai.search"));
+ + +
458  }
+
459 
+
460  else {
+
461  obj_w = Point();
+
462  objective = Point();
+
463  }
+
464 }
+
465 
+
466 // +--------------------------------------------------------------------+
+
467 
+
468 void
+ +
470 {
+
471  if (!tgt) {
+
472  obj_w = Point();
+
473  return;
+
474  }
+
475 
+
476  navpt = 0; // this tells fire control that we are chasing a target,
+
477  // instead of a navpoint!
+
478 
+
479  Point cv = ClosingVelocity();
+
480  double cvl = cv.length();
+
481  double time = 0;
+
482 
+
483  if (cvl > 50) {
+
484  // distance from self to target:
+
485  distance = Point(tgt->Location() - self->Location()).length();
+
486 
+
487  // time to reach target:
+
488  time = distance / cvl;
+
489 
+
490  // where the target will be when we reach it:
+
491  if (time < 15) {
+
492  Point run_vec = tgt->Velocity();
+
493  obj_w = tgt->Location() + (run_vec * time);
+
494 
+
495 
+
496  if (time < 10)
+
497  obj_w += (tgt->Acceleration() * 0.33 * time * time);
+
498  }
+
499  else {
+
500  obj_w = tgt->Location();
+
501  }
+
502  }
+
503 
+
504  else {
+
505  obj_w = tgt->Location();
+
506  }
+
507 
+
508  distance = Point(obj_w - self->Location()).length();
+
509 
+
510  if (cvl > 50) {
+
511  time = distance / cvl;
+
512 
+
513  // where we will be when the target gets there:
+
514  if (time < 15) {
+
515  Point self_dest = self->Location() + cv * time;
+
516  Point err = obj_w - self_dest;
+
517 
+
518  obj_w += err;
+
519  }
+
520  }
+
521 
+
522  Point approach = obj_w - self->Location();
+
523  distance = approach.length();
+
524 
+
525  if (bracket && distance > 25e3) {
+
526  Point offset = approach.cross(Point(0,1,0));
+
527  offset.Normalize();
+
528  offset *= 15e3;
+
529 
+
530  Ship* s = (Ship*) self;
+
531  if (s->GetElementIndex() & 1)
+
532  obj_w -= offset;
+
533  else
+
534  obj_w += offset;
+
535  }
+
536 }
+
537 
+
538 // +--------------------------------------------------------------------+
+
539 
+
540 void
+ +
542 {
+
543  navpt = 0;
+
544 
+
545  Point npt = patrol_loc;
+
546  obj_w = npt;
+
547 
+
548  // distance from self to navpt:
+
549  distance = Point(obj_w - self->Location()).length();
+
550 
+
551  if (distance < 1000) {
+ +
553  ClearPatrol();
+
554  }
+
555 }
+
556 
+
557 // +--------------------------------------------------------------------+
+
558 
+
559 void
+ +
561 {
+
562  SimRegion* self_rgn = ship->GetRegion();
+
563  SimRegion* nav_rgn = navpt->Region();
+
564  QuantumDrive* qdrive = ship->GetQuantumDrive();
+
565 
+
566  if (!self_rgn)
+
567  return;
+
568 
+
569  if (!nav_rgn) {
+
570  nav_rgn = self_rgn;
+
571  navpt->SetRegion(nav_rgn);
+
572  }
+
573 
+
574  bool use_farcaster = self_rgn != nav_rgn &&
+
575  (navpt->Farcast() ||
+
576  !qdrive ||
+
577  !qdrive->IsPowerOn() ||
+
578  qdrive->Status() < System::DEGRADED
+
579  );
+
580 
+
581  if (use_farcaster) {
+
582  FindObjectiveFarcaster(self_rgn, nav_rgn);
+
583  }
+
584 
+
585  else {
+
586  if (farcaster) {
+
587  if (farcaster->GetShip()->GetRegion() != self_rgn)
+ +
589 
+
590  obj_w = farcaster->EndPoint();
+
591  }
+
592 
+
593  else {
+
594  // transform from starsystem to world coordinates:
+
595  Point npt = navpt->Region()->Location() + navpt->Location();
+
596 
+
597  SimRegion* active_region = ship->GetRegion();
+
598 
+
599  if (active_region)
+
600  npt -= active_region->Location();
+
601 
+
602  npt = npt.OtherHand();
+
603 
+
604  obj_w = npt;
+
605  }
+
606 
+
607  // distance from self to navpt:
+
608  distance = Point(obj_w - ship->Location()).length();
+
609 
+
610  if (farcaster && distance < 1000)
+
611  farcaster = 0;
+
612 
+
613  if (distance < 1000 || (navpt->Action() == Instruction::LAUNCH && distance > 25000))
+ +
615  }
+
616 }
+
617 
+
618 // +--------------------------------------------------------------------+
+
619 
+
620 void
+ +
622 {
+
623  Instruction* orders = ship->GetRadioOrders();
+
624  SimRegion* self_rgn = ship->GetRegion();
+
625  SimRegion* nav_rgn = orders->Region();
+
626  QuantumDrive* qdrive = ship->GetQuantumDrive();
+
627 
+
628  if (!self_rgn || !nav_rgn)
+
629  return;
+
630 
+
631  bool use_farcaster = self_rgn != nav_rgn &&
+
632  (orders->Farcast() ||
+
633  !qdrive ||
+
634  !qdrive->IsPowerOn() ||
+
635  qdrive->Status() < System::DEGRADED
+
636  );
+
637 
+
638  if (use_farcaster) {
+
639  FindObjectiveFarcaster(self_rgn, nav_rgn);
+
640  }
+
641 
+
642  else {
+
643  if (farcaster) {
+
644  if (farcaster->GetShip()->GetRegion() != self_rgn)
+ +
646 
+
647  obj_w = farcaster->EndPoint();
+
648  }
+
649 
+
650  else {
+
651  // transform from starsystem to world coordinates:
+
652  Point npt = orders->Region()->Location() + orders->Location();
+
653 
+
654  SimRegion* active_region = ship->GetRegion();
+
655 
+
656  if (active_region)
+
657  npt -= active_region->Location();
+
658 
+
659  npt = npt.OtherHand();
+
660 
+
661  obj_w = npt;
+
662 
+
663  if (qdrive && qdrive->ActiveState() == QuantumDrive::ACTIVE_READY) {
+
664  qdrive->SetDestination(nav_rgn, orders->Location());
+
665  qdrive->Engage();
+
666  return;
+
667  }
+
668  }
+
669 
+
670  // distance from self to navpt:
+
671  distance = Point(obj_w - ship->Location()).length();
+
672 
+
673  if (farcaster) {
+
674  if (distance < 1000) {
+
675  farcaster = 0;
+ +
677  }
+
678  }
+
679  else if (self_rgn == nav_rgn) {
+ +
681  }
+
682  }
+
683 }
+
684 
+
685 void
+ +
687 {
+
688  if (!farcaster) {
+
689  ListIter<Ship> s = src_rgn->Ships();
+
690  while (++s && !farcaster) {
+
691  if (s->GetFarcaster()) {
+
692  const Ship* dest = s->GetFarcaster()->GetDest();
+
693  if (dest && dest->GetRegion() == dst_rgn) {
+
694  farcaster = s->GetFarcaster();
+
695  }
+
696  }
+
697  }
+
698  }
+
699 
+
700  if (farcaster) {
+
701  Point apt = farcaster->ApproachPoint(0);
+
702  Point npt = farcaster->StartPoint();
+
703  double r1 = (ship->Location() - npt).length();
+
704 
+
705  if (r1 > 50e3) {
+
706  obj_w = apt;
+
707  distance = r1;
+
708  }
+
709 
+
710  else {
+
711  double r2 = (ship->Location() - apt).length();
+
712  double r3 = (npt - apt).length();
+
713 
+
714  if (r1+r2 < 1.2*r3) {
+
715  obj_w = npt;
+
716  distance = r1;
+
717  }
+
718  else {
+
719  obj_w = apt;
+
720  distance = r2;
+
721  }
+
722  }
+
723 
+ +
725  }
+
726 }
+
727 
+
728 // +--------------------------------------------------------------------+
+
729 
+
730 void
+ +
732 {
+
733  formation_delta = point;
+
734 }
+
735 
+
736 void
+ +
738 {
+
739  const double prediction = 5;
+
740 
+
741  // find the base position:
+
742  Element* elem = ship->GetElement();
+
743  Ship* lead = elem->GetShip(1);
+
744  Ship* ward = ship->GetWard();
+
745 
+
746  if (!lead || lead == ship) {
+
747  lead = ward;
+
748 
+
749  distance = (lead->Location() - self->Location()).length();
+
750  if (distance < 30e3 && lead->Velocity().length() < 50) {
+
751  obj_w = self->Location() + lead->Heading() * 1e6;
+
752  distance = -1;
+
753  return;
+
754  }
+
755  }
+
756 
+
757  obj_w = lead->Location() + lead->Velocity() * prediction;
+
758  Matrix m; m.Rotate(0, 0, lead->CompassHeading() - PI);
+
759  Point fd = formation_delta * m;
+
760  obj_w += fd;
+
761 
+
762  // try to avoid smacking into the ground...
+
763  if (ship->IsAirborne()) {
+
764  if (ship->AltitudeAGL() < 3000 || lead->AltitudeAGL() < 3000) {
+
765  obj_w.y += 500;
+
766  }
+
767  }
+
768 
+
769  Point dst_w = self->Location() + self->Velocity() * prediction;
+
770  Point dlt_w = obj_w - dst_w;
+
771 
+
772  distance = dlt_w.length();
+
773 
+
774  // get slot z distance:
+
775  dlt_w += ship->Location();
+
776  slot_dist = Transform(dlt_w).z;
+
777 
+
778  Director* lead_dir = lead->GetDirector();
+
779  if (lead_dir && (lead_dir->Type() == FIGHTER || lead_dir->Type() == STARSHIP)) {
+
780  ShipAI* lead_ai = (ShipAI*) lead_dir;
+
781  farcaster = lead_ai->GetFarcaster();
+
782  }
+
783  else {
+
784  Instruction* navpt = elem->GetNextNavPoint();
+
785  if (!navpt) {
+
786  farcaster = 0;
+
787  return;
+
788  }
+
789 
+
790  SimRegion* self_rgn = ship->GetRegion();
+
791  SimRegion* nav_rgn = navpt->Region();
+
792  QuantumDrive* qdrive = ship->GetQuantumDrive();
+
793 
+
794  if (self_rgn && !nav_rgn) {
+
795  nav_rgn = self_rgn;
+
796  navpt->SetRegion(nav_rgn);
+
797  }
+
798 
+
799  bool use_farcaster = self_rgn != nav_rgn &&
+
800  (navpt->Farcast() ||
+
801  !qdrive ||
+
802  !qdrive->IsPowerOn() ||
+
803  qdrive->Status() < System::DEGRADED
+
804  );
+
805 
+
806  if (use_farcaster) {
+
807  ListIter<Ship> s = self_rgn->Ships();
+
808  while (++s && !farcaster) {
+
809  if (s->GetFarcaster()) {
+
810  const Ship* dest = s->GetFarcaster()->GetDest();
+
811  if (dest && dest->GetRegion() == nav_rgn) {
+
812  farcaster = s->GetFarcaster();
+
813  }
+
814  }
+
815  }
+
816  }
+
817  else if (farcaster) {
+
818  if (farcaster->GetShip()->GetRegion() != self_rgn)
+ +
820 
+
821  obj_w = farcaster->EndPoint();
+
822  distance = Point(obj_w - ship->Location()).length();
+
823 
+
824  if (distance < 1000)
+
825  farcaster = 0;
+
826  }
+
827  }
+
828 }
+
829 
+
830 // +--------------------------------------------------------------------+
+
831 
+
832 void
+
833 ShipAI::Splash(const Ship* targ)
+
834 {
+
835  if (splash_count > 6)
+
836  splash_count = 4;
+
837 
+
838  // call splash:
+ +
840  splash_count++;
+
841 }
+
842 
+
843 // +--------------------------------------------------------------------+
+
844 
+
845 void
+ +
847 {
+
848  if (targ != target) {
+
849  bracket = false;
+
850  }
+
851 
+
852  SteerAI::SetTarget(targ, sub);
+
853 }
+
854 
+
855 void
+
856 ShipAI::DropTarget(double dtime)
+
857 {
+
858  SetTarget(0);
+
859  drop_time = dtime; // seconds until we can re-acquire
+
860 
+
861  ship->DropTarget();
+
862 }
+
863 
+
864 void
+ +
866 {
+
867  bracket = b;
+
868  identify = false;
+
869 }
+
870 
+
871 void
+ +
873 {
+
874  identify = i;
+
875  bracket = false;
+
876 }
+
877 
+
878 // +--------------------------------------------------------------------+
+
879 
+
880 void
+ +
882 {
+
883  accumulator.Clear();
+
884  magnitude = 0;
+
885 
+
886  hold = false;
+
887  if ((ship->GetElement() && ship->GetElement()->GetHoldTime() > 0) ||
+
888  (navpt && navpt->Status() == Instruction::COMPLETE && navpt->HoldTime() > 0))
+
889  hold = true;
+
890 
+ +
892 
+
893  if (target)
+
894  ship->SetDirectorInfo(Game::GetText("ai.seek-target"));
+
895  else if (rumor)
+
896  ship->SetDirectorInfo(Game::GetText("ai.seek-rumor"));
+
897  else
+
898  ship->SetDirectorInfo(Game::GetText("ai.none"));
+
899 
+ + +
902 
+
903  if (!hold)
+ +
905 
+
906  HelmControl();
+
907  ThrottleControl();
+
908  FireControl();
+
909  AdjustDefenses();
+
910 }
+
911 
+
912 // +--------------------------------------------------------------------+
+
913 
+
914 void
+ +
916 {
+
917  double trans_x = 0;
+
918  double trans_y = 0;
+
919  double trans_z = 0;
+
920 
+ +
922 
+
923  if (fabs(accumulator.pitch) < 5*DEGREES || fabs(accumulator.pitch) > 45*DEGREES) {
+
924  trans_z = objective.y;
+
925  ship->SetHelmPitch(0);
+
926  }
+
927 
+
928  else {
+ +
930  }
+
931 
+
932  ship->SetTransX(trans_x);
+
933  ship->SetTransY(trans_y);
+
934  ship->SetTransZ(trans_z);
+
935 
+
936  ship->ExecFLCSFrame();
+
937 }
+
938 
+
939 /*****************************************
+
940 **
+
941 ** NOTE:
+
942 ** No one is really using this method.
+
943 ** It is overridden by both StarshipAI
+
944 ** and FighterAI.
+
945 **
+
946 *****************************************/
+
947 
+
948 void
+ +
950 {
+
951  if (navpt && !threat && !target) { // lead only, get speed from navpt
+
952  double speed = navpt->Speed();
+
953 
+
954  if (speed > 0)
+
955  throttle = speed / ship->VelocityLimit() * 100;
+
956  else
+
957  throttle = 50;
+
958  }
+
959 
+
960  else if (patrol && !threat && !target) { // lead only, get speed from navpt
+
961  double speed = 200;
+
962 
+
963  if (distance > 5000)
+
964  speed = 500;
+
965 
+
966  if (ship->Velocity().length() > speed)
+
967  throttle = 0;
+
968  else
+
969  throttle = 50;
+
970  }
+
971 
+
972  else {
+
973  if (threat || target || element_index < 2) { // element lead
+
974  throttle = 100;
+
975 
+
976  if (!threat && !target)
+
977  throttle = 50;
+
978 
+
979  if (accumulator.brake > 0) {
+
980  throttle *= (1 - accumulator.brake);
+
981  }
+
982  }
+
983 
+
984  else { // wingman
+
985  Ship* lead = ship->GetElement()->GetShip(1);
+
986  double lv = lead->Velocity().length();
+
987  double sv = ship->Velocity().length();
+
988  double dv = lv-sv;
+
989  double dt = 0;
+
990 
+
991  if (dv > 0) dt = dv * 1e-2 * seconds;
+
992  else if (dv < 0) dt = dv * 1e-2 * seconds;
+
993 
+
994  throttle = old_throttle + dt;
+
995  }
+
996  }
+
997 
+ +
999  ship->SetThrottle((int) throttle);
+
1000 }
+
1001 
+
1002 // +--------------------------------------------------------------------+
+
1003 
+
1004 void
+ +
1006 {
+
1007  Ship* leader = ship->GetLeader();
+
1008 
+
1009  if (leader && leader != ship) {
+
1010  bool navlight_enabled = false;
+
1011 
+
1012  if (leader->NavLights().size() > 0)
+
1013  navlight_enabled = leader->NavLights().at(0)->IsEnabled();
+
1014 
+
1015  for (int i = 0; i < ship->NavLights().size(); i++) {
+
1016  if (navlight_enabled)
+
1017  ship->NavLights().at(i)->Enable();
+
1018  else
+
1019  ship->NavLights().at(i)->Disable();
+
1020  }
+
1021  }
+
1022 }
+
1023 
+
1024 // +--------------------------------------------------------------------+
+
1025 
+
1026 Steer
+ +
1028 {
+
1029  Steer avoid;
+
1030  return avoid;
+
1031 }
+
1032 
+
1033 // +--------------------------------------------------------------------+
+
1034 
+
1035 Steer
+ +
1037 {
+
1038  Steer avoid;
+
1039 
+
1040  if (!ship || !ship->GetRegion() || !ship->GetRegion()->IsActive())
+
1041  return avoid;
+
1042 
+
1043  if (other && (other->Life() == 0 || other->Integrity() < 1)) {
+
1044  other = 0;
+
1045  last_avoid_time = 0; // check for a new obstacle immediately
+
1046  }
+
1047 
+
1048  if (!other && Game::GameTime() - last_avoid_time < 500)
+
1049  return avoid;
+
1050 
+
1051  brake = 0;
+
1052 
+
1053  // don't get closer than this:
+
1054  double avoid_dist = 5 * self->Radius();
+
1055 
+
1056  if (avoid_dist < 1e3) avoid_dist = 1e3;
+
1057  else if (avoid_dist > 12e3) avoid_dist = 12e3;
+
1058 
+
1059  // find the soonest potential collision,
+
1060  // ignore any that occur after this:
+
1061  double avoid_time = 15;
+
1062 
+
1063  if (ship->Design()->avoid_time > 0)
+
1064  avoid_time = ship->Design()->avoid_time;
+
1065  else if (ship->IsStarship())
+
1066  avoid_time *= 1.5;
+
1067 
+
1068  Point bearing = self->Velocity();
+
1069  bearing.Normalize();
+
1070 
+
1071  bool found = false;
+
1072  int num_contacts = ship->NumContacts();
+
1073  ListIter<Contact> contact = ship->ContactList();
+
1074 
+
1075  // check current obstacle first:
+
1076  if (other) {
+
1077  found = AvoidTestSingleObject(other, bearing, avoid_dist, avoid_time, avoid);
+
1078  }
+
1079 
+
1080  if (!found) {
+
1081  // avoid ships:
+
1082  while (++contact && !found) {
+
1083  Ship* c_ship = contact->GetShip();
+
1084 
+
1085  if (c_ship && c_ship != ship && c_ship->IsStarship()) {
+
1086  found = AvoidTestSingleObject(c_ship, bearing, avoid_dist, avoid_time, avoid);
+
1087  }
+
1088  }
+
1089 
+
1090  // also avoid large pieces of debris:
+
1091  if (!found) {
+
1092  ListIter<Debris> iter = ship->GetRegion()->Rocks();
+
1093  while (++iter && !found) {
+
1094  Debris* debris = iter.value();
+
1095 
+
1096  if (debris->Mass() > ship->Mass())
+
1097  found = AvoidTestSingleObject(debris, bearing, avoid_dist, avoid_time, avoid);
+
1098  }
+
1099  }
+
1100 
+
1101  // and asteroids:
+
1102  if (!found) {
+
1103  // give asteroids a wider berth -
+
1104  avoid_dist *= 8;
+
1105 
+
1106  ListIter<Asteroid> iter = ship->GetRegion()->Roids();
+
1107  while (++iter && !found) {
+
1108  Asteroid* roid = iter.value();
+
1109  found = AvoidTestSingleObject(roid, bearing, avoid_dist, avoid_time, avoid);
+
1110  }
+
1111 
+
1112  if (!found)
+
1113  avoid_dist /= 8;
+
1114  }
+
1115 
+
1116  // if found, steer to avoid:
+
1117  if (other) {
+
1118  avoid = Avoid(obstacle, (float) (ship->Radius() + other->Radius() + avoid_dist * 0.9));
+
1119  avoid.brake = brake;
+
1120 
+
1121  ship->SetDirectorInfo(Game::GetText("ai.avoid-collision"));
+
1122  }
+
1123  }
+
1124 
+ +
1126  return avoid;
+
1127 }
+
1128 
+
1129 bool
+ +
1131 const Point& bearing,
+
1132 double avoid_dist,
+
1133 double& avoid_time,
+
1134 Steer& avoid)
+
1135 {
+
1136  if (too_close == obj->Identity()) {
+
1137  double dist = (ship->Location() - obj->Location()).length();
+
1138  double closure = (ship->Velocity() - obj->Velocity()) * bearing;
+
1139 
+
1140  if (closure > 1 && dist < avoid_dist) {
+
1141  avoid = AvoidCloseObject(obj);
+
1142  return true;
+
1143  }
+
1144  else {
+
1145  too_close = 0;
+
1146  }
+
1147  }
+
1148 
+
1149  // will we get close?
+
1150  double time = ClosestApproachTime(ship->Location(), ship->Velocity(),
+
1151  obj->Location(), obj->Velocity());
+
1152 
+
1153  // already past the obstacle:
+
1154  if (time <= 0) {
+
1155  if (other == obj) other = 0;
+
1156  return false;
+
1157  }
+
1158 
+
1159  // how quickly could we collide?
+
1160  Point current_relation = ship->Location() - obj->Location();
+
1161  double current_distance = current_relation.length() - ship->Radius() - obj->Radius();
+
1162 
+
1163  // are we really far away?
+
1164  if (current_distance > 25e3) {
+
1165  if (other == obj) other = 0;
+
1166  return false;
+
1167  }
+
1168 
+
1169  // is the obstacle a farcaster?
+
1170  if (obj->Type() == SimObject::SIM_SHIP) {
+
1171  Ship* c_ship = (Ship*) obj;
+
1172 
+
1173  if (c_ship->GetFarcaster()) {
+
1174  // are we on a safe vector?
+
1175  Point dir = ship->Velocity();
+
1176  dir.Normalize();
+
1177 
+
1178  double angle_off = fabs(acos(dir * obj->Cam().vpn()));
+
1179 
+
1180  if (angle_off > 90*DEGREES)
+
1181  angle_off = 180*DEGREES - angle_off;
+
1182 
+
1183  if (angle_off < 35*DEGREES) {
+
1184  // will we pass through the center?
+
1185  Point d = ship->Location() + dir * (current_distance + ship->Radius() + obj->Radius());
+
1186  double err = (obj->Location() - d).length();
+
1187 
+
1188  if (err < 0.667 * obj->Radius()) {
+
1189  return false;
+
1190  }
+
1191  }
+
1192  }
+
1193  }
+
1194 
+
1195  // rate of closure:
+
1196  double closing_velocity = (ship->Velocity() - obj->Velocity()) * bearing;
+
1197 
+
1198  // are we too close already?
+
1199  if (current_distance < (avoid_dist * 0.35)) {
+
1200  if (closing_velocity > 1 || current_distance < ship->Radius()) {
+
1201  avoid = AvoidCloseObject(obj);
+
1202  return true;
+
1203  }
+
1204  }
+
1205 
+
1206  // too far away to worry about:
+
1207  double separation = (avoid_dist + obj->Radius());
+
1208  if ((current_distance-separation) / closing_velocity > avoid_time) {
+
1209  if (other == obj) other = 0;
+
1210  return false;
+
1211  }
+
1212 
+
1213  // where will we be?
+
1214  Point selfpt = ship->Location() + ship->Velocity() * time;
+
1215  Point testpt = obj->Location() + obj->Velocity() * time;
+
1216 
+
1217  // how close will we get?
+
1218  double dist = (selfpt - testpt).length()
+
1219  - ship->Radius()
+
1220  - obj->Radius();
+
1221 
+
1222  // that's too close:
+
1223  if (dist < avoid_dist) {
+
1224  if (dist < avoid_dist * 0.25 && time < avoid_time * 0.5) {
+
1225  avoid = AvoidCloseObject(obj);
+
1226  return true;
+
1227  }
+
1228 
+
1229  obstacle = Transform(testpt);
+
1230 
+
1231  if (obstacle.z > 0) {
+
1232  other = obj;
+
1233  avoid_time = time;
+
1234  brake = 0.5;
+
1235 
+
1236  Observe(other);
+
1237  }
+
1238  }
+
1239 
+
1240  // hysteresis:
+
1241  else if (other == obj && dist > avoid_dist * 1.25) {
+
1242  other = 0;
+
1243  }
+
1244 
+
1245  return false;
+
1246 }
+
1247 
+
1248 // +--------------------------------------------------------------------+
+
1249 
+
1250 Steer
+ +
1252 {
+
1253  too_close = obj->Identity();
+
1254  obstacle = Transform(obj->Location());
+
1255  other = obj;
+
1256 
+
1257  Observe(other);
+
1258 
+
1259  Steer avoid = Flee(obstacle);
+
1260  avoid.brake = 0.3;
+
1261 
+
1262  ship->SetDirectorInfo(Game::GetText("ai.avoid-collision"));
+
1263  return avoid;
+
1264 }
+
1265 
+
1266 // +--------------------------------------------------------------------+
+
1267 
+
1268 Steer
+ +
1270 {
+
1271  Ship* ward = ship->GetWard();
+
1272 
+
1273  if (!target && !ward && !navpt && !patrol) {
+
1274  if (element_index > 1) {
+
1275  // wingmen keep in formation:
+
1276  return Seek(objective);
+
1277  }
+
1278 
+
1279  if (farcaster) {
+
1280  return Seek(objective);
+
1281  }
+
1282 
+
1283  if (rumor) {
+
1284  return Seek(objective);
+
1285  }
+
1286 
+
1287  return Steer();
+
1288  }
+
1289 
+
1290  if (patrol) {
+
1291  Steer result = Seek(objective);
+
1292 
+
1293  if (distance < 2000) {
+
1294  result.brake = 1;
+
1295  }
+
1296 
+
1297  return result;
+
1298  }
+
1299 
+
1300  if (target && too_close == target->Identity()) {
+
1301  drop_time = 4;
+
1302  return Avoid(objective, 0.0f);
+
1303  }
+
1304  else if (drop_time > 0) {
+
1305  return Steer();
+
1306  }
+
1307 
+
1308  return Seek(objective);
+
1309 }
+
1310 
+
1311 // +--------------------------------------------------------------------+
+
1312 
+
1313 Steer
+ +
1315 {
+
1316  return Steer();
+
1317 }
+
1318 
+
1319 // +--------------------------------------------------------------------+
+
1320 
+
1321 void
+ +
1323 {
+
1324 }
+
1325 
+
1326 // +--------------------------------------------------------------------+
+
1327 
+
1328 void
+ +
1330 {
+
1331  Shield* shield = ship->GetShield();
+
1332 
+
1333  if (shield) {
+
1334  double desire = 50;
+
1335 
+
1336  if (threat_missile || threat)
+
1337  desire = 100;
+
1338 
+
1339  shield->SetPowerLevel(desire);
+
1340  }
+
1341 }
+
1342 
+
1343 // +--------------------------------------------------------------------+
+
1344 
+
1345 void
+ +
1347 {
+
1348  if (target) {
+
1349  if (target->Life() == 0)
+
1350  target = 0;
+
1351 
+
1352  else if (target->Type() == SimObject::SIM_SHIP) {
+
1353  Ship* tgt_ship = (Ship*) target;
+
1354 
+
1355  if (tgt_ship->GetIFF() == ship->GetIFF() && !tgt_ship->IsRogue())
+
1356  target = 0;
+
1357  }
+
1358  }
+
1359 }
+
+
+ + + + -- cgit v1.1