1 /* Ship.h
2 Copyright (c) 2014 by Michael Zahniser
3 
4 Endless Sky is free software: you can redistribute it and/or modify it under the
5 terms of the GNU General Public License as published by the Free Software
6 Foundation, either version 3 of the License, or (at your option) any later version.
7 
8 Endless Sky is distributed in the hope that it will be useful, but WITHOUT ANY
9 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
10 PARTICULAR PURPOSE.  See the GNU General Public License for more details.
11 */
12 
13 #ifndef SHIP_H_
14 #define SHIP_H_
15 
16 #include "Body.h"
17 
18 #include "Angle.h"
19 #include "Armament.h"
20 #include "CargoHold.h"
21 #include "Command.h"
22 #include "Outfit.h"
23 #include "Personality.h"
24 #include "Point.h"
25 
26 #include <list>
27 #include <map>
28 #include <memory>
29 #include <set>
30 #include <string>
31 #include <vector>
32 
33 class DataNode;
34 class DataWriter;
35 class Effect;
36 class Flotsam;
37 class Government;
38 class Hazard;
39 class Minable;
40 class Phrase;
41 class Planet;
42 class PlayerInfo;
43 class Projectile;
44 class StellarObject;
45 class System;
46 class Visual;
47 
48 
49 
50 // Class representing a ship (either a model for sale or an instance of it). A
51 // ship's information can be saved to a file, so that it can later be read back
52 // in exactly the same state. The same class is used for the player's ship as
53 // for all other ships, so their capabilities are exactly the same  within the
54 // limits of what the AI knows how to command them to do.
55 class Ship : public Body, public std::enable_shared_from_this<Ship> {
56 public:
57 	// These are all the possible category strings for ships.
58 	static const std::vector<std::string> CATEGORIES;
59 	// Allow retrieving the available bay types for the current game;
60 	static const std::set<std::string> BAY_TYPES;
61 
62 	class Bay {
63 	public:
Bay(double x,double y,std::string category)64 		Bay(double x, double y, std::string category) : point(x * .5, y * .5), category(category) {}
65 		Bay(Bay &&) = default;
66 		Bay &operator=(Bay &&) = default;
67 		~Bay() = default;
68 
69 		// Copying a bay does not copy the ship inside it.
Bay(const Bay & b)70 		Bay(const Bay &b) : point(b.point), category(b.category), side(b.side), facing(b.facing), launchEffects(b.launchEffects) {}
71 		Bay &operator=(const Bay &b) { return *this = Bay(b); }
72 
73 		Point point;
74 		std::shared_ptr<Ship> ship;
75 		std::string category;
76 
77 		uint8_t side = 0;
78 		static const uint8_t INSIDE = 0;
79 		static const uint8_t OVER = 1;
80 		static const uint8_t UNDER = 2;
81 
82 		// The angle at which the carried ship will depart, relative to the carrying ship.
83 		Angle facing;
84 
85 		// The launch effect(s) to be simultaneously played when the bay's ship launches.
86 		std::vector<const Effect *> launchEffects;
87 	};
88 
89 	class EnginePoint : public Point {
90 	public:
EnginePoint(double x,double y,double zoom)91 		EnginePoint(double x, double y, double zoom) : Point(x, y), zoom(zoom) {}
92 
93 		uint8_t side = 0;
94 		static const uint8_t UNDER = 0;
95 		static const uint8_t OVER = 1;
96 
97 		uint8_t steering = 0;
98 		static const uint8_t NONE = 0;
99 		static const uint8_t LEFT = 1;
100 		static const uint8_t RIGHT = 2;
101 
102 		double zoom;
103 		Angle facing;
104 	};
105 
106 
107 public:
108 	/* Functions provided by the Body base class:
109 	bool HasSprite() const;
110 	const Sprite *GetSprite() const;
111 	int Width() const;
112 	int Height() const;
113 	int GetSwizzle() const;
114 	Frame GetFrame(int step = -1) const;
115 	const Mask &GetMask(int step = -1) const;
116 	const Point &Position() const;
117 	const Point &Velocity() const;
118 	const Angle &Facing() const;
119 	Point Unit() const;
120 	double Zoom() const;
121 	const Government *GetGovernment() const;
122 	*/
123 
124 	Ship() = default;
125 	// Construct and Load() at the same time.
126 	Ship(const DataNode &node);
127 
128 	// Load data for a type of ship:
129 	void Load(const DataNode &node);
130 	// When loading a ship, some of the outfits it lists may not have been
131 	// loaded yet. So, wait until everything has been loaded, then call this.
132 	void FinishLoading(bool isNewInstance);
133 	// Check that this ship model and all its outfits have been loaded.
134 	bool IsValid() const;
135 	// Save a full description of this ship, as currently configured.
136 	void Save(DataWriter &out) const;
137 
138 	// Get the name of this particular ship.
139 	const std::string &Name() const;
140 
141 	// Set / Get the name of this model of ship.
142 	void SetModelName(const std::string &model);
143 	const std::string &ModelName() const;
144 	const std::string &PluralModelName() const;
145 	// Get the name of this ship as a variant.
146 	const std::string &VariantName() const;
147 	// Get the generic noun (e.g. "ship") to be used when describing this ship.
148 	const std::string &Noun() const;
149 	// Get this ship's description.
150 	const std::string &Description() const;
151 	// Get the shipyard thumbnail for this ship.
152 	const Sprite *Thumbnail() const;
153 	// Get this ship's cost.
154 	int64_t Cost() const;
155 	int64_t ChassisCost() const;
156 
157 	// Check if this ship is configured in such a way that it would be difficult
158 	// or impossible to fly.
159 	std::vector<std::string> FlightCheck() const;
160 
161 	void SetPosition(Point position);
162 	// When creating a new ship, you must set the following:
163 	void Place(Point position = Point(), Point velocity = Point(), Angle angle = Angle());
164 	void SetName(const std::string &name);
165 	void SetSystem(const System *system);
166 	void SetPlanet(const Planet *planet);
167 	void SetGovernment(const Government *government);
168 	void SetIsSpecial(bool special = true);
169 	bool IsSpecial() const;
170 
171 	// If a ship belongs to the player, the player can give it commands.
172 	void SetIsYours(bool yours = true);
173 	bool IsYours() const;
174 	// A parked ship stays on a planet and requires no daily salary payments.
175 	void SetIsParked(bool parked = true);
176 	bool IsParked() const;
177 	// The player can selectively deploy their carried ships, rather than just all / none.
178 	void SetDeployOrder(bool shouldDeploy = true);
179 	bool HasDeployOrder() const;
180 
181 	// Access the ship's personality, which affects how the AI behaves.
182 	const Personality &GetPersonality() const;
183 	void SetPersonality(const Personality &other);
184 	// Get a random hail message, or set the object used to generate them. If no
185 	// object is given the government's default will be used.
186 	void SetHail(const Phrase &phrase);
187 	std::string GetHail(const PlayerInfo &player) const;
188 
189 	// Set the commands for this ship to follow this timestep.
190 	void SetCommands(const Command &command);
191 	const Command &Commands() const;
192 	// Move this ship. A ship may create effects as it moves, in particular if
193 	// it is in the process of blowing up.
194 	void Move(std::vector<Visual> &visuals, std::list<std::shared_ptr<Flotsam>> &flotsam);
195 	// Generate energy, heat, etc. (This is called by Move().)
196 	void DoGeneration();
197 	// Launch any ships that are ready to launch.
198 	void Launch(std::list<std::shared_ptr<Ship>> &ships, std::vector<Visual> &visuals);
199 	// Check if this ship is boarding another ship. If it is, it either plunders
200 	// it or, if this is a player ship, returns the ship it is plundering so a
201 	// plunder dialog can be displayed.
202 	std::shared_ptr<Ship> Board(bool autoPlunder = true);
203 	// Scan the target, if able and commanded to. Return a ShipEvent bitmask
204 	// giving the types of scan that succeeded.
205 	int Scan();
206 	// Find out what fraction of the scan is complete.
207 	double CargoScanFraction() const;
208 	double OutfitScanFraction() const;
209 
210 	// Fire any weapons that are ready to fire. If an anti-missile is ready,
211 	// instead of firing here this function returns true and it can be fired if
212 	// collision detection finds a missile in range.
213 	bool Fire(std::vector<Projectile> &projectiles, std::vector<Visual> &visuals);
214 	// Fire an anti-missile. Returns true if the missile was killed.
215 	bool FireAntiMissile(const Projectile &projectile, std::vector<Visual> &visuals);
216 
217 	// Get the system this ship is in.
218 	const System *GetSystem() const;
219 	// If the ship is landed, get the planet it has landed on.
220 	const Planet *GetPlanet() const;
221 
222 	// Check the status of this ship.
223 	bool IsCapturable() const;
224 	bool IsTargetable() const;
225 	bool IsOverheated() const;
226 	bool IsDisabled() const;
227 	bool IsBoarding() const;
228 	bool IsLanding() const;
229 	// Check if this ship is currently able to begin landing on its target.
230 	bool CanLand() const;
231 	// Check if some condition is keeping this ship from acting. (That is, it is
232 	// landing, hyperspacing, cloaking, disabled, or under-crewed.)
233 	bool CannotAct() const;
234 	// Get the degree to which this ship is cloaked. 1 means invisible and
235 	// impossible to hit or target; 0 means fully visible.
236 	double Cloaking() const;
237 	// Check if this ship is entering (rather than leaving) hyperspace.
238 	bool IsEnteringHyperspace() const;
239 	// Check if this ship is entering or leaving hyperspace.
240 	bool IsHyperspacing() const;
241 	// Check if this ship is hyperspacing, specifically via a jump drive.
242 	bool IsUsingJumpDrive() const;
243 	// Check if this ship is currently able to enter hyperspace to it target.
244 	bool IsReadyToJump(bool waitingIsReady = false) const;
245 	// Get this ship's custom swizzle.
246 	int CustomSwizzle() const;
247 
248 	// Check if the ship is thrusting. If so, the engine sound should be played.
249 	bool IsThrusting() const;
250 	bool IsReversing() const;
251 	bool IsSteering() const;
252 	// The direction that the ship is steering. If positive, the ship is steering right.
253 	// If negative, the ship is steering left.
254 	double SteeringDirection() const;
255 	// Get the points from which engine flares should be drawn.
256 	const std::vector<EnginePoint> &EnginePoints() const;
257 	const std::vector<EnginePoint> &ReverseEnginePoints() const;
258 	const std::vector<EnginePoint> &SteeringEnginePoints() const;
259 
260 	// Make a ship disabled or destroyed, or bring back a destroyed ship.
261 	void Disable();
262 	void Destroy();
263 	void SelfDestruct();
264 	void Restore();
265 	// Check if this ship has been destroyed.
266 	bool IsDestroyed() const;
267 	// Recharge and repair this ship (e.g. because it has landed).
268 	void Recharge(bool atSpaceport = true);
269 	// Check if this ship is able to give the given ship enough fuel to jump.
270 	bool CanRefuel(const Ship &other) const;
271 	// Give the other ship enough fuel for it to jump.
272 	double TransferFuel(double amount, Ship *to);
273 	// Mark this ship as property of the given ship.
274 	void WasCaptured(const std::shared_ptr<Ship> &capturer);
275 
276 	// Get characteristics of this ship, as a fraction between 0 and 1.
277 	double Shields() const;
278 	double Hull() const;
279 	double Fuel() const;
280 	double Energy() const;
281 	// A ship's heat is generally between 0 and 1, but if it receives
282 	// heat damage the value can increase above 1.
283 	double Heat() const;
284 	// Get the ship's "health," where <=0 is disabled and 1 means full health.
285 	double Health() const;
286 	// Get the hull fraction at which this ship is disabled.
287 	double DisabledHull() const;
288 	// Get the number of jumps this ship can make before running out of fuel.
289 	// This depends on how much fuel it has and what sort of hyperdrive it uses.
290 	// If followParent is false, this ship will not follow the parent.
291 	int JumpsRemaining(bool followParent = true) const;
292 	// Get the amount of fuel expended per jump.
293 	double JumpFuel(const System *destination = nullptr) const;
294 	// Get the distance that this ship can jump.
295 	double JumpRange(bool getCached = true) const;
296 	// Get the cost of making a jump of the given type (if possible).
297 	double HyperdriveFuel() const;
298 	double JumpDriveFuel(double jumpDistance = 0.) const;
299 	// Get the amount of fuel missing for the next jump (smart refuelling)
300 	double JumpFuelMissing() const;
301 	// Get the heat level at idle.
302 	double IdleHeat() const;
303 	// Get the heat dissipation, in heat units per heat unit per frame.
304 	double HeatDissipation() const;
305 	// Get the maximum heat level, in heat units (not temperature).
306 	double MaximumHeat() const;
307 	// Calculate the multiplier for cooling efficiency.
308 	double CoolingEfficiency() const;
309 
310 	// Access how many crew members this ship has or needs.
311 	int Crew() const;
312 	int RequiredCrew() const;
313 	void AddCrew(int count);
314 	// Check if this is a ship that can be used as a flagship.
315 	bool CanBeFlagship() const;
316 
317 	// Get this ship's movement characteristics.
318 	double Mass() const;
319 	double TurnRate() const;
320 	double Acceleration() const;
321 	double MaxVelocity() const;
322 	double MaxReverseVelocity() const;
323 
324 	// This ship just got hit by the given projectile. Take damage according to
325 	// what sort of weapon the projectile it. The return value is a ShipEvent
326 	// type, which may be a combination of PROVOKED, DISABLED, and DESTROYED.
327 	// If isBlast, this ship was caught in the blast radius of a weapon but was
328 	// not necessarily its primary target.
329 	// Blast damage is dependent on the distance to the damage source.
330 	int TakeDamage(const Projectile &projectile, bool isBlast = false);
331 	// This ship just got hit by the given hazard. Take damage according to what
332 	// sort of weapon the hazard has, and create any hit effects as sparks.
333 	void TakeHazardDamage(std::vector<Visual> &visuals, const Hazard *hazard, double strength);
334 	// Apply a force to this ship, accelerating it. This might be from a weapon
335 	// impact, or from firing a weapon, for example.
336 	void ApplyForce(const Point &force, bool gravitational = false);
337 
338 	// Check if this ship has bays to carry other ships.
339 	bool HasBays() const;
340 	// Check how many bays are not occupied at present. This does not check
341 	// whether one of your escorts plans to use that bay.
342 	int BaysFree(const std::string &category) const;
343 	// Check how many bays this ship has of a given category.
344 	int BaysTotal(const std::string &category) const;
345 	// Check if this ship has a bay free for the given other ship, and the
346 	// bay is not reserved for one of its existing escorts.
347 	bool CanCarry(const Ship &ship) const;
348 	// Change whether this ship can be carried. If false, the ship cannot be
349 	// carried. If true, the ship can be carried if its category allows it.
350 	void AllowCarried(bool allowCarried);
351 	// Check if this is a ship of a type that can be carried.
352 	bool CanBeCarried() const;
353 	// Move the given ship into one of the bays, if possible.
354 	bool Carry(const std::shared_ptr<Ship> &ship);
355 	// Empty the bays. If the carried ships are not special ships that are
356 	// saved in the player data, they will be deleted. Otherwise, they become
357 	// visible as ships landed on the same planet as their parent.
358 	void UnloadBays();
359 	// Get a list of any ships this ship is carrying.
360 	const std::vector<Bay> &Bays() const;
361 	// Adjust the positions and velocities of any visible carried fighters or
362 	// drones. If any are visible, return true.
363 	bool PositionFighters() const;
364 
365 	// Get cargo information.
366 	CargoHold &Cargo();
367 	const CargoHold &Cargo() const;
368 	// Display box effects from jettisoning this much cargo.
369 	void Jettison(const std::string &commodity, int tons);
370 	void Jettison(const Outfit *outfit, int count);
371 
372 	// Get the current attributes of this ship.
373 	const Outfit &Attributes() const;
374 	// Get the attributes of this ship chassis before any outfits were added.
375 	const Outfit &BaseAttributes() const;
376 	// Get the list of all outfits installed in this ship.
377 	const std::map<const Outfit *, int> &Outfits() const;
378 	// Find out how many outfits of the given type this ship contains.
379 	int OutfitCount(const Outfit *outfit) const;
380 	// Add or remove outfits. (To remove, pass a negative number.)
381 	void AddOutfit(const Outfit *outfit, int count);
382 
383 	// Get the list of weapons.
384 	Armament &GetArmament();
385 	const std::vector<Hardpoint> &Weapons() const;
386 	// Check if we are able to fire the given weapon (i.e. there is enough
387 	// energy, ammo, and fuel to fire it).
388 	bool CanFire(const Weapon *weapon) const;
389 	// Fire the given weapon (i.e. deduct whatever energy, ammo, or fuel it uses
390 	// and add whatever heat it generates. Assume that CanFire() is true.
391 	void ExpendAmmo(const Weapon *weapon);
392 
393 	// Each ship can have a target system (to travel to), a target planet (to
394 	// land on) and a target ship (to move to, and attack if hostile).
395 	std::shared_ptr<Ship> GetTargetShip() const;
396 	std::shared_ptr<Ship> GetShipToAssist() const;
397 	const StellarObject *GetTargetStellar() const;
398 	const System *GetTargetSystem() const;
399 	// Mining target.
400 	std::shared_ptr<Minable> GetTargetAsteroid() const;
401 	std::shared_ptr<Flotsam> GetTargetFlotsam() const;
402 
403 	// Set this ship's targets.
404 	void SetTargetShip(const std::shared_ptr<Ship> &ship);
405 	void SetShipToAssist(const std::shared_ptr<Ship> &ship);
406 	void SetTargetStellar(const StellarObject *object);
407 	void SetTargetSystem(const System *system);
408 	// Mining target.
409 	void SetTargetAsteroid(const std::shared_ptr<Minable> &asteroid);
410 	void SetTargetFlotsam(const std::shared_ptr<Flotsam> &flotsam);
411 
412 	// Manage escorts. When you set this ship's parent, it will automatically
413 	// register itself as an escort of that ship, and unregister itself from any
414 	// previous parent it had.
415 	void SetParent(const std::shared_ptr<Ship> &ship);
416 	std::shared_ptr<Ship> GetParent() const;
417 	const std::vector<std::weak_ptr<Ship>> &GetEscorts() const;
418 
419 
420 private:
421 	// Add or remove a ship from this ship's list of escorts.
422 	void AddEscort(Ship &ship);
423 	void RemoveEscort(const Ship &ship);
424 	// Get the hull amount at which this ship is disabled.
425 	double MinimumHull() const;
426 	// Find out how much fuel is consumed by the hyperdrive of the given type.
427 	double BestFuel(const std::string &type, const std::string &subtype, double defaultFuel, double jumpDistance = 0.) const;
428 	// Create one of this ship's explosions, within its mask. The explosions can
429 	// either stay over the ship, or spread out if this is the final explosion.
430 	void CreateExplosion(std::vector<Visual> &visuals, bool spread = false);
431 	// Place a "spark" effect, like ionization or disruption.
432 	void CreateSparks(std::vector<Visual> &visuals, const std::string &name, double amount);
433 	void CreateSparks(std::vector<Visual> &visuals, const Effect *effect, double amount);
434 	// A helper method for taking damage from either a projectile or a hazard.
435 	int TakeDamage(const Weapon &weapon, double damageScaling, double distanceTraveled, const Point &damagePosition, bool isBlast);
436 
437 
438 private:
439 	/* Protected member variables of the Body class:
440 	Point position;
441 	Point velocity;
442 	Angle angle;
443 	double zoom;
444 	int swizzle;
445 	const Government *government;
446 	*/
447 
448 	// Characteristics of the chassis:
449 	bool isDefined = false;
450 	const Ship *base = nullptr;
451 	std::string modelName;
452 	std::string pluralModelName;
453 	std::string variantName;
454 	std::string noun;
455 	std::string description;
456 	const Sprite *thumbnail = nullptr;
457 	// Characteristics of this particular ship:
458 	std::string name;
459 	bool canBeCarried = false;
460 
461 	int forget = 0;
462 	bool isInSystem = true;
463 	// "Special" ships cannot be forgotten, and if they land on a planet, they
464 	// continue to exist and refuel instead of being deleted.
465 	bool isSpecial = false;
466 	bool isYours = false;
467 	bool isParked = false;
468 	bool shouldDeploy = false;
469 	bool isOverheated = false;
470 	bool isDisabled = false;
471 	bool isBoarding = false;
472 	bool hasBoarded = false;
473 	bool isThrusting = false;
474 	bool isReversing = false;
475 	bool isSteering = false;
476 	double steeringDirection = 0.;
477 	bool neverDisabled = false;
478 	bool isCapturable = true;
479 	bool isInvisible = false;
480 	int customSwizzle = -1;
481 	double cloak = 0.;
482 	double cloakDisruption = 0.;
483 	// Cached values for figuring out when anti-missile is in range.
484 	double antiMissileRange = 0.;
485 	double weaponRadius = 0.;
486 	// Cargo and outfit scanning takes time.
487 	double cargoScan = 0.;
488 	double outfitScan = 0.;
489 
490 	Command commands;
491 
492 	Personality personality;
493 	const Phrase *hail = nullptr;
494 
495 	// Installed outfits, cargo, etc.:
496 	Outfit attributes;
497 	Outfit baseAttributes;
498 	bool addAttributes = false;
499 	const Outfit *explosionWeapon = nullptr;
500 	std::map<const Outfit *, int> outfits;
501 	CargoHold cargo;
502 	std::list<std::shared_ptr<Flotsam>> jettisoned;
503 
504 	std::vector<Bay> bays;
505 	// Cache the mass of carried ships to avoid repeatedly recomputing it.
506 	double carriedMass = 0.;
507 
508 	std::vector<EnginePoint> enginePoints;
509 	std::vector<EnginePoint> reverseEnginePoints;
510 	std::vector<EnginePoint> steeringEnginePoints;
511 	Armament armament;
512 	// While loading, keep track of which outfits already have been equipped.
513 	// (That is, they were specified as linked to a given gun or turret point.)
514 	std::map<const Outfit *, int> equipped;
515 
516 	// Various energy levels:
517 	double shields = 0.;
518 	double hull = 0.;
519 	double fuel = 0.;
520 	double energy = 0.;
521 	double heat = 0.;
522 	double ionization = 0.;
523 	double disruption = 0.;
524 	double slowness = 0.;
525 	// Delays for shield generation and hull repair.
526 	int shieldDelay = 0;
527 	int hullDelay = 0;
528 	// Acceleration can be created by engines, firing weapons, or weapon impacts.
529 	Point acceleration;
530 
531 	int crew = 0;
532 	int pilotError = 0;
533 	int pilotOkay = 0;
534 
535 	// Current status of this particular ship:
536 	const System *currentSystem = nullptr;
537 	// A Ship can be locked into one of three special states: landing,
538 	// hyperspacing, and exploding. Each one must track some special counters:
539 	const Planet *landingPlanet = nullptr;
540 
541 	int hyperspaceCount = 0;
542 	const System *hyperspaceSystem = nullptr;
543 	bool isUsingJumpDrive = false;
544 	double hyperspaceFuelCost = 0.;
545 	Point hyperspaceOffset;
546 
547 	double jumpRange = 0.;
548 
549 	// The hull may spring a "leak" (venting atmosphere, flames, blood, etc.)
550 	// when the ship is dying.
551 	class Leak {
552 	public:
effect(effect)553 		Leak(const Effect *effect = nullptr) : effect(effect) {}
554 
555 		const Effect *effect = nullptr;
556 		Point location;
557 		Angle angle;
558 		int openPeriod = 60;
559 		int closePeriod = 60;
560 	};
561 	std::vector<Leak> leaks;
562 	std::vector<Leak> activeLeaks;
563 
564 	// Explosions that happen when the ship is dying:
565 	std::map<const Effect *, int> explosionEffects;
566 	unsigned explosionRate = 0;
567 	unsigned explosionCount = 0;
568 	unsigned explosionTotal = 0;
569 	std::map<const Effect *, int> finalExplosions;
570 
571 	// Target ships, planets, systems, etc.
572 	std::weak_ptr<Ship> targetShip;
573 	std::weak_ptr<Ship> shipToAssist;
574 	const StellarObject *targetPlanet = nullptr;
575 	const System *targetSystem = nullptr;
576 	std::weak_ptr<Minable> targetAsteroid;
577 	std::weak_ptr<Flotsam> targetFlotsam;
578 
579 	// Links between escorts and parents.
580 	std::vector<std::weak_ptr<Ship>> escorts;
581 	std::weak_ptr<Ship> parent;
582 };
583 
584 
585 
586 #endif
587