Weapon.h 40 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889
  1. /*
  2. ** Command & Conquer Generals Zero Hour(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 ; Removed protection so other clases can use these strings... not sure why this was protected in the 1st place
  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_TARGET_FAERIE_FIRE,
  183. WEAPONBONUSCONDITION_FANATICISM, // FOR THE NEW GC INFANTRY GENERAL... adds to nationalism
  184. WEAPONBONUSCONDITION_FRENZY_ONE,
  185. WEAPONBONUSCONDITION_FRENZY_TWO,
  186. WEAPONBONUSCONDITION_FRENZY_THREE,
  187. WEAPONBONUSCONDITION_COUNT
  188. };
  189. #ifdef DEFINE_WEAPONBONUSCONDITION_NAMES
  190. static const char *TheWeaponBonusNames[] =
  191. {
  192. // This is a RHS enum (weapon.ini will have WeaponBonus = IT) so it is all caps
  193. "GARRISONED",
  194. "HORDE",
  195. "CONTINUOUS_FIRE_MEAN",
  196. "CONTINUOUS_FIRE_FAST",
  197. "NATIONALISM",
  198. "PLAYER_UPGRADE",
  199. "DRONE_SPOTTING",
  200. #ifdef ALLOW_DEMORALIZE
  201. "DEMORALIZED",
  202. #else
  203. "DEMORALIZED_OBSOLETE",
  204. #endif
  205. "ENTHUSIASTIC",
  206. "VETERAN",
  207. "ELITE",
  208. "HERO",
  209. "BATTLEPLAN_BOMBARDMENT",
  210. "BATTLEPLAN_HOLDTHELINE",
  211. "BATTLEPLAN_SEARCHANDDESTROY",
  212. "SUBLIMINAL",
  213. "SOLO_HUMAN_EASY",
  214. "SOLO_HUMAN_NORMAL",
  215. "SOLO_HUMAN_HARD",
  216. "SOLO_AI_EASY",
  217. "SOLO_AI_NORMAL",
  218. "SOLO_AI_HARD",
  219. "TARGET_FAERIE_FIRE",
  220. "FANATICISM", // FOR THE NEW GC INFANTRY GENERAL... adds to nationalism
  221. "FRENZY_ONE",
  222. "FRENZY_TWO",
  223. "FRENZY_THREE",
  224. NULL
  225. };
  226. #endif
  227. // For WeaponBonusConditionFlags
  228. // part of detangling
  229. #include "GameLogic/WeaponBonusConditionFlags.h"
  230. #include "GameLogic/WeaponStatus.h"
  231. //-------------------------------------------------------------------------------------------------
  232. class WeaponBonus
  233. {
  234. public:
  235. enum Field
  236. {
  237. DAMAGE = 0,
  238. RADIUS,
  239. RANGE,
  240. RATE_OF_FIRE,
  241. PRE_ATTACK,
  242. FIELD_COUNT // keep last
  243. };
  244. WeaponBonus()
  245. {
  246. clear();
  247. }
  248. inline void clear()
  249. {
  250. for (int i = 0; i < FIELD_COUNT; ++i)
  251. m_field[i] = 1.0f;
  252. }
  253. inline Real getField(Field f) const { return m_field[f]; }
  254. inline void setField(Field f, Real v) { m_field[f] = v; }
  255. void appendBonuses(WeaponBonus& bonus) const;
  256. private:
  257. Real m_field[FIELD_COUNT];
  258. };
  259. #ifdef DEFINE_WEAPONBONUSFIELD_NAMES
  260. static const char *TheWeaponBonusFieldNames[] =
  261. {
  262. "DAMAGE",
  263. "RADIUS",
  264. "RANGE",
  265. "RATE_OF_FIRE",
  266. "PRE_ATTACK",
  267. NULL
  268. };
  269. #endif
  270. //-------------------------------------------------------------------------------------------------
  271. class WeaponBonusSet : public MemoryPoolObject
  272. {
  273. MEMORY_POOL_GLUE_WITH_USERLOOKUP_CREATE( WeaponBonusSet, "WeaponBonusSet" )
  274. private:
  275. WeaponBonus m_bonus[WEAPONBONUSCONDITION_COUNT];
  276. public:
  277. void appendBonuses(WeaponBonusConditionFlags flags, WeaponBonus& bonus) const;
  278. void parseWeaponBonusSet(INI* ini);
  279. static void parseWeaponBonusSet(INI* ini, void *instance, void* /*store*/, const void* /*userData*/);
  280. static void parseWeaponBonusSetPtr(INI* ini, void *instance, void* /*store*/, const void* /*userData*/);
  281. };
  282. EMPTY_DTOR(WeaponBonusSet)
  283. //-------------------------------------------------------------------------------------------------
  284. struct HistoricWeaponDamageInfo
  285. {
  286. // The time and location this weapon was fired
  287. UnsignedInt frame;
  288. Coord3D location;
  289. HistoricWeaponDamageInfo(UnsignedInt f, const Coord3D& l) :
  290. frame(f), location(l)
  291. {
  292. }
  293. };
  294. typedef std::list<HistoricWeaponDamageInfo> HistoricWeaponDamageList;
  295. //-------------------------------------------------------------------------------------------------
  296. class WeaponTemplate : public MemoryPoolObject
  297. {
  298. friend class WeaponStore;
  299. MEMORY_POOL_GLUE_WITH_USERLOOKUP_CREATE( WeaponTemplate, "WeaponTemplate" )
  300. public:
  301. WeaponTemplate();
  302. // virtual destructor declared by memory pool
  303. void reset( void );
  304. void friend_setNextTemplate(WeaponTemplate *nextTemplate) { m_nextTemplate = nextTemplate; }
  305. WeaponTemplate *friend_clearNextTemplate( void ) { WeaponTemplate *ret = m_nextTemplate; m_nextTemplate = NULL; return ret; }
  306. Bool isOverride( void ) { return m_nextTemplate != NULL; }
  307. /// field table for loading the values from an INI
  308. inline const FieldParse *getFieldParse() const { return TheWeaponTemplateFieldParseTable; }
  309. /**
  310. fire the weapon. return the logic-frame in which the damage will be dealt.
  311. If the damage will be determined at an indeterminate later date (eg, via Projectile),
  312. or will never be dealt (eg, target was out of range), return zero.
  313. You may not pass null for source or target.
  314. */
  315. UnsignedInt fireWeaponTemplate
  316. (
  317. const Object *sourceObj,
  318. WeaponSlotType wslot,
  319. Int specificBarrelToUse,
  320. Object *victimObj,
  321. const Coord3D* victimPos,
  322. const WeaponBonus& bonus,
  323. Bool isProjectileDetonation,
  324. Bool ignoreRanges,
  325. Weapon *firingWeapon,
  326. ObjectID* projectileID,
  327. Bool inflictDamage
  328. ) const;
  329. /**
  330. return the estimate damage that would be done to the given target, taking bonuses, armor, etc
  331. into account. (this isn't guaranteed to be 100% accurate; it is intended to be used to
  332. decide which weapon should be used when a unit has multiple weapons.) Note that it DOES NOT
  333. take weapon range into account -- it ASSUMES that the victim is within range!
  334. */
  335. Real estimateWeaponTemplateDamage(
  336. const Object *sourceObj,
  337. const Object *victimObj,
  338. const Coord3D* victimPos,
  339. const WeaponBonus& bonus
  340. ) const;
  341. Real getAttackRange(const WeaponBonus& bonus) const;
  342. Real getUnmodifiedAttackRange() const;
  343. Real getMinimumAttackRange() const;
  344. Int getDelayBetweenShots(const WeaponBonus& bonus) const;
  345. Int getClipReloadTime(const WeaponBonus& bonus) const;
  346. Real getPrimaryDamage(const WeaponBonus& bonus) const;
  347. Real getPrimaryDamageRadius(const WeaponBonus& bonus) const;
  348. Real getSecondaryDamage(const WeaponBonus& bonus) const;
  349. Real getSecondaryDamageRadius(const WeaponBonus& bonus) const;
  350. Int getPreAttackDelay(const WeaponBonus& bonus) const;
  351. Bool isContactWeapon() const;
  352. inline Real getShockWaveAmount() const { return m_shockWaveAmount; }
  353. inline Real getShockWaveRadius() const { return m_shockWaveRadius; }
  354. inline Real getShockWaveTaperOff() const { return m_shockWaveTaperOff; }
  355. inline Real getRequestAssistRange() const {return m_requestAssistRange;}
  356. inline AsciiString getName() const { return m_name; }
  357. inline AsciiString getProjectileStreamName() const { return m_projectileStreamName; }
  358. inline AsciiString getLaserName() const { return m_laserName; }
  359. inline const AsciiString& getLaserBoneName() const { return m_laserBoneName; }
  360. inline NameKeyType getNameKey() const { return m_nameKey; }
  361. inline Real getWeaponSpeed() const { return m_weaponSpeed; }
  362. inline Real getMinWeaponSpeed() const { return m_minWeaponSpeed; }
  363. inline Bool isScaleWeaponSpeed() const { return m_isScaleWeaponSpeed; }
  364. inline Real getWeaponRecoilAmount() const { return m_weaponRecoil; }
  365. inline Real getMinTargetPitch() const { return m_minTargetPitch; }
  366. inline Real getMaxTargetPitch() const { return m_maxTargetPitch; }
  367. inline Real getRadiusDamageAngle() const { return m_radiusDamageAngle; }
  368. inline DamageType getDamageType() const { return m_damageType; }
  369. inline ObjectStatusTypes getDamageStatusType() const { return m_damageStatusType; }
  370. inline DeathType getDeathType() const { return m_deathType; }
  371. inline Real getContinueAttackRange() const { return m_continueAttackRange; }
  372. inline Real getInfantryInaccuracyDist() const { return m_infantryInaccuracyDist; }
  373. inline Real getAimDelta() const { return m_aimDelta; }
  374. inline Real getScatterRadius() const { return m_scatterRadius; }
  375. inline Real getScatterTargetScalar() const { return m_scatterTargetScalar; }
  376. inline const ThingTemplate* getProjectileTemplate() const { return m_projectileTmpl; }
  377. inline Bool getDamageDealtAtSelfPosition() const { return m_damageDealtAtSelfPosition; }
  378. inline Int getAffectsMask() const { return m_affectsMask; }
  379. inline Int getProjectileCollideMask() const { return m_collideMask; }
  380. inline WeaponReloadType getReloadType() const { return m_reloadType; }
  381. inline WeaponPrefireType getPrefireType() const { return m_prefireType; }
  382. inline Bool getAutoReloadsClip() const { return m_reloadType == AUTO_RELOAD; }
  383. inline Int getClipSize() const { return m_clipSize; }
  384. inline Int getContinuousFireOneShotsNeeded() const { return m_continuousFireOneShotsNeeded; }
  385. inline Int getContinuousFireTwoShotsNeeded() const { return m_continuousFireTwoShotsNeeded; }
  386. inline UnsignedInt getContinuousFireCoastFrames() const { return m_continuousFireCoastFrames; }
  387. inline UnsignedInt getAutoReloadWhenIdleFrames() const { return m_autoReloadWhenIdleFrames; }
  388. inline UnsignedInt getSuspendFXDelay() const { return m_suspendFXDelay; }
  389. inline const FXList* getFireFX(VeterancyLevel v) const { return m_fireFXs[v]; }
  390. inline const FXList* getProjectileDetonateFX(VeterancyLevel v) const { return m_projectileDetonateFXs[v]; }
  391. inline const ObjectCreationList* getFireOCL(VeterancyLevel v) const { return m_fireOCLs[v]; }
  392. inline const ObjectCreationList* getProjectileDetonationOCL(VeterancyLevel v) const { return m_projectileDetonationOCLs[v]; }
  393. inline const ParticleSystemTemplate* getProjectileExhaust(VeterancyLevel v) const { return m_projectileExhausts[v]; }
  394. inline const AudioEventRTS& getFireSound() const { return m_fireSound; }
  395. inline UnsignedInt getFireSoundLoopTime() const { return m_fireSoundLoopTime; }
  396. inline const std::vector<Coord2D>& getScatterTargetsVector() const { return m_scatterTargets; }
  397. inline const WeaponBonusSet* getExtraBonus() const { return m_extraBonus; }
  398. inline Int getShotsPerBarrel() const { return m_shotsPerBarrel; }
  399. inline Int getAntiMask() const { return m_antiMask; }
  400. inline Bool isLeechRangeWeapon() const { return m_leechRangeWeapon; }
  401. inline Bool isCapableOfFollowingWaypoint() const { return m_capableOfFollowingWaypoint; }
  402. inline Bool isShowsAmmoPips() const { return m_isShowsAmmoPips; }
  403. inline Bool isPlayFXWhenStealthed() const { return m_playFXWhenStealthed; }
  404. inline Bool getDieOnDetonate() const { return m_dieOnDetonate; }
  405. Bool shouldProjectileCollideWith(
  406. const Object* projectileLauncher,
  407. const Object* projectile,
  408. const Object* thingWeCollidedWith,
  409. ObjectID intendedVictimID // could be INVALID_ID for a position-shot
  410. ) const;
  411. void postProcessLoad();
  412. protected:
  413. // actually deal out the damage.
  414. void dealDamageInternal(ObjectID sourceID, ObjectID victimID, const Coord3D *pos, const WeaponBonus& bonus, Bool isProjectileDetonation) const;
  415. void trimOldHistoricDamage() const;
  416. private:
  417. // NOTE: m_nextTemplate will be cleaned up if it is NON-NULL.
  418. WeaponTemplate *m_nextTemplate;
  419. static void parseWeaponBonusSet( INI* ini, void *instance, void * /*store*/, const void* /*userData*/ );
  420. static void parseScatterTarget( INI* ini, void *instance, void * /*store*/, const void* /*userData*/ );
  421. static void parseShotDelay( INI* ini, void *instance, void * /*store*/, const void* /*userData*/ );
  422. static const FieldParse TheWeaponTemplateFieldParseTable[]; ///< the parse table for INI definition
  423. AsciiString m_name; ///< name for this weapon
  424. NameKeyType m_nameKey; ///< unique name key for this weapon template
  425. AsciiString m_projectileStreamName; ///< Name of object that tracks are stream, if we have one
  426. AsciiString m_laserName; ///< Name of the laser object that persists.
  427. AsciiString m_laserBoneName; ///< Where to put the laser object
  428. Real m_primaryDamage; ///< primary damage amount
  429. Real m_primaryDamageRadius; ///< primary damage radius range
  430. Real m_secondaryDamage; ///< secondary damage amount
  431. Real m_secondaryDamageRadius; ///< secondary damage radius range
  432. Real m_shockWaveAmount; ///( How much shockwave generated
  433. Real m_shockWaveRadius; ///( How far shockwave effect affects objects
  434. Real m_shockWaveTaperOff; ///( How much shockwave is left at the tip of the shockwave radius
  435. Real m_attackRange; ///< max distance the weapon can deal damage
  436. Real m_minimumAttackRange; ///< Min distance the weapon should be fired from
  437. Real m_requestAssistRange; ///< My object will look this far around to get people to join in the attack.
  438. Real m_aimDelta; ///< when aiming, consider yourself "aimed" if you are within +/- this much of an angle
  439. Real m_scatterRadius; ///< Radius of area actual fire point will be in, default is zero for no deviation
  440. Real m_scatterTargetScalar; ///< Radius of area covered by the coordinates in the scatterTarget table
  441. std::vector<Coord2D> m_scatterTargets; ///< instead of pure randomness, this is the list of places I will randomly choose from to attack
  442. DamageType m_damageType; ///< damage type enum
  443. DeathType m_deathType; ///< death type enum
  444. Real m_weaponSpeed; ///< speed of damage travel, in dist/frame
  445. Real m_minWeaponSpeed; ///< speed of damage travel, in dist/frame
  446. Bool m_isScaleWeaponSpeed; ///< Scale from min to normal based on range (for lobbers)
  447. Real m_weaponRecoil; ///< amt of recoil caused to firer, in rads
  448. Real m_minTargetPitch; ///< min pitch from source->victim allowable in order to target
  449. Real m_maxTargetPitch; ///< max pitch from source->victim allowable in order to target
  450. Real m_radiusDamageAngle; ///< Damage is directional, so max defelection of straight at target (cone) you do damage
  451. AsciiString m_projectileName; ///< if projectile, object name to "fire"
  452. const ThingTemplate* m_projectileTmpl; ///< direct access to projectile object type to "fire"
  453. AsciiString m_fireOCLNames[LEVEL_COUNT]; ///< Name of OCL to create at firing
  454. AsciiString m_projectileDetonationOCLNames[LEVEL_COUNT]; ///< Name of OCL to create at firing at missile's end
  455. const ParticleSystemTemplate* m_projectileExhausts[LEVEL_COUNT]; ///< Templates of particle systems for projectile exhaust
  456. const ObjectCreationList* m_fireOCLs[LEVEL_COUNT]; ///< Post-loaded lookup of name string for ease and speed
  457. const ObjectCreationList* m_projectileDetonationOCLs[LEVEL_COUNT]; ///< Post-loaded lookup of name string for ease and speed (and subsystem init order)
  458. const FXList* m_fireFXs[LEVEL_COUNT]; ///< weapon is fired fx
  459. const FXList* m_projectileDetonateFXs[LEVEL_COUNT]; ///< if we have a projectile, fx for projectile blowing up
  460. AudioEventRTS m_fireSound; ///< weapon is fired sound
  461. UnsignedInt m_fireSoundLoopTime; ///< if nonzero, num frames for looping of fire sound
  462. WeaponBonusSet* m_extraBonus; ///< optional extra per-weapon bonus
  463. Int m_clipSize; ///< number of 'shots' in a clip
  464. Int m_clipReloadTime; ///< when 'clip' is empty, how long it takes to reload (frames)
  465. Int m_minDelayBetweenShots; ///< min time allowed between firing single shots (frames)
  466. Int m_maxDelayBetweenShots; ///< max time allowed between firing single shots (frames)
  467. Int m_continuousFireOneShotsNeeded; ///< How many consecutive shots will give my owner the ContinuousFire Property
  468. Int m_continuousFireTwoShotsNeeded; ///< How many consecutive shots will give my owner the ContinuousFireTwo Property
  469. UnsignedInt m_continuousFireCoastFrames;///< How long after we should have shot should we start to wind down from Continuous fire mode
  470. UnsignedInt m_autoReloadWhenIdleFrames; ///< How long we have to wait after our last shot to force a reload
  471. 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
  472. Int m_antiMask; ///< what we can target
  473. Int m_affectsMask; ///< what we can affect
  474. Int m_collideMask; ///< what we can collide with (projectiles only)
  475. Bool m_damageDealtAtSelfPosition; ///< if T, weapon damage is done at source's position, not victim's pos. (useful for suicide weapons.)
  476. WeaponReloadType m_reloadType; ///< does the weapon auto-reload a clip when empty?
  477. WeaponPrefireType m_prefireType; ///< The way this weapon handles its prefire delay
  478. UnsignedInt m_historicBonusTime; ///< if 'count' instances of this weapon do damage within 'time' and 'radius' from each other, fire the historic bonus weapon
  479. Real m_historicBonusRadius; ///< see above
  480. Int m_historicBonusCount; ///< see above
  481. const WeaponTemplate* m_historicBonusWeapon; ///< see above
  482. 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
  483. Bool m_capableOfFollowingWaypoint; ///< determines if the weapon is capable of following a waypoint path.
  484. Bool m_isShowsAmmoPips; ///< shows ammo pips
  485. Bool m_allowAttackGarrisonedBldgs; ///< allow attacks on garrisoned bldgs, even if estimated damage would be zero
  486. Bool m_playFXWhenStealthed; ///< Ignores rule about not playing FX when stealthed
  487. Int m_preAttackDelay; ///< doesn't attack until preAttack delay is finish (triggering detonation, aiming a snipe shot, etc.)
  488. 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)
  489. Real m_infantryInaccuracyDist; ///< When this weapon is used against infantry, it can randomly miss by as much as this distance.
  490. ObjectStatusTypes m_damageStatusType; ///< If our damage is Status damage, the status we apply
  491. UnsignedInt m_suspendFXDelay; ///< The fx can be suspended for any delay, in frames, then they will execute as normal
  492. Bool m_dieOnDetonate;
  493. mutable HistoricWeaponDamageList m_historicDamage;
  494. };
  495. // ---------------------------------------------------------
  496. class Weapon : public MemoryPoolObject,
  497. public Snapshot
  498. {
  499. friend class WeaponStore;
  500. MEMORY_POOL_GLUE_WITH_USERLOOKUP_CREATE( Weapon, "Weapon" )
  501. private:
  502. // only our friend (WeaponStore) is allowed to use our ctor
  503. // Weapon(); -- nope, no default ctor anymore! (srj)
  504. Weapon(const Weapon& that);
  505. Weapon& operator=(const Weapon& that);
  506. protected:
  507. // snapshot methods
  508. virtual void crc( Xfer *xfer );
  509. virtual void xfer( Xfer *xfer );
  510. virtual void loadPostProcess( void );
  511. public:
  512. //~Weapon();
  513. // return true if we auto-reloaded our clip after firing.
  514. Bool fireWeapon(const Object *source, Object *target, ObjectID* projectileID = NULL);
  515. // return true if we auto-reloaded our clip after firing.
  516. Bool fireWeapon(const Object *source, const Coord3D* pos, ObjectID* projectileID = NULL);
  517. void fireProjectileDetonationWeapon(const Object *source, Object *target, WeaponBonusConditionFlags extraBonusFlags, Bool inflictDamage = TRUE );
  518. void fireProjectileDetonationWeapon(const Object *source, const Coord3D* pos, WeaponBonusConditionFlags extraBonusFlags, Bool inflictDamage = TRUE );
  519. void preFireWeapon( const Object *source, const Object *victim );
  520. //Currently, this function was added to allow a script to force fire a weapon,
  521. //and immediately gain control of the weapon that was fired to give it special orders...
  522. Object* forceFireWeapon( const Object *source, const Coord3D *pos );
  523. /**
  524. return the estimate damage that would be done to the given target, taking bonuses, armor, etc
  525. into account. (this isn't guaranteed to be 100% accurate; it is intended to be used to
  526. decide which weapon should be used when a unit has multiple weapons.) Note that it DOES NOT
  527. take weapon range into account -- it ASSUMES that the victim is within range!
  528. */
  529. Real estimateWeaponDamage(const Object *source, const Object *target)
  530. {
  531. return estimateWeaponDamage(source, target, NULL);
  532. }
  533. Real estimateWeaponDamage(const Object *source, const Coord3D* pos)
  534. {
  535. return estimateWeaponDamage(source, NULL, pos);
  536. }
  537. void onWeaponBonusChange(const Object *source);///< Our Object's weapon bonus changed, so we need to update to reflect that instead of waiting
  538. /** return true if the target is within attack range, false otherwise.
  539. */
  540. Bool isWithinAttackRange(const Object *source, const Object *target) const;
  541. Bool isWithinAttackRange(const Object *source, const Coord3D* pos) const;
  542. Bool isTooClose(const Object *source, const Object *target) const;
  543. Bool isTooClose(const Object *source, const Coord3D *pos) const;
  544. Bool isGoalPosWithinAttackRange(const Object *source, const Coord3D* goalPos, const Object *target, const Coord3D* targetPos) const;
  545. //Used only by garrison contains that move objects around before doing the range check.
  546. //If target object is specified, we'll use his position, but if it's NULL we will use the
  547. //target position passed in.
  548. //NOTE: This is not a user friendly function -- use with caution if at all! -- Kris
  549. Bool isSourceObjectWithGoalPositionWithinAttackRange(const Object *source, const Coord3D *goalPos, const Object *target, const Coord3D *targetPos) const;
  550. /**
  551. Compute a target position from which 'source' can target 'target'. Note that this doesn't
  552. guarantee that source can actually move to the location, it just guarantees that the
  553. target position is plausibly within attack range. returns TRUE if the source's current pos
  554. is already close enough (in which case that current pos is stuffed into the return arg).
  555. */
  556. Bool computeApproachTarget(const Object *source, const Object *target, const Coord3D *pos, Real angleOffset, Coord3D& approachTargetPos) const;
  557. /**
  558. note that "load" makes the ammo instantly available, while "reload" keeps the weapon in the RELOADING
  559. state until the clip-reload-time is up. Normally you should use "load" only for newly-created
  560. units, who presumably come into existence with fully loaded weapons.
  561. */
  562. void loadAmmoNow(const Object *source);
  563. void reloadAmmo(const Object *source);
  564. WeaponStatus getStatus() const;
  565. /// Some AI needs to know when the soonest I can possibly next shoot. Bonuses have been figured into this number already.
  566. UnsignedInt getPossibleNextShotFrame() const { return m_whenWeCanFireAgain; }
  567. UnsignedInt getPreAttackFinishedFrame() const { return m_whenPreAttackFinished; }
  568. UnsignedInt getLastReloadStartedFrame() const { return m_whenLastReloadStarted; }
  569. Real getPercentReadyToFire() const;
  570. // do not ever use this unless you are weaponset.cpp
  571. void setPossibleNextShotFrame( UnsignedInt frameNum ) { m_whenWeCanFireAgain = frameNum; }
  572. void setPreAttackFinishedFrame( UnsignedInt frameNum ) { m_whenPreAttackFinished = frameNum; }
  573. void setLastReloadStartedFrame( UnsignedInt frameNum ) { m_whenLastReloadStarted = frameNum; }
  574. //Transfer the reload times and status from the passed in weapon.
  575. void transferNextShotStatsFrom( const Weapon &weapon );
  576. // we must pass the source object for these (and for ANY FUTURE ADDITIONS)
  577. // so that we can take the source's weapon bonuses, if any, into account.
  578. // Also note: you should RARELY need to call getAttackRange. If what you want is to
  579. // determine if you are within attack range, please call isWithinAttackRange instead.
  580. Real getAttackRange(const Object *source) const;
  581. // Returns the max distance between the centerpoints of source & victim for victim to be in range.
  582. Real getAttackDistance(const Object *source, const Object *victim, const Coord3D* victimPos) const;
  583. void newProjectileFired( const Object *sourceObj, const Object *projectile, const Object *victimObj, const Coord3D *victimPos );///<I just made this projectile and may need to keep track of it
  584. Bool isLaser() const { return m_template->getLaserName().isNotEmpty(); }
  585. void createLaser( const Object *sourceObj, const Object *victimObj, const Coord3D *victimPos );
  586. inline const WeaponTemplate* getTemplate() const { return m_template; }
  587. inline WeaponSlotType getWeaponSlot() const { return m_wslot; }
  588. inline AsciiString getName() const { return m_template->getName(); }
  589. inline UnsignedInt getLastShotFrame() const { return m_lastFireFrame; } ///< frame a shot was last fired on
  590. // If we are "reloading", then m_ammoInClip is a lie. It will say full.
  591. inline UnsignedInt getRemainingAmmo() const { return (getStatus() == RELOADING_CLIP) ? 0 : m_ammoInClip; }
  592. inline WeaponReloadType getReloadType() const { return m_template->getReloadType(); }
  593. inline Bool getAutoReloadsClip() const { return m_template->getAutoReloadsClip(); }
  594. inline Real getAimDelta() const { return m_template->getAimDelta(); }
  595. inline Real getScatterRadius() const { return m_template->getScatterRadius(); }
  596. inline Real getScatterTargetScalar() const { return m_template->getScatterTargetScalar(); }
  597. inline Int getAntiMask() const { return m_template->getAntiMask(); }
  598. inline Bool isCapableOfFollowingWaypoint() const { return m_template->isCapableOfFollowingWaypoint(); }
  599. inline Int getContinuousFireOneShotsNeeded() const { return m_template->getContinuousFireOneShotsNeeded(); }
  600. inline Int getContinuousFireTwoShotsNeeded() const { return m_template->getContinuousFireTwoShotsNeeded(); }
  601. inline UnsignedInt getContinuousFireCoastFrames() const { return m_template->getContinuousFireCoastFrames(); }
  602. inline UnsignedInt getAutoReloadWhenIdleFrames() const { return m_template->getAutoReloadWhenIdleFrames(); }
  603. inline const AudioEventRTS& getFireSound() const { return m_template->getFireSound(); }
  604. inline UnsignedInt getFireSoundLoopTime() const { return m_template->getFireSoundLoopTime(); }
  605. inline DamageType getDamageType() const { return m_template->getDamageType(); }
  606. inline DeathType getDeathType() const { return m_template->getDeathType(); }
  607. inline Real getContinueAttackRange() const { return m_template->getContinueAttackRange(); }
  608. inline Bool isShowsAmmoPips() const { return m_template->isShowsAmmoPips(); }
  609. inline Int getClipSize() const { return m_template->getClipSize(); }
  610. // Contact weapons (like car bombs) need to basically collide with their target.
  611. inline Bool isContactWeapon() const { return m_template->isContactWeapon(); }
  612. Int getClipReloadTime(const Object *source) const;
  613. Real getPrimaryDamageRadius(const Object *source) const;
  614. Int getPreAttackDelay( const Object *source, const Object *victim ) const;
  615. Bool isDamageWeapon() const;
  616. Bool isPitchLimited() const { return m_pitchLimited; }
  617. Bool isWithinTargetPitch(const Object *source, const Object *victim) const;
  618. //Leech range functionality simply means this weapon has unlimited range temporarily. How it works is if the
  619. //weapon template has the LeechRangeWeapon set, it means that once the unit has closed to standard weapon range
  620. //it fires the weapon, and will be able to hit the target even if it moves out of range! The unit will simply
  621. //stand there. This functionality is used by hack attacks.
  622. void setLeechRangeActive( Bool active ) { m_leechWeaponRangeActive = active; }
  623. Bool hasLeechRange() const { return m_leechWeaponRangeActive; }
  624. void setMaxShotCount(Int maxShots) { m_maxShotCount = maxShots; }
  625. Int getMaxShotCount() const { return m_maxShotCount; }
  626. Bool isClearFiringLineOfSightTerrain(const Object* source, const Object* victim) const;
  627. Bool isClearFiringLineOfSightTerrain(const Object* source, const Coord3D& victimPos) const;
  628. Bool isClearGoalFiringLineOfSightTerrain(const Object* source, const Coord3D& goalPos, const Object* victim) const;
  629. Bool isClearGoalFiringLineOfSightTerrain(const Object* source, const Coord3D& goalPos, const Coord3D& victimPos) const;
  630. static void calcProjectileLaunchPosition(
  631. const Object* launcher,
  632. WeaponSlotType wslot,
  633. Int specificBarrelToUse,
  634. Matrix3D& worldTransform,
  635. Coord3D& worldPos
  636. );
  637. static void positionProjectileForLaunch(
  638. Object* projectile,
  639. const Object *launcher,
  640. WeaponSlotType wslot,
  641. Int specificBarrelToUse
  642. );
  643. /**
  644. special purpose call for jets in airfields: directly set the ammoinclip to a certain
  645. percentage full (note that percent=1.0 is full, NOT percent=100.0!). this will end up
  646. with status as READY_TO_FIRE or OUT_OF_AMMO, but never RELOADING_CLIP!
  647. */
  648. void setClipPercentFull(Real percent, Bool allowReduction);
  649. UnsignedInt getSuspendFXFrame( void ) const { return m_suspendFXFrame; }
  650. protected:
  651. Weapon(const WeaponTemplate* tmpl, WeaponSlotType wslot);
  652. // return true if we auto-reloaded our clip after firing.
  653. Bool privateFireWeapon(
  654. const Object *sourceObj,
  655. Object *victimObj,
  656. const Coord3D* victimPos,
  657. Bool isProjectileDetonation,
  658. Bool ignoreRanges,
  659. WeaponBonusConditionFlags extraBonusFlags,
  660. ObjectID* projectileID,
  661. Bool inflictDamage
  662. );
  663. Real estimateWeaponDamage(const Object *sourceObj, const Object *victimObj, const Coord3D* victimPos);
  664. void reloadWithBonus(const Object *source, const WeaponBonus& bonus, Bool loadInstantly);
  665. void processRequestAssistance( const Object *requestingObject, Object *victimObject ); ///< Weapons can call for extra attacks from nearby objects
  666. void getFiringLineOfSightOrigin(const Object* source, Coord3D& origin) const;
  667. void computeBonus(const Object *source, WeaponBonusConditionFlags extraBonusFlags, WeaponBonus& bonus) const;
  668. void rebuildScatterTargets();
  669. private:
  670. const WeaponTemplate* m_template; ///< the kind of weapon this is
  671. WeaponSlotType m_wslot; ///< are we primary, secondary, etc. weapon? (used for projectile placement on reload)
  672. mutable WeaponStatus m_status; ///< weapon status
  673. UnsignedInt m_ammoInClip; ///< how many shots left in current clip
  674. UnsignedInt m_whenWeCanFireAgain; ///< the first frame the weapon can fire again
  675. UnsignedInt m_whenPreAttackFinished; ///< the frame the pre attack will complete.
  676. UnsignedInt m_whenLastReloadStarted; ///< the frame the current reload/between-shots began. (only valid if status is RELOADING_CLIP or BETWEEN_FIRING_SHOTS)
  677. UnsignedInt m_lastFireFrame; ///< frame a shot was last fired on
  678. UnsignedInt m_suspendFXFrame; ///< The fireFX can be suspended for any delay, in frames, then they will execute as normal
  679. ObjectID m_projectileStreamID; ///< the object that is tracking our stream if we have one. It can't go away without us.
  680. Int m_maxShotCount; ///< used for limiting consecutive firing
  681. Int m_curBarrel; ///< current barrel used for firing
  682. Int m_numShotsForCurBarrel; ///< how many shots to fire from cur barrel before moving to next barrel
  683. std::vector<Int> m_scatterTargetsUnused; ///< A running memory of which targets I've used, so I can shoot them all at random
  684. Bool m_pitchLimited;
  685. Bool m_leechWeaponRangeActive; ///< This weapon has unlimited range until attack state is aborted!
  686. // setter function for status that should not be used outside this class
  687. void setStatus( WeaponStatus status) { m_status = status; }
  688. };
  689. //-------------------------------------------------------------------------------------------------
  690. /**
  691. The "store" used to hold all the WeaponTemplates in existence. This is usually used when creating
  692. an Object, but can be used at any time after that. (It is explicitly
  693. OK to swap an Object's Weapon out at any given time.)
  694. */
  695. //-------------------------------------------------------------------------------------------------
  696. class WeaponStore : public SubsystemInterface
  697. {
  698. friend class WeaponTemplate;
  699. public:
  700. WeaponStore();
  701. ~WeaponStore();
  702. void init() { };
  703. void postProcessLoad();
  704. void reset();
  705. void update();
  706. /**
  707. Find the WeaponTemplate with the given name. If no such WeaponTemplate exists, return null.
  708. */
  709. const WeaponTemplate *findWeaponTemplate(AsciiString name) const;
  710. const WeaponTemplate *findWeaponTemplateByNameKey( NameKeyType key ) const { return findWeaponTemplatePrivate( key ); }
  711. // this dynamically allocates a new Weapon, which is owned (and must be freed!) by the caller.
  712. inline Weapon* allocateNewWeapon(const WeaponTemplate *tmpl, WeaponSlotType wslot) const
  713. {
  714. return newInstance(Weapon)(tmpl, wslot); // my, that was easy
  715. }
  716. void createAndFireTempWeapon(const WeaponTemplate* w, const Object *source, const Coord3D* pos);
  717. void createAndFireTempWeapon(const WeaponTemplate* w, const Object *source, Object *target);
  718. void handleProjectileDetonation( const WeaponTemplate* w, const Object *source, const Coord3D* pos, WeaponBonusConditionFlags extraBonusFlags, Bool inflictDamage = TRUE );
  719. static void parseWeaponTemplateDefinition(INI* ini);
  720. protected:
  721. WeaponTemplate *findWeaponTemplatePrivate( NameKeyType key ) const;
  722. WeaponTemplate *newWeaponTemplate( AsciiString name );
  723. WeaponTemplate *newOverride( WeaponTemplate *weaponTemplate );
  724. void deleteAllDelayedDamage();
  725. void resetWeaponTemplates( void );
  726. void setDelayedDamage(const WeaponTemplate *weapon, const Coord3D* pos, UnsignedInt whichFrame, ObjectID sourceID, ObjectID victimID, const WeaponBonus& bonus);
  727. private:
  728. /**
  729. WeaponDelayedDamageInfo is a utility class used by the WeaponStore to keep track
  730. of what damage will need to be dealt in the future. It is never used for Projectile
  731. weaponry, but rather for weapons that do damage in the short-term future without
  732. instantiating full-fledged Objects as a bullet. (e.g., tank shells do this.)
  733. */
  734. struct WeaponDelayedDamageInfo
  735. {
  736. public:
  737. const WeaponTemplate *m_delayedWeapon; ///< if delayed damage is pending, the weapon to deal the damage
  738. Coord3D m_delayDamagePos; ///< where to do the delay damage when it's time
  739. UnsignedInt m_delayDamageFrame; ///< frames we do the damage
  740. ObjectID m_delaySourceID; ///< who dealt the damage (by ID since it might be dead due to delay)
  741. ObjectID m_delayIntendedVictimID; ///< who the damage was intended for (or zero if no specific target)
  742. WeaponBonus m_bonus; ///< the weapon bonus to use
  743. };
  744. std::vector<WeaponTemplate*> m_weaponTemplateVector;
  745. std::list<WeaponDelayedDamageInfo> m_weaponDDI;
  746. };
  747. // EXTERNALS //////////////////////////////////////////////////////////////////////////////////////
  748. extern WeaponStore *TheWeaponStore;
  749. #endif // __WEAPON_H_