diff --git a/Generals/Code/GameEngine/Include/GameLogic/Module/ContainModule.h b/Generals/Code/GameEngine/Include/GameLogic/Module/ContainModule.h index 0fd739a4822..6ebd21ba40a 100644 --- a/Generals/Code/GameEngine/Include/GameLogic/Module/ContainModule.h +++ b/Generals/Code/GameEngine/Include/GameLogic/Module/ContainModule.h @@ -164,7 +164,7 @@ class ContainModuleInterface // Player Occupancy. virtual PlayerMaskType getPlayerWhoEntered() const = 0; - virtual void processDamageToContained() = 0; ///< Do our % damage to units now. + virtual void processDamageToContained(Real percentDamage) = 0; ///< Do our % damage to units now. virtual void enableLoadSounds( Bool enable ) = 0; diff --git a/Generals/Code/GameEngine/Include/GameLogic/Module/OpenContain.h b/Generals/Code/GameEngine/Include/GameLogic/Module/OpenContain.h index c3dc8a535ba..bb696ba16e9 100644 --- a/Generals/Code/GameEngine/Include/GameLogic/Module/OpenContain.h +++ b/Generals/Code/GameEngine/Include/GameLogic/Module/OpenContain.h @@ -204,7 +204,7 @@ class OpenContain : public UpdateModule, // returns true iff there are objects currently waiting to enter. virtual Bool hasObjectsWantingToEnterOrExit() const override; - virtual void processDamageToContained() override; ///< Do our % damage to units now. + virtual void processDamageToContained(Real percentDamage) override; ///< Do our % damage to units now. virtual void enableLoadSounds( Bool enable ) override { m_loadSoundsEnabled = enable; } diff --git a/Generals/Code/GameEngine/Source/GameLogic/Object/Contain/OpenContain.cpp b/Generals/Code/GameEngine/Source/GameLogic/Object/Contain/OpenContain.cpp index 65e0565cb3a..0c1df3eaf31 100644 --- a/Generals/Code/GameEngine/Source/GameLogic/Object/Contain/OpenContain.cpp +++ b/Generals/Code/GameEngine/Source/GameLogic/Object/Contain/OpenContain.cpp @@ -760,14 +760,20 @@ void OpenContain::onDie( const DamageInfo * damageInfo ) if (!getOpenContainModuleData()->m_dieMuxData.isDieApplicable(getObject(), damageInfo)) return; +#if !RETAIL_COMPATIBLE_CRC + killRidersWhoAreNotFreeToExit(); +#endif + //Check to see if we are going to inflict damage on contained units. if( getOpenContainModuleData()->m_damagePercentageToUnits > 0 ) { //Cycle through the units and apply damage to them! - processDamageToContained(); + processDamageToContained(getOpenContainModuleData()->m_damagePercentageToUnits); } +#if RETAIL_COMPATIBLE_CRC killRidersWhoAreNotFreeToExit(); +#endif // Leaving this commented out to show it can't work. We are about to die, so they will have zero // chance to hit an exitState::Update. At least we would clean them up in onDelete. @@ -1291,9 +1297,9 @@ void OpenContain::orderAllPassengersToExit( CommandSourceType commandSource ) } //------------------------------------------------------------------------------------------------- -void OpenContain::processDamageToContained() +void OpenContain::processDamageToContained(Real percentDamage) { - const OpenContainModuleData* data = getOpenContainModuleData(); + const bool killContained = percentDamage == 1.0f; #if RETAIL_COMPATIBLE_CRC @@ -1308,7 +1314,7 @@ void OpenContain::processDamageToContained() Object *object = *it++; //Calculate the damage to be inflicted on each unit. - Real damage = object->getBodyModule()->getMaxHealth() * data->m_damagePercentageToUnits; + Real damage = object->getBodyModule()->getMaxHealth() * percentDamage; DamageInfo damageInfo; damageInfo.in.m_damageType = DAMAGE_UNRESISTABLE; @@ -1317,7 +1323,7 @@ void OpenContain::processDamageToContained() damageInfo.in.m_amount = damage; object->attemptDamage( &damageInfo ); - if( !object->isEffectivelyDead() && data->m_damagePercentageToUnits == 1.0f ) + if( !object->isEffectivelyDead() && killContained ) object->kill(); // in case we are carrying flame proof troops we have been asked to kill // TheSuperHackers @info Calls to Object::attemptDamage and Object::kill will not remove @@ -1365,7 +1371,7 @@ void OpenContain::processDamageToContained() DEBUG_ASSERTCRASH( object, ("Contain list must not contain null element") ); // Calculate the damage to be inflicted on each unit. - Real damage = object->getBodyModule()->getMaxHealth() * data->m_damagePercentageToUnits; + Real damage = object->getBodyModule()->getMaxHealth() * percentDamage; DamageInfo damageInfo; damageInfo.in.m_damageType = DAMAGE_UNRESISTABLE; @@ -1374,7 +1380,7 @@ void OpenContain::processDamageToContained() damageInfo.in.m_amount = damage; object->attemptDamage( &damageInfo ); - if( !object->isEffectivelyDead() && data->m_damagePercentageToUnits == 1.0f ) + if( !object->isEffectivelyDead() && killContained ) object->kill(); // in case we are carrying flame proof troops we have been asked to kill if ( object->isEffectivelyDead() ) diff --git a/Generals/Code/GameEngine/Source/GameLogic/Object/Contain/TransportContain.cpp b/Generals/Code/GameEngine/Source/GameLogic/Object/Contain/TransportContain.cpp index 65333ea9918..7c533936c5b 100644 --- a/Generals/Code/GameEngine/Source/GameLogic/Object/Contain/TransportContain.cpp +++ b/Generals/Code/GameEngine/Source/GameLogic/Object/Contain/TransportContain.cpp @@ -456,6 +456,14 @@ Bool TransportContain::isSpecificRiderFreeToExit(Object* specificObject) if (ai && ai->getAiFreeToExit(specificObject) != FREE_TO_EXIT) return FALSE; +#if !RETAIL_COMPATIBLE_CRC + // TheSuperHackers @bugfix Stubbjax 02/03/2026 If our parent container is held, then we + // are not free to exit. + DEBUG_ASSERTCRASH(specificObject->getContainedBy(), ("rider must be contained")); + if (specificObject->getContainedBy()->isDisabledByType(DISABLED_HELD)) + return FALSE; +#endif + // I can always kick people out if I am in the air, I know what I'm doing if (me->isUsingAirborneLocomotor()) return TRUE; diff --git a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Contain/OpenContain.cpp b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Contain/OpenContain.cpp index d2a741e441c..f436ed26245 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Contain/OpenContain.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Contain/OpenContain.cpp @@ -880,6 +880,10 @@ void OpenContain::onDie( const DamageInfo * damageInfo ) if (!getOpenContainModuleData()->m_dieMuxData.isDieApplicable(getObject(), damageInfo)) return; +#if !RETAIL_COMPATIBLE_CRC + killRidersWhoAreNotFreeToExit(); +#endif + //Check to see if we are going to inflict damage on contained units. if( getDamagePercentageToUnits() > 0 ) { @@ -887,7 +891,9 @@ void OpenContain::onDie( const DamageInfo * damageInfo ) processDamageToContained(getDamagePercentageToUnits()); } +#if RETAIL_COMPATIBLE_CRC killRidersWhoAreNotFreeToExit(); +#endif // Leaving this commented out to show it can't work. We are about to die, so they will have zero // chance to hit an exitState::Update. At least we would clean them up in onDelete. @@ -1462,6 +1468,7 @@ void OpenContain::orderAllPassengersToHackInternet( CommandSourceType commandSou void OpenContain::processDamageToContained(Real percentDamage) { const OpenContainModuleData *data = getOpenContainModuleData(); + const bool killContained = percentDamage == 1.0f; #if RETAIL_COMPATIBLE_CRC @@ -1485,7 +1492,7 @@ void OpenContain::processDamageToContained(Real percentDamage) damageInfo.in.m_amount = damage; object->attemptDamage( &damageInfo ); - if( !object->isEffectivelyDead() && percentDamage == 1.0f ) + if( !object->isEffectivelyDead() && killContained ) object->kill(); // in case we are carrying flame proof troops we have been asked to kill // TheSuperHackers @info Calls to Object::attemptDamage and Object::kill will not remove @@ -1542,7 +1549,7 @@ void OpenContain::processDamageToContained(Real percentDamage) damageInfo.in.m_amount = damage; object->attemptDamage( &damageInfo ); - if( !object->isEffectivelyDead() && percentDamage == 1.0f ) + if( !object->isEffectivelyDead() && killContained ) object->kill(); // in case we are carrying flame proof troops we have been asked to kill if ( object->isEffectivelyDead() ) diff --git a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Contain/TransportContain.cpp b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Contain/TransportContain.cpp index 32de3e281df..fe364eee869 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Contain/TransportContain.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Contain/TransportContain.cpp @@ -540,7 +540,12 @@ void TransportContain::killRidersWhoAreNotFreeToExit() if (d->m_destroyRidersWhoAreNotFreeToExit) TheGameLogic->destroyObject(obj); else +#if RETAIL_COMPATIBLE_CRC obj->kill(); +#else + // TheSuperHackers @info Burned death prevents infantry corpses dropping out of the container. + obj->kill(DAMAGE_UNRESISTABLE, d->m_isBurnedDeathToUnits ? DEATH_BURNED : DEATH_NORMAL); +#endif } } } @@ -562,6 +567,14 @@ Bool TransportContain::isSpecificRiderFreeToExit(Object* specificObject) if (ai && ai->getAiFreeToExit(specificObject) != FREE_TO_EXIT) return FALSE; +#if !RETAIL_COMPATIBLE_CRC + // TheSuperHackers @bugfix Stubbjax 02/03/2026 If our parent container is held, then we + // are not free to exit. + DEBUG_ASSERTCRASH(specificObject->getContainedBy(), ("rider must be contained")); + if (specificObject->getContainedBy()->isDisabledByType(DISABLED_HELD)) + return FALSE; +#endif + // I can always kick people out if I am in the air, I know what I'm doing if (me->isUsingAirborneLocomotor()) return TRUE;