Initial commit of Command & Conquer Generals and Command & Conquer Generals Zero Hour source code.

This commit is contained in:
LFeenanEA 2025-02-27 17:34:39 +00:00
parent 2e338c00cb
commit 3d0ee53a05
No known key found for this signature in database
GPG key ID: C6EBE8C2EA08F7E0
6072 changed files with 2283311 additions and 0 deletions

View file

@ -0,0 +1,75 @@
/*
** Command & Conquer Generals(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: DrawModule.cpp ///////////////////////////////////////////////////////////////////////////
// Author: Colin Day, September 2002
// Desc: Draw module base class
///////////////////////////////////////////////////////////////////////////////////////////////////
// INCLUDES ///////////////////////////////////////////////////////////////////////////////////////
#include "PreRTS.h"
#include "Common/DrawModule.h"
#include "Common/Xfer.h"
// ------------------------------------------------------------------------------------------------
/** CRC */
// ------------------------------------------------------------------------------------------------
void DrawModule::crc( Xfer *xfer )
{
// extend base class
DrawableModule::crc( xfer );
} // end crc
// ------------------------------------------------------------------------------------------------
/** Xfer method
* Version Info;
* 1: Initial version */
// ------------------------------------------------------------------------------------------------
void DrawModule::xfer( Xfer *xfer )
{
// version
XferVersion currentVersion = 1;
XferVersion version = currentVersion;
xfer->xferVersion( &version, currentVersion );
// extend base class
DrawableModule::xfer( xfer );
} // end xfer
// ------------------------------------------------------------------------------------------------
/** Load post process */
// ------------------------------------------------------------------------------------------------
void DrawModule::loadPostProcess( void )
{
// extend base class
DrawableModule::loadPostProcess();
} // end loadPostProcess

View file

@ -0,0 +1,285 @@
/*
** Command & Conquer Generals(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: Module.cpp ///////////////////////////////////////////////////////////////////////////////
// Author: Colin Day, September 2001
// Desc: Object and drawable modules and actions. These are simply just class
// instances that we can assign to objects, drawables, and things to contain
// data and code for specific events, or just to hold data
///////////////////////////////////////////////////////////////////////////////////////////////////
#include "PreRTS.h" // This must go first in EVERY cpp file in the GameEngine
// INCLUDES ///////////////////////////////////////////////////////////////////////////////////////
#include "Common/Module.h"
#include "Common/Thing.h"
#include "Common/INI.h"
#include "Common/ThingTemplate.h"
#include "Common/Upgrade.h"
#include "Common/Xfer.h"
#include "GameLogic/Object.h"
#include "GameLogic/GameLogic.h"
#include "GameLogic/Module/BodyModule.h"
#include "GameLogic/Module/CollideModule.h"
#include "GameLogic/Module/ContainModule.h"
#include "GameLogic/Module/DamageModule.h"
#include "GameLogic/Module/DieModule.h"
#include "GameLogic/Module/UpdateModule.h"
#include "GameLogic/Module/UpgradeModule.h"
///////////////////////////////////////////////////////////////////////////////////////////////////
// PUBLIC FUNCTIONS ///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////
//-------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------
// this method should NEVER be overridden by user code, only via the MAKE_STANDARD_MODULE_xxx macros!
// it should also NEVER be called directly; it's only for use by ModuleFactory!
/*static*/ ModuleData* Module::friend_newModuleData(INI* ini)
{
ModuleData* data = MSGNEW("Module::friend_newModuleData") ModuleData; // no need to memorypool these since we never allocate more than one of each
if (ini)
ini->initFromINI(data, 0); // this is just so that an "end" token is required
return data;
}
// ------------------------------------------------------------------------------------------------
// ------------------------------------------------------------------------------------------------
Module::~Module()
{
} // end ~Module
// ------------------------------------------------------------------------------------------------
/** CRC */
// ------------------------------------------------------------------------------------------------
void Module::crc( Xfer *xfer )
{
} // end crc
// ------------------------------------------------------------------------------------------------
/** Xfer method
* Version Info:
* 1: Initial version */
// ------------------------------------------------------------------------------------------------
void Module::xfer( Xfer *xfer )
{
// version
XferVersion currentVersion = 1;
XferVersion version = currentVersion;
xfer->xferVersion( &version, currentVersion );
} // end xfer
// ------------------------------------------------------------------------------------------------
/** load post process */
// ------------------------------------------------------------------------------------------------
void Module::loadPostProcess( void )
{
} // end loadPostProcess
//-------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------
ObjectModule::ObjectModule( Thing *thing, const ModuleData* moduleData ) : Module(moduleData)
{
if (!moduleData)
{
DEBUG_CRASH(("module data may not be null\n"));
throw INI_INVALID_DATA;
}
DEBUG_ASSERTCRASH( thing, ("Thing passed to ObjectModule is NULL!\n") );
m_object = AsObject(thing);
DEBUG_ASSERTCRASH( m_object, ("Thing passed to ObjectModule is not an Object!\n") );
} // end ObjectModule
//-------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------
ObjectModule::~ObjectModule( void )
{
} // end ~ObjectModule
// ------------------------------------------------------------------------------------------------
/** CRC */
// ------------------------------------------------------------------------------------------------
void ObjectModule::crc( Xfer *xfer )
{
// extend base class
Module::crc( xfer );
} // end crc
// ------------------------------------------------------------------------------------------------
/** Xfer method
* Version Info:
* 1: Initial version */
// ------------------------------------------------------------------------------------------------
void ObjectModule::xfer( Xfer *xfer )
{
// version
XferVersion currentVersion = 1;
XferVersion version = currentVersion;
xfer->xferVersion( &version, currentVersion );
// extend base class
Module::xfer( xfer );
} // end xfer
// ------------------------------------------------------------------------------------------------
/** load post process */
// ------------------------------------------------------------------------------------------------
void ObjectModule::loadPostProcess( void )
{
// extend base class
Module::loadPostProcess();
} // end loadPostProcess
//-------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------
DrawableModule::DrawableModule( Thing *thing, const ModuleData* moduleData ) : Module(moduleData)
{
if (!moduleData)
{
DEBUG_CRASH(("module data may not be null\n"));
throw INI_INVALID_DATA;
}
DEBUG_ASSERTCRASH( thing, ("Thing passed to DrawableModule is NULL!\n") );
m_drawable = AsDrawable(thing);
DEBUG_ASSERTCRASH( m_drawable, ("Thing passed to DrawableModule is not a Drawable!\n") );
} // end ~DrawableModule
//-------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------
DrawableModule::~DrawableModule( void )
{
} // end ~DrawableModule
// ------------------------------------------------------------------------------------------------
/** CRC */
// ------------------------------------------------------------------------------------------------
void DrawableModule::crc( Xfer *xfer )
{
// extend base class
Module::crc( xfer );
} // end crc
// ------------------------------------------------------------------------------------------------
/** Xfer method
* Version Info:
* 1: Initial version */
// ------------------------------------------------------------------------------------------------
void DrawableModule::xfer( Xfer *xfer )
{
// version
XferVersion currentVersion = 1;
XferVersion version = currentVersion;
xfer->xferVersion( &version, currentVersion );
// extend base class
Module::xfer( xfer );
} // end xfer
// ------------------------------------------------------------------------------------------------
/** load post process */
// ------------------------------------------------------------------------------------------------
void DrawableModule::loadPostProcess( void )
{
// extend base class
Module::loadPostProcess();
} // end loadPostProcess
//-------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------
void UpgradeMuxData::performUpgradeFX(Object* obj) const
{
if (m_fxListUpgrade)
{
FXList::doFXObj(m_fxListUpgrade, obj);
}
}
//-------------------------------------------------------------------------------------------------
void UpgradeMuxData::getUpgradeActivationMasks(Int64& activation, Int64& conflicting) const
{
// already computed.
if (!m_activationUpgradeNames.empty() || !m_conflictingUpgradeNames.empty())
{
m_activationMask = 0;
m_conflictingMask = 0;
std::vector<AsciiString>::const_iterator it;
for( it = m_activationUpgradeNames.begin();
it != m_activationUpgradeNames.end();
it++)
{
const UpgradeTemplate* theTemplate = TheUpgradeCenter->findUpgrade( *it );
if( !theTemplate && !it->isEmpty() && !it->isNone())
{
DEBUG_CRASH(("An upgrade module references %s, which is not an Upgrade", it->str()));
throw INI_INVALID_DATA;
}
m_activationMask |= theTemplate->getUpgradeMask();
}
for( it = m_conflictingUpgradeNames.begin();
it != m_conflictingUpgradeNames.end();
it++)
{
const UpgradeTemplate* theTemplate = TheUpgradeCenter->findUpgrade( *it );
if( !theTemplate && !it->isEmpty() && !it->isNone())
{
DEBUG_CRASH(("An upgrade module references %s, which is not an Upgrade", it->str()));
throw INI_INVALID_DATA;
}
m_conflictingMask |= theTemplate->getUpgradeMask();
}
m_activationUpgradeNames.clear();
m_conflictingUpgradeNames.clear();
}
activation = m_activationMask;
conflicting = m_conflictingMask;
}

