unify(commandxlat): Move AcademyStats files to Core and merge CommandXlat and related code from Zero Hour#2765
unify(commandxlat): Move AcademyStats files to Core and merge CommandXlat and related code from Zero Hour#2765xezon wants to merge 2 commits into
Conversation
|
| Filename | Overview |
|---|---|
| Generals/Code/GameEngine/Source/GameClient/MessageStream/CommandXlat.cpp | Large port from Zero Hour adding Firebase attack logic, Sneak Attack commands, cliff locomotor cursor, cheat/demo messages, and double-click attack move; contains a switch-case mismatch in the CONSTRUCT special power handler that makes it dead code, plus a missing DESTROY_MESSAGE in MSG_CHEAT_ADD_CASH. |
| Generals/Code/GameEngine/Include/GameLogic/Module/ContainModule.h | Adds pure-virtual getClosestRider to ContainModuleInterface; all concrete subclasses go through OpenContain which provides the implementation, so the hierarchy is complete. |
| Core/GameEngine/Include/Common/AcademyStats.h | Moved from GeneralsMD to Core unchanged; uses #pragma once correctly; copyright header still references Generals Zero Hour(tm) but the Core directory has no specific convention rule. |
| Generals/Code/GameEngine/Source/GameLogic/Object/Contain/OpenContain.cpp | Adds getClosestRider implementation iterating the contain list by squared distance; straightforward logic with safe uninitialized-distance handling via the !closest short-circuit. |
| Generals/Code/GameEngine/Source/GameClient/InGameUI.cpp | Adds double-click attack-move feedback via a frame-countdown timer and a stashed guard-hint position; timer decrements below zero on subsequent frames but the > 0 guard prevents visible effects. |
| Generals/Code/GameEngine/Include/Common/KindOf.h | Adds ~25 KindOf flags from Zero Hour and wraps KINDOF_AIRFIELD in #if RTS_GENERALS to keep enum values aligned between Generals and ZH builds. |
| Core/GameEngine/Source/GameLogic/AI/AIPathfind.cpp | Removes #if RTS_GENERALS guard since both builds now share KINDOF_FS_AIRFIELD; correct since Generals KindOf.h also gains KINDOF_FS_AIRFIELD in this PR. |
| GeneralsMD/Code/GameEngine/Source/GameClient/MessageStream/CommandXlat.cpp | Minor cleanup: removes duplicate comment banners, adds null-check for workerShoeTemplate, and adds #if guard around INVALID_ANGLE append for retail-compatible networking. |
Sequence Diagram
sequenceDiagram
participant Player
participant CommandTranslator
participant InGameUI
participant ContainModule
participant MessageStream
Note over Player,MessageStream: Double-click attack-move (new feature)
Player->>CommandTranslator: MSG_MOUSE_LEFT/RIGHT_DOUBLE_CLICK
CommandTranslator->>MessageStream: MSG_DO_GUARD_POSITION
CommandTranslator->>InGameUI: triggerDoubleClickAttackMoveGuardHint()
InGameUI->>InGameUI: "m_duringDoubleClickAttackMoveGuardHintTimer = 11"
Note over Player,MessageStream: Firebase garrison attack (new routing)
Player->>CommandTranslator: canObjectForceAttack(firebase, victim)
alt "SPAWNS_ARE_THE_WEAPONS AND result==POSSIBLE"
CommandTranslator->>ContainModule: "getClosestRider(victim->pos)"
ContainModule-->>CommandTranslator: rider
CommandTranslator->>CommandTranslator: rider.getAbleToAttackSpecificObject()
else "SPAWNS_ARE_THE_WEAPONS AND result!=POSSIBLE"
CommandTranslator->>CommandTranslator: spawnInterface.getClosestSlave(pos)
end
Note over Player,MessageStream: Shortcut special power auto-select (new feature)
Player->>CommandTranslator: GUI_COMMAND_SPECIAL_POWER_FROM_SHORTCUT
CommandTranslator->>CommandTranslator: findMostReadyShortcutSpecialPowerOfType()
CommandTranslator->>InGameUI: deselectAllDrawables()
CommandTranslator->>MessageStream: MSG_CREATE_SELECTED_GROUP_NO_SOUND(unit)
Prompt To Fix All With AI
Fix the following 3 code review issues. Work through them one at a time, proposing concise fixes.
---
### Issue 1 of 3
Generals/Code/GameEngine/Source/GameClient/MessageStream/CommandXlat.cpp:1797-1809
**Unreachable switch cases in CONSTRUCT handler**
The outer `else if` only enters this block when `commandType` is `GUI_COMMAND_SPECIAL_POWER_CONSTRUCT` or `GUI_COMMAND_SPECIAL_POWER_CONSTRUCT_FROM_SHORTCUT`, but the inner `switch` tests the same value against `GUI_COMMAND_SPECIAL_POWER_FROM_SHORTCUT` and `GUI_COMMAND_SPECIAL_POWER` — entirely different enum values. No case will ever match, so `issueSpecialPowerCommand` is never called and the command silently does nothing. The case labels should be `GUI_COMMAND_SPECIAL_POWER_CONSTRUCT_FROM_SHORTCUT` and `GUI_COMMAND_SPECIAL_POWER_CONSTRUCT` respectively. Note: the identical pattern exists in `GeneralsMD/Code/GameEngine/Source/GameClient/MessageStream/CommandXlat.cpp` (line 1799), so the same bug is present in the Zero Hour build as well.
### Issue 2 of 3
Generals/Code/GameEngine/Source/GameClient/MessageStream/CommandXlat.cpp:3883-3886
Newly added comment references July 2003, which is prior to the current year (2026). Per project convention, newly added code comments should not reference dates in the past.
```suggestion
// Added this code to deselect build placement mode when right clicked. This fixes
// a bug where you couldn't cancel the sneak attack mode via right click. This only happened when you
// didn't have anything selected which is possible via the shortcut bar. Normally, it would get deselected
// via the deselect drawable code.
```
### Issue 3 of 3
Generals/Code/GameEngine/Source/GameClient/MessageStream/CommandXlat.cpp:3607-3617
`MSG_CHEAT_ADD_CASH` is the only cheat case in this block that does not set `disp = DESTROY_MESSAGE` after acting. Without it the message continues propagating through the pipeline when not in multiplayer; all neighboring cases (`MSG_CHEAT_INSTANT_BUILD`, `MSG_CHEAT_GIVE_ALL_SCIENCES`, etc.) consistently destroy the message.
```suggestion
case GameMessage::MSG_CHEAT_ADD_CASH:
{
if ( !TheGameLogic->isInMultiplayerGame() )
{
Player *localPlayer = ThePlayerList->getLocalPlayer();
Money *money = localPlayer->getMoney();
money->deposit( 10000 );
TheInGameUI->messageNoFormat( TheGameText->FETCH_OR_SUBSTITUTE("GUI:DebugAddCash", L"Add Cash") );
disp = DESTROY_MESSAGE;
}
break;
}
```
Reviews (1): Last reviewed commit: "unify(commandxlat): Merge CommandXlat an..." | Re-trigger Greptile
Merge with Rebase
This change has 2 commits.
Behavior should be unchanged in both games.
Generals gets
AcademyStatsclassKindOfflags from Zero Hour (Drone selection and Airfields required a migration strategy)TODO