1 // Copyright © 2008-2021 Pioneer Developers. See AUTHORS.txt for details
2 // Licensed under the terms of the GPL v3. See licenses/GPL-3.txt
3 
4 #include "EnumStrings.h"
5 #include "Frame.h"
6 #include "Pi.h"
7 #include "Planet.h"
8 #include "Player.h"
9 #include "Ship.h"
10 #include "ShipAICmd.h"
11 #include "Space.h"
12 #include "SpaceStation.h"
13 #include "libs.h"
14 #include "lua/LuaConstants.h"
15 #include "lua/LuaEvent.h"
16 #include "perlin.h"
17 #include "ship/Propulsion.h"
18 
19 // returns true if command is complete
AITimeStep(float timeStep)20 bool Ship::AITimeStep(float timeStep)
21 {
22 	PROFILE_SCOPED()
23 	// allow the launch thruster thing to happen
24 	if (m_launchLockTimeout > 0.0) return false;
25 
26 	m_decelerating = false;
27 	if (!m_curAICmd) {
28 		if (this == Pi::player) return true;
29 
30 		// just in case the AI left it on
31 		ClearThrusterState();
32 		for (int i = 0; i < Guns::GUNMOUNT_MAX; i++)
33 			SetGunState(i, 0);
34 		return true;
35 	}
36 
37 	if (m_curAICmd->TimeStepUpdate()) {
38 		AIClearInstructions();
39 		//		ClearThrusterState();		// otherwise it does one timestep at 10k and gravity is fatal
40 		LuaEvent::Queue("onAICompleted", this, EnumStrings::GetString("ShipAIError", AIMessage()));
41 		return true;
42 	} else
43 		return false;
44 }
45 
AIClearInstructions()46 void Ship::AIClearInstructions()
47 {
48 	if (!m_curAICmd) return;
49 
50 	delete m_curAICmd; // rely on destructor to kill children
51 	m_curAICmd = 0;
52 	m_decelerating = false; // don't adjust unless AI is running
53 }
54 
AIGetStatusText(char * str)55 void Ship::AIGetStatusText(char *str)
56 {
57 	if (!m_curAICmd)
58 		strcpy(str, "AI inactive");
59 	else
60 		m_curAICmd->GetStatusText(str);
61 }
62 
AIKamikaze(Body * target)63 void Ship::AIKamikaze(Body *target)
64 {
65 	AIClearInstructions();
66 	m_curAICmd = new AICmdKamikaze(this, target);
67 }
68 
AIKill(Ship * target)69 void Ship::AIKill(Ship *target)
70 {
71 	AIClearInstructions();
72 	SetFuelReserve((GetFuel() < 0.5) ? GetFuel() / 2 : 0.25);
73 
74 	m_curAICmd = new AICmdKill(this, target);
75 }
76 
77 /*
78 void Ship::AIJourney(SystemBodyPath &dest)
79 {
80 	AIClearInstructions();
81 //	m_curAICmd = new AICmdJourney(this, dest);
82 }
83 */
84 
AIFlyTo(Body * target)85 void Ship::AIFlyTo(Body *target)
86 {
87 	AIClearInstructions();
88 	SetFuelReserve((GetFuel() < 0.5) ? GetFuel() / 2 : 0.25);
89 
90 	if (target->IsType(ObjectType::SHIP)) { // test code
91 		vector3d posoff(-1000.0, 0.0, 1000.0);
92 		m_curAICmd = new AICmdFormation(this, static_cast<Ship *>(target), posoff);
93 	} else
94 		m_curAICmd = new AICmdFlyTo(this, target);
95 }
96 
AIDock(SpaceStation * target)97 void Ship::AIDock(SpaceStation *target)
98 {
99 	AIClearInstructions();
100 	SetFuelReserve((GetFuel() < 0.5) ? GetFuel() / 2 : 0.25);
101 
102 	m_curAICmd = new AICmdDock(this, target);
103 }
104 
AIOrbit(Body * target,double alt)105 void Ship::AIOrbit(Body *target, double alt)
106 {
107 	AIClearInstructions();
108 	SetFuelReserve((GetFuel() < 0.5) ? GetFuel() / 2 : 0.25);
109 
110 	m_curAICmd = new AICmdFlyAround(this, target, alt);
111 }
112 
AIHoldPosition()113 void Ship::AIHoldPosition()
114 {
115 	AIClearInstructions();
116 	m_curAICmd = new AICmdHoldPosition(this);
117 }
118