View file

@ -0,0 +1,676 @@
/*
** Command & Conquer Generals(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: ModuleFactory.cpp ////////////////////////////////////////////////////////////////////////
// Author: Colin Day, September 2001
// Desc: TheModuleFactory is where we actually instance modules for objects
// and drawbles. Those modules are things such as an UpdateModule
// or DamageModule or DrawModule etc.
//
// TheModuleFactory will contain a list of ModuleTemplates, when we
// request a new module, we will look for that template in our
// list and create it
//
///////////////////////////////////////////////////////////////////////////////////////////////////
// INCLUDES ///////////////////////////////////////////////////////////////////////////////////////
#include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
#include "Common/Module.h"
#include "Common/ModuleFactory.h"
#include "Common/NameKeyGenerator.h"
// behavior includes
#include "GameLogic/Module/AutoHealBehavior.h"
#include "GameLogic/Module/BehaviorModule.h"
#include "GameLogic/Module/BridgeBehavior.h"
#include "GameLogic/Module/BridgeScaffoldBehavior.h"
#include "GameLogic/Module/BridgeTowerBehavior.h"
#include "GameLogic/Module/DumbProjectileBehavior.h"
#include "GameLogic/Module/InstantDeathBehavior.h"
#include "GameLogic/Module/SlowDeathBehavior.h"
#include "GameLogic/Module/HelicopterSlowDeathUpdate.h"
#include "GameLogic/Module/NeutronMissileSlowDeathUpdate.h"
#include "GameLogic/Module/CaveContain.h"
#include "GameLogic/Module/OpenContain.h"
#include "GameLogic/Module/OverchargeBehavior.h"
#include "GameLogic/Module/HealContain.h"
#include "GameLogic/Module/GarrisonContain.h"
#include "GameLogic/Module/TransportContain.h"
#include "GameLogic/Module/RailedTransportContain.h"
#include "GameLogic/Module/MobNexusContain.h"
#include "GameLogic/Module/TunnelContain.h"
#include "GameLogic/Module/OverlordContain.h"
#include "GameLogic/Module/ParachuteContain.h"
#ifdef ALLOW_SURRENDER
#include "GameLogic/Module/POWTruckBehavior.h"
#include "GameLogic/Module/PrisonBehavior.h"
#include "GameLogic/Module/PropagandaCenterBehavior.h"
#endif
#include "GameLogic/Module/PropagandaTowerBehavior.h"
#include "GameLogic/Module/FireWeaponWhenDamagedBehavior.h"
#include "GameLogic/Module/FireWeaponWhenDeadBehavior.h"
#include "GameLogic/Module/GenerateMinefieldBehavior.h"
#include "GameLogic/Module/ParkingPlaceBehavior.h"
#include "GameLogic/Module/PoisonedBehavior.h"
#include "GameLogic/Module/RebuildHoleBehavior.h"
#include "GameLogic/Module/SupplyWarehouseCripplingBehavior.h"
#include "GameLogic/Module/TechBuildingBehavior.h"
#include "GameLogic/Module/MinefieldBehavior.h"
#include "GameLogic/Module/JetSlowDeathBehavior.h"
// die includes
#include "GameLogic/Module/CreateCrateDie.h"
#include "GameLogic/Module/CreateObjectDie.h"
#include "GameLogic/Module/CrushDie.h"
#include "GameLogic/Module/DamDie.h"
#include "GameLogic/Module/DestroyDie.h"
#include "GameLogic/Module/EjectPilotDie.h"
#include "GameLogic/Module/FXListDie.h"
#include "GameLogic/Module/RebuildHoleExposeDie.h"
#include "GameLogic/Module/SpecialPowerCompletionDie.h"
#include "GameLogic/Module/UpgradeDie.h"
#include "GameLogic/Module/KeepObjectDie.h"
// logic update includes
#include "GameLogic/Module/AIUpdate.h"
#include "GameLogic/Module/AssistedTargetingUpdate.h"
#include "GameLogic/Module/BaseRegenerateUpdate.h"
#include "GameLogic/Module/BoneFXUpdate.h"
#include "GameLogic/Module/ChinookAIUpdate.h"
#include "GameLogic/Module/DefaultProductionExitUpdate.h"
#include "GameLogic/Module/DelayedWeaponSetUpgradeUpdate.h"
#include "GameLogic/Module/DeletionUpdate.h"
#include "GameLogic/Module/DeliverPayloadAIUpdate.h"
#include "GameLogic/Module/DozerAIUpdate.h"
#include "GameLogic/Module/DynamicGeometryInfoUpdate.h"
#include "GameLogic/Module/DynamicShroudClearingRangeUpdate.h"
#include "GameLogic/Module/EnemyNearUpdate.h"
#include "GameLogic/Module/FireSpreadUpdate.h"
#include "GameLogic/Module/FirestormDynamicGeometryInfoUpdate.h"
#include "GameLogic/Module/FireWeaponUpdate.h"
#include "GameLogic/Module/FlammableUpdate.h"
#include "GameLogic/Module/FloatUpdate.h"
#include "GameLogic/Module/TensileFormationUpdate.h"
#include "GameLogic/Module/HackInternetAIUpdate.h"
#include "GameLogic/Module/DeployStyleAIUpdate.h"
#include "GameLogic/Module/AssaultTransportAIUpdate.h"
#include "GameLogic/Module/HeightDieUpdate.h"
#include "GameLogic/Module/HordeUpdate.h"
#include "GameLogic/Module/JetAIUpdate.h"
#include "GameLogic/Module/LaserUpdate.h"
#include "GameLogic/Module/PointDefenseLaserUpdate.h"
#include "GameLogic/Module/CleanupHazardUpdate.h"
#include "GameLogic/Module/AutoFindHealingUpdate.h"
#include "GameLogic/Module/CommandButtonHuntUpdate.h"
#include "GameLogic/Module/PilotFindVehicleUpdate.h"
#include "GameLogic/Module/DemoTrapUpdate.h"
#include "GameLogic/Module/ParticleUplinkCannonUpdate.h"
#include "GameLogic/Module/BaikonurLaunchPower.h"
#include "GameLogic/Module/BattlePlanUpdate.h"
#include "GameLogic/Module/LifetimeUpdate.h"
#include "GameLogic/Module/RadiusDecalUpdate.h"
#include "GameLogic/Module/AutoDepositUpdate.h"
#include "GameLogic/Module/MissileAIUpdate.h"
#include "GameLogic/Module/NeutronMissileUpdate.h"
#include "GameLogic/Module/OCLUpdate.h"
#include "GameLogic/Module/PhysicsUpdate.h"
#ifdef ALLOW_SURRENDER
#include "GameLogic/Module/POWTruckAIUpdate.h"
#endif
#include "GameLogic/Module/ProductionUpdate.h"
#include "GameLogic/Module/ProjectileStreamUpdate.h"
#include "GameLogic/Module/ProneUpdate.h"
#include "GameLogic/Module/QueueProductionExitUpdate.h"
#include "GameLogic/Module/RadarUpdate.h"
#include "GameLogic/Module/RepairDockUpdate.h"
#ifdef ALLOW_SURRENDER
#include "GameLogic/Module/PrisonDockUpdate.h"
#endif
#include "GameLogic/Module/RailedTransportDockUpdate.h"
#include "GameLogic/Module/RailedTransportAIUpdate.h"
#include "GameLogic/Module/RailroadGuideAIUpdate.h"
#include "GameLogic/Module/SlavedUpdate.h"
#include "GameLogic/Module/MobMemberSlavedUpdate.h"
#include "GameLogic/Module/SpecialAbilityUpdate.h"
#include "GameLogic/Module/MissileLauncherBuildingUpdate.h"
#include "GameLogic/Module/StealthDetectorUpdate.h"
#include "GameLogic/Module/StealthUpdate.h"
#include "GameLogic/Module/SpawnPointProductionExitUpdate.h"
#include "GameLogic/Module/SpawnBehavior.h"
#include "GameLogic/Module/SpyVisionUpdate.h"
#include "GameLogic/Module/StickyBombUpdate.h"
#include "GameLogic/Module/FireOCLAfterWeaponCooldownUpdate.h"
#include "GameLogic/Module/HijackerUpdate.h"
#include "GameLogic/Module/StructureCollapseUpdate.h"
#include "GameLogic/Module/StructureToppleUpdate.h"
#include "GameLogic/Module/SupplyCenterDockUpdate.h"
#include "GameLogic/Module/SupplyCenterProductionExitUpdate.h"
#include "GameLogic/Module/SupplyTruckAIUpdate.h"
#include "GameLogic/Module/SupplyWarehouseDockUpdate.h"
#include "GameLogic/Module/ToppleUpdate.h"
#include "GameLogic/Module/TransportAIUpdate.h"
#include "GameLogic/Module/WanderAIUpdate.h"
#include "GameLogic/Module/WaveGuideUpdate.h"
#include "GameLogic/Module/WorkerAIUpdate.h"
#include "GameLogic/Module/PowerPlantUpdate.h"
#include "GameLogic/Module/CheckpointUpdate.h"
#include "GameLogic/Module/EMPUpdate.h"
// upgrade includes
#include "GameLogic/Module/ActiveShroudUpgrade.h"
#include "GameLogic/Module/ArmorUpgrade.h"
#include "GameLogic/Module/CommandSetUpgrade.h"
#include "GameLogic/Module/DelayedUpgrade.h"
#include "GameLogic/Module/LocomotorSetUpgrade.h"
#include "GameLogic/Module/ObjectCreationUpgrade.h"
#include "GameLogic/Module/RadarUpgrade.h"
#include "GameLogic/Module/PowerPlantUpgrade.h"
#include "GameLogic/Module/StatusBitsUpgrade.h"
#include "GameLogic/Module/SubObjectsUpgrade.h"
#include "GameLogic/Module/StealthUpgrade.h"
#include "GameLogic/Module/UnpauseSpecialPowerUpgrade.h"
#include "GameLogic/Module/WeaponBonusUpgrade.h"
#include "GameLogic/Module/WeaponSetUpgrade.h"
#include "GameLogic/Module/WeaponBonusUpgrade.h"
#include "GameLogic/Module/CostModifierUpgrade.h"
#include "GameLogic/Module/ExperienceScalarUpgrade.h"
#include "GameLogic/Module/MaxHealthUpgrade.h"
// create includes
#include "GameLogic/Module/SupplyCenterCreate.h"
#include "GameLogic/Module/SupplyWarehouseCreate.h"
#include "GameLogic/Module/GrantUpgradeCreate.h"
#include "GameLogic/Module/PreorderCreate.h"
#include "GameLogic/Module/SpecialPowerCreate.h"
#include "GameLogic/Module/VeterancyGainCreate.h"
// damage includes
#include "GameLogic/Module/BoneFXDamage.h"
#include "GameLogic/Module/TransitionDamageFX.h"
// collide includes
#include "GameLogic/Module/FireWeaponCollide.h"
#include "GameLogic/Module/SquishCollide.h"
#include "GameLogic/Module/HealCrateCollide.h"
#include "GameLogic/Module/MoneyCrateCollide.h"
#include "GameLogic/Module/ShroudCrateCollide.h"
#include "GameLogic/Module/UnitCrateCollide.h"
#include "GameLogic/Module/VeterancyCrateCollide.h"
#include "GameLogic/Module/ConvertToCarBombCrateCollide.h"
#include "GameLogic/Module/ConvertToHijackedVehicleCrateCollide.h"
#include "GameLogic/Module/SalvageCrateCollide.h"
// body includes
#include "GameLogic/Module/InactiveBody.h"
#include "GameLogic/Module/ActiveBody.h"
#include "GameLogic/Module/HighlanderBody.h"
#include "GameLogic/Module/ImmortalBody.h"
#include "GameLogic/Module/StructureBody.h"
#include "GameLogic/Module/HiveStructureBody.h"
// contain includes
// (none)
// special power modules
#include "GameLogic/Module/CashHackSpecialPower.h"
#include "GameLogic/Module/DefectorSpecialPower.h"
#ifdef ALLOW_DEMORALIZE
#include "GameLogic/Module/DemoralizeSpecialPower.h"
#endif
#include "GameLogic/Module/OCLSpecialPower.h"
#include "GameLogic/Module/SpecialAbility.h"
#include "GameLogic/Module/SpyVisionSpecialPower.h"
#include "GameLogic/Module/CashBountyPower.h"
#include "GameLogic/Module/CleanupAreaPower.h"
// destroy includes
// (none)
// client update includes
#include "GameClient/Module/AnimatedParticleSysBoneClientUpdate.h"
#include "GameClient/Module/SwayClientUpdate.h"
#include "GameClient/Module/BeaconClientUpdate.h"
// PUBLIC DATA ////////////////////////////////////////////////////////////////////////////////////
ModuleFactory *TheModuleFactory = NULL; ///< the module factory singleton
// PUBLIC FUNCTIONS ///////////////////////////////////////////////////////////////////////////////
#ifdef _INTERNAL
// for occasional debugging...
//#pragma optimize("", off)
//#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes")
#endif
//-------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------
ModuleFactory::ModuleFactory( void )
{
m_moduleTemplateMap.clear();
m_moduleDataList.clear();
}
//-------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------
ModuleFactory::~ModuleFactory( void )
{
m_moduleTemplateMap.clear();
for (ModuleDataList::iterator i = m_moduleDataList.begin(); i != m_moduleDataList.end(); ++i)
{
const ModuleData* data = *i;
delete data;
}
m_moduleDataList.clear();
}
//-------------------------------------------------------------------------------------------------
/** Initialize the module factory. Any class that needs to be attached
* to objects or drawables as modules needs to add a template
* for that class here */
//-------------------------------------------------------------------------------------------------
void ModuleFactory::init( void )
{
// behavior modules
addModule( AutoHealBehavior );
addModule( BridgeBehavior );
addModule( BridgeScaffoldBehavior );
addModule( BridgeTowerBehavior );
addModule( DumbProjectileBehavior );
addModule( PhysicsBehavior );
addModule( InstantDeathBehavior );
addModule( SlowDeathBehavior );
addModule( HelicopterSlowDeathBehavior );
addModule( NeutronMissileSlowDeathBehavior );
addModule( CaveContain );
addModule( OpenContain );
addModule( OverchargeBehavior );
addModule( HealContain );
addModule( GarrisonContain );
addModule( TransportContain );
addModule( RailedTransportContain );
addModule( MobNexusContain );
addModule( TunnelContain );
addModule( OverlordContain );
addModule( ParachuteContain );
#ifdef ALLOW_SURRENDER
addModule( POWTruckBehavior );
addModule( PrisonBehavior );
addModule( PropagandaCenterBehavior );
#endif
addModule( PropagandaTowerBehavior );
addModule( FireWeaponWhenDamagedBehavior );
addModule( FireWeaponWhenDeadBehavior );
addModule( GenerateMinefieldBehavior );
addModule( ParkingPlaceBehavior );
addModule( PoisonedBehavior );
addModule( RebuildHoleBehavior );
addModule( SupplyWarehouseCripplingBehavior );
addModule( TechBuildingBehavior );
addModule( MinefieldBehavior );
addModule( JetSlowDeathBehavior );
addModule( RailroadBehavior );
addModule( SpawnBehavior );
// die modules
addModule( DestroyDie );
addModule( FXListDie );
addModule( CrushDie );
addModule( DamDie );
addModule( CreateCrateDie );
addModule( CreateObjectDie );
addModule( EjectPilotDie );
addModule( SpecialPowerCompletionDie );
addModule( RebuildHoleExposeDie );
addModule( UpgradeDie );
addModule( KeepObjectDie );
// update modules
addModule( AssistedTargetingUpdate );
addModule( AutoFindHealingUpdate );
addModule( BaseRegenerateUpdate );
addModule( StealthDetectorUpdate );
addModule( StealthUpdate );
addModule( DelayedWeaponSetUpgradeUpdate );
addModule( DeletionUpdate );
addModule( DynamicShroudClearingRangeUpdate );
addModule( DeployStyleAIUpdate );
addModule( AssaultTransportAIUpdate );
addModule( HordeUpdate );
addModule( ToppleUpdate );
addModule( EnemyNearUpdate );
addModule( LifetimeUpdate );
addModule( RadiusDecalUpdate );
addModule( EMPUpdate );
addModule( AutoDepositUpdate );
addModule( MissileAIUpdate );
addModule( NeutronMissileUpdate );
addModule( FireSpreadUpdate );
addModule( FireWeaponUpdate );
addModule( FlammableUpdate );
addModule( FloatUpdate );
addModule( TensileFormationUpdate );
addModule( HeightDieUpdate );
addModule( ChinookAIUpdate );
addModule( JetAIUpdate );
addModule( AIUpdateInterface );
addModule( SupplyTruckAIUpdate );
addModule( DeliverPayloadAIUpdate );
addModule( HackInternetAIUpdate );
addModule( DynamicGeometryInfoUpdate );
addModule( FirestormDynamicGeometryInfoUpdate );
addModule( LaserUpdate );
addModule( PointDefenseLaserUpdate );
addModule( CleanupHazardUpdate );
addModule( CommandButtonHuntUpdate );
addModule( PilotFindVehicleUpdate );
addModule( DemoTrapUpdate );
addModule( ParticleUplinkCannonUpdate );
addModule( BaikonurLaunchPower );
addModule( BattlePlanUpdate );
addModule( ProjectileStreamUpdate );
addModule( QueueProductionExitUpdate );
addModule( RepairDockUpdate );
#ifdef ALLOW_SURRENDER
addModule( PrisonDockUpdate );
#endif
addModule( RailedTransportDockUpdate );
addModule( DefaultProductionExitUpdate );
addModule( SpawnPointProductionExitUpdate );
addModule( SpyVisionUpdate );
addModule( SlavedUpdate );
addModule( MobMemberSlavedUpdate );
addModule( OCLUpdate );
addModule( SpecialAbilityUpdate );
addModule( MissileLauncherBuildingUpdate );
addModule( SupplyCenterProductionExitUpdate );
addModule( SupplyCenterDockUpdate );
addModule( SupplyWarehouseDockUpdate );
addModule( DozerAIUpdate );
#ifdef ALLOW_SURRENDER
addModule( POWTruckAIUpdate );
#endif
addModule( RailedTransportAIUpdate );
addModule( ProductionUpdate );
addModule( ProneUpdate );
addModule( StickyBombUpdate );
addModule( FireOCLAfterWeaponCooldownUpdate );
addModule( HijackerUpdate );
addModule( StructureToppleUpdate );
addModule( StructureCollapseUpdate );
addModule( BoneFXUpdate );
addModule( RadarUpdate );
addModule( TransportAIUpdate );
addModule( WanderAIUpdate );
addModule( WaveGuideUpdate );
addModule( WorkerAIUpdate );
addModule( PowerPlantUpdate );
addModule( CheckpointUpdate );
// upgrade modules
addModule( CostModifierUpgrade );
addModule( ActiveShroudUpgrade );
addModule( ArmorUpgrade );
addModule( CommandSetUpgrade );
addModule( DelayedUpgrade );
addModule( StatusBitsUpgrade );
addModule( SubObjectsUpgrade );
addModule( StealthUpgrade );
addModule( RadarUpgrade );
addModule( PowerPlantUpgrade );
addModule( LocomotorSetUpgrade );
addModule( ObjectCreationUpgrade );
addModule( UnpauseSpecialPowerUpgrade );
addModule( WeaponBonusUpgrade );
addModule( WeaponSetUpgrade );
addModule( WeaponBonusUpgrade );
addModule( ExperienceScalarUpgrade );
addModule( MaxHealthUpgrade );
// create modules
addModule( PreorderCreate );
addModule( SupplyCenterCreate );
addModule( SupplyWarehouseCreate );
addModule( SpecialPowerCreate );
addModule( GrantUpgradeCreate );
addModule( VeterancyGainCreate );
// damage modules
addModule( BoneFXDamage );
addModule( TransitionDamageFX );
// collide modules
addModule( FireWeaponCollide );
addModule( SquishCollide );
addModule( HealCrateCollide );
addModule( MoneyCrateCollide );
addModule( ShroudCrateCollide );
addModule( UnitCrateCollide );
addModule( VeterancyCrateCollide );
addModule( ConvertToCarBombCrateCollide );
addModule( ConvertToHijackedVehicleCrateCollide );
addModule( SalvageCrateCollide );
// body modules
addModule( InactiveBody );
addModule( ActiveBody );
addModule( HighlanderBody );
addModule( ImmortalBody );
addModule( StructureBody );
addModule( HiveStructureBody );
// contain modules
// (none)
// special power modules
addModule( CashHackSpecialPower );
addModule( DefectorSpecialPower );
#ifdef ALLOW_DEMORALIZE
addModule( DemoralizeSpecialPower );
#endif
addModule( OCLSpecialPower );
addModule( SpecialAbility );
addModule( SpyVisionSpecialPower );
addModule( CashBountyPower );
addModule( CleanupAreaPower );
// destroy modules
// (none)
// client update modules
addModule( AnimatedParticleSysBoneClientUpdate );
addModule( SwayClientUpdate );
addModule( BeaconClientUpdate );
} // end init
//-------------------------------------------------------------------------------------------------
Int ModuleFactory::findModuleInterfaceMask(const AsciiString& name, ModuleType type)
{
if (name.isEmpty())
return 0;
const ModuleTemplate* moduleTemplate = findModuleTemplate(name, type);
if (moduleTemplate)
{
return moduleTemplate->m_whichInterfaces;
}
return 0;
}
//-------------------------------------------------------------------------------------------------
ModuleData* ModuleFactory::newModuleDataFromINI(INI* ini, const AsciiString& name, ModuleType type,
const AsciiString& moduleTag)
{
if (name.isEmpty())
return NULL;
const ModuleTemplate* moduleTemplate = findModuleTemplate(name, type);
if (moduleTemplate)
{
ModuleData* md = (*moduleTemplate->m_createDataProc)(ini);
md->setModuleTagNameKey( NAMEKEY( moduleTag ) );
m_moduleDataList.push_back(md);
return md;
}
return NULL;
}
// PRIVATE FUNCTIONS //////////////////////////////////////////////////////////////////////////////
//-------------------------------------------------------------------------------------------------
/*static*/ NameKeyType ModuleFactory::makeDecoratedNameKey(const AsciiString& name, ModuleType type)
{
char tmp[256];
tmp[0] = '0' + (int)type;
strcpy(&tmp[1], name.str());
return TheNameKeyGenerator->nameToKey(tmp);
}
//-------------------------------------------------------------------------------------------------
const ModuleFactory::ModuleTemplate* ModuleFactory::findModuleTemplate(const AsciiString& name, ModuleType type)
{
NameKeyType namekey = makeDecoratedNameKey(name, type);
ModuleTemplateMap::const_iterator it = m_moduleTemplateMap.find(namekey);
if (it == m_moduleTemplateMap.end())
{
DEBUG_CRASH(( "Module name '%s' not found\n", name.str() ));
return NULL;
}
else
{
return &(*it).second;
}
}
//-------------------------------------------------------------------------------------------------
/** Allocate a new acton class istance given the name */
//-------------------------------------------------------------------------------------------------
Module *ModuleFactory::newModule( Thing *thing, const AsciiString& name, const ModuleData* moduleData, ModuleType type )
{
// sanity
if( name.isEmpty() )
{
DEBUG_CRASH(("attempting to create module with empty name\n"));
return NULL;
}
const ModuleTemplate* mt = findModuleTemplate(name, type);
if (mt)
{
Module* mod = (*mt->m_createProc)( thing, moduleData );
#ifdef _DEBUG
if (type == MODULETYPE_BEHAVIOR)
{
BehaviorModule* bm = (BehaviorModule*)mod;
DEBUG_ASSERTCRASH(
((mt->m_whichInterfaces & (MODULEINTERFACE_BODY)) != 0) == (bm->getBody() != NULL),
("getInterfaceMask bad for MODULE_BODY (%s)\n",name.str()));
DEBUG_ASSERTCRASH(
((mt->m_whichInterfaces & (MODULEINTERFACE_COLLIDE)) != 0) == (bm->getCollide() != NULL),
("getInterfaceMask bad for MODULE_COLLIDE (%s)\n",name.str()));
DEBUG_ASSERTCRASH(
((mt->m_whichInterfaces & (MODULEINTERFACE_CONTAIN)) != 0) == (bm->getContain() != NULL),
("getInterfaceMask bad for MODULE_CONTAIN (%s)\n",name.str()));
DEBUG_ASSERTCRASH(
((mt->m_whichInterfaces & (MODULEINTERFACE_CREATE)) != 0) == (bm->getCreate() != NULL),
("getInterfaceMask bad for MODULE_CREATE (%s)\n",name.str()));
DEBUG_ASSERTCRASH(
((mt->m_whichInterfaces & (MODULEINTERFACE_DAMAGE)) != 0) == (bm->getDamage() != NULL),
("getInterfaceMask bad for MODULE_DAMAGE (%s)\n",name.str()));
DEBUG_ASSERTCRASH(
((mt->m_whichInterfaces & (MODULEINTERFACE_DESTROY)) != 0) == (bm->getDestroy() != NULL),
("getInterfaceMask bad for MODULE_DESTROY (%s)\n",name.str()));
DEBUG_ASSERTCRASH(
((mt->m_whichInterfaces & (MODULEINTERFACE_DIE)) != 0) == (bm->getDie() != NULL),
("getInterfaceMask bad for MODULE_DIE (%s)\n",name.str()));
DEBUG_ASSERTCRASH(
((mt->m_whichInterfaces & (MODULEINTERFACE_SPECIAL_POWER)) != 0) == (bm->getSpecialPower() != NULL),
("getInterfaceMask bad for MODULE_SPECIAL_POWER (%s)\n",name.str()));
DEBUG_ASSERTCRASH(
((mt->m_whichInterfaces & (MODULEINTERFACE_UPDATE)) != 0) == (bm->getUpdate() != NULL),
("getInterfaceMask bad for MODULE_UPDATE (%s)\n",name.str()));
DEBUG_ASSERTCRASH(
((mt->m_whichInterfaces & (MODULEINTERFACE_UPGRADE)) != 0) == (bm->getUpgrade() != NULL),
("getInterfaceMask bad for MODULE_UPGRADE (%s)\n",name.str()));
}
#endif
return mod;
}
return NULL;
} // end newModule
//-------------------------------------------------------------------------------------------------
/** Add a module template to our list of templates */
//-------------------------------------------------------------------------------------------------
void ModuleFactory::addModuleInternal( NewModuleProc proc, NewModuleDataProc dataproc, ModuleType type, const AsciiString& name, Int whichIntf )
{
NameKeyType namekey = makeDecoratedNameKey(name, type);
ModuleTemplate& mtm = m_moduleTemplateMap[namekey]; // this creates it if it does not exist already
mtm.m_createProc = proc;
mtm.m_createDataProc = dataproc;
mtm.m_whichInterfaces = whichIntf;
}
//-------------------------------------------------------------------------------------------------
void ModuleFactory::crc( Xfer *xfer )
{
for (ModuleDataList::iterator mdIt = m_moduleDataList.begin(); mdIt != m_moduleDataList.end(); ++mdIt)
{
((ModuleData *)(*mdIt))->crc(xfer);
}
}
//-------------------------------------------------------------------------------------------------
void ModuleFactory::xfer( Xfer *xfer )
{
// version
XferVersion currentVersion = 1;
XferVersion version = currentVersion;
xfer->xferVersion( &version, currentVersion );
for (ModuleDataList::iterator mdIt = m_moduleDataList.begin(); mdIt != m_moduleDataList.end(); ++mdIt)
{
((ModuleData *)(*mdIt))->xfer(xfer);
}
}
//-------------------------------------------------------------------------------------------------
void ModuleFactory::loadPostProcess( void )
{
}

