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/_starship_a_i_8cpp_source.html | 939 ++++++++++++++++++++++++ 1 file changed, 939 insertions(+) create mode 100644 Doc/doxygen/html/_starship_a_i_8cpp_source.html (limited to 'Doc/doxygen/html/_starship_a_i_8cpp_source.html') diff --git a/Doc/doxygen/html/_starship_a_i_8cpp_source.html b/Doc/doxygen/html/_starship_a_i_8cpp_source.html new file mode 100644 index 0000000..525fba3 --- /dev/null +++ b/Doc/doxygen/html/_starship_a_i_8cpp_source.html @@ -0,0 +1,939 @@ + + + + + +Starshatter_Open: D:/SRC/StarshatterSVN/Stars45/StarshipAI.cpp Source File + + + + + + + + + + + + + +
+
+ + + + + + +
+
Starshatter_Open +
+
Open source Starshatter engine
+
+
+ + + + + +
+
+ +
+
+
+ +
+ + + + +
+ +
+ +
+
+
StarshipAI.cpp
+
+
+Go to the documentation of this file.
1 /* Project Starshatter 5.0
+
2  Destroyer Studios LLC
+
3  Copyright © 1997-2007. All Rights Reserved.
+
4 
+
5  SUBSYSTEM: Stars.exe
+
6  FILE: StarshipAI.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 "StarshipAI.h"
+
17 #include "StarshipTacticalAI.h"
+
18 #include "Ship.h"
+
19 #include "ShipDesign.h"
+
20 #include "Element.h"
+
21 #include "Mission.h"
+
22 #include "Instruction.h"
+
23 #include "RadioMessage.h"
+
24 #include "Contact.h"
+
25 #include "WeaponGroup.h"
+
26 #include "Drive.h"
+
27 #include "Sim.h"
+
28 #include "StarSystem.h"
+
29 #include "FlightComp.h"
+
30 #include "Farcaster.h"
+
31 #include "QuantumDrive.h"
+
32 
+
33 #include "Game.h"
+
34 #include "Random.h"
+
35 
+
36 // +----------------------------------------------------------------------+
+
37 
+ +
39 : ShipAI(s), sub_select_time(0), subtarget(0), tgt_point_defense(false)
+
40 {
+
41  ai_type = STARSHIP;
+
42 
+
43  // signifies this ship is a dead hulk:
+
44  if (ship && ship->Design()->auto_roll < 0) {
+
45  Point torque(rand()-16000, rand()-16000, rand()-16000);
+
46  torque.Normalize();
+
47  torque *= ship->Mass() / 10;
+
48 
+
49  ship->SetFLCSMode(0);
+
50  if (ship->GetFLCS())
+
51  ship->GetFLCS()->PowerOff();
+
52 
+
53  ship->ApplyTorque(torque);
+
54  ship->SetVelocity(RandomDirection() * Random(20, 50));
+
55 
+
56  for (int i = 0; i < 64; i++) {
+
57  Weapon* w = ship->GetWeaponByIndex(i+1);
+
58  if (w)
+
59  w->DrainPower(0);
+
60  else
+
61  break;
+
62  }
+
63  }
+
64 
+
65  else {
+
66  tactical = new(__FILE__,__LINE__) StarshipTacticalAI(this);
+
67  }
+
68 
+
69  sub_select_time = Game::GameTime() + (DWORD) Random(0, 2000);
+ +
71 }
+
72 
+
73 
+
74 // +--------------------------------------------------------------------+
+
75 
+ +
77 { }
+
78 
+
79 // +--------------------------------------------------------------------+
+
80 
+
81 void
+ +
83 {
+
84  distance = 0;
+
85 
+
86  int order = ship->GetRadioOrders()->Action();
+
87 
+
88  if (order == RadioMessage::QUANTUM_TO ||
+
89  order == RadioMessage::FARCAST_TO) {
+
90 
+ + +
93  return;
+
94  }
+
95 
+
96  bool hold = order == RadioMessage::WEP_HOLD ||
+
97  order == RadioMessage::FORM_UP;
+
98 
+
99  bool form = hold ||
+
100  (!order && !target) ||
+
101  (farcaster);
+
102 
+
103  // if not the element leader, stay in formation:
+
104  if (form && element_index > 1) {
+
105  ship->SetDirectorInfo(Game::GetText("ai.formation"));
+
106 
+
107  if (navpt && navpt->Action() == Instruction::LAUNCH) {
+ +
109  }
+
110  else {
+
111  navpt = 0;
+ +
113  }
+
114 
+
115  // transform into camera coords:
+ +
117  return;
+
118  }
+
119 
+
120  // under orders?
+
121  bool directed = false;
+
122  double threat_level = 0;
+
123  double support_level = 1;
+
124  Ship* ward = ship->GetWard();
+
125 
+
126  if (tactical) {
+ +
128  threat_level = tactical->ThreatLevel();
+
129  support_level = tactical->SupportLevel();
+
130  }
+
131 
+
132  // threat processing:
+
133  if (hold || !directed && threat_level >= 2*support_level) {
+
134 
+
135  // seek support:
+
136  if (support) {
+
137  double d_support = Point(support->Location() - ship->Location()).length();
+
138  if (d_support > 35e3) {
+
139  ship->SetDirectorInfo(Game::GetText("ai.regroup"));
+ + +
142  return;
+
143  }
+
144  }
+
145 
+
146  // run away:
+
147  else if (threat && threat != target) {
+
148  ship->SetDirectorInfo(Game::GetText("ai.retreat"));
+
149  obj_w = ship->Location() + Point(ship->Location() - threat->Location()) * 100;
+ +
151  return;
+
152  }
+
153  }
+
154 
+
155  // weapons hold:
+
156  if (hold) {
+
157  if (navpt) {
+
158  ship->SetDirectorInfo(Game::GetText("ai.seek-navpt"));
+ +
160  }
+
161 
+
162  else if (patrol) {
+
163  ship->SetDirectorInfo(Game::GetText("ai.patrol"));
+ +
165  }
+
166 
+
167  else {
+
168  ship->SetDirectorInfo(Game::GetText("ai.holding"));
+
169  objective = Point();
+
170  }
+
171  }
+
172 
+
173  // normal processing:
+
174  else if (target) {
+
175  ship->SetDirectorInfo(Game::GetText("ai.seek-target"));
+ +
177  }
+
178 
+
179  else if (patrol) {
+
180  ship->SetDirectorInfo(Game::GetText("ai.patrol"));
+ +
182  }
+
183 
+
184  else if (ward) {
+
185  ship->SetDirectorInfo(Game::GetText("ai.seek-ward"));
+ +
187  }
+
188 
+
189  else if (navpt) {
+
190  ship->SetDirectorInfo(Game::GetText("ai.seek-navpt"));
+ +
192  }
+
193 
+
194  else if (rumor) {
+
195  ship->SetDirectorInfo(Game::GetText("ai.search"));
+ +
197  }
+
198 
+
199  else {
+
200  objective = Point();
+
201  }
+
202 
+
203  // transform into camera coords:
+ +
205 }
+
206 
+
207 // +--------------------------------------------------------------------+
+
208 
+
209 void
+ +
211 {
+
212  // signifies this ship is a dead hulk:
+
213  if (ship && ship->Design()->auto_roll < 0) {
+
214  ship->SetDirectorInfo(Game::GetText("ai.dead"));
+
215  return;
+
216  }
+
217 
+
218  accumulator.Clear();
+
219  magnitude = 0;
+
220 
+
221  hold = false;
+
222  if ((ship->GetElement() && ship->GetElement()->GetHoldTime() > 0) ||
+
223  (navpt && navpt->Status() == Instruction::COMPLETE && navpt->HoldTime() > 0))
+
224  hold = true;
+
225 
+ +
227 
+
228  if (!ship->GetDirectorInfo()) {
+
229  if (target)
+
230  ship->SetDirectorInfo(Game::GetText("ai.seek-target"));
+
231  else if (ship->GetWard())
+
232  ship->SetDirectorInfo(Game::GetText("ai.seek-ward"));
+
233  else
+
234  ship->SetDirectorInfo(Game::GetText("ai.patrol"));
+
235  }
+
236 
+
237  if (farcaster && distance < 25e3) {
+ +
239  }
+
240  else {
+ +
242 
+
243  if (!other && !hold)
+ +
245  }
+
246 
+
247  HelmControl();
+
248  ThrottleControl();
+
249  FireControl();
+
250  AdjustDefenses();
+
251 }
+
252 
+
253 // +--------------------------------------------------------------------+
+
254 
+
255 void
+ +
257 {
+
258  // signifies this ship is a dead hulk:
+
259  if (ship && ship->Design()->auto_roll < 0) {
+
260  return;
+
261  }
+
262 
+
263  double trans_x = 0;
+
264  double trans_y = 0;
+
265  double trans_z = 0;
+
266 
+
267  bool station_keeping = distance < 0;
+
268 
+
269  if (station_keeping) {
+
270  accumulator.brake = 1;
+
271  accumulator.stop = 1;
+
272 
+
273  ship->SetHelmPitch(0);
+
274  }
+
275 
+
276  else {
+
277  Element* elem = ship->GetElement();
+
278 
+
279  Ship* ward = ship->GetWard();
+
280  Ship* s_threat = 0;
+
281  if (threat && threat->Class() >= ship->Class())
+
282  s_threat = threat;
+
283 
+
284  if (other || target || ward || s_threat || navpt || patrol || farcaster || element_index > 1) {
+ +
286 
+
287  if (elem->Type() == Mission::FLIGHT_OPS) {
+
288  ship->SetHelmPitch(0);
+
289 
+
290  if (ship->NumInbound() > 0) {
+ +
292  }
+
293  }
+
294 
+
295  else if (accumulator.pitch > 60*DEGREES) {
+ +
297  }
+
298 
+
299  else if (accumulator.pitch < -60*DEGREES) {
+
300  ship->SetHelmPitch(-60*DEGREES);
+
301  }
+
302 
+
303  else {
+ +
305  }
+
306 
+
307  }
+
308  else {
+
309  ship->SetHelmPitch(0);
+
310  }
+
311  }
+
312 
+
313  ship->SetTransX(trans_x);
+
314  ship->SetTransY(trans_y);
+
315  ship->SetTransZ(trans_z);
+
316 
+
317  ship->ExecFLCSFrame();
+
318 }
+
319 
+
320 void
+ +
322 {
+
323  // signifies this ship is a dead hulk:
+
324  if (ship && ship->Design()->auto_roll < 0) {
+
325  return;
+
326  }
+
327 
+
328  // station keeping:
+
329 
+
330  if (distance < 0) {
+
331  old_throttle = 0;
+
332  throttle = 0;
+
333 
+
334  ship->SetThrottle(0);
+
335 
+
336  if (ship->GetFLCS())
+
337  ship->GetFLCS()->FullStop();
+
338 
+
339  return;
+
340  }
+
341 
+
342  // normal throttle processing:
+
343 
+
344  double ship_speed = ship->Velocity() * ship->Heading();
+
345  double brakes = 0;
+
346  Ship* ward = ship->GetWard();
+
347  Ship* s_threat = 0;
+
348 
+
349  if (threat && threat->Class() >= ship->Class())
+
350  s_threat = threat;
+
351 
+
352  if (target || s_threat) { // target pursuit, or retreat
+
353  throttle = 100;
+
354 
+
355  if (target && distance < 50e3) {
+
356  double closing_speed = ship_speed;
+
357 
+
358  if (target) {
+
359  Point delta = target->Location() - ship->Location();
+
360  delta.Normalize();
+
361 
+
362  closing_speed = ship->Velocity() * delta;
+
363  }
+
364 
+
365  if (closing_speed > 300) {
+
366  throttle = 30;
+
367  brakes = 0.25;
+
368  }
+
369  }
+
370 
+
371  throttle *= (1 - accumulator.brake);
+
372 
+
373  if (throttle < 1 && ship->GetFLCS() != 0)
+
374  ship->GetFLCS()->FullStop();
+
375  }
+
376 
+
377  else if (ward) { // escort, match speed of ward
+
378  double speed = ward->Velocity().length();
+ +
380 
+
381  if (speed == 0) {
+
382  double d = (ship->Location() - ward->Location()).length();
+
383 
+
384  if (d > 30e3)
+
385  speed = (d - 30e3) / 100;
+
386  }
+
387 
+
388  if (speed > 0) {
+
389  if (ship_speed > speed) {
+
390  throttle = old_throttle - 1;
+
391  brakes = 0.2;
+
392  }
+
393  else if (ship_speed < speed - 10) {
+
394  throttle = old_throttle + 1;
+
395  }
+
396  }
+
397  else {
+
398  throttle = 0;
+
399  brakes = 0.5;
+
400  }
+
401  }
+
402 
+
403  else if (patrol || farcaster) { // seek patrol point
+
404  throttle = 100;
+
405 
+
406  if (distance < 10 * ship_speed) {
+
407  if (ship->Velocity().length() > 200)
+
408  throttle = 5;
+
409  else
+
410  throttle = 50;
+
411  }
+
412  }
+
413 
+
414  else if (navpt) { // lead only, get speed from navpt
+
415  double speed = navpt->Speed();
+ +
417 
+
418  if (hold) {
+
419  throttle = 0;
+
420  brakes = 1;
+
421  }
+
422 
+
423  else {
+
424  if (speed <= 0)
+
425  speed = 300;
+
426 
+
427  if (ship_speed > speed) {
+
428  if (throttle > 0 && old_throttle > 1)
+
429  throttle = old_throttle - 1;
+
430 
+
431  brakes = 0.25;
+
432  }
+
433  else if (ship_speed < speed - 10) {
+
434  throttle = old_throttle + 1;
+
435  }
+
436  }
+
437  }
+
438 
+
439  else if (element_index > 1) { // wingman
+
440  Ship* lead = ship->GetElement()->GetShip(1);
+
441  double lv = lead->Velocity().length();
+
442  double sv = ship_speed;
+
443  double dv = lv-sv;
+
444  double dt = 0;
+
445 
+
446  if (dv > 0) dt = dv * 1e-2 * seconds;
+
447  else if (dv < 0) dt = dv * 1e-2 * seconds;
+
448 
+
449  throttle = old_throttle + dt;
+
450  }
+
451 
+
452  else {
+
453  throttle = 0;
+
454  }
+
455 
+ + +
458 
+
459  if (ship_speed > 1 && brakes > 0)
+
460  ship->SetTransY(-brakes * ship->Design()->trans_y);
+
461 
+
462  else if (throttle > 10 && (ship->GetEMCON() < 2 || ship->GetFuelLevel() < 10))
+ +
464 }
+
465 
+
466 // +--------------------------------------------------------------------+
+
467 
+
468 Steer
+ +
470 {
+
471  if (navpt) {
+
472  SimRegion* self_rgn = ship->GetRegion();
+
473  SimRegion* nav_rgn = navpt->Region();
+
474  QuantumDrive* qdrive = ship->GetQuantumDrive();
+
475 
+
476  if (self_rgn && !nav_rgn) {
+
477  nav_rgn = self_rgn;
+
478  navpt->SetRegion(nav_rgn);
+
479  }
+
480 
+
481  bool use_farcaster = self_rgn != nav_rgn &&
+
482  (navpt->Farcast() ||
+
483  !qdrive ||
+
484  !qdrive->IsPowerOn() ||
+
485  qdrive->Status() < System::DEGRADED
+
486  );
+
487 
+
488  if (use_farcaster) {
+
489  if (!farcaster) {
+
490  ListIter<Ship> s = self_rgn->Ships();
+
491  while (++s && !farcaster) {
+
492  if (s->GetFarcaster()) {
+
493  const Ship* dest = s->GetFarcaster()->GetDest();
+
494  if (dest && dest->GetRegion() == nav_rgn) {
+
495  farcaster = s->GetFarcaster();
+
496  }
+
497  }
+
498  }
+
499  }
+
500 
+
501  if (farcaster) {
+
502  if (farcaster->GetShip()->GetRegion() != self_rgn)
+ +
504 
+
505  obj_w = farcaster->EndPoint();
+
506  distance = Point(obj_w - ship->Location()).length();
+
507 
+
508  if (distance < 1000)
+
509  farcaster = 0;
+
510  }
+
511  }
+
512  else if (self_rgn != nav_rgn) {
+ +
514 
+
515  if (q) {
+ + +
518  q->Engage();
+
519  }
+
520  }
+
521  }
+
522  }
+
523 
+
524  return ShipAI::SeekTarget();
+
525 }
+
526 
+
527 // +--------------------------------------------------------------------+
+
528 
+
529 Steer
+ +
531 {
+
532  if (!ship || ship->Velocity().length() < 25)
+
533  return Steer();
+
534 
+
535  return ShipAI::AvoidCollision();
+
536 }
+
537 
+
538 // +--------------------------------------------------------------------+
+
539 
+
540 void
+ +
542 {
+
543  // identify unknown contacts:
+
544  if (identify) {
+
545  if (fabs(ship->GetHelmHeading() - ship->CompassHeading()) < 10*DEGREES) {
+
546  Contact* contact = ship->FindContact(target);
+
547 
+
548  if (contact && !contact->ActLock()) {
+
549  if (!ship->GetProbe()) {
+
550  ship->LaunchProbe();
+
551  }
+
552  }
+
553  }
+
554 
+
555  return;
+
556  }
+
557 
+
558  // investigate last known location of enemy ship:
+
559  if (rumor && !target && ship->GetProbeLauncher() && !ship->GetProbe()) {
+
560  // is rumor in basket?
+
561  Point rmr = Transform(rumor->Location());
+
562  rmr.Normalize();
+
563 
+
564  double dx = fabs(rmr.x);
+
565  double dy = fabs(rmr.y);
+
566 
+
567  if (dx < 10*DEGREES && dy < 10*DEGREES && rmr.z > 0) {
+
568  ship->LaunchProbe();
+
569  }
+
570  }
+
571 
+
572  // Corvettes and Frigates are anti-air platforms. They need to
+
573  // target missile threats even when the threat is aimed at another
+
574  // friendly ship. Forward facing weapons must be on auto fire,
+
575  // while lateral and aft facing weapons are set to point defense.
+
576 
+
577  if (ship->Class() == Ship::CORVETTE || ship->Class() == Ship::FRIGATE) {
+ +
579  while (++iter) {
+
580  WeaponGroup* group = iter.value();
+
581 
+
582  ListIter<Weapon> w_iter = group->GetWeapons();
+
583  while (++w_iter) {
+
584  Weapon* weapon = w_iter.value();
+
585 
+
586  double az = weapon->GetAzimuth();
+
587  if (fabs(az) < 45*DEGREES) {
+
588  weapon->SetFiringOrders(Weapon::AUTO);
+
589  weapon->SetTarget(target, 0);
+
590  }
+
591 
+
592  else {
+ +
594  }
+
595  }
+
596  }
+
597  }
+
598 
+
599  // All other starships are free to engage ship targets. Weapon
+
600  // fire control is managed by the type of weapon.
+
601 
+
602  else {
+
603  System* subtgt = SelectSubtarget();
+
604 
+ +
606  while (++iter) {
+
607  WeaponGroup* weapon = iter.value();
+
608 
+
609  if (weapon->GetDesign()->target_type & Ship::DROPSHIPS) { // anti-air weapon?
+ +
611  }
+
612  else if (weapon->IsDrone()) { // torpedoes
+ +
614  weapon->SetTarget(target, 0);
+
615 
+
616  if (target && target->GetRegion() == ship->GetRegion()) {
+
617  Point delta = target->Location() - ship->Location();
+
618  double range = delta.length();
+
619 
+
620  if (range < weapon->GetDesign()->max_range * 0.9 &&
+ +
622  weapon->SetFiringOrders(Weapon::AUTO);
+
623 
+
624  else if (range < weapon->GetDesign()->max_range * 0.5)
+
625  weapon->SetFiringOrders(Weapon::AUTO);
+
626  }
+
627  }
+
628  else { // anti-ship weapon
+
629  weapon->SetFiringOrders(Weapon::AUTO);
+
630  weapon->SetTarget(target, subtgt);
+
631  weapon->SetSweep(subtgt ? Weapon::SWEEP_NONE : Weapon::SWEEP_TIGHT);
+
632  }
+
633  }
+
634  }
+
635 }
+
636 
+
637 // +--------------------------------------------------------------------+
+
638 
+
639 System*
+ +
641 {
+
642  if (Game::GameTime() - sub_select_time < 2345)
+
643  return subtarget;
+
644 
+
645  subtarget = 0;
+
646 
+
647  if (!target || target->Type() != SimObject::SIM_SHIP || GetAILevel() < 1)
+
648  return subtarget;
+
649 
+
650  Ship* tgt_ship = (Ship*) target;
+
651 
+
652  if (!tgt_ship->IsStarship())
+
653  return subtarget;
+
654 
+
655  Weapon* subtgt = 0;
+
656  double dist = 50e3;
+
657  Point svec = ship->Location() - tgt_ship->Location();
+
658 
+ +
660 
+
661  // first pass: turrets
+
662  ListIter<WeaponGroup> g_iter = tgt_ship->Weapons();
+
663  while (++g_iter) {
+
664  WeaponGroup* g = g_iter.value();
+
665 
+
666  if (g->GetDesign() && g->GetDesign()->turret_model) {
+
667  ListIter<Weapon> w_iter = g->GetWeapons();
+
668  while (++w_iter) {
+
669  Weapon* w = w_iter.value();
+
670 
+
671  if (w->Availability() < 35)
+
672  continue;
+
673 
+
674  if (w->GetAimVector() * svec < 0)
+
675  continue;
+
676 
+
677  if (w->GetTurret()) {
+
678  Point tloc = w->GetTurret()->Location();
+
679  Point delta = tloc - ship->Location();
+
680  double dlen = delta.length();
+
681 
+
682  if (dlen < dist) {
+
683  subtgt = w;
+
684  dist = dlen;
+
685  }
+
686  }
+
687  }
+
688  }
+
689  }
+
690 
+
691  // second pass: major weapons
+
692  if (!subtgt) {
+
693  g_iter.reset();
+
694  while (++g_iter) {
+
695  WeaponGroup* g = g_iter.value();
+
696 
+
697  if (g->GetDesign() && !g->GetDesign()->turret_model) {
+
698  ListIter<Weapon> w_iter = g->GetWeapons();
+
699  while (++w_iter) {
+
700  Weapon* w = w_iter.value();
+
701 
+
702  if (w->Availability() < 35)
+
703  continue;
+
704 
+
705  if (w->GetAimVector() * svec < 0)
+
706  continue;
+
707 
+
708  Point tloc = w->MountLocation();
+
709  Point delta = tloc - ship->Location();
+
710  double dlen = delta.length();
+
711 
+
712  if (dlen < dist) {
+
713  subtgt = w;
+
714  dist = dlen;
+
715  }
+
716  }
+
717  }
+
718  }
+
719  }
+
720 
+
721  subtarget = subtgt;
+
722  return subtarget;
+
723 }
+
724 
+
725 // +--------------------------------------------------------------------+
+
726 
+
727 bool
+ +
729 {
+
730  if (Game::GameTime() - point_defense_time < 3500)
+
731  return tgt_point_defense;
+
732 
+
733  tgt_point_defense = false;
+
734 
+
735  if (!target || target->Type() != SimObject::SIM_SHIP || GetAILevel() < 2)
+
736  return tgt_point_defense;
+
737 
+
738  Ship* tgt_ship = (Ship*) target;
+
739 
+
740  if (!tgt_ship->IsStarship())
+
741  return tgt_point_defense;
+
742 
+
743  Weapon* subtgt = 0;
+
744  Point svec = ship->Location() - tgt_ship->Location();
+
745 
+ +
747 
+
748  // first pass: turrets
+
749  ListIter<WeaponGroup> g_iter = tgt_ship->Weapons();
+
750  while (++g_iter && !tgt_point_defense) {
+
751  WeaponGroup* g = g_iter.value();
+
752 
+
753  if (g->CanTarget(1)) {
+
754  ListIter<Weapon> w_iter = g->GetWeapons();
+
755  while (++w_iter && !tgt_point_defense) {
+
756  Weapon* w = w_iter.value();
+
757 
+
758  if (w->Availability() > 35 && w->GetAimVector() * svec > 0)
+
759  tgt_point_defense = true;
+
760  }
+
761  }
+
762  }
+
763 
+
764  return tgt_point_defense;
+
765 }
+
766 
+
767 
+
768 // +--------------------------------------------------------------------+
+
769 
+
770 Point
+ +
772 {
+
773  return point - self->Location();
+
774 }
+
775 
+
776 Steer
+
777 StarshipAI::Seek(const Point& point)
+
778 {
+
779  // the point is in relative world coordinates
+
780  // x: distance east(-) / west(+)
+
781  // y: altitude down(-) / up(+)
+
782  // z: distance north(-) / south(+)
+
783 
+
784  Steer result;
+
785 
+
786  result.yaw = atan2(point.x, point.z) + PI;
+
787 
+
788  double adjacent = sqrt(point.x*point.x + point.z*point.z);
+
789  if (fabs(point.y) > ship->Radius() && adjacent > ship->Radius())
+
790  result.pitch = atan(point.y / adjacent);
+
791 
+
792  if (!_finite(result.yaw))
+
793  result.yaw = 0;
+
794 
+
795  if (!_finite(result.pitch))
+
796  result.pitch = 0;
+
797 
+
798  return result;
+
799 }
+
800 
+
801 Steer
+
802 StarshipAI::Flee(const Point& point)
+
803 {
+
804  Steer result = Seek(point);
+
805  result.yaw += PI;
+
806  return result;
+
807 }
+
808 
+
809 Steer
+
810 StarshipAI::Avoid(const Point& point, float radius)
+
811 {
+
812  Steer result = Seek(point);
+
813 
+
814  if (point * ship->BeamLine() > 0)
+
815  result.yaw -= PI/2;
+
816  else
+
817  result.yaw += PI/2;
+
818 
+
819  return result;
+
820 }
+
821 
+
822 
+
+
+ + + + -- cgit v1.1