From 056719b9c04ce1acc3d3ded8b165a322ff5d7bbe Mon Sep 17 00:00:00 2001 From: pWn3d Date: Sun, 26 Oct 2025 20:52:00 +0100 Subject: [PATCH 1/8] wip --- .../System/GameMemoryInitPools_GeneralsMD.inl | 3 + GeneralsMD/Code/GameEngine/CMakeLists.txt | 6 + .../GameLogic/Module/DroneCarrierAIUpdate.h | 117 +++ .../GameLogic/Module/DroneCarrierContain.h | 29 + .../Module/DroneCarrierSlavedUpdate.h | 35 + .../Include/GameLogic/Module/SlavedUpdate.h | 2 +- .../GameLogic/Module/TransportContain.h | 2 +- .../Source/Common/Thing/ModuleFactory.cpp | 6 + .../Object/Contain/DroneCarrierContain.cpp | 113 +++ .../Update/AIUpdate/DroneCarrierAIUpdate.cpp | 696 ++++++++++++++++++ .../Update/DroneCarrierSlavedUpdate.cpp | 165 +++++ 11 files changed, 1172 insertions(+), 2 deletions(-) create mode 100644 GeneralsMD/Code/GameEngine/Include/GameLogic/Module/DroneCarrierAIUpdate.h create mode 100644 GeneralsMD/Code/GameEngine/Include/GameLogic/Module/DroneCarrierContain.h create mode 100644 GeneralsMD/Code/GameEngine/Include/GameLogic/Module/DroneCarrierSlavedUpdate.h create mode 100644 GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Contain/DroneCarrierContain.cpp create mode 100644 GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/DroneCarrierAIUpdate.cpp create mode 100644 GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/DroneCarrierSlavedUpdate.cpp diff --git a/Core/GameEngine/Source/Common/System/GameMemoryInitPools_GeneralsMD.inl b/Core/GameEngine/Source/Common/System/GameMemoryInitPools_GeneralsMD.inl index d91bedf41d1..6b986f2b907 100644 --- a/Core/GameEngine/Source/Common/System/GameMemoryInitPools_GeneralsMD.inl +++ b/Core/GameEngine/Source/Common/System/GameMemoryInitPools_GeneralsMD.inl @@ -677,5 +677,8 @@ static PoolSizeRec PoolSizes[] = { "SmudgeSet", 32, 32}, { "Smudge", 128, 32}, { "ResetSpecialPowerTimerWhileAliveUpdate", 8, 8 }, + { "DroneCarrierAIUpdate", 8, 8 }, + { "DroneCarrierSlavedUpdate", 8, 8 }, + { "DroneCarrierContain", 8, 8 }, { 0, 0, 0 } }; diff --git a/GeneralsMD/Code/GameEngine/CMakeLists.txt b/GeneralsMD/Code/GameEngine/CMakeLists.txt index fa5f444cabc..67ebd388230 100644 --- a/GeneralsMD/Code/GameEngine/CMakeLists.txt +++ b/GeneralsMD/Code/GameEngine/CMakeLists.txt @@ -335,6 +335,7 @@ set(GAMEENGINE_SRC Include/GameLogic/Module/DelayedUpgradeBehavior.h Include/GameLogic/Module/FlammableUpdate.h Include/GameLogic/Module/FlightDeckBehavior.h + Include/GameLogic/Module/DroneCarrierAIUpdate.h Include/GameLogic/Module/FloatUpdate.h Include/GameLogic/Module/FXListDie.h Include/GameLogic/Module/GarrisonContain.h @@ -497,6 +498,8 @@ set(GAMEENGINE_SRC Include/GameLogic/Module/WorkerAIUpdate.h Include/GameLogic/Module/KodiakDeploymentUpdate.h Include/GameLogic/Module/KodiakUpdate.h + Include/GameLogic/Module/DroneCarrierSlavedUpdate.h + Include/GameLogic/Module/DroneCarrierContain.h Include/GameLogic/Object.h Include/GameLogic/ObjectCreationList.h Include/GameLogic/ObjectIter.h @@ -946,6 +949,7 @@ set(GAMEENGINE_SRC Source/GameLogic/Object/Contain/RiderChangeContain.cpp Source/GameLogic/Object/Contain/TransportContain.cpp Source/GameLogic/Object/Contain/TunnelContain.cpp + Source/GameLogic/Object/Contain/DroneCarrierContain.cpp Source/GameLogic/Object/Create/CreateModule.cpp Source/GameLogic/Object/Create/GrantUpgradeCreate.cpp Source/GameLogic/Object/Create/LockWeaponCreate.cpp @@ -1017,6 +1021,7 @@ set(GAMEENGINE_SRC Source/GameLogic/Object/Update/AIUpdate/WanderAIUpdate.cpp Source/GameLogic/Object/Update/AIUpdate/TeleporterAIUpdate.cpp Source/GameLogic/Object/Update/AIUpdate/WorkerAIUpdate.cpp + Source/GameLogic/Object/Update/AIUpdate/DroneCarrierAIUpdate.cpp Source/GameLogic/Object/Update/AnimationSteeringUpdate.cpp Source/GameLogic/Object/Update/AssistedTargetingUpdate.cpp Source/GameLogic/Object/Update/AutoDepositUpdate.cpp @@ -1094,6 +1099,7 @@ set(GAMEENGINE_SRC Source/GameLogic/Object/Update/ArmorDamageScalarUpdate.cpp Source/GameLogic/Object/Update/KodiakDeploymentUpdate.cpp Source/GameLogic/Object/Update/KodiakUpdate.cpp + Source/GameLogic/Object/Update/DroneCarrierSlavedUpdate.cpp Source/GameLogic/Object/Upgrade/ActiveShroudUpgrade.cpp Source/GameLogic/Object/Upgrade/ArmorUpgrade.cpp Source/GameLogic/Object/Upgrade/CommandSetUpgrade.cpp diff --git a/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/DroneCarrierAIUpdate.h b/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/DroneCarrierAIUpdate.h new file mode 100644 index 00000000000..18f3d8e9a2d --- /dev/null +++ b/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/DroneCarrierAIUpdate.h @@ -0,0 +1,117 @@ +// FILE: DroneCarrierAIUpdate.h ///////////////////////////////////////////////////////////////////// +// Desc: Mobile drone carrier. +/////////////////////////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#ifndef __DRONE_CARRIER_AI_UPDATE_H +#define __DRONE_CARRIER_AI_UPDATE_H + +// INCLUDES /////////////////////////////////////////////////////////////////////////////////////// +#include "GameLogic/Module/BehaviorModule.h" +#include "GameLogic/Module/DieModule.h" +#include "GameLogic/Module/AIUpdate.h" +#include "GameLogic/Module/SpawnBehavior.h" + + +//------------------------------------------------------------------------------------------------- +class DroneCarrierAIUpdateModuleData : public AIUpdateModuleData +{ +public: + Int m_slots; + UnsignedInt m_respawn_time; + + std::vector m_spawnTemplateNameData; + + DroneCarrierAIUpdateModuleData(); + + static void buildFieldParse(MultiIniFieldParse& p); +}; + +//------------------------------------------------------------------------------------------------- +//------------------------------------------------------------------------------------------------- +class DroneCarrierAIUpdate : public AIUpdateInterface, + public SpawnBehaviorInterface, + public DieModuleInterface + //public ExitInterface +{ + + MEMORY_POOL_GLUE_WITH_USERLOOKUP_CREATE(DroneCarrierAIUpdate, "DroneCarrierAIUpdate") + MAKE_STANDARD_MODULE_MACRO_WITH_MODULE_DATA(DroneCarrierAIUpdate, DroneCarrierAIUpdateModuleData) + +public: + + DroneCarrierAIUpdate(Thing* thing, const ModuleData* moduleData); + // virtual destructor prototype provided by memory pool declaration + + static Int getInterfaceMask() { return UpdateModule::getInterfaceMask() | (MODULEINTERFACE_DIE); } + + // BehaviorModule + virtual DieModuleInterface* getDie() { return this; } + + // UpdateModule + virtual UpdateSleepTime update(); + + // SpawnBehaviorInterface + virtual SpawnBehaviorInterface* getSpawnBehaviorInterface() { return this; } + + virtual Bool maySpawnSelfTaskAI(Real maxSelfTaskersRatio) { return false; /*TODO*/ }; + virtual void onSpawnDeath(ObjectID deadSpawn, DamageInfo* damageInfo); + virtual Object* getClosestSlave(const Coord3D* pos); + virtual void orderSlavesToAttackTarget(Object* target, Int maxShotsToFire, CommandSourceType cmdSource); + virtual void orderSlavesToAttackPosition(const Coord3D* pos, Int maxShotsToFire, CommandSourceType cmdSource); + virtual CanAttackResult getCanAnySlavesAttackSpecificTarget(AbleToAttackType attackType, const Object* target, CommandSourceType cmdSource); + virtual CanAttackResult getCanAnySlavesUseWeaponAgainstTarget(AbleToAttackType attackType, const Object* victim, const Coord3D* pos, CommandSourceType cmdSource); + virtual Bool canAnySlavesAttack(); + virtual void orderSlavesToGoIdle(CommandSourceType cmdSource); + virtual void orderSlavesDisabledUntil(DisabledType type, UnsignedInt frame); + virtual void orderSlavesToClearDisabled(DisabledType type); + virtual void giveSlavesStealthUpgrade(Bool grantStealth); + virtual Bool areAllSlavesStealthed() const; + virtual void revealSlaves(); + virtual Bool doSlavesHaveFreedom() const { return false; }; + + // DieModule + virtual void onDie(const DamageInfo* damageInfo); + + // AIUpdateInterface + virtual void aiDoCommand(const AICommandParms* parms); + +private: + + struct DroneSlotInfo + { + UnsignedInt m_slot_id; + ObjectID m_objectInSpace; + + DroneSlotInfo() + { + m_slot_id = 0; + m_objectInSpace = INVALID_ID; + } + }; + Bool is_full(); ///< has this carrier an open spot? + Bool shouldTryToSpawn(); ///< For my own use, should I even think of spawning + Bool createSpawn(); ///< Actual work of creating a guy + + void deployDrones(); ///< let all drones exit the transport + void retrieveDrones(); ///< order all drones to go back to the transport + + void propagateOrdersToDrones(); + void propagateOrderToSpecificDrone(Object* drone); + + bool positionInRange(const Coord3D* loc); + + const ThingTemplate* m_spawnTemplate; ///< What it is I spawn + std::vector m_spawnIDs; ///< IDs of currently active drones + std::vector::const_iterator m_templateNameIterator; + UnsignedInt m_rebuild_time; // which frame a drone will be rebuilt. 0 if not active + Bool m_active; ///< Am I currently turned on + Bool m_initial_spawns; ///< Have initial drones be spawned? (first update frame) + ObjectID m_designatedTarget; + AICommandType m_designatedCommand; + Coord3D m_designatedPosition; +}; + +#endif // __DRONE_CARRIER_AI_UPDATE_H + diff --git a/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/DroneCarrierContain.h b/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/DroneCarrierContain.h new file mode 100644 index 00000000000..604b33940a3 --- /dev/null +++ b/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/DroneCarrierContain.h @@ -0,0 +1,29 @@ +// FILE: DroneCarrierContain.h //////////////////////////////////////////////////////////////////////// +// Desc: expanded transport contain to work with drone carrier +/////////////////////////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#ifndef __DRONE_CARRIER_CONTAIN_H_ +#define __DRONE_CARRIER_CONTAIN_H_ + +// USER INCLUDES ////////////////////////////////////////////////////////////////////////////////// +#include "GameLogic/Module/OpenContain.h" +#include "GameLogic/Module/TransportContain.h" + +//------------------------------------------------------------------------------------------------- +class DroneCarrierContain: public TransportContain +{ + + MEMORY_POOL_GLUE_WITH_USERLOOKUP_CREATE(DroneCarrierContain, "DroneCarrierContain") + MAKE_STANDARD_MODULE_MACRO_WITH_MODULE_DATA(DroneCarrierContain, TransportContainModuleData) + +public: + + DroneCarrierContain(Thing* thing, const ModuleData* moduleData); + // virtual destructor prototype provided by memory pool declaration + + virtual Bool isValidContainerFor(const Object* obj, Bool checkCapacity) const; +}; + +#endif // __TransportContain_H_ diff --git a/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/DroneCarrierSlavedUpdate.h b/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/DroneCarrierSlavedUpdate.h new file mode 100644 index 00000000000..71aa50f0bec --- /dev/null +++ b/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/DroneCarrierSlavedUpdate.h @@ -0,0 +1,35 @@ + +// FILE: DroneCarrierSlavedUpdate.cpp ///////////////////////////////////////////////////////////////////////// +// Desc: expanded Slaved update to work with drone carrier +/////////////////////////////////////////////////////////////////////////////////////////////////// +#pragma once + +#ifndef _DRONE_CARRIER_SLAVED_UPDATE_H_ +#define _DRONE_CARRIER_SLAVED_UPDATE_H_ +#include "Common/INI.h" +#include "GameLogic/Module/UpdateModule.h" +#include "GameLogic/Module/SlavedUpdate.h" + +//------------------------------------------------------------------------------------------------- +class DroneCarrierSlavedUpdateModuleData : public SlavedUpdateModuleData +{ +public: +}; + +class DroneCarrierSlavedUpdate : public SlavedUpdate +{ + + MEMORY_POOL_GLUE_WITH_USERLOOKUP_CREATE(DroneCarrierSlavedUpdate, "DroneCarrierSlavedUpdate") + MAKE_STANDARD_MODULE_MACRO_WITH_MODULE_DATA(DroneCarrierSlavedUpdate, SlavedUpdateModuleData) + +public: + + DroneCarrierSlavedUpdate(Thing* thing, const ModuleData* moduleData); + // virtual destructor prototype provided by memory pool declaration + + virtual UpdateSleepTime update(); ///< Deciding whether or not to make new guys + + virtual SlavedUpdateInterface* getSlavedUpdateInterface() { return this; } +}; + +#endif diff --git a/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/SlavedUpdate.h b/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/SlavedUpdate.h index 9bbc9164151..98241464ca5 100644 --- a/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/SlavedUpdate.h +++ b/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/SlavedUpdate.h @@ -167,7 +167,7 @@ class SlavedUpdate : public UpdateModule, public SlavedUpdateInterface virtual UpdateSleepTime update(); ///< Deciding whether or not to make new guys -private: +protected: void startSlavedEffects( const Object *slaver ); ///< We have been marked as Slaved, so we can't be selected or move too far or other stuff void stopSlavedEffects(); ///< We are no longer slaved. diff --git a/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/TransportContain.h b/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/TransportContain.h index 2cb73f73ea6..3ebd9a5e8ca 100644 --- a/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/TransportContain.h +++ b/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/TransportContain.h @@ -109,10 +109,10 @@ class TransportContain : public OpenContain void letRidersUpgradeWeaponSet( void ); Bool m_payloadCreated; + Int m_extraSlotsInUse; private: - Int m_extraSlotsInUse; UnsignedInt m_frameExitNotBusy; }; diff --git a/GeneralsMD/Code/GameEngine/Source/Common/Thing/ModuleFactory.cpp b/GeneralsMD/Code/GameEngine/Source/Common/Thing/ModuleFactory.cpp index b7d073b3083..2034f9957f8 100644 --- a/GeneralsMD/Code/GameEngine/Source/Common/Thing/ModuleFactory.cpp +++ b/GeneralsMD/Code/GameEngine/Source/Common/Thing/ModuleFactory.cpp @@ -204,6 +204,9 @@ #include "GameLogic/Module/CheckpointUpdate.h" #include "GameLogic/Module/EMPUpdate.h" #include "GameLogic/Module/ResetSpecialPowerTimerWhileAliveUpdate.h" +#include "GameLogic/Module/DroneCarrierAIUpdate.h" +#include "GameLogic/Module/DroneCarrierSlavedUpdate.h" +#include "GameLogic/Module/DroneCarrierContain.h" // upgrade includes #include "GameLogic/Module/ActiveShroudUpgrade.h" @@ -395,6 +398,7 @@ void ModuleFactory::init( void ) addModule( JetSlowDeathBehavior ); addModule( RailroadBehavior ); addModule( SpawnBehavior ); + addModule( DroneCarrierContain ); // die modules addModule( DestroyDie ); @@ -503,6 +507,8 @@ void ModuleFactory::init( void ) addModule( PowerPlantUpdate ); addModule( CheckpointUpdate ); addModule( ResetSpecialPowerTimerWhileAliveUpdate ); + addModule( DroneCarrierAIUpdate ); + addModule( DroneCarrierSlavedUpdate ); // upgrade modules addModule( CostModifierUpgrade ); diff --git a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Contain/DroneCarrierContain.cpp b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Contain/DroneCarrierContain.cpp new file mode 100644 index 00000000000..1f096bc9a54 --- /dev/null +++ b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Contain/DroneCarrierContain.cpp @@ -0,0 +1,113 @@ +// FILE: DroneCarrierContain.cpp ////////////////////////////////////////////////////////////////////// +// Desc: Contain module for drone carrier +/////////////////////////////////////////////////////////////////////////////////////////////////// + +// USER INCLUDES ////////////////////////////////////////////////////////////////////////////////// +#include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine + +#include "Common/Player.h" +#include "Common/ThingTemplate.h" +#include "Common/ThingFactory.h" +#include "Common/Xfer.h" +#include "GameClient/Drawable.h" +#include "GameLogic/AI.h" +#include "GameLogic/AIPathfind.h" +#include "GameLogic/Locomotor.h" +#include "GameLogic/Module/AIUpdate.h" +#include "GameLogic/Module/BodyModule.h" +#include "GameLogic/Module/PhysicsUpdate.h" +#include "GameLogic/Module/StealthUpdate.h" +#include "GameLogic/Module/TransportContain.h" +#include "GameLogic/Module/DroneCarrierContain.h" +#include "GameLogic/Object.h" +#include "GameLogic/Weapon.h" +#include "GameLogic/WeaponSetType.h" + +// PUBLIC ///////////////////////////////////////////////////////////////////////////////////////// +//------------------------------------------------------------------------------------------------- +//------------------------------------------------------------------------------------------------- +DroneCarrierContain::DroneCarrierContain(Thing* thing, const ModuleData* moduleData) : + TransportContain(thing, moduleData) +{ +} + +//------------------------------------------------------------------------------------------------- +//------------------------------------------------------------------------------------------------- +DroneCarrierContain::~DroneCarrierContain(void) +{ +} + +Bool DroneCarrierContain::isValidContainerFor(const Object* rider, Bool checkCapacity) const +{ + // sanity + if (!rider) + return false; + + // no... actually, only OUR OWN units can be transported. + if (rider->getControllingPlayer() != getObject()->getControllingPlayer()) + return false; + + Int transportSlotCount = rider->getTransportSlotCount(); + + // if 0, this object isn't transportable. + if (transportSlotCount == 0) + return false; + + if (checkCapacity) + { + Int containMax = getContainMax(); + Int containCount = getContainCount(); + + if (!(m_extraSlotsInUse + containCount + transportSlotCount <= containMax)) { + return false; + } + } + + // Check if this is actually a slaved unit + for (BehaviorModule** update = rider->getBehaviorModules(); *update; ++update) + { + SlavedUpdateInterface* sdu = (*update)->getSlavedUpdateInterface(); + if (sdu != nullptr) + { + return sdu->getSlaverID() == getObject()->getID(); + } + } + + return false; +} + + +// ------------------------------------------------------------------------------------------------ +/** CRC */ +// ------------------------------------------------------------------------------------------------ +void DroneCarrierContain::crc(Xfer* xfer) +{ + + // extend base class + TransportContain::crc(xfer); + +} // end crc + +// ------------------------------------------------------------------------------------------------ +/** Xfer method + * Version Info: + * 1: Initial version */ + // ------------------------------------------------------------------------------------------------ +void DroneCarrierContain::xfer(Xfer* xfer) +{ + // extend base class + TransportContain::xfer(xfer); + +} // end xfer + +// ------------------------------------------------------------------------------------------------ +/** Load post process */ +// ------------------------------------------------------------------------------------------------ +void DroneCarrierContain::loadPostProcess(void) +{ + + // extend base class + TransportContain::loadPostProcess(); + +} // end loadPostProcess + diff --git a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/DroneCarrierAIUpdate.cpp b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/DroneCarrierAIUpdate.cpp new file mode 100644 index 00000000000..61e1bc21d01 --- /dev/null +++ b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/DroneCarrierAIUpdate.cpp @@ -0,0 +1,696 @@ +// FILE: DroneCarrierAIUpdate.cpp /////////////////////////////////////////////////////////////////// +// Desc: Handles aircraft movement and parking behavior for aircraft carriers. +/////////////////////////////////////////////////////////////////////////////////////////////////// + +// INCLUDES /////////////////////////////////////////////////////////////////////////////////////// +#include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine + +#include "Common/CRCDebug.h" +#include "Common/Player.h" +#include "Common/Team.h" +#include "Common/ThingFactory.h" +#include "Common/ThingTemplate.h" +#include "Common/Xfer.h" + +#include "GameClient/Drawable.h" +#include "GameClient/ParticleSys.h" + +#include "GameLogic/AI.h" +#include "GameLogic/AIPathfind.h" +#include "GameLogic/GameLogic.h" +#include "GameLogic/Object.h" +#include "GameLogic/PartitionManager.h" +#include "GameLogic/TerrainLogic.h" +#include "GameLogic/Weapon.h" + +#include "GameLogic/Module/DroneCarrierAIUpdate.h" +#include "GameLogic/Module/JetAIUpdate.h" +#include "GameLogic/Module/ProductionUpdate.h" +#include "GameLogic/Module/ContainModule.h" + + +DroneCarrierAIUpdateModuleData::DroneCarrierAIUpdateModuleData() +{ + m_respawn_time = 0; + m_spawnTemplateNameData.clear(); +} +//------------------------------------------------------------------------------------------------- +void DroneCarrierAIUpdateModuleData::buildFieldParse(MultiIniFieldParse& p) +{ + AIUpdateModuleData::buildFieldParse(p); + + static const FieldParse dataFieldParse[] = + { + { "RespawnTime", INI::parseDurationUnsignedInt, NULL, offsetof(DroneCarrierAIUpdateModuleData, m_respawn_time) }, + { "DroneTemplateName",INI::parseAsciiStringVectorAppend,NULL, offsetof(DroneCarrierAIUpdateModuleData, m_spawnTemplateNameData) }, + { "Slots", INI::parseInt, NULL, offsetof(DroneCarrierAIUpdateModuleData, m_slots) }, + + { 0, 0, 0, 0 } + }; + p.add(dataFieldParse); +} + +DroneCarrierAIUpdate::DroneCarrierAIUpdate(Thing* thing, const ModuleData* moduleData) : AIUpdateInterface(thing, moduleData) +{ + const DroneCarrierAIUpdateModuleData* md = getDroneCarrierAIUpdateModuleData(); + + m_templateNameIterator = md->m_spawnTemplateNameData.begin(); + m_spawnTemplate = TheThingFactory->findTemplate(*m_templateNameIterator); + m_rebuild_time = 0; + m_active = true; + m_initial_spawns = false; + + m_designatedTarget = INVALID_ID; + m_designatedCommand = AICMD_NO_COMMAND; + m_designatedPosition.zero(); +} + +//------------------------------------------------------------------------------------------------- +//------------------------------------------------------------------------------------------------- +DroneCarrierAIUpdate::~DroneCarrierAIUpdate(void) +{ +} + +Bool DroneCarrierAIUpdate::shouldTryToSpawn() +{ + return false; // TODO +} + +Bool DroneCarrierAIUpdate::createSpawn() +{ + Object* parent = getObject(); + const DroneCarrierAIUpdateModuleData* md = getDroneCarrierAIUpdateModuleData(); + ContainModuleInterface* contain = parent->getContain(); + if (contain == nullptr) { + DEBUG_CRASH(("DroneCarrierAIUpdate requires unit to have a contain module!")); + return false; + } + if (contain->getContainMax() < md->m_slots) { + DEBUG_CRASH(("DroneCarrierAIUpdate requires unit to have a contain module with equal or more slots!")); + return false; + } + + Object* newSpawn = NULL; + + m_spawnTemplate = TheThingFactory->findTemplate(*m_templateNameIterator); + + newSpawn = TheThingFactory->newObject(m_spawnTemplate, parent->getTeam()); // just a little worried about this... + + // Count this unit towards our score. + newSpawn->getControllingPlayer()->onUnitCreated(parent, newSpawn); + + ++m_templateNameIterator; + if (m_templateNameIterator == md->m_spawnTemplateNameData.end()) + { + m_templateNameIterator = md->m_spawnTemplateNameData.begin(); + } + + newSpawn->setProducer(parent); + + // If they have a SlavedUpdate, then I have to tell them who their daddy is from now on. + for (BehaviorModule** update = newSpawn->getBehaviorModules(); *update; ++update) + { + SlavedUpdateInterface* sdu = (*update)->getSlavedUpdateInterface(); + if (sdu != NULL) + { + sdu->onEnslave(parent); + break; + } + } + m_spawnIDs.push_back(newSpawn->getID()); + + contain->addToContain(newSpawn); + return TRUE; +} + +Bool DroneCarrierAIUpdate::is_full() { + const DroneCarrierAIUpdateModuleData* md = getDroneCarrierAIUpdateModuleData(); + return m_spawnIDs.size() >= md->m_slots; +} + +Object* DroneCarrierAIUpdate::getClosestSlave(const Coord3D* pos) +{ + Object* closest = NULL; + Real closestDistance; + + for (const ObjectID & spawn_id : m_spawnIDs) { + Object* obj = TheGameLogic->findObjectByID(spawn_id); + if (obj) + { + Real distance = ThePartitionManager->getDistanceSquared(obj, pos, FROM_CENTER_2D); + + if (!closest || closestDistance > distance) + { + closest = obj; + closestDistance = distance; + } + } + } + return closest; //Could be null! +} + +void DroneCarrierAIUpdate::onSpawnDeath(ObjectID deadSpawn, DamageInfo* damageInfo) +{ + auto it = std::find(m_spawnIDs.begin(), m_spawnIDs.end(), deadSpawn); + + // If the iterator is at the end, we didn't find deadSpawn, so bail out. + // Otherwise, bad crash stuff will happen. + if (it == m_spawnIDs.end()) + return; + + //When one dies, you push (now + delay) as the time a new one should be made + const DroneCarrierAIUpdateModuleData* md = getDroneCarrierAIUpdateModuleData(); + + //trigger rebuilt timer when not active, carrier must have open slot if one died + if (m_rebuild_time == 0) { + m_rebuild_time = TheGameLogic->getFrame() + md->m_respawn_time; + } + + m_spawnIDs.erase(it); +} + +// ------------------------------------------------------------------------------------------------ +void DroneCarrierAIUpdate::orderSlavesToAttackTarget(Object* target, Int maxShotsToFire, CommandSourceType cmdSource) +{ + for (const auto & slave_id: m_spawnIDs) + { + Object* obj = TheGameLogic->findObjectByID(slave_id); + if (obj) + { + AIUpdateInterface* ai = obj->getAI(); + if (ai) + { + ai->aiForceAttackObject(target, maxShotsToFire, cmdSource); + } + } + } +} + +// ------------------------------------------------------------------------------------------------ +void DroneCarrierAIUpdate::orderSlavesToAttackPosition(const Coord3D* pos, Int maxShotsToFire, CommandSourceType cmdSource) +{ + for (const auto& slave_id : m_spawnIDs) + { + Object* obj = TheGameLogic->findObjectByID(slave_id); + if (obj) + { + AIUpdateInterface* ai = obj->getAI(); + if (ai) + { + ai->aiAttackPosition(pos, maxShotsToFire, cmdSource); + } + } + } +} + +// ------------------------------------------------------------------------------------------------ +void DroneCarrierAIUpdate::orderSlavesToGoIdle(CommandSourceType cmdSource) +{ + for (const auto& slave_id : m_spawnIDs) + { + Object* obj = TheGameLogic->findObjectByID(slave_id); + if (obj) + { + AIUpdateInterface* ai = obj->getAI(); + if (ai) + { + ai->aiIdle(cmdSource); + } + } + } +} + +// ------------------------------------------------------------------------------------------------ +void DroneCarrierAIUpdate::orderSlavesDisabledUntil(DisabledType type, UnsignedInt frame) +{ + for (const auto& slave_id : m_spawnIDs) + { + Object* obj = TheGameLogic->findObjectByID(slave_id); + if (obj) + { + AIUpdateInterface* ai = obj->getAI(); + if (ai) + { + ai->aiIdle(CMD_FROM_AI); + } + obj->setDisabledUntil(type, frame); + } + } +} + +// ------------------------------------------------------------------------------------------------ +void DroneCarrierAIUpdate::orderSlavesToClearDisabled(DisabledType type) +{ + for (const auto& slave_id : m_spawnIDs) + { + Object* obj = TheGameLogic->findObjectByID(slave_id); + if (obj) + { + obj->clearDisabled(type); + } + } +} + +// ------------------------------------------------------------------------------------------------ +CanAttackResult DroneCarrierAIUpdate::getCanAnySlavesAttackSpecificTarget(AbleToAttackType attackType, const Object* target, CommandSourceType cmdSource) +{ + Bool invalidShot = FALSE; + for (const auto& slave_id : m_spawnIDs) + { + Object* obj = TheGameLogic->findObjectByID(slave_id); + if (obj) + { + CanAttackResult result = obj->getAbleToAttackSpecificObject(attackType, target, cmdSource); + + switch (result) + { + case ATTACKRESULT_POSSIBLE: + case ATTACKRESULT_POSSIBLE_AFTER_MOVING: + return result; + + case ATTACKRESULT_NOT_POSSIBLE: + break; + + case ATTACKRESULT_INVALID_SHOT: + invalidShot = TRUE; + break; + + default: + DEBUG_CRASH(("DroneCarrierAIUpdate::getCanAnySlavesAttackSpecificTarget encountered unhandled CanAttackResult of %d. Treating as not possible...", result)); + break; + } + } + } + //Prioritize the reasonings! + if (invalidShot) + { + return ATTACKRESULT_INVALID_SHOT; + } + return ATTACKRESULT_NOT_POSSIBLE; +} + +// ------------------------------------------------------------------------------------------------ +CanAttackResult DroneCarrierAIUpdate::getCanAnySlavesUseWeaponAgainstTarget(AbleToAttackType attackType, const Object* victim, const Coord3D* pos, CommandSourceType cmdSource) +{ + Bool invalidShot = FALSE; + for (const auto& slave_id : m_spawnIDs) + { + Object* obj = TheGameLogic->findObjectByID(slave_id); + if (obj) + { + CanAttackResult result = obj->getAbleToUseWeaponAgainstTarget(attackType, victim, pos, cmdSource); + + switch (result) + { + case ATTACKRESULT_POSSIBLE: + case ATTACKRESULT_POSSIBLE_AFTER_MOVING: + return result; + + case ATTACKRESULT_NOT_POSSIBLE: + break; + + case ATTACKRESULT_INVALID_SHOT: + invalidShot = TRUE; + break; + + default: + DEBUG_CRASH(("DroneCarrierAIUpdate::getCanAnySlavesUseWeaponAgainstTarget encountered unhandled CanAttackResult of %d. Treating as not possible...", result)); + break; + } + } + } + //Prioritize the reasonings! + if (invalidShot) + { + return ATTACKRESULT_INVALID_SHOT; + } + return ATTACKRESULT_NOT_POSSIBLE; +} + +// ------------------------------------------------------------------------------------------------ +void DroneCarrierAIUpdate::giveSlavesStealthUpgrade(Bool grantStealth) +{ + for (const auto& slave_id : m_spawnIDs) + { + Object* obj = TheGameLogic->findObjectByID(slave_id); + if (obj) + { + obj->setStatus(MAKE_OBJECT_STATUS_MASK(OBJECT_STATUS_CAN_STEALTH), grantStealth); + } + } +} + +Bool DroneCarrierAIUpdate::canAnySlavesAttack() +{ + for (const auto& slave_id : m_spawnIDs) + { + Object* obj = TheGameLogic->findObjectByID(slave_id); + if (obj) + { + if (obj->isAbleToAttack()) + { + return true; + } + } + } + return false; +} +// ------------------------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------------------------- +Bool DroneCarrierAIUpdate::areAllSlavesStealthed() const +{ + Object* currentSpawn; + + for (const auto& slave_id : m_spawnIDs) + { + currentSpawn = TheGameLogic->findObjectByID((slave_id)); + if (currentSpawn) + { + const StealthUpdate* stealthUpdate = currentSpawn->getStealth(); + if (!stealthUpdate || !stealthUpdate->allowedToStealth(currentSpawn)) + { + return FALSE; + } + } + } + + return TRUE; //0 or more spawns are ALL stealthed... I suppose if you have NO spawns, then they are considered stealthed ;) +} + +//------------------------------------------------------------------------------------------------- +void DroneCarrierAIUpdate::revealSlaves() +{ + Object* currentSpawn; + + for (const auto& slave_id : m_spawnIDs) + { + currentSpawn = TheGameLogic->findObjectByID((slave_id)); + if (currentSpawn) + { + StealthUpdate* stealthUpdate = currentSpawn->getStealth(); + if (stealthUpdate) + { + stealthUpdate->markAsDetected(); + } + } + } +} + +/*************************************************/ +/* DIE */ +//------------------------------------------------------------------------------------------------- +void DroneCarrierAIUpdate::onDie(const DamageInfo* damageInfo) +{ + // kill all drone slaves + for (const auto& slave_id : m_spawnIDs) + { + Object* obj = TheGameLogic->findObjectByID(slave_id); + if (obj == NULL || obj->isEffectivelyDead()) + continue; + + //TODO config option for disabled effect? + obj->setDisabled(DISABLED_UNMANNED); + if (obj->getAI()) + obj->getAI()->aiIdle(CMD_FROM_AI); + //obj->kill(); + } +} + +/****************************************/ +void DroneCarrierAIUpdate::deployDrones() +{ + for (const auto& slave_id : m_spawnIDs) + { + Object* carrier = getObject(); + Object* obj = TheGameLogic->findObjectByID(slave_id); + if (obj == NULL || obj->isEffectivelyDead()) + continue; + + if (obj->isContained()) { + AIUpdateInterface* ai = obj->getAI(); + if (ai != nullptr) { + ai->aiExit(carrier, CMD_FROM_AI); + } + } + } +} + +void DroneCarrierAIUpdate::retrieveDrones() +{ + //Order all outside drones back inside! + for (const auto& slave_id : m_spawnIDs) + { + Object* member = TheGameLogic->findObjectByID(slave_id); + AIUpdateInterface* ai = member ? member->getAI() : NULL; + if (member && ai) + { + Bool contained = member->isContained(); + if (!contained) + { + if (ai->getAIStateType() != AI_ENTER) { + ai->aiEnter(getObject(), CMD_FROM_AI); + } + } + } + } +} + +void DroneCarrierAIUpdate::propagateOrderToSpecificDrone(Object* drone) +{ + if (drone != nullptr) + { + AIUpdateInterface* ai = drone->getAI(); + if (ai != nullptr) + { + Object* target = TheGameLogic->findObjectByID(m_designatedTarget); + bool contained = drone->isContained(); + switch (m_designatedCommand) + { + case AICMD_GUARD_POSITION: + if (!contained) { + ai->aiGuardPosition(&m_designatedPosition, GUARDMODE_NORMAL, CMD_FROM_AI); + } + else { + ai->aiExit(getObject(), CMD_FROM_AI); + } + break; + case AICMD_ATTACK_POSITION: + if (!contained) { + ai->aiAttackPosition(&m_designatedPosition, NO_MAX_SHOTS_LIMIT, CMD_FROM_AI); + } + else { + ai->aiExit(getObject(), CMD_FROM_AI); + } + break; + case AICMD_FORCE_ATTACK_OBJECT: + case AICMD_ATTACK_OBJECT: + if (!contained) { + ai->aiForceAttackObject(target, NO_MAX_SHOTS_LIMIT, CMD_FROM_PLAYER); + } + else { + ai->aiExit(getObject(), CMD_FROM_AI); + } + break; + case AICMD_ATTACKMOVE_TO_POSITION: + if (!contained) { + ai->aiAttackMoveToPosition(&m_designatedPosition, NO_MAX_SHOTS_LIMIT, CMD_FROM_AI); + } + else + { + ai->aiExit(getObject(), CMD_FROM_AI); + } + break; + case AICMD_IDLE: + if (!contained) { + ai->aiEnter(getObject(), CMD_FROM_AI); + } + else { + ai->aiIdle(CMD_FROM_AI); + } + break; + } + } + } +} + +bool DroneCarrierAIUpdate::positionInRange(const Coord3D* loc) +{ + Object* carrier = getObject(); + Weapon* primaryWeapon = carrier->getWeaponInWeaponSlot(PRIMARY_WEAPON); + + // set a limit on how far drones are send out + if (primaryWeapon == nullptr) { + return true; + } + + Real range = primaryWeapon->getAttackRange(carrier); + Coord3D pos = *carrier->getPosition(); + pos.sub(loc); + return pos.lengthSqr() <= range * range; +} + +//------------------------------------------------------------------------------------------------- +void DroneCarrierAIUpdate::propagateOrdersToDrones() +{ + for (const auto& slave_id : m_spawnIDs) + { + Object* drone = TheGameLogic->findObjectByID(slave_id); + if (drone != nullptr) { + propagateOrderToSpecificDrone(drone); + } + } +} + +/**********************************************/ +/* AI Update */ +//------------------------------------------------------------------------------------------------- +void DroneCarrierAIUpdate::aiDoCommand(const AICommandParms* parms) +{ + //forward commands to drones + if (parms->m_cmdSource != CMD_FROM_AI) + { + //Now the only time we care about anything is if we were ordered to attack something or attack move. + switch (parms->m_cmd) + { + case AICMD_GUARD_POSITION: + m_designatedTarget = INVALID_ID; + m_designatedPosition.set(&parms->m_pos); + m_designatedCommand = parms->m_cmd; + //if (positionInRange(&m_designatedPosition)) + // propagateOrdersToDrones(); + break; + case AICMD_ATTACK_POSITION: + m_designatedTarget = INVALID_ID; + m_designatedPosition.set(&parms->m_pos); + m_designatedCommand = parms->m_cmd; + //if (positionInRange(&m_designatedPosition)) + // propagateOrdersToDrones(); + break; + case AICMD_FORCE_ATTACK_OBJECT: + case AICMD_ATTACK_OBJECT: + m_designatedTarget = parms->m_obj ? parms->m_obj->getID() : INVALID_ID; + m_designatedPosition.zero(); + m_designatedCommand = parms->m_cmd; + //if (parms->m_obj != nullptr && positionInRange(parms->m_obj->getPosition())) + // propagateOrdersToDrones(); + break; + case AICMD_ATTACKMOVE_TO_POSITION: + m_designatedTarget = INVALID_ID; + m_designatedPosition.set(&parms->m_pos); + m_designatedCommand = parms->m_cmd; + //if (positionInRange(&m_designatedPosition)) + // propagateOrdersToDrones(); + break; + case AICMD_IDLE: + m_designatedTarget = INVALID_ID; + m_designatedPosition.zero(); + m_designatedCommand = parms->m_cmd; + //propagateOrdersToDrones(); + break; + default: + m_designatedCommand = AICMD_NO_COMMAND; + break; + } + } + + AIUpdateInterface::aiDoCommand( parms ); +} + + +UpdateSleepTime DroneCarrierAIUpdate::update() +{ + const DroneCarrierAIUpdateModuleData* data = getDroneCarrierAIUpdateModuleData(); + + // initially fill + if (!m_initial_spawns) { + for (size_t i = 0; i < data->m_slots; i++) { + createSpawn(); + } + m_initial_spawns = true; + } + + UnsignedInt now = TheGameLogic->getFrame(); + + if (m_rebuild_time != 0 && m_rebuild_time <= now && !is_full()) + { + if (createSpawn()) { + if (is_full()) { + m_rebuild_time = 0; + } + else { + m_rebuild_time = now + data->m_respawn_time; + } + } + } + + Object* my_target = getCurrentVictim(); + if (my_target != nullptr) { + + if (positionInRange(my_target->getPosition())) { + // send out contained drones + deployDrones(); + + //update orders + if (now % 5 == 0) { //do every 5th frame + switch (m_designatedCommand) { + case AICMD_GUARD_POSITION: + case AICMD_ATTACK_POSITION: + case AICMD_FORCE_ATTACK_OBJECT: + case AICMD_ATTACK_OBJECT: + case AICMD_ATTACKMOVE_TO_POSITION: + propagateOrdersToDrones(); + break; + default: + break; + } + } + } + } + + return AIUpdateInterface::update(); +} + +// ------------------------------------------------------------------------------------------------ +/** CRC */ +// ------------------------------------------------------------------------------------------------ +void DroneCarrierAIUpdate::crc(Xfer* xfer) +{ + + // extend base class + AIUpdateInterface::crc(xfer); + +} // end crc + +// ------------------------------------------------------------------------------------------------ +/** Xfer method + * Version Info: + * 1: Initial version + * 2: Added m_initialBurstTimesInited to the save. jba. +*/ +// ------------------------------------------------------------------------------------------------ +void DroneCarrierAIUpdate::xfer(Xfer* xfer) +{ + AsciiString name; + + // version + XferVersion currentVersion = 2; + XferVersion version = currentVersion; + xfer->xferVersion(&version, currentVersion); + + // extend base class + AIUpdateInterface::xfer(xfer); + + +} // end xfer + +// ------------------------------------------------------------------------------------------------ +/** Load post process */ +// ------------------------------------------------------------------------------------------------ +void DroneCarrierAIUpdate::loadPostProcess(void) +{ + + // extend base class + AIUpdateInterface::loadPostProcess(); + +} // end loadPostProcess diff --git a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/DroneCarrierSlavedUpdate.cpp b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/DroneCarrierSlavedUpdate.cpp new file mode 100644 index 00000000000..db1e379edfc --- /dev/null +++ b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/DroneCarrierSlavedUpdate.cpp @@ -0,0 +1,165 @@ +#include "GameLogic/Module/AIUpdate.h" +#include "GameLogic/Module/DroneCarrierSlavedUpdate.h" +#include "GameLogic/Object.h" + +#include "Common/RandomValue.h" +#include "Common/Xfer.h" +#include "Common/Team.h" +#include "Common/MiscAudio.h" +#include "GameClient/Drawable.h" +#include "GameClient/ParticleSys.h" +#include "GameLogic/AIPathfind.h" +#include "GameLogic/Damage.h" +#include "GameLogic/GameLogic.h" +#include "GameLogic/Locomotor.h" +#include "GameLogic/PartitionManager.h" +#include "GameLogic/TerrainLogic.h" +#include "GameLogic/Module/BodyModule.h" +#include "GameLogic/Module/SlavedUpdate.h" +#include "GameLogic/Weapon.h" +#include "Common/ThingTemplate.h" + +// copies from SlavedUpdate.cpp +#define STRAY_MULTIPLIER 2.0f // Multiplier from stating diestance from tunnel, to max distance from +const Real CLOSE_ENOUGH = 15; // Our moveTo commands and pathfinding can't handle people in the way, so quit trying to hump someone on your spot +const Real CLOSE_ENOUGH_SQR = (CLOSE_ENOUGH * CLOSE_ENOUGH); + +DroneCarrierSlavedUpdate::DroneCarrierSlavedUpdate(Thing* thing, const ModuleData* moduleData) : SlavedUpdate(thing, moduleData) +{ +} + +//------------------------------------------------------------------------------------------------- +DroneCarrierSlavedUpdate::~DroneCarrierSlavedUpdate(void) +{ +} + +UpdateSleepTime DroneCarrierSlavedUpdate::update(void) +{ + if (m_framesToWait > 0) + { + m_framesToWait--; + } + if (m_repairState == REPAIRSTATE_NONE) + { + if (m_framesToWait > 0) + { + return UPDATE_SLEEP_NONE; + } + m_framesToWait = SLAVED_UPDATE_RATE; + } + + if (m_slaver == INVALID_ID) + return UPDATE_SLEEP_NONE; + + const SlavedUpdateModuleData* data = getSlavedUpdateModuleData(); + Object* me = getObject(); + if (!me) + { + return UPDATE_SLEEP_NONE; + } + AIUpdateInterface* myAI = me->getAIUpdateInterface(); + if (!myAI) + { + return UPDATE_SLEEP_NONE; + } + Locomotor* locomotor = myAI->getCurLocomotor(); + if (!locomotor) + { + return UPDATE_SLEEP_NONE; + } + + Object* master = TheGameLogic->findObjectByID(m_slaver); + if (!master || master->isEffectivelyDead() || master->isDisabledByType(DISABLED_UNMANNED)) + { + stopSlavedEffects(); + + //Let's disable the drone so it crashes instead! + //Added special case code in physics falling to ensure death. + me->setDisabled(DISABLED_UNMANNED); + if (me->getAI()) + me->getAI()->aiIdle(CMD_FROM_AI); + + return UPDATE_SLEEP_NONE; + } + else + { + Team* masterTeam = master->getTeam(); + Team* myTeam = me->getTeam(); + if (masterTeam->getRelationship(myTeam) != ALLIES) + {//slaver must have been hijacked or something.. // we will join his team + me->defect(masterTeam, 0); + } + } + + if (data->m_stayOnSameLayerAsMaster) + me->setLayer(master->getLayer()); + + + Object* target = NULL; + AIUpdateInterface* masterAI = master->getAIUpdateInterface(); + if (masterAI) + { + target = masterAI->getCurrentVictim(); + } + + AIUpdateInterface* ai = me->getAI(); + if (ai == nullptr) return UPDATE_SLEEP_NONE; + + if (data->m_attackRange) + { + if (target) + { + doAttackLogic(target); + + return UPDATE_SLEEP_NONE; + } + } + + // No Target, go home to carrier + if (!me->isContained()) { + if (ai->isIdle()) { + ai->aiEnter(master, CMD_FROM_AI); + } + } + return UPDATE_SLEEP_NONE; +} + +// ------------------------------------------------------------------------------------------------ +/** CRC */ +// ------------------------------------------------------------------------------------------------ +void DroneCarrierSlavedUpdate::crc(Xfer* xfer) +{ + + // extend base class + SlavedUpdate::crc(xfer); + +} // end crc + +// ------------------------------------------------------------------------------------------------ +/** Xfer method + * Version Info: + * 1: Initial version */ + // ------------------------------------------------------------------------------------------------ +void DroneCarrierSlavedUpdate::xfer(Xfer* xfer) +{ + + // version + XferVersion currentVersion = 1; + XferVersion version = currentVersion; + xfer->xferVersion(&version, currentVersion); + + // extend base class + SlavedUpdate::xfer(xfer); + +} // end xfer + +// ------------------------------------------------------------------------------------------------ +/** Load post process */ +// ------------------------------------------------------------------------------------------------ +void DroneCarrierSlavedUpdate::loadPostProcess(void) +{ + + // extend base class + SlavedUpdate::loadPostProcess(); + +} // end loadPostProcess From d1f8f04e0b336f253e2ddde8ddd25782ca961d4a Mon Sep 17 00:00:00 2001 From: pWn3d Date: Sun, 16 Nov 2025 13:20:57 +0100 Subject: [PATCH 2/8] carrier stuff --- .../System/GameMemoryInitPools_GeneralsMD.inl | 2 + .../GameLogic/Module/DroneCarrierContain.h | 14 +- .../Module/DroneCarrierSlavedUpdate.h | 1 + .../GameLogic/Module/TransportContain.h | 2 - .../Object/Contain/DroneCarrierContain.cpp | 146 ++++++++++++++- .../Code/GameEngineDevice/CMakeLists.txt | 4 + .../Module/W3DDependencyCarrierDraw.h | 30 ++++ .../Common/Thing/W3DModuleFactory.cpp | 2 + .../Draw/W3DDependencyCarrierDraw.cpp | 167 ++++++++++++++++++ 9 files changed, 364 insertions(+), 4 deletions(-) create mode 100644 GeneralsMD/Code/GameEngineDevice/Include/W3DDevice/GameClient/Module/W3DDependencyCarrierDraw.h create mode 100644 GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/Drawable/Draw/W3DDependencyCarrierDraw.cpp diff --git a/Core/GameEngine/Source/Common/System/GameMemoryInitPools_GeneralsMD.inl b/Core/GameEngine/Source/Common/System/GameMemoryInitPools_GeneralsMD.inl index 6b986f2b907..c8dd3de2b5a 100644 --- a/Core/GameEngine/Source/Common/System/GameMemoryInitPools_GeneralsMD.inl +++ b/Core/GameEngine/Source/Common/System/GameMemoryInitPools_GeneralsMD.inl @@ -680,5 +680,7 @@ static PoolSizeRec PoolSizes[] = { "DroneCarrierAIUpdate", 8, 8 }, { "DroneCarrierSlavedUpdate", 8, 8 }, { "DroneCarrierContain", 8, 8 }, + { "W3DCarrierDraw", 8, 8 }, + { "W3DDependencyCarrierDraw", 8, 8 }, { 0, 0, 0 } }; diff --git a/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/DroneCarrierContain.h b/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/DroneCarrierContain.h index 604b33940a3..1a4b61f9162 100644 --- a/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/DroneCarrierContain.h +++ b/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/DroneCarrierContain.h @@ -10,9 +10,10 @@ // USER INCLUDES ////////////////////////////////////////////////////////////////////////////////// #include "GameLogic/Module/OpenContain.h" #include "GameLogic/Module/TransportContain.h" +#include "GameLogic/Module/GarrisonContain.h" //------------------------------------------------------------------------------------------------- -class DroneCarrierContain: public TransportContain +class DroneCarrierContain: public TransportContain //public GarrisonContain { MEMORY_POOL_GLUE_WITH_USERLOOKUP_CREATE(DroneCarrierContain, "DroneCarrierContain") @@ -23,7 +24,18 @@ class DroneCarrierContain: public TransportContain DroneCarrierContain(Thing* thing, const ModuleData* moduleData); // virtual destructor prototype provided by memory pool declaration + //Only allow slaved units in virtual Bool isValidContainerFor(const Object* obj, Bool checkCapacity) const; + + virtual Bool isEnclosingContainerFor(const Object* obj) const { return true; } //TODO param in module + + //support for specific exit bones + virtual void onRemoving(Object* obj); + + virtual short getRiderSlot(ObjectID riderID) const override; + virtual short getPortableSlot(ObjectID portableID) const override; + virtual const ContainedItemsList* getAddOnList() const override; + virtual ContainedItemsList* getAddOnList() override; }; #endif // __TransportContain_H_ diff --git a/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/DroneCarrierSlavedUpdate.h b/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/DroneCarrierSlavedUpdate.h index 71aa50f0bec..1de6d108e54 100644 --- a/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/DroneCarrierSlavedUpdate.h +++ b/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/DroneCarrierSlavedUpdate.h @@ -30,6 +30,7 @@ class DroneCarrierSlavedUpdate : public SlavedUpdate virtual UpdateSleepTime update(); ///< Deciding whether or not to make new guys virtual SlavedUpdateInterface* getSlavedUpdateInterface() { return this; } + }; #endif diff --git a/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/TransportContain.h b/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/TransportContain.h index 3ebd9a5e8ca..c6634e1d534 100644 --- a/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/TransportContain.h +++ b/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/TransportContain.h @@ -111,8 +111,6 @@ class TransportContain : public OpenContain Bool m_payloadCreated; Int m_extraSlotsInUse; -private: - UnsignedInt m_frameExitNotBusy; }; diff --git a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Contain/DroneCarrierContain.cpp b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Contain/DroneCarrierContain.cpp index 1f096bc9a54..4629a434d71 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Contain/DroneCarrierContain.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Contain/DroneCarrierContain.cpp @@ -27,6 +27,7 @@ //------------------------------------------------------------------------------------------------- //------------------------------------------------------------------------------------------------- DroneCarrierContain::DroneCarrierContain(Thing* thing, const ModuleData* moduleData) : + //GarrisonContain(thing, moduleData) TransportContain(thing, moduleData) { } @@ -58,7 +59,10 @@ Bool DroneCarrierContain::isValidContainerFor(const Object* rider, Bool checkCap Int containMax = getContainMax(); Int containCount = getContainCount(); - if (!(m_extraSlotsInUse + containCount + transportSlotCount <= containMax)) { + /*if (!(m_extraSlotsInUse + containCount + transportSlotCount <= containMax)) { + return false; + }*/ + if (containCount >= containMax) { return false; } } @@ -76,6 +80,143 @@ Bool DroneCarrierContain::isValidContainerFor(const Object* rider, Bool checkCap return false; } +//------------------------------------------------------------------------------------------------- +//------------------------------------------------------------------------------------------------- +void DroneCarrierContain::onRemoving(Object* rider) +{ + OpenContain::onRemoving(rider); + + // object is no longer held inside a transport + rider->clearDisabled(DISABLED_HELD); + + const TransportContainModuleData* d = getTransportContainModuleData(); + + // give the object back a regular weapon + rider->clearWeaponBonusCondition(WEAPONBONUSCONDITION_CONTAINED); + rider->clearWeaponSetFlag(WEAPONSET_CONTAINED); + + // If we have a bone and no exit paths, put each rider at the numbered bone position + if (!d->m_exitBone.isEmpty() && d->m_numberOfExitPaths <= 0) + { + Drawable* draw = getObject()->getDrawable(); + if (draw) + { + Coord3D bonePos; + Matrix3D boneMat; + AsciiString boneName; + + Int slot = static_cast(getContainCount()); + boneName.format("%s%02d", d->m_exitBone.str(), slot + 1); + + Int foundBones = draw->getPristineBonePositions(boneName.str(), 0, &bonePos, &boneMat, 1); + + if (foundBones > 0) { + Coord3D worldPos; + Matrix3D worldMat; + getObject()->convertBonePosToWorldPos(&bonePos, &boneMat, &worldPos, &worldMat); + rider->setPosition(&worldPos); + rider->setTransformMatrix(&worldMat); + } + } + } + + if (d->m_orientLikeContainerOnExit) + { + rider->setOrientation(getObject()->getOrientation()); + } + + if (d->m_keepContainerVelocityOnExit) + { + PhysicsBehavior* parent = getObject()->getPhysics(); + PhysicsBehavior* child = rider->getPhysics(); + if (parent && child) + { + Coord3D startingForce = *parent->getVelocity(); + Real mass = child->getMass(); + startingForce.x *= mass; + startingForce.y *= mass; + startingForce.z *= mass; + child->applyMotiveForce(&startingForce); + + Real pitchRate = child->getCenterOfMassOffset() * d->m_exitPitchRate; + child->setPitchRate(pitchRate); + } + } + + Int transportSlotCount = rider->getTransportSlotCount(); + DEBUG_ASSERTCRASH(transportSlotCount > 0, ("Hmm, this object isnt transportable")); + m_extraSlotsInUse -= transportSlotCount - 1; + DEBUG_ASSERTCRASH(m_extraSlotsInUse >= 0 && m_extraSlotsInUse + getContainCount() <= getContainMax(), ("Hmm, bad slot count")); + + // when we are empty again, clear the model condition for loaded + if (getContainCount() == 0) + { + Drawable* draw = getObject()->getDrawable(); + + if (draw) + draw->clearModelConditionState(MODELCONDITION_LOADED); + + } // end if + + if (getObject()->isAboveTerrain()) + { + // temporarily mark the guy as being allowed to fall + // (overriding his locomotor's stick-to-ground attribute). + // this will be reset (by PhysicsBehavior) when he touches the ground. + PhysicsBehavior* physics = rider->getPhysics(); + if (physics) + physics->setAllowToFall(true); + } + + // AI might need help using this transport in a good way. Make the passengers aggressive. + //There is no computer player check since Aggressive only means something for computer players anyway + if (d->m_goAggressiveOnExit && rider->getAI()) + { + rider->getAI()->setAttitude(ATTITUDE_AGGRESSIVE); + } + if (getObject()->isEffectivelyDead()) { + scatterToNearbyPosition(rider); + } + if (d->m_resetMoodCheckTimeOnExit && rider->getAI()) + { + rider->getAI()->wakeUpAndAttemptToTarget(); + } + + m_frameExitNotBusy = TheGameLogic->getFrame() + d->m_exitDelay; + +} + +short DroneCarrierContain::getRiderSlot(ObjectID riderID) const +{ + short idx = 0; + for (ContainedItemsList::const_iterator it = getContainList().begin(); it != getContainList().end(); it++) + { + Object* obj; + + // get the object + obj = *it; + + if (obj && obj->getID() == riderID) + return idx; + idx++; + } + return -1; +} + +short DroneCarrierContain::getPortableSlot(ObjectID portableID) const +{ + return getRiderSlot(portableID); +} + +const ContainedItemsList* DroneCarrierContain::getAddOnList() const +{ + return &m_containList; +} + +ContainedItemsList* DroneCarrierContain::getAddOnList() +{ + return &m_containList; +} // ------------------------------------------------------------------------------------------------ /** CRC */ @@ -85,6 +226,7 @@ void DroneCarrierContain::crc(Xfer* xfer) // extend base class TransportContain::crc(xfer); + //GarrisonContain::crc(xfer); } // end crc @@ -97,6 +239,7 @@ void DroneCarrierContain::xfer(Xfer* xfer) { // extend base class TransportContain::xfer(xfer); + //GarrisonContain::xfer(xfer); } // end xfer @@ -108,6 +251,7 @@ void DroneCarrierContain::loadPostProcess(void) // extend base class TransportContain::loadPostProcess(); + //GarrisonContain::loadPostProcess(); } // end loadPostProcess diff --git a/GeneralsMD/Code/GameEngineDevice/CMakeLists.txt b/GeneralsMD/Code/GameEngineDevice/CMakeLists.txt index 895c4d0122a..0fd4f8f137e 100644 --- a/GeneralsMD/Code/GameEngineDevice/CMakeLists.txt +++ b/GeneralsMD/Code/GameEngineDevice/CMakeLists.txt @@ -29,6 +29,8 @@ set(GAMEENGINEDEVICE_SRC Include/W3DDevice/GameClient/Module/W3DTracerDraw.h Include/W3DDevice/GameClient/Module/W3DTreeDraw.h Include/W3DDevice/GameClient/Module/W3DTruckDraw.h + Include/W3DDevice/GameClient/Module/W3DCarrierDraw.h + Include/W3DDevice/GameClient/Module/W3DDependencyCarrierDraw.h Include/W3DDevice/GameClient/TerrainTex.h Include/W3DDevice/GameClient/TileData.h Include/W3DDevice/GameClient/W3DAssetManager.h @@ -118,6 +120,8 @@ set(GAMEENGINEDEVICE_SRC Source/W3DDevice/GameClient/Drawable/Draw/W3DTracerDraw.cpp Source/W3DDevice/GameClient/Drawable/Draw/W3DTreeDraw.cpp Source/W3DDevice/GameClient/Drawable/Draw/W3DTruckDraw.cpp + Source/W3DDevice/GameClient/Drawable/Draw/W3DCarrierDraw.cpp + Source/W3DDevice/GameClient/Drawable/Draw/W3DDependencyCarrierDraw.cpp Source/W3DDevice/GameClient/FlatHeightMap.cpp Source/W3DDevice/GameClient/GUI/Gadget/W3DCheckBox.cpp Source/W3DDevice/GameClient/GUI/Gadget/W3DComboBox.cpp diff --git a/GeneralsMD/Code/GameEngineDevice/Include/W3DDevice/GameClient/Module/W3DDependencyCarrierDraw.h b/GeneralsMD/Code/GameEngineDevice/Include/W3DDevice/GameClient/Module/W3DDependencyCarrierDraw.h new file mode 100644 index 00000000000..24290d456e2 --- /dev/null +++ b/GeneralsMD/Code/GameEngineDevice/Include/W3DDevice/GameClient/Module/W3DDependencyCarrierDraw.h @@ -0,0 +1,30 @@ +// FILE: W3DDependencyCarrierDraw.h ///////////////////////////////////////////////////////////////////////// +// Desc: Draw as dependent when garrisoned in carrier +/////////////////////////////////////////////////////////////////////////////////////////////////// + +#pragma once + +// INCLUDES /////////////////////////////////////////////////////////////////////////////////////// +#include "Common/ModelState.h" +#include "Common/DrawModule.h" +#include "W3DDevice/GameClient/Module/W3DDependencyModelDraw.h" + +//------------------------------------------------------------------------------------------------- +class W3DDependencyCarrierDraw : public W3DDependencyModelDraw +{ + + MEMORY_POOL_GLUE_WITH_USERLOOKUP_CREATE(W3DDependencyCarrierDraw, "W3DDependencyCarrierDraw") + MAKE_STANDARD_MODULE_MACRO_WITH_MODULE_DATA(W3DDependencyCarrierDraw, W3DDependencyModelDrawModuleData) + +public: + + W3DDependencyCarrierDraw(Thing* thing, const ModuleData* moduleData); + // virtual destructor prototype provided by memory pool declaration + + virtual void doDrawModule(const Matrix3D* transformMtx) override; + virtual void notifyDrawModuleDependencyCleared();///< if you were waiting for something before you drew, it's ready now + virtual void adjustTransformMtx(Matrix3D& mtx) const override; + +protected: + +}; diff --git a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/Common/Thing/W3DModuleFactory.cpp b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/Common/Thing/W3DModuleFactory.cpp index 5f66ef65c2c..d04a0797da5 100644 --- a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/Common/Thing/W3DModuleFactory.cpp +++ b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/Common/Thing/W3DModuleFactory.cpp @@ -48,6 +48,7 @@ #include "W3DDevice/GameClient/Module/W3DTracerDraw.h" #include "W3DDevice/GameClient/Module/W3DTreeDraw.h" #include "W3DDevice/GameClient/Module/W3DPropDraw.h" +#include "W3DDevice/GameClient/Module/W3DDependencyCarrierDraw.h" //------------------------------------------------------------------------------------------------- /** Initialize method */ @@ -78,5 +79,6 @@ void W3DModuleFactory::init( void ) addModule( W3DTankTruckDraw ); addModule( W3DTreeDraw ); addModule( W3DPropDraw ); + addModule( W3DDependencyCarrierDraw ); } // end init diff --git a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/Drawable/Draw/W3DDependencyCarrierDraw.cpp b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/Drawable/Draw/W3DDependencyCarrierDraw.cpp new file mode 100644 index 00000000000..534d103281a --- /dev/null +++ b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/Drawable/Draw/W3DDependencyCarrierDraw.cpp @@ -0,0 +1,167 @@ +// FILE: W3DCarrierDraw.cpp //////////////////////////////////////////////////////////////////////////// + +// Desc: Render stationed Objects with carriers +/////////////////////////////////////////////////////////////////////////////////////////////////// + +// INCLUDES /////////////////////////////////////////////////////////////////////////////////////// +#include "Common/Xfer.h" +#include "GameClient/Drawable.h" +#include "GameLogic/Object.h" +#include "GameLogic/Module/ContainModule.h" +#include "W3DDevice/GameClient/Module/W3DDependencyCarrierDraw.h" + +//------------------------------------------------------------------------------------------------- +W3DDependencyCarrierDraw::W3DDependencyCarrierDraw(Thing* thing, const ModuleData* moduleData) + : W3DDependencyModelDraw(thing, moduleData) +{ +} + +//------------------------------------------------------------------------------------------------- +//------------------------------------------------------------------------------------------------- +W3DDependencyCarrierDraw::~W3DDependencyCarrierDraw() +{ +} + +//------------------------------------------------------------------------------------------------- +// All this does is stop the call path if we haven't been cleared to draw yet +void W3DDependencyCarrierDraw::doDrawModule(const Matrix3D* transformMtx) +{ + Drawable* myDrawable = getDrawable(); + if (!myDrawable) + return; + + const Object* me = myDrawable->getObject(); + if (!me) + return; + + if (!me->isContained()) { + W3DModelDraw::doDrawModule(transformMtx); + } + else { + + if (m_dependencyCleared) + { + // We've been cleared by the thing we were waiting to draw, so we can draw. + W3DModelDraw::doDrawModule(transformMtx); + m_dependencyCleared = FALSE; + + Drawable* theirDrawable = NULL; + + if (me->getContainedBy()) // no enclosing container check here, as carrier wants to draw units anyway + theirDrawable = me->getContainedBy()->getDrawable(); + + if (!theirDrawable) + return; + + myDrawable->imitateStealthLook(*theirDrawable); + + } + } +} + +//------------------------------------------------------------------------------------------------- +void W3DDependencyCarrierDraw::notifyDrawModuleDependencyCleared() +{ + m_dependencyCleared = TRUE; + + //this is called shortly before rendering so we set the hidden status to that of the parent if contained + const Object* me = getDrawable()->getObject(); + // No special adjustements when currently not contained + if (me && me->isContained()) { + const Object* container = me->getContainedBy(); + if (container && container->getDrawable()) { + me->getDrawable()->setDrawableHidden(container->getDrawable()->isDrawableEffectivelyHidden()); + } + } +} + +// ------------------------------------------------------------------------------------------------ +void W3DDependencyCarrierDraw::adjustTransformMtx(Matrix3D& mtx) const +{ + W3DModelDraw::adjustTransformMtx(mtx); + + // We have an additional adjustment to make, we want to use a bone in our container if there is one + const Object* me = getDrawable()->getObject(); + + // No special adjustements when currently not contained + if (me && !me->isContained()) return; + + const W3DDependencyModelDrawModuleData* md = getW3DDependencyModelDrawModuleData(); + + if (md->m_attachToDrawableBoneInContainer.isNotEmpty() + && me + && me->getContainedBy() + // && !me->getContainedBy()->getContain()->isEnclosingContainerFor(me) // no enclosing check + ) + { + // If we are currently "riding on", then our client position is determined by the client position of + // a particular bone in our container object. Our logic position is updated by OpenContain. + const Drawable* theirDrawable = me->getContainedBy()->getDrawable(); + if (theirDrawable) + { + Matrix3D theirBoneMtx; + + AsciiString boneName; + + short slot = me->getContainedBy()->getContain()->getRiderSlot(me->getID()); + if (slot > -1) + boneName.format("%s%02d", md->m_attachToDrawableBoneInContainer.str(), slot + 1); + + if ((slot > -1) && theirDrawable->getCurrentWorldspaceClientBonePositions(boneName.str(), theirBoneMtx)) + { + mtx = theirBoneMtx; + } + else if (theirDrawable->getCurrentWorldspaceClientBonePositions(md->m_attachToDrawableBoneInContainer.str(), theirBoneMtx)) + { + mtx = theirBoneMtx; + } + else + { + mtx = *theirDrawable->getTransformMatrix(); + DEBUG_LOG(("m_attachToDrawableBoneInContainer %s not found", md->m_attachToDrawableBoneInContainer.str())); + } + } + } +} + + +//------------------------------------------------------------------------------------------------- +// ------------------------------------------------------------------------------------------------ +/** CRC */ +// ------------------------------------------------------------------------------------------------ +void W3DDependencyCarrierDraw::crc(Xfer* xfer) +{ + + // extend base class + W3DDependencyModelDraw::crc(xfer); + +} // end crc + +// ------------------------------------------------------------------------------------------------ +/** Xfer method + * Version Info: + * 1: Initial version */ + // ------------------------------------------------------------------------------------------------ +void W3DDependencyCarrierDraw::xfer(Xfer* xfer) +{ + + // version + XferVersion currentVersion = 1; + XferVersion version = currentVersion; + xfer->xferVersion(&version, currentVersion); + + // extend base class + W3DDependencyModelDraw::xfer(xfer); + +} // end xfer + +// ------------------------------------------------------------------------------------------------ +/** Load post process */ +// ------------------------------------------------------------------------------------------------ +void W3DDependencyCarrierDraw::loadPostProcess(void) +{ + + // extend base class + W3DDependencyModelDraw::loadPostProcess(); + +} // end loadPostProcess From 3fde6cb8e6e78b25cc47197b4b674d7162379e9e Mon Sep 17 00:00:00 2001 From: pWn3d Date: Sun, 23 Nov 2025 20:57:02 +0100 Subject: [PATCH 3/8] carrier stuff --- .../System/GameMemoryInitPools_GeneralsMD.inl | 1 + GeneralsMD/Code/GameEngine/CMakeLists.txt | 2 + .../Module/CarrierDroneJetAIUpdate.h | 37 ++++++ .../GameLogic/Module/DroneCarrierContain.h | 11 +- .../GameEngine/Include/GameLogic/Object.h | 1 + .../GameEngine/Include/GameLogic/WeaponSet.h | 2 + .../Source/Common/Thing/ModuleFactory.cpp | 2 + .../Object/Contain/DroneCarrierContain.cpp | 85 ++++++++++-- .../Source/GameLogic/Object/Object.cpp | 6 + .../AIUpdate/CarrierDroneJetAIUpdate.cpp | 71 ++++++++++ .../Update/AIUpdate/DroneCarrierAIUpdate.cpp | 70 +++++++++- .../Source/GameLogic/Object/WeaponSet.cpp | 18 +++ .../GameClient/Module/W3DCarrierDraw.h | 41 ++++++ .../Drawable/Draw/W3DCarrierDraw.cpp | 121 ++++++++++++++++++ 14 files changed, 452 insertions(+), 16 deletions(-) create mode 100644 GeneralsMD/Code/GameEngine/Include/GameLogic/Module/CarrierDroneJetAIUpdate.h create mode 100644 GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/CarrierDroneJetAIUpdate.cpp create mode 100644 GeneralsMD/Code/GameEngineDevice/Include/W3DDevice/GameClient/Module/W3DCarrierDraw.h create mode 100644 GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/Drawable/Draw/W3DCarrierDraw.cpp diff --git a/Core/GameEngine/Source/Common/System/GameMemoryInitPools_GeneralsMD.inl b/Core/GameEngine/Source/Common/System/GameMemoryInitPools_GeneralsMD.inl index c8dd3de2b5a..37c44100a29 100644 --- a/Core/GameEngine/Source/Common/System/GameMemoryInitPools_GeneralsMD.inl +++ b/Core/GameEngine/Source/Common/System/GameMemoryInitPools_GeneralsMD.inl @@ -682,5 +682,6 @@ static PoolSizeRec PoolSizes[] = { "DroneCarrierContain", 8, 8 }, { "W3DCarrierDraw", 8, 8 }, { "W3DDependencyCarrierDraw", 8, 8 }, + { "CarrierDroneJetAIUpdate", 16, 16 }, { 0, 0, 0 } }; diff --git a/GeneralsMD/Code/GameEngine/CMakeLists.txt b/GeneralsMD/Code/GameEngine/CMakeLists.txt index 67ebd388230..1d26e245424 100644 --- a/GeneralsMD/Code/GameEngine/CMakeLists.txt +++ b/GeneralsMD/Code/GameEngine/CMakeLists.txt @@ -500,6 +500,7 @@ set(GAMEENGINE_SRC Include/GameLogic/Module/KodiakUpdate.h Include/GameLogic/Module/DroneCarrierSlavedUpdate.h Include/GameLogic/Module/DroneCarrierContain.h + Include/GameLogic/Module/CarrierDroneJetAIUpdate.h Include/GameLogic/Object.h Include/GameLogic/ObjectCreationList.h Include/GameLogic/ObjectIter.h @@ -1022,6 +1023,7 @@ set(GAMEENGINE_SRC Source/GameLogic/Object/Update/AIUpdate/TeleporterAIUpdate.cpp Source/GameLogic/Object/Update/AIUpdate/WorkerAIUpdate.cpp Source/GameLogic/Object/Update/AIUpdate/DroneCarrierAIUpdate.cpp + Source/GameLogic/Object/Update/AIUpdate/CarrierDroneJetAIUpdate.cpp Source/GameLogic/Object/Update/AnimationSteeringUpdate.cpp Source/GameLogic/Object/Update/AssistedTargetingUpdate.cpp Source/GameLogic/Object/Update/AutoDepositUpdate.cpp diff --git a/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/CarrierDroneJetAIUpdate.h b/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/CarrierDroneJetAIUpdate.h new file mode 100644 index 00000000000..237933700c9 --- /dev/null +++ b/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/CarrierDroneJetAIUpdate.h @@ -0,0 +1,37 @@ +// CarrierDroneJetAIUpdate.h ////////// +#pragma once + +#include "Common/STLTypedefs.h" +#include "Common/GameMemory.h" +#include "GameLogic/AIStateMachine.h" +#include "GameLogic/Module/AIUpdate.h" + +//------------------------------------------------------------------------------------------------- +//------------------------------------------------------------------------------------------------- +//------------------------------------------------------------------------------------------------- + + +//------------------------------------------------------------------------------------------------- +//class CarrierDroneJetAIUpdateModuleData : public AIUpdateModuleData +//{ +//public: +// +// +// CarrierDroneJetAIUpdateModuleData(); +// static void buildFieldParse(MultiIniFieldParse& p); +//}; + +//------------------------------------------------------------------------------------------------- +class CarrierDroneJetAIUpdate : public AIUpdateInterface +{ + + MEMORY_POOL_GLUE_WITH_USERLOOKUP_CREATE(CarrierDroneJetAIUpdate, "CarrierDroneJetAIUpdate") + MAKE_STANDARD_MODULE_MACRO_WITH_MODULE_DATA(CarrierDroneJetAIUpdate, AIUpdateModuleData) + + //virtual UpdateSleepTime update(); + +public: + + CarrierDroneJetAIUpdate(Thing* thing, const ModuleData* moduleData); + // virtual destructor prototype provided by memory pool declaration +}; diff --git a/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/DroneCarrierContain.h b/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/DroneCarrierContain.h index 1a4b61f9162..7676586e664 100644 --- a/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/DroneCarrierContain.h +++ b/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/DroneCarrierContain.h @@ -30,12 +30,21 @@ class DroneCarrierContain: public TransportContain //public GarrisonContain virtual Bool isEnclosingContainerFor(const Object* obj) const { return true; } //TODO param in module //support for specific exit bones - virtual void onRemoving(Object* obj); + virtual void onRemoving(Object* obj) override; + virtual void onContaining(Object* obj, Bool wasSelected) override; ///< object now contains 'obj' virtual short getRiderSlot(ObjectID riderID) const override; virtual short getPortableSlot(ObjectID portableID) const override; virtual const ContainedItemsList* getAddOnList() const override; virtual ContainedItemsList* getAddOnList() override; + + // Called from the AI update to reload the contained drones + void updateContainedReloadingStatus(); + +protected: + + // Saves slot assignement and frame when entered + std::vector> m_contained_units; }; #endif // __TransportContain_H_ diff --git a/GeneralsMD/Code/GameEngine/Include/GameLogic/Object.h b/GeneralsMD/Code/GameEngine/Include/GameLogic/Object.h index 429a8f1b9f7..4582a189b60 100644 --- a/GeneralsMD/Code/GameEngine/Include/GameLogic/Object.h +++ b/GeneralsMD/Code/GameEngine/Include/GameLogic/Object.h @@ -478,6 +478,7 @@ class Object : public Thing, public Snapshot // Weapons & Damage ------------------------------------------------------------------------------------------------- void reloadAllAmmo(Bool now); Bool isOutOfAmmo() const; + Bool isFullAmmo() const; //added by OFS Bool hasAnyWeapon() const; Bool hasAnyDamageWeapon() const; //Kris: a should be used for real weapons that directly inflict damage... not deploy, hack, etc. Bool hasWeaponToDealDamageType(DamageType typeToDeal) const; diff --git a/GeneralsMD/Code/GameEngine/Include/GameLogic/WeaponSet.h b/GeneralsMD/Code/GameEngine/Include/GameLogic/WeaponSet.h index 772d8a8cea8..9a27b85ab74 100644 --- a/GeneralsMD/Code/GameEngine/Include/GameLogic/WeaponSet.h +++ b/GeneralsMD/Code/GameEngine/Include/GameLogic/WeaponSet.h @@ -238,6 +238,7 @@ class WeaponSet : public Snapshot void updateWeaponSet(const Object* obj); void reloadAllAmmo(const Object *obj, Bool now); Bool isOutOfAmmo() const; + Bool isFullAmmo() const; // Added for OFS Bool hasAnyWeapon() const { return m_filledWeaponSlotMask != 0; } Bool hasAnyDamageWeapon() const { return m_hasDamageWeapon; } Bool hasWeaponToDealDamageType(DamageType typeToDeal) const { return m_totalDamageTypeMask.test(typeToDeal); } @@ -281,6 +282,7 @@ class WeaponSet : public Snapshot Weapon* getWeaponInWeaponSlot(WeaponSlotType wslot) const; + static ModelConditionFlags getModelConditionForWeaponSlot(WeaponSlotType wslot, WeaponSetConditionType a); }; diff --git a/GeneralsMD/Code/GameEngine/Source/Common/Thing/ModuleFactory.cpp b/GeneralsMD/Code/GameEngine/Source/Common/Thing/ModuleFactory.cpp index 2034f9957f8..73b503b0e57 100644 --- a/GeneralsMD/Code/GameEngine/Source/Common/Thing/ModuleFactory.cpp +++ b/GeneralsMD/Code/GameEngine/Source/Common/Thing/ModuleFactory.cpp @@ -207,6 +207,7 @@ #include "GameLogic/Module/DroneCarrierAIUpdate.h" #include "GameLogic/Module/DroneCarrierSlavedUpdate.h" #include "GameLogic/Module/DroneCarrierContain.h" +#include "GameLogic/Module/CarrierDroneJetAIUpdate.h" // upgrade includes #include "GameLogic/Module/ActiveShroudUpgrade.h" @@ -509,6 +510,7 @@ void ModuleFactory::init( void ) addModule( ResetSpecialPowerTimerWhileAliveUpdate ); addModule( DroneCarrierAIUpdate ); addModule( DroneCarrierSlavedUpdate ); + addModule( CarrierDroneJetAIUpdate ); // upgrade modules addModule( CostModifierUpgrade ); diff --git a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Contain/DroneCarrierContain.cpp b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Contain/DroneCarrierContain.cpp index 4629a434d71..4196069e22d 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Contain/DroneCarrierContain.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Contain/DroneCarrierContain.cpp @@ -30,6 +30,13 @@ DroneCarrierContain::DroneCarrierContain(Thing* thing, const ModuleData* moduleD //GarrisonContain(thing, moduleData) TransportContain(thing, moduleData) { + const TransportContainModuleData* data = dynamic_cast(moduleData); + if (data != nullptr) { + m_contained_units.reserve(data->m_slotCapacity); + for (size_t i = 0; i < data->m_slotCapacity; i++) { + m_contained_units.emplace_back(INVALID_ID, 0); + } + } } //------------------------------------------------------------------------------------------------- @@ -84,6 +91,7 @@ Bool DroneCarrierContain::isValidContainerFor(const Object* rider, Bool checkCap //------------------------------------------------------------------------------------------------- void DroneCarrierContain::onRemoving(Object* rider) { + //Intentionally not use TransportContain::onRemoving OpenContain::onRemoving(rider); // object is no longer held inside a transport @@ -105,17 +113,20 @@ void DroneCarrierContain::onRemoving(Object* rider) Matrix3D boneMat; AsciiString boneName; - Int slot = static_cast(getContainCount()); - boneName.format("%s%02d", d->m_exitBone.str(), slot + 1); + //Int slot = static_cast(getContainCount()); + Int slot = getRiderSlot(rider->getID()); + if (slot >= 0) { + boneName.format("%s%02d", d->m_exitBone.str(), slot + 1); - Int foundBones = draw->getPristineBonePositions(boneName.str(), 0, &bonePos, &boneMat, 1); + Int foundBones = draw->getPristineBonePositions(boneName.str(), 0, &bonePos, &boneMat, 1); - if (foundBones > 0) { - Coord3D worldPos; - Matrix3D worldMat; - getObject()->convertBonePosToWorldPos(&bonePos, &boneMat, &worldPos, &worldMat); - rider->setPosition(&worldPos); - rider->setTransformMatrix(&worldMat); + if (foundBones > 0) { + Coord3D worldPos; + Matrix3D worldMat; + getObject()->convertBonePosToWorldPos(&bonePos, &boneMat, &worldPos, &worldMat); + rider->setPosition(&worldPos); + rider->setTransformMatrix(&worldMat); + } } } } @@ -182,13 +193,32 @@ void DroneCarrierContain::onRemoving(Object* rider) rider->getAI()->wakeUpAndAttemptToTarget(); } + // Remove unit from slot assign vector + for (size_t i = 0; i < m_contained_units.size(); i++) { + if (std::get<0>(m_contained_units[i]) == rider->getID()){ + m_contained_units[i] = { INVALID_ID, 0 }; + } + } + m_frameExitNotBusy = TheGameLogic->getFrame() + d->m_exitDelay; +} + +void DroneCarrierContain::onContaining(Object* obj, Bool wasSelected) +{ + TransportContain::onContaining(obj, wasSelected); + // Assing in first free slot + for (size_t i = 0; i < m_contained_units.size(); i++) { + if (std::get<0>(m_contained_units[i]) == INVALID_ID) { + m_contained_units[i] = { obj->getID(), TheGameLogic->getFrame() }; + break; + } + } } short DroneCarrierContain::getRiderSlot(ObjectID riderID) const { - short idx = 0; + /*short idx = 0; for (ContainedItemsList::const_iterator it = getContainList().begin(); it != getContainList().end(); it++) { Object* obj; @@ -199,6 +229,11 @@ short DroneCarrierContain::getRiderSlot(ObjectID riderID) const if (obj && obj->getID() == riderID) return idx; idx++; + }*/ + for (size_t i = 0; i < m_contained_units.size(); i++) { + if (std::get<0>(m_contained_units[i]) == riderID) { + return i; + } } return -1; } @@ -218,6 +253,36 @@ ContainedItemsList* DroneCarrierContain::getAddOnList() return &m_containList; } +// Similar to jet ai when parking +void DroneCarrierContain::updateContainedReloadingStatus() +{ + UnsignedInt now = TheGameLogic->getFrame(); + + for (size_t i = 0; i < m_contained_units.size(); i++) { + const auto& [objectID, enteredFrame] = m_contained_units[i]; + if (objectID != INVALID_ID) { + + Object* drone = TheGameLogic->findObjectByID(objectID); + if (drone != nullptr) { + for (Int i = 0; i < WEAPONSLOT_COUNT; ++i) + { + Weapon* w = drone->getWeaponInWeaponSlot((WeaponSlotType)i); + if (w == NULL) + continue; + + Int reloadTime = w->getClipReloadTime(drone); + UnsignedInt reloadDone = enteredFrame + reloadTime; + + if (now >= reloadDone) + w->setClipPercentFull(1.0f, false); + else + w->setClipPercentFull((Real)(reloadTime - (reloadDone - now)) / reloadTime, false); + } + } + } + } +} + // ------------------------------------------------------------------------------------------------ /** CRC */ // ------------------------------------------------------------------------------------------------ diff --git a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Object.cpp b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Object.cpp index 7da79cec6bc..85e884c061c 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Object.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Object.cpp @@ -1277,6 +1277,12 @@ Bool Object::isOutOfAmmo() const return m_weaponSet.isOutOfAmmo(); } +//============================================================================= +Bool Object::isFullAmmo() const +{ + return m_weaponSet.isFullAmmo(); +} + //============================================================================= Bool Object::hasAnyWeapon() const { diff --git a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/CarrierDroneJetAIUpdate.cpp b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/CarrierDroneJetAIUpdate.cpp new file mode 100644 index 00000000000..c946e7521e5 --- /dev/null +++ b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/CarrierDroneJetAIUpdate.cpp @@ -0,0 +1,71 @@ +// INCLUDES /////////////////////////////////////////////////////////////////////////////////////// +#include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine + +#include "Common/CRCDebug.h" +#include "Common/Player.h" +#include "Common/Team.h" +#include "Common/ThingFactory.h" +#include "Common/ThingTemplate.h" +#include "Common/Xfer.h" + +#include "GameClient/Drawable.h" +#include "GameClient/ParticleSys.h" + +#include "GameLogic/AI.h" +#include "GameLogic/AIPathfind.h" +#include "GameLogic/GameLogic.h" +#include "GameLogic/Object.h" +#include "GameLogic/PartitionManager.h" +#include "GameLogic/TerrainLogic.h" +#include "GameLogic/Weapon.h" + +#include "GameLogic/Module/CarrierDroneJetAIUpdate.h" +#include "GameLogic/Module/JetAIUpdate.h" +#include "GameLogic/Module/ProductionUpdate.h" +#include "GameLogic/Module/ContainModule.h" + +CarrierDroneJetAIUpdate::CarrierDroneJetAIUpdate(Thing* thing, const ModuleData* moduleData) : AIUpdateInterface(thing, moduleData) +{ +} + +//------------------------------------------------------------------------------------------------- +//------------------------------------------------------------------------------------------------- +CarrierDroneJetAIUpdate::~CarrierDroneJetAIUpdate(void) +{ +} + +// ------------------------------------------------------------------------------------------------ +/** CRC */ +// ------------------------------------------------------------------------------------------------ +void CarrierDroneJetAIUpdate::crc(Xfer* xfer) +{ + // extend base class + AIUpdateInterface::crc(xfer); +} // end crc + +// ------------------------------------------------------------------------------------------------ +/** Xfer method + * Version Info: + * 1: Initial version */ + // ------------------------------------------------------------------------------------------------ +void CarrierDroneJetAIUpdate::xfer(Xfer* xfer) +{ + + // version + XferVersion currentVersion = 2; + XferVersion version = currentVersion; + xfer->xferVersion(&version, currentVersion); + + // extend base class + AIUpdateInterface::xfer(xfer); + +} // end xfer + +// ------------------------------------------------------------------------------------------------ +/** Load post process */ +// ------------------------------------------------------------------------------------------------ +void CarrierDroneJetAIUpdate::loadPostProcess(void) +{ + // extend base class + AIUpdateInterface::loadPostProcess(); +} // end loadPostProcess diff --git a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/DroneCarrierAIUpdate.cpp b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/DroneCarrierAIUpdate.cpp index 61e1bc21d01..6ff394d2100 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/DroneCarrierAIUpdate.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/DroneCarrierAIUpdate.cpp @@ -27,6 +27,7 @@ #include "GameLogic/Module/JetAIUpdate.h" #include "GameLogic/Module/ProductionUpdate.h" #include "GameLogic/Module/ContainModule.h" +#include "GameLogic/Module/DroneCarrierContain.h" DroneCarrierAIUpdateModuleData::DroneCarrierAIUpdateModuleData() @@ -417,6 +418,41 @@ void DroneCarrierAIUpdate::onDie(const DamageInfo* damageInfo) } } +/** +* Check if drone has ammo and is repaired depending on combat state +*/ +bool drone_is_combat_ready(Object* drone) { + if (drone->isContained()) { + // Contained drone must be repaired before getting back to fight + BodyModuleInterface* body = drone->getBodyModule(); + if (body) { + if (body->getHealth() < body->getMaxHealth()) { + DEBUG_LOG(("Drone %d is contained annd not fully healed", drone->getID())); + return false; + } + } + if (drone->isFullAmmo()) { + DEBUG_LOG(("Drone %d is contained and full ammo", drone->getID())); + } + else { + DEBUG_LOG(("Drone %d is contained and but NOT full ammo", drone->getID())); + } + return drone->isFullAmmo(); + } + else { + if (drone->isOutOfAmmo()) { + DEBUG_LOG(("Drone %d is outside and out of ammo", drone->getID())); + } + else { + DEBUG_LOG(("Drone %d is outside and has ammo", drone->getID())); + } + + // if not contained we can fight as long as we have ammo + return !drone->isOutOfAmmo(); + } + return false; +} + /****************************************/ void DroneCarrierAIUpdate::deployDrones() { @@ -427,7 +463,7 @@ void DroneCarrierAIUpdate::deployDrones() if (obj == NULL || obj->isEffectivelyDead()) continue; - if (obj->isContained()) { + if (obj->isContained() && drone_is_combat_ready(obj)) { AIUpdateInterface* ai = obj->getAI(); if (ai != nullptr) { ai->aiExit(carrier, CMD_FROM_AI); @@ -464,8 +500,11 @@ void DroneCarrierAIUpdate::propagateOrderToSpecificDrone(Object* drone) if (ai != nullptr) { Object* target = TheGameLogic->findObjectByID(m_designatedTarget); + + AICommandType cmd = drone_is_combat_ready(drone) ? m_designatedCommand : AICMD_IDLE; + bool contained = drone->isContained(); - switch (m_designatedCommand) + switch (cmd) { case AICMD_GUARD_POSITION: if (!contained) { @@ -523,11 +562,15 @@ bool DroneCarrierAIUpdate::positionInRange(const Coord3D* loc) if (primaryWeapon == nullptr) { return true; } - + // calc if within 2D range with 5% leeway Real range = primaryWeapon->getAttackRange(carrier); Coord3D pos = *carrier->getPosition(); - pos.sub(loc); - return pos.lengthSqr() <= range * range; + pos.z = 0; + Coord3D loc2d = *loc; + loc2d.z = 0; + + pos.sub(&loc2d); + return pos.lengthSqr() <= range * range * 1.05f; } //------------------------------------------------------------------------------------------------- @@ -624,6 +667,23 @@ UpdateSleepTime DroneCarrierAIUpdate::update() } } + if (now % 5 == 0) { + + // check for reloading drones each 5th frame + Object* carrier = getObject(); + if (carrier != nullptr) { + + ContainModuleInterface* cmi = carrier->getContain(); + + if (cmi != nullptr) { + DroneCarrierContain* drone_contain = dynamic_cast(cmi); + if (drone_contain != nullptr) { + drone_contain->updateContainedReloadingStatus(); + } + } + } + } + Object* my_target = getCurrentVictim(); if (my_target != nullptr) { diff --git a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/WeaponSet.cpp b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/WeaponSet.cpp index e4b615d1fcf..54b0804a276 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/WeaponSet.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/WeaponSet.cpp @@ -1064,6 +1064,24 @@ Bool WeaponSet::isOutOfAmmo() const } return true; } +//------------------------------------------------------------------------------------------------- +Bool WeaponSet::isFullAmmo() const +{ + for (Int i = 0; i < WEAPONSLOT_COUNT; i++) + { + const Weapon* weapon = m_weapons[i]; + if (weapon == NULL) + continue; + if (weapon->getStatus() == RELOADING_CLIP) + { + return false; + } + if (weapon->getRemainingAmmo() < weapon->getClipSize()) { + return false; + } + } + return true; +} //------------------------------------------------------------------------------------------------- const Weapon* WeaponSet::findAmmoPipShowingWeapon() const diff --git a/GeneralsMD/Code/GameEngineDevice/Include/W3DDevice/GameClient/Module/W3DCarrierDraw.h b/GeneralsMD/Code/GameEngineDevice/Include/W3DDevice/GameClient/Module/W3DCarrierDraw.h new file mode 100644 index 00000000000..b309ca00916 --- /dev/null +++ b/GeneralsMD/Code/GameEngineDevice/Include/W3DDevice/GameClient/Module/W3DCarrierDraw.h @@ -0,0 +1,41 @@ +// FILE: W3DModelDraw.h ///////////////////////////////////////////////////////////////////////// +// Desc: Draw with stationed drones for drone carrier +/////////////////////////////////////////////////////////////////////////////////////////////////// + +#pragma once + +// INCLUDES /////////////////////////////////////////////////////////////////////////////////////// +#include "Common/ModelState.h" +#include "Common/DrawModule.h" +#include "W3DDevice/GameClient/Module/W3DModelDraw.h" + +//------------------------------------------------------------------------------------------------- +class W3DCarrierDrawModuleData : public W3DModelDrawModuleData +{ +public: + AsciiString m_dockingbone; + + W3DCarrierDrawModuleData(); + ~W3DCarrierDrawModuleData(); + + static void buildFieldParse(MultiIniFieldParse& p); +}; + +//------------------------------------------------------------------------------------------------- +class W3DCarrierDraw : public W3DModelDraw +{ + + MEMORY_POOL_GLUE_WITH_USERLOOKUP_CREATE(W3DCarrierDraw, "W3DCarrierDraw") + MAKE_STANDARD_MODULE_MACRO_WITH_MODULE_DATA(W3DCarrierDraw, W3DCarrierDrawModuleData) + +public: + + W3DCarrierDraw(Thing* thing, const ModuleData* moduleData); + // virtual destructor prototype provided by memory pool declaration + + virtual void setHidden(Bool h); + virtual void doDrawModule(const Matrix3D* transformMtx); + +protected: + +}; diff --git a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/Drawable/Draw/W3DCarrierDraw.cpp b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/Drawable/Draw/W3DCarrierDraw.cpp new file mode 100644 index 00000000000..beff2e25b45 --- /dev/null +++ b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/Drawable/Draw/W3DCarrierDraw.cpp @@ -0,0 +1,121 @@ +// FILE: W3DCarrierDraw.cpp //////////////////////////////////////////////////////////////////////////// + +// Desc: Render stationed Objects with carriers +/////////////////////////////////////////////////////////////////////////////////////////////////// + +// INCLUDES /////////////////////////////////////////////////////////////////////////////////////// +#include "Common/Xfer.h" +#include "GameClient/Drawable.h" +#include "GameLogic/Object.h" +#include "GameLogic/Module/ContainModule.h" +#include "W3DDevice/GameClient/Module/W3DCarrierDraw.h" + +//------------------------------------------------------------------------------------------------- +W3DCarrierDrawModuleData::W3DCarrierDrawModuleData() +{ + m_dockingbone.clear(); +} + +//------------------------------------------------------------------------------------------------- +W3DCarrierDrawModuleData::~W3DCarrierDrawModuleData() +{ +} + +//------------------------------------------------------------------------------------------------- +void W3DCarrierDrawModuleData::buildFieldParse(MultiIniFieldParse& p) +{ + W3DModelDrawModuleData::buildFieldParse(p); + + static const FieldParse dataFieldParse[] = + { + { "DockingBone", INI::parseAsciiString, NULL, offsetof(W3DCarrierDrawModuleData, m_dockingbone) }, + { 0, 0, 0, 0 } + }; + p.add(dataFieldParse); +} + +//------------------------------------------------------------------------------------------------- +//------------------------------------------------------------------------------------------------- +W3DCarrierDraw::W3DCarrierDraw(Thing* thing, const ModuleData* moduleData) + : W3DModelDraw(thing, moduleData) +{ +} + +//------------------------------------------------------------------------------------------------- +//------------------------------------------------------------------------------------------------- +W3DCarrierDraw::~W3DCarrierDraw() +{ +} + +//------------------------------------------------------------------------------------------------- +void W3DCarrierDraw::doDrawModule(const Matrix3D* transformMtx) +{ + W3DModelDraw::doDrawModule(transformMtx); + + Object* me = getDrawable()->getObject(); + if (me && me->getContain()) { + + const ContainedItemsList* docked_units = me->getContain()->getContainedItemsList(); + for (ContainedItemsList::const_iterator it = docked_units->begin(); it != docked_units->end(); ++it) { + Drawable* riderDraw = (*it)->getDrawable(); + riderDraw->setColorTintEnvelope(*getDrawable()->getColorTintEnvelope()); + riderDraw->notifyDrawableDependencyCleared(); + riderDraw->draw(NULL); + } + } +} + +//------------------------------------------------------------------------------------------------- +void W3DCarrierDraw::setHidden(Bool h) +{ + W3DModelDraw::setHidden(h); + + //TODO + // + // We need to hide our rider, since he won't realize he's being contained in a contained container + //Object* me = getDrawable()->getObject(); + //if (me && me->getContain()) { + + //} +} + +//------------------------------------------------------------------------------------------------- +// ------------------------------------------------------------------------------------------------ +/** CRC */ +// ------------------------------------------------------------------------------------------------ +void W3DCarrierDraw::crc(Xfer* xfer) +{ + + // extend base class + W3DModelDraw::crc(xfer); + +} // end crc + +// ------------------------------------------------------------------------------------------------ +/** Xfer method + * Version Info: + * 1: Initial version */ + // ------------------------------------------------------------------------------------------------ +void W3DCarrierDraw::xfer(Xfer* xfer) +{ + + // version + XferVersion currentVersion = 1; + XferVersion version = currentVersion; + xfer->xferVersion(&version, currentVersion); + + // extend base class + W3DModelDraw::xfer(xfer); + +} // end xfer + +// ------------------------------------------------------------------------------------------------ +/** Load post process */ +// ------------------------------------------------------------------------------------------------ +void W3DCarrierDraw::loadPostProcess(void) +{ + + // extend base class + W3DModelDraw::loadPostProcess(); + +} // end loadPostProcess From 35d8f4f61d268de7068dbdae96e4e959ed68ba85 Mon Sep 17 00:00:00 2001 From: pWn3d Date: Thu, 4 Dec 2025 18:29:53 +0100 Subject: [PATCH 4/8] update drone carrier --- .../System/GameMemoryInitPools_GeneralsMD.inl | 2 +- GeneralsMD/Code/GameEngine/CMakeLists.txt | 4 +- .../GameLogic/Module/CarrierDroneAIUpdate.h | 25 ++++ .../Module/CarrierDroneJetAIUpdate.h | 37 ------ .../GameLogic/Module/DroneCarrierAIUpdate.h | 2 + .../GameLogic/Module/DroneCarrierContain.h | 16 ++- .../Module/DroneCarrierSlavedUpdate.h | 6 +- .../Source/Common/Thing/ModuleFactory.cpp | 4 +- .../Object/Contain/DroneCarrierContain.cpp | 112 +++++++++++++++--- ...tAIUpdate.cpp => CarrierDroneAIUpdate.cpp} | 19 ++- .../Update/AIUpdate/DroneCarrierAIUpdate.cpp | 49 +++++++- .../Update/DroneCarrierSlavedUpdate.cpp | 35 +++++- 12 files changed, 231 insertions(+), 80 deletions(-) create mode 100644 GeneralsMD/Code/GameEngine/Include/GameLogic/Module/CarrierDroneAIUpdate.h delete mode 100644 GeneralsMD/Code/GameEngine/Include/GameLogic/Module/CarrierDroneJetAIUpdate.h rename GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/{CarrierDroneJetAIUpdate.cpp => CarrierDroneAIUpdate.cpp} (76%) diff --git a/Core/GameEngine/Source/Common/System/GameMemoryInitPools_GeneralsMD.inl b/Core/GameEngine/Source/Common/System/GameMemoryInitPools_GeneralsMD.inl index 37c44100a29..87ffdb27f22 100644 --- a/Core/GameEngine/Source/Common/System/GameMemoryInitPools_GeneralsMD.inl +++ b/Core/GameEngine/Source/Common/System/GameMemoryInitPools_GeneralsMD.inl @@ -682,6 +682,6 @@ static PoolSizeRec PoolSizes[] = { "DroneCarrierContain", 8, 8 }, { "W3DCarrierDraw", 8, 8 }, { "W3DDependencyCarrierDraw", 8, 8 }, - { "CarrierDroneJetAIUpdate", 16, 16 }, + { "CarrierDroneAIUpdate", 16, 16 }, { 0, 0, 0 } }; diff --git a/GeneralsMD/Code/GameEngine/CMakeLists.txt b/GeneralsMD/Code/GameEngine/CMakeLists.txt index 1d26e245424..e25aabab8f1 100644 --- a/GeneralsMD/Code/GameEngine/CMakeLists.txt +++ b/GeneralsMD/Code/GameEngine/CMakeLists.txt @@ -500,7 +500,7 @@ set(GAMEENGINE_SRC Include/GameLogic/Module/KodiakUpdate.h Include/GameLogic/Module/DroneCarrierSlavedUpdate.h Include/GameLogic/Module/DroneCarrierContain.h - Include/GameLogic/Module/CarrierDroneJetAIUpdate.h + Include/GameLogic/Module/CarrierDroneAIUpdate.h Include/GameLogic/Object.h Include/GameLogic/ObjectCreationList.h Include/GameLogic/ObjectIter.h @@ -1023,7 +1023,7 @@ set(GAMEENGINE_SRC Source/GameLogic/Object/Update/AIUpdate/TeleporterAIUpdate.cpp Source/GameLogic/Object/Update/AIUpdate/WorkerAIUpdate.cpp Source/GameLogic/Object/Update/AIUpdate/DroneCarrierAIUpdate.cpp - Source/GameLogic/Object/Update/AIUpdate/CarrierDroneJetAIUpdate.cpp + Source/GameLogic/Object/Update/AIUpdate/CarrierDroneAIUpdate.cpp Source/GameLogic/Object/Update/AnimationSteeringUpdate.cpp Source/GameLogic/Object/Update/AssistedTargetingUpdate.cpp Source/GameLogic/Object/Update/AutoDepositUpdate.cpp diff --git a/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/CarrierDroneAIUpdate.h b/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/CarrierDroneAIUpdate.h new file mode 100644 index 00000000000..513242436ff --- /dev/null +++ b/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/CarrierDroneAIUpdate.h @@ -0,0 +1,25 @@ +#pragma once + +#include "Common/STLTypedefs.h" +#include "Common/GameMemory.h" +#include "GameLogic/AIStateMachine.h" +#include "GameLogic/Module/AIUpdate.h" + + +//------------------------------------------------------------------------------------------------- +class CarrierDroneAIUpdate : public AIUpdateInterface +{ + + MEMORY_POOL_GLUE_WITH_USERLOOKUP_CREATE(CarrierDroneAIUpdate, "CarrierDroneAIUpdate") + MAKE_STANDARD_MODULE_MACRO_WITH_MODULE_DATA(CarrierDroneAIUpdate, AIUpdateModuleData) + + //virtual UpdateSleepTime update(); + +public: + + CarrierDroneAIUpdate(Thing* thing, const ModuleData* moduleData); + // virtual destructor prototype provided by memory pool declaration + + //stop contained drones from attacking + virtual void privateAttackPosition(const Coord3D* pos, Int maxShotsToFire, CommandSourceType cmdSource) override; ///< attack given spot +}; diff --git a/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/CarrierDroneJetAIUpdate.h b/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/CarrierDroneJetAIUpdate.h deleted file mode 100644 index 237933700c9..00000000000 --- a/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/CarrierDroneJetAIUpdate.h +++ /dev/null @@ -1,37 +0,0 @@ -// CarrierDroneJetAIUpdate.h ////////// -#pragma once - -#include "Common/STLTypedefs.h" -#include "Common/GameMemory.h" -#include "GameLogic/AIStateMachine.h" -#include "GameLogic/Module/AIUpdate.h" - -//------------------------------------------------------------------------------------------------- -//------------------------------------------------------------------------------------------------- -//------------------------------------------------------------------------------------------------- - - -//------------------------------------------------------------------------------------------------- -//class CarrierDroneJetAIUpdateModuleData : public AIUpdateModuleData -//{ -//public: -// -// -// CarrierDroneJetAIUpdateModuleData(); -// static void buildFieldParse(MultiIniFieldParse& p); -//}; - -//------------------------------------------------------------------------------------------------- -class CarrierDroneJetAIUpdate : public AIUpdateInterface -{ - - MEMORY_POOL_GLUE_WITH_USERLOOKUP_CREATE(CarrierDroneJetAIUpdate, "CarrierDroneJetAIUpdate") - MAKE_STANDARD_MODULE_MACRO_WITH_MODULE_DATA(CarrierDroneJetAIUpdate, AIUpdateModuleData) - - //virtual UpdateSleepTime update(); - -public: - - CarrierDroneJetAIUpdate(Thing* thing, const ModuleData* moduleData); - // virtual destructor prototype provided by memory pool declaration -}; diff --git a/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/DroneCarrierAIUpdate.h b/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/DroneCarrierAIUpdate.h index 18f3d8e9a2d..6d98c177710 100644 --- a/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/DroneCarrierAIUpdate.h +++ b/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/DroneCarrierAIUpdate.h @@ -77,6 +77,8 @@ class DroneCarrierAIUpdate : public AIUpdateInterface, // AIUpdateInterface virtual void aiDoCommand(const AICommandParms* parms); + static bool isDroneCombatReady(Object* drone); + private: struct DroneSlotInfo diff --git a/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/DroneCarrierContain.h b/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/DroneCarrierContain.h index 7676586e664..87c63f2da42 100644 --- a/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/DroneCarrierContain.h +++ b/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/DroneCarrierContain.h @@ -12,12 +12,24 @@ #include "GameLogic/Module/TransportContain.h" #include "GameLogic/Module/GarrisonContain.h" +//------------------------------------------------------------------------------------------------- +class DroneCarrierContainModuleData: public TransportContainModuleData +{ +public: + Real m_launchVelocityBoost; + + DroneCarrierContainModuleData(); + + static void buildFieldParse(MultiIniFieldParse& p); + +}; + //------------------------------------------------------------------------------------------------- class DroneCarrierContain: public TransportContain //public GarrisonContain { MEMORY_POOL_GLUE_WITH_USERLOOKUP_CREATE(DroneCarrierContain, "DroneCarrierContain") - MAKE_STANDARD_MODULE_MACRO_WITH_MODULE_DATA(DroneCarrierContain, TransportContainModuleData) + MAKE_STANDARD_MODULE_MACRO_WITH_MODULE_DATA(DroneCarrierContain, DroneCarrierContainModuleData) public: @@ -29,6 +41,8 @@ class DroneCarrierContain: public TransportContain //public GarrisonContain virtual Bool isEnclosingContainerFor(const Object* obj) const { return true; } //TODO param in module + virtual Bool isPassengerAllowedToFire(ObjectID id = INVALID_ID) const override; ///< Hey, can I shoot out of this container? + //support for specific exit bones virtual void onRemoving(Object* obj) override; virtual void onContaining(Object* obj, Bool wasSelected) override; ///< object now contains 'obj' diff --git a/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/DroneCarrierSlavedUpdate.h b/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/DroneCarrierSlavedUpdate.h index 1de6d108e54..640411cbd17 100644 --- a/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/DroneCarrierSlavedUpdate.h +++ b/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/DroneCarrierSlavedUpdate.h @@ -14,13 +14,17 @@ class DroneCarrierSlavedUpdateModuleData : public SlavedUpdateModuleData { public: + Real m_leashRange; + + DroneCarrierSlavedUpdateModuleData(); + static void buildFieldParse(MultiIniFieldParse& p); }; class DroneCarrierSlavedUpdate : public SlavedUpdate { MEMORY_POOL_GLUE_WITH_USERLOOKUP_CREATE(DroneCarrierSlavedUpdate, "DroneCarrierSlavedUpdate") - MAKE_STANDARD_MODULE_MACRO_WITH_MODULE_DATA(DroneCarrierSlavedUpdate, SlavedUpdateModuleData) + MAKE_STANDARD_MODULE_MACRO_WITH_MODULE_DATA(DroneCarrierSlavedUpdate, DroneCarrierSlavedUpdateModuleData) public: diff --git a/GeneralsMD/Code/GameEngine/Source/Common/Thing/ModuleFactory.cpp b/GeneralsMD/Code/GameEngine/Source/Common/Thing/ModuleFactory.cpp index 73b503b0e57..bbab7d75a5c 100644 --- a/GeneralsMD/Code/GameEngine/Source/Common/Thing/ModuleFactory.cpp +++ b/GeneralsMD/Code/GameEngine/Source/Common/Thing/ModuleFactory.cpp @@ -207,7 +207,7 @@ #include "GameLogic/Module/DroneCarrierAIUpdate.h" #include "GameLogic/Module/DroneCarrierSlavedUpdate.h" #include "GameLogic/Module/DroneCarrierContain.h" -#include "GameLogic/Module/CarrierDroneJetAIUpdate.h" +#include "GameLogic/Module/CarrierDroneAIUpdate.h" // upgrade includes #include "GameLogic/Module/ActiveShroudUpgrade.h" @@ -510,7 +510,7 @@ void ModuleFactory::init( void ) addModule( ResetSpecialPowerTimerWhileAliveUpdate ); addModule( DroneCarrierAIUpdate ); addModule( DroneCarrierSlavedUpdate ); - addModule( CarrierDroneJetAIUpdate ); + addModule( CarrierDroneAIUpdate ); // upgrade modules addModule( CostModifierUpgrade ); diff --git a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Contain/DroneCarrierContain.cpp b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Contain/DroneCarrierContain.cpp index 4196069e22d..54a49c93782 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Contain/DroneCarrierContain.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Contain/DroneCarrierContain.cpp @@ -23,11 +23,27 @@ #include "GameLogic/Weapon.h" #include "GameLogic/WeaponSetType.h" -// PUBLIC ///////////////////////////////////////////////////////////////////////////////////////// + +DroneCarrierContainModuleData::DroneCarrierContainModuleData() : TransportContainModuleData() +{ + m_launchVelocityBoost = 0.0f; +} + +void DroneCarrierContainModuleData::buildFieldParse(MultiIniFieldParse& p) +{ + TransportContainModuleData::buildFieldParse(p); + + static const FieldParse dataFieldParse[] = + { + { "LaunchVelocityBoost", INI::parseReal, NULL, offsetof(DroneCarrierContainModuleData, m_launchVelocityBoost) }, + { 0, 0, 0, 0 } + }; + p.add(dataFieldParse); +} + //------------------------------------------------------------------------------------------------- //------------------------------------------------------------------------------------------------- DroneCarrierContain::DroneCarrierContain(Thing* thing, const ModuleData* moduleData) : - //GarrisonContain(thing, moduleData) TransportContain(thing, moduleData) { const TransportContainModuleData* data = dynamic_cast(moduleData); @@ -87,6 +103,11 @@ Bool DroneCarrierContain::isValidContainerFor(const Object* rider, Bool checkCap return false; } +Bool DroneCarrierContain::isPassengerAllowedToFire(ObjectID id) const +{ + return false; +} + //------------------------------------------------------------------------------------------------- //------------------------------------------------------------------------------------------------- void DroneCarrierContain::onRemoving(Object* rider) @@ -97,7 +118,7 @@ void DroneCarrierContain::onRemoving(Object* rider) // object is no longer held inside a transport rider->clearDisabled(DISABLED_HELD); - const TransportContainModuleData* d = getTransportContainModuleData(); + const DroneCarrierContainModuleData* d = getDroneCarrierContainModuleData(); // give the object back a regular weapon rider->clearWeaponBonusCondition(WEAPONBONUSCONDITION_CONTAINED); @@ -154,6 +175,19 @@ void DroneCarrierContain::onRemoving(Object* rider) } } + if (d->m_launchVelocityBoost > 0.0f) { + PhysicsBehavior* phys = rider->getPhysics(); + if (phys != nullptr) { + Coord3D dir; + rider->getUnitDirectionVector3D(dir); + Real mass = phys->getMass() * d->m_launchVelocityBoost; + dir.x *= mass; + dir.y *= mass; + dir.z *= mass; + phys->applyMotiveForce(&dir); + } + } + Int transportSlotCount = rider->getTransportSlotCount(); DEBUG_ASSERTCRASH(transportSlotCount > 0, ("Hmm, this object isnt transportable")); m_extraSlotsInUse -= transportSlotCount - 1; @@ -200,6 +234,8 @@ void DroneCarrierContain::onRemoving(Object* rider) } } + + m_frameExitNotBusy = TheGameLogic->getFrame() + d->m_exitDelay; } @@ -218,18 +254,6 @@ void DroneCarrierContain::onContaining(Object* obj, Bool wasSelected) short DroneCarrierContain::getRiderSlot(ObjectID riderID) const { - /*short idx = 0; - for (ContainedItemsList::const_iterator it = getContainList().begin(); it != getContainList().end(); it++) - { - Object* obj; - - // get the object - obj = *it; - - if (obj && obj->getID() == riderID) - return idx; - idx++; - }*/ for (size_t i = 0; i < m_contained_units.size(); i++) { if (std::get<0>(m_contained_units[i]) == riderID) { return i; @@ -291,7 +315,6 @@ void DroneCarrierContain::crc(Xfer* xfer) // extend base class TransportContain::crc(xfer); - //GarrisonContain::crc(xfer); } // end crc @@ -304,7 +327,60 @@ void DroneCarrierContain::xfer(Xfer* xfer) { // extend base class TransportContain::xfer(xfer); - //GarrisonContain::xfer(xfer); + + //xfer the contain vector + // xfer the count of the vector + UnsignedShort listCount = m_contained_units.size(); + xfer->xferUnsignedShort(&listCount); + + // xfer vector data + std::tuple entry; + if (xfer->getXferMode() == XFER_SAVE || xfer->getXferMode() == XFER_CRC) + { + // save all tuples + std::vector< std::tuple >::const_iterator it; + for (it = m_contained_units.begin(); it != m_contained_units.end(); ++it) + { + + entry = *it; + xfer->xferObjectID(&std::get<0>(entry)); + xfer->xferUnsignedInt(&std::get<1>(entry)); + + } // end for + + } // end if, save + else if (xfer->getXferMode() == XFER_LOAD) + { + m_contained_units.clear(); + m_contained_units.reserve(listCount); + + // sanity, the list should be empty before we transfer more data into it + if (m_contained_units.size() != 0) + { + + DEBUG_CRASH(("DroneCarrierContain::xfer - object vector should be empty before loading")); + throw XFER_LIST_NOT_EMPTY; + + } // end if + + // read all ids + for (UnsignedShort i = 0; i < listCount; ++i) + { + + xfer->xferObjectID(&std::get<0>(entry)); + xfer->xferUnsignedInt(&std::get<1>(entry)); + m_contained_units.push_back(entry); + + } // end for, i + + } // end else if + else + { + + DEBUG_CRASH(("DroneCarrierContain::xfer - Unknown xfer mode '%d'", xfer->getXferMode())); + throw XFER_MODE_UNKNOWN; + + } // end else } // end xfer @@ -316,7 +392,5 @@ void DroneCarrierContain::loadPostProcess(void) // extend base class TransportContain::loadPostProcess(); - //GarrisonContain::loadPostProcess(); } // end loadPostProcess - diff --git a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/CarrierDroneJetAIUpdate.cpp b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/CarrierDroneAIUpdate.cpp similarity index 76% rename from GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/CarrierDroneJetAIUpdate.cpp rename to GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/CarrierDroneAIUpdate.cpp index c946e7521e5..47c912d7740 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/CarrierDroneJetAIUpdate.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/CarrierDroneAIUpdate.cpp @@ -19,25 +19,32 @@ #include "GameLogic/TerrainLogic.h" #include "GameLogic/Weapon.h" -#include "GameLogic/Module/CarrierDroneJetAIUpdate.h" +#include "GameLogic/Module/CarrierDroneAIUpdate.h" #include "GameLogic/Module/JetAIUpdate.h" #include "GameLogic/Module/ProductionUpdate.h" #include "GameLogic/Module/ContainModule.h" -CarrierDroneJetAIUpdate::CarrierDroneJetAIUpdate(Thing* thing, const ModuleData* moduleData) : AIUpdateInterface(thing, moduleData) +CarrierDroneAIUpdate::CarrierDroneAIUpdate(Thing* thing, const ModuleData* moduleData) : AIUpdateInterface(thing, moduleData) { } +void CarrierDroneAIUpdate::privateAttackPosition(const Coord3D* pos, Int maxShotsToFire, CommandSourceType cmdSource) +{ + if (getObject() && !getObject()->isContained()) { + AIUpdateInterface::privateAttackPosition(pos, maxShotsToFire, cmdSource); + } +} + //------------------------------------------------------------------------------------------------- //------------------------------------------------------------------------------------------------- -CarrierDroneJetAIUpdate::~CarrierDroneJetAIUpdate(void) +CarrierDroneAIUpdate::~CarrierDroneAIUpdate(void) { } // ------------------------------------------------------------------------------------------------ /** CRC */ // ------------------------------------------------------------------------------------------------ -void CarrierDroneJetAIUpdate::crc(Xfer* xfer) +void CarrierDroneAIUpdate::crc(Xfer* xfer) { // extend base class AIUpdateInterface::crc(xfer); @@ -48,7 +55,7 @@ void CarrierDroneJetAIUpdate::crc(Xfer* xfer) * Version Info: * 1: Initial version */ // ------------------------------------------------------------------------------------------------ -void CarrierDroneJetAIUpdate::xfer(Xfer* xfer) +void CarrierDroneAIUpdate::xfer(Xfer* xfer) { // version @@ -64,7 +71,7 @@ void CarrierDroneJetAIUpdate::xfer(Xfer* xfer) // ------------------------------------------------------------------------------------------------ /** Load post process */ // ------------------------------------------------------------------------------------------------ -void CarrierDroneJetAIUpdate::loadPostProcess(void) +void CarrierDroneAIUpdate::loadPostProcess(void) { // extend base class AIUpdateInterface::loadPostProcess(); diff --git a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/DroneCarrierAIUpdate.cpp b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/DroneCarrierAIUpdate.cpp index 6ff394d2100..f5791a8636a 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/DroneCarrierAIUpdate.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/DroneCarrierAIUpdate.cpp @@ -8,6 +8,7 @@ #include "Common/CRCDebug.h" #include "Common/Player.h" #include "Common/Team.h" +#include "Common/GameState.h" #include "Common/ThingFactory.h" #include "Common/ThingTemplate.h" #include "Common/Xfer.h" @@ -421,7 +422,8 @@ void DroneCarrierAIUpdate::onDie(const DamageInfo* damageInfo) /** * Check if drone has ammo and is repaired depending on combat state */ -bool drone_is_combat_ready(Object* drone) { +bool DroneCarrierAIUpdate::isDroneCombatReady(Object* drone) { + if (drone == nullptr) return false; if (drone->isContained()) { // Contained drone must be repaired before getting back to fight BodyModuleInterface* body = drone->getBodyModule(); @@ -463,7 +465,7 @@ void DroneCarrierAIUpdate::deployDrones() if (obj == NULL || obj->isEffectivelyDead()) continue; - if (obj->isContained() && drone_is_combat_ready(obj)) { + if (obj->isContained() && isDroneCombatReady(obj)) { AIUpdateInterface* ai = obj->getAI(); if (ai != nullptr) { ai->aiExit(carrier, CMD_FROM_AI); @@ -501,7 +503,7 @@ void DroneCarrierAIUpdate::propagateOrderToSpecificDrone(Object* drone) { Object* target = TheGameLogic->findObjectByID(m_designatedTarget); - AICommandType cmd = drone_is_combat_ready(drone) ? m_designatedCommand : AICMD_IDLE; + AICommandType cmd = isDroneCombatReady(drone) ? m_designatedCommand : AICMD_IDLE; bool contained = drone->isContained(); switch (cmd) @@ -726,7 +728,6 @@ void DroneCarrierAIUpdate::crc(Xfer* xfer) /** Xfer method * Version Info: * 1: Initial version - * 2: Added m_initialBurstTimesInited to the save. jba. */ // ------------------------------------------------------------------------------------------------ void DroneCarrierAIUpdate::xfer(Xfer* xfer) @@ -734,13 +735,51 @@ void DroneCarrierAIUpdate::xfer(Xfer* xfer) AsciiString name; // version - XferVersion currentVersion = 2; + XferVersion currentVersion = 1; XferVersion version = currentVersion; xfer->xferVersion(&version, currentVersion); // extend base class AIUpdateInterface::xfer(xfer); + // spawn template + name = m_spawnTemplate ? m_spawnTemplate->getName() : AsciiString::TheEmptyString; + xfer->xferAsciiString(&name); + if (xfer->getXferMode() == XFER_LOAD) + { + m_spawnTemplate = NULL; + if (name.isEmpty() == FALSE) + { + m_spawnTemplate = TheThingFactory->findTemplate(name); + if (m_spawnTemplate == NULL) + { + DEBUG_CRASH(("SpawnBehavior::xfer - Unable to find template '%s'", name.str())); + throw SC_INVALID_DATA; + + } // end if + } // end if + } // end if + + // spawn ids + xfer->xferSTLObjectIDVector(&m_spawnIDs); + + xfer->xferUnsignedInt(&m_rebuild_time); + xfer->xferBool(&m_active); + xfer->xferBool(&m_initial_spawns); + + xfer->xferObjectID(&m_designatedTarget); + + if (xfer->getXferMode() == XFER_LOAD) { + Int commandType; + xfer->xferInt(&commandType); + m_designatedCommand = (AICommandType)commandType; + } + else { + Int commandType = m_designatedCommand; + xfer->xferInt(&commandType); + } + + xfer->xferCoord3D(&m_designatedPosition); } // end xfer diff --git a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/DroneCarrierSlavedUpdate.cpp b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/DroneCarrierSlavedUpdate.cpp index db1e379edfc..f7325d5d25f 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/DroneCarrierSlavedUpdate.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/DroneCarrierSlavedUpdate.cpp @@ -1,5 +1,6 @@ #include "GameLogic/Module/AIUpdate.h" #include "GameLogic/Module/DroneCarrierSlavedUpdate.h" +#include "GameLogic/Module/DroneCarrierAIUpdate.h" #include "GameLogic/Object.h" #include "Common/RandomValue.h" @@ -24,6 +25,23 @@ const Real CLOSE_ENOUGH = 15; // Our moveTo commands and pathfinding can't handle people in the way, so quit trying to hump someone on your spot const Real CLOSE_ENOUGH_SQR = (CLOSE_ENOUGH * CLOSE_ENOUGH); + +DroneCarrierSlavedUpdateModuleData::DroneCarrierSlavedUpdateModuleData() +{ + m_leashRange = 0.0f; +} + +void DroneCarrierSlavedUpdateModuleData::buildFieldParse(MultiIniFieldParse& p) +{ + SlavedUpdateModuleData::buildFieldParse(p); + static const FieldParse dataFieldParse[] = + { + { "LeashRange", INI::parseReal, NULL, offsetof(DroneCarrierSlavedUpdateModuleData, m_leashRange) }, + { 0, 0, 0, 0 } + }; + p.add(dataFieldParse); +} + DroneCarrierSlavedUpdate::DroneCarrierSlavedUpdate(Thing* thing, const ModuleData* moduleData) : SlavedUpdate(thing, moduleData) { } @@ -51,7 +69,7 @@ UpdateSleepTime DroneCarrierSlavedUpdate::update(void) if (m_slaver == INVALID_ID) return UPDATE_SLEEP_NONE; - const SlavedUpdateModuleData* data = getSlavedUpdateModuleData(); + const DroneCarrierSlavedUpdateModuleData* data = getDroneCarrierSlavedUpdateModuleData(); Object* me = getObject(); if (!me) { @@ -97,7 +115,7 @@ UpdateSleepTime DroneCarrierSlavedUpdate::update(void) Object* target = NULL; AIUpdateInterface* masterAI = master->getAIUpdateInterface(); - if (masterAI) + if (masterAI && DroneCarrierAIUpdate::isDroneCombatReady(me)) { target = masterAI->getCurrentVictim(); } @@ -105,14 +123,19 @@ UpdateSleepTime DroneCarrierSlavedUpdate::update(void) AIUpdateInterface* ai = me->getAI(); if (ai == nullptr) return UPDATE_SLEEP_NONE; - if (data->m_attackRange) + if (data->m_attackRange && target != nullptr) { - if (target) + //Check distance to master + Real dist = ThePartitionManager->getDistanceSquared(me, master->getPosition(), FROM_BOUNDINGSPHERE_2D); + if (data->m_leashRange > 0.0f && dist > sqr(data->m_leashRange)) { + //Call back when too far away + ai->aiEnter(master, CMD_FROM_AI); + } + else { doAttackLogic(target); - - return UPDATE_SLEEP_NONE; } + return UPDATE_SLEEP_NONE; } // No Target, go home to carrier From 45c25bcde9d9182272050127182b5958428a62fd Mon Sep 17 00:00:00 2001 From: pWn3d Date: Thu, 4 Dec 2025 19:03:30 +0100 Subject: [PATCH 5/8] cleanup --- .../GameLogic/Module/DroneCarrierAIUpdate.h | 14 +- .../GameLogic/Module/DroneCarrierContain.h | 2 +- .../Update/AIUpdate/DroneCarrierAIUpdate.cpp | 22 +--- .../Update/DroneCarrierSlavedUpdate.cpp | 2 +- .../Code/GameEngineDevice/CMakeLists.txt | 2 - .../GameClient/Module/W3DCarrierDraw.h | 41 ------ .../Drawable/Draw/W3DCarrierDraw.cpp | 121 ------------------ .../Draw/W3DDependencyCarrierDraw.cpp | 2 +- 8 files changed, 6 insertions(+), 200 deletions(-) delete mode 100644 GeneralsMD/Code/GameEngineDevice/Include/W3DDevice/GameClient/Module/W3DCarrierDraw.h delete mode 100644 GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/Drawable/Draw/W3DCarrierDraw.cpp diff --git a/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/DroneCarrierAIUpdate.h b/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/DroneCarrierAIUpdate.h index 6d98c177710..1b2ad3c75c3 100644 --- a/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/DroneCarrierAIUpdate.h +++ b/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/DroneCarrierAIUpdate.h @@ -55,7 +55,7 @@ class DroneCarrierAIUpdate : public AIUpdateInterface, // SpawnBehaviorInterface virtual SpawnBehaviorInterface* getSpawnBehaviorInterface() { return this; } - virtual Bool maySpawnSelfTaskAI(Real maxSelfTaskersRatio) { return false; /*TODO*/ }; + virtual Bool maySpawnSelfTaskAI(Real maxSelfTaskersRatio) { return false; }; virtual void onSpawnDeath(ObjectID deadSpawn, DamageInfo* damageInfo); virtual Object* getClosestSlave(const Coord3D* pos); virtual void orderSlavesToAttackTarget(Object* target, Int maxShotsToFire, CommandSourceType cmdSource); @@ -81,19 +81,7 @@ class DroneCarrierAIUpdate : public AIUpdateInterface, private: - struct DroneSlotInfo - { - UnsignedInt m_slot_id; - ObjectID m_objectInSpace; - - DroneSlotInfo() - { - m_slot_id = 0; - m_objectInSpace = INVALID_ID; - } - }; Bool is_full(); ///< has this carrier an open spot? - Bool shouldTryToSpawn(); ///< For my own use, should I even think of spawning Bool createSpawn(); ///< Actual work of creating a guy void deployDrones(); ///< let all drones exit the transport diff --git a/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/DroneCarrierContain.h b/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/DroneCarrierContain.h index 87c63f2da42..0d6d620445c 100644 --- a/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/DroneCarrierContain.h +++ b/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/DroneCarrierContain.h @@ -25,7 +25,7 @@ class DroneCarrierContainModuleData: public TransportContainModuleData }; //------------------------------------------------------------------------------------------------- -class DroneCarrierContain: public TransportContain //public GarrisonContain +class DroneCarrierContain: public TransportContain { MEMORY_POOL_GLUE_WITH_USERLOOKUP_CREATE(DroneCarrierContain, "DroneCarrierContain") diff --git a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/DroneCarrierAIUpdate.cpp b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/DroneCarrierAIUpdate.cpp index f5791a8636a..50d718b146c 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/DroneCarrierAIUpdate.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/DroneCarrierAIUpdate.cpp @@ -73,11 +73,6 @@ DroneCarrierAIUpdate::~DroneCarrierAIUpdate(void) { } -Bool DroneCarrierAIUpdate::shouldTryToSpawn() -{ - return false; // TODO -} - Bool DroneCarrierAIUpdate::createSpawn() { Object* parent = getObject(); @@ -566,13 +561,9 @@ bool DroneCarrierAIUpdate::positionInRange(const Coord3D* loc) } // calc if within 2D range with 5% leeway Real range = primaryWeapon->getAttackRange(carrier); - Coord3D pos = *carrier->getPosition(); - pos.z = 0; - Coord3D loc2d = *loc; - loc2d.z = 0; + Real distsq = ThePartitionManager->getDistanceSquared(carrier, loc, FROM_CENTER_2D); - pos.sub(&loc2d); - return pos.lengthSqr() <= range * range * 1.05f; + return distsq < sqr(range) * 1.05f; } //------------------------------------------------------------------------------------------------- @@ -602,36 +593,27 @@ void DroneCarrierAIUpdate::aiDoCommand(const AICommandParms* parms) m_designatedTarget = INVALID_ID; m_designatedPosition.set(&parms->m_pos); m_designatedCommand = parms->m_cmd; - //if (positionInRange(&m_designatedPosition)) - // propagateOrdersToDrones(); break; case AICMD_ATTACK_POSITION: m_designatedTarget = INVALID_ID; m_designatedPosition.set(&parms->m_pos); m_designatedCommand = parms->m_cmd; - //if (positionInRange(&m_designatedPosition)) - // propagateOrdersToDrones(); break; case AICMD_FORCE_ATTACK_OBJECT: case AICMD_ATTACK_OBJECT: m_designatedTarget = parms->m_obj ? parms->m_obj->getID() : INVALID_ID; m_designatedPosition.zero(); m_designatedCommand = parms->m_cmd; - //if (parms->m_obj != nullptr && positionInRange(parms->m_obj->getPosition())) - // propagateOrdersToDrones(); break; case AICMD_ATTACKMOVE_TO_POSITION: m_designatedTarget = INVALID_ID; m_designatedPosition.set(&parms->m_pos); m_designatedCommand = parms->m_cmd; - //if (positionInRange(&m_designatedPosition)) - // propagateOrdersToDrones(); break; case AICMD_IDLE: m_designatedTarget = INVALID_ID; m_designatedPosition.zero(); m_designatedCommand = parms->m_cmd; - //propagateOrdersToDrones(); break; default: m_designatedCommand = AICMD_NO_COMMAND; diff --git a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/DroneCarrierSlavedUpdate.cpp b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/DroneCarrierSlavedUpdate.cpp index f7325d5d25f..0c754edd798 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/DroneCarrierSlavedUpdate.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/DroneCarrierSlavedUpdate.cpp @@ -126,7 +126,7 @@ UpdateSleepTime DroneCarrierSlavedUpdate::update(void) if (data->m_attackRange && target != nullptr) { //Check distance to master - Real dist = ThePartitionManager->getDistanceSquared(me, master->getPosition(), FROM_BOUNDINGSPHERE_2D); + Real dist = ThePartitionManager->getDistanceSquared(me, master->getPosition(), FROM_CENTER_2D); if (data->m_leashRange > 0.0f && dist > sqr(data->m_leashRange)) { //Call back when too far away diff --git a/GeneralsMD/Code/GameEngineDevice/CMakeLists.txt b/GeneralsMD/Code/GameEngineDevice/CMakeLists.txt index 0fd4f8f137e..45ff9e102b2 100644 --- a/GeneralsMD/Code/GameEngineDevice/CMakeLists.txt +++ b/GeneralsMD/Code/GameEngineDevice/CMakeLists.txt @@ -29,7 +29,6 @@ set(GAMEENGINEDEVICE_SRC Include/W3DDevice/GameClient/Module/W3DTracerDraw.h Include/W3DDevice/GameClient/Module/W3DTreeDraw.h Include/W3DDevice/GameClient/Module/W3DTruckDraw.h - Include/W3DDevice/GameClient/Module/W3DCarrierDraw.h Include/W3DDevice/GameClient/Module/W3DDependencyCarrierDraw.h Include/W3DDevice/GameClient/TerrainTex.h Include/W3DDevice/GameClient/TileData.h @@ -120,7 +119,6 @@ set(GAMEENGINEDEVICE_SRC Source/W3DDevice/GameClient/Drawable/Draw/W3DTracerDraw.cpp Source/W3DDevice/GameClient/Drawable/Draw/W3DTreeDraw.cpp Source/W3DDevice/GameClient/Drawable/Draw/W3DTruckDraw.cpp - Source/W3DDevice/GameClient/Drawable/Draw/W3DCarrierDraw.cpp Source/W3DDevice/GameClient/Drawable/Draw/W3DDependencyCarrierDraw.cpp Source/W3DDevice/GameClient/FlatHeightMap.cpp Source/W3DDevice/GameClient/GUI/Gadget/W3DCheckBox.cpp diff --git a/GeneralsMD/Code/GameEngineDevice/Include/W3DDevice/GameClient/Module/W3DCarrierDraw.h b/GeneralsMD/Code/GameEngineDevice/Include/W3DDevice/GameClient/Module/W3DCarrierDraw.h deleted file mode 100644 index b309ca00916..00000000000 --- a/GeneralsMD/Code/GameEngineDevice/Include/W3DDevice/GameClient/Module/W3DCarrierDraw.h +++ /dev/null @@ -1,41 +0,0 @@ -// FILE: W3DModelDraw.h ///////////////////////////////////////////////////////////////////////// -// Desc: Draw with stationed drones for drone carrier -/////////////////////////////////////////////////////////////////////////////////////////////////// - -#pragma once - -// INCLUDES /////////////////////////////////////////////////////////////////////////////////////// -#include "Common/ModelState.h" -#include "Common/DrawModule.h" -#include "W3DDevice/GameClient/Module/W3DModelDraw.h" - -//------------------------------------------------------------------------------------------------- -class W3DCarrierDrawModuleData : public W3DModelDrawModuleData -{ -public: - AsciiString m_dockingbone; - - W3DCarrierDrawModuleData(); - ~W3DCarrierDrawModuleData(); - - static void buildFieldParse(MultiIniFieldParse& p); -}; - -//------------------------------------------------------------------------------------------------- -class W3DCarrierDraw : public W3DModelDraw -{ - - MEMORY_POOL_GLUE_WITH_USERLOOKUP_CREATE(W3DCarrierDraw, "W3DCarrierDraw") - MAKE_STANDARD_MODULE_MACRO_WITH_MODULE_DATA(W3DCarrierDraw, W3DCarrierDrawModuleData) - -public: - - W3DCarrierDraw(Thing* thing, const ModuleData* moduleData); - // virtual destructor prototype provided by memory pool declaration - - virtual void setHidden(Bool h); - virtual void doDrawModule(const Matrix3D* transformMtx); - -protected: - -}; diff --git a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/Drawable/Draw/W3DCarrierDraw.cpp b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/Drawable/Draw/W3DCarrierDraw.cpp deleted file mode 100644 index beff2e25b45..00000000000 --- a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/Drawable/Draw/W3DCarrierDraw.cpp +++ /dev/null @@ -1,121 +0,0 @@ -// FILE: W3DCarrierDraw.cpp //////////////////////////////////////////////////////////////////////////// - -// Desc: Render stationed Objects with carriers -/////////////////////////////////////////////////////////////////////////////////////////////////// - -// INCLUDES /////////////////////////////////////////////////////////////////////////////////////// -#include "Common/Xfer.h" -#include "GameClient/Drawable.h" -#include "GameLogic/Object.h" -#include "GameLogic/Module/ContainModule.h" -#include "W3DDevice/GameClient/Module/W3DCarrierDraw.h" - -//------------------------------------------------------------------------------------------------- -W3DCarrierDrawModuleData::W3DCarrierDrawModuleData() -{ - m_dockingbone.clear(); -} - -//------------------------------------------------------------------------------------------------- -W3DCarrierDrawModuleData::~W3DCarrierDrawModuleData() -{ -} - -//------------------------------------------------------------------------------------------------- -void W3DCarrierDrawModuleData::buildFieldParse(MultiIniFieldParse& p) -{ - W3DModelDrawModuleData::buildFieldParse(p); - - static const FieldParse dataFieldParse[] = - { - { "DockingBone", INI::parseAsciiString, NULL, offsetof(W3DCarrierDrawModuleData, m_dockingbone) }, - { 0, 0, 0, 0 } - }; - p.add(dataFieldParse); -} - -//------------------------------------------------------------------------------------------------- -//------------------------------------------------------------------------------------------------- -W3DCarrierDraw::W3DCarrierDraw(Thing* thing, const ModuleData* moduleData) - : W3DModelDraw(thing, moduleData) -{ -} - -//------------------------------------------------------------------------------------------------- -//------------------------------------------------------------------------------------------------- -W3DCarrierDraw::~W3DCarrierDraw() -{ -} - -//------------------------------------------------------------------------------------------------- -void W3DCarrierDraw::doDrawModule(const Matrix3D* transformMtx) -{ - W3DModelDraw::doDrawModule(transformMtx); - - Object* me = getDrawable()->getObject(); - if (me && me->getContain()) { - - const ContainedItemsList* docked_units = me->getContain()->getContainedItemsList(); - for (ContainedItemsList::const_iterator it = docked_units->begin(); it != docked_units->end(); ++it) { - Drawable* riderDraw = (*it)->getDrawable(); - riderDraw->setColorTintEnvelope(*getDrawable()->getColorTintEnvelope()); - riderDraw->notifyDrawableDependencyCleared(); - riderDraw->draw(NULL); - } - } -} - -//------------------------------------------------------------------------------------------------- -void W3DCarrierDraw::setHidden(Bool h) -{ - W3DModelDraw::setHidden(h); - - //TODO - // - // We need to hide our rider, since he won't realize he's being contained in a contained container - //Object* me = getDrawable()->getObject(); - //if (me && me->getContain()) { - - //} -} - -//------------------------------------------------------------------------------------------------- -// ------------------------------------------------------------------------------------------------ -/** CRC */ -// ------------------------------------------------------------------------------------------------ -void W3DCarrierDraw::crc(Xfer* xfer) -{ - - // extend base class - W3DModelDraw::crc(xfer); - -} // end crc - -// ------------------------------------------------------------------------------------------------ -/** Xfer method - * Version Info: - * 1: Initial version */ - // ------------------------------------------------------------------------------------------------ -void W3DCarrierDraw::xfer(Xfer* xfer) -{ - - // version - XferVersion currentVersion = 1; - XferVersion version = currentVersion; - xfer->xferVersion(&version, currentVersion); - - // extend base class - W3DModelDraw::xfer(xfer); - -} // end xfer - -// ------------------------------------------------------------------------------------------------ -/** Load post process */ -// ------------------------------------------------------------------------------------------------ -void W3DCarrierDraw::loadPostProcess(void) -{ - - // extend base class - W3DModelDraw::loadPostProcess(); - -} // end loadPostProcess diff --git a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/Drawable/Draw/W3DDependencyCarrierDraw.cpp b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/Drawable/Draw/W3DDependencyCarrierDraw.cpp index 534d103281a..690e60cd15a 100644 --- a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/Drawable/Draw/W3DDependencyCarrierDraw.cpp +++ b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/Drawable/Draw/W3DDependencyCarrierDraw.cpp @@ -1,4 +1,4 @@ -// FILE: W3DCarrierDraw.cpp //////////////////////////////////////////////////////////////////////////// +// FILE: W3DDependencyCarrierDraw.cpp //////////////////////////////////////////////////////////////////////////// // Desc: Render stationed Objects with carriers /////////////////////////////////////////////////////////////////////////////////////////////////// From 5c79737c72335294db2d042a21e79320a52f50f9 Mon Sep 17 00:00:00 2001 From: pWn3d Date: Thu, 4 Dec 2025 19:46:39 +0100 Subject: [PATCH 6/8] add ambient sound toggle --- .../GameLogic/Object/Contain/DroneCarrierContain.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Contain/DroneCarrierContain.cpp b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Contain/DroneCarrierContain.cpp index 54a49c93782..73093466c2a 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Contain/DroneCarrierContain.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Contain/DroneCarrierContain.cpp @@ -124,6 +124,11 @@ void DroneCarrierContain::onRemoving(Object* rider) rider->clearWeaponBonusCondition(WEAPONBONUSCONDITION_CONTAINED); rider->clearWeaponSetFlag(WEAPONSET_CONTAINED); + Drawable* rider_draw = rider->getDrawable(); + if (rider_draw != nullptr) { + rider_draw->enableAmbientSound(true); + } + // If we have a bone and no exit paths, put each rider at the numbered bone position if (!d->m_exitBone.isEmpty() && d->m_numberOfExitPaths <= 0) { @@ -243,6 +248,11 @@ void DroneCarrierContain::onContaining(Object* obj, Bool wasSelected) { TransportContain::onContaining(obj, wasSelected); + Drawable* draw = obj->getDrawable(); + if (draw != nullptr) { + draw->enableAmbientSound(false); + } + // Assing in first free slot for (size_t i = 0; i < m_contained_units.size(); i++) { if (std::get<0>(m_contained_units[i]) == INVALID_ID) { From 3259792588a3dca3e74ded5e93342d03d6b424f6 Mon Sep 17 00:00:00 2001 From: pWn3d Date: Sat, 6 Dec 2025 08:12:03 +0100 Subject: [PATCH 7/8] update memory pools --- .../Source/Common/System/GameMemoryInitPools_GeneralsMD.inl | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Core/GameEngine/Source/Common/System/GameMemoryInitPools_GeneralsMD.inl b/Core/GameEngine/Source/Common/System/GameMemoryInitPools_GeneralsMD.inl index 87ffdb27f22..322d1a668f1 100644 --- a/Core/GameEngine/Source/Common/System/GameMemoryInitPools_GeneralsMD.inl +++ b/Core/GameEngine/Source/Common/System/GameMemoryInitPools_GeneralsMD.inl @@ -680,8 +680,7 @@ static PoolSizeRec PoolSizes[] = { "DroneCarrierAIUpdate", 8, 8 }, { "DroneCarrierSlavedUpdate", 8, 8 }, { "DroneCarrierContain", 8, 8 }, - { "W3DCarrierDraw", 8, 8 }, - { "W3DDependencyCarrierDraw", 8, 8 }, + { "W3DDependencyCarrierDraw", 16, 16 }, { "CarrierDroneAIUpdate", 16, 16 }, { 0, 0, 0 } }; From 79c68ad6d44a6c980c6a561ab2b0bb380212e6ac Mon Sep 17 00:00:00 2001 From: pWn3d Date: Sat, 6 Dec 2025 11:10:59 +0100 Subject: [PATCH 8/8] allow force firing of carrier --- .../GameLogic/Module/DroneCarrierAIUpdate.h | 7 ++- .../Update/AIUpdate/DroneCarrierAIUpdate.cpp | 47 +++++++++---------- 2 files changed, 29 insertions(+), 25 deletions(-) diff --git a/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/DroneCarrierAIUpdate.h b/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/DroneCarrierAIUpdate.h index 1b2ad3c75c3..6021d4dc1e9 100644 --- a/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/DroneCarrierAIUpdate.h +++ b/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/DroneCarrierAIUpdate.h @@ -90,7 +90,9 @@ class DroneCarrierAIUpdate : public AIUpdateInterface, void propagateOrdersToDrones(); void propagateOrderToSpecificDrone(Object* drone); - bool positionInRange(const Coord3D* loc); + //works for both Object and Coord3D + template + bool targetInRange(const T* target); const ThingTemplate* m_spawnTemplate; ///< What it is I spawn std::vector m_spawnIDs; ///< IDs of currently active drones @@ -103,5 +105,8 @@ class DroneCarrierAIUpdate : public AIUpdateInterface, Coord3D m_designatedPosition; }; +template bool DroneCarrierAIUpdate::targetInRange(const Object* target); +template bool DroneCarrierAIUpdate::targetInRange(const Coord3D* target); + #endif // __DRONE_CARRIER_AI_UPDATE_H diff --git a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/DroneCarrierAIUpdate.cpp b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/DroneCarrierAIUpdate.cpp index 50d718b146c..6bb0ccd8d79 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/DroneCarrierAIUpdate.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/DroneCarrierAIUpdate.cpp @@ -550,8 +550,11 @@ void DroneCarrierAIUpdate::propagateOrderToSpecificDrone(Object* drone) } } -bool DroneCarrierAIUpdate::positionInRange(const Coord3D* loc) +template +bool DroneCarrierAIUpdate::targetInRange(const T* target) { + if (target == nullptr) return false; + Object* carrier = getObject(); Weapon* primaryWeapon = carrier->getWeaponInWeaponSlot(PRIMARY_WEAPON); @@ -559,11 +562,8 @@ bool DroneCarrierAIUpdate::positionInRange(const Coord3D* loc) if (primaryWeapon == nullptr) { return true; } - // calc if within 2D range with 5% leeway - Real range = primaryWeapon->getAttackRange(carrier); - Real distsq = ThePartitionManager->getDistanceSquared(carrier, loc, FROM_CENTER_2D); - return distsq < sqr(range) * 1.05f; + return primaryWeapon->isWithinAttackRange(carrier, target); } //------------------------------------------------------------------------------------------------- @@ -586,6 +586,7 @@ void DroneCarrierAIUpdate::aiDoCommand(const AICommandParms* parms) //forward commands to drones if (parms->m_cmdSource != CMD_FROM_AI) { + //DEBUG_LOG(("DroneCarrier: getting order: %d", parms->m_cmd)); //Now the only time we care about anything is if we were ordered to attack something or attack move. switch (parms->m_cmd) { @@ -669,25 +670,23 @@ UpdateSleepTime DroneCarrierAIUpdate::update() } Object* my_target = getCurrentVictim(); - if (my_target != nullptr) { - - if (positionInRange(my_target->getPosition())) { - // send out contained drones - deployDrones(); - - //update orders - if (now % 5 == 0) { //do every 5th frame - switch (m_designatedCommand) { - case AICMD_GUARD_POSITION: - case AICMD_ATTACK_POSITION: - case AICMD_FORCE_ATTACK_OBJECT: - case AICMD_ATTACK_OBJECT: - case AICMD_ATTACKMOVE_TO_POSITION: - propagateOrdersToDrones(); - break; - default: - break; - } + const Coord3D* my_target_pos = getCurrentVictimPos(); + if (targetInRange(my_target) || targetInRange(my_target_pos)) { + // send out contained drones + deployDrones(); + + //update orders + if (now % 5 == 0) { //do every 5th frame + switch (m_designatedCommand) { + case AICMD_GUARD_POSITION: + case AICMD_ATTACK_POSITION: + case AICMD_FORCE_ATTACK_OBJECT: + case AICMD_ATTACK_OBJECT: + case AICMD_ATTACKMOVE_TO_POSITION: + propagateOrdersToDrones(); + break; + default: + break; } } }