View file

@ -0,0 +1,392 @@
/*
** Command & Conquer Generals(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: Thing.cpp ////////////////////////////////////////////////////////////
// Created: Colin Day, May 2001
//
// Desc: Things are the base class for objects and drawables, objects
// are logic side representations while drawables are client
// side. Common data will be held in the Thing defined here
// and systems that need to work with both of them will work with
// "Things"
//
//-----------------------------------------------------------------------------
#include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
#include "Common/PerfTimer.h"
#include "Common/Thing.h"
#include "Common/ThingTemplate.h"
#include "Common/ThingFactory.h"
#include "Common/GlobalData.h"
#include "Common/NameKeyGenerator.h"
#include "Common/Player.h"
#include "Common/PlayerList.h"
#include "Common/Team.h"
#include "Lib/Trig.h"
#include "GameLogic/TerrainLogic.h"
#ifdef _INTERNAL
// for occasional debugging...
//#pragma optimize("", off)
//#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes")
#endif
//=============================================================================
/** Constructor */
//=============================================================================
Thing::Thing( const ThingTemplate *thingTemplate )
{
// sanity
if( thingTemplate == NULL )
{
// cannot create thing without template
DEBUG_CRASH(( "no template" ));
return;
} // end if
m_template = thingTemplate;
#if defined(_DEBUG) || defined(_INTERNAL)
m_templateName = thingTemplate->getName();
#endif
m_transform.Make_Identity();
m_cachedPos.zero();
m_cachedAngle = 0.0f;
m_cachedDirVector.zero();
m_cachedAltitudeAboveTerrain = 0;
m_cachedAltitudeAboveTerrainOrWater = 0;
m_cacheFlags = 0;
}
//=============================================================================
/** Destructor */
//=============================================================================
Thing::~Thing()
{
}
//DECLARE_PERF_TIMER(ThingMatrixStuff)
//=============================================================================
const ThingTemplate *Thing::getTemplate() const
{
return m_template;
}
//=============================================================================
const Coord3D* Thing::getUnitDirectionVector2D() const
{
//USE_PERF_TIMER(ThingMatrixStuff)
if (!(m_cacheFlags & VALID_DIRVECTOR))
{
Real angle = getOrientation();
m_cachedDirVector.x = Cos( angle );
m_cachedDirVector.y = Sin( angle );
m_cachedDirVector.z = 0;
m_cacheFlags |= VALID_DIRVECTOR;
}
return &m_cachedDirVector;
}
//=============================================================================
void Thing::getUnitDirectionVector2D(Coord3D& dir) const
{
dir = *getUnitDirectionVector2D();
}
//=============================================================================
void Thing::getUnitDirectionVector3D(Coord3D& dir) const
{
Vector3 vdir = m_transform.Get_X_Vector();
vdir.Normalize();
dir.x = vdir.X;
dir.y = vdir.Y;
dir.z = vdir.Z;
}
//=============================================================================
// the nice thing about this is that we don't have to recalc out cached terrain stuff.
void Thing::setPositionZ( Real z )
{
//USE_PERF_TIMER(ThingMatrixStuff)
if( !m_template->isKindOf( KINDOF_STICK_TO_TERRAIN_SLOPE) )
{
Real oldAngle = m_cachedAngle;
Coord3D oldPos = m_cachedPos;
Matrix3D oldMtx = m_transform;
m_transform.Set_Z_Translation( z );
m_cachedPos.z = z;
if (m_cacheFlags & VALID_ALTITUDE_TERRAIN)
{
m_cachedAltitudeAboveTerrain += (z - oldPos.z);
}
if (m_cacheFlags & VALID_ALTITUDE_SEALEVEL)
{
m_cachedAltitudeAboveTerrainOrWater += (z - oldPos.z);
}
reactToTransformChange(&oldMtx, &oldPos, oldAngle);
}
else
{
Matrix3D mtx;
const Bool stickToGround = true; // yes, set the "z" pos
Coord3D pos = m_cachedPos;
pos.z = z;
TheTerrainLogic->alignOnTerrain(getOrientation(), pos, stickToGround, mtx );
setTransformMatrix(&mtx);
}
DEBUG_ASSERTCRASH(!(_isnan(getPosition()->x) || _isnan(getPosition()->y) || _isnan(getPosition()->z)), ("Drawable/Object position NAN! '%s'\n", m_template->getName().str() ));
}
//=============================================================================
void Thing::setPosition( const Coord3D *pos )
{
//USE_PERF_TIMER(ThingMatrixStuff)
if( !m_template->isKindOf( KINDOF_STICK_TO_TERRAIN_SLOPE) )
{
Real oldAngle = m_cachedAngle;
Coord3D oldPos = m_cachedPos;
Matrix3D oldMtx = m_transform;
//DEBUG_ASSERTCRASH(!(_isnan(pos->x) || _isnan(pos->y) || _isnan(pos->z)), ("Drawable/Object position NAN! '%s'\n", m_template->getName().str() ));
m_transform.Set_X_Translation( pos->x );
m_transform.Set_Y_Translation( pos->y );
m_transform.Set_Z_Translation( pos->z );
m_cachedPos = *pos;
m_cacheFlags &= ~(VALID_ALTITUDE_TERRAIN | VALID_ALTITUDE_SEALEVEL); // but don't clear the dir flags.
reactToTransformChange(&oldMtx, &oldPos, oldAngle);
}
else
{
Matrix3D mtx;
const Bool stickToGround = true; // yes, set the "z" pos
TheTerrainLogic->alignOnTerrain(getOrientation(), *pos, stickToGround, mtx );
setTransformMatrix(&mtx);
}
DEBUG_ASSERTCRASH(!(_isnan(getPosition()->x) || _isnan(getPosition()->y) || _isnan(getPosition()->z)), ("Drawable/Object position NAN! '%s'\n", m_template->getName().str() ));
}
//=============================================================================
void Thing::setOrientation( Real angle )
{
//USE_PERF_TIMER(ThingMatrixStuff)
Coord3D u, x, y, z, pos;
// setOrientation always forces us straight up in the Z axis,
// or aligned with the terrain if we have the magic flag set.
// don't want this? call setTransformMatrix instead.
Real oldAngle = m_cachedAngle;
Coord3D oldPos = m_cachedPos;
Matrix3D oldMtx = m_transform;
pos.x = m_transform.Get_X_Translation();
pos.y = m_transform.Get_Y_Translation();
pos.z = m_transform.Get_Z_Translation();
if( m_template->isKindOf( KINDOF_STICK_TO_TERRAIN_SLOPE) )
{
Matrix3D mtx;
const Bool stickToGround = true; // yes, set the "z" pos
TheTerrainLogic->alignOnTerrain(angle, pos, stickToGround, m_transform );
}
else
{
z.x = 0.0f;
z.y = 0.0f;
z.z = 1.0f;
u.x = Cos(angle);
u.y = Sin(angle);
u.z = 0.0f;
y.crossProduct( &z, &u, &y );
x.crossProduct( &y, &z, &x );
m_transform.Set( x.x, y.x, z.x, pos.x,
x.y, y.y, z.y, pos.y,
x.z, y.z, z.z, pos.z );
}
//DEBUG_ASSERTCRASH(-PI <= angle && angle <= PI, ("Please pass only normalized (-PI..PI) angles to setOrientation (%f).\n", angle));
m_cachedAngle = normalizeAngle(angle);
m_cachedPos = pos;
m_cacheFlags &= ~VALID_DIRVECTOR; // but don't clear the altitude flags.
reactToTransformChange(&oldMtx, &oldPos, oldAngle);
DEBUG_ASSERTCRASH(!(_isnan(getPosition()->x) || _isnan(getPosition()->y) || _isnan(getPosition()->z)), ("Drawable/Object position NAN! '%s'\n", m_template->getName().str() ));
}
//=============================================================================
/** Set the world transformation matrix */
//=============================================================================
void Thing::setTransformMatrix( const Matrix3D *mx )
{
//USE_PERF_TIMER(ThingMatrixStuff)
Real oldAngle = m_cachedAngle;
Coord3D oldPos = m_cachedPos;
Matrix3D oldMtx = m_transform;
m_transform = *mx;
m_cachedPos.x = m_transform.Get_X_Translation();
m_cachedPos.y = m_transform.Get_Y_Translation();
m_cachedPos.z = m_transform.Get_Z_Translation();
m_cachedAngle = m_transform.Get_Z_Rotation();
m_cacheFlags = 0;
reactToTransformChange(&oldMtx, &oldPos, oldAngle);
DEBUG_ASSERTCRASH(!(_isnan(getPosition()->x) || _isnan(getPosition()->y) || _isnan(getPosition()->z)), ("Drawable/Object position NAN! '%s'\n", m_template->getName().str() ));
}
//-------------------------------------------------------------------------------------------------
Bool Thing::isKindOf(KindOfType t) const
{
return getTemplate()->isKindOf(t);
}
//-------------------------------------------------------------------------------------------------
Bool Thing::isKindOfMulti(const KindOfMaskType& mustBeSet, const KindOfMaskType& mustBeClear) const
{
return getTemplate()->isKindOfMulti(mustBeSet, mustBeClear);
}
// ------------------------------------------------------------------------------------------------
Bool Thing::isAnyKindOf( const KindOfMaskType& anyKindOf ) const
{
return getTemplate()->isAnyKindOf( anyKindOf );
}
// ------------------------------------------------------------------------------------------------
Real Thing::calculateHeightAboveTerrain() const
{
//USE_PERF_TIMER(ThingMatrixStuff)
const Coord3D* pos = getPosition();
Real terrainZ = TheTerrainLogic->getGroundHeight( pos->x, pos->y );
Real myZ = pos->z;
return myZ - terrainZ;
}
//-------------------------------------------------------------------------------------------------
Real Thing::getHeightAboveTerrain() const
{
if (!(m_cacheFlags & VALID_ALTITUDE_TERRAIN))
{
m_cachedAltitudeAboveTerrain = calculateHeightAboveTerrain();
m_cacheFlags |= VALID_ALTITUDE_TERRAIN;
}
return m_cachedAltitudeAboveTerrain;
}
//-------------------------------------------------------------------------------------------------
Real Thing::getHeightAboveTerrainOrWater() const
{
//USE_PERF_TIMER(ThingMatrixStuff)
if (!(m_cacheFlags & VALID_ALTITUDE_SEALEVEL))
{
const Coord3D* pos = getPosition();
Real waterZ;
if (TheTerrainLogic->isUnderwater(pos->x, pos->y, &waterZ))
{
m_cachedAltitudeAboveTerrainOrWater = pos->z - waterZ;
}
else
{
m_cachedAltitudeAboveTerrainOrWater = getHeightAboveTerrain();
}
m_cacheFlags |= VALID_ALTITUDE_SEALEVEL;
}
return m_cachedAltitudeAboveTerrainOrWater;
}
//=============================================================================
/** If we treat this as airborne, then they slide down slopes. This checks whether
they are high enough that we should let them act like they're flying. jba. */
//=============================================================================
Bool Thing::isSignificantlyAboveTerrain() const
{
// If it's high enough that it will take more than 3 frames to return to the ground,
// then it's significantly airborne. jba
return (getHeightAboveTerrain() > -(3*3)*TheGlobalData->m_gravity);
}
//-------------------------------------------------------------------------------------------------
void Thing::convertBonePosToWorldPos(const Coord3D* bonePos, const Matrix3D* boneTransform, Coord3D* worldPos, Matrix3D* worldTransform) const
{
if (worldTransform)
{
#ifdef ALLOW_TEMPORARIES
*worldTransform = m_transform * (*boneTransform);
#else
worldTransform->mul(m_transform, *boneTransform);
#endif
}
if (worldPos)
{
Vector3 vector;
vector.X = bonePos->x;
vector.Y = bonePos->y;
vector.Z = bonePos->z;
m_transform.Transform_Vector(m_transform, vector, &vector);
worldPos->x = vector.X;
worldPos->y = vector.Y;
worldPos->z = vector.Z;
}
}
// ------------------------------------------------------------------------------------------------
/** Push the 'in' parameter through our transformation matrix and store in 'out' */
// ------------------------------------------------------------------------------------------------
void Thing::transformPoint( const Coord3D *in, Coord3D *out )
{
// santiy
if( in == NULL || out == NULL )
return;
// for conversion
Vector3 vectorIn;
Vector3 vectorOut;
///@ todo this is dumb and we should not have to convert types
// convert to Vector3 datatypes
vectorIn.X = in->x;
vectorIn.Y = in->y;
vectorIn.Z = in->z;
// do the transform
m_transform.Transform_Vector( m_transform, vectorIn, &vectorOut );
// store converted vector in 'out'
out->x = vectorOut.X;
out->y = vectorOut.Y;
out->z = vectorOut.Z;
} // end transformPoint

