/* ** 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) 2001-2003 Electronic Arts Inc. // // // //////////////////////////////////////////////////////////////////////////////// // FILE: DamageFX.cpp /////////////////////////////////////////////////////////////////////////////// // Author: Steven Johnson, November 2001 // Desc: DamageFX descriptions /////////////////////////////////////////////////////////////////////////////////////////////////// // INCLUDES /////////////////////////////////////////////////////////////////////////////////////// #include "PreRTS.h" // This must go first in EVERY cpp file in the GameEngine #include "Common/INI.h" #include "Common/ThingFactory.h" #include "Common/ThingTemplate.h" #include "Common/DamageFX.h" #include "Common/GameAudio.h" #include "GameClient/FXList.h" #include "GameLogic/Damage.h" #include "GameLogic/GameLogic.h" #include "GameLogic/Object.h" #include "GameClient/GameClient.h" #include "GameClient/InGameUI.h" /////////////////////////////////////////////////////////////////////////////////////////////////// // PUBLIC DATA //////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////// DamageFXStore *TheDamageFXStore = NULL; ///< the DamageFX store definition /////////////////////////////////////////////////////////////////////////////////////////////////// // PRIVATE DATA /////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////// // PRIVATE CLASSES /////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////// // PUBLIC FUNCTIONS /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////// //------------------------------------------------------------------------------------------------- DamageFX::DamageFX() { // not necessary. //clear(); } //------------------------------------------------------------------------------------------------- void DamageFX::clear() { for (Int dt = 0; dt < DAMAGE_NUM_TYPES; ++dt) { for (Int v = LEVEL_FIRST; v <= LEVEL_LAST; ++v) { m_dfx[dt][v].clear(); } } } //------------------------------------------------------------------------------------------------- UnsignedInt DamageFX::getDamageFXThrottleTime(DamageType t, const Object* source) const { return m_dfx[t][source ? source->getVeterancyLevel() : LEVEL_REGULAR].m_damageFXThrottleTime; } //------------------------------------------------------------------------------------------------- void DamageFX::doDamageFX(DamageType t, Real damageAmount, const Object* source, const Object* victim) const { ConstFXListPtr fx = getDamageFXList(t, damageAmount, source); // since the victim is receiving the damage, it's the "primary" object. // the source is the "secondary" object -- unused by most fx, but could be // useful in some cases. FXList::doFXObj(fx, victim, source); } //------------------------------------------------------------------------------------------------- ConstFXListPtr DamageFX::getDamageFXList(DamageType t, Real damageAmount, const Object* source) const { /* if damage is zero, never do damage fx. this is by design, since "zero" damage can happen with some special weapons, like the battleship, which is a "faux" weapon that never does damage. if you really need to change this for some reason, consider carefully... (srj) */ if (damageAmount == 0.0f) return NULL; const DFX& dfx = m_dfx[t][source ? source->getVeterancyLevel() : LEVEL_REGULAR]; ConstFXListPtr fx = damageAmount >= dfx.m_amountForMajorFX ? dfx.m_majorDamageFXList : dfx.m_minorDamageFXList; return fx; } //------------------------------------------------------------------------------------------------- const FieldParse* DamageFX::getFieldParse() const { static const FieldParse myFieldParse[] = { { "AmountForMajorFX", parseAmount, NULL, 0 }, { "MajorFX", parseMajorFXList, NULL, 0 }, { "MinorFX", parseMinorFXList, NULL, 0 }, { "ThrottleTime", parseTime, NULL, 0 }, { "VeterancyAmountForMajorFX", parseAmount, TheVeterancyNames, 0 }, { "VeterancyMajorFX", parseMajorFXList, TheVeterancyNames, 0 }, { "VeterancyMinorFX", parseMinorFXList, TheVeterancyNames, 0 }, { "VeterancyThrottleTime", parseTime, TheVeterancyNames, 0 }, { 0, 0, 0,0 } }; return myFieldParse; } //-------------------------------------------------------------------------------------------Static static void parseCommonStuff( INI* ini, ConstCharPtrArray names, VeterancyLevel& vetFirst, VeterancyLevel& vetLast, DamageType& damageFirst, DamageType& damageLast ) { if (names) { vetFirst = (VeterancyLevel)INI::scanIndexList(ini->getNextToken(), names); vetLast = vetFirst; } else { vetFirst = LEVEL_FIRST; vetLast = LEVEL_LAST; } const char* damageName = ini->getNextToken(); if (stricmp(damageName, "Default") == 0) { damageFirst = (DamageType)0; damageLast = (DamageType)(DAMAGE_NUM_TYPES - 1); } else { damageFirst = (DamageType)DamageTypeFlags::getSingleBitFromName(damageName); damageLast = damageFirst; } } //-------------------------------------------------------------------------------------------Static /*static*/ void DamageFX::parseAmount( INI* ini, void* instance, void* /*store*/, const void* userData ) { DamageFX* self = (DamageFX*)instance; ConstCharPtrArray names = (ConstCharPtrArray)userData; VeterancyLevel vetFirst, vetLast; DamageType damageFirst, damageLast; parseCommonStuff(ini, names, vetFirst, vetLast, damageFirst, damageLast); Real amt = INI::scanReal(ini->getNextToken()); for (Int dt = damageFirst; dt <= damageLast; ++dt) { for (Int v = vetFirst; v <= vetLast; ++v) { self->m_dfx[dt][v].m_amountForMajorFX = amt; } } } //-------------------------------------------------------------------------------------------Static /*static*/ void DamageFX::parseMajorFXList( INI* ini, void* instance, void* /*store*/, const void* userData ) { DamageFX* self = (DamageFX*)instance; ConstCharPtrArray names = (ConstCharPtrArray)userData; VeterancyLevel vetFirst, vetLast; DamageType damageFirst, damageLast; parseCommonStuff(ini, names, vetFirst, vetLast, damageFirst, damageLast); ConstFXListPtr fx; INI::parseFXList(ini, NULL, &fx, NULL); for (Int dt = damageFirst; dt <= damageLast; ++dt) { for (Int v = vetFirst; v <= vetLast; ++v) { self->m_dfx[dt][v].m_majorDamageFXList = fx; } } } //-------------------------------------------------------------------------------------------Static /*static*/ void DamageFX::parseMinorFXList( INI* ini, void* instance, void* /*store*/, const void* userData ) { DamageFX* self = (DamageFX*)instance; ConstCharPtrArray names = (ConstCharPtrArray)userData; VeterancyLevel vetFirst, vetLast; DamageType damageFirst, damageLast; parseCommonStuff(ini, names, vetFirst, vetLast, damageFirst, damageLast); ConstFXListPtr fx; INI::parseFXList(ini, NULL, &fx, NULL); for (Int dt = damageFirst; dt <= damageLast; ++dt) { for (Int v = vetFirst; v <= vetLast; ++v) { self->m_dfx[dt][v].m_minorDamageFXList = fx; } } } //-------------------------------------------------------------------------------------------Static /*static*/ void DamageFX::parseTime( INI* ini, void* instance, void* /*store*/, const void* userData ) { DamageFX* self = (DamageFX*)instance; ConstCharPtrArray names = (ConstCharPtrArray)userData; VeterancyLevel vetFirst, vetLast; DamageType damageFirst, damageLast; parseCommonStuff(ini, names, vetFirst, vetLast, damageFirst, damageLast); UnsignedInt t; INI::parseDurationUnsignedInt(ini, NULL, &t, NULL); for (Int dt = damageFirst; dt <= damageLast; ++dt) { for (Int v = vetFirst; v <= vetLast; ++v) { self->m_dfx[dt][v].m_damageFXThrottleTime = t; } } } //------------------------------------------------------------------------------------------------- //------------------------------------------------------------------------------------------------- //------------------------------------------------------------------------------------------------- //------------------------------------------------------------------------------------------------- DamageFXStore::DamageFXStore() { m_dfxmap.clear(); } //------------------------------------------------------------------------------------------------- DamageFXStore::~DamageFXStore() { m_dfxmap.clear(); } //------------------------------------------------------------------------------------------------- const DamageFX *DamageFXStore::findDamageFX(AsciiString name) const { NameKeyType namekey = TheNameKeyGenerator->nameToKey(name); DamageFXMap::const_iterator it = m_dfxmap.find(namekey); if (it == m_dfxmap.end()) { return NULL; } else { return &(*it).second; } } //------------------------------------------------------------------------------------------------- void DamageFXStore::init() { } //------------------------------------------------------------------------------------------------- void DamageFXStore::reset() { } //------------------------------------------------------------------------------------------------- void DamageFXStore::update() { } //------------------------------------------------------------------------------------------------- /*static */ void DamageFXStore::parseDamageFXDefinition(INI* ini) { const char *c = ini->getNextToken(); NameKeyType key = TheNameKeyGenerator->nameToKey(c); DamageFX& dfx = TheDamageFXStore->m_dfxmap[key]; dfx.clear(); ini->initFromINI(&dfx, dfx.getFieldParse()); }