From ba4f1138da3915b28ccda81565606499279cdbd5 Mon Sep 17 00:00:00 2001 From: Stubbjax Date: Thu, 5 Feb 2026 02:06:49 +1100 Subject: [PATCH 1/4] bugfix: Battle plans are now transferred to the new owner on capture --- .../GameLogic/Module/BattlePlanUpdate.h | 1 + .../GameEngine/Source/Common/RTS/Player.cpp | 22 +++++++++++-------- .../Object/Update/BattlePlanUpdate.cpp | 10 +++++++++ .../GameLogic/Module/BattlePlanUpdate.h | 1 + .../GameEngine/Source/Common/RTS/Player.cpp | 22 +++++++++++-------- .../Object/Update/BattlePlanUpdate.cpp | 10 +++++++++ 6 files changed, 48 insertions(+), 18 deletions(-) diff --git a/Generals/Code/GameEngine/Include/GameLogic/Module/BattlePlanUpdate.h b/Generals/Code/GameEngine/Include/GameLogic/Module/BattlePlanUpdate.h index ae93f31951f..17fbd910298 100644 --- a/Generals/Code/GameEngine/Include/GameLogic/Module/BattlePlanUpdate.h +++ b/Generals/Code/GameEngine/Include/GameLogic/Module/BattlePlanUpdate.h @@ -162,6 +162,7 @@ class BattlePlanUpdate : public UpdateModule, public SpecialPowerUpdateInterface virtual void onObjectCreated() override; virtual void onDelete() override; virtual UpdateSleepTime update() override; + virtual void onCapture(Player* oldOwner, Player* newOwner) override; virtual CommandOption getCommandOption() const override; protected: diff --git a/Generals/Code/GameEngine/Source/Common/RTS/Player.cpp b/Generals/Code/GameEngine/Source/Common/RTS/Player.cpp index 25596036b7b..4ccddbd8ff6 100644 --- a/Generals/Code/GameEngine/Source/Common/RTS/Player.cpp +++ b/Generals/Code/GameEngine/Source/Common/RTS/Player.cpp @@ -2976,22 +2976,26 @@ void Player::changeBattlePlan( BattlePlanStatus plan, Int delta, BattlePlanBonus else if( removeBonus ) { //First, inverse the bonuses - bonus->m_armorScalar = 1.0f / __max( bonus->m_armorScalar, 0.01f ); - bonus->m_sightRangeScalar = 1.0f / __max( bonus->m_sightRangeScalar, 0.01f ); - if( bonus->m_bombardment > 0 ) + BattlePlanBonuses* invertedBonus = newInstance(BattlePlanBonuses); + *invertedBonus = *bonus; + + invertedBonus->m_armorScalar = 1.0f / __max( bonus->m_armorScalar, 0.01f ); + invertedBonus->m_sightRangeScalar = 1.0f / __max( bonus->m_sightRangeScalar, 0.01f ); + if( invertedBonus->m_bombardment > 0 ) { - bonus->m_bombardment = -1; + invertedBonus->m_bombardment = -1; } - if( bonus->m_holdTheLine > 0 ) + if( invertedBonus->m_holdTheLine > 0 ) { - bonus->m_holdTheLine = -1; + invertedBonus->m_holdTheLine = -1; } - if( bonus->m_searchAndDestroy > 0 ) + if( invertedBonus->m_searchAndDestroy > 0 ) { - bonus->m_searchAndDestroy = -1; + invertedBonus->m_searchAndDestroy = -1; } - applyBattlePlanBonusesForPlayerObjects( bonus ); + applyBattlePlanBonusesForPlayerObjects( invertedBonus ); + deleteInstance(invertedBonus); } } diff --git a/Generals/Code/GameEngine/Source/GameLogic/Object/Update/BattlePlanUpdate.cpp b/Generals/Code/GameEngine/Source/GameLogic/Object/Update/BattlePlanUpdate.cpp index 40b091ec4e3..64da934984c 100644 --- a/Generals/Code/GameEngine/Source/GameLogic/Object/Update/BattlePlanUpdate.cpp +++ b/Generals/Code/GameEngine/Source/GameLogic/Object/Update/BattlePlanUpdate.cpp @@ -247,6 +247,16 @@ void BattlePlanUpdate::onObjectCreated() enableTurret( false ); } +//------------------------------------------------------------------------------------------------- +void BattlePlanUpdate::onCapture(Player* oldOwner, Player* newOwner) +{ +#if !RETAIL_COMPATIBLE_CRC + // TheSuperHackers @bugfix Stubbjax 04/11/2025 Transfer battle plan bonuses on capture. + oldOwner->changeBattlePlan(m_planAffectingArmy, -1, m_bonuses); + newOwner->changeBattlePlan(m_planAffectingArmy, 1, m_bonuses); +#endif +} + //------------------------------------------------------------------------------------------------- Bool BattlePlanUpdate::initiateIntentToDoSpecialPower(const SpecialPowerTemplate *specialPowerTemplate, const Object *targetObj, const Coord3D *targetPos, const Waypoint *way, UnsignedInt commandOptions ) { diff --git a/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/BattlePlanUpdate.h b/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/BattlePlanUpdate.h index 2d16d1c481b..3e9e438a9be 100644 --- a/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/BattlePlanUpdate.h +++ b/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/BattlePlanUpdate.h @@ -162,6 +162,7 @@ class BattlePlanUpdate : public SpecialPowerUpdateModule virtual void onObjectCreated() override; virtual void onDelete() override; virtual UpdateSleepTime update() override; + virtual void onCapture(Player* oldOwner, Player* newOwner) override; virtual CommandOption getCommandOption() const override; protected: diff --git a/GeneralsMD/Code/GameEngine/Source/Common/RTS/Player.cpp b/GeneralsMD/Code/GameEngine/Source/Common/RTS/Player.cpp index 5c4009fd423..55a80414023 100644 --- a/GeneralsMD/Code/GameEngine/Source/Common/RTS/Player.cpp +++ b/GeneralsMD/Code/GameEngine/Source/Common/RTS/Player.cpp @@ -3469,22 +3469,26 @@ void Player::changeBattlePlan( BattlePlanStatus plan, Int delta, BattlePlanBonus else if( removeBonus ) { //First, inverse the bonuses - bonus->m_armorScalar = 1.0f / __max( bonus->m_armorScalar, 0.01f ); - bonus->m_sightRangeScalar = 1.0f / __max( bonus->m_sightRangeScalar, 0.01f ); - if( bonus->m_bombardment > 0 ) + BattlePlanBonuses* invertedBonus = newInstance(BattlePlanBonuses); + *invertedBonus = *bonus; + + invertedBonus->m_armorScalar = 1.0f / __max( bonus->m_armorScalar, 0.01f ); + invertedBonus->m_sightRangeScalar = 1.0f / __max( bonus->m_sightRangeScalar, 0.01f ); + if( invertedBonus->m_bombardment > 0 ) { - bonus->m_bombardment = -1; + invertedBonus->m_bombardment = -1; } - if( bonus->m_holdTheLine > 0 ) + if( invertedBonus->m_holdTheLine > 0 ) { - bonus->m_holdTheLine = -1; + invertedBonus->m_holdTheLine = -1; } - if( bonus->m_searchAndDestroy > 0 ) + if( invertedBonus->m_searchAndDestroy > 0 ) { - bonus->m_searchAndDestroy = -1; + invertedBonus->m_searchAndDestroy = -1; } - applyBattlePlanBonusesForPlayerObjects( bonus ); + applyBattlePlanBonusesForPlayerObjects( invertedBonus ); + deleteInstance(invertedBonus); } } diff --git a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/BattlePlanUpdate.cpp b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/BattlePlanUpdate.cpp index 8a23e0f9683..d4d0cead9dd 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/BattlePlanUpdate.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/BattlePlanUpdate.cpp @@ -247,6 +247,16 @@ void BattlePlanUpdate::onObjectCreated() enableTurret( false ); } +//------------------------------------------------------------------------------------------------- +void BattlePlanUpdate::onCapture(Player* oldOwner, Player* newOwner) +{ +#if !RETAIL_COMPATIBLE_CRC + // TheSuperHackers @bugfix Stubbjax 04/11/2025 Transfer battle plan bonuses on capture. + oldOwner->changeBattlePlan(m_planAffectingArmy, -1, m_bonuses); + newOwner->changeBattlePlan(m_planAffectingArmy, 1, m_bonuses); +#endif +} + //------------------------------------------------------------------------------------------------- Bool BattlePlanUpdate::initiateIntentToDoSpecialPower(const SpecialPowerTemplate *specialPowerTemplate, const Object *targetObj, const Coord3D *targetPos, const Waypoint *way, UnsignedInt commandOptions ) { From 85a414b8b27f0e0de5ad2f12ab8c4d5406a694f7 Mon Sep 17 00:00:00 2001 From: Stubbjax Date: Wed, 4 Mar 2026 12:40:20 +1100 Subject: [PATCH 2/4] refactor: Use new allocation method --- .../Code/GameEngine/Include/Common/Player.h | 2 +- .../GameEngine/Source/Common/RTS/Player.cpp | 24 +++++++++---------- .../Code/GameEngine/Include/Common/Player.h | 2 +- .../GameEngine/Source/Common/RTS/Player.cpp | 24 +++++++++---------- 4 files changed, 24 insertions(+), 28 deletions(-) diff --git a/Generals/Code/GameEngine/Include/Common/Player.h b/Generals/Code/GameEngine/Include/Common/Player.h index cf37308e704..07bf31aff09 100644 --- a/Generals/Code/GameEngine/Include/Common/Player.h +++ b/Generals/Code/GameEngine/Include/Common/Player.h @@ -345,7 +345,7 @@ class Player : public Snapshot //it's possible for multiple strategy centers to have the same plan, so we need //to keep track of that like radar. Keep in mind multiple strategy centers with //same plan do not stack, but different strategy centers with different plans do. - void changeBattlePlan( BattlePlanStatus plan, Int delta, BattlePlanBonusesData *bonus ); + void changeBattlePlan( BattlePlanStatus plan, Int delta, const BattlePlanBonusesData *bonus ); Int getNumBattlePlansActive() const { return m_bombardBattlePlans + m_holdTheLineBattlePlans + m_searchAndDestroyBattlePlans; } Int getBattlePlansActiveSpecific( BattlePlanStatus plan ) const; void applyBattlePlanBonusesForObject( Object *obj ) const; //New object or converted object gaining our current battle plan bonuses. diff --git a/Generals/Code/GameEngine/Source/Common/RTS/Player.cpp b/Generals/Code/GameEngine/Source/Common/RTS/Player.cpp index 4ccddbd8ff6..83428953b45 100644 --- a/Generals/Code/GameEngine/Source/Common/RTS/Player.cpp +++ b/Generals/Code/GameEngine/Source/Common/RTS/Player.cpp @@ -2922,7 +2922,7 @@ Bool Player::doesObjectQualifyForBattlePlan( Object *obj ) const //------------------------------------------------------------------------------------------------- // note, bonus is an in-out parm. -void Player::changeBattlePlan( BattlePlanStatus plan, Int delta, BattlePlanBonusesData *bonus ) +void Player::changeBattlePlan( BattlePlanStatus plan, Int delta, const BattlePlanBonusesData *bonus ) { DUMPBATTLEPLANBONUSES(bonus, this, nullptr); Bool addBonus = false; @@ -2976,26 +2976,24 @@ void Player::changeBattlePlan( BattlePlanStatus plan, Int delta, BattlePlanBonus else if( removeBonus ) { //First, inverse the bonuses - BattlePlanBonuses* invertedBonus = newInstance(BattlePlanBonuses); - *invertedBonus = *bonus; + BattlePlanBonusesData invertedBonus = *bonus; - invertedBonus->m_armorScalar = 1.0f / __max( bonus->m_armorScalar, 0.01f ); - invertedBonus->m_sightRangeScalar = 1.0f / __max( bonus->m_sightRangeScalar, 0.01f ); - if( invertedBonus->m_bombardment > 0 ) + invertedBonus.m_armorScalar = 1.0f / __max( bonus->m_armorScalar, 0.01f ); + invertedBonus.m_sightRangeScalar = 1.0f / __max( bonus->m_sightRangeScalar, 0.01f ); + if( invertedBonus.m_bombardment > 0 ) { - invertedBonus->m_bombardment = -1; + invertedBonus.m_bombardment = -1; } - if( invertedBonus->m_holdTheLine > 0 ) + if( invertedBonus.m_holdTheLine > 0 ) { - invertedBonus->m_holdTheLine = -1; + invertedBonus.m_holdTheLine = -1; } - if( invertedBonus->m_searchAndDestroy > 0 ) + if( invertedBonus.m_searchAndDestroy > 0 ) { - invertedBonus->m_searchAndDestroy = -1; + invertedBonus.m_searchAndDestroy = -1; } - applyBattlePlanBonusesForPlayerObjects( invertedBonus ); - deleteInstance(invertedBonus); + applyBattlePlanBonusesForPlayerObjects( &invertedBonus ); } } diff --git a/GeneralsMD/Code/GameEngine/Include/Common/Player.h b/GeneralsMD/Code/GameEngine/Include/Common/Player.h index 582f97d2db6..e30dcf59535 100644 --- a/GeneralsMD/Code/GameEngine/Include/Common/Player.h +++ b/GeneralsMD/Code/GameEngine/Include/Common/Player.h @@ -369,7 +369,7 @@ class Player : public Snapshot //it's possible for multiple strategy centers to have the same plan, so we need //to keep track of that like radar. Keep in mind multiple strategy centers with //same plan do not stack, but different strategy centers with different plans do. - void changeBattlePlan( BattlePlanStatus plan, Int delta, BattlePlanBonusesData *bonus ); + void changeBattlePlan( BattlePlanStatus plan, Int delta, const BattlePlanBonusesData *bonus ); Int getNumBattlePlansActive() const { return m_bombardBattlePlans + m_holdTheLineBattlePlans + m_searchAndDestroyBattlePlans; } Int getBattlePlansActiveSpecific( BattlePlanStatus plan ) const; void applyBattlePlanBonusesForObject( Object *obj ) const; //New object or converted object gaining our current battle plan bonuses. diff --git a/GeneralsMD/Code/GameEngine/Source/Common/RTS/Player.cpp b/GeneralsMD/Code/GameEngine/Source/Common/RTS/Player.cpp index 55a80414023..c1e107f509c 100644 --- a/GeneralsMD/Code/GameEngine/Source/Common/RTS/Player.cpp +++ b/GeneralsMD/Code/GameEngine/Source/Common/RTS/Player.cpp @@ -3415,7 +3415,7 @@ Bool Player::doesObjectQualifyForBattlePlan( Object *obj ) const //------------------------------------------------------------------------------------------------- // note, bonus is an in-out parm. -void Player::changeBattlePlan( BattlePlanStatus plan, Int delta, BattlePlanBonusesData *bonus ) +void Player::changeBattlePlan( BattlePlanStatus plan, Int delta, const BattlePlanBonusesData *bonus ) { DUMPBATTLEPLANBONUSES(bonus, this, nullptr); Bool addBonus = false; @@ -3469,26 +3469,24 @@ void Player::changeBattlePlan( BattlePlanStatus plan, Int delta, BattlePlanBonus else if( removeBonus ) { //First, inverse the bonuses - BattlePlanBonuses* invertedBonus = newInstance(BattlePlanBonuses); - *invertedBonus = *bonus; + BattlePlanBonusesData invertedBonus = *bonus; - invertedBonus->m_armorScalar = 1.0f / __max( bonus->m_armorScalar, 0.01f ); - invertedBonus->m_sightRangeScalar = 1.0f / __max( bonus->m_sightRangeScalar, 0.01f ); - if( invertedBonus->m_bombardment > 0 ) + invertedBonus.m_armorScalar = 1.0f / __max( bonus->m_armorScalar, 0.01f ); + invertedBonus.m_sightRangeScalar = 1.0f / __max( bonus->m_sightRangeScalar, 0.01f ); + if( invertedBonus.m_bombardment > 0 ) { - invertedBonus->m_bombardment = -1; + invertedBonus.m_bombardment = -1; } - if( invertedBonus->m_holdTheLine > 0 ) + if( invertedBonus.m_holdTheLine > 0 ) { - invertedBonus->m_holdTheLine = -1; + invertedBonus.m_holdTheLine = -1; } - if( invertedBonus->m_searchAndDestroy > 0 ) + if( invertedBonus.m_searchAndDestroy > 0 ) { - invertedBonus->m_searchAndDestroy = -1; + invertedBonus.m_searchAndDestroy = -1; } - applyBattlePlanBonusesForPlayerObjects( invertedBonus ); - deleteInstance(invertedBonus); + applyBattlePlanBonusesForPlayerObjects( &invertedBonus ); } } From 72575e2d8cae8217444387676fc11cfbbbf4be9b Mon Sep 17 00:00:00 2001 From: Stubbjax Date: Thu, 5 Mar 2026 10:53:14 +1100 Subject: [PATCH 3/4] docs: Remove obsolete comments --- Generals/Code/GameEngine/Source/Common/RTS/Player.cpp | 1 - GeneralsMD/Code/GameEngine/Source/Common/RTS/Player.cpp | 1 - 2 files changed, 2 deletions(-) diff --git a/Generals/Code/GameEngine/Source/Common/RTS/Player.cpp b/Generals/Code/GameEngine/Source/Common/RTS/Player.cpp index 83428953b45..10233d18a21 100644 --- a/Generals/Code/GameEngine/Source/Common/RTS/Player.cpp +++ b/Generals/Code/GameEngine/Source/Common/RTS/Player.cpp @@ -2921,7 +2921,6 @@ Bool Player::doesObjectQualifyForBattlePlan( Object *obj ) const } //------------------------------------------------------------------------------------------------- -// note, bonus is an in-out parm. void Player::changeBattlePlan( BattlePlanStatus plan, Int delta, const BattlePlanBonusesData *bonus ) { DUMPBATTLEPLANBONUSES(bonus, this, nullptr); diff --git a/GeneralsMD/Code/GameEngine/Source/Common/RTS/Player.cpp b/GeneralsMD/Code/GameEngine/Source/Common/RTS/Player.cpp index c1e107f509c..062871fbddc 100644 --- a/GeneralsMD/Code/GameEngine/Source/Common/RTS/Player.cpp +++ b/GeneralsMD/Code/GameEngine/Source/Common/RTS/Player.cpp @@ -3414,7 +3414,6 @@ Bool Player::doesObjectQualifyForBattlePlan( Object *obj ) const } //------------------------------------------------------------------------------------------------- -// note, bonus is an in-out parm. void Player::changeBattlePlan( BattlePlanStatus plan, Int delta, const BattlePlanBonusesData *bonus ) { DUMPBATTLEPLANBONUSES(bonus, this, nullptr); From 2f6c72a6adff47c565237f17b92c556148e70d19 Mon Sep 17 00:00:00 2001 From: Stubbjax Date: Wed, 18 Mar 2026 19:25:27 +1100 Subject: [PATCH 4/4] fix: Formatting --- .../GameEngine/Source/Common/RTS/Player.cpp | 18 +++++++++--------- .../GameEngine/Source/Common/RTS/Player.cpp | 18 +++++++++--------- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/Generals/Code/GameEngine/Source/Common/RTS/Player.cpp b/Generals/Code/GameEngine/Source/Common/RTS/Player.cpp index 10233d18a21..6240cca19da 100644 --- a/Generals/Code/GameEngine/Source/Common/RTS/Player.cpp +++ b/Generals/Code/GameEngine/Source/Common/RTS/Player.cpp @@ -2977,22 +2977,22 @@ void Player::changeBattlePlan( BattlePlanStatus plan, Int delta, const BattlePla //First, inverse the bonuses BattlePlanBonusesData invertedBonus = *bonus; - invertedBonus.m_armorScalar = 1.0f / __max( bonus->m_armorScalar, 0.01f ); - invertedBonus.m_sightRangeScalar = 1.0f / __max( bonus->m_sightRangeScalar, 0.01f ); - if( invertedBonus.m_bombardment > 0 ) + invertedBonus.m_armorScalar = 1.0f / __max(bonus->m_armorScalar, 0.01f); + invertedBonus.m_sightRangeScalar = 1.0f / __max(bonus->m_sightRangeScalar, 0.01f); + if (invertedBonus.m_bombardment > 0) { - invertedBonus.m_bombardment = -1; + invertedBonus.m_bombardment = -1; } - if( invertedBonus.m_holdTheLine > 0 ) + if (invertedBonus.m_holdTheLine > 0) { - invertedBonus.m_holdTheLine = -1; + invertedBonus.m_holdTheLine = -1; } - if( invertedBonus.m_searchAndDestroy > 0 ) + if (invertedBonus.m_searchAndDestroy > 0) { - invertedBonus.m_searchAndDestroy = -1; + invertedBonus.m_searchAndDestroy = -1; } - applyBattlePlanBonusesForPlayerObjects( &invertedBonus ); + applyBattlePlanBonusesForPlayerObjects(&invertedBonus); } } diff --git a/GeneralsMD/Code/GameEngine/Source/Common/RTS/Player.cpp b/GeneralsMD/Code/GameEngine/Source/Common/RTS/Player.cpp index 062871fbddc..2a5171bbcf2 100644 --- a/GeneralsMD/Code/GameEngine/Source/Common/RTS/Player.cpp +++ b/GeneralsMD/Code/GameEngine/Source/Common/RTS/Player.cpp @@ -3470,22 +3470,22 @@ void Player::changeBattlePlan( BattlePlanStatus plan, Int delta, const BattlePla //First, inverse the bonuses BattlePlanBonusesData invertedBonus = *bonus; - invertedBonus.m_armorScalar = 1.0f / __max( bonus->m_armorScalar, 0.01f ); - invertedBonus.m_sightRangeScalar = 1.0f / __max( bonus->m_sightRangeScalar, 0.01f ); - if( invertedBonus.m_bombardment > 0 ) + invertedBonus.m_armorScalar = 1.0f / __max(bonus->m_armorScalar, 0.01f); + invertedBonus.m_sightRangeScalar = 1.0f / __max(bonus->m_sightRangeScalar, 0.01f); + if (invertedBonus.m_bombardment > 0) { - invertedBonus.m_bombardment = -1; + invertedBonus.m_bombardment = -1; } - if( invertedBonus.m_holdTheLine > 0 ) + if (invertedBonus.m_holdTheLine > 0) { - invertedBonus.m_holdTheLine = -1; + invertedBonus.m_holdTheLine = -1; } - if( invertedBonus.m_searchAndDestroy > 0 ) + if (invertedBonus.m_searchAndDestroy > 0) { - invertedBonus.m_searchAndDestroy = -1; + invertedBonus.m_searchAndDestroy = -1; } - applyBattlePlanBonusesForPlayerObjects( &invertedBonus ); + applyBattlePlanBonusesForPlayerObjects(&invertedBonus); } }