diff options
author | milo24x7@gmail.com <milo24x7@gmail.com@076cb2c4-205e-83fd-5cf3-1be9aa105544> | 2013-07-07 22:08:49 +0000 |
---|---|---|
committer | milo24x7@gmail.com <milo24x7@gmail.com@076cb2c4-205e-83fd-5cf3-1be9aa105544> | 2013-07-07 22:08:49 +0000 |
commit | d17521c8b9085a91d08fecfd0b51bbbf7b1dccac (patch) | |
tree | 4673104b47dc68a079cac9f94deefd48dfcb66fa /Stars45/NavAI.cpp | |
parent | 1de4b2bdbb019be6f1b7262c3eba5568d7682edd (diff) | |
download | starshatter-d17521c8b9085a91d08fecfd0b51bbbf7b1dccac.zip starshatter-d17521c8b9085a91d08fecfd0b51bbbf7b1dccac.tar.gz starshatter-d17521c8b9085a91d08fecfd0b51bbbf7b1dccac.tar.bz2 |
Updated open source license declaration and fixed some formatting issues.
Diffstat (limited to 'Stars45/NavAI.cpp')
-rw-r--r-- | Stars45/NavAI.cpp | 1268 |
1 files changed, 646 insertions, 622 deletions
diff --git a/Stars45/NavAI.cpp b/Stars45/NavAI.cpp index a6b53cc..6470a41 100644 --- a/Stars45/NavAI.cpp +++ b/Stars45/NavAI.cpp @@ -1,622 +1,646 @@ -/* Project Starshatter 5.0
- Destroyer Studios LLC
- Copyright © 1997-2007. All Rights Reserved.
-
- SUBSYSTEM: Stars.exe
- FILE: NavAI.cpp
- AUTHOR: John DiCamillo
-
-
- OVERVIEW
- ========
- Automatic Navigator Artificial Intelligence class
-*/
-
-#include "MemDebug.h"
-#include "NavAI.h"
-#include "TacticalAI.h"
-#include "Instruction.h"
-#include "NavSystem.h"
-#include "QuantumDrive.h"
-#include "Ship.h"
-#include "ShipDesign.h"
-#include "ShipCtrl.h"
-#include "Drive.h"
-#include "Farcaster.h"
-#include "Shield.h"
-#include "Sim.h"
-#include "StarSystem.h"
-#include "KeyMap.h"
-#include "HUDView.h"
-#include "HUDSounds.h"
-
-#include "Game.h"
-
-// +----------------------------------------------------------------------+
-
-NavAI::NavAI(Ship* s)
-: ShipAI(s), complete(false), brakes(0),
-drop_state(0), quantum_state(0), farcaster(0), terrain_warning(false)
-{
- seek_gain = 20;
- seek_damp = 0.55;
-
- delete tactical;
- tactical = 0;
-}
-
-// +--------------------------------------------------------------------+
-
-NavAI::~NavAI()
-{ }
-
-// +--------------------------------------------------------------------+
-
-void
-NavAI::ExecFrame(double s)
-{
- if (!ship) return;
-
- seconds = s;
-
- ship->SetDirectorInfo(" ");
-
- if (ship->GetFlightPhase() == Ship::TAKEOFF)
- takeoff = true;
-
- else if (takeoff && ship->MissionClock() > 10000)
- takeoff = false;
-
- FindObjective();
- Navigator();
-
- // watch for disconnect:
- if (ShipCtrl::Toggled(KEY_AUTO_NAV)) {
- NavSystem* navsys = ship->GetNavSystem();
- if (navsys) {
- HUDView::GetInstance()->SetHUDMode(HUDView::HUD_MODE_TAC);
- navsys->DisengageAutoNav();
-
- Sim* sim = Sim::GetSim();
- if (sim) {
- ship->SetControls(sim->GetControls());
- return;
- }
- }
- }
-
- static double time_til_change = 0.0;
-
- if (time_til_change < 0.001) {
- if (ship->GetShield()) {
- Shield* shield = ship->GetShield();
- double level = shield->GetPowerLevel();
-
- if (ShipCtrl::KeyDown(KEY_SHIELDS_FULL)) {
- HUDSounds::PlaySound(HUDSounds::SND_SHIELD_LEVEL);
- shield->SetPowerLevel(100);
- time_til_change = 0.5f;
- }
-
- else if (ShipCtrl::KeyDown(KEY_SHIELDS_ZERO)) {
- HUDSounds::PlaySound(HUDSounds::SND_SHIELD_LEVEL);
- shield->SetPowerLevel(0);
- time_til_change = 0.5f;
- }
-
- else if (ShipCtrl::KeyDown(KEY_SHIELDS_UP)) {
- if (level < 25) level = 25;
- else if (level < 50) level = 50;
- else if (level < 75) level = 75;
- else level = 100;
-
- HUDSounds::PlaySound(HUDSounds::SND_SHIELD_LEVEL);
- shield->SetPowerLevel(level);
- time_til_change = 0.5f;
- }
-
- else if (ShipCtrl::KeyDown(KEY_SHIELDS_DOWN)) {
- if (level > 75) level = 75;
- else if (level > 50) level = 50;
- else if (level > 25) level = 25;
- else level = 0;
-
- HUDSounds::PlaySound(HUDSounds::SND_SHIELD_LEVEL);
- shield->SetPowerLevel(level);
- time_til_change = 0.5f;
- }
-
- }
- }
- else {
- time_til_change -= seconds;
- }
-
- if (ShipCtrl::Toggled(KEY_DECOY))
- ship->FireDecoy();
-
- if (ShipCtrl::Toggled(KEY_LAUNCH_PROBE))
- ship->LaunchProbe();
-
- if (ShipCtrl::Toggled(KEY_GEAR_TOGGLE))
- ship->ToggleGear();
-
- if (ShipCtrl::Toggled(KEY_NAVLIGHT_TOGGLE))
- ship->ToggleNavlights();
-
- if (drop_state < 0) {
- ship->DropOrbit();
- return;
- }
-
- if (drop_state > 0) {
- ship->MakeOrbit();
- return;
- }
-}
-
-// +--------------------------------------------------------------------+
-
-void
-NavAI::FindObjective()
-{
- navpt = 0;
- distance = 0;
-
- // runway takeoff:
- if (takeoff) {
- obj_w = ship->Location() + ship->Heading() * 10e3;
- obj_w.y = ship->Location().y + 2e3;
-
- // transform into camera coords:
- objective = Transform(obj_w);
- ship->SetDirectorInfo(Game::GetText("ai.takeoff"));
- return;
- }
-
- // PART I: Find next NavPoint:
- if (ship->GetNavSystem())
- navpt = ship->GetNextNavPoint();
-
- complete = !navpt;
- if (complete) return;
-
- // PART II: Compute Objective from NavPoint:
- Point npt = navpt->Location();
- Sim* sim = Sim::GetSim();
- SimRegion* self_rgn = ship->GetRegion();
- SimRegion* nav_rgn = navpt->Region();
-
- if (self_rgn && !nav_rgn) {
- nav_rgn = self_rgn;
- navpt->SetRegion(nav_rgn);
- }
-
- if (self_rgn == nav_rgn) {
- if (farcaster) {
- if (farcaster->GetShip()->GetRegion() != self_rgn)
- farcaster = farcaster->GetDest()->GetFarcaster();
-
- obj_w = farcaster->EndPoint();
- }
-
- else {
- obj_w = npt.OtherHand();
- }
-
- // distance from self to navpt:
- distance = Point(obj_w - self->Location()).length();
-
- // transform into camera coords:
- objective = Transform(obj_w);
-
- if (!ship->IsStarship())
- objective.Normalize();
-
- if (farcaster && distance < 1000)
- farcaster = 0;
- }
-
- // PART III: Deal with orbital transitions:
- else if (ship->IsDropship()) {
- if (nav_rgn->GetOrbitalRegion()->Primary() ==
- self_rgn->GetOrbitalRegion()->Primary()) {
-
- Point npt = nav_rgn->Location() - self_rgn->Location();
- obj_w = npt.OtherHand();
-
- // distance from self to navpt:
- distance = Point(obj_w - ship->Location()).length();
-
- // transform into camera coords:
- objective = Transform(obj_w);
-
- if (nav_rgn->IsAirSpace()) {
- drop_state = -1;
- }
- else if (nav_rgn->IsOrbital()) {
- drop_state = 1;
- }
- }
-
- // PART IIIa: Deal with farcaster jumps:
- else if (nav_rgn->IsOrbital() && self_rgn->IsOrbital()) {
- ListIter<Ship> s = self_rgn->Ships();
- while (++s && !farcaster) {
- if (s->GetFarcaster()) {
- const Ship* dest = s->GetFarcaster()->GetDest();
- if (dest && dest->GetRegion() == nav_rgn) {
- farcaster = s->GetFarcaster();
- }
- }
- }
-
- if (farcaster) {
- Point apt = farcaster->ApproachPoint(0);
- Point npt = farcaster->StartPoint();
- double r1 = (ship->Location() - npt).length();
-
- if (r1 > 50e3) {
- obj_w = apt;
- distance = r1;
- objective = Transform(obj_w);
- }
-
- else {
- double r2 = (ship->Location() - apt).length();
- double r3 = (npt - apt).length();
-
- if (r1+r2 < 1.2*r3) {
- obj_w = npt;
- distance = r1;
- objective = Transform(obj_w);
- }
- else {
- obj_w = apt;
- distance = r2;
- objective = Transform(obj_w);
- }
- }
- }
- }
- }
-
- // PART IV: Deal with quantum jumps:
- else if (ship->IsStarship()) {
- quantum_state = 1;
-
- Point npt = nav_rgn->Location() + navpt->Location();
- npt -= self_rgn->Location();
- obj_w = npt.OtherHand();
-
- // distance from self to navpt:
- distance = Point(obj_w - ship->Location()).length();
-
- // transform into camera coords:
- objective = Transform(obj_w);
- }
-}
-
-// +--------------------------------------------------------------------+
-
-void
-NavAI::Navigator()
-{
- accumulator.Clear();
- magnitude = 0;
- brakes = 0;
- hold = false;
-
- if (navpt) {
- if (navpt->Status() == Instruction::COMPLETE && navpt->HoldTime() > 0) {
- ship->SetDirectorInfo(Game::GetText("ai.auto-hold"));
- hold = true;
- }
- else {
- ship->SetDirectorInfo(Game::GetText("ai.auto-nav"));
- }
- }
- else {
- ship->SetDirectorInfo(Game::GetText("ai.auto-stop"));
- }
-
- Accumulate(AvoidTerrain());
- Accumulate(AvoidCollision());
-
- if (!hold)
- accumulator = SeekTarget();
-
- HelmControl();
- ThrottleControl();
-}
-
-// +--------------------------------------------------------------------+
-
-void
-NavAI::HelmControl()
-{
- // ----------------------------------------------------------
- // STARSHIP HELM MODE
- // ----------------------------------------------------------
-
- if (ship->IsStarship()) {
- ship->SetFLCSMode(Ship::FLCS_HELM);
- ship->SetHelmHeading(accumulator.yaw);
-
- if (accumulator.pitch > 45*DEGREES)
- ship->SetHelmPitch(45*DEGREES);
-
- else if (accumulator.pitch < -45*DEGREES)
- ship->SetHelmPitch(-45*DEGREES);
-
- else
- ship->SetHelmPitch(accumulator.pitch);
- }
-
- // ----------------------------------------------------------
- // FIGHTER FLCS AUTO MODE
- // ----------------------------------------------------------
-
- else {
- ship->SetFLCSMode(Ship::FLCS_AUTO);
-
- // are we being asked to flee?
- if (fabs(accumulator.yaw) == 1.0 && accumulator.pitch == 0.0) {
- accumulator.pitch = -0.7f;
- accumulator.yaw *= 0.25f;
- }
-
- self->ApplyRoll((float) (accumulator.yaw * -0.4));
- self->ApplyYaw((float) (accumulator.yaw * 0.2));
-
- if (fabs(accumulator.yaw) > 0.5 && fabs(accumulator.pitch) < 0.1)
- accumulator.pitch -= 0.1f;
-
- if (accumulator.pitch != 0)
- self->ApplyPitch((float) accumulator.pitch);
-
- // if not turning, roll to orient with world coords:
- if (fabs(accumulator.yaw) < 0.1) {
- Point vrt = ((Camera*) &(self->Cam()))->vrt();
- double deflection = vrt.y;
- if (deflection != 0) {
- double theta = asin(deflection/vrt.length());
- self->ApplyRoll(-theta);
- }
- }
-
- if (!ship->IsAirborne() || ship->AltitudeAGL() > 100)
- ship->RaiseGear();
- }
-
- ship->SetTransX(0);
- ship->SetTransY(0);
- ship->SetTransZ(0);
- ship->ExecFLCSFrame();
-}
-
-// +--------------------------------------------------------------------+
-
-void
-NavAI::ThrottleControl()
-{
- double ship_speed = ship->Velocity() * ship->Heading();
- bool augmenter = false;
-
- if (hold) {
- throttle = 0;
- brakes = 1;
- }
-
- else if (navpt) {
- double speed = navpt->Speed();
-
- if (speed < 10)
- speed = 250;
-
- throttle = 0;
-
- if (Ship::GetFlightModel() > 0) {
- if (ship_speed > speed + 10)
- throttle = old_throttle - 0.25;
-
- else if (ship_speed < speed - 10)
- throttle = old_throttle + 0.25;
-
- else
- throttle = old_throttle;
- }
-
- else {
- if (ship_speed > speed+5)
- brakes = 0.25;
-
- else if (ship_speed < speed-5)
- throttle = 50;
- }
- }
- else {
- throttle = 0;
- brakes = 0.25;
- }
-
- if (ship->IsAirborne() && ship->Class() < Ship::LCA) {
- if (ship_speed < 250) {
- throttle = 100;
- brakes = 0;
-
- if (ship_speed < 200)
- augmenter = true;
- }
-
- else if (throttle < 20) {
- throttle = 20;
- }
- }
-
- old_throttle = throttle;
- ship->SetThrottle(throttle);
- ship->SetAugmenter(augmenter);
-
- if (ship_speed > 1 && brakes > 0)
- ship->SetTransY(-brakes * ship->Design()->trans_y);
-}
-
-// +--------------------------------------------------------------------+
-
-Steer
-NavAI::SeekTarget()
-{
- if (!ship)
- return Steer();
-
- if (takeoff)
- return Seek(objective);
-
- if (navpt) {
- if (quantum_state == 1) {
- QuantumDrive* q = ship->GetQuantumDrive();
-
- if (q) {
- if (q->ActiveState() == QuantumDrive::ACTIVE_READY) {
- q->SetDestination(navpt->Region(), navpt->Location());
- q->Engage();
- }
-
- else if (q->ActiveState() == QuantumDrive::ACTIVE_POSTWARP) {
- quantum_state = 0;
- }
- }
- }
-
- if (distance < 2 * self->Radius()) {
- ship->SetNavptStatus(navpt, Instruction::COMPLETE);
-
- return Steer();
- }
- else {
- return Seek(objective);
- }
- }
-
- return Steer();
-}
-
-// +--------------------------------------------------------------------+
-
-void
-NavAI::Disengage()
-{
- throttle = 0;
-}
-
-// +--------------------------------------------------------------------+
-
-Point
-NavAI::Transform(const Point& point)
-{
- if (ship && ship->IsStarship())
- return point - self->Location();
-
- return SteerAI::Transform(point);
-}
-
-Steer
-NavAI::Seek(const Point& point)
-{
- // if ship is starship, the point is in relative world coordinates
- // x: distance east(-) / west(+)
- // y: altitude down(-) / up(+)
- // z: distance north(-) / south(+)
-
- if (ship && ship->IsStarship()) {
- Steer result;
-
- result.yaw = atan2(point.x, point.z) + PI;
-
- double adjacent = sqrt(point.x * point.x + point.z * point.z);
- if (fabs(point.y) > ship->Radius() && adjacent > ship->Radius())
- result.pitch = atan(point.y / adjacent);
-
- if (_isnan(result.yaw))
- result.yaw = 0;
-
- if (_isnan(result.pitch))
- result.pitch = 0;
-
- return result;
- }
-
- return SteerAI::Seek(point);
-}
-
-Steer
-NavAI::Flee(const Point& point)
-{
- if (ship && ship->IsStarship()) {
- Steer result = Seek(point);
- result.yaw += PI;
- result.pitch *= -1;
- return result;
- }
-
- return SteerAI::Flee(point);
-}
-
-Steer
-NavAI::Avoid(const Point& point, float radius)
-{
- if (ship && ship->IsStarship()) {
- Steer result = Seek(point);
-
- if (point * ship->BeamLine() > 0)
- result.yaw -= PI/2;
- else
- result.yaw += PI/2;
-
- return result;
- }
-
- return SteerAI::Avoid(point, radius);
-}
-
-// +--------------------------------------------------------------------+
-
-Steer
-NavAI::AvoidTerrain()
-{
- Steer avoid;
-
- terrain_warning = false;
-
- if (!ship || !ship->GetRegion() || !ship->GetRegion()->IsActive() ||
- takeoff || (navpt && navpt->Action() == Instruction::LAUNCH))
- return avoid;
-
- if (ship->IsAirborne() && ship->GetFlightPhase() == Ship::ACTIVE) {
- // too low?
- if (ship->AltitudeAGL() < 1000) {
- terrain_warning = true;
- ship->SetDirectorInfo(Game::GetText("ai.too-low"));
-
- // way too low?
- if (ship->AltitudeAGL() < 750) {
- ship->SetDirectorInfo(Game::GetText("ai.way-too-low"));
- }
-
- // where will we be?
- Point selfpt = ship->Location() + ship->Velocity() + Point(0, 10e3, 0);
-
- // transform into camera coords:
- Point obj = Transform(selfpt);
-
- // pull up!
- avoid = Seek(obj);
- }
- }
-
- return avoid;
-}
-
-
-
+/* Starshatter OpenSource Distribution + Copyright (c) 1997-2004, Destroyer Studios LLC. + All Rights Reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + * Neither the name "Destroyer Studios" nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + SUBSYSTEM: Stars.exe + FILE: NavAI.cpp + AUTHOR: John DiCamillo + + + OVERVIEW + ======== + Automatic Navigator Artificial Intelligence class +*/ + +#include "MemDebug.h" +#include "NavAI.h" +#include "TacticalAI.h" +#include "Instruction.h" +#include "NavSystem.h" +#include "QuantumDrive.h" +#include "Ship.h" +#include "ShipDesign.h" +#include "ShipCtrl.h" +#include "Drive.h" +#include "Farcaster.h" +#include "Shield.h" +#include "Sim.h" +#include "StarSystem.h" +#include "KeyMap.h" +#include "HUDView.h" +#include "HUDSounds.h" + +#include "Game.h" + +// +----------------------------------------------------------------------+ + +NavAI::NavAI(Ship* s) +: ShipAI(s), complete(false), brakes(0), +drop_state(0), quantum_state(0), farcaster(0), terrain_warning(false) +{ + seek_gain = 20; + seek_damp = 0.55; + + delete tactical; + tactical = 0; +} + +// +--------------------------------------------------------------------+ + +NavAI::~NavAI() +{ } + +// +--------------------------------------------------------------------+ + +void +NavAI::ExecFrame(double s) +{ + if (!ship) return; + + seconds = s; + + ship->SetDirectorInfo(" "); + + if (ship->GetFlightPhase() == Ship::TAKEOFF) + takeoff = true; + + else if (takeoff && ship->MissionClock() > 10000) + takeoff = false; + + FindObjective(); + Navigator(); + + // watch for disconnect: + if (ShipCtrl::Toggled(KEY_AUTO_NAV)) { + NavSystem* navsys = ship->GetNavSystem(); + if (navsys) { + HUDView::GetInstance()->SetHUDMode(HUDView::HUD_MODE_TAC); + navsys->DisengageAutoNav(); + + Sim* sim = Sim::GetSim(); + if (sim) { + ship->SetControls(sim->GetControls()); + return; + } + } + } + + static double time_til_change = 0.0; + + if (time_til_change < 0.001) { + if (ship->GetShield()) { + Shield* shield = ship->GetShield(); + double level = shield->GetPowerLevel(); + + if (ShipCtrl::KeyDown(KEY_SHIELDS_FULL)) { + HUDSounds::PlaySound(HUDSounds::SND_SHIELD_LEVEL); + shield->SetPowerLevel(100); + time_til_change = 0.5f; + } + + else if (ShipCtrl::KeyDown(KEY_SHIELDS_ZERO)) { + HUDSounds::PlaySound(HUDSounds::SND_SHIELD_LEVEL); + shield->SetPowerLevel(0); + time_til_change = 0.5f; + } + + else if (ShipCtrl::KeyDown(KEY_SHIELDS_UP)) { + if (level < 25) level = 25; + else if (level < 50) level = 50; + else if (level < 75) level = 75; + else level = 100; + + HUDSounds::PlaySound(HUDSounds::SND_SHIELD_LEVEL); + shield->SetPowerLevel(level); + time_til_change = 0.5f; + } + + else if (ShipCtrl::KeyDown(KEY_SHIELDS_DOWN)) { + if (level > 75) level = 75; + else if (level > 50) level = 50; + else if (level > 25) level = 25; + else level = 0; + + HUDSounds::PlaySound(HUDSounds::SND_SHIELD_LEVEL); + shield->SetPowerLevel(level); + time_til_change = 0.5f; + } + + } + } + else { + time_til_change -= seconds; + } + + if (ShipCtrl::Toggled(KEY_DECOY)) + ship->FireDecoy(); + + if (ShipCtrl::Toggled(KEY_LAUNCH_PROBE)) + ship->LaunchProbe(); + + if (ShipCtrl::Toggled(KEY_GEAR_TOGGLE)) + ship->ToggleGear(); + + if (ShipCtrl::Toggled(KEY_NAVLIGHT_TOGGLE)) + ship->ToggleNavlights(); + + if (drop_state < 0) { + ship->DropOrbit(); + return; + } + + if (drop_state > 0) { + ship->MakeOrbit(); + return; + } +} + +// +--------------------------------------------------------------------+ + +void +NavAI::FindObjective() +{ + navpt = 0; + distance = 0; + + // runway takeoff: + if (takeoff) { + obj_w = ship->Location() + ship->Heading() * 10e3; + obj_w.y = ship->Location().y + 2e3; + + // transform into camera coords: + objective = Transform(obj_w); + ship->SetDirectorInfo(Game::GetText("ai.takeoff")); + return; + } + + // PART I: Find next NavPoint: + if (ship->GetNavSystem()) + navpt = ship->GetNextNavPoint(); + + complete = !navpt; + if (complete) return; + + // PART II: Compute Objective from NavPoint: + Point npt = navpt->Location(); + Sim* sim = Sim::GetSim(); + SimRegion* self_rgn = ship->GetRegion(); + SimRegion* nav_rgn = navpt->Region(); + + if (self_rgn && !nav_rgn) { + nav_rgn = self_rgn; + navpt->SetRegion(nav_rgn); + } + + if (self_rgn == nav_rgn) { + if (farcaster) { + if (farcaster->GetShip()->GetRegion() != self_rgn) + farcaster = farcaster->GetDest()->GetFarcaster(); + + obj_w = farcaster->EndPoint(); + } + + else { + obj_w = npt.OtherHand(); + } + + // distance from self to navpt: + distance = Point(obj_w - self->Location()).length(); + + // transform into camera coords: + objective = Transform(obj_w); + + if (!ship->IsStarship()) + objective.Normalize(); + + if (farcaster && distance < 1000) + farcaster = 0; + } + + // PART III: Deal with orbital transitions: + else if (ship->IsDropship()) { + if (nav_rgn->GetOrbitalRegion()->Primary() == + self_rgn->GetOrbitalRegion()->Primary()) { + + Point npt = nav_rgn->Location() - self_rgn->Location(); + obj_w = npt.OtherHand(); + + // distance from self to navpt: + distance = Point(obj_w - ship->Location()).length(); + + // transform into camera coords: + objective = Transform(obj_w); + + if (nav_rgn->IsAirSpace()) { + drop_state = -1; + } + else if (nav_rgn->IsOrbital()) { + drop_state = 1; + } + } + + // PART IIIa: Deal with farcaster jumps: + else if (nav_rgn->IsOrbital() && self_rgn->IsOrbital()) { + ListIter<Ship> s = self_rgn->Ships(); + while (++s && !farcaster) { + if (s->GetFarcaster()) { + const Ship* dest = s->GetFarcaster()->GetDest(); + if (dest && dest->GetRegion() == nav_rgn) { + farcaster = s->GetFarcaster(); + } + } + } + + if (farcaster) { + Point apt = farcaster->ApproachPoint(0); + Point npt = farcaster->StartPoint(); + double r1 = (ship->Location() - npt).length(); + + if (r1 > 50e3) { + obj_w = apt; + distance = r1; + objective = Transform(obj_w); + } + + else { + double r2 = (ship->Location() - apt).length(); + double r3 = (npt - apt).length(); + + if (r1+r2 < 1.2*r3) { + obj_w = npt; + distance = r1; + objective = Transform(obj_w); + } + else { + obj_w = apt; + distance = r2; + objective = Transform(obj_w); + } + } + } + } + } + + // PART IV: Deal with quantum jumps: + else if (ship->IsStarship()) { + quantum_state = 1; + + Point npt = nav_rgn->Location() + navpt->Location(); + npt -= self_rgn->Location(); + obj_w = npt.OtherHand(); + + // distance from self to navpt: + distance = Point(obj_w - ship->Location()).length(); + + // transform into camera coords: + objective = Transform(obj_w); + } +} + +// +--------------------------------------------------------------------+ + +void +NavAI::Navigator() +{ + accumulator.Clear(); + magnitude = 0; + brakes = 0; + hold = false; + + if (navpt) { + if (navpt->Status() == Instruction::COMPLETE && navpt->HoldTime() > 0) { + ship->SetDirectorInfo(Game::GetText("ai.auto-hold")); + hold = true; + } + else { + ship->SetDirectorInfo(Game::GetText("ai.auto-nav")); + } + } + else { + ship->SetDirectorInfo(Game::GetText("ai.auto-stop")); + } + + Accumulate(AvoidTerrain()); + Accumulate(AvoidCollision()); + + if (!hold) + accumulator = SeekTarget(); + + HelmControl(); + ThrottleControl(); +} + +// +--------------------------------------------------------------------+ + +void +NavAI::HelmControl() +{ + // ---------------------------------------------------------- + // STARSHIP HELM MODE + // ---------------------------------------------------------- + + if (ship->IsStarship()) { + ship->SetFLCSMode(Ship::FLCS_HELM); + ship->SetHelmHeading(accumulator.yaw); + + if (accumulator.pitch > 45*DEGREES) + ship->SetHelmPitch(45*DEGREES); + + else if (accumulator.pitch < -45*DEGREES) + ship->SetHelmPitch(-45*DEGREES); + + else + ship->SetHelmPitch(accumulator.pitch); + } + + // ---------------------------------------------------------- + // FIGHTER FLCS AUTO MODE + // ---------------------------------------------------------- + + else { + ship->SetFLCSMode(Ship::FLCS_AUTO); + + // are we being asked to flee? + if (fabs(accumulator.yaw) == 1.0 && accumulator.pitch == 0.0) { + accumulator.pitch = -0.7f; + accumulator.yaw *= 0.25f; + } + + self->ApplyRoll((float) (accumulator.yaw * -0.4)); + self->ApplyYaw((float) (accumulator.yaw * 0.2)); + + if (fabs(accumulator.yaw) > 0.5 && fabs(accumulator.pitch) < 0.1) + accumulator.pitch -= 0.1f; + + if (accumulator.pitch != 0) + self->ApplyPitch((float) accumulator.pitch); + + // if not turning, roll to orient with world coords: + if (fabs(accumulator.yaw) < 0.1) { + Point vrt = ((Camera*) &(self->Cam()))->vrt(); + double deflection = vrt.y; + if (deflection != 0) { + double theta = asin(deflection/vrt.length()); + self->ApplyRoll(-theta); + } + } + + if (!ship->IsAirborne() || ship->AltitudeAGL() > 100) + ship->RaiseGear(); + } + + ship->SetTransX(0); + ship->SetTransY(0); + ship->SetTransZ(0); + ship->ExecFLCSFrame(); +} + +// +--------------------------------------------------------------------+ + +void +NavAI::ThrottleControl() +{ + double ship_speed = ship->Velocity() * ship->Heading(); + bool augmenter = false; + + if (hold) { + throttle = 0; + brakes = 1; + } + + else if (navpt) { + double speed = navpt->Speed(); + + if (speed < 10) + speed = 250; + + throttle = 0; + + if (Ship::GetFlightModel() > 0) { + if (ship_speed > speed + 10) + throttle = old_throttle - 0.25; + + else if (ship_speed < speed - 10) + throttle = old_throttle + 0.25; + + else + throttle = old_throttle; + } + + else { + if (ship_speed > speed+5) + brakes = 0.25; + + else if (ship_speed < speed-5) + throttle = 50; + } + } + else { + throttle = 0; + brakes = 0.25; + } + + if (ship->IsAirborne() && ship->Class() < Ship::LCA) { + if (ship_speed < 250) { + throttle = 100; + brakes = 0; + + if (ship_speed < 200) + augmenter = true; + } + + else if (throttle < 20) { + throttle = 20; + } + } + + old_throttle = throttle; + ship->SetThrottle(throttle); + ship->SetAugmenter(augmenter); + + if (ship_speed > 1 && brakes > 0) + ship->SetTransY(-brakes * ship->Design()->trans_y); +} + +// +--------------------------------------------------------------------+ + +Steer +NavAI::SeekTarget() +{ + if (!ship) + return Steer(); + + if (takeoff) + return Seek(objective); + + if (navpt) { + if (quantum_state == 1) { + QuantumDrive* q = ship->GetQuantumDrive(); + + if (q) { + if (q->ActiveState() == QuantumDrive::ACTIVE_READY) { + q->SetDestination(navpt->Region(), navpt->Location()); + q->Engage(); + } + + else if (q->ActiveState() == QuantumDrive::ACTIVE_POSTWARP) { + quantum_state = 0; + } + } + } + + if (distance < 2 * self->Radius()) { + ship->SetNavptStatus(navpt, Instruction::COMPLETE); + + return Steer(); + } + else { + return Seek(objective); + } + } + + return Steer(); +} + +// +--------------------------------------------------------------------+ + +void +NavAI::Disengage() +{ + throttle = 0; +} + +// +--------------------------------------------------------------------+ + +Point +NavAI::Transform(const Point& point) +{ + if (ship && ship->IsStarship()) + return point - self->Location(); + + return SteerAI::Transform(point); +} + +Steer +NavAI::Seek(const Point& point) +{ + // if ship is starship, the point is in relative world coordinates + // x: distance east(-) / west(+) + // y: altitude down(-) / up(+) + // z: distance north(-) / south(+) + + if (ship && ship->IsStarship()) { + Steer result; + + result.yaw = atan2(point.x, point.z) + PI; + + double adjacent = sqrt(point.x * point.x + point.z * point.z); + if (fabs(point.y) > ship->Radius() && adjacent > ship->Radius()) + result.pitch = atan(point.y / adjacent); + + if (_isnan(result.yaw)) + result.yaw = 0; + + if (_isnan(result.pitch)) + result.pitch = 0; + + return result; + } + + return SteerAI::Seek(point); +} + +Steer +NavAI::Flee(const Point& point) +{ + if (ship && ship->IsStarship()) { + Steer result = Seek(point); + result.yaw += PI; + result.pitch *= -1; + return result; + } + + return SteerAI::Flee(point); +} + +Steer +NavAI::Avoid(const Point& point, float radius) +{ + if (ship && ship->IsStarship()) { + Steer result = Seek(point); + + if (point * ship->BeamLine() > 0) + result.yaw -= PI/2; + else + result.yaw += PI/2; + + return result; + } + + return SteerAI::Avoid(point, radius); +} + +// +--------------------------------------------------------------------+ + +Steer +NavAI::AvoidTerrain() +{ + Steer avoid; + + terrain_warning = false; + + if (!ship || !ship->GetRegion() || !ship->GetRegion()->IsActive() || + takeoff || (navpt && navpt->Action() == Instruction::LAUNCH)) + return avoid; + + if (ship->IsAirborne() && ship->GetFlightPhase() == Ship::ACTIVE) { + // too low? + if (ship->AltitudeAGL() < 1000) { + terrain_warning = true; + ship->SetDirectorInfo(Game::GetText("ai.too-low")); + + // way too low? + if (ship->AltitudeAGL() < 750) { + ship->SetDirectorInfo(Game::GetText("ai.way-too-low")); + } + + // where will we be? + Point selfpt = ship->Location() + ship->Velocity() + Point(0, 10e3, 0); + + // transform into camera coords: + Point obj = Transform(selfpt); + + // pull up! + avoid = Seek(obj); + } + } + + return avoid; +} + + + |