SpecialAbilityUpdate.h 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289
  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: SpecialAbilityUpdate.h /////////////////////////////////////////////////////////////////////////
  24. // Author: Kris Morness, July 2002
  25. // Desc: Handles processing of unit special abilities.
  26. ///////////////////////////////////////////////////////////////////////////////////////////////////
  27. #pragma once
  28. #ifndef __SPECIAL_ABILITY_UPDATE_H
  29. #define __SPECIAL_ABILITY_UPDATE_H
  30. // INCLUDES ///////////////////////////////////////////////////////////////////////////////////////
  31. #include "Common/AudioEventRTS.h"
  32. #include "Common/INI.h"
  33. #include "GameLogic/Module/SpecialPowerUpdateModule.h"
  34. #include "GameClient/ParticleSys.h"
  35. class DamageInfo;
  36. class SpecialPowerTemplate;
  37. class SpecialPowerModule;
  38. class FXList;
  39. enum SpecialPowerType;
  40. #define SPECIAL_ABILITY_HUGE_DISTANCE 10000000.0f
  41. //-------------------------------------------------------------------------------------------------
  42. class SpecialAbilityUpdateModuleData : public UpdateModuleData
  43. {
  44. public:
  45. AsciiString m_specialObjectName;
  46. AsciiString m_specialObjectAttachToBoneName;
  47. const SpecialPowerTemplate* m_specialPowerTemplate; ///< pointer to the special power template
  48. Real m_startAbilityRange;
  49. Real m_abilityAbortRange;
  50. Real m_packUnpackVariationFactor;
  51. Real m_fleeRangeAfterCompletion;
  52. Int m_effectValue;
  53. Int m_awardXPForTriggering;
  54. Int m_skillPointsForTriggering;
  55. UnsignedInt m_preparationFrames;
  56. UnsignedInt m_persistentPrepFrames;
  57. UnsignedInt m_effectDuration;
  58. UnsignedInt m_maxSpecialObjects;
  59. UnsignedInt m_packTime;
  60. UnsignedInt m_unpackTime;
  61. UnsignedInt m_preTriggerUnstealthFrames;
  62. Bool m_skipPackingWithNoTarget;
  63. Bool m_specialObjectsPersistent;
  64. Bool m_uniqueSpecialObjectTargets;
  65. Bool m_specialObjectsPersistWhenOwnerDies;
  66. Bool m_flipObjectAfterPacking;
  67. Bool m_flipObjectAfterUnpacking;
  68. Bool m_alwaysValidateSpecialObjects;
  69. Bool m_doCaptureFX; ///< the house color flashing while a building is getting captured
  70. Bool m_loseStealthOnTrigger;
  71. Bool m_approachRequiresLOS;
  72. Bool m_needToFaceTarget;
  73. Bool m_persistenceRequiresRecharge;
  74. const ParticleSystemTemplate *m_disableFXParticleSystem;
  75. AudioEventRTS m_packSound;
  76. AudioEventRTS m_unpackSound;
  77. AudioEventRTS m_prepSoundLoop;
  78. AudioEventRTS m_triggerSound;
  79. SpecialAbilityUpdateModuleData()
  80. {
  81. m_specialPowerTemplate = NULL;
  82. m_startAbilityRange = SPECIAL_ABILITY_HUGE_DISTANCE;
  83. m_abilityAbortRange = SPECIAL_ABILITY_HUGE_DISTANCE;
  84. m_preparationFrames = 0;
  85. m_persistentPrepFrames = 0;
  86. m_packTime = 0;
  87. m_unpackTime = 0;
  88. m_packUnpackVariationFactor = 0.0f;
  89. m_effectDuration = 0;
  90. m_maxSpecialObjects = 1;
  91. m_effectValue = 1;
  92. m_specialObjectsPersistent = FALSE;
  93. m_uniqueSpecialObjectTargets = FALSE;
  94. m_specialObjectsPersistWhenOwnerDies = FALSE;
  95. m_skipPackingWithNoTarget = FALSE;
  96. m_flipObjectAfterPacking = FALSE;
  97. m_flipObjectAfterUnpacking = FALSE;
  98. m_disableFXParticleSystem = NULL;
  99. m_fleeRangeAfterCompletion = 0.0f;
  100. m_doCaptureFX = FALSE;
  101. m_alwaysValidateSpecialObjects = FALSE;
  102. m_loseStealthOnTrigger = FALSE;
  103. m_awardXPForTriggering = 0;
  104. m_skillPointsForTriggering = -1;
  105. m_approachRequiresLOS = TRUE;
  106. m_preTriggerUnstealthFrames = 0;
  107. m_needToFaceTarget = TRUE;
  108. m_persistenceRequiresRecharge = FALSE;
  109. }
  110. static void buildFieldParse(MultiIniFieldParse& p)
  111. {
  112. UpdateModuleData::buildFieldParse(p);
  113. static const FieldParse dataFieldParse[] =
  114. {
  115. //Primary data values
  116. { "SpecialPowerTemplate", INI::parseSpecialPowerTemplate, NULL, offsetof( SpecialAbilityUpdateModuleData, m_specialPowerTemplate ) },
  117. { "StartAbilityRange", INI::parseReal, NULL, offsetof( SpecialAbilityUpdateModuleData, m_startAbilityRange ) },
  118. { "AbilityAbortRange", INI::parseReal, NULL, offsetof( SpecialAbilityUpdateModuleData, m_abilityAbortRange ) },
  119. { "PreparationTime", INI::parseDurationUnsignedInt, NULL, offsetof( SpecialAbilityUpdateModuleData, m_preparationFrames ) },
  120. { "PersistentPrepTime", INI::parseDurationUnsignedInt, NULL, offsetof( SpecialAbilityUpdateModuleData, m_persistentPrepFrames ) },
  121. { "PackTime", INI::parseDurationUnsignedInt, NULL, offsetof( SpecialAbilityUpdateModuleData, m_packTime ) },
  122. { "UnpackTime", INI::parseDurationUnsignedInt, NULL, offsetof( SpecialAbilityUpdateModuleData, m_unpackTime ) },
  123. { "PreTriggerUnstealthTime", INI::parseDurationUnsignedInt, NULL, offsetof( SpecialAbilityUpdateModuleData, m_preTriggerUnstealthFrames ) },
  124. { "SkipPackingWithNoTarget", INI::parseBool, NULL, offsetof( SpecialAbilityUpdateModuleData, m_skipPackingWithNoTarget ) },
  125. { "PackUnpackVariationFactor", INI::parseReal, NULL, offsetof( SpecialAbilityUpdateModuleData, m_packUnpackVariationFactor ) },
  126. //Secondary data values
  127. { "SpecialObject", INI::parseAsciiString, NULL, offsetof( SpecialAbilityUpdateModuleData, m_specialObjectName ) },
  128. { "SpecialObjectAttachToBone", INI::parseAsciiString, NULL, offsetof( SpecialAbilityUpdateModuleData, m_specialObjectAttachToBoneName ) },
  129. { "MaxSpecialObjects", INI::parseUnsignedInt, NULL, offsetof( SpecialAbilityUpdateModuleData, m_maxSpecialObjects ) },
  130. { "SpecialObjectsPersistent", INI::parseBool, NULL, offsetof( SpecialAbilityUpdateModuleData, m_specialObjectsPersistent ) },
  131. { "EffectDuration", INI::parseDurationUnsignedInt, NULL, offsetof( SpecialAbilityUpdateModuleData, m_effectDuration ) },
  132. { "EffectValue", INI::parseInt, NULL, offsetof( SpecialAbilityUpdateModuleData, m_effectValue ) },
  133. { "UniqueSpecialObjectTargets", INI::parseBool, NULL, offsetof( SpecialAbilityUpdateModuleData, m_uniqueSpecialObjectTargets ) },
  134. { "SpecialObjectsPersistWhenOwnerDies", INI::parseBool, NULL, offsetof( SpecialAbilityUpdateModuleData, m_specialObjectsPersistWhenOwnerDies ) },
  135. { "AlwaysValidateSpecialObjects", INI::parseBool, NULL, offsetof( SpecialAbilityUpdateModuleData, m_alwaysValidateSpecialObjects ) },
  136. { "FlipOwnerAfterPacking", INI::parseBool, NULL, offsetof( SpecialAbilityUpdateModuleData, m_flipObjectAfterPacking ) },
  137. { "FlipOwnerAfterUnpacking", INI::parseBool, NULL, offsetof( SpecialAbilityUpdateModuleData, m_flipObjectAfterUnpacking ) },
  138. { "FleeRangeAfterCompletion", INI::parseReal, NULL, offsetof( SpecialAbilityUpdateModuleData, m_fleeRangeAfterCompletion ) },
  139. { "DisableFXParticleSystem", INI::parseParticleSystemTemplate, NULL, offsetof( SpecialAbilityUpdateModuleData, m_disableFXParticleSystem ) },
  140. { "DoCaptureFX", INI::parseBool, NULL, offsetof( SpecialAbilityUpdateModuleData, m_doCaptureFX ) },
  141. { "PackSound", INI::parseAudioEventRTS, NULL, offsetof( SpecialAbilityUpdateModuleData, m_packSound ) },
  142. { "UnpackSound", INI::parseAudioEventRTS, NULL, offsetof( SpecialAbilityUpdateModuleData, m_unpackSound ) },
  143. { "PrepSoundLoop", INI::parseAudioEventRTS, NULL, offsetof( SpecialAbilityUpdateModuleData, m_prepSoundLoop ) },
  144. { "TriggerSound", INI::parseAudioEventRTS, NULL, offsetof( SpecialAbilityUpdateModuleData, m_triggerSound ) },
  145. { "LoseStealthOnTrigger", INI::parseBool, NULL, offsetof( SpecialAbilityUpdateModuleData, m_loseStealthOnTrigger ) },
  146. { "AwardXPForTriggering", INI::parseInt, NULL, offsetof( SpecialAbilityUpdateModuleData, m_awardXPForTriggering ) },
  147. { "SkillPointsForTriggering", INI::parseInt, NULL, offsetof( SpecialAbilityUpdateModuleData, m_skillPointsForTriggering ) },
  148. { "ApproachRequiresLOS", INI::parseBool, NULL, offsetof( SpecialAbilityUpdateModuleData, m_approachRequiresLOS ) },
  149. { "ApproachRequiresLOS", INI::parseBool, NULL, offsetof( SpecialAbilityUpdateModuleData, m_approachRequiresLOS ) },
  150. { "NeedToFaceTarget", INI::parseBool, NULL, offsetof( SpecialAbilityUpdateModuleData, m_needToFaceTarget ) },
  151. { "PersistenceRequiresRecharge",INI::parseBool, NULL, offsetof( SpecialAbilityUpdateModuleData, m_persistenceRequiresRecharge ) },
  152. { 0, 0, 0, 0 }
  153. };
  154. p.add(dataFieldParse);
  155. }
  156. };
  157. //-------------------------------------------------------------------------------------------------
  158. class SpecialAbilityUpdate : public SpecialPowerUpdateModule
  159. {
  160. MEMORY_POOL_GLUE_WITH_USERLOOKUP_CREATE( SpecialAbilityUpdate, "SpecialAbilityUpdate" )
  161. MAKE_STANDARD_MODULE_MACRO_WITH_MODULE_DATA( SpecialAbilityUpdate, SpecialAbilityUpdateModuleData )
  162. public:
  163. SpecialAbilityUpdate( Thing *thing, const ModuleData* moduleData );
  164. // virtual destructor prototype provided by memory pool declaration
  165. // SpecialPowerUpdateInterface
  166. virtual Bool initiateIntentToDoSpecialPower(const SpecialPowerTemplate *specialPowerTemplate, const Object *targetObj, const Coord3D *targetPos, const Waypoint *way, UnsignedInt commandOptions );
  167. virtual Bool isSpecialAbility() const { return true; }
  168. virtual Bool isSpecialPower() const { return false; }
  169. virtual Bool isActive() const { return m_active; }
  170. virtual Bool doesSpecialPowerHaveOverridableDestinationActive() const { return false; } //Is it active now?
  171. virtual Bool doesSpecialPowerHaveOverridableDestination() const { return false; } //Does it have it, even if it's not active?
  172. virtual void setSpecialPowerOverridableDestination( const Coord3D *loc ) {}
  173. virtual Bool isPowerCurrentlyInUse( const CommandButton *command = NULL ) const;
  174. // virtual Bool isBusy() const { return m_isBusy; }
  175. // UpdateModule
  176. virtual SpecialPowerUpdateInterface* getSpecialPowerUpdateInterface() { return this; }
  177. virtual CommandOption getCommandOption() const { return (CommandOption)0; }
  178. virtual UpdateSleepTime update();
  179. // ??? ugh, public stuff that shouldn't be -- hell yeah!
  180. UnsignedInt getSpecialObjectCount() const;
  181. UnsignedInt getSpecialObjectMax() const;
  182. Object* findSpecialObjectWithProducerID( const Object *target );
  183. SpecialPowerType getSpecialPowerType( void ) const;
  184. protected:
  185. void onExit( Bool cleanup );
  186. const SpecialPowerTemplate* getTemplate() const;
  187. SpecialPowerModuleInterface* getMySPM();
  188. //Wrapper function that determines if our object is close enough to the target object or position (auto knowledge)... only if necessary.
  189. //Returns true if it's not necessary, in which case, it can skip any approach.
  190. Bool isWithinStartAbilityRange() const;
  191. Bool isWithinAbilityAbortRange() const; //If not, we abort the ability
  192. Bool initLaser(Object* specialObject, Object* target);
  193. //Various steps of performing any special ability. Not all special abilities will use all of them.
  194. Bool approachTarget(); //Approaches the target before starting the special attack (if appropriate)
  195. void startPreparation(); //Begins the preparation of ability -- like firing off a hacker attack, or laser tracer, etc.
  196. Bool continuePreparation(); //Updates the preparation of ability -- like recalculating tracer lines.
  197. void triggerAbilityEffect(); //After the preparation time has elapsed, this part actually triggers the desired effect of the special ability.
  198. void finishAbility();
  199. void validateSpecialObjects();
  200. Object* createSpecialObject();
  201. void killSpecialObjects();
  202. Bool handlePackingProcessing();
  203. void startPacking(Bool success);
  204. void startUnpacking();
  205. Bool needToPack() const;
  206. Bool needToUnpack() const;
  207. Bool isPreparationComplete() const { return !m_prepFrames; }
  208. void endPreparation();
  209. Bool isPersistentAbility() const { return getSpecialAbilityUpdateModuleData()->m_persistentPrepFrames > 0; }
  210. void resetPreparation() { m_prepFrames = getSpecialAbilityUpdateModuleData()->m_persistentPrepFrames; }
  211. Bool isFacing();
  212. Bool needToFace() const;
  213. void startFacing();
  214. // Lorenzen added this additional flag to support the NapalmBombDrop
  215. // It causes this update to force a recharge of the SPM between drops
  216. Bool getDoesPersistenceRequireRecharge() const { return getSpecialAbilityUpdateModuleData()->m_persistenceRequiresRecharge; }
  217. // void setBusy ( Bool is ) { m_isBusy = is; }
  218. // Bool m_isBusy; ///< whether I am between trigger and completion
  219. protected:
  220. UpdateSleepTime calcSleepTime()
  221. {
  222. return (m_active || getSpecialAbilityUpdateModuleData()->m_alwaysValidateSpecialObjects) ? UPDATE_SLEEP_NONE : UPDATE_SLEEP_FOREVER;
  223. }
  224. private:
  225. enum PackingState
  226. {
  227. STATE_NONE,
  228. STATE_PACKING,
  229. STATE_UNPACKING,
  230. STATE_PACKED,
  231. STATE_UNPACKED,
  232. };
  233. AudioEventRTS m_prepSoundLoop;
  234. UnsignedInt m_prepFrames;
  235. UnsignedInt m_animFrames; //Used for packing/unpacking unit before or after using ability.
  236. ObjectID m_targetID;
  237. Coord3D m_targetPos;
  238. Int m_locationCount;
  239. std::list<ObjectID> m_specialObjectIDList; //The list of special objects
  240. UnsignedInt m_specialObjectEntries; //The size of the list of member Objects
  241. Real m_captureFlashPhase; ///< used to track the accellerating flash of the capture FX
  242. PackingState m_packingState;
  243. Bool m_active;
  244. Bool m_noTargetCommand;
  245. Bool m_facingInitiated;
  246. Bool m_facingComplete;
  247. Bool m_withinStartAbilityRange;
  248. Bool m_doDisableFXParticles; // smaller targets cause this flag to toggle, making the particle effect more sparse
  249. };
  250. #endif // _SPECIAL_POWER_UPDATE_H_