/*
** 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