From 804f382371452403786a6cfb13ce5f311f1893e5 Mon Sep 17 00:00:00 2001 From: Bobby Battista Date: Mon, 17 Nov 2025 17:33:11 -0500 Subject: [PATCH 1/2] Fix PoisonedBehavior damage over time to respect poison resistance --- .../GameLogic/Object/Behavior/PoisonedBehavior.cpp | 8 +++++--- .../GameLogic/Object/Behavior/PoisonedBehavior.cpp | 10 ++++++---- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/Generals/Code/GameEngine/Source/GameLogic/Object/Behavior/PoisonedBehavior.cpp b/Generals/Code/GameEngine/Source/GameLogic/Object/Behavior/PoisonedBehavior.cpp index d9c446f248..738564b10b 100644 --- a/Generals/Code/GameEngine/Source/GameLogic/Object/Behavior/PoisonedBehavior.cpp +++ b/Generals/Code/GameEngine/Source/GameLogic/Object/Behavior/PoisonedBehavior.cpp @@ -86,7 +86,8 @@ PoisonedBehavior::~PoisonedBehavior( void ) //------------------------------------------------------------------------------------------------- void PoisonedBehavior::onDamage( DamageInfo *damageInfo ) { - if( damageInfo->in.m_damageType == DAMAGE_POISON ) + if( damageInfo->in.m_damageType == DAMAGE_POISON && + damageInfo->in.m_sourceID != INVALID_ID ) startPoisonedEffects( damageInfo ); } @@ -118,8 +119,9 @@ UpdateSleepTime PoisonedBehavior::update() // If it is time to do damage, then do it and reset the damage timer DamageInfo damage; damage.in.m_amount = m_poisonDamageAmount; - damage.in.m_sourceID = m_poisonSource; - damage.in.m_damageType = DAMAGE_UNRESISTABLE; // Not poison, as that will infect us again + // TheSuperHackers @bugfix bobtista 11/17/2025 Use INVALID_ID to prevent infinite loop while allowing poison resistance to work + damage.in.m_sourceID = INVALID_ID; + damage.in.m_damageType = DAMAGE_POISON; damage.in.m_deathType = m_deathType; getObject()->attemptDamage( &damage ); diff --git a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Behavior/PoisonedBehavior.cpp b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Behavior/PoisonedBehavior.cpp index 3c32fe58a7..6aa371e330 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Behavior/PoisonedBehavior.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Behavior/PoisonedBehavior.cpp @@ -86,7 +86,8 @@ PoisonedBehavior::~PoisonedBehavior( void ) //------------------------------------------------------------------------------------------------- void PoisonedBehavior::onDamage( DamageInfo *damageInfo ) { - if( damageInfo->in.m_damageType == DAMAGE_POISON ) + if( damageInfo->in.m_damageType == DAMAGE_POISON && + damageInfo->in.m_sourceID != INVALID_ID ) startPoisonedEffects( damageInfo ); } @@ -118,9 +119,10 @@ UpdateSleepTime PoisonedBehavior::update() // If it is time to do damage, then do it and reset the damage timer DamageInfo damage; damage.in.m_amount = m_poisonDamageAmount; - damage.in.m_sourceID = m_poisonSource; - damage.in.m_damageType = DAMAGE_UNRESISTABLE; // Not poison, as that will infect us again - damage.in.m_damageFXOverride = DAMAGE_POISON; // but this will ensure that the right effect is played + // TheSuperHackers @bugfix bobtista 11/17/2025 Use INVALID_ID to prevent infinite loop while allowing poison resistance to work + damage.in.m_sourceID = INVALID_ID; + damage.in.m_damageType = DAMAGE_POISON; + damage.in.m_damageFXOverride = DAMAGE_POISON; damage.in.m_deathType = m_deathType; getObject()->attemptDamage( &damage ); From b743b0ba274fe506c39d4291845daf58b657acc4 Mon Sep 17 00:00:00 2001 From: Bobby Battista Date: Mon, 17 Nov 2025 18:15:18 -0500 Subject: [PATCH 2/2] put behind CRC retail compat flag --- .../Object/Behavior/PoisonedBehavior.cpp | 16 ++++++++++++++-- .../Object/Behavior/PoisonedBehavior.cpp | 17 +++++++++++++++-- 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/Generals/Code/GameEngine/Source/GameLogic/Object/Behavior/PoisonedBehavior.cpp b/Generals/Code/GameEngine/Source/GameLogic/Object/Behavior/PoisonedBehavior.cpp index 738564b10b..57619735e2 100644 --- a/Generals/Code/GameEngine/Source/GameLogic/Object/Behavior/PoisonedBehavior.cpp +++ b/Generals/Code/GameEngine/Source/GameLogic/Object/Behavior/PoisonedBehavior.cpp @@ -86,9 +86,16 @@ PoisonedBehavior::~PoisonedBehavior( void ) //------------------------------------------------------------------------------------------------- void PoisonedBehavior::onDamage( DamageInfo *damageInfo ) { - if( damageInfo->in.m_damageType == DAMAGE_POISON && - damageInfo->in.m_sourceID != INVALID_ID ) + if( damageInfo->in.m_damageType == DAMAGE_POISON ) + { +#if !RETAIL_COMPATIBLE_CRC + // TheSuperHackers @bugfix bobtista 11/17/2025 Ignore damage with INVALID_ID source to prevent infinite loop from DoT + if( damageInfo->in.m_sourceID != INVALID_ID ) + startPoisonedEffects( damageInfo ); +#else startPoisonedEffects( damageInfo ); +#endif + } } // ------------------------------------------------------------------------------------------------ @@ -119,9 +126,14 @@ UpdateSleepTime PoisonedBehavior::update() // If it is time to do damage, then do it and reset the damage timer DamageInfo damage; damage.in.m_amount = m_poisonDamageAmount; +#if !RETAIL_COMPATIBLE_CRC // TheSuperHackers @bugfix bobtista 11/17/2025 Use INVALID_ID to prevent infinite loop while allowing poison resistance to work damage.in.m_sourceID = INVALID_ID; damage.in.m_damageType = DAMAGE_POISON; +#else + damage.in.m_sourceID = m_poisonSource; + damage.in.m_damageType = DAMAGE_UNRESISTABLE; // Not poison, as that will infect us again +#endif damage.in.m_deathType = m_deathType; getObject()->attemptDamage( &damage ); diff --git a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Behavior/PoisonedBehavior.cpp b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Behavior/PoisonedBehavior.cpp index 6aa371e330..ab0e1a8f57 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Behavior/PoisonedBehavior.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Behavior/PoisonedBehavior.cpp @@ -86,9 +86,16 @@ PoisonedBehavior::~PoisonedBehavior( void ) //------------------------------------------------------------------------------------------------- void PoisonedBehavior::onDamage( DamageInfo *damageInfo ) { - if( damageInfo->in.m_damageType == DAMAGE_POISON && - damageInfo->in.m_sourceID != INVALID_ID ) + if( damageInfo->in.m_damageType == DAMAGE_POISON ) + { +#if !RETAIL_COMPATIBLE_CRC + // TheSuperHackers @bugfix bobtista 11/17/2025 Ignore damage with INVALID_ID source to prevent infinite loop from DoT + if( damageInfo->in.m_sourceID != INVALID_ID ) + startPoisonedEffects( damageInfo ); +#else startPoisonedEffects( damageInfo ); +#endif + } } // ------------------------------------------------------------------------------------------------ @@ -119,10 +126,16 @@ UpdateSleepTime PoisonedBehavior::update() // If it is time to do damage, then do it and reset the damage timer DamageInfo damage; damage.in.m_amount = m_poisonDamageAmount; +#if !RETAIL_COMPATIBLE_CRC // TheSuperHackers @bugfix bobtista 11/17/2025 Use INVALID_ID to prevent infinite loop while allowing poison resistance to work damage.in.m_sourceID = INVALID_ID; damage.in.m_damageType = DAMAGE_POISON; damage.in.m_damageFXOverride = DAMAGE_POISON; +#else + damage.in.m_sourceID = m_poisonSource; + damage.in.m_damageType = DAMAGE_UNRESISTABLE; // Not poison, as that will infect us again + damage.in.m_damageFXOverride = DAMAGE_POISON; // but this will ensure that the right effect is played +#endif damage.in.m_deathType = m_deathType; getObject()->attemptDamage( &damage );