You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This change fixes an issue where multiple Strategy Center battle plans are not correctly applied. The issue is that only the most recent plan is applied, as only the new plan data is passed to the battle plan application logic.
For example, in retail, if the player has Search and Destroy on one Strategy Center, and then selects Bombardment on another, the data that gets applied to all units becomes:
Search and Destroy: 0 (this undoes the range bonus)
Bombardment: 1 (new bonus is applied)
Hold the Line: 0
After this change, the logic correctly accounts for existing plans, and so the data becomes this:
Search and Destroy: 1 (range bonus remains intact)
Bombardment: 1 (new bonus is applied)
Hold the Line: 0
In the Player::applyBattlePlanBonusesForPlayerObjects method, the bonus is essentially the delta, while m_battlePlanBonuses is the combined bonus. The problem was that the bonus was being applied to units instead of m_battlePlanBonuses. However, the armour scalar is still expected as a delta when being applied to units, so a temporary newBonus is now used to merge the armour scalar delta with the combined bonus.
Stubbjax
added
Buff
Makes a thing more powerful
Bug
Something is not working right, typically is user facing
Minor
Severity: Minor < Major < Critical < Blocker
USA
Affects USA faction
Gen
Relates to Generals
ZH
Relates to Zero Hour
NoRetail
This fix or change is not applicable with Retail game compatibility
labels
Feb 4, 2026
Fixed a critical bug where multiple Strategy Center battle plans would not stack correctly - only the most recently activated plan would remain active while previous plans were incorrectly cleared.
The issue occurred in Player::applyBattlePlanBonusesForPlayerObjects where the function correctly accumulated all bonuses in m_battlePlanBonuses but then applied only the delta bonus parameter to existing units. Since the delta contains zeroes for non-active bonuses in the specific activation, this caused weapon bonus flags (searchAndDestroy, bombardment, holdTheLine) to be incorrectly cleared on units when a second plan was activated.
The fix creates a temporary newBonus object that combines the accumulated bonuses from m_battlePlanBonuses with the delta armor scalar from bonus. This ensures:
Weapon bonus flags remain set for all active plans (using accumulated values)
Sight range scalar uses the accumulated total (for absolute recalculation)
Armor scalar uses the delta (for multiplicative application via applyDamageScalar)
The change is properly guarded by RETAIL_COMPATIBLE_CRC to maintain compatibility with the original game behavior.
Confidence Score: 5/5
This PR is safe to merge - it fixes a well-understood bug with a clean, minimal solution
The fix correctly addresses the root cause by applying accumulated bonuses instead of deltas for flags/absolute values while preserving delta application for multiplicative values. The logic is sound, the change is minimal and well-isolated behind a feature flag, and applies identically to both game versions.
Fixed battle plan bonus application to use accumulated bonuses instead of just deltas, preserving all active plans
Sequence Diagram
sequenceDiagram
participant SC1 as Strategy Center 1
participant SC2 as Strategy Center 2
participant Player as Player
participant Units as Player Units
Note over SC1,Units: First Battle Plan Activation
SC1->>Player: Activate Search & Destroy<br/>(bonus delta)
Player->>Player: m_battlePlanBonuses = bonus<br/>searchAndDestroy=1, bombardment=0
Player->>Units: Apply bonuses to all units<br/>(searchAndDestroy flag set)
Note over SC1,Units: Second Battle Plan Activation (Bug Scenario)
SC2->>Player: Activate Bombardment<br/>(bonus delta: bombardment=1, searchAndDestroy=0)
Player->>Player: m_battlePlanBonuses updated<br/>searchAndDestroy=1, bombardment=1
alt OLD CODE (Bug)
Player->>Units: iterateObjects(bonus)<br/>(searchAndDestroy=0, bombardment=1)
Note over Units: BUG: searchAndDestroy flag cleared!<br/>Only bombardment remains active
else NEW CODE (Fixed)
Player->>Player: newBonus = m_battlePlanBonuses<br/>newBonus.armorScalar = bonus.armorScalar
Player->>Units: iterateObjects(newBonus)<br/>(searchAndDestroy=1, bombardment=1)
Note over Units: FIXED: Both plans remain active
end
Loading
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
BuffMakes a thing more powerfulBugSomething is not working right, typically is user facingGenRelates to GeneralsMinorSeverity: Minor < Major < Critical < BlockerNoRetailThis fix or change is not applicable with Retail game compatibilityUSAAffects USA factionZHRelates to Zero Hour
1 participant
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #46
Closes #2209
This change fixes an issue where multiple Strategy Center battle plans are not correctly applied. The issue is that only the most recent plan is applied, as only the new plan data is passed to the battle plan application logic.
For example, in retail, if the player has Search and Destroy on one Strategy Center, and then selects Bombardment on another, the data that gets applied to all units becomes:
After this change, the logic correctly accounts for existing plans, and so the data becomes this:
In the
Player::applyBattlePlanBonusesForPlayerObjectsmethod, thebonusis essentially the delta, whilem_battlePlanBonusesis the combined bonus. The problem was that thebonuswas being applied to units instead ofm_battlePlanBonuses. However, the armour scalar is still expected as a delta when being applied to units, so a temporarynewBonusis now used to merge the armour scalar delta with the combined bonus.