Skip to content

bugfix(specialpower): Charge uninitialized special powers on new buildings#2781

Open
bobtista wants to merge 1 commit into
TheSuperHackers:mainfrom
bobtista:bobtista/bugfix/specialpower-build-ready
Open

bugfix(specialpower): Charge uninitialized special powers on new buildings#2781
bobtista wants to merge 1 commit into
TheSuperHackers:mainfrom
bobtista:bobtista/bugfix/specialpower-build-ready

Conversation

@bobtista

Copy link
Copy Markdown

With RETAIL_COMPATIBLE_CRC=0, special-power buttons on freshly built buildings that lack a SpecialPowerCreate module (Strategy Center battle plans, Intelligence) are permanently disabled. Addresses #2780

Cause

PR #1218 initialized SpecialPowerModule::m_availableOnFrame to 0xFFFFFFFF under !RETAIL_COMPATIBLE_CRC. The constructor only calls startPowerRecharge() when the object is not UNDER_CONSTRUCTION; for built structures the recharge is otherwise driven by SpecialPowerCreate::onBuildComplete(). Buildings without that module never leave the sentinel value, so isReady() never returns true.

Fix

In Player::onStructureConstructionComplete(), after a structure finishes building, charge any special-power module still at the 0xFFFFFFFF sentinel to ready-now (setReadyFrame(TheGameLogic->getFrame())). This restores retail's immediate availability for these powers. Guarded with #if !RETAIL_COMPATIBLE_CRC, so retail CRC/replay compatibility is unchanged.

Testing

  • [x]Fresh game: build a Strategy Center → battle-plan buttons are enabled and clickable; build a Detention Camp → CIA Intelligence is usable. DebugLogFile.txt logs the charged power.

Todo

[] Replicate to Generals

@greptile-apps

greptile-apps Bot commented Jun 10, 2026

Copy link
Copy Markdown

Greptile Summary

This PR fixes an issue where special-power buttons on freshly constructed buildings (e.g. Strategy Center battle plans, Detention Camp CIA Intelligence) remain permanently disabled under !RETAIL_COMPATIBLE_CRC. The root cause is that SpecialPowerModule::m_availableOnFrame is initialized to 0xFFFFFFFF in non-retail mode, and buildings without a SpecialPowerCreate module have no mechanism to exit that sentinel state.

  • Adds a post-construction loop in Player::onStructureConstructionComplete() that detects the 0xFFFFFFFF sentinel on any SpecialPowerModuleInterface and sets it to the current frame (ready immediately), guarded by #if !RETAIL_COMPATIBLE_CRC.
  • For buildings that do have SpecialPowerCreate, their onBuildComplete() runs after this function and calls startPowerRecharge(), which overwrites the sentinel-cleared value with the proper countdown — so those buildings are unaffected.

Confidence Score: 4/5

Safe to merge; the fix is narrowly scoped to buildings that lack a SpecialPowerCreate module, and for those that have one, the subsequent onBuildComplete() call correctly overwrites the sentinel-cleared value.

The change is a single-function, one-file addition that targets a well-understood sentinel value. The call-order relationship between onStructureConstructionComplete and SpecialPowerCreate::onBuildComplete is what makes buildings with a SpecialPowerCreate module unaffected — that relationship holds in all construction paths (Dozer, BuildAssistant, ReplaceObjectUpgrade). The only open item is replicating the fix to the Generals (non-MD) directory, noted in the PR's own todo list.

No files require special attention beyond Player.cpp, which contains the entire change.

Important Files Changed

Filename Overview
GeneralsMD/Code/GameEngine/Source/Common/RTS/Player.cpp Adds a sentinel-check loop in onStructureConstructionComplete() to make uninitialized special powers ready on build completion; logic is correct, but uses a bare 0xFFFFFFFF literal that is already repeated across the special-power subsystem without a named constant.

Sequence Diagram

sequenceDiagram
    participant Dozer as DozerAIUpdate
    participant Player as Player
    participant SPMod as SpecialPowerModule
    participant SPCreate as SpecialPowerCreate

    Note over SPMod: Constructor (UNDER_CONSTRUCTION)<br/>m_availableOnFrame = 0xFFFFFFFF<br/>startPowerRecharge() NOT called

    Dozer->>Player: onStructureConstructionComplete()
    activate Player
    Note over Player: #if !RETAIL_COMPATIBLE_CRC
    Player->>SPMod: getReadyFrame()
    SPMod-->>Player: 0xFFFFFFFF (sentinel)
    Player->>SPMod: setReadyFrame(currentFrame)
    Note over SPMod: m_availableOnFrame = currentFrame<br/>isReady() → true
    Player-->>Dozer: 
    deactivate Player

    alt Building HAS SpecialPowerCreate
        Dozer->>SPCreate: onBuildComplete()
        activate SPCreate
        SPCreate->>SPMod: onSpecialPowerCreation() → startPowerRecharge()
        Note over SPMod: m_availableOnFrame = currentFrame + reloadTime<br/>(overwrites fix — correct countdown)
        SPCreate-->>Dozer: 
        deactivate SPCreate
    else Building has NO SpecialPowerCreate
        Note over SPMod: m_availableOnFrame = currentFrame remains<br/>isReady() → true immediately
    end
Loading
Prompt To Fix All With AI
Fix the following 1 code review issue. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 1
GeneralsMD/Code/GameEngine/Source/Common/RTS/Player.cpp:1667
The sentinel value `0xFFFFFFFF` is repeated here as a bare literal — it already appears verbatim in `SpecialPowerModule.cpp` (constructor, `initiateIntentToDoSpecialPower`, `getReadyFrame`). Introducing a named constant shared between those sites (e.g. `SPECIAL_POWER_UNINITIALIZED_FRAME`) would make the intent explicit and ensure any future change to the sentinel propagates everywhere automatically.

```suggestion
		if( specialPower->getReadyFrame() == SPECIAL_POWER_UNINITIALIZED_FRAME )
```

Reviews (1): Last reviewed commit: "bugfix(specialpower): Charge uninitializ..." | Re-trigger Greptile

@xezon

xezon commented Jun 10, 2026

Copy link
Copy Markdown

I think this is now the third open pull for this issue.

@xezon

xezon commented Jun 10, 2026

Copy link
Copy Markdown

@bobtista

Copy link
Copy Markdown
Author

I think this is now the third open pull for this issue.

Let's merge one and close the others + issue

@xezon

xezon commented Jun 10, 2026

Copy link
Copy Markdown

Which fix is the best?

@bobtista

Copy link
Copy Markdown
Author

Which fix is the best?

1461 seems to actually fix the issue, the other two just let the building finish, then force the still-uninitialized power to ready-now. I'd test it, replicate to Generals and merge it

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants