From 2b9660980605ea61c64ee19602b9a02630ed3c1b Mon Sep 17 00:00:00 2001 From: Stubbjax Date: Sun, 9 Aug 2026 01:51:05 +1000 Subject: [PATCH 1/2] bugfix: Helicopters no longer land or remain landed at destroyed Airfields --- .../Object/Update/AIUpdate/JetAIUpdate.cpp | 18 +++++++++++++++++- .../Object/Update/AIUpdate/JetAIUpdate.cpp | 18 +++++++++++++++++- 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/Generals/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/JetAIUpdate.cpp b/Generals/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/JetAIUpdate.cpp index fd146a37bdc..2cc53c7be37 100644 --- a/Generals/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/JetAIUpdate.cpp +++ b/Generals/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/JetAIUpdate.cpp @@ -819,7 +819,11 @@ class HeliTakeoffOrLandingState : public State Object* airfield; ParkingPlaceBehaviorInterface* pp = getPP(jet->getProducerID(), &airfield); if (pp == nullptr) - return STATE_SUCCESS; // no airfield? just skip this step +#if RETAIL_COMPATIBLE_CRC + return STATE_SUCCESS; +#else + return STATE_FAILURE; +#endif Coord3D landingApproach; if (jet->isKindOf(KINDOF_PRODUCED_AT_HELIPAD)) @@ -1431,6 +1435,13 @@ class JetOrHeliReloadAmmoState : public State virtual StateReturnType update() override { Object* jet = getMachineOwner(); + +#if !RETAIL_COMPATIBLE_CRC + ParkingPlaceBehaviorInterface* pp = getPP(jet->getProducerID()); + if (pp == nullptr) + return STATE_FAILURE; +#endif + UnsignedInt now = TheGameLogic->getFrame(); Bool allDone = true; for (Int i = 0; i < WEAPONSLOT_COUNT; ++i) @@ -1577,8 +1588,13 @@ HeliAIStateMachine::HeliAIStateMachine(Object *owner, AsciiString name) : AIStat defineState( TAKING_OFF, newInstance(HeliTakeoffOrLandingState)( this, false ), AI_IDLE, AI_IDLE ); defineState( LANDING_AWAIT_CLEARANCE, newInstance(SuccessState)( this ), ORIENT_FOR_PARKING_PLACE, AI_IDLE ); defineState( ORIENT_FOR_PARKING_PLACE, newInstance(JetOrHeliParkOrientState)( this ), LANDING, AI_IDLE ); +#if RETAIL_COMPATIBLE_CRC defineState( LANDING, newInstance(HeliTakeoffOrLandingState)( this, true ), RELOAD_AMMO, AI_IDLE ); defineState( RELOAD_AMMO, newInstance(JetOrHeliReloadAmmoState)( this ), AI_IDLE, AI_IDLE ); +#else + defineState( LANDING, newInstance(HeliTakeoffOrLandingState)( this, true ), RELOAD_AMMO, TAKING_OFF ); + defineState( RELOAD_AMMO, newInstance(JetOrHeliReloadAmmoState)( this ), AI_IDLE, TAKING_OFF ); +#endif defineState( RETURN_TO_DEAD_AIRFIELD, newInstance(JetOrHeliReturningToDeadAirfieldState)( this ), CIRCLING_DEAD_AIRFIELD, RETURN_TO_DEAD_AIRFIELD ); defineState( CIRCLING_DEAD_AIRFIELD, newInstance(JetOrHeliCirclingDeadAirfieldState)( this ), AI_IDLE, AI_IDLE ); defineState( TAXI_FROM_HANGAR, newInstance(JetOrHeliTaxiState)( this, FROM_HANGAR ), AI_IDLE, AI_IDLE ); diff --git a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/JetAIUpdate.cpp b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/JetAIUpdate.cpp index 33fdc0ab89b..9c2e3c64f2f 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/JetAIUpdate.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/JetAIUpdate.cpp @@ -1006,7 +1006,11 @@ class HeliTakeoffOrLandingState : public State Object* airfield; ParkingPlaceBehaviorInterface* pp = getPP(jet->getProducerID(), &airfield); if (pp == nullptr) - return STATE_SUCCESS; // no airfield? just skip this step +#if RETAIL_COMPATIBLE_CRC + return STATE_SUCCESS; +#else + return STATE_FAILURE; +#endif Coord3D landingApproach; if (jet->isKindOf(KINDOF_PRODUCED_AT_HELIPAD)) @@ -1623,6 +1627,13 @@ class JetOrHeliReloadAmmoState : public State virtual StateReturnType update() override { Object* jet = getMachineOwner(); + +#if !RETAIL_COMPATIBLE_CRC + ParkingPlaceBehaviorInterface* pp = getPP(jet->getProducerID()); + if (pp == nullptr) + return STATE_FAILURE; +#endif + UnsignedInt now = TheGameLogic->getFrame(); Bool allDone = true; for (Int i = 0; i < WEAPONSLOT_COUNT; ++i) @@ -1769,8 +1780,13 @@ HeliAIStateMachine::HeliAIStateMachine(Object *owner, AsciiString name) : AIStat defineState( TAKING_OFF, newInstance(HeliTakeoffOrLandingState)( this, false ), AI_IDLE, AI_IDLE ); defineState( LANDING_AWAIT_CLEARANCE, newInstance(SuccessState)( this ), ORIENT_FOR_PARKING_PLACE, AI_IDLE ); defineState( ORIENT_FOR_PARKING_PLACE, newInstance(JetOrHeliParkOrientState)( this ), LANDING, AI_IDLE ); +#if RETAIL_COMPATIBLE_CRC defineState( LANDING, newInstance(HeliTakeoffOrLandingState)( this, true ), RELOAD_AMMO, AI_IDLE ); defineState( RELOAD_AMMO, newInstance(JetOrHeliReloadAmmoState)( this ), AI_IDLE, AI_IDLE ); +#else + defineState( LANDING, newInstance(HeliTakeoffOrLandingState)( this, true ), RELOAD_AMMO, TAKING_OFF ); + defineState( RELOAD_AMMO, newInstance(JetOrHeliReloadAmmoState)( this ), AI_IDLE, TAKING_OFF ); +#endif defineState( RETURN_TO_DEAD_AIRFIELD, newInstance(JetOrHeliReturningToDeadAirfieldState)( this ), CIRCLING_DEAD_AIRFIELD, RETURN_TO_DEAD_AIRFIELD ); defineState( CIRCLING_DEAD_AIRFIELD, newInstance(JetOrHeliCirclingDeadAirfieldState)( this ), AI_IDLE, AI_IDLE ); defineState( TAXI_FROM_HANGAR, newInstance(JetOrHeliTaxiState)( this, FROM_HANGAR ), AI_IDLE, AI_IDLE ); From 64bba9be1d3b265649b0ca1b6946ac41ca720d87 Mon Sep 17 00:00:00 2001 From: Stubbjax Date: Mon, 10 Aug 2026 00:41:06 +1000 Subject: [PATCH 2/2] refactor: Remove superfluous airfield param --- .../Source/GameLogic/Object/Update/AIUpdate/JetAIUpdate.cpp | 3 +-- .../Source/GameLogic/Object/Update/AIUpdate/JetAIUpdate.cpp | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/Generals/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/JetAIUpdate.cpp b/Generals/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/JetAIUpdate.cpp index 2cc53c7be37..8aabf776799 100644 --- a/Generals/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/JetAIUpdate.cpp +++ b/Generals/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/JetAIUpdate.cpp @@ -816,8 +816,7 @@ class HeliTakeoffOrLandingState : public State loco->setUltraAccurate(true); jetAI->ignoreObstacleID(jet->getProducerID()); - Object* airfield; - ParkingPlaceBehaviorInterface* pp = getPP(jet->getProducerID(), &airfield); + ParkingPlaceBehaviorInterface* pp = getPP(jet->getProducerID()); if (pp == nullptr) #if RETAIL_COMPATIBLE_CRC return STATE_SUCCESS; diff --git a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/JetAIUpdate.cpp b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/JetAIUpdate.cpp index 9c2e3c64f2f..998825c9648 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/JetAIUpdate.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/JetAIUpdate.cpp @@ -1003,8 +1003,7 @@ class HeliTakeoffOrLandingState : public State loco->setUltraAccurate(true); jetAI->ignoreObstacleID(jet->getProducerID()); - Object* airfield; - ParkingPlaceBehaviorInterface* pp = getPP(jet->getProducerID(), &airfield); + ParkingPlaceBehaviorInterface* pp = getPP(jet->getProducerID()); if (pp == nullptr) #if RETAIL_COMPATIBLE_CRC return STATE_SUCCESS;