/* ** Command & Conquer Generals Zero Hour(tm) ** Copyright 2025 Electronic Arts Inc. ** ** This program is free software: you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation, either version 3 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program. If not, see . */ //////////////////////////////////////////////////////////////////////////////// // // // (c) 2003 Electronic Arts Inc. // // // //////////////////////////////////////////////////////////////////////////////// // FILE: CountermeasuresBehavior.h ///////////////////////////////////////////////////////////////////////// // Author: Kris Morness, April 2003 // Desc: Handles countermeasure firing when under missile threat, and responsible // for diverting missiles to the flares. //------------------------------------------ #pragma once #ifndef __COUNTERMEASURES_BEHAVIOR_H #define __COUNTERMEASURES_BEHAVIOR_H // INCLUDES /////////////////////////////////////////////////////////////////////////////////////// #include "GameClient/ParticleSys.h" #include "GameLogic/Module/BehaviorModule.h" #include "GameLogic/Module/UpgradeModule.h" #include "GameLogic/Module/UpdateModule.h" #include "GameLogic/Module/DamageModule.h" #include "Common/BitFlagsIO.h" class ParticleSystem; class ParticleSystemTemplate; //------------------------------------------------------------------------------------------------- class CountermeasuresBehaviorModuleData : public UpdateModuleData { public: UpgradeMuxData m_upgradeMuxData; AsciiString m_flareTemplateName; AsciiString m_flareBoneBaseName; Real m_evasionRate; UnsignedInt m_volleySize; Real m_volleyArcAngle; Real m_volleyVelocityFactor; UnsignedInt m_framesBetweenVolleys; UnsignedInt m_numberOfVolleys; UnsignedInt m_reloadFrames; UnsignedInt m_missileDecoyFrames; UnsignedInt m_countermeasureReactionFrames; Bool m_mustReloadAtAirfield; CountermeasuresBehaviorModuleData() { m_volleySize = 0; m_volleyArcAngle = 0.0f; m_framesBetweenVolleys = 0; m_numberOfVolleys = 0; m_reloadFrames = 0; m_evasionRate = 0.0f; m_mustReloadAtAirfield = FALSE; m_missileDecoyFrames = 0; m_volleyVelocityFactor = 1.0f; } static void buildFieldParse(MultiIniFieldParse& p) { static const FieldParse dataFieldParse[] = { { "FlareTemplateName", INI::parseAsciiString, NULL, offsetof( CountermeasuresBehaviorModuleData, m_flareTemplateName ) }, { "FlareBoneBaseName", INI::parseAsciiString, NULL, offsetof( CountermeasuresBehaviorModuleData, m_flareBoneBaseName ) }, { "VolleySize", INI::parseUnsignedInt, NULL, offsetof( CountermeasuresBehaviorModuleData, m_volleySize ) }, { "VolleyArcAngle", INI::parseAngleReal, NULL, offsetof( CountermeasuresBehaviorModuleData, m_volleyArcAngle ) }, { "VolleyVelocityFactor", INI::parseReal, NULL, offsetof( CountermeasuresBehaviorModuleData, m_volleyVelocityFactor ) }, { "DelayBetweenVolleys", INI::parseDurationUnsignedInt, NULL, offsetof( CountermeasuresBehaviorModuleData, m_framesBetweenVolleys ) }, { "NumberOfVolleys", INI::parseUnsignedInt, NULL, offsetof( CountermeasuresBehaviorModuleData, m_numberOfVolleys ) }, { "ReloadTime", INI::parseDurationUnsignedInt, NULL, offsetof( CountermeasuresBehaviorModuleData, m_reloadFrames ) }, { "EvasionRate", INI::parsePercentToReal, NULL, offsetof( CountermeasuresBehaviorModuleData, m_evasionRate ) }, { "MustReloadAtAirfield", INI::parseBool, NULL, offsetof( CountermeasuresBehaviorModuleData, m_mustReloadAtAirfield ) }, { "MissileDecoyDelay", INI::parseDurationUnsignedInt, NULL, offsetof( CountermeasuresBehaviorModuleData, m_missileDecoyFrames ) }, { "ReactionLaunchLatency", INI::parseDurationUnsignedInt, NULL, offsetof( CountermeasuresBehaviorModuleData, m_countermeasureReactionFrames ) }, { 0, 0, 0, 0 } }; UpdateModuleData::buildFieldParse(p); p.add(dataFieldParse); p.add(UpgradeMuxData::getFieldParse(), offsetof( CountermeasuresBehaviorModuleData, m_upgradeMuxData )); } }; // ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------ class CountermeasuresBehaviorInterface { public: virtual void reportMissileForCountermeasures( Object *missile ) = 0; virtual ObjectID calculateCountermeasureToDivertTo( const Object& victim ) = 0; virtual void reloadCountermeasures() = 0; virtual Bool isActive() const = 0; }; typedef std::vector CountermeasuresVec; //------------------------------------------------------------------------------------------------- //------------------------------------------------------------------------------------------------- class CountermeasuresBehavior : public UpdateModule, public UpgradeMux, public CountermeasuresBehaviorInterface { MEMORY_POOL_GLUE_WITH_USERLOOKUP_CREATE( CountermeasuresBehavior, "CountermeasuresBehavior" ) MAKE_STANDARD_MODULE_MACRO_WITH_MODULE_DATA( CountermeasuresBehavior, CountermeasuresBehaviorModuleData ) public: CountermeasuresBehavior( Thing *thing, const ModuleData* moduleData ); // virtual destructor prototype provided by memory pool declaration // module methods static Int getInterfaceMask() { return UpdateModule::getInterfaceMask() | MODULEINTERFACE_UPGRADE; } // BehaviorModule virtual UpgradeModuleInterface* getUpgrade() { return this; } virtual CountermeasuresBehaviorInterface* getCountermeasuresBehaviorInterface() { return this; } virtual const CountermeasuresBehaviorInterface* getCountermeasuresBehaviorInterface() const { return this; } // UpdateModuleInterface virtual UpdateSleepTime update(); virtual DisabledMaskType getDisabledTypesToProcess() const { return MAKE_DISABLED_MASK( DISABLED_HELD ); } // CountermeasuresBehaviorInterface virtual void reportMissileForCountermeasures( Object *missile ); virtual ObjectID calculateCountermeasureToDivertTo( const Object& victim ); virtual void reloadCountermeasures(); virtual Bool isActive() const; protected: virtual void upgradeImplementation() { setWakeFrame(getObject(), UPDATE_SLEEP_NONE); } virtual void getUpgradeActivationMasks(UpgradeMaskType& activation, UpgradeMaskType& conflicting) const { getCountermeasuresBehaviorModuleData()->m_upgradeMuxData.getUpgradeActivationMasks(activation, conflicting); } virtual void performUpgradeFX() { getCountermeasuresBehaviorModuleData()->m_upgradeMuxData.performUpgradeFX(getObject()); } virtual void processUpgradeRemoval() { // I can't take it any more. Let the record show that I think the UpgradeMux multiple inheritence is CRAP. getCountermeasuresBehaviorModuleData()->m_upgradeMuxData.muxDataProcessUpgradeRemoval(getObject()); } virtual Bool requiresAllActivationUpgrades() const { return getCountermeasuresBehaviorModuleData()->m_upgradeMuxData.m_requiresAllTriggers; } inline Bool isUpgradeActive() const { return isAlreadyUpgraded(); } virtual Bool isSubObjectsUpgrade() { return false; } void launchVolley(); private: CountermeasuresVec m_counterMeasures; //vector of countermeasures in the world. UnsignedInt m_availableCountermeasures; //number of countermeasures that can be launched to divert missiles. UnsignedInt m_activeCountermeasures; //number of countermeasures currently able to divert missiles. UnsignedInt m_divertedMissiles; //number of missiles that have been diverted to countermeasures. UnsignedInt m_incomingMissiles; //grand total of all missiles that were ever fired at me. UnsignedInt m_reactionFrame; //The frame countermeasures will be launched after initial hostile act. UnsignedInt m_nextVolleyFrame; //Frame the next volley is fired. UnsignedInt m_reloadFrame; //The frame countermeasures will be ready to use again. }; #endif // __COUNTERMEASURES_BEHAVIOR_H