1 /* Weapon.h
2 Copyright (c) 2015 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 WEAPON_H_
14 #define WEAPON_H_
15 
16 #include "Body.h"
17 #include "Point.h"
18 
19 #include <map>
20 #include <utility>
21 
22 class DataNode;
23 class Effect;
24 class Outfit;
25 class Sound;
26 class Sprite;
27 
28 
29 
30 // Class representing all the characteristics of a weapon, including sprites and
31 // effects, sounds, icons, ammo, submunitions, and other attributes. Storing
32 // these parameters in a separate class keeps each Projectile from needing a
33 // copy of them, and storing them as class variables instead of in a map of
34 // string to double significantly reduces access time.
35 class Weapon {
36 public:
37 	// Load from a "weapon" node, either in an outfit, a ship (explosion), or a hazard.
38 	void LoadWeapon(const DataNode &node);
39 	bool IsWeapon() const;
40 
41 	// Get assets used by this weapon.
42 	const Body &WeaponSprite() const;
43 	const Body &HardpointSprite() const;
44 	const Sound *WeaponSound() const;
45 	const Outfit *Ammo() const;
46 	const Sprite *Icon() const;
47 
48 	// Effects to be created at the start or end of the weapon's lifetime.
49 	const std::map<const Effect *, int> &FireEffects() const;
50 	const std::map<const Effect *, int> &LiveEffects() const;
51 	const std::map<const Effect *, int> &HitEffects() const;
52 	const std::map<const Effect *, int> &DieEffects() const;
53 	const std::map<const Outfit *, int> &Submunitions() const;
54 
55 	// Accessor functions for various attributes.
56 	int Lifetime() const;
57 	int RandomLifetime() const;
58 	double Reload() const;
59 	double BurstReload() const;
60 	int BurstCount() const;
61 	int Homing() const;
62 
63 	int AmmoUsage() const;
64 
65 	int MissileStrength() const;
66 	int AntiMissile() const;
67 	// Weapons of the same type will alternate firing (streaming) rather than
68 	// firing all at once (clustering) if the weapon is not an anti-missile and
69 	// is not vulnerable to anti-missile, or has the "stream" attribute.
70 	bool IsStreamed() const;
71 	bool IsParallel() const;
72 
73 	double Velocity() const;
74 	double RandomVelocity() const;
75 	double WeightedVelocity() const;
76 	double Acceleration() const;
77 	double Drag() const;
78 	const Point &HardpointOffset() const;
79 
80 	double Turn() const;
81 	double Inaccuracy() const;
82 	double TurretTurn() const;
83 
84 	double Tracking() const;
85 	double OpticalTracking() const;
86 	double InfraredTracking() const;
87 	double RadarTracking() const;
88 
89 	// Normal damage sustained on firing ship when weapon fired.
90 	double FiringEnergy() const;
91 	double FiringForce() const;
92 	double FiringFuel() const;
93 	double FiringHeat() const;
94 	double FiringHull() const;
95 	double FiringShields() const;
96 	double FiringIon() const;
97 	double FiringSlowing() const;
98 	double FiringDisruption() const;
99 
100 	// Relative damage sustained on firing ship when weapon fired.
101 	double RelativeFiringEnergy() const;
102 	double RelativeFiringHeat() const;
103 	double RelativeFiringFuel() const;
104 	double RelativeFiringHull() const;
105 	double RelativeFiringShields() const;
106 
107 	double SplitRange() const;
108 	double TriggerRadius() const;
109 	double BlastRadius() const;
110 	double HitForce() const;
111 
112 	// A "safe" weapon hits only hostile ships (even if it has a blast radius).
113 	// A "phasing" weapon hits only its intended target; it passes through
114 	// everything else, including asteroids.
115 	bool IsSafe() const;
116 	bool IsPhasing() const;
117 	// Blast radius weapons will scale damage and hit force based on distance,
118 	// unless the "no damage scaling" keyphrase is used in the weapon definition.
119 	bool IsDamageScaled() const;
120 	// Gravitational weapons deal the same amount of hit force to a ship regardless
121 	// of its mass.
122 	bool IsGravitational() const;
123 
124 	// These values include all submunitions:
125 	// Normal damage types:
126 	double ShieldDamage() const;
127 	double HullDamage() const;
128 	double FuelDamage() const;
129 	double HeatDamage() const;
130 	double EnergyDamage() const;
131 	// Status effects:
132 	double IonDamage() const;
133 	double DisruptionDamage() const;
134 	double SlowingDamage() const;
135 	// Relative damage types:
136 	double RelativeShieldDamage() const;
137 	double RelativeHullDamage() const;
138 	double RelativeFuelDamage() const;
139 	double RelativeHeatDamage() const;
140 	double RelativeEnergyDamage() const;
141 	// Check if this weapon does damage. If not, attacking a ship with this
142 	// weapon is not a provocation (even if you push or pull it).
143 	bool DoesDamage() const;
144 
145 	double Piercing() const;
146 
147 	double TotalLifetime() const;
148 	double Range() const;
149 
150 	// Check if this weapon has a damage dropoff range.
151 	bool HasDamageDropoff() const;
152 	// Calculate the percent damage that this weapon deals given the distance
153 	// that the projectile traveled if it has a damage dropoff range.
154 	double DamageDropoff(double distance) const;
155 
156 
157 protected:
158 	// Legacy support: allow turret outfits with no turn rate to specify a
159 	// default turnrate.
160 	void SetTurretTurn(double rate);
161 
162 	// A pair representing the outfit that is consumed as ammo and the number
163 	// of that outfit consumed upon fire.
164 	std::pair<const Outfit*, int> ammo;
165 
166 
167 private:
168 	double TotalDamage(int index) const;
169 
170 
171 private:
172 	// Sprites and sounds.
173 	Body sprite;
174 	Body hardpointSprite;
175 	const Sound *sound = nullptr;
176 	const Sprite *icon = nullptr;
177 
178 	// Fire, die and hit effects.
179 	std::map<const Effect *, int> fireEffects;
180 	std::map<const Effect *, int> liveEffects;
181 	std::map<const Effect *, int> hitEffects;
182 	std::map<const Effect *, int> dieEffects;
183 	std::map<const Outfit *, int> submunitions;
184 
185 	// This stores whether or not the weapon has been loaded.
186 	bool isWeapon = false;
187 	bool isStreamed = false;
188 	bool isSafe = false;
189 	bool isPhasing = false;
190 	bool isDamageScaled = true;
191 	bool isGravitational = false;
192 	// Guns and missiles are by default aimed a converged point at the
193 	// maximum weapons range in front of the ship. When either the installed
194 	// weapon or the gun-port (or both) have the isParallel attribute set
195 	// to true, then this convergence will not be used and the weapon will
196 	// be aimed directly in the gunport angle/direction.
197 	bool isParallel = false;
198 
199 	// Attributes.
200 	int lifetime = 0;
201 	int randomLifetime = 0;
202 	double reload = 1.;
203 	double burstReload = 1.;
204 	int burstCount = 1;
205 	int homing = 0;
206 
207 	int missileStrength = 0;
208 	int antiMissile = 0;
209 
210 	double velocity = 0.;
211 	double randomVelocity = 0.;
212 	double acceleration = 0.;
213 	double drag = 0.;
214 	Point hardpointOffset = {0., 0.};
215 
216 	double turn = 0.;
217 	double inaccuracy = 0.;
218 	double turretTurn = 0.;
219 
220 	double tracking = 0.;
221 	double opticalTracking = 0.;
222 	double infraredTracking = 0.;
223 	double radarTracking = 0.;
224 
225 	double firingEnergy = 0.;
226 	double firingForce = 0.;
227 	double firingFuel = 0.;
228 	double firingHeat = 0.;
229 	double firingHull = 0.;
230 	double firingShields = 0.;
231 	double firingIon = 0.;
232 	double firingSlowing = 0.;
233 	double firingDisruption = 0.;
234 
235 	double relativeFiringEnergy = 0.;
236 	double relativeFiringHeat = 0.;
237 	double relativeFiringFuel = 0.;
238 	double relativeFiringHull = 0.;
239 	double relativeFiringShields = 0.;
240 
241 	double splitRange = 0.;
242 	double triggerRadius = 0.;
243 	double blastRadius = 0.;
244 
245 	static const int DAMAGE_TYPES = 14;
246 	static const int HIT_FORCE = 0;
247 	// Normal damage types:
248 	static const int SHIELD_DAMAGE = 1;
249 	static const int HULL_DAMAGE = 2;
250 	static const int FUEL_DAMAGE = 3;
251 	static const int HEAT_DAMAGE = 4;
252 	static const int ENERGY_DAMAGE = 5;
253 	// Status effects:
254 	static const int ION_DAMAGE = 6;
255 	static const int DISRUPTION_DAMAGE = 7;
256 	static const int SLOWING_DAMAGE = 8;
257 	// Relative damage types:
258 	static const int RELATIVE_SHIELD_DAMAGE = 9;
259 	static const int RELATIVE_HULL_DAMAGE = 10;
260 	static const int RELATIVE_FUEL_DAMAGE = 11;
261 	static const int RELATIVE_HEAT_DAMAGE = 12;
262 	static const int RELATIVE_ENERGY_DAMAGE = 13;
263 	mutable double damage[DAMAGE_TYPES] = {};
264 
265 	double piercing = 0.;
266 
267 	double rangeOverride = 0.;
268 	double velocityOverride = 0.;
269 
270 	bool hasDamageDropoff = false;
271 	std::pair<double, double> damageDropoffRange;
272 	double damageDropoffModifier;
273 
274 	// Cache the calculation of these values, for faster access.
275 	mutable bool calculatedDamage = true;
276 	mutable bool doesDamage = false;
277 	mutable double totalLifetime = -1.;
278 };
279 
280 
281 
282 // Inline the accessors because they get called so frequently.
Lifetime()283 inline int Weapon::Lifetime() const { return lifetime; }
RandomLifetime()284 inline int Weapon::RandomLifetime() const { return randomLifetime; }
Reload()285 inline double Weapon::Reload() const { return reload; }
BurstReload()286 inline double Weapon::BurstReload() const { return burstReload; }
BurstCount()287 inline int Weapon::BurstCount() const { return burstCount; }
Homing()288 inline int Weapon::Homing() const { return homing; }
289 
MissileStrength()290 inline int Weapon::MissileStrength() const { return missileStrength; }
AntiMissile()291 inline int Weapon::AntiMissile() const { return antiMissile; }
IsStreamed()292 inline bool Weapon::IsStreamed() const { return isStreamed; }
293 
Velocity()294 inline double Weapon::Velocity() const { return velocity; }
RandomVelocity()295 inline double Weapon::RandomVelocity() const { return randomVelocity; }
WeightedVelocity()296 inline double Weapon::WeightedVelocity() const { return (velocityOverride > 0.) ? velocityOverride : velocity; }
Acceleration()297 inline double Weapon::Acceleration() const { return acceleration; }
Drag()298 inline double Weapon::Drag() const { return drag; }
HardpointOffset()299 inline const Point &Weapon::HardpointOffset() const { return hardpointOffset; }
300 
Turn()301 inline double Weapon::Turn() const { return turn; }
Inaccuracy()302 inline double Weapon::Inaccuracy() const { return inaccuracy; }
TurretTurn()303 inline double Weapon::TurretTurn() const { return turretTurn; }
304 
Tracking()305 inline double Weapon::Tracking() const { return tracking; }
OpticalTracking()306 inline double Weapon::OpticalTracking() const { return opticalTracking; }
InfraredTracking()307 inline double Weapon::InfraredTracking() const { return infraredTracking; }
RadarTracking()308 inline double Weapon::RadarTracking() const { return radarTracking; }
309 
FiringEnergy()310 inline double Weapon::FiringEnergy() const { return firingEnergy; }
FiringForce()311 inline double Weapon::FiringForce() const { return firingForce; }
FiringFuel()312 inline double Weapon::FiringFuel() const { return firingFuel; }
FiringHeat()313 inline double Weapon::FiringHeat() const { return firingHeat; }
FiringHull()314 inline double Weapon::FiringHull() const { return firingHull; }
FiringShields()315 inline double Weapon::FiringShields() const { return firingShields; }
FiringIon()316 inline double Weapon::FiringIon() const{ return firingIon; }
FiringSlowing()317 inline double Weapon::FiringSlowing() const{ return firingSlowing; }
FiringDisruption()318 inline double Weapon::FiringDisruption() const{ return firingDisruption; }
319 
RelativeFiringEnergy()320 inline double Weapon::RelativeFiringEnergy() const{ return relativeFiringEnergy; }
RelativeFiringHeat()321 inline double Weapon::RelativeFiringHeat() const{ return relativeFiringHeat; }
RelativeFiringFuel()322 inline double Weapon::RelativeFiringFuel() const{ return relativeFiringFuel; }
RelativeFiringHull()323 inline double Weapon::RelativeFiringHull() const{ return relativeFiringHull; }
RelativeFiringShields()324 inline double Weapon::RelativeFiringShields() const{ return relativeFiringShields; }
325 
Piercing()326 inline double Weapon::Piercing() const { return piercing; }
327 
SplitRange()328 inline double Weapon::SplitRange() const { return splitRange; }
TriggerRadius()329 inline double Weapon::TriggerRadius() const { return triggerRadius; }
BlastRadius()330 inline double Weapon::BlastRadius() const { return blastRadius; }
HitForce()331 inline double Weapon::HitForce() const { return TotalDamage(HIT_FORCE); }
332 
IsSafe()333 inline bool Weapon::IsSafe() const { return isSafe; }
IsPhasing()334 inline bool Weapon::IsPhasing() const { return isPhasing; }
IsDamageScaled()335 inline bool Weapon::IsDamageScaled() const { return isDamageScaled; }
IsGravitational()336 inline bool Weapon::IsGravitational() const { return isGravitational; }
337 
ShieldDamage()338 inline double Weapon::ShieldDamage() const { return TotalDamage(SHIELD_DAMAGE); }
HullDamage()339 inline double Weapon::HullDamage() const { return TotalDamage(HULL_DAMAGE); }
FuelDamage()340 inline double Weapon::FuelDamage() const { return TotalDamage(FUEL_DAMAGE); }
HeatDamage()341 inline double Weapon::HeatDamage() const { return TotalDamage(HEAT_DAMAGE); }
EnergyDamage()342 inline double Weapon::EnergyDamage() const { return TotalDamage(ENERGY_DAMAGE); }
343 
IonDamage()344 inline double Weapon::IonDamage() const { return TotalDamage(ION_DAMAGE); }
DisruptionDamage()345 inline double Weapon::DisruptionDamage() const { return TotalDamage(DISRUPTION_DAMAGE); }
SlowingDamage()346 inline double Weapon::SlowingDamage() const { return TotalDamage(SLOWING_DAMAGE); }
347 
RelativeShieldDamage()348 inline double Weapon::RelativeShieldDamage() const { return TotalDamage(RELATIVE_SHIELD_DAMAGE); }
RelativeHullDamage()349 inline double Weapon::RelativeHullDamage() const { return TotalDamage(RELATIVE_HULL_DAMAGE); }
RelativeFuelDamage()350 inline double Weapon::RelativeFuelDamage() const { return TotalDamage(RELATIVE_FUEL_DAMAGE); }
RelativeHeatDamage()351 inline double Weapon::RelativeHeatDamage() const { return TotalDamage(RELATIVE_HEAT_DAMAGE); }
RelativeEnergyDamage()352 inline double Weapon::RelativeEnergyDamage() const { return TotalDamage(RELATIVE_ENERGY_DAMAGE); }
353 
DoesDamage()354 inline bool Weapon::DoesDamage() const { if(!calculatedDamage) TotalDamage(0); return doesDamage; }
355 
HasDamageDropoff()356 inline bool Weapon::HasDamageDropoff() const { return hasDamageDropoff; }
357 
358 
359 
360 #endif
361