Skip to content

Overlord Gatling Cannon disappears on force-attack empty terrain (POSIX port) #95

Description

@fbraz3

Summary

When the Overlord tank has a Gatling Cannon upgrade and the player issues a force-attack on empty terrain (no units, no buildings — just ground), the Gatling Cannon disappears from the Overlord. Because the upgrade slot is consumed, the Gatling cannot be re-built.

This does not affect:

  • Normal attacks against actual targets (units, buildings) — Gatling fires correctly
  • Propaganda Tower upgrade — never disappears regardless of force-attack
  • BattleBunker upgrade — unaffected

Steps to Reproduce

  1. Build an Overlord tank (China faction)
  2. Apply the Gatling Cannon upgrade
  3. Select the Overlord
  4. Force-attack (A + click) on an empty area of terrain with no targets
  5. Gatling Cannon disappears

Root Cause Analysis

The Gatling Cannon's AI enters the following state chain when force-attacking empty terrain:

aiAttackPosition
  → AI_ATTACK_POSITION (AIAttackState)
    → AttackStateMachine::AIM_AT_TARGET
      → outOfWeaponRange → CHASE_TARGET
        → ContinueState (KINDOF_PORTABLE_STRUCTURE + KINDOF_CAN_ATTACK special case)
          → EXIT_MACHINE_WITH_FAILURE
    → STATE_FAILURE → AI_EXIT_INSTANTLY
      → AIExitInstantlyState::onEnter()
        → goalExitInterface->exitObjectViaDoor(obj, DOOR_1)  ← Gatling ejected here

The key issue is in AttackStateMachine constructor (AIStates.cpp): when the attacker is both KINDOF_PORTABLE_STRUCTURE and KINDOF_CAN_ATTACK, CHASE_TARGET is a ContinueState that always fails — this is intentional (portables can't move), but it causes AI_EXIT_INSTANTLY to be triggered.

The Propaganda Tower never hits this path because it has no attack weapons and never enters attack states — its healing works via PropagandaTowerBehavior area scan.

Attempted Fixes

Two guards were added to OverlordContain (commits 93de21fe6, 689b38e78):

  1. isSpecificRiderFreeToExit() — blocks AIExitState (normal exit via reserveDoorForExit). Works.
  2. exitObjectViaDoor() — meant to block AIExitInstantlyState which calls exitObjectViaDoor(DOOR_1) directly, bypassing reserveDoorForExit. Did not resolve the issue.

The exact bypass mechanism when exitObjectViaDoor override is in place is not yet identified. Possible unexplored paths:

  • removeFromContain() called directly from a different code path
  • getContainExitInterface() returning a different ExitInterface in this context
  • A different trigger (not AI_EXIT_INSTANTLY) causing the removal

Affected Files

  • GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Contain/OverlordContain.cpp
  • GeneralsMD/Code/GameEngine/Source/GameLogic/AI/AIStates.cpp (AttackStateMachine, AIExitInstantlyState)

Workaround

None currently. Avoid force-attacking empty terrain with an Overlord that has the Gatling Cannon upgrade.

Platform

macOS (POSIX port). Behavior on original Windows/VC6 build is unknown — the locomotor-based DISABLED_HELD mechanism may have prevented the issue naturally on that platform.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions