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