diff --git a/Generals/Code/GameEngine/Include/GameLogic/Module/JetAIUpdate.h b/Generals/Code/GameEngine/Include/GameLogic/Module/JetAIUpdate.h index c1b5facba1..bcda7b4310 100644 --- a/Generals/Code/GameEngine/Include/GameLogic/Module/JetAIUpdate.h +++ b/Generals/Code/GameEngine/Include/GameLogic/Module/JetAIUpdate.h @@ -131,6 +131,10 @@ class JetAIUpdate : public AIUpdateInterface void positionLockon(); virtual Bool getTreatAsAircraftForLocoDistToGoal() const; + virtual Bool shouldDeferCommand(const AICommandType commandType) const; ///< returns whether the specified command type should be deferred + virtual Bool commandRequiresTakeoff(const AICommandParms* parms) const; ///< returns whether the specified command requires takeoff + virtual Bool commandRequiresAmmo(const AICommandType commandType) const; ///< returns whether the specified command type requires ammo + virtual Bool isGuardCommand(const AICommandType commandType) const; ///< returns whether the specified command type is a guard command Bool isParkedAt(const Object* obj) const; private: 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 08258ee868..39de2c1b13 100644 --- a/Generals/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/JetAIUpdate.cpp +++ b/Generals/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/JetAIUpdate.cpp @@ -2316,69 +2316,100 @@ void JetAIUpdate::aiDoCommand(const AICommandParms* parms) // note that we always store this, even if nothing will be "pending". m_mostRecentCommand.store(*parms); - if (getFlag(TAKEOFF_IN_PROGRESS) || getFlag(LANDING_IN_PROGRESS)) + if (shouldDeferCommand(parms->m_cmd)) { - // have to wait for takeoff or landing to complete, just store the sucker setFlag(HAS_PENDING_COMMAND, true); return; } - else if (parms->m_cmd == AICMD_IDLE && getStateMachine()->getCurrentStateID() == RELOAD_AMMO) + + if (!getFlag(ALLOW_AIR_LOCO) && commandRequiresTakeoff(parms)) { - // uber-special-case... if we are told to idle, but are reloading ammo, ignore it for now, - // since we're already doing "nothing" and responding to this will cease our reload... - // don't just return, tho, in case we were (say) reloading during a guard stint. + // nuke any existing pending cmd + m_mostRecentCommand.store(*parms); setFlag(HAS_PENDING_COMMAND, true); + + getStateMachine()->clear(); + setLastCommandSource(CMD_FROM_AI); + getStateMachine()->setState(TAKING_OFF_AWAIT_CLEARANCE); return; } - else if (!getFlag(ALLOW_AIR_LOCO)) - { - switch (parms->m_cmd) - { - case AICMD_IDLE: - case AICMD_BUSY: - case AICMD_FOLLOW_EXITPRODUCTION_PATH: - // don't need (or want) to take off for these - break; - case AICMD_ENTER: - case AICMD_GET_REPAIRED: + setFlag(ALLOW_INTERRUPT_AND_RESUME_OF_CUR_STATE_FOR_RELOAD, isGuardCommand(parms->m_cmd)); + setFlag(HAS_PENDING_COMMAND, false); + AIUpdateInterface::aiDoCommand(parms); +} - // if we're already parked at the airfield in question, just ignore. - if (isParkedAt(parms->m_obj)) - return; +//------------------------------------------------------------------------------------------------- +Bool JetAIUpdate::shouldDeferCommand(const AICommandType commandType) const +{ + // Always defer commands received during takeoff or landing + if (getFlag(TAKEOFF_IN_PROGRESS) || getFlag(LANDING_IN_PROGRESS)) + return true; - FALLTHROUGH; // else fall thru to the default case! + const StateID currentState = getStateMachine()->getCurrentStateID(); - default: - { - // nuke any existing pending cmd - m_mostRecentCommand.store(*parms); - setFlag(HAS_PENDING_COMMAND, true); + // uber-special-case... if we are told to idle, but are reloading ammo, ignore it for now, + // since we're already doing "nothing" and responding to this will cease our reload... + // don't just return, tho, in case we were (say) reloading during a guard stint. + if (commandType == AICMD_IDLE && currentState == RELOAD_AMMO) + return true; - getStateMachine()->clear(); - setLastCommandSource( CMD_FROM_AI ); - getStateMachine()->setState( TAKING_OFF_AWAIT_CLEARANCE ); +#if !RETAIL_COMPATIBLE_CRC + if (commandRequiresAmmo(commandType) && currentState == RELOAD_AMMO) + return true; +#endif - return; - } - } - } + return false; +} +//------------------------------------------------------------------------------------------------- +Bool JetAIUpdate::commandRequiresTakeoff(const AICommandParms* parms) const +{ switch (parms->m_cmd) { - case AICMD_GUARD_POSITION: - case AICMD_GUARD_OBJECT: + case AICMD_IDLE: + case AICMD_BUSY: + case AICMD_FOLLOW_EXITPRODUCTION_PATH: + return false; + + case AICMD_ENTER: + case AICMD_GET_REPAIRED: + // if we're already parked at the airfield in question, just ignore. + return !isParkedAt(parms->m_obj); + + default: + return true; + } +} + +Bool JetAIUpdate::commandRequiresAmmo(const AICommandType commandType) const +{ + switch (commandType) + { + case AICMD_ATTACKMOVE_TO_POSITION: + case AICMD_ATTACK_AREA: + case AICMD_ATTACK_OBJECT: + case AICMD_ATTACK_POSITION: + case AICMD_ATTACK_TEAM: + case AICMD_FORCE_ATTACK_OBJECT: + return true; + default: + return isGuardCommand(commandType); + } +} + +Bool JetAIUpdate::isGuardCommand(const AICommandType commandType) const +{ + switch (commandType) + { case AICMD_GUARD_AREA: + case AICMD_GUARD_OBJECT: + case AICMD_GUARD_POSITION: case AICMD_HUNT: - setFlag(ALLOW_INTERRUPT_AND_RESUME_OF_CUR_STATE_FOR_RELOAD, true); - break; + return true; default: - setFlag(ALLOW_INTERRUPT_AND_RESUME_OF_CUR_STATE_FOR_RELOAD, false); - break; + return false; } - - setFlag(HAS_PENDING_COMMAND, false); - AIUpdateInterface::aiDoCommand(parms); } //------------------------------------------------------------------------------------------------- diff --git a/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/JetAIUpdate.h b/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/JetAIUpdate.h index 1840d30a4b..10f93c8266 100644 --- a/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/JetAIUpdate.h +++ b/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/JetAIUpdate.h @@ -140,6 +140,10 @@ class JetAIUpdate : public AIUpdateInterface void positionLockon(); virtual Bool getTreatAsAircraftForLocoDistToGoal() const; + virtual Bool shouldDeferCommand(const AICommandType commandType) const; ///< returns whether the specified command type should be deferred + virtual Bool commandRequiresTakeoff(const AICommandParms* parms) const; ///< returns whether the specified command requires takeoff + virtual Bool commandRequiresAmmo(const AICommandType commandType) const; ///< returns whether the specified command type requires ammo + virtual Bool isGuardCommand(const AICommandType commandType) const; ///< returns whether the specified command type is a guard command Bool isParkedAt(const Object* obj) const; private: 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 5d5189ed68..d894bd5ffb 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/JetAIUpdate.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/JetAIUpdate.cpp @@ -2543,77 +2543,109 @@ void JetAIUpdate::aiDoCommand(const AICommandParms* parms) // note that we always store this, even if nothing will be "pending". m_mostRecentCommand.store(*parms); - if (getFlag(TAKEOFF_IN_PROGRESS) || getFlag(LANDING_IN_PROGRESS)) - { - // have to wait for takeoff or landing to complete, just store the sucker - setFlag(HAS_PENDING_COMMAND, true); - return; - } - else if (parms->m_cmd == AICMD_IDLE && getStateMachine()->getCurrentStateID() == RELOAD_AMMO) + if (shouldDeferCommand(parms->m_cmd)) { - // uber-special-case... if we are told to idle, but are reloading ammo, ignore it for now, - // since we're already doing "nothing" and responding to this will cease our reload... - // don't just return, tho, in case we were (say) reloading during a guard stint. setFlag(HAS_PENDING_COMMAND, true); return; } - else if( parms->m_cmd == AICMD_IDLE && getObject()->isAirborneTarget() && !getObject()->isKindOf( KINDOF_PRODUCED_AT_HELIPAD ) ) + + if( parms->m_cmd == AICMD_IDLE && getObject()->isAirborneTarget() && !getObject()->isKindOf( KINDOF_PRODUCED_AT_HELIPAD ) ) { getStateMachine()->clear(); setLastCommandSource( CMD_FROM_AI ); getStateMachine()->setState( RETURNING_FOR_LANDING ); return; } - else if (!getFlag(ALLOW_AIR_LOCO)) + + if (!getFlag(ALLOW_AIR_LOCO) && commandRequiresTakeoff(parms)) { - switch (parms->m_cmd) - { - case AICMD_IDLE: - case AICMD_BUSY: - case AICMD_FOLLOW_EXITPRODUCTION_PATH: - // don't need (or want) to take off for these - break; + // nuke any existing pending cmd + m_mostRecentCommand.store(*parms); + setFlag(HAS_PENDING_COMMAND, true); + + getStateMachine()->clear(); + setLastCommandSource(CMD_FROM_AI); + getStateMachine()->setState(TAKING_OFF_AWAIT_CLEARANCE); + return; + } - case AICMD_ENTER: - case AICMD_GET_REPAIRED: + setFlag(ALLOW_INTERRUPT_AND_RESUME_OF_CUR_STATE_FOR_RELOAD, isGuardCommand(parms->m_cmd)); + setFlag(HAS_PENDING_COMMAND, false); + AIUpdateInterface::aiDoCommand(parms); +} - // if we're already parked at the airfield in question, just ignore. - if (isParkedAt(parms->m_obj)) - return; +//------------------------------------------------------------------------------------------------- +Bool JetAIUpdate::shouldDeferCommand(const AICommandType commandType) const +{ + // Always defer commands received during takeoff or landing + if (getFlag(TAKEOFF_IN_PROGRESS) || getFlag(LANDING_IN_PROGRESS)) + return true; - FALLTHROUGH; // else fall thru to the default case! + const StateID currentState = getStateMachine()->getCurrentStateID(); - default: - { - // nuke any existing pending cmd - m_mostRecentCommand.store(*parms); - setFlag(HAS_PENDING_COMMAND, true); + // uber-special-case... if we are told to idle, but are reloading ammo, ignore it for now, + // since we're already doing "nothing" and responding to this will cease our reload... + // don't just return, tho, in case we were (say) reloading during a guard stint. + if (commandType == AICMD_IDLE && currentState == RELOAD_AMMO) + return true; - getStateMachine()->clear(); - setLastCommandSource( CMD_FROM_AI ); - getStateMachine()->setState( TAKING_OFF_AWAIT_CLEARANCE ); +#if !RETAIL_COMPATIBLE_CRC + if (commandRequiresAmmo(commandType) && currentState == RELOAD_AMMO) + return true; +#endif - return; - } - } - } + return false; +} +//------------------------------------------------------------------------------------------------- +Bool JetAIUpdate::commandRequiresTakeoff(const AICommandParms* parms) const +{ switch (parms->m_cmd) { - case AICMD_GUARD_POSITION: - case AICMD_GUARD_OBJECT: + case AICMD_IDLE: + case AICMD_BUSY: + case AICMD_FOLLOW_EXITPRODUCTION_PATH: + return false; + + case AICMD_ENTER: + case AICMD_GET_REPAIRED: + // if we're already parked at the airfield in question, just ignore. + return !isParkedAt(parms->m_obj); + + default: + return true; + } +} + +Bool JetAIUpdate::commandRequiresAmmo(const AICommandType commandType) const +{ + switch (commandType) + { + case AICMD_ATTACKMOVE_TO_POSITION: + case AICMD_ATTACK_AREA: + case AICMD_ATTACK_OBJECT: + case AICMD_ATTACK_POSITION: + case AICMD_ATTACK_TEAM: + case AICMD_FORCE_ATTACK_OBJECT: + return true; + default: + return isGuardCommand(commandType); + } +} + +Bool JetAIUpdate::isGuardCommand(const AICommandType commandType) const +{ + switch (commandType) + { case AICMD_GUARD_AREA: - case AICMD_HUNT: + case AICMD_GUARD_OBJECT: + case AICMD_GUARD_POSITION: case AICMD_GUARD_RETALIATE: - setFlag(ALLOW_INTERRUPT_AND_RESUME_OF_CUR_STATE_FOR_RELOAD, true); - break; + case AICMD_HUNT: + return true; default: - setFlag(ALLOW_INTERRUPT_AND_RESUME_OF_CUR_STATE_FOR_RELOAD, false); - break; + return false; } - - setFlag(HAS_PENDING_COMMAND, false); - AIUpdateInterface::aiDoCommand(parms); } //-------------------------------------------------------------------------------------------------