| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376 |
- /*
- ** 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 <http://www.gnu.org/licenses/>.
- */
- ////////////////////////////////////////////////////////////////////////////////
- // //
- // (c) 2001-2003 Electronic Arts Inc. //
- // //
- ////////////////////////////////////////////////////////////////////////////////
- // FILE: Damage.h /////////////////////////////////////////////////////////////////////////////////
- // Author: Colin Day, November 2001
- // Desc: Damage description
- ///////////////////////////////////////////////////////////////////////////////////////////////////
- #pragma once
- #ifndef __DAMAGE_H_
- #define __DAMAGE_H_
- // INCLUDES ///////////////////////////////////////////////////////////////////////////////////////
- #include "Common/BitFlags.h"
- #include "Common/GameType.h"
- #include "Common/ObjectStatusTypes.h" // Precompiled header anyway, no detangling possibility
- #include "Common/Snapshot.h"
- // FORWARD REFERENCES /////////////////////////////////////////////////////////////////////////////
- class Object;
- class INI;
- class ThingTemplate;
- //-------------------------------------------------------------------------------------------------
- /** Damage types, keep this in sync with DamageTypeFlags::s_bitNameList[] */
- //-------------------------------------------------------------------------------------------------
- enum DamageType
- {
- DAMAGE_EXPLOSION = 0,
- DAMAGE_CRUSH = 1,
- DAMAGE_ARMOR_PIERCING = 2,
- DAMAGE_SMALL_ARMS = 3,
- DAMAGE_GATTLING = 4,
- DAMAGE_RADIATION = 5,
- DAMAGE_FLAME = 6,
- DAMAGE_LASER = 7,
- DAMAGE_SNIPER = 8,
- DAMAGE_POISON = 9,
- DAMAGE_HEALING = 10,
- DAMAGE_UNRESISTABLE = 11, // this is for scripting to cause 'armorproof' damage
- DAMAGE_WATER = 12,
- DAMAGE_DEPLOY = 13, // for transports to deploy units and order them to all attack.
- DAMAGE_SURRENDER = 14, // if something "dies" to surrender damage, they surrender.... duh!
- DAMAGE_HACK = 15,
- DAMAGE_KILLPILOT = 16, // special snipe attack that kills the pilot and renders a vehicle unmanned.
- DAMAGE_PENALTY = 17, // from game penalty (you won't receive radar warnings BTW)
- DAMAGE_FALLING = 18,
- DAMAGE_MELEE = 19, // Blades, clubs...
- DAMAGE_DISARM = 20, // "special" damage type used for disarming mines, bombs, etc (NOT for "disarming" an opponent!)
- DAMAGE_HAZARD_CLEANUP = 21, // special damage type for cleaning up hazards like radiation or bio-poison.
- DAMAGE_PARTICLE_BEAM = 22, // Incinerates virtually everything (insanely powerful orbital beam)
- DAMAGE_TOPPLING = 23, // damage from getting toppled.
- DAMAGE_INFANTRY_MISSILE = 24,
- DAMAGE_AURORA_BOMB = 25,
- DAMAGE_LAND_MINE = 26,
- DAMAGE_JET_MISSILES = 27,
- DAMAGE_STEALTHJET_MISSILES = 28,
- DAMAGE_MOLOTOV_COCKTAIL = 29,
- DAMAGE_COMANCHE_VULCAN = 30,
- DAMAGE_SUBDUAL_MISSILE = 31, ///< Damage that does not kill you, but produces some special effect based on your Body Module. Seperate HP from normal damage.
- DAMAGE_SUBDUAL_VEHICLE = 32,
- DAMAGE_SUBDUAL_BUILDING = 33,
- DAMAGE_SUBDUAL_UNRESISTABLE = 34,
- DAMAGE_MICROWAVE = 35, ///< Radiation that only affects infantry
- DAMAGE_KILL_GARRISONED = 36, ///< Kills Passengers up to the number specified in Damage
- DAMAGE_STATUS = 37, ///< Damage that gives a status condition, not that does hitpoint damage
- // Please note: There is a string array DamageTypeFlags::s_bitNameList[]
- DAMAGE_NUM_TYPES // keep this last
- };
- //-------------------------------------------------------------------------------------------------
- //-------------------------------------------------------------------------------------------------
- typedef BitFlags<DAMAGE_NUM_TYPES> DamageTypeFlags;
- inline Bool getDamageTypeFlag(DamageTypeFlags flags, DamageType dt)
- {
- return flags.test(dt);
- }
- inline DamageTypeFlags setDamageTypeFlag(DamageTypeFlags flags, DamageType dt)
- {
- flags.set(dt, TRUE);
- return flags;
- }
- inline DamageTypeFlags clearDamageTypeFlag(DamageTypeFlags flags, DamageType dt)
- {
- flags.set(dt, FALSE);
- return flags;
- }
- // Instead of checking against a single damage type, gather the question here so we can have more than one
- inline Bool IsSubdualDamage( DamageType type )
- {
- switch( type )
- {
- case DAMAGE_SUBDUAL_MISSILE:
- case DAMAGE_SUBDUAL_VEHICLE:
- case DAMAGE_SUBDUAL_BUILDING:
- case DAMAGE_SUBDUAL_UNRESISTABLE:
- return TRUE;
- }
- return FALSE;
- }
- /// Does this type of damage go to internalChangeHealth?
- inline Bool IsHealthDamagingDamage( DamageType type )
- {
- // The need for this function brought to you by "Have the guy with no game experience write the weapon code" Foundation.
- // Health Damage should be one type of WeaponEffect. Thinking "Weapons can only do damage" is why AoE is boring.
- switch( type )
- {
- case DAMAGE_STATUS:
- case DAMAGE_SUBDUAL_MISSILE:
- case DAMAGE_SUBDUAL_VEHICLE:
- case DAMAGE_SUBDUAL_BUILDING:
- case DAMAGE_SUBDUAL_UNRESISTABLE:
- case DAMAGE_KILLPILOT:
- case DAMAGE_KILL_GARRISONED:
- return FALSE;
- }
- return TRUE;
- }
- inline void SET_ALL_DAMAGE_TYPE_BITS(DamageTypeFlags& m)
- {
- m.clear();
- m.flip();
- }
- extern DamageTypeFlags DAMAGE_TYPE_FLAGS_NONE;
- extern DamageTypeFlags DAMAGE_TYPE_FLAGS_ALL;
- void initDamageTypeFlags();
- //-------------------------------------------------------------------------------------------------
- /** Death types, keep this in sync with TheDeathNames[] */
- //-------------------------------------------------------------------------------------------------
- enum DeathType
- {
- // note that these DELIBERATELY have (slightly) different names from the damage names,
- // since there isn't necessarily a one-to-one correspondence. e.g., DEATH_BURNED
- // can come from DAMAGE_FLAME but also from DAMAGE_PARTICLE_BEAM.
- DEATH_NORMAL = 0,
- DEATH_NONE = 1, ///< this is a "special case" that can't normally cause death
- DEATH_CRUSHED = 2,
- DEATH_BURNED = 3,
- DEATH_EXPLODED = 4,
- DEATH_POISONED = 5,
- DEATH_TOPPLED = 6,
- DEATH_FLOODED = 7,
- DEATH_SUICIDED = 8,
- DEATH_LASERED = 9,
- DEATH_DETONATED = 10, /**< this is the "death" that occurs when a missile/warhead/etc detonates normally,
- as opposed to being shot down, etc */
- DEATH_SPLATTED = 11, /**< the death that results from DAMAGE_FALLING */
- DEATH_POISONED_BETA = 12,
- // these are the "extra" types for yet-to-be-defined stuff. Don't bother renaming or adding
- // or removing these; they are reserved for modders :-)
- DEATH_EXTRA_2 = 13,
- DEATH_EXTRA_3 = 14,
- DEATH_EXTRA_4 = 15,
- DEATH_EXTRA_5 = 16,
- DEATH_EXTRA_6 = 17,
- DEATH_EXTRA_7 = 18,
- DEATH_EXTRA_8 = 19,
- DEATH_POISONED_GAMMA = 20,
-
- DEATH_NUM_TYPES // keep this last
- };
- #ifdef DEFINE_DEATH_NAMES
- static const char *TheDeathNames[] =
- {
- "NORMAL",
- "NONE",
- "CRUSHED",
- "BURNED",
- "EXPLODED",
- "POISONED",
- "TOPPLED",
- "FLOODED",
- "SUICIDED",
- "LASERED",
- "DETONATED",
- "SPLATTED",
- "POISONED_BETA",
- "EXTRA_2",
- "EXTRA_3",
- "EXTRA_4",
- "EXTRA_5",
- "EXTRA_6",
- "EXTRA_7",
- "EXTRA_8",
- "POISONED_GAMMA",
- NULL
- };
- #endif // end DEFINE_DEATH_NAMES
- //-------------------------------------------------------------------------------------------------
- //-------------------------------------------------------------------------------------------------
- typedef UnsignedInt DeathTypeFlags;
- const DeathTypeFlags DEATH_TYPE_FLAGS_ALL = 0xffffffff;
- const DeathTypeFlags DEATH_TYPE_FLAGS_NONE = 0x00000000;
- inline Bool getDeathTypeFlag(DeathTypeFlags flags, DeathType dt)
- {
- return (flags & (1UL << (dt - 1))) != 0;
- }
- inline DeathTypeFlags setDeathTypeFlag(DeathTypeFlags flags, DeathType dt)
- {
- return (flags | (1UL << (dt - 1)));
- }
- inline DeathTypeFlags clearDeathTypeFlag(DeathTypeFlags flags, DeathType dt)
- {
- return (flags & ~(1UL << (dt - 1)));
- }
- //-------------------------------------------------------------------------------------------------
- /** Damage info inputs */
- //-------------------------------------------------------------------------------------------------
- class DamageInfoInput : public Snapshot
- {
- public:
- DamageInfoInput( void )
- {
- m_sourceID = INVALID_ID;
- m_sourceTemplate = NULL;
- m_sourcePlayerMask = 0;
- m_damageType = DAMAGE_EXPLOSION;
- m_damageStatusType = OBJECT_STATUS_NONE;
- m_damageFXOverride = DAMAGE_UNRESISTABLE;
- m_deathType = DEATH_NORMAL;
- m_amount = 0;
- m_kill = FALSE;
-
- m_shockWaveVector.zero();
- m_shockWaveAmount = 0.0f;
- m_shockWaveRadius = 0.0f;
- m_shockWaveTaperOff = 0.0f;
- }
- ObjectID m_sourceID; ///< source of the damage
- const ThingTemplate *m_sourceTemplate; ///< source of the damage (the template).
- PlayerMaskType m_sourcePlayerMask; ///< Player mask of m_sourceID.
- DamageType m_damageType; ///< type of damage
- ObjectStatusTypes m_damageStatusType; ///< If status damage, what type
- DamageType m_damageFXOverride; ///< If not marked as the default of Unresistable, the damage type to use in doDamageFX instead of the real damamge type
- DeathType m_deathType; ///< if this kills us, death type to be used
- Real m_amount; ///< # value of how much damage to inflict
- Bool m_kill; ///< will always cause object to die regardless of damage.
- // These are used for damage causing shockwave, forcing units affected to be pushed around
- Coord3D m_shockWaveVector; ///< This represents the incoming damage vector
- Real m_shockWaveAmount; ///< This represents the amount of shockwave created by the damage. 0 = no shockwave, 1.0 = shockwave equal to damage.
- Real m_shockWaveRadius; ///< This represents the effect radius of the shockwave.
- Real m_shockWaveTaperOff; ///< This represents the taper off effect of the shockwave at the tip of the radius. 0.0 means shockwave is 0% at the radius edge.
- protected:
- // snapshot methods
- virtual void crc( Xfer *xfer ) { }
- virtual void xfer( Xfer *xfer );
- virtual void loadPostProcess( void ) { }
-
- };
- const Real HUGE_DAMAGE_AMOUNT = 999999.0f;
- //-------------------------------------------------------------------------------------------------
- /** Damage into outputs */
- //-------------------------------------------------------------------------------------------------
- class DamageInfoOutput : public Snapshot
- {
- public:
- DamageInfoOutput( void )
- {
- m_actualDamageDealt = 0;
- m_actualDamageClipped = 0;
- m_noEffect = false;
- }
- /**
- m_actualDamageDealt is the damage we tried to apply to object (after multipliers and such).
- m_actualDamageClipped is the value of m_actualDamageDealt, but clipped to the max health remaining of the obj.
- example:
- a mammoth tank fires a round at a small tank, attempting 100 damage.
- the small tank has a damage multiplier of 50%, meaning that only 50 damage is applied.
- furthermore, the small tank has only 30 health remaining.
- so: m_actualDamageDealt = 50, m_actualDamageClipped = 30.
- this distinction is useful, since visual fx really wants to do the fx for "50 damage",
- even though it was more than necessary to kill this object; game logic, on the other hand,
- may want to know the "clipped" damage for ai purposes.
- */
- Real m_actualDamageDealt;
- Real m_actualDamageClipped; ///< (see comment for m_actualDamageDealt)
- Bool m_noEffect; ///< if true, no damage was done at all (generally due to being InactiveBody)
- protected:
- // snapshot methods
- virtual void crc( Xfer *xfer ) { }
- virtual void xfer( Xfer *xfer );
- virtual void loadPostProcess( void ) { }
- };
- //-------------------------------------------------------------------------------------------------
- /** DamageInfo is a descriptor of damage we're trying to inflict. The structure
- * is divided up into two parts, inputs and outputs.
- *
- * INPUTS: You must provide valid values for these fields in order for damage
- * calculation to correctly take place
- * OUTPUT: Upon returning from damage issuing functions, the output fields
- * will be filled with the results of the damage occurrence
- */
- //-------------------------------------------------------------------------------------------------
- class DamageInfo : public Snapshot
- {
- public:
- DamageInfoInput in; ///< inputs for the damage info
- DamageInfoOutput out; ///< results for the damage occurrence
- protected:
- virtual void crc( Xfer *xfer ) { }
- virtual void xfer( Xfer *xfer );
- virtual void loadPostProcess( void ){ }
- };
- #endif // __DAMAGE_H_
|