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/_tactical_a_i_8cpp_source.html | 1076 +++++++++++++++++++++++ 1 file changed, 1076 insertions(+) create mode 100644 Doc/doxygen/html/_tactical_a_i_8cpp_source.html (limited to 'Doc/doxygen/html/_tactical_a_i_8cpp_source.html') diff --git a/Doc/doxygen/html/_tactical_a_i_8cpp_source.html b/Doc/doxygen/html/_tactical_a_i_8cpp_source.html new file mode 100644 index 0000000..c3babf0 --- /dev/null +++ b/Doc/doxygen/html/_tactical_a_i_8cpp_source.html @@ -0,0 +1,1076 @@ + + + + + +Starshatter_Open: D:/SRC/StarshatterSVN/Stars45/TacticalAI.cpp Source File + + + + + + + + + + + + + +
+
+ + + + + + +
+
Starshatter_Open +
+
Open source Starshatter engine
+
+
+ + + + + +
+
+ +
+
+
+ +
+ + + + +
+ +
+ +
+
+
TacticalAI.cpp
+
+
+Go to the documentation of this file.
1 /* Project Starshatter 4.5
+
2  Destroyer Studios LLC
+
3  Copyright (C) 1997-2004. All Rights Reserved.
+
4 
+
5  SUBSYSTEM: Stars.exe
+
6  FILE: TacticalAI.cpp
+
7  AUTHOR: John DiCamillo
+
8 
+
9 
+
10  OVERVIEW
+
11  ========
+
12  Generic Ship Tactical Level AI class
+
13 */
+
14 
+
15 #include "MemDebug.h"
+
16 #include "TacticalAI.h"
+
17 #include "ShipAI.h"
+
18 #include "CarrierAI.h"
+
19 #include "Ship.h"
+
20 #include "ShipDesign.h"
+
21 #include "Element.h"
+
22 #include "Instruction.h"
+
23 #include "RadioMessage.h"
+
24 #include "RadioTraffic.h"
+
25 #include "Contact.h"
+
26 #include "WeaponGroup.h"
+
27 #include "Drive.h"
+
28 #include "Hangar.h"
+
29 #include "Sim.h"
+
30 #include "Shot.h"
+
31 #include "Drone.h"
+
32 #include "StarSystem.h"
+
33 
+
34 #include "Game.h"
+
35 #include "Random.h"
+
36 
+
37 // +----------------------------------------------------------------------+
+
38 
+
39 static int exec_time_seed = 0;
+
40 
+
41 // +----------------------------------------------------------------------+
+
42 
+ +
44 : ship(0), ship_ai(0), carrier_ai(0), navpt(0), orders(0),
+
45 action(0), threat_level(0), support_level(1),
+
46 directed_tgtid(0)
+
47 {
+
48  if (ai) {
+
49  ship_ai = ai;
+
50  ship = ai->GetShip();
+
51 
+
52  Sim* sim = Sim::GetSim();
+
53 
+
54  if (ship && ship->GetHangar() && ship->GetCommandAILevel() > 0 &&
+
55  ship != sim->GetPlayerShip())
+
56  carrier_ai = new(__FILE__,__LINE__) CarrierAI(ship, ship_ai->GetAILevel());
+
57  }
+
58 
+
59  agression = 0;
+
60  roe = FLEXIBLE;
+
61  element_index = 1;
+
62  exec_time = exec_time_seed;
+
63  exec_time_seed += 17;
+
64 }
+
65 
+ +
67 {
+
68  delete carrier_ai;
+
69 }
+
70 
+
71 // +--------------------------------------------------------------------+
+
72 
+
73 void
+ +
75 {
+
76  const int exec_period = 1000;
+
77 
+
78  if (!ship || !ship_ai)
+
79  return;
+
80 
+ + +
83 
+
84  if ((int) Game::GameTime() - exec_time > exec_period) {
+ +
86 
+
87  CheckOrders();
+
88  SelectTarget();
+
89  FindThreat();
+
90  FindSupport();
+
91 
+
92  if (element_index > 1) {
+
93  int formation = 0;
+
94 
+
95  if (orders && orders->Formation() >= 0)
+
96  formation = orders->Formation();
+
97 
+
98  else if (navpt)
+
99  formation = navpt->Formation();
+
100 
+
101  FindFormationSlot(formation);
+
102  }
+
103 
+ +
105 
+
106  if (carrier_ai)
+
107  carrier_ai->ExecFrame(secs);
+
108 
+
109  exec_time += exec_period;
+
110  }
+
111 }
+
112 
+
113 // +--------------------------------------------------------------------+
+
114 
+
115 void
+ +
117 {
+
118  directed_tgtid = 0;
+
119 
+
120  if (CheckShipOrders())
+
121  return;
+
122 
+
123  if (CheckFlightPlan())
+
124  return;
+
125 
+
126  if (CheckObjectives())
+
127  return;
+
128 }
+
129 
+
130 // +--------------------------------------------------------------------+
+
131 
+
132 bool
+ +
134 {
+
135  return ProcessOrders();
+
136 }
+
137 
+
138 // +--------------------------------------------------------------------+
+
139 
+
140 bool
+ +
142 {
+
143  bool processed = false;
+
144  Ship* ward = 0;
+
145  Element* elem = ship->GetElement();
+
146 
+
147  if (elem) {
+
148  Instruction* obj = elem->GetTargetObjective();
+
149 
+
150  if (obj) {
+
151  ship_ai->ClearPatrol();
+
152 
+
153  if (obj->Action()) {
+
154  switch (obj->Action()) {
+ +
156  case Instruction::STRIKE:
+ +
158  {
+
159  SimObject* tgt = obj->GetTarget();
+
160  if (tgt && tgt->Type() == SimObject::SIM_SHIP) {
+
161  roe = DIRECTED;
+
162  SelectTargetDirected((Ship*) tgt);
+
163  }
+
164  }
+
165  break;
+
166 
+
167  case Instruction::DEFEND:
+
168  case Instruction::ESCORT:
+
169  {
+
170  SimObject* tgt = obj->GetTarget();
+
171  if (tgt && tgt->Type() == SimObject::SIM_SHIP) {
+
172  roe = DEFENSIVE;
+
173  ward = (Ship*) tgt;
+
174  }
+
175  }
+
176  break;
+
177 
+
178  default:
+
179  break;
+
180  }
+
181  }
+
182 
+
183  orders = obj;
+
184  processed = true;
+
185  }
+
186  }
+
187 
+
188  ship_ai->SetWard(ward);
+
189  return processed;
+
190 }
+
191 
+
192 // +--------------------------------------------------------------------+
+
193 
+
194 bool
+ +
196 {
+
197  if (ship_ai)
+
198  ship_ai->ClearPatrol();
+
199 
+
200  if (orders && orders->EMCON() > 0) {
+
201  int desired_emcon = orders->EMCON();
+
202 
+ +
204  desired_emcon = 3;
+
205 
+
206  if (ship->GetEMCON() != desired_emcon)
+
207  ship->SetEMCON(desired_emcon);
+
208  }
+
209 
+
210  if (orders && orders->Action()) {
+
211  switch (orders->Action()) {
+ + + +
215  {
+
216  bool tgt_ok = false;
+
217  SimObject* tgt = orders->GetTarget();
+
218 
+
219  if (tgt && tgt->Type() == SimObject::SIM_SHIP) {
+
220  Ship* tgt_ship = (Ship*) tgt;
+
221 
+
222  if (CanTarget(tgt_ship)) {
+
223  roe = DIRECTED;
+
224  SelectTargetDirected((Ship*) tgt);
+
225 
+ + +
228  ship_ai->SetNavPoint(0);
+
229 
+
230  tgt_ok = true;
+
231  }
+
232  }
+
233 
+
234  if (!tgt_ok)
+ +
236  }
+
237  break;
+
238 
+ + +
241  {
+
242  SimObject* tgt = orders->GetTarget();
+
243  if (tgt && tgt->Type() == SimObject::SIM_SHIP) {
+
244  roe = DEFENSIVE;
+
245  ship_ai->SetWard((Ship*) tgt);
+
246  ship_ai->SetNavPoint(0);
+
247  }
+
248  else {
+ +
250  }
+
251  }
+
252  break;
+
253 
+ +
255  roe = AGRESSIVE;
+
256  ship_ai->DropTarget(0.1);
+
257  break;
+
258 
+ + +
261  roe = NONE;
+
262  ship_ai->DropTarget(5);
+
263  break;
+
264 
+ + + +
268  ship_ai->SetNavPoint(0);
+
269  ship_ai->DropTarget(Random(5, 10));
+
270  break;
+
271 
+
272  case RadioMessage::RTB:
+ +
274  roe = NONE;
+
275 
+
276  ship_ai->DropTarget(10);
+
277 
+
278  if (!ship->GetInbound()) {
+
279  RadioMessage* msg = 0;
+
280  Ship* controller = ship->GetController();
+
281 
+ +
283  controller = (Ship*) orders->GetTarget();
+
284  }
+
285 
+
286  if (!controller) {
+
287  Element* elem = ship->GetElement();
+
288  if (elem && elem->GetCommander()) {
+
289  Element* cmdr = elem->GetCommander();
+
290  controller = cmdr->GetShip(1);
+
291  }
+
292  }
+
293 
+
294  if (controller && controller->GetHangar() &&
+
295  controller->GetHangar()->CanStow(ship)) {
+
296  SimRegion* self_rgn = ship->GetRegion();
+
297  SimRegion* rtb_rgn = controller->GetRegion();
+
298 
+
299  if (self_rgn == rtb_rgn) {
+
300  double range = Point(controller->Location() - ship->Location()).length();
+
301 
+
302  if (range < 50e3) {
+
303  msg = new(__FILE__,__LINE__) RadioMessage(controller, ship, RadioMessage::CALL_INBOUND);
+ +
305  }
+
306  }
+
307  }
+
308  else {
+ +
310  }
+
311 
+
312  ship_ai->SetNavPoint(0);
+
313  }
+
314  break;
+
315 
+ + +
318  roe = NONE;
+
319  ship_ai->DropTarget(10);
+
320  break;
+
321 
+
322  }
+
323 
+
324  action = orders->Action();
+
325  return true;
+
326  }
+
327 
+
328  // if we had an action before, this must be a "cancel orders"
+
329  else if (action) {
+ +
331  }
+
332 
+
333  return false;
+
334 }
+
335 
+
336 void
+ +
338 {
+
339  action = 0;
+
340  roe = FLEXIBLE;
+
341 
+
342  if (ship_ai)
+
343  ship_ai->DropTarget(0.1);
+
344 
+
345  if (ship)
+ +
347 
+
348 }
+
349 
+
350 // +--------------------------------------------------------------------+
+
351 
+
352 bool
+ +
354 {
+
355  Ship* ward = 0;
+
356 
+
357  // Find next Instruction:
+ +
359 
+
360  roe = FLEXIBLE;
+
361 
+
362  if (navpt) {
+
363  switch (navpt->Action()) {
+
364  case Instruction::LAUNCH:
+
365  case Instruction::DOCK:
+
366  case Instruction::RTB: roe = NONE;
+
367  break;
+
368 
+ +
370  break;
+
371 
+
372  case Instruction::DEFEND:
+ +
374  break;
+
375 
+ +
377  roe = DIRECTED;
+
378  break;
+
379 
+
380  case Instruction::RECON:
+
381  case Instruction::STRIKE:
+ +
383  break;
+
384 
+
385  case Instruction::PATROL:
+ +
387  break;
+
388 
+
389  default: break;
+
390  }
+
391 
+
392  if (roe == DEFENSIVE) {
+
393  SimObject* tgt = navpt->GetTarget();
+
394 
+
395  if (tgt && tgt->Type() == SimObject::SIM_SHIP)
+
396  ward = (Ship*) tgt;
+
397  }
+
398 
+
399 
+
400  if (navpt->EMCON() > 0) {
+
401  int desired_emcon = navpt->EMCON();
+
402 
+ +
404  desired_emcon = 3;
+
405 
+
406  if (ship->GetEMCON() != desired_emcon)
+
407  ship->SetEMCON(desired_emcon);
+
408  }
+
409  }
+
410 
+
411  if (ship_ai)
+
412  ship_ai->SetWard(ward);
+
413 
+
414  return (navpt != 0);
+
415 }
+
416 
+
417 // +--------------------------------------------------------------------+
+
418 
+
419 void
+ +
421 {
+
422  if (!ship) {
+
423  roe = NONE;
+
424  return;
+
425  }
+
426 
+
427  // unarmed vessels should never engage an enemy:
+
428  if (ship->Weapons().size() < 1)
+
429  roe = NONE;
+
430 
+
431  SimObject* target = ship_ai->GetTarget();
+
432  SimObject* ward = ship_ai->GetWard();
+
433 
+
434  // if not allowed to engage, drop and return:
+
435  if (roe == NONE) {
+
436  if (target)
+
437  ship_ai->DropTarget();
+
438  return;
+
439  }
+
440 
+
441  // if we have abandoned our ward, drop and return:
+
442  if (ward && roe != AGRESSIVE) {
+
443  double d = (ward->Location() - ship->Location()).length();
+
444  double safe_zone = 50e3;
+
445 
+
446  if (target) {
+
447  if (ship->IsStarship())
+
448  safe_zone = 100e3;
+
449 
+
450  if (d > safe_zone) {
+
451  ship_ai->DropTarget();
+
452  return;
+
453  }
+
454  }
+
455  else {
+
456  if (d > safe_zone) {
+
457  return;
+
458  }
+
459  }
+
460  }
+
461 
+
462  // already have a target, keep it:
+
463  if (target) {
+
464  if (target->Life()) {
+
465  CheckTarget();
+
466 
+
467  // frigates need to be ready to abandon ship-type targets
+
468  // in favor of drone-type targets, others should just go
+
469  // with what they have:
+
470  if (ship->Class() != Ship::CORVETTE && ship->Class() != Ship::FRIGATE)
+
471  return;
+
472 
+
473  // in case the check decided to drop the target:
+
474  target = ship_ai->GetTarget();
+
475  }
+
476 
+
477  // if the old target is dead, forget it:
+
478  else {
+
479  ship_ai->DropTarget();
+
480  target = 0;
+
481  }
+
482  }
+
483 
+
484  // if not allowed to acquire, forget it:
+
485  if (ship_ai->DropTime() > 0)
+
486  return;
+
487 
+
488  if (roe == DIRECTED) {
+
489  if (target && target->Type() == SimObject::SIM_SHIP)
+
490  SelectTargetDirected((Ship*) target);
+
491  else if (navpt && navpt->GetTarget() && navpt->GetTarget()->Type() == SimObject::SIM_SHIP)
+ +
493  else
+ +
495  }
+
496 
+
497  else {
+ +
499 
+
500  // don't switch one ship target for another...
+
501  if (ship->Class() == Ship::CORVETTE || ship->Class() == Ship::FRIGATE) {
+
502  SimObject* potential_target = ship_ai->GetTarget();
+
503  if (target && potential_target && target != potential_target) {
+
504  if (target->Type() == SimObject::SIM_SHIP &&
+
505  potential_target->Type() == SimObject::SIM_SHIP) {
+
506 
+
507  ship_ai->SetTarget(target);
+
508  }
+
509  }
+
510  }
+
511  }
+
512 }
+
513 
+
514 // +--------------------------------------------------------------------+
+
515 
+
516 void
+ +
518 {
+
519  Ship* potential_target = tgt;
+
520 
+
521  // try to target one of the element's objectives
+
522  // (if it shows up in the contact list)
+
523 
+
524  if (!tgt) {
+
525  Element* elem = ship->GetElement();
+
526 
+
527  if (elem) {
+
528  Instruction* objective = elem->GetTargetObjective();
+
529 
+
530  if (objective) {
+
531  SimObject* obj_sim_obj = objective->GetTarget();
+
532  Ship* obj_tgt = 0;
+
533 
+
534  if (obj_sim_obj && obj_sim_obj->Type() == SimObject::SIM_SHIP)
+
535  obj_tgt = (Ship*) obj_sim_obj;
+
536 
+
537  if (obj_tgt) {
+
538  ListIter<Contact> contact = ship->ContactList();
+
539  while (++contact && !potential_target) {
+
540  Ship* test = contact->GetShip();
+
541 
+
542  if (obj_tgt == test) {
+
543  potential_target = test;
+
544  }
+
545  }
+
546  }
+
547  }
+
548  }
+
549  }
+
550 
+
551  if (!CanTarget(potential_target))
+
552  potential_target = 0;
+
553 
+
554  ship_ai->SetTarget(potential_target);
+
555 
+
556  if (tgt && tgt == ship_ai->GetTarget())
+
557  directed_tgtid = tgt->Identity();
+
558  else
+
559  directed_tgtid = 0;
+
560 }
+
561 
+
562 // +--------------------------------------------------------------------+
+
563 
+
564 bool
+ +
566 {
+
567  bool result = false;
+
568 
+
569  if (tgt && !tgt->InTransition()) {
+
570  if (tgt->IsRogue() || tgt->GetIFF() != ship->GetIFF())
+
571  result = true;
+
572  }
+
573 
+
574  return result;
+
575 }
+
576 
+
577 // +--------------------------------------------------------------------+
+
578 
+
579 void
+ +
581 {
+
582  // NON-COMBATANTS do not pick targets of opportunity:
+
583  if (ship->GetIFF() == 0)
+
584  return;
+
585 
+
586  SimObject* potential_target = 0;
+
587 
+
588  // pick the closest combatant ship with a different IFF code:
+
589  double target_dist = ship->Design()->commit_range;
+
590 
+
591  SimObject* ward = ship_ai->GetWard();
+
592 
+
593  // FRIGATES are primarily anti-air platforms, but may
+
594  // also attack smaller starships:
+
595 
+
596  if (ship->Class() == Ship::CORVETTE || ship->Class() == Ship::FRIGATE) {
+
597  Ship* current_ship_target = 0;
+
598  Shot* current_shot_target = 0;
+
599 
+
600  // if we are escorting a larger warship, it is good to attack
+
601  // the same target as our ward:
+
602 
+
603  if (ward) {
+
604  Ship* s = (Ship*) ward;
+
605 
+
606  if (s->Class() > ship->Class()) {
+
607  SimObject* obj = s->GetTarget();
+
608 
+
609  if (obj && obj->Type() == SimObject::SIM_SHIP) {
+
610  current_ship_target = (Ship*) obj;
+
611  target_dist = (ship->Location() - obj->Location()).length();
+
612  }
+
613  }
+
614  }
+
615 
+
616  ListIter<Contact> contact = ship->ContactList();
+
617  while (++contact) {
+
618  Ship* c_ship = contact->GetShip();
+
619  Shot* c_shot = contact->GetShot();
+
620 
+
621  if (!c_ship && !c_shot)
+
622  continue;
+
623 
+
624  int c_iff = contact->GetIFF(ship);
+
625  bool rogue = c_ship && c_ship->IsRogue();
+
626  bool tgt_ok = c_iff > 0 &&
+
627  c_iff != ship->GetIFF() &&
+
628  c_iff < 1000;
+
629 
+
630  if (rogue || tgt_ok) {
+
631  if (c_ship && c_ship != ship && !c_ship->InTransition()) {
+
632  if (c_ship->Class() < Ship::DESTROYER ||
+
633  (c_ship->Class() >= Ship::MINE && c_ship->Class() <= Ship::SWACS)) {
+
634  // found an enemy, check distance:
+
635  double dist = (ship->Location() - c_ship->Location()).length();
+
636 
+
637  if (dist < 0.75 * target_dist &&
+
638  (!current_ship_target || c_ship->Class() <= current_ship_target->Class())) {
+
639  current_ship_target = c_ship;
+
640  target_dist = dist;
+
641  }
+
642  }
+
643  }
+
644 
+
645  else if (c_shot) {
+
646  // found an enemy shot, is there enough time to engage?
+
647  if (c_shot->GetEta() < 3)
+
648  continue;
+
649 
+
650  // found an enemy shot, check distance:
+
651  double dist = (ship->Location() - c_shot->Location()).length();
+
652 
+
653  if (!current_shot_target) {
+
654  current_shot_target = c_shot;
+
655  target_dist = dist;
+
656  }
+
657 
+
658  // is this shot a better target than the one we've found?
+
659  else {
+
660  Ship* ward = ship_ai->GetWard();
+
661 
+
662  if ((c_shot->IsTracking(ward) || c_shot->IsTracking(ship)) &&
+
663  (!current_shot_target->IsTracking(ward) ||
+
664  !current_shot_target->IsTracking(ship))) {
+
665  current_shot_target = c_shot;
+
666  target_dist = dist;
+
667  }
+
668  else if (dist < target_dist) {
+
669  current_shot_target = c_shot;
+
670  target_dist = dist;
+
671  }
+
672  }
+
673  }
+
674  }
+
675  }
+
676 
+
677  if (current_shot_target)
+
678  potential_target = current_shot_target;
+
679  else
+
680  potential_target = current_ship_target;
+
681  }
+
682 
+
683  // ALL OTHER SHIP CLASSES ignore fighters and only engage
+
684  // other starships:
+
685 
+
686  else {
+
687  List<Ship> ward_threats;
+
688 
+
689  ListIter<Contact> contact = ship->ContactList();
+
690  while (++contact) {
+
691  Ship* c_ship = contact->GetShip();
+
692 
+
693  if (!c_ship)
+
694  continue;
+
695 
+
696  int c_iff = contact->GetIFF(ship);
+
697  bool rogue = c_ship->IsRogue();
+
698  bool tgt_ok = c_ship != ship &&
+
699  c_iff > 0 &&
+
700  c_iff != ship->GetIFF() &&
+
701  !c_ship->InTransition();
+
702 
+
703  if (rogue || tgt_ok) {
+
704  if (c_ship->IsStarship() || c_ship->IsStatic()) {
+
705  // found an enemy, check distance:
+
706  double dist = (ship->Location() - c_ship->Location()).length();
+
707 
+
708  if (dist < 0.75 * target_dist) {
+
709  potential_target = c_ship;
+
710  target_dist = dist;
+
711  }
+
712 
+
713  if (ward && c_ship->IsTracking(ward)) {
+
714  ward_threats.append(c_ship);
+
715  }
+
716  }
+
717  }
+
718  }
+
719 
+
720  // if this ship is protecting a ward,
+
721  // prefer targets that are threatening that ward:
+
722  if (potential_target && ward_threats.size() && !ward_threats.contains((Ship*)potential_target)) {
+
723  target_dist *= 2;
+
724 
+
725  ListIter<Ship> iter = ward_threats;
+
726  while (++iter) {
+
727  Ship* threat = iter.value();
+
728 
+
729  double dist = (ward->Location() - threat->Location()).length();
+
730 
+
731  if (dist < target_dist) {
+
732  potential_target = threat;
+
733  target_dist = dist;
+
734  }
+
735  }
+
736  }
+
737  }
+
738 
+
739  if (ship->Class() != Ship::CARRIER)
+
740  ship_ai->SetTarget(potential_target);
+
741 }
+
742 
+
743 // +--------------------------------------------------------------------+
+
744 
+
745 void
+ +
747 {
+
748  SimObject* tgt = ship_ai->GetTarget();
+
749 
+
750  if (!tgt) return;
+
751 
+
752  if (tgt->GetRegion() != ship->GetRegion()) {
+
753  ship_ai->DropTarget();
+
754  return;
+
755  }
+
756 
+
757  if (tgt->Type() == SimObject::SIM_SHIP) {
+
758  Ship* target = (Ship*) tgt;
+
759 
+
760  // has the target joined our side?
+
761  if (target->GetIFF() == ship->GetIFF() && !target->IsRogue()) {
+
762  ship_ai->DropTarget();
+
763  return;
+
764  }
+
765 
+
766  // is the target already jumping/breaking/dying?
+
767  if (target->InTransition()) {
+
768  ship_ai->DropTarget();
+
769  return;
+
770  }
+
771 
+
772  // have we been ordered to pursue the target?
+
773  if (directed_tgtid) {
+
774  if (directed_tgtid != target->Identity()) {
+
775  ship_ai->DropTarget();
+
776  }
+
777 
+
778  return;
+
779  }
+
780 
+
781  // can we catch the target?
+
782  if (target->Design()->vlimit <= ship->Design()->vlimit ||
+
783  ship->Velocity().length() <= ship->Design()->vlimit)
+
784  return;
+
785 
+
786  // is the target now out of range?
+
787  WeaponDesign* wep_dsn = ship->GetPrimaryDesign();
+
788  if (!wep_dsn)
+
789  return;
+
790 
+
791  // compute the "give up" range:
+
792  double drop_range = 3 * wep_dsn->max_range;
+
793  if (drop_range > 0.75 * ship->Design()->commit_range)
+
794  drop_range = 0.75 * ship->Design()->commit_range;
+
795 
+
796  double range = Point(target->Location() - ship->Location()).length();
+
797  if (range < drop_range)
+
798  return;
+
799 
+
800  // is the target closing or separating?
+
801  Point delta = (target->Location() + target->Velocity()) -
+
802  (ship->Location() + ship->Velocity());
+
803 
+
804  if (delta.length() < range)
+
805  return;
+
806 
+
807  ship_ai->DropTarget();
+
808  }
+
809 
+
810  else if (tgt->Type() == SimObject::SIM_DRONE) {
+
811  Drone* drone = (Drone*) tgt;
+
812 
+
813  // is the target still a threat?
+
814  if (drone->GetEta() < 1 || drone->GetTarget() == 0)
+
815  ship_ai->DropTarget();
+
816  }
+
817 }
+
818 
+
819 // +--------------------------------------------------------------------+
+
820 
+
821 void
+ +
823 {
+
824  // pick the closest contact on Threat Warning System:
+
825  Ship* threat = 0;
+
826  Shot* threat_missile = 0;
+
827  Ship* rumor = 0;
+
828  double threat_dist = 1e9;
+
829  const DWORD THREAT_REACTION_TIME = 1000; // 1 second
+
830 
+ +
832 
+
833  while (++iter) {
+
834  Contact* contact = iter.value();
+
835 
+
836  if (contact->Threat(ship) &&
+
837  (Game::GameTime() - contact->AcquisitionTime()) > THREAT_REACTION_TIME) {
+
838 
+
839  if (contact->GetShot()) {
+
840  threat_missile = contact->GetShot();
+
841  rumor = (Ship*) threat_missile->Owner();
+
842  }
+
843  else {
+
844  double rng = contact->Range(ship);
+
845 
+
846  Ship* c_ship = contact->GetShip();
+
847  if (c_ship && !c_ship->InTransition() &&
+
848  c_ship->Class() != Ship::FREIGHTER &&
+
849  c_ship->Class() != Ship::FARCASTER) {
+
850 
+
851  if (c_ship->GetTarget() == ship) {
+
852  if (!threat || c_ship->Class() > threat->Class()) {
+
853  threat = c_ship;
+
854  threat_dist = 0;
+
855  }
+
856  }
+
857  else if (rng < threat_dist) {
+
858  threat = c_ship;
+
859  threat_dist = rng;
+
860  }
+
861  }
+
862  }
+
863  }
+
864  }
+
865 
+
866  if (rumor && !rumor->InTransition()) {
+
867  iter.reset();
+
868 
+
869  while (++iter) {
+
870  if (iter->GetShip() == rumor) {
+
871  rumor = 0;
+
872  ship_ai->ClearRumor();
+
873  break;
+
874  }
+
875  }
+
876  }
+
877  else {
+
878  rumor = 0;
+
879  ship_ai->ClearRumor();
+
880  }
+
881 
+
882  ship_ai->SetRumor(rumor);
+
883  ship_ai->SetThreat(threat);
+
884  ship_ai->SetThreatMissile(threat_missile);
+
885 }
+
886 
+
887 // +--------------------------------------------------------------------+
+
888 
+
889 void
+ +
891 {
+
892  if (!ship_ai->GetThreat()) {
+
893  ship_ai->SetSupport(0);
+
894  return;
+
895  }
+
896 
+
897  // pick the biggest friendly contact in the sector:
+
898  Ship* support = 0;
+
899  double support_dist = 1e9;
+
900 
+
901  ListIter<Contact> contact = ship->ContactList();
+
902 
+
903  while (++contact) {
+
904  if (contact->GetShip() && contact->GetIFF(ship) == ship->GetIFF()) {
+
905  Ship* c_ship = contact->GetShip();
+
906 
+
907  if (c_ship != ship && c_ship->Class() >= ship->Class() && !c_ship->InTransition()) {
+
908  if (!support || c_ship->Class() > support->Class())
+
909  support = c_ship;
+
910  }
+
911  }
+
912  }
+
913 
+
914  ship_ai->SetSupport(support);
+
915 }
+
916 
+
917 // +--------------------------------------------------------------------+
+
918 
+
919 void
+ +
921 {
+
922  // find the formation delta:
+
923  int s = element_index - 1;
+
924  Point delta(10*s, 0, 10*s);
+
925 
+
926  // diamond:
+
927  if (formation == Instruction::DIAMOND) {
+
928  switch (element_index) {
+
929  case 2: delta = Point( 10, 0, -12); break;
+
930  case 3: delta = Point(-10, 0, -12); break;
+
931  case 4: delta = Point( 0, 0, -24); break;
+
932  }
+
933  }
+
934 
+
935  // spread:
+
936  if (formation == Instruction::SPREAD) {
+
937  switch (element_index) {
+
938  case 2: delta = Point( 15, 0, 0); break;
+
939  case 3: delta = Point(-15, 0, 0); break;
+
940  case 4: delta = Point(-30, 0, 0); break;
+
941  }
+
942  }
+
943 
+
944  // box:
+
945  if (formation == Instruction::BOX) {
+
946  switch (element_index) {
+
947  case 2: delta = Point(15, 0, 0); break;
+
948  case 3: delta = Point( 0, -1, -15); break;
+
949  case 4: delta = Point(15, -1, -15); break;
+
950  }
+
951  }
+
952 
+
953  // trail:
+
954  if (formation == Instruction::TRAIL) {
+
955  delta = Point(0, 0, -15*s);
+
956  }
+
957 
+
958  ship_ai->SetFormationDelta(delta * ship->Radius() * 2);
+
959 }
+
+
+ + + + -- cgit v1.1