Weapon.h 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853
  1. /*
  2. ** Command & Conquer Generals(tm)
  3. ** Copyright 2025 Electronic Arts Inc.
  4. **
  5. ** This program is free software: you can redistribute it and/or modify
  6. ** it under the terms of the GNU General Public License as published by
  7. ** the Free Software Foundation, either version 3 of the License, or
  8. ** (at your option) any later version.
  9. **
  10. ** This program is distributed in the hope that it will be useful,
  11. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ** GNU General Public License for more details.
  14. **
  15. ** You should have received a copy of the GNU General Public License
  16. ** along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. ////////////////////////////////////////////////////////////////////////////////
  19. // //
  20. // (c) 2001-2003 Electronic Arts Inc. //
  21. // //
  22. ////////////////////////////////////////////////////////////////////////////////
  23. // FILE: Weapon.h /////////////////////////////////////////////////////////////////////////////////
  24. // Author: Colin Day, November 2001
  25. // Desc: Weapon Descriptions
  26. ///////////////////////////////////////////////////////////////////////////////////////////////////
  27. #pragma once
  28. #ifndef __WEAPON_H_
  29. #define __WEAPON_H_
  30. // INCLUDES ///////////////////////////////////////////////////////////////////////////////////////
  31. #include "Common/AudioEventRTS.h"
  32. #include "Common/GameCommon.h"
  33. #include "GameLogic/Damage.h"
  34. #include "WWMath/Matrix3D.h"
  35. // FORWARD REFERENCES /////////////////////////////////////////////////////////////////////////////
  36. struct FieldParse;
  37. class FXList;
  38. class ObjectCreationList;
  39. class ThingTemplate;
  40. class Object;
  41. class Weapon;
  42. class WeaponTemplate;
  43. class INI;
  44. class ParticleSystemTemplate;
  45. enum NameKeyType;
  46. //-------------------------------------------------------------------------------------------------
  47. const Int NO_MAX_SHOTS_LIMIT = 0x7fffffff;
  48. //-------------------------------------------------------------------------------------------------
  49. enum WeaponReloadType
  50. {
  51. AUTO_RELOAD,
  52. NO_RELOAD,
  53. RETURN_TO_BASE_TO_RELOAD
  54. };
  55. #ifdef DEFINE_WEAPONRELOAD_NAMES
  56. static const char *TheWeaponReloadNames[] =
  57. {
  58. "YES",
  59. "NO",
  60. "RETURN_TO_BASE",
  61. NULL
  62. };
  63. #endif
  64. //-------------------------------------------------------------------------------------------------
  65. enum WeaponPrefireType
  66. {
  67. PREFIRE_PER_SHOT, ///< Use the prefire delay for every shot we make
  68. PREFIRE_PER_ATTACK, ///< Use the prefire delay each time we attack a new target
  69. PREFIRE_PER_CLIP, ///< Use the prefire attack delay for each new clip
  70. PREFIRE_COUNT
  71. };
  72. #ifdef DEFINE_WEAPONPREFIRE_NAMES
  73. static const char *TheWeaponPrefireNames[] =
  74. {
  75. "PER_SHOT",
  76. "PER_ATTACK",
  77. "PER_CLIP",
  78. NULL
  79. };
  80. #endif
  81. //-------------------------------------------------------------------------------------------------
  82. enum WeaponAntiMaskType
  83. {
  84. WEAPON_ANTI_AIRBORNE_VEHICLE = 0x01,
  85. WEAPON_ANTI_GROUND = 0x02,
  86. WEAPON_ANTI_PROJECTILE = 0x04,
  87. WEAPON_ANTI_SMALL_MISSILE = 0x08, // All missiles are also projectiles (but not all projectiles are missiles)
  88. WEAPON_ANTI_MINE = 0x10,
  89. WEAPON_ANTI_AIRBORNE_INFANTRY = 0x20, // When set, anti-air weapons will not target infantry paratroopers.
  90. WEAPON_ANTI_BALLISTIC_MISSILE = 0x40, // Specifically large missiles that are vulnerable to base defenses
  91. WEAPON_ANTI_PARACHUTE = 0x80, // Parachutes can be targeted directly
  92. };
  93. //-------------------------------------------------------------------------------------------------
  94. enum WeaponAffectsMaskType
  95. {
  96. WEAPON_AFFECTS_SELF = 0x01,
  97. WEAPON_AFFECTS_ALLIES = 0x02,
  98. WEAPON_AFFECTS_ENEMIES = 0x04, // that is, enemies that aren't the primary target
  99. WEAPON_AFFECTS_NEUTRALS = 0x08, // ditto
  100. WEAPON_KILLS_SELF = 0x10, // ensures that it's not possible to survive self damage
  101. WEAPON_DOESNT_AFFECT_SIMILAR = 0x20, // Doesn't affect others that are the same as us (like other terrorists for a terrorist bomb to prevent chain reaction)
  102. WEAPON_DOESNT_AFFECT_AIRBORNE = 0x40, // Radius damage doesn't affect airborne units, unless they are the primary target. (used for poison fields.)
  103. };
  104. #ifdef DEFINE_WEAPONAFFECTSMASK_NAMES
  105. static const char *TheWeaponAffectsMaskNames[] =
  106. {
  107. "SELF",
  108. "ALLIES",
  109. "ENEMIES",
  110. "NEUTRALS",
  111. "SUICIDE",
  112. "NOT_SIMILAR",
  113. "NOT_AIRBORNE",
  114. NULL
  115. };
  116. #endif
  117. //-------------------------------------------------------------------------------------------------
  118. enum WeaponCollideMaskType
  119. {
  120. // all of these apply to *nontargeted* things that might just happen to get in the way...
  121. // the target can always be collided with, regardless of flags
  122. WEAPON_COLLIDE_ALLIES = 0x0001,
  123. WEAPON_COLLIDE_ENEMIES = 0x0002,
  124. WEAPON_COLLIDE_STRUCTURES = 0x0004, // this is "all structures EXCEPT for structures belonging to the projectile's controller".
  125. WEAPON_COLLIDE_SHRUBBERY = 0x0008,
  126. WEAPON_COLLIDE_PROJECTILE = 0x0010,
  127. WEAPON_COLLIDE_WALLS = 0x0020,
  128. WEAPON_COLLIDE_SMALL_MISSILES = 0x0040, //All missiles are also projectiles!
  129. WEAPON_COLLIDE_BALLISTIC_MISSILES = 0x0080, //All missiles are also projectiles!
  130. WEAPON_COLLIDE_CONTROLLED_STRUCTURES = 0x0100 //this is "ONLY structures belonging to the projectile's controller".
  131. };
  132. #ifdef DEFINE_WEAPONCOLLIDEMASK_NAMES
  133. static const char *TheWeaponCollideMaskNames[] =
  134. {
  135. "ALLIES",
  136. "ENEMIES",
  137. "STRUCTURES",
  138. "SHRUBBERY",
  139. "PROJECTILES",
  140. "WALLS",
  141. "SMALL_MISSILES", //All missiles are also projectiles!
  142. "BALLISTIC_MISSILES", //All missiles are also projectiles!
  143. "CONTROLLED_STRUCTURES",
  144. NULL
  145. };
  146. #endif
  147. //-------------------------------------------------------------------------------------------------
  148. //
  149. // Note: these values are saved in save files, so you MUST NOT REMOVE OR CHANGE
  150. // existing values!
  151. //
  152. enum WeaponBonusConditionType
  153. {
  154. // The access and use of this enum has the bit shifting built in, so this is a 0,1,2,3,4,5 enum
  155. WEAPONBONUSCONDITION_INVALID = -1,
  156. WEAPONBONUSCONDITION_GARRISONED = 0,
  157. WEAPONBONUSCONDITION_HORDE,
  158. WEAPONBONUSCONDITION_CONTINUOUS_FIRE_MEAN,
  159. WEAPONBONUSCONDITION_CONTINUOUS_FIRE_FAST,
  160. WEAPONBONUSCONDITION_NATIONALISM,
  161. WEAPONBONUSCONDITION_PLAYER_UPGRADE,
  162. WEAPONBONUSCONDITION_DRONE_SPOTTING,
  163. #ifdef ALLOW_DEMORALIZE
  164. WEAPONBONUSCONDITION_DEMORALIZED,
  165. #else
  166. WEAPONBONUSCONDITION_DEMORALIZED_OBSOLETE,
  167. #endif
  168. WEAPONBONUSCONDITION_ENTHUSIASTIC,
  169. WEAPONBONUSCONDITION_VETERAN,
  170. WEAPONBONUSCONDITION_ELITE,
  171. WEAPONBONUSCONDITION_HERO,
  172. WEAPONBONUSCONDITION_BATTLEPLAN_BOMBARDMENT,
  173. WEAPONBONUSCONDITION_BATTLEPLAN_HOLDTHELINE,
  174. WEAPONBONUSCONDITION_BATTLEPLAN_SEARCHANDDESTROY,
  175. WEAPONBONUSCONDITION_SUBLIMINAL,
  176. WEAPONBONUSCONDITION_SOLO_HUMAN_EASY,
  177. WEAPONBONUSCONDITION_SOLO_HUMAN_NORMAL,
  178. WEAPONBONUSCONDITION_SOLO_HUMAN_HARD,
  179. WEAPONBONUSCONDITION_SOLO_AI_EASY,
  180. WEAPONBONUSCONDITION_SOLO_AI_NORMAL,
  181. WEAPONBONUSCONDITION_SOLO_AI_HARD,
  182. WEAPONBONUSCONDITION_COUNT
  183. };
  184. #ifdef DEFINE_WEAPONBONUSCONDITION_NAMES
  185. static const char *TheWeaponBonusNames[] =
  186. {
  187. // This is a RHS enum (weapon.ini will have WeaponBonus = IT) so it is all caps
  188. "GARRISONED",
  189. "HORDE",
  190. "CONTINUOUS_FIRE_MEAN",
  191. "CONTINUOUS_FIRE_FAST",
  192. "NATIONALISM",
  193. "PLAYER_UPGRADE",
  194. "DRONE_SPOTTING",
  195. #ifdef ALLOW_DEMORALIZE
  196. "DEMORALIZED",
  197. #else
  198. "DEMORALIZED_OBSOLETE",
  199. #endif
  200. "ENTHUSIASTIC",
  201. "VETERAN",
  202. "ELITE",
  203. "HERO",
  204. "BATTLEPLAN_BOMBARDMENT",
  205. "BATTLEPLAN_HOLDTHELINE",
  206. "BATTLEPLAN_SEARCHANDDESTROY",
  207. "SUBLIMINAL",
  208. "SOLO_HUMAN_EASY",
  209. "SOLO_HUMAN_NORMAL",
  210. "SOLO_HUMAN_HARD",
  211. "SOLO_AI_EASY",
  212. "SOLO_AI_NORMAL",
  213. "SOLO_AI_HARD",
  214. NULL
  215. };
  216. #endif
  217. // For WeaponBonusConditionFlags
  218. // part of detangling
  219. #include "GameLogic/WeaponBonusConditionFlags.h"
  220. #include "GameLogic/WeaponStatus.h"
  221. //-------------------------------------------------------------------------------------------------
  222. class WeaponBonus
  223. {
  224. public:
  225. enum Field
  226. {
  227. DAMAGE = 0,
  228. RADIUS,
  229. RANGE,
  230. RATE_OF_FIRE,
  231. PRE_ATTACK,
  232. FIELD_COUNT // keep last
  233. };
  234. WeaponBonus()
  235. {
  236. clear();
  237. }
  238. inline void clear()
  239. {
  240. for (int i = 0; i < FIELD_COUNT; ++i)
  241. m_field[i] = 1.0f;
  242. }
  243. inline Real getField(Field f) const { return m_field[f]; }
  244. inline void setField(Field f, Real v) { m_field[f] = v; }
  245. void appendBonuses(WeaponBonus& bonus) const;
  246. private:
  247. Real m_field[FIELD_COUNT];
  248. };
  249. #ifdef DEFINE_WEAPONBONUSFIELD_NAMES
  250. static const char *TheWeaponBonusFieldNames[] =
  251. {
  252. "DAMAGE",
  253. "RADIUS",
  254. "RANGE",
  255. "RATE_OF_FIRE",
  256. "PRE_ATTACK",
  257. NULL
  258. };
  259. #endif
  260. //-------------------------------------------------------------------------------------------------
  261. class WeaponBonusSet : public MemoryPoolObject
  262. {
  263. MEMORY_POOL_GLUE_WITH_USERLOOKUP_CREATE( WeaponBonusSet, "WeaponBonusSet" )
  264. private:
  265. WeaponBonus m_bonus[WEAPONBONUSCONDITION_COUNT];
  266. public:
  267. void appendBonuses(WeaponBonusConditionFlags flags, WeaponBonus& bonus) const;
  268. void parseWeaponBonusSet(INI* ini);
  269. static void parseWeaponBonusSet(INI* ini, void *instance, void* /*store*/, const void* /*userData*/);
  270. static void parseWeaponBonusSetPtr(INI* ini, void *instance, void* /*store*/, const void* /*userData*/);
  271. };
  272. EMPTY_DTOR(WeaponBonusSet)
  273. //-------------------------------------------------------------------------------------------------
  274. struct HistoricWeaponDamageInfo
  275. {
  276. // The time and location this weapon was fired
  277. UnsignedInt frame;
  278. Coord3D location;
  279. HistoricWeaponDamageInfo(UnsignedInt f, const Coord3D& l) :
  280. frame(f), location(l)
  281. {
  282. }
  283. };
  284. typedef std::list<HistoricWeaponDamageInfo> HistoricWeaponDamageList;
  285. //-------------------------------------------------------------------------------------------------
  286. class WeaponTemplate : public MemoryPoolObject
  287. {
  288. friend class WeaponStore;
  289. MEMORY_POOL_GLUE_WITH_USERLOOKUP_CREATE( WeaponTemplate, "WeaponTemplate" )
  290. public:
  291. WeaponTemplate();
  292. // virtual destructor declared by memory pool
  293. void reset( void );
  294. void friend_setNextTemplate(WeaponTemplate *nextTemplate) { m_nextTemplate = nextTemplate; }
  295. WeaponTemplate *friend_clearNextTemplate( void ) { WeaponTemplate *ret = m_nextTemplate; m_nextTemplate = NULL; return ret; }
  296. Bool isOverride( void ) { return m_nextTemplate != NULL; }
  297. /// field table for loading the values from an INI
  298. inline const FieldParse *getFieldParse() const { return TheWeaponTemplateFieldParseTable; }
  299. /**
  300. fire the weapon. return the logic-frame in which the damage will be dealt.
  301. If the damage will be determined at an indeterminate later date (eg, via Projectile),
  302. or will never be dealt (eg, target was out of range), return zero.
  303. You may not pass null for source or target.
  304. */
  305. UnsignedInt fireWeaponTemplate
  306. (
  307. const Object *sourceObj,
  308. WeaponSlotType wslot,
  309. Int specificBarrelToUse,
  310. const Object *victimObj,
  311. const Coord3D* victimPos,
  312. const WeaponBonus& bonus,
  313. Bool isProjectileDetonation,
  314. Bool ignoreRanges,
  315. Weapon *firingWeapon,
  316. ObjectID* projectileID
  317. ) const;
  318. /**
  319. return the estimate damage that would be done to the given target, taking bonuses, armor, etc
  320. into account. (this isn't guaranteed to be 100% accurate; it is intended to be used to
  321. decide which weapon should be used when a unit has multiple weapons.) Note that it DOES NOT
  322. take weapon range into account -- it ASSUMES that the victim is within range!
  323. */
  324. Real estimateWeaponTemplateDamage(
  325. const Object *sourceObj,
  326. const Object *victimObj,
  327. const Coord3D* victimPos,
  328. const WeaponBonus& bonus
  329. ) const;
  330. Real getAttackRange(const WeaponBonus& bonus) const;
  331. Real getUnmodifiedAttackRange() const;
  332. Real getMinimumAttackRange() const;
  333. Int getDelayBetweenShots(const WeaponBonus& bonus) const;
  334. Int getClipReloadTime(const WeaponBonus& bonus) const;
  335. Real getPrimaryDamage(const WeaponBonus& bonus) const;
  336. Real getPrimaryDamageRadius(const WeaponBonus& bonus) const;
  337. Real getSecondaryDamage(const WeaponBonus& bonus) const;
  338. Real getSecondaryDamageRadius(const WeaponBonus& bonus) const;
  339. Int getPreAttackDelay(const WeaponBonus& bonus) const;
  340. Bool isContactWeapon() const;
  341. inline Real getRequestAssistRange() const {return m_requestAssistRange;}
  342. inline AsciiString getName() const { return m_name; }
  343. inline AsciiString getProjectileStreamName() const { return m_projectileStreamName; }
  344. inline AsciiString getLaserName() const { return m_laserName; }
  345. inline NameKeyType getNameKey() const { return m_nameKey; }
  346. inline Real getWeaponSpeed() const { return m_weaponSpeed; }
  347. inline Real getMinWeaponSpeed() const { return m_minWeaponSpeed; }
  348. inline Bool isScaleWeaponSpeed() const { return m_isScaleWeaponSpeed; }
  349. inline Real getWeaponRecoilAmount() const { return m_weaponRecoil; }
  350. inline Real getMinTargetPitch() const { return m_minTargetPitch; }
  351. inline Real getMaxTargetPitch() const { return m_maxTargetPitch; }
  352. inline DamageType getDamageType() const { return m_damageType; }
  353. inline DeathType getDeathType() const { return m_deathType; }
  354. inline Real getContinueAttackRange() const { return m_continueAttackRange; }
  355. inline Real getInfantryInaccuracyDist() const { return m_infantryInaccuracyDist; }
  356. inline Real getAimDelta() const { return m_aimDelta; }
  357. inline Real getScatterRadius() const { return m_scatterRadius; }
  358. inline Real getScatterTargetScalar() const { return m_scatterTargetScalar; }
  359. inline const ThingTemplate* getProjectileTemplate() const { return m_projectileTmpl; }
  360. inline Bool getDamageDealtAtSelfPosition() const { return m_damageDealtAtSelfPosition; }
  361. inline Int getAffectsMask() const { return m_affectsMask; }
  362. inline Int getProjectileCollideMask() const { return m_collideMask; }
  363. inline WeaponReloadType getReloadType() const { return m_reloadType; }
  364. inline WeaponPrefireType getPrefireType() const { return m_prefireType; }
  365. inline Bool getAutoReloadsClip() const { return m_reloadType == AUTO_RELOAD; }
  366. inline Int getClipSize() const { return m_clipSize; }
  367. inline Int getContinuousFireOneShotsNeeded() const { return m_continuousFireOneShotsNeeded; }
  368. inline Int getContinuousFireTwoShotsNeeded() const { return m_continuousFireTwoShotsNeeded; }
  369. inline UnsignedInt getContinuousFireCoastFrames() const { return m_continuousFireCoastFrames; }
  370. inline UnsignedInt getAutoReloadWhenIdleFrames() const { return m_autoReloadWhenIdleFrames; }
  371. inline UnsignedInt getSuspendFXDelay() const { return m_suspendFXDelay; }
  372. inline const FXList* getFireFX(VeterancyLevel v) const { return m_fireFXs[v]; }
  373. inline const FXList* getProjectileDetonateFX(VeterancyLevel v) const { return m_projectileDetonateFXs[v]; }
  374. inline const ObjectCreationList* getFireOCL(VeterancyLevel v) const { return m_fireOCLs[v]; }
  375. inline const ObjectCreationList* getProjectileDetonationOCL(VeterancyLevel v) const { return m_projectileDetonationOCLs[v]; }
  376. inline const ParticleSystemTemplate* getProjectileExhaust(VeterancyLevel v) const { return m_projectileExhausts[v]; }
  377. inline const AudioEventRTS& getFireSound() const { return m_fireSound; }
  378. inline UnsignedInt getFireSoundLoopTime() const { return m_fireSoundLoopTime; }
  379. inline const std::vector<Coord2D>& getScatterTargetsVector() const { return m_scatterTargets; }
  380. inline const WeaponBonusSet* getExtraBonus() const { return m_extraBonus; }
  381. inline Int getShotsPerBarrel() const { return m_shotsPerBarrel; }
  382. inline Int getAntiMask() const { return m_antiMask; }
  383. inline Bool isLeechRangeWeapon() const { return m_leechRangeWeapon; }
  384. inline Bool isCapableOfFollowingWaypoint() const { return m_capableOfFollowingWaypoint; }
  385. inline Bool isShowsAmmoPips() const { return m_isShowsAmmoPips; }
  386. inline Bool isPlayFXWhenStealthed() const { return m_playFXWhenStealthed; }
  387. Bool shouldProjectileCollideWith(
  388. const Object* projectileLauncher,
  389. const Object* projectile,
  390. const Object* thingWeCollidedWith,
  391. ObjectID intendedVictimID // could be INVALID_ID for a position-shot
  392. ) const;
  393. void postProcessLoad();
  394. protected:
  395. // actually deal out the damage.
  396. void dealDamageInternal(ObjectID sourceID, ObjectID victimID, const Coord3D *pos, const WeaponBonus& bonus, Bool isProjectileDetonation) const;
  397. void trimOldHistoricDamage() const;
  398. private:
  399. // NOTE: m_nextTemplate will be cleaned up if it is NON-NULL.
  400. WeaponTemplate *m_nextTemplate;
  401. static void parseWeaponBonusSet( INI* ini, void *instance, void * /*store*/, const void* /*userData*/ );
  402. static void parseScatterTarget( INI* ini, void *instance, void * /*store*/, const void* /*userData*/ );
  403. static void parseShotDelay( INI* ini, void *instance, void * /*store*/, const void* /*userData*/ );
  404. static const FieldParse TheWeaponTemplateFieldParseTable[]; ///< the parse table for INI definition
  405. AsciiString m_name; ///< name for this weapon
  406. NameKeyType m_nameKey; ///< unique name key for this weapon template
  407. AsciiString m_projectileStreamName; ///< Name of object that tracks are stream, if we have one
  408. AsciiString m_laserName; ///< Name of the laser object that persists.
  409. Real m_primaryDamage; ///< primary damage amount
  410. Real m_primaryDamageRadius; ///< primary damage radius range
  411. Real m_secondaryDamage; ///< secondary damage amount
  412. Real m_secondaryDamageRadius; ///< secondary damage radius range
  413. Real m_attackRange; ///< max distance the weapon can deal damage
  414. Real m_minimumAttackRange; ///< Min distance the weapon should be fired from
  415. Real m_requestAssistRange; ///< My object will look this far around to get people to join in the attack.
  416. Real m_aimDelta; ///< when aiming, consider yourself "aimed" if you are within +/- this much of an angle
  417. Real m_scatterRadius; ///< Radius of area actual fire point will be in, default is zero for no deviation
  418. Real m_scatterTargetScalar; ///< Radius of area covered by the coordinates in the scatterTarget table
  419. std::vector<Coord2D> m_scatterTargets; ///< instead of pure randomness, this is the list of places I will randomly choose from to attack
  420. DamageType m_damageType; ///< damage type enum
  421. DeathType m_deathType; ///< death type enum
  422. Real m_weaponSpeed; ///< speed of damage travel, in dist/frame
  423. Real m_minWeaponSpeed; ///< speed of damage travel, in dist/frame
  424. Bool m_isScaleWeaponSpeed; ///< Scale from min to normal based on range (for lobbers)
  425. Real m_weaponRecoil; ///< amt of recoil caused to firer, in rads
  426. Real m_minTargetPitch; ///< min pitch from source->victim allowable in order to target
  427. Real m_maxTargetPitch; ///< max pitch from source->victim allowable in order to target
  428. AsciiString m_projectileName; ///< if projectile, object name to "fire"
  429. const ThingTemplate* m_projectileTmpl; ///< direct access to projectile object type to "fire"
  430. AsciiString m_fireOCLNames[LEVEL_COUNT]; ///< Name of OCL to create at firing
  431. AsciiString m_projectileDetonationOCLNames[LEVEL_COUNT]; ///< Name of OCL to create at firing at missile's end
  432. const ParticleSystemTemplate* m_projectileExhausts[LEVEL_COUNT]; ///< Templates of particle systems for projectile exhaust
  433. const ObjectCreationList* m_fireOCLs[LEVEL_COUNT]; ///< Post-loaded lookup of name string for ease and speed
  434. const ObjectCreationList* m_projectileDetonationOCLs[LEVEL_COUNT]; ///< Post-loaded lookup of name string for ease and speed (and subsystem init order)
  435. const FXList* m_fireFXs[LEVEL_COUNT]; ///< weapon is fired fx
  436. const FXList* m_projectileDetonateFXs[LEVEL_COUNT]; ///< if we have a projectile, fx for projectile blowing up
  437. AudioEventRTS m_fireSound; ///< weapon is fired sound
  438. UnsignedInt m_fireSoundLoopTime; ///< if nonzero, num frames for looping of fire sound
  439. WeaponBonusSet* m_extraBonus; ///< optional extra per-weapon bonus
  440. Int m_clipSize; ///< number of 'shots' in a clip
  441. Int m_clipReloadTime; ///< when 'clip' is empty, how long it takes to reload (frames)
  442. Int m_minDelayBetweenShots; ///< min time allowed between firing single shots (frames)
  443. Int m_maxDelayBetweenShots; ///< max time allowed between firing single shots (frames)
  444. Int m_continuousFireOneShotsNeeded; ///< How many consecutive shots will give my owner the ContinuousFire Property
  445. Int m_continuousFireTwoShotsNeeded; ///< How many consecutive shots will give my owner the ContinuousFireTwo Property
  446. UnsignedInt m_continuousFireCoastFrames;///< How long after we should have shot should we start to wind down from Continuous fire mode
  447. UnsignedInt m_autoReloadWhenIdleFrames; ///< How long we have to wait after our last shot to force a reload
  448. Int m_shotsPerBarrel; ///< If non zero, don't cycle through your launch points every shot, mod the shot by this to get even chucks of firing
  449. Int m_antiMask; ///< what we can target
  450. Int m_affectsMask; ///< what we can affect
  451. Int m_collideMask; ///< what we can collide with (projectiles only)
  452. Bool m_damageDealtAtSelfPosition; ///< if T, weapon damage is done at source's position, not victim's pos. (useful for suicide weapons.)
  453. WeaponReloadType m_reloadType; ///< does the weapon auto-reload a clip when empty?
  454. WeaponPrefireType m_prefireType; ///< The way this weapon handles its prefire delay
  455. UnsignedInt m_historicBonusTime; ///< if 'count' instances of this weapon do damage within 'time' and 'radius' from each other, fire the historic bonus weapon
  456. Real m_historicBonusRadius; ///< see above
  457. Int m_historicBonusCount; ///< see above
  458. const WeaponTemplate* m_historicBonusWeapon; ///< see above
  459. Bool m_leechRangeWeapon; ///< once the weapon has fired once at the proper range, the weapon gains unlimited range for the remainder of the attack cycle
  460. Bool m_capableOfFollowingWaypoint; ///< determines if the weapon is capable of following a waypoint path.
  461. Bool m_isShowsAmmoPips; ///< shows ammo pips
  462. Bool m_allowAttackGarrisonedBldgs; ///< allow attacks on garrisoned bldgs, even if estimated damage would be zero
  463. Bool m_playFXWhenStealthed; ///< Ignores rule about not playing FX when stealthed
  464. Int m_preAttackDelay; ///< doesn't attack until preAttack delay is finish (triggering detonation, aiming a snipe shot, etc.)
  465. Real m_continueAttackRange; ///< if nonzero: when you destroy something, look for a similar obj controlled by same player to attack (used mainly for mine-clearing)
  466. Real m_infantryInaccuracyDist; ///< When this weapon is used against infantry, it can randomly miss by as much as this distance.
  467. UnsignedInt m_suspendFXDelay; ///< The fx can be suspended for any delay, in frames, then they will execute as normal
  468. mutable HistoricWeaponDamageList m_historicDamage;
  469. };
  470. // ---------------------------------------------------------
  471. class Weapon : public MemoryPoolObject,
  472. public Snapshot
  473. {
  474. friend class WeaponStore;
  475. MEMORY_POOL_GLUE_WITH_USERLOOKUP_CREATE( Weapon, "Weapon" )
  476. private:
  477. // only our friend (WeaponStore) is allowed to use our ctor
  478. // Weapon(); -- nope, no default ctor anymore! (srj)
  479. Weapon(const Weapon& that);
  480. Weapon& operator=(const Weapon& that);
  481. protected:
  482. // snapshot methods
  483. virtual void crc( Xfer *xfer );
  484. virtual void xfer( Xfer *xfer );
  485. virtual void loadPostProcess( void );
  486. public:
  487. //~Weapon();
  488. // return true if we auto-reloaded our clip after firing.
  489. Bool fireWeapon(const Object *source, Object *target, ObjectID* projectileID = NULL);
  490. // return true if we auto-reloaded our clip after firing.
  491. Bool fireWeapon(const Object *source, const Coord3D* pos, ObjectID* projectileID = NULL);
  492. void fireProjectileDetonationWeapon(const Object *source, Object *target, WeaponBonusConditionFlags extraBonusFlags);
  493. void fireProjectileDetonationWeapon(const Object *source, const Coord3D* pos, WeaponBonusConditionFlags extraBonusFlags);
  494. void preFireWeapon( const Object *source, const Object *victim );
  495. //Currently, this function was added to allow a script to force fire a weapon,
  496. //and immediately gain control of the weapon that was fired to give it special orders...
  497. Object* forceFireWeapon( const Object *source, const Coord3D *pos );
  498. /**
  499. return the estimate damage that would be done to the given target, taking bonuses, armor, etc
  500. into account. (this isn't guaranteed to be 100% accurate; it is intended to be used to
  501. decide which weapon should be used when a unit has multiple weapons.) Note that it DOES NOT
  502. take weapon range into account -- it ASSUMES that the victim is within range!
  503. */
  504. Real estimateWeaponDamage(const Object *source, const Object *target)
  505. {
  506. return estimateWeaponDamage(source, target, NULL);
  507. }
  508. Real estimateWeaponDamage(const Object *source, const Coord3D* pos)
  509. {
  510. return estimateWeaponDamage(source, NULL, pos);
  511. }
  512. /** return true if the target is within attack range, false otherwise.
  513. */
  514. Bool isWithinAttackRange(const Object *source, const Object *target) const;
  515. Bool isWithinAttackRange(const Object *source, const Coord3D* pos) const;
  516. Bool isTooClose(const Object *source, const Object *target) const;
  517. Bool isTooClose(const Object *source, const Coord3D *pos) const;
  518. Bool isGoalPosWithinAttackRange(const Object *source, const Coord3D* goalPos, const Object *target, const Coord3D* targetPos) const;
  519. //Used only by garrison contains that move objects around before doing the range check.
  520. //If target object is specified, we'll use his position, but if it's NULL we will use the
  521. //target position passed in.
  522. //NOTE: This is not a user friendly function -- use with caution if at all! -- Kris
  523. Bool isSourceObjectWithGoalPositionWithinAttackRange(const Object *source, const Coord3D *goalPos, const Object *target, const Coord3D *targetPos) const;
  524. /**
  525. Compute a target position from which 'source' can target 'target'. Note that this doesn't
  526. guarantee that source can actually move to the location, it just guarantees that the
  527. target position is plausibly within attack range. returns TRUE if the source's current pos
  528. is already close enough (in which case that current pos is stuffed into the return arg).
  529. */
  530. Bool computeApproachTarget(const Object *source, const Object *target, const Coord3D *pos, Real angleOffset, Coord3D& approachTargetPos) const;
  531. /**
  532. note that "load" makes the ammo instantly available, while "reload" keeps the weapon in the RELOADING
  533. state until the clip-reload-time is up. Normally you should use "load" only for newly-created
  534. units, who presumably come into existence with fully loaded weapons.
  535. */
  536. void loadAmmoNow(const Object *source);
  537. void reloadAmmo(const Object *source);
  538. WeaponStatus getStatus() const;
  539. /// Some AI needs to know when the soonest I can possibly next shoot. Bonuses have been figured into this number already.
  540. UnsignedInt getPossibleNextShotFrame() const { return m_whenWeCanFireAgain; }
  541. UnsignedInt getPreAttackFinishedFrame() const { return m_whenPreAttackFinished; }
  542. Real getPercentReadyToFire() const;
  543. // do not ever use this unless you are weaponset.cpp
  544. void setPossibleNextShotFrame( UnsignedInt frameNum ) { m_whenWeCanFireAgain = frameNum; }
  545. void setPreAttackFinishedFrame( UnsignedInt frameNum ) { m_whenPreAttackFinished = frameNum; }
  546. // we must pass the source object for these (and for ANY FUTURE ADDITIONS)
  547. // so that we can take the source's weapon bonuses, if any, into account.
  548. // Also note: you should RARELY need to call getAttackRange. If what you want is to
  549. // determine if you are within attack range, please call isWithinAttackRange instead.
  550. Real getAttackRange(const Object *source) const;
  551. // Returns the max distance between the centerpoints of source & victim for victim to be in range.
  552. Real getAttackDistance(const Object *source, const Object *victim, const Coord3D* victimPos) const;
  553. void newProjectileFired( const Object *sourceObj, const Object *projectile );///<I just made this projectile and may need to keep track of it
  554. Bool isLaser() const { return m_template->getLaserName().isNotEmpty(); }
  555. void createLaser( const Object *sourceObj, const Object *victimObj, const Coord3D *victimPos );
  556. inline const WeaponTemplate* getTemplate() const { return m_template; }
  557. inline WeaponSlotType getWeaponSlot() const { return m_wslot; }
  558. inline AsciiString getName() const { return m_template->getName(); }
  559. inline UnsignedInt getLastShotFrame() const { return m_lastFireFrame; } ///< frame a shot was last fired on
  560. // If we are "reloading", then m_ammoInClip is a lie. It will say full.
  561. inline UnsignedInt getRemainingAmmo() const { return (getStatus() == RELOADING_CLIP) ? 0 : m_ammoInClip; }
  562. inline WeaponReloadType getReloadType() const { return m_template->getReloadType(); }
  563. inline Bool getAutoReloadsClip() const { return m_template->getAutoReloadsClip(); }
  564. inline Real getAimDelta() const { return m_template->getAimDelta(); }
  565. inline Real getScatterRadius() const { return m_template->getScatterRadius(); }
  566. inline Real getScatterTargetScalar() const { return m_template->getScatterTargetScalar(); }
  567. inline Int getAntiMask() const { return m_template->getAntiMask(); }
  568. inline Bool isCapableOfFollowingWaypoint() const { return m_template->isCapableOfFollowingWaypoint(); }
  569. inline Int getContinuousFireOneShotsNeeded() const { return m_template->getContinuousFireOneShotsNeeded(); }
  570. inline Int getContinuousFireTwoShotsNeeded() const { return m_template->getContinuousFireTwoShotsNeeded(); }
  571. inline UnsignedInt getContinuousFireCoastFrames() const { return m_template->getContinuousFireCoastFrames(); }
  572. inline UnsignedInt getAutoReloadWhenIdleFrames() const { return m_template->getAutoReloadWhenIdleFrames(); }
  573. inline const AudioEventRTS& getFireSound() const { return m_template->getFireSound(); }
  574. inline UnsignedInt getFireSoundLoopTime() const { return m_template->getFireSoundLoopTime(); }
  575. inline DamageType getDamageType() const { return m_template->getDamageType(); }
  576. inline DeathType getDeathType() const { return m_template->getDeathType(); }
  577. inline Real getContinueAttackRange() const { return m_template->getContinueAttackRange(); }
  578. inline Bool isShowsAmmoPips() const { return m_template->isShowsAmmoPips(); }
  579. inline Int getClipSize() const { return m_template->getClipSize(); }
  580. // Contact weapons (like car bombs) need to basically collide with their target.
  581. inline Bool isContactWeapon() const { return m_template->isContactWeapon(); }
  582. UnsignedInt getClipReloadTime(const Object *source) const;
  583. Real getPrimaryDamageRadius(const Object *source) const;
  584. Int getPreAttackDelay( const Object *source, const Object *victim ) const;
  585. Bool isDamageWeapon() const;
  586. Bool isPitchLimited() const { return m_pitchLimited; }
  587. Bool isWithinTargetPitch(const Object *source, const Object *victim) const;
  588. //Leech range functionality simply means this weapon has unlimited range temporarily. How it works is if the
  589. //weapon template has the LeechRangeWeapon set, it means that once the unit has closed to standard weapon range
  590. //it fires the weapon, and will be able to hit the target even if it moves out of range! The unit will simply
  591. //stand there. This functionality is used by hack attacks.
  592. void setLeechRangeActive( Bool active ) { m_leechWeaponRangeActive = active; }
  593. Bool hasLeechRange() const { return m_leechWeaponRangeActive; }
  594. void setMaxShotCount(Int maxShots) { m_maxShotCount = maxShots; }
  595. Int getMaxShotCount() const { return m_maxShotCount; }
  596. Bool isClearFiringLineOfSightTerrain(const Object* source, const Object* victim) const;
  597. Bool isClearFiringLineOfSightTerrain(const Object* source, const Coord3D& victimPos) const;
  598. Bool isClearGoalFiringLineOfSightTerrain(const Object* source, const Coord3D& goalPos, const Object* victim) const;
  599. Bool isClearGoalFiringLineOfSightTerrain(const Object* source, const Coord3D& goalPos, const Coord3D& victimPos) const;
  600. static void calcProjectileLaunchPosition(
  601. const Object* launcher,
  602. WeaponSlotType wslot,
  603. Int specificBarrelToUse,
  604. Matrix3D& worldTransform,
  605. Coord3D& worldPos
  606. );
  607. static void positionProjectileForLaunch(
  608. Object* projectile,
  609. const Object *launcher,
  610. WeaponSlotType wslot,
  611. Int specificBarrelToUse
  612. );
  613. /**
  614. special purpose call for jets in airfields: directly set the ammoinclip to a certain
  615. percentage full (note that percent=1.0 is full, NOT percent=100.0!). this will end up
  616. with status as READY_TO_FIRE or OUT_OF_AMMO, but never RELOADING_CLIP!
  617. */
  618. void setClipPercentFull(Real percent, Bool allowReduction);
  619. UnsignedInt getSuspendFXFrame( void ) const { return m_suspendFXFrame; }
  620. protected:
  621. Weapon(const WeaponTemplate* tmpl, WeaponSlotType wslot);
  622. // return true if we auto-reloaded our clip after firing.
  623. Bool privateFireWeapon(
  624. const Object *sourceObj,
  625. Object *victimObj,
  626. const Coord3D* victimPos,
  627. Bool isProjectileDetonation,
  628. Bool ignoreRanges,
  629. WeaponBonusConditionFlags extraBonusFlags,
  630. ObjectID* projectileID
  631. );
  632. Real estimateWeaponDamage(const Object *sourceObj, const Object *victimObj, const Coord3D* victimPos);
  633. void reloadWithBonus(const Object *source, const WeaponBonus& bonus, Bool loadInstantly);
  634. void processRequestAssistance( const Object *requestingObject, Object *victimObject ); ///< Weapons can call for extra attacks from nearby objects
  635. void getFiringLineOfSightOrigin(const Object* source, Coord3D& origin) const;
  636. void computeBonus(const Object *source, WeaponBonusConditionFlags extraBonusFlags, WeaponBonus& bonus) const;
  637. void rebuildScatterTargets();
  638. private:
  639. const WeaponTemplate* m_template; ///< the kind of weapon this is
  640. WeaponSlotType m_wslot; ///< are we primary, secondary, etc. weapon? (used for projectile placement on reload)
  641. mutable WeaponStatus m_status; ///< weapon status
  642. UnsignedInt m_ammoInClip; ///< how many shots left in current clip
  643. UnsignedInt m_whenWeCanFireAgain; ///< the first frame the weapon can fire again
  644. UnsignedInt m_whenPreAttackFinished; ///< the frame the pre attack will complete.
  645. UnsignedInt m_whenLastReloadStarted; ///< the frame the current reload/between-shots began. (only valid if status is RELOADING_CLIP or BETWEEN_FIRING_SHOTS)
  646. UnsignedInt m_lastFireFrame; ///< frame a shot was last fired on
  647. UnsignedInt m_suspendFXFrame; ///< The fireFX can be suspended for any delay, in frames, then they will execute as normal
  648. ObjectID m_projectileStreamID; ///< the object that is tracking our stream if we have one. It can't go away without us.
  649. Int m_maxShotCount; ///< used for limiting consecutive firing
  650. Int m_curBarrel; ///< current barrel used for firing
  651. Int m_numShotsForCurBarrel; ///< how many shots to fire from cur barrel before moving to next barrel
  652. std::vector<Int> m_scatterTargetsUnused; ///< A running memory of which targets I've used, so I can shoot them all at random
  653. Bool m_pitchLimited;
  654. Bool m_leechWeaponRangeActive; ///< This weapon has unlimited range until attack state is aborted!
  655. // setter function for status that should not be used outside this class
  656. void setStatus( WeaponStatus status) { m_status = status; }
  657. };
  658. //-------------------------------------------------------------------------------------------------
  659. /**
  660. The "store" used to hold all the WeaponTemplates in existence. This is usually used when creating
  661. an Object, but can be used at any time after that. (It is explicitly
  662. OK to swap an Object's Weapon out at any given time.)
  663. */
  664. //-------------------------------------------------------------------------------------------------
  665. class WeaponStore : public SubsystemInterface
  666. {
  667. friend class WeaponTemplate;
  668. public:
  669. WeaponStore();
  670. ~WeaponStore();
  671. void init() { };
  672. void postProcessLoad();
  673. void reset();
  674. void update();
  675. /**
  676. Find the WeaponTemplate with the given name. If no such WeaponTemplate exists, return null.
  677. */
  678. const WeaponTemplate *findWeaponTemplate(AsciiString name) const;
  679. const WeaponTemplate *findWeaponTemplateByNameKey( NameKeyType key ) const { return findWeaponTemplatePrivate( key ); }
  680. // this dynamically allocates a new Weapon, which is owned (and must be freed!) by the caller.
  681. inline Weapon* allocateNewWeapon(const WeaponTemplate *tmpl, WeaponSlotType wslot) const
  682. {
  683. return newInstance(Weapon)(tmpl, wslot); // my, that was easy
  684. }
  685. void createAndFireTempWeapon(const WeaponTemplate* w, const Object *source, const Coord3D* pos);
  686. void createAndFireTempWeapon(const WeaponTemplate* w, const Object *source, Object *target);
  687. void handleProjectileDetonation(const WeaponTemplate* w, const Object *source, const Coord3D* pos, WeaponBonusConditionFlags extraBonusFlags);
  688. static void parseWeaponTemplateDefinition(INI* ini);
  689. protected:
  690. WeaponTemplate *findWeaponTemplatePrivate( NameKeyType key ) const;
  691. WeaponTemplate *newWeaponTemplate( AsciiString name );
  692. WeaponTemplate *newOverride( WeaponTemplate *weaponTemplate );
  693. void deleteAllDelayedDamage();
  694. void resetWeaponTemplates( void );
  695. void setDelayedDamage(const WeaponTemplate *weapon, const Coord3D* pos, UnsignedInt whichFrame, ObjectID sourceID, ObjectID victimID, const WeaponBonus& bonus);
  696. private:
  697. /**
  698. WeaponDelayedDamageInfo is a utility class used by the WeaponStore to keep track
  699. of what damage will need to be dealt in the future. It is never used for Projectile
  700. weaponry, but rather for weapons that do damage in the short-term future without
  701. instantiating full-fledged Objects as a bullet. (e.g., tank shells do this.)
  702. */
  703. struct WeaponDelayedDamageInfo
  704. {
  705. public:
  706. const WeaponTemplate *m_delayedWeapon; ///< if delayed damage is pending, the weapon to deal the damage
  707. Coord3D m_delayDamagePos; ///< where to do the delay damage when it's time
  708. UnsignedInt m_delayDamageFrame; ///< frames we do the damage
  709. ObjectID m_delaySourceID; ///< who dealt the damage (by ID since it might be dead due to delay)
  710. ObjectID m_delayIntendedVictimID; ///< who the damage was intended for (or zero if no specific target)
  711. WeaponBonus m_bonus; ///< the weapon bonus to use
  712. };
  713. std::vector<WeaponTemplate*> m_weaponTemplateVector;
  714. std::list<WeaponDelayedDamageInfo> m_weaponDDI;
  715. };
  716. // EXTERNALS //////////////////////////////////////////////////////////////////////////////////////
  717. extern WeaponStore *TheWeaponStore;
  718. #endif // __WEAPON_H_