/*
** 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. //
// //
////////////////////////////////////////////////////////////////////////////////
// JetAIUpdate.h //////////
// Author: Steven Johnson, June 2002
#pragma once
#ifndef _JET_AI_UPDATE_H_
#define _JET_AI_UPDATE_H_
#include "Common/STLTypedefs.h"
#include "Common/GameMemory.h"
#include "GameLogic/AIStateMachine.h"
#include "GameLogic/Module/AIUpdate.h"
#ifdef _INTERNAL
// for occasional debugging...
//#pragma optimize("", off)
//#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes")
#endif
//-------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------
class JetAIUpdateModuleData : public AIUpdateModuleData
{
public:
Real m_outOfAmmoDamagePerSecond; /**< amount of damage to take per SEC (not per frame) when out of ammo
note that it's expressed as a percent of max health, not an absolute */
Real m_takeoffDistForMaxLift; ///< percent of distance from start (100%) to end (0%) that gives us max lift. Higher value lifts off sooner.
Real m_minHeight; ///< how far off the ground to lift the drawable when taxiing
Real m_parkingOffset; ///< tweaking the park loc
Real m_sneakyOffsetWhenAttacking; ///< our sneaky offset when attacking (or zero)
Bool m_keepsParkingSpaceWhenAirborne; ///< if t, keeps its parking space reservation even when airborne
Bool m_needsRunway; ///< if t, needs runways to takeoff/land
UnsignedInt m_takeoffPause; ///< pre-takeoff pause
LocomotorSetType m_attackingLoco; ///< custom attacking loco
LocomotorSetType m_returningLoco; ///< custom return-for-ammo loco
UnsignedInt m_attackLocoPersistTime; ///< if we have a custom attack loco, it persists for this long after attack is done
UnsignedInt m_attackersMissPersistTime; ///< how long after our attack we continue immunity
UnsignedInt m_lockonTime; ///< time it takes for someone to lock-on to us.
AsciiString m_lockonCursor; ///< template used for lockon.
Real m_lockonInitialDist; ///< how far away the lockon cursor starts.
Real m_lockonFreq;
Real m_lockonAngleSpin; ///< how many times to spin around it
Real m_lockonBlinky;
UnsignedInt m_returnToBaseIdleTime; ///< if we're idle for this long, return to base
JetAIUpdateModuleData();
static void buildFieldParse(MultiIniFieldParse& p);
};
//-------------------------------------------------------------------------------------------------
class JetAIUpdate : public AIUpdateInterface
{
MEMORY_POOL_GLUE_WITH_USERLOOKUP_CREATE( JetAIUpdate, "JetAIUpdate" )
MAKE_STANDARD_MODULE_MACRO_WITH_MODULE_DATA( JetAIUpdate, JetAIUpdateModuleData )
virtual UpdateSleepTime update();
public:
JetAIUpdate( Thing *thing, const ModuleData* moduleData );
// virtual destructor prototype provided by memory pool declaration
virtual void onObjectCreated();
virtual void onDelete();
virtual JetAIUpdate* getJetAIUpdate() { return this; }
virtual const JetAIUpdate* getJetAIUpdate() const { return this; }
virtual void aiDoCommand(const AICommandParms* parms);
virtual Bool chooseLocomotorSet(LocomotorSetType wst);
virtual void setLocomotorGoalNone();
virtual Bool isIdle() const;
virtual Bool isTaxiingToParking() const; //only applies to jets interacting with runways.
virtual Bool isReloading() const;
virtual Bool isAllowedToMoveAwayFromUnit() const;
virtual Bool getSneakyTargetingOffset(Coord3D* offset) const;
virtual void addTargeter(ObjectID id, Bool add);
virtual Bool isTemporarilyPreventingAimSuccess() const;
virtual Bool isDoingGroundMovement() const;
virtual void notifyVictimIsDead();
virtual Bool isOutOfSpecialReloadAmmo() const;
const Coord3D* friend_getProducerLocation() const { return &m_producerLocation; }
Real friend_getOutOfAmmoDamagePerSecond() const { return getJetAIUpdateModuleData()->m_outOfAmmoDamagePerSecond; }
Bool friend_keepsParkingSpaceWhenAirborne() const { return getJetAIUpdateModuleData()->m_keepsParkingSpaceWhenAirborne; }
Bool friend_needsRunway() const { return getJetAIUpdateModuleData()->m_needsRunway; }
Real friend_getTakeoffDistForMaxLift() const { return getJetAIUpdateModuleData()->m_takeoffDistForMaxLift; }
Real friend_getMinHeight() const { return getJetAIUpdateModuleData()->m_minHeight; }
Real friend_getParkingOffset() const { return getJetAIUpdateModuleData()->m_parkingOffset; }
UnsignedInt friend_getTakeoffPause() const { return getJetAIUpdateModuleData()->m_takeoffPause; }
void friend_setGoalPath( const std::vector* path ) { getStateMachine()->setGoalPath(path); }
void friend_setTakeoffInProgress(Bool v) { setFlag(TAKEOFF_IN_PROGRESS, v); }
void friend_setLandingInProgress(Bool v) { setFlag(LANDING_IN_PROGRESS, v); }
void friend_setTaxiInProgress(Bool v) { setFlag(TAXI_IN_PROGRESS, v); }
void friend_setUseSpecialReturnLoco(Bool v) { setFlag(USE_SPECIAL_RETURN_LOCO, v); }
void friend_setAllowCircling(Bool v) { setFlag(ALLOW_CIRCLING, v); }
const Coord3D& friend_getLandingPosForHelipadStuff() const { return m_landingPosForHelipadStuff; }
void friend_enableAfterburners(Bool v);
void friend_setAllowAirLoco(Bool a);
Bool friend_isTakeoffOrLandingInProgress() const
{
return (getFlag(TAKEOFF_IN_PROGRESS) || getFlag(LANDING_IN_PROGRESS));
}
void friend_addWaypointToGoalPath( const Coord3D &pos );
AICommandType friend_getPendingCommandType() const;
void friend_purgePendingCommand();
protected:
virtual AIStateMachine* makeStateMachine();
virtual void privateFollowPath( const std::vector* path, Object *ignoreObject, CommandSourceType cmdSource, Bool exitProduction );///< follow the path defined by the given array of points
virtual void privateFollowPathAppend( const Coord3D *pos, CommandSourceType cmdSource );
virtual void privateEnter( Object *obj, CommandSourceType cmdSource ); ///< enter the given object
virtual void privateGetRepaired( Object *repairDepot, CommandSourceType cmdSource );///< get repaired at repair depot
void pruneDeadTargeters();
void positionLockon();
virtual Bool getTreatAsAircraftForLocoDistToGoal() const;
Bool isParkedAt(const Object* obj) const;
private:
enum FlagType
{
HAS_PENDING_COMMAND,
ALLOW_AIR_LOCO,
HAS_PRODUCER_LOCATION,
TAKEOFF_IN_PROGRESS,
LANDING_IN_PROGRESS,
USE_SPECIAL_RETURN_LOCO,
ALLOW_CIRCLING,
ALLOW_INTERRUPT_AND_RESUME_OF_CUR_STATE_FOR_RELOAD,
TAXI_IN_PROGRESS
};
Coord3D m_producerLocation; ///< remember this, so that if our producer dies, we have a place to circle aimlessly
AICommandParmsStorage m_mostRecentCommand;
AudioEventRTS m_afterburnerSound; ///< Sound when afterburners on
UnsignedInt m_attackLocoExpireFrame;
UnsignedInt m_attackersMissExpireFrame;
UnsignedInt m_returnToBaseFrame; ///< if nonzero, return to base at this frame when we are idle, even if not out of ammo
std::list m_targetedBy; ///< object(s) currently targeting us, if any
UnsignedInt m_untargetableExpireFrame;
Drawable* m_lockonDrawable;
Int m_flags;
Coord3D m_landingPosForHelipadStuff;
Bool m_enginesOn; ///<
void getProducerLocation();
void buildLockonDrawableIfNecessary();
void doLandingCommand(Object *airfield, CommandSourceType cmdSource);
Bool getFlag(FlagType f) const;
void setFlag(FlagType f, Bool v);
};
#endif