/* ** Command & Conquer Generals Zero Hour(tm) ** Copyright 2025 Electronic Arts Inc. ** ** This program is free software: you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation, either version 3 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program. If not, see . */ //////////////////////////////////////////////////////////////////////////////// // // // (c) 2001-2003 Electronic Arts Inc. // // // //////////////////////////////////////////////////////////////////////////////// // SupplyTruckAIUpdate.h //////////// // Author: Graham Smallwood, February 2002 // Desc: State machine that controls when and with who a Truck docks #pragma once #ifndef _SUPPLY_TRUCK_AI_UPDATE_H_ #define _SUPPLY_TRUCK_AI_UPDATE_H_ #include "Common/StateMachine.h" #include "GameLogic/Module/AIUpdate.h" //------------------------------------------------------------------------------------------------- class SupplyTruckStateMachine : public StateMachine { MEMORY_POOL_GLUE_WITH_USERLOOKUP_CREATE( SupplyTruckStateMachine, "SupplyTruckStateMachine" ); public: SupplyTruckStateMachine( Object *owner ); // state transition conditions static Bool ownerDocking( State *thisState, void* userData ); static Bool ownerIdle( State *thisState, void* userData ); static Bool ownerAvailableForSupplying( State *thisState, void* userData ); static Bool ownerNotDockingOrIdle( State *thisState, void* userData ); static Bool isForcedIntoWantingState( State *thisState, void* userData ); static Bool isForcedIntoBusyState( State *thisState, void* userData ); static Bool ownerPlayerCommanded( State *thisState, void* userData ); protected: // snapshot interface virtual void crc( Xfer *xfer ); virtual void xfer( Xfer *xfer ); virtual void loadPostProcess(); }; //------------------------------------------------------------------------------------------------- class SupplyTruckWantsToPickUpOrDeliverBoxesState : public State { MEMORY_POOL_GLUE_WITH_USERLOOKUP_CREATE(SupplyTruckWantsToPickUpOrDeliverBoxesState, "SupplyTruckWantsToPickUpOrDeliverBoxesState") protected: // snapshot interface STUBBED. virtual void crc( Xfer *xfer ){}; virtual void xfer( Xfer *xfer ){XferVersion cv = 1; XferVersion v = cv; xfer->xferVersion( &v, cv );} virtual void loadPostProcess(){}; public: SupplyTruckWantsToPickUpOrDeliverBoxesState( StateMachine *machine ) : State( machine, "SupplyTruckWantsToPickUpOrDeliverBoxesState" ) {} virtual StateReturnType update(); virtual StateReturnType onEnter(); virtual void onExit(StateExitType status); }; EMPTY_DTOR(SupplyTruckWantsToPickUpOrDeliverBoxesState) //------------------------------------------------------------------------------------------------- class RegroupingState : public State { MEMORY_POOL_GLUE_WITH_USERLOOKUP_CREATE(RegroupingState, "RegroupingState") protected: // snapshot interface STUBBED. virtual void crc( Xfer *xfer ){}; virtual void xfer( Xfer *xfer ){XferVersion cv = 1; XferVersion v = cv; xfer->xferVersion( &v, cv );} virtual void loadPostProcess(){}; public: RegroupingState( StateMachine *machine ) : State( machine, "RegroupingState" ) {} virtual StateReturnType update(); virtual StateReturnType onEnter();// Will tell me to aiMove back to base. virtual void onExit(StateExitType status); }; EMPTY_DTOR(RegroupingState) //------------------------------------------------------------------------------------------------- class DockingState : public State { MEMORY_POOL_GLUE_WITH_USERLOOKUP_CREATE(DockingState, "DockingState") protected: // snapshot interface STUBBED. virtual void crc( Xfer *xfer ){}; virtual void xfer( Xfer *xfer ){XferVersion cv = 1; XferVersion v = cv; xfer->xferVersion( &v, cv );} virtual void loadPostProcess(){}; public: DockingState( StateMachine *machine ) :State( machine, "DockingState" ) {} virtual StateReturnType update(); virtual StateReturnType onEnter(); virtual void onExit(StateExitType status); }; EMPTY_DTOR(DockingState) //------------------------------------------------------------------------------------------------- enum { ST_IDLE, ///< Not doing anything. Should I autopilot? ST_BUSY, ///< Direct player involvement (move) has taken me off autopilot ST_WANTING, ///< Search for warehouse or center and dock with it ST_REGROUPING, ///< Wanting failed, so hang out at base until something changes. Autopilot will turn off. ST_DOCKING ///< Docking substates are running, wait for them to finish }; //------------------------------------------------------------------------------------------------- class SupplyTruckAIUpdateModuleData : public AIUpdateModuleData { public: Int m_maxBoxesData; UnsignedInt m_centerDelay; UnsignedInt m_warehouseDelay; Real m_warehouseScanDistance; AudioEventRTS m_suppliesDepletedVoice; ///< Sound played when I take the last box. SupplyTruckAIUpdateModuleData() { m_maxBoxesData = 0; m_centerDelay = 0; m_warehouseDelay = 0; m_warehouseScanDistance = 100; } static void buildFieldParse(MultiIniFieldParse& p) { AIUpdateModuleData::buildFieldParse(p); static const FieldParse dataFieldParse[] = { { "MaxBoxes", INI::parseInt, NULL, offsetof( SupplyTruckAIUpdateModuleData, m_maxBoxesData ) }, { "SupplyCenterActionDelay", INI::parseDurationUnsignedInt, NULL, offsetof( SupplyTruckAIUpdateModuleData, m_centerDelay ) }, { "SupplyWarehouseActionDelay", INI::parseDurationUnsignedInt, NULL, offsetof( SupplyTruckAIUpdateModuleData, m_warehouseDelay ) }, { "SupplyWarehouseScanDistance", INI::parseReal, NULL, offsetof( SupplyTruckAIUpdateModuleData, m_warehouseScanDistance ) }, { "SuppliesDepletedVoice", INI::parseAudioEventRTS, NULL, offsetof( SupplyTruckAIUpdateModuleData, m_suppliesDepletedVoice) }, { 0, 0, 0, 0 } }; p.add(dataFieldParse); } }; //------------------------------------------------------------------------------------------------- class SupplyTruckAIInterface { // This is no longer a leaf behavior. Someone else needs to combine this // with another major AIUpdate. So provide an interface to satisfy the people // who look this up by name. public: virtual Int getNumberBoxes() const = 0; virtual Bool loseOneBox() = 0; virtual Bool gainOneBox( Int remainingStock ) = 0; // returns true if we can fetch/deliver supplies. normally returns true // if the AI is idle, but subclasses might add further restrictions. virtual Bool isAvailableForSupplying() const = 0; virtual Bool isCurrentlyFerryingSupplies() const = 0; virtual Real getWarehouseScanDistance() const = 0; ///< How far can I look for a warehouse? virtual void setForceWantingState(Bool v) = 0; virtual Bool isForcedIntoWantingState() const = 0; virtual void setForceBusyState(Bool v) = 0; virtual Bool isForcedIntoBusyState() const = 0; virtual ObjectID getPreferredDockID() const = 0; virtual UnsignedInt getActionDelayForDock( Object *dock ) = 0; virtual Int getUpgradedSupplyBoost() const = 0; }; //------------------------------------------------------------------------------------------------- class SupplyTruckAIUpdate : public AIUpdateInterface, public SupplyTruckAIInterface { MEMORY_POOL_GLUE_WITH_USERLOOKUP_CREATE( SupplyTruckAIUpdate, "SupplyTruckAIUpdate" ) MAKE_STANDARD_MODULE_MACRO_WITH_MODULE_DATA( SupplyTruckAIUpdate, SupplyTruckAIUpdateModuleData ) private: public: SupplyTruckAIUpdate( Thing *thing, const ModuleData* moduleData ); // virtual destructor prototype provided by memory pool declaration virtual SupplyTruckAIInterface* getSupplyTruckAIInterface() {return this;} virtual const SupplyTruckAIInterface* getSupplyTruckAIInterface() const {return this;} virtual Int getNumberBoxes() const { return m_numberBoxes; } virtual Bool loseOneBox(); virtual Bool gainOneBox( Int remainingStock ); // this is present for subclasses (eg, Chinook) to override, to // prevent supply-ferry behavior in some cases (eg, when toting passengers) virtual Bool isAvailableForSupplying() const; virtual Bool isCurrentlyFerryingSupplies() const; virtual Real getWarehouseScanDistance() const; ///< How far can I look for a warehouse? virtual void setForceWantingState(Bool v) { m_forcePending = v; } // When a Supply Center creates us (or maybe other sources later), we need to hop into autopilot mode. virtual Bool isForcedIntoWantingState() const { return m_forcePending; } virtual void setForceBusyState(Bool v) { m_forcedBusyPending = v; } virtual Bool isForcedIntoBusyState() const { return m_forcedBusyPending; } virtual ObjectID getPreferredDockID() const { return m_preferredDock; } virtual UnsignedInt getActionDelayForDock( Object *dock ); virtual Int getUpgradedSupplyBoost() const { return 0; } virtual UpdateSleepTime update(); protected: virtual AIStateMachine* makeStateMachine(); virtual void privateDock( Object *obj, CommandSourceType cmdSource ); virtual void privateIdle(CommandSourceType cmdSource); ///< Enter idle state. private: SupplyTruckStateMachine* m_supplyTruckStateMachine; ObjectID m_preferredDock; ///< Instead of searching, try this one first Int m_numberBoxes; Bool m_forcePending; // To prevent a function from doing a setState, // forceWanting will latch into here until serviced. Bool m_forcedBusyPending; // A supply truck can't tell the difference between Idle since // I'm between docking states, or a Stop command without help. AudioEventRTS m_suppliesDepletedVoice; ///< Sound played when I take the last box. }; #endif