View file

@ -0,0 +1,542 @@
/*
** Command & Conquer Generals(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: ThingFactory.cpp /////////////////////////////////////////////////////////////////////////
// Created: Colin Day, April 2001
// Desc: This is how we go and make our things, we make our things, we make our things!
///////////////////////////////////////////////////////////////////////////////////////////////////
// INCLUDES ///////////////////////////////////////////////////////////////////////////////////////
#include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
#include "Common/ThingFactory.h"
#include "Common/ThingTemplate.h"
#include "Common/FileSystem.h"
#include "Common/GameAudio.h"
#include "Common/MapObject.h"
#include "Common/ModuleFactory.h"
#include "Common/RandomValue.h"
#include "GameLogic/GameLogic.h"
#include "GameLogic/Object.h"
#include "Common/Player.h"
#include "Common/PlayerList.h"
#include "GameLogic/PartitionManager.h"
#include "GameLogic/Module/CreateModule.h"
#include "Common/ProductionPrerequisite.h"
#include "GameClient/GameClient.h"
#include "GameClient/Drawable.h"
#include "Common/INI.h"
#ifdef _INTERNAL
// for occasional debugging...
///#pragma optimize("", off)
///#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes")
#endif
enum { TEMPLATE_HASH_SIZE = 12288 };
// PUBLIC DATA ////////////////////////////////////////////////////////////////////////////////////
ThingFactory *TheThingFactory = NULL; ///< Thing manager singleton declaration
// STATIC FUNCTIONS ///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////
// PRIVATE METHODS
///////////////////////////////////////////////////////////////////////////////////////////////////
//-------------------------------------------------------------------------------------------------
/** Free all data loaded into this template database */
//-------------------------------------------------------------------------------------------------
void ThingFactory::freeDatabase( void )
{
while (m_firstTemplate)
{
ThingTemplate* tmpl = m_firstTemplate;
m_firstTemplate = m_firstTemplate->friend_getNextTemplate();
tmpl->deleteInstance();
}
m_templateHashMap.clear();
} // end freeDatabase
//-------------------------------------------------------------------------------------------------
/** add the thing template passed in, into the databse */
//-------------------------------------------------------------------------------------------------
void ThingFactory::addTemplate( ThingTemplate *tmplate )
{
ThingTemplateHashMapIt tIt = m_templateHashMap.find(tmplate->getName());
if (tIt != m_templateHashMap.end()) {
DEBUG_CRASH(("Duplicate Thing Template name found: %s\n", tmplate->getName().str()));
}
// Link it to the list
tmplate->friend_setNextTemplate(m_firstTemplate);
m_firstTemplate = tmplate;
// Add it to the hash table.
m_templateHashMap[tmplate->getName()] = tmplate;
} // end addTemplate
///////////////////////////////////////////////////////////////////////////////////////////////////
// PUBLIC METHODS
///////////////////////////////////////////////////////////////////////////////////////////////////
//-------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------
ThingFactory::ThingFactory()
{
m_firstTemplate = NULL;
m_nextTemplateID = 1; // not zero!
m_templateHashMap.resize( TEMPLATE_HASH_SIZE );
} // end ThingFactory
//-------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------
ThingFactory::~ThingFactory()
{
// free all the template data
freeDatabase();
} // end ~ThingFactory
//-------------------------------------------------------------------------------------------------
/** Create a new template with name 'name' and add to our template list */
//-------------------------------------------------------------------------------------------------
ThingTemplate *ThingFactory::newTemplate( const AsciiString& name )
{
ThingTemplate *newTemplate;
// allocate template
newTemplate = newInstance(ThingTemplate);
// if the default template is present, get it and copy over any data to the new template
const ThingTemplate *defaultT = findTemplate( AsciiString( "DefaultThingTemplate" ) );
if( defaultT )
{
// copy over static data
*newTemplate = *defaultT;
newTemplate->setCopiedFromDefault();
} // end if
// give template a unique identifier
newTemplate->friend_setTemplateID( m_nextTemplateID++ );
DEBUG_ASSERTCRASH( m_nextTemplateID != 0, ("m_nextTemplateID wrapped to zero") );
// assign name
newTemplate->friend_setTemplateName( name );
// add to list
addTemplate( newTemplate );
// return the newly created template
return newTemplate;
}
//-------------------------------------------------------------------------------------------------
/** Create newTemplate, copy data from final override of 'thingTemplate' to the newly created one,
* and add newTemplate as the m_override of that final override. NOTE that newTemplate
* is *NOT* added to master template list, it is a hidden place to store
* override values for 'thingTemplate' */
//-------------------------------------------------------------------------------------------------
ThingTemplate* ThingFactory::newOverride( ThingTemplate *thingTemplate )
{
// sanity
DEBUG_ASSERTCRASH( thingTemplate, ("newOverride(): NULL 'parent' thing template\n") );
// sanity just for debuging, the weapon must be in the master list to do overrides
DEBUG_ASSERTCRASH( findTemplate( thingTemplate->getName() ) != NULL,
("newOverride(): Thing template '%s' not in master list\n",
thingTemplate->getName().str()) );
// find final override of the 'parent' template
ThingTemplate *child = (ThingTemplate*) thingTemplate->friend_getFinalOverride();
// allocate new template
ThingTemplate *newTemplate = newInstance(ThingTemplate);
// copy data from final override to 'newTemplate' as a set of initial default values
*newTemplate = *child;
newTemplate->setCopiedFromDefault();
newTemplate->markAsOverride();
child->setNextOverride(newTemplate);
// return the newly created override for us to set values with etc
return newTemplate;
} // end newOverride
//-------------------------------------------------------------------------------------------------
/** Init */
//-------------------------------------------------------------------------------------------------
void ThingFactory::init( void )
{
} // end init
//-------------------------------------------------------------------------------------------------
/** Reset */
//-------------------------------------------------------------------------------------------------
void ThingFactory::reset( void )
{
ThingTemplate *t;
// go through all templates and delete any overrides
for( t = m_firstTemplate; t; /* empty */ )
{
Bool possibleAdjustment = FALSE;
// t itself can be deleted if it is something created for this map only. Therefore,
// we need to store what the next item is so that we don't orphan a bunch of templates.
ThingTemplate *nextT = t->friend_getNextTemplate();
if (t == m_firstTemplate) {
possibleAdjustment = TRUE;
}
// if stillValid is NULL after we delete the overrides, then this template was created for
// this map only. If it also happens to be m_firstTemplate, then we need to update m_firstTemplate
// as well. Finally, if it was only created for this map, we need to remove the name from the
// hash map, to prevent any crashes.
AsciiString templateName = t->getName();
Overridable *stillValid = t->deleteOverrides();
if (stillValid == NULL && possibleAdjustment) {
m_firstTemplate = nextT;
}
if (stillValid == NULL) {
// Also needs to be removed from the Hash map.
m_templateHashMap.erase(templateName);
}
t = nextT;
}
} // end reset
//-------------------------------------------------------------------------------------------------
/** Update */
//-------------------------------------------------------------------------------------------------
void ThingFactory::update( void )
{
} // end update
//-------------------------------------------------------------------------------------------------
/** Return the template with the matching database name */
//-------------------------------------------------------------------------------------------------
const ThingTemplate *ThingFactory::findByTemplateID( UnsignedShort id )
{
for (ThingTemplate *tmpl = m_firstTemplate; tmpl; tmpl = tmpl->friend_getNextTemplate())
{
if (tmpl->getTemplateID() == id)
return tmpl;
}
DEBUG_CRASH(("template %d not found\n",(Int)id));
return NULL;
}
//-------------------------------------------------------------------------------------------------
/** Return the template with the matching database name */
//-------------------------------------------------------------------------------------------------
ThingTemplate *ThingFactory::findTemplateInternal( const AsciiString& name )
{
ThingTemplateHashMapIt tIt = m_templateHashMap.find(name);
if (tIt != m_templateHashMap.end()) {
return tIt->second;
}
#ifdef LOAD_TEST_ASSETS
if (!strncmp(name.str(), TEST_STRING, strlen(TEST_STRING)))
{
ThingTemplate *tmplate = newTemplate( AsciiString( "Un-namedTemplate" ) );
// load the values
tmplate->initForLTA( name );
// Kinda lame, but necessary.
m_templateHashMap.erase("Un-namedTemplate");
m_templateHashMap[name] = tmplate;
// add tmplate template to the database
return findTemplateInternal( name );
}
#endif
//DEBUG_LOG(("*** Object template %s not found\n",name.str()));
return NULL;
} // end getTemplate
//=============================================================================
Object *ThingFactory::newObject( const ThingTemplate *tmplate, Team *team, ObjectStatusBits statusBits )
{
if (tmplate == NULL)
throw ERROR_BAD_ARG;
const std::vector<AsciiString>& asv = tmplate->getBuildVariations();
if (!asv.empty())
{
Int which = GameLogicRandomValue(0, asv.size()-1);
const ThingTemplate* tmp = findTemplate( asv[which] );
if (tmp != NULL)
tmplate = tmp;
}
DEBUG_ASSERTCRASH(!tmplate->isKindOf(KINDOF_DRAWABLE_ONLY), ("You may not create Objects with the template %s, only Drawables\n",tmplate->getName().str()));
// have the game logic create an object of the correct type.
// (this will throw an exception on failure.)
//Added ability to pass in optional statusBits. This is needed to be set prior to
//the onCreate() calls... in the case of constructing.
Object *obj = TheGameLogic->friend_createObject( tmplate, statusBits, team );
// run the create function for the thing
for (BehaviorModule** m = obj->getBehaviorModules(); *m; ++m)
{
CreateModuleInterface* create = (*m)->getCreate();
if (!create)
continue;
create->onCreate();
}
//
// all objects are part of the partition manager system, add it to that
// system now
//
ThePartitionManager->registerObject( obj );
obj->initObject();
return obj;
}
//=============================================================================
Drawable *ThingFactory::newDrawable(const ThingTemplate *tmplate, DrawableStatus statusBits)
{
if (tmplate == NULL)
throw ERROR_BAD_ARG;
Drawable *draw = TheGameClient->friend_createDrawable( tmplate, statusBits );
/** @todo we should keep track of all the drawables we've allocated here
but we'll wait until we have an drawable storage to do that cause it will
all be tied together */
return draw;
} // end newDrawableByType
#if defined(_DEBUG) || defined(_INTERNAL)
AsciiString TheThingTemplateBeingParsedName;
#endif
//-------------------------------------------------------------------------------------------------
/** Parse Object entry */
//-------------------------------------------------------------------------------------------------
/*static*/ void ThingFactory::parseObjectDefinition( INI* ini, const AsciiString& name, const AsciiString& reskinFrom )
{
#if defined(_DEBUG) || defined(_INTERNAL)
TheThingTemplateBeingParsedName = name;
#endif
// find existing item if present
ThingTemplate *thingTemplate = TheThingFactory->findTemplateInternal( name );
if( !thingTemplate )
{
// no item is present, create a new one
thingTemplate = TheThingFactory->newTemplate( name );
if ( ini->getLoadType() == INI_LOAD_CREATE_OVERRIDES )
{
// This ThingTemplate is actually an override, so we will mark it as such so that it properly
// gets deleted on ::reset().
thingTemplate->markAsOverride();
}
}
else if( ini->getLoadType() != INI_LOAD_CREATE_OVERRIDES )
{
//Holy crap, this sucks to debug!!!
//If you have two different objects, the previous code would simply
//allow you to define multiple objects with the same name, and just
//nuke the old one with the new one. So, I (KM) have added this
//assert to notify in case of two same-name objects.
DEBUG_CRASH(( "[LINE: %d in '%s'] Duplicate factionunit %s found!", ini->getLineNum(), ini->getFilename().str(), name.str() ));
}
else
{
thingTemplate = TheThingFactory->newOverride( thingTemplate );
}
if (reskinFrom.isNotEmpty())
{
const ThingTemplate* reskinTmpl = TheThingFactory->findTemplate(reskinFrom);
if (reskinTmpl)
{
thingTemplate->copyFrom(reskinTmpl);
thingTemplate->setCopiedFromDefault();
thingTemplate->setReskinnedFrom(reskinTmpl);
ini->initFromINI( thingTemplate, thingTemplate->getReskinFieldParse() );
}
else
{
DEBUG_CRASH(("ObjectReskin must come after the original Object (%s, %s).\n",reskinFrom.str(),name.str()));
throw INI_INVALID_DATA;
}
}
else
{
ini->initFromINI( thingTemplate, thingTemplate->getFieldParse() );
}
thingTemplate->validate();
#if defined(_DEBUG) || defined(_INTERNAL)
TheThingTemplateBeingParsedName.clear();
#endif
}
//#define CHECK_THING_NAMES
#ifdef CHECK_THING_NAMES
#include "Common/STLTypedefs.h"
const char *outFilenameINI = "thing.txt";
const char *outFilenameStringFile = "thingString.txt";
void resetReportFile( void )
{
FILE *fp = fopen(outFilenameINI, "w");
if (fp)
{
fprintf(fp, "-- ThingTemplate INI Report --\n\n");
fclose(fp);
}
fp = fopen(outFilenameStringFile, "w");
if (fp)
{
fprintf(fp, "-- ThingTemplate String File Report --\n\n");
fclose(fp);
}
}
AsciiStringList missingStrings;
void reportMissingNameInStringFile( AsciiString templateName )
{
// see if we've seen it before
AsciiStringListConstIterator cit = std::find(missingStrings.begin(), missingStrings.end(), templateName);
if (cit != missingStrings.end())
return;
missingStrings.push_back(templateName);
}
void dumpMissingStringNames( void )
{
missingStrings.sort();
FILE *fp = fopen(outFilenameStringFile, "w");
if (fp)
{
fprintf(fp, "-- ThingTemplate String File Report --\n\n");
for (AsciiStringListConstIterator cit = missingStrings.begin(); cit!=missingStrings.end(); cit++)
{
fprintf(fp, "OBJECT:%s\n\"%s\"\nEND\n\n", cit->str(), cit->str());
}
fclose(fp);
}
}
AsciiStringList missingNames;
void reportMissingNameInTemplate( AsciiString templateName )
{
// see if we've seen it before
AsciiStringListConstIterator cit = std::find(missingNames.begin(), missingNames.end(), templateName);
if (cit != missingNames.end())
return;
missingNames.push_back(templateName);
FILE *fp = fopen(outFilenameINI, "a+");
if (fp)
{
fprintf(fp, " DisplayName = OBJECT:%s\n", templateName.str());
fclose(fp);
}
//reportMissingNameInStringFile( templateName );
}
#endif
//-------------------------------------------------------------------------------------------------
/** Post process phase after loading the database files */
//-------------------------------------------------------------------------------------------------
void ThingFactory::postProcessLoad()
{
#ifdef CHECK_THING_NAMES
//resetReportFile();
#endif
// go through all thing templates
for( ThingTemplate *thingTemplate = m_firstTemplate;
thingTemplate;
thingTemplate = thingTemplate->friend_getNextTemplate() )
{
// resolve the prerequisite names
thingTemplate->resolveNames();
#ifdef CHECK_THING_NAMES
if (thingTemplate->getDisplayName().isEmpty())
{
reportMissingNameInTemplate( thingTemplate->getName() );
}
else if (wcsstr(thingTemplate->getDisplayName().str(), L"MISSING:"))
{
AsciiString asciiName;
asciiName.translate(thingTemplate->getDisplayName());
asciiName.removeLastChar();
asciiName = asciiName.str() + 17;
reportMissingNameInStringFile( asciiName );
}
#endif
} // end for
#ifdef CHECK_THING_NAMES
dumpMissingStringNames();
exit(0);
#endif
} // end postProcess

File diff suppressed because it is too large Load diff