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 #ifndef _SHIP_H
5 #define _SHIP_H
6 
7 #include <unordered_map>
8 
9 #include "DynamicBody.h"
10 #include "ShipType.h"
11 #include "galaxy/SystemPath.h"
12 #include "lua/LuaRef.h"
13 #include "scenegraph/ModelSkin.h"
14 #include "sound/Sound.h"
15 
16 #include "FixedGuns.h"
17 #include "ship/Propulsion.h"
18 
19 class AICommand;
20 class Camera;
21 class CargoBody;
22 class SpaceStation;
23 class HyperspaceCloud;
24 class Missile;
25 class NavLights;
26 class Planet;
27 class Sensors;
28 class ShipController;
29 class Space;
30 
31 struct CollisionContact;
32 struct HeatGradientParameters_t;
33 
34 namespace Graphics {
35 	class Renderer;
36 }
37 
38 struct shipstats_t {
39 	int used_capacity;
40 	int used_cargo;
41 	int free_capacity;
42 	int static_mass;	  // cargo, equipment + hull
43 	float hull_mass_left; // effectively hitpoints
44 	float hyperspace_range;
45 	float hyperspace_range_max;
46 	float shield_mass;
47 	float shield_mass_left;
48 	float fuel_tank_mass_left;
49 
50 	// cached equipment information to avoid costly Lua lookups
51 	int atmo_shield_cap;
52 	int radar_cap;
53 	int fuel_scoop_cap;
54 	int cargo_bay_life_support_cap;
55 	int hull_autorepair_cap;
56 };
57 
58 struct HyperdriveSoundsTable {
59 	std::string jump_sound;
60 	std::string warmup_sound;
61 	std::string abort_sound;
62 };
63 
64 class Ship : public DynamicBody {
65 	friend class ShipController; //only controllers need access to AITimeStep
66 	friend class PlayerShipController;
67 
68 public:
69 	OBJDEF(Ship, DynamicBody, SHIP);
70 	Ship() = delete;
71 	Ship(const Json &jsonObj, Space *space);
72 	Ship(const ShipType::Id &shipId);
73 	virtual ~Ship();
74 
75 	virtual void SetFrame(FrameId fId) override;
76 
77 	void SetController(ShipController *c); //deletes existing
GetController()78 	ShipController *GetController() const { return m_controller; }
79 
80 	virtual void SetDockedWith(SpaceStation *, int port);
81 	/** Use GetDockedWith() to determine if docked */
GetDockedWith()82 	SpaceStation *GetDockedWith() const { return m_dockedWith; }
GetDockingPort()83 	int GetDockingPort() const { return m_dockedWithPort; }
IsDocked()84 	bool IsDocked() const { return GetFlightState() == Ship::DOCKED; }
IsLanded()85 	bool IsLanded() const { return GetFlightState() == Ship::LANDED; }
86 
87 	virtual void SetLandedOn(Planet *p, float latitude, float longitude);
88 
89 	virtual void Render(Graphics::Renderer *r, const Camera *camera, const vector3d &viewCoords, const matrix4x4d &viewTransform) override;
90 
ClearThrusterState()91 	inline void ClearThrusterState()
92 	{
93 		ClearAngThrusterState();
94 		if (m_launchLockTimeout <= 0.0f) ClearLinThrusterState();
95 	}
96 	void UpdateLuaStats();
97 	void UpdateEquipStats();
98 	void UpdateFuelStats();
99 	void UpdateGunsStats();
GetStats()100 	const shipstats_t &GetStats() const { return m_stats; }
101 
102 	void Explode();
103 	virtual bool DoDamage(float kgDamage); // can be overloaded in Player to add audio
104 	void SetGunState(int idx, int state);
GetGunTemperature(int idx)105 	float GetGunTemperature(int idx) const { return GetFixedGuns()->GetGunTemperature(idx); }
106 	void UpdateMass();
107 	virtual bool SetWheelState(bool down); // returns success of state change, NOT state itself
108 	void Blastoff();
109 	bool Undock();
110 	virtual void TimeStepUpdate(const float timeStep) override;
111 	virtual void StaticUpdate(const float timeStep) override;
112 
113 	void TimeAccelAdjust(const float timeStep);
114 
IsDecelerating()115 	bool IsDecelerating() const { return m_decelerating; }
116 
117 	virtual void NotifyRemoved(const Body *const removedBody) override;
118 	virtual bool OnCollision(Body *o, Uint32 flags, double relVel) override;
119 	virtual bool OnDamage(Body *attacker, float kgDamage, const CollisionContact &contactData) override;
120 
121 	enum FlightState { // <enum scope='Ship' name=ShipFlightState public>
122 		FLYING,		   // open flight (includes autopilot)
123 		DOCKING,	   // in docking animation
124 		UNDOCKING,	   // in docking animation
125 		DOCKED,		   // docked with station
126 		LANDED,		   // rough landed (not docked)
127 		JUMPING,	   // between space and hyperspace ;)
128 		HYPERSPACE,	   // in hyperspace
129 	};
130 
131 	// vector3d CalcAtmoPassiveControl() const;
132 	vector3d CalcAtmoTorque() const;
133 
GetFlightState()134 	FlightState GetFlightState() const { return m_flightState; }
135 	void SetFlightState(FlightState s);
GetWheelState()136 	float GetWheelState() const { return m_wheelState; }
GetWheelTransition()137 	int GetWheelTransition() const { return m_wheelTransition; }
138 	bool SpawnCargo(CargoBody *c_body) const;
139 
GetEquipSet()140 	LuaRef GetEquipSet() const { return m_equipSet; }
141 
IsInSpace()142 	virtual bool IsInSpace() const override { return (m_flightState != HYPERSPACE); }
143 
SetHyperspaceDest(const SystemPath & dest)144 	void SetHyperspaceDest(const SystemPath &dest) { m_hyperspace.dest = dest; }
GetHyperspaceDest()145 	const SystemPath &GetHyperspaceDest() const { return m_hyperspace.dest; }
GetHyperspaceDuration()146 	double GetHyperspaceDuration() const { return m_hyperspace.duration; }
GetECMRechargeRemain()147 	double GetECMRechargeRemain() const { return m_ecmRecharge; }
148 
149 	enum HyperjumpStatus { // <enum scope='Ship' name=ShipJumpStatus prefix=HYPERJUMP_ public>
150 		HYPERJUMP_OK,
151 		HYPERJUMP_CURRENT_SYSTEM,
152 		HYPERJUMP_NO_DRIVE,
153 		HYPERJUMP_INITIATED,
154 		HYPERJUMP_DRIVE_ACTIVE,
155 		HYPERJUMP_OUT_OF_RANGE,
156 		HYPERJUMP_INSUFFICIENT_FUEL,
157 		HYPERJUMP_SAFETY_LOCKOUT
158 	};
159 
160 	Ship::HyperjumpStatus CheckHyperjumpCapability() const;
161 	virtual Ship::HyperjumpStatus InitiateHyperjumpTo(const SystemPath &dest, int warmup_time, double duration, const HyperdriveSoundsTable &sounds, LuaRef checks);
162 	virtual void AbortHyperjump();
GetHyperspaceCountdown()163 	float GetHyperspaceCountdown() const { return m_hyperspace.countdown; }
IsHyperspaceActive()164 	bool IsHyperspaceActive() const { return (m_hyperspace.countdown > 0.0); }
165 
166 	// 0 to 1.0 is alive, > 1.0 = death
167 	double GetHullTemperature() const;
168 
169 	enum ECMResult {
170 		ECM_NOT_INSTALLED,
171 		ECM_ACTIVATED,
172 		ECM_RECHARGING,
173 	};
174 
175 	ECMResult UseECM();
176 
177 	virtual Missile *SpawnMissile(ShipType::Id missile_type, int power = -1);
178 
179 	enum AlertState { // <enum scope='Ship' name=ShipAlertStatus prefix=ALERT_ public>
180 		ALERT_NONE,
181 		ALERT_SHIP_NEARBY,
182 		ALERT_SHIP_FIRING,
183 		ALERT_MISSILE_DETECTED,
184 	};
GetAlertState()185 	AlertState GetAlertState() { return m_alertState; }
186 
187 	void AIClearInstructions(); // Note: defined in Ship-AI.cpp
AIIsActive()188 	bool AIIsActive() { return m_curAICmd ? true : false; }
189 	void AIGetStatusText(char *str); // Note: defined in Ship-AI.cpp
190 
191 	void AIKamikaze(Body *target); // Note: defined in Ship-AI.cpp
192 	void AIKill(Ship *target);	   // Note: defined in Ship-AI.cpp
193 	//void AIJourney(SystemBodyPath &dest);
194 	void AIDock(SpaceStation *target);		// Note: defined in Ship-AI.cpp
195 	void AIFlyTo(Body *target);				// Note: defined in Ship-AI.cpp
196 	void AIOrbit(Body *target, double alt); // Note: defined in Ship-AI.cpp
197 	void AIHoldPosition();					// Note: defined in Ship-AI.cpp
198 
AIBodyDeleted(const Body * const body)199 	void AIBodyDeleted(const Body *const body){}; // Note: defined in Ship-AI.cpp // todo: signals
200 
GetAICommand()201 	const AICommand *GetAICommand() const { return m_curAICmd; }
202 
203 	virtual void PostLoadFixup(Space *space) override;
204 
GetShipType()205 	const ShipType *GetShipType() const { return m_type; }
206 	virtual void SetShipType(const ShipType::Id &shipId);
207 
GetSkin()208 	const SceneGraph::ModelSkin &GetSkin() const { return m_skin; }
209 	void SetSkin(const SceneGraph::ModelSkin &skin);
210 
211 	void SetPattern(unsigned int num);
212 
213 	void SetLabel(const std::string &label) override;
214 	void SetShipName(const std::string &shipName);
215 
216 	float GetAtmosphericPressureLimit() const;
217 	float GetPercentShields() const;
218 	float GetPercentHull() const;
219 	void SetPercentHull(float);
220 
221 	void EnterSystem();
222 
GetHyperspaceCloud()223 	HyperspaceCloud *GetHyperspaceCloud() const { return m_hyperspaceCloud; }
224 
225 	sigc::signal<void> onDock; // JJ: check what these are for
226 	sigc::signal<void> onUndock;
227 	sigc::signal<void> onLanded;
228 
229 	// mutable because asking to know when state changes is not the same as
230 	// actually changing state
231 	mutable sigc::signal<void> onFlavourChanged;
232 
IsInvulnerable()233 	bool IsInvulnerable() const { return m_invulnerable; }
SetInvulnerable(bool b)234 	void SetInvulnerable(bool b) { m_invulnerable = b; }
235 
GetSensors()236 	Sensors *GetSensors() const { return m_sensors.get(); }
237 
238 	Uint8 GetRelations(Body *other) const; //0=hostile, 50=neutral, 100=ally
239 	void SetRelations(Body *other, Uint8 percent);
240 
GetLandingPosOffset()241 	double GetLandingPosOffset() const { return m_landingMinOffset; }
242 
243 protected:
244 	vector3d CalcAtmosphericForce() const override;
245 
246 	virtual void SaveToJson(Json &jsonObj, Space *space) override;
247 
248 	bool AITimeStep(float timeStep); // Called by controller. Returns true if complete
249 
250 	virtual void SetAlertState(AlertState as);
251 
252 	virtual void OnEnterHyperspace();
253 	virtual void OnEnterSystem();
254 
255 	SpaceStation *m_dockedWith;
256 	int m_dockedWithPort;
257 
258 	float m_ecmRecharge;
259 
260 	ShipController *m_controller;
261 
262 	struct HyperspacingOut {
263 		SystemPath dest;
264 		// > 0 means active
265 		float countdown;
266 		bool now;
267 		double duration;
268 		LuaRef checks; // A Lua function to check all the conditions before the jump
269 		HyperdriveSoundsTable sounds;
270 	} m_hyperspace;
271 
272 	LuaRef m_equipSet;
273 
274 private:
275 	float GetECMRechargeTime();
276 	void DoThrusterSounds() const;
277 	void Init();
278 	void TestLanded();
279 	void UpdateAlertState();
280 	void UpdateFuel(float timeStep);
281 	void SetShipId(const ShipType::Id &shipId);
282 	void EnterHyperspace();
283 	void InitMaterials();
284 	void InitEquipSet();
285 
286 	bool m_invulnerable;
287 
288 	static const double DEFAULT_LIFT_TO_DRAG_RATIO;
289 
290 	static const float DEFAULT_SHIELD_COOLDOWN_TIME;
291 	float m_shieldCooldown;
292 	shipstats_t m_stats;
293 	const ShipType *m_type;
294 	SceneGraph::ModelSkin m_skin;
295 
296 	Sound::Event m_beamLaser[2];
297 
298 	FlightState m_flightState;
299 	bool m_testLanded;
300 	bool m_forceWheelUpdate;
301 	float m_launchLockTimeout;
302 	float m_wheelState;
303 	int m_wheelTransition;
304 
305 	AlertState m_alertState;
306 	double m_lastAlertUpdate;
307 	double m_lastFiringAlert;
308 	bool m_shipNear;
309 	bool m_shipFiring;
310 	bool m_missileDetected;
311 
312 	HyperspaceCloud *m_hyperspaceCloud;
313 
314 	AICommand *m_curAICmd;
315 
316 	double m_landingMinOffset; // offset from the centre of the ship used during docking
317 
318 	int m_dockedWithIndex; // deserialisation
319 
320 	SceneGraph::Animation *m_landingGearAnimation;
321 	std::unique_ptr<NavLights> m_navLights;
322 
323 	static HeatGradientParameters_t s_heatGradientParams;
324 
325 	std::unique_ptr<Sensors> m_sensors;
326 	std::unordered_map<Body *, Uint8> m_relationsMap;
327 
328 	std::string m_shipName;
329 
330 public:
ClearAngThrusterState()331 	void ClearAngThrusterState() { GetPropulsion()->ClearAngThrusterState(); }
ClearLinThrusterState()332 	void ClearLinThrusterState() { GetPropulsion()->ClearLinThrusterState(); }
GetAccelFwd()333 	double GetAccelFwd() { return GetPropulsion()->GetAccelFwd(); }
SetAngThrusterState(const vector3d & levels)334 	void SetAngThrusterState(const vector3d &levels) { GetPropulsion()->SetAngThrusterState(levels); }
GetFuel()335 	double GetFuel() const { return GetPropulsion()->GetFuel(); }
GetAccel(Thruster thruster)336 	double GetAccel(Thruster thruster) const { return GetPropulsion()->GetAccel(thruster); }
SetFuel(const double f)337 	void SetFuel(const double f) { GetPropulsion()->SetFuel(f); }
SetFuelReserve(const double f)338 	void SetFuelReserve(const double f) { GetPropulsion()->SetFuelReserve(f); }
339 
AIMatchVel(const vector3d & vel)340 	bool AIMatchVel(const vector3d &vel) { return GetPropulsion()->AIMatchVel(vel); }
341 	double AIFaceDirection(const vector3d &dir, double av = 0) { return GetPropulsion()->AIFaceDirection(dir, av); }
AIMatchAngVelObjSpace(const vector3d & angvel)342 	void AIMatchAngVelObjSpace(const vector3d &angvel) { return GetPropulsion()->AIMatchAngVelObjSpace(angvel); }
SetThrusterState(int axis,double level)343 	void SetThrusterState(int axis, double level) { return GetPropulsion()->SetLinThrusterState(axis, level); }
AIModelCoordsMatchAngVel(const vector3d & desiredAngVel,double softness)344 	void AIModelCoordsMatchAngVel(const vector3d &desiredAngVel, double softness) { return GetPropulsion()->AIModelCoordsMatchAngVel(desiredAngVel, softness); }
345 };
346 
347 #endif /* _SHIP_H */
348