Skip to content

Commit 292ac6d

Browse files
Apply requested changes.
1 parent 2f4446f commit 292ac6d

2 files changed

Lines changed: 46 additions & 3 deletions

File tree

GeneralsMD/Code/GameEngine/Source/GameLogic/AI/AIGuard.cpp

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -179,8 +179,30 @@ AIGuardMachine::AIGuardMachine( Object *owner ) :
179179
//Kris: Except that guard return is more like an attack move, and will acquire targets while moving there.
180180
//This breaks deployAI units because they have to completely unpack before realizing that there is a target in range.
181181
//So I'm making AI_GUARD_INNER the first state.
182-
defineState( AI_GUARD_INNER, newInstance(AIGuardInnerState)( this ), AI_GUARD_OUTER, AI_GUARD_OUTER );
183-
defineState( AI_GUARD_RETURN, newInstance(AIGuardReturnState)( this ), AI_GUARD_IDLE, AI_GUARD_INNER );
182+
#if RETAIL_COMPATIBLE_CRC
183+
defineState(AI_GUARD_INNER, newInstance(AIGuardInnerState)(this), AI_GUARD_OUTER, AI_GUARD_OUTER, attackAggressors);
184+
defineState(AI_GUARD_RETURN, newInstance(AIGuardReturnState)(this), AI_GUARD_IDLE, AI_GUARD_INNER, attackAggressors);
185+
#else
186+
// TheSuperHackers @bugfix 9/4/2026:
187+
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
188+
// This fixes the conflicting movement and fire behavior in Guard mode when the unit is under attack
189+
// (see https://github.com/TheSuperHackers/GeneralsGameCode/issues/2097).
190+
//
191+
// Root cause: In retail, both AI_GUARD_INNER and AI_GUARD_RETURN had the attackAggressors
192+
// handler attached.
193+
// While the INNER state was issuing attack orders or RETURN state was
194+
// issuing movement orders back to the guard position,
195+
// the aggressor handler kept firing attack commands on every shot.
196+
// This resulted in confliction in orders, causing the unit to do unexpected behavior.
197+
//
198+
// Fix: Remove the attackAggressors handler from AI_GUARD_INNER and AI_GUARD_RETURN.
199+
// The inner guard engagement logic is still handled within the AI_GUARD_INNER state,
200+
// and once the unit decides to return (RETURN state), it performs a clean movement without
201+
// competing attack orders (unless something enters its Inner guard range).
202+
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
203+
defineState(AI_GUARD_INNER, newInstance(AIGuardInnerState)(this), AI_GUARD_OUTER, AI_GUARD_OUTER);
204+
defineState(AI_GUARD_RETURN, newInstance(AIGuardReturnState)(this), AI_GUARD_IDLE, AI_GUARD_INNER);
205+
#endif
184206
defineState( AI_GUARD_IDLE, newInstance(AIGuardIdleState)( this ), AI_GUARD_INNER, AI_GUARD_RETURN, attackAggressors );
185207
defineState( AI_GUARD_OUTER, newInstance(AIGuardOuterState)( this ), AI_GUARD_GET_CRATE, AI_GUARD_GET_CRATE );
186208
defineState( AI_GUARD_GET_CRATE, newInstance(AIGuardPickUpCrateState)( this ), AI_GUARD_RETURN, AI_GUARD_RETURN );

GeneralsMD/Code/GameEngine/Source/GameLogic/AI/AIGuardRetaliate.cpp

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,28 @@ AIGuardRetaliateMachine::AIGuardRetaliateMachine( Object *owner ) :
184184
// srj sez: I made "return" the start state, so that if ordered to guard a position
185185
// that isn't the unit's current position, it moves to that position first.
186186
defineState( AI_GUARD_RETALIATE_ATTACK_AGGRESSOR, newInstance(AIGuardRetaliateAttackAggressorState)( this ), AI_GUARD_RETALIATE_RETURN, AI_GUARD_RETALIATE_RETURN );
187-
defineState( AI_GUARD_RETALIATE_RETURN, newInstance(AIGuardRetaliateReturnState)( this ), AI_GUARD_RETALIATE_IDLE, AI_GUARD_RETALIATE_INNER );
187+
#if RETAIL_COMPATIBLE_CRC
188+
defineState(AI_GUARD_RETALIATE_RETURN, newInstance(AIGuardRetaliateReturnState)(this), AI_GUARD_RETALIATE_IDLE, AI_GUARD_RETALIATE_INNER, attackAggressors);
189+
#else
190+
// TheSuperHackers @bugfix 9/4/2026:
191+
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
192+
// This fixes the conflicting movement and fire behavior in Guard mode when the unit is under attack
193+
// (see https://github.com/TheSuperHackers/GeneralsGameCode/issues/2097).
194+
//
195+
// Root cause: In retail, both AI_GUARD_INNER and AI_GUARD_RETURN had the attackAggressors
196+
// handler attached.
197+
// While the INNER state was issuing attack orders or RETURN state was
198+
// issuing movement orders back to the guard position,
199+
// the aggressor handler kept firing attack commands on every shot.
200+
// This resulted in confliction in orders, causing the unit to do unexpected behavior.
201+
//
202+
// Fix: Remove the attackAggressors handler from AI_GUARD_INNER and AI_GUARD_RETURN.
203+
// The inner guard engagement logic is still handled within the AI_GUARD_INNER state,
204+
// and once the unit decides to return (RETURN state), it performs a clean movement without
205+
// competing attack orders (unless something enters its Inner guard range).
206+
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
207+
defineState(AI_GUARD_RETALIATE_RETURN, newInstance(AIGuardRetaliateReturnState)(this), AI_GUARD_RETALIATE_IDLE, AI_GUARD_RETALIATE_INNER);
208+
#endif
188209
defineState( AI_GUARD_RETALIATE_IDLE, newInstance(AIGuardRetaliateIdleState)( this ), AI_GUARD_RETALIATE_INNER, EXIT_MACHINE_WITH_SUCCESS, attackAggressors );
189210
defineState( AI_GUARD_RETALIATE_INNER, newInstance(AIGuardRetaliateInnerState)( this ), AI_GUARD_RETALIATE_OUTER, AI_GUARD_RETALIATE_OUTER );
190211
defineState( AI_GUARD_RETALIATE_OUTER, newInstance(AIGuardRetaliateOuterState)( this ), AI_GUARD_RETALIATE_GET_CRATE, AI_GUARD_RETALIATE_GET_CRATE );

0 commit comments

Comments
 (0)