/* * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or * its licensors. * * For complete copyright and license terms please see the LICENSE at the root of this * distribution (the "License"). All use of this software is governed by the License, * or, if provided, by the license below or the license accompanying this file. Do not * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * */ // Original file Copyright Crytek GMBH or its affiliates, used under license. // Description : Crysi2 GoalOps // These should move into GameDLL when interfaces allow! #ifndef CRYINCLUDE_CRYAISYSTEM_GAMESPECIFIC_GOALOP_CRYSIS2_H #define CRYINCLUDE_CRYAISYSTEM_GAMESPECIFIC_GOALOP_CRYSIS2_H #pragma once #include "GoalOp.h" #include "GoalOpFactory.h" #include "Communication/Communication.h" #include "PostureManager.h" #include "FlightNavRegion2.h" #include "GenericAStarSolver.h" // Forward declarations class COPPathFind; class COPTrace; /** * Factory for Crysis2 goalops * */ class CGoalOpFactoryCrysis2 : public IGoalOpFactory { IGoalOp* GetGoalOp(const char* sGoalOpName, IFunctionHandler* pH, int nFirstParam, GoalParameters& params) const; IGoalOp* GetGoalOp(EGoalOperations op, GoalParameters& params) const; }; //////////////////////////////////////////////////////// // // Adjust aim while staying still. // //////////////////////////////////////////////////////// class COPCrysis2AdjustAim : public CGoalOp { CTimeValue m_startTime; CTimeValue m_lastGood; bool m_useLastOpAsBackup; bool m_allowProne; float m_timeoutRandomness; int m_timeoutMs; int m_runningTimeoutMs; int m_nextUpdateMs; PostureManager::PostureID m_bestPostureID; PostureManager::PostureQueryID m_queryID; int RandomizeTimeInterval() const; bool ProcessQueryResult(CPipeUser* pipeUser, AsyncState queryStatus, PostureManager::PostureInfo* postureInfo); public: COPCrysis2AdjustAim(bool useLastOpAsBackup, bool allowProne, float timeout); COPCrysis2AdjustAim(const XmlNodeRef& node); virtual EGoalOpResult Execute(CPipeUser* pPipeUser); virtual void Reset(CPipeUser* pPipeUser); virtual void Serialize(TSerialize ser); virtual void DebugDraw(CPipeUser* pPipeUser) const; }; //////////////////////////////////////////////////////// // // Peek while staying in cover. // //////////////////////////////////////////////////////// class COPCrysis2Peek : public CGoalOp { CTimeValue m_startTime; CTimeValue m_lastGood; bool m_useLastOpAsBackup; float m_timeoutRandomness; int m_timeoutMs; int m_runningTimeoutMs; int m_nextUpdateMs; PostureManager::PostureID m_bestPostureID; PostureManager::PostureQueryID m_queryID; int RandomizeTimeInterval() const; bool ProcessQueryResult(CPipeUser* pipeUser, AsyncState queryStatus, PostureManager::PostureInfo* postureInfo); public: COPCrysis2Peek(bool useLastOpAsBackup, float timeout); COPCrysis2Peek(const XmlNodeRef& node); virtual EGoalOpResult Execute(CPipeUser* pPipeUser); virtual void Reset(CPipeUser* pPipeUser); virtual void Serialize(TSerialize ser); virtual void DebugDraw(CPipeUser* pPipeUser) const; }; //////////////////////////////////////////////////////////// // // HIDE - makes agent find closest hiding place and then hide there // //////////////////////////////////////////////////////// class COPCrysis2Hide : public CGoalOp { public: COPCrysis2Hide(EAIRegister location, bool exact); COPCrysis2Hide(const XmlNodeRef& node); COPCrysis2Hide(const COPCrysis2Hide& rhs); virtual ~COPCrysis2Hide(); virtual EGoalOpResult Execute(CPipeUser* pPipeUser); void UpdateMovingToCoverAnimation(CPipeUser* pPipeUser) const; virtual void ExecuteDry(CPipeUser* pPipeUser); virtual void Reset(CPipeUser* pPipeUser); virtual void Serialize(TSerialize ser); virtual void DebugDraw(CPipeUser* pPipeUser) const; private: void CreateHideTarget(CPipeUser* pPipeUser, const Vec3& pos, const Vec3& dir = Vec3_Zero); CStrongRef m_refHideTarget; EAIRegister m_location; bool m_exact; COPPathFind* m_pPathfinder; COPTrace* m_pTracer; }; //////////////////////////////////////////////////////////// // // COMMUNICATE - makes agent communicate (duh!) // //////////////////////////////////////////////////////// class COPCrysis2Communicate : public CGoalOp { public: COPCrysis2Communicate(CommID commID, CommChannelID channelID, float expirity, EAIRegister target, SCommunicationRequest::EOrdering ordering); COPCrysis2Communicate(const XmlNodeRef& node); virtual ~COPCrysis2Communicate(); EGoalOpResult Execute(CPipeUser* pPipeUser); private: CommID m_commID; CommChannelID m_channelID; SCommunicationRequest::EOrdering m_ordering; float m_expirity; EAIRegister m_target; }; //////////////////////////////////////////////////////////// // // STICKPATH - Follows an AI path, sticking to a target // projected on the path // //////////////////////////////////////////////////////////// class COPCrysis2StickPath : public CGoalOp { public: COPCrysis2StickPath(bool bFinishInRange, float fMaxStickDist, float fMinStickDist = 0.0f, bool bCanReverse = true); COPCrysis2StickPath(const XmlNodeRef& node); COPCrysis2StickPath(const COPCrysis2StickPath& rhs); virtual ~COPCrysis2StickPath(); virtual EGoalOpResult Execute(CPipeUser* pPipeUser); virtual void ExecuteDry(CPipeUser* pPipeUser); virtual void Reset(CPipeUser* pPipeUser); virtual void Serialize(TSerialize ser); private: // State execute helpers EGoalOpResult ExecuteCurrentState(CPipeUser* pPipeUser, bool bDryUpdate); bool ExecuteState_Prepare(CPuppet* pPuppet, bool bDryUpdate); bool ExecuteState_Navigate(CPuppet* pPuppet, bool bDryUpdate); bool ExecuteState_Wait(CPuppet* pPuppet, bool bDryUpdate); // Project the target onto the path void ProjectTargetOntoPath(Vec3& outPos, float& outNearestDistance, float& outDistanceAlongPath) const; // Returns true if within range of target enum ETargetRange { eTR_TooFar, eTR_InRange, eTR_TooClose, }; ETargetRange GetTargetRange(const Vec3& vMyPos) const; ETargetRange GetTargetRange(const Vec3& vMyPos, const Vec3& vTargetPos) const; // Gets the projected position to use for the vehicle based on speed settings Vec3 GetProjectedPos(CPuppet* pPuppet) const; private: // Current state enum EStates { eState_FIRST, eState_Prepare = eState_FIRST, eState_Navigate, eState_Wait, eState_COUNT, }; EStates m_State; // Current designer path shape SShape m_Path; float m_fPathLength; CWeakRef m_refTarget; CStrongRef m_refNavTarget; float m_fMinStickDistSq; float m_fMaxStickDistSq; bool m_bFinishInRange; bool m_bCanReverse; }; class COPAcquirePosition : public CGoalOp { enum COPAcquirePositionState { C2AP_INVALID, C2AP_INIT, C2AP_COMPUTING, C2AP_FAILED, }; enum COPAPComputingSubstate { C2APCS_GATHERSPANS, C2APCS_CHECKSPANS, C2APCS_VISTESTS, }; COPAcquirePositionState m_State; COPAPComputingSubstate m_SubState; EAIRegister m_target; EAIRegister m_output; Vec3 m_curPosition; Vec3 m_destination; float m_Timeout; std::vector m_Coords; const CFlightNavRegion2::NavData* m_Graph; public: COPAcquirePosition(); COPAcquirePosition(const XmlNodeRef& node); virtual ~COPAcquirePosition(); EGoalOpResult Execute(CPipeUser* pPipeUser); void ExecuteDry(CPipeUser* pPipeUser); void Reset(CPipeUser* pPipeUser); bool GetTarget(CPipeUser* pPipeUser, Vec3& target); bool SetOutput(CPipeUser* pPipeUser, Vec3& target); }; struct AStarNodeCompareFlight { bool operator()(const AStarNode& LHS, const AStarNode& RHS) const { const Vec3i& lhs = LHS.graphNodeIndex; const Vec3i& rhs = RHS.graphNodeIndex; return lhs.x + lhs.y * 1000 + lhs.z * 1000000 < rhs.x + rhs.y * 1000 + rhs.z * 1000000; } }; class NodeContainerFlight { std::set, AStarNodeCompareFlight> aStarNodes; public: AStarNode* GetAStarNode(Vec3i nodeIndex) { std::pair, AStarNodeCompareFlight>::iterator, bool> result = aStarNodes.insert(AStarNode(nodeIndex)); return const_cast*>(&*result.first); } void Clear() { aStarNodes.clear(); } }; class ClosedListFlight { std::set closedList; public: void Resize(Vec3i size) { closedList.clear(); } void Close(Vec3i index) { closedList.insert(index); } bool IsClosed(Vec3i index) const { return closedList.find(index) != closedList.end(); } //For users debug benefit they may template specialize this function: void Print() const {} }; class COPCrysis2Fly : public CGoalOpParallel { typedef CGoalOpParallel Base; enum COPCrysis2FlyState { C2F_INVALID, C2F_PATHFINDING, C2F_FOLLOWINGPATH, C2F_FOLLOW_AND_CALC_NEXT, C2F_FOLLOW_AND_SWITCH, C2F_FAILED, C2F_FAILED_TEMP, }; enum TargetResult { C2F_NO_TARGET, C2F_TARGET_FOUND, C2F_SET_PATH, }; struct Threat { EntityId threatId; Vec3 threatPos; Vec3 threatDir; Threat() { Reset(); } void Reset() { threatId = 0; threatPos = ZERO; threatDir = ZERO; } }; COPCrysis2FlyState m_State; EAIRegister m_target; Vec3 m_CurSegmentDir; Vec3 m_destination; Vec3 m_nextDestination; uint32 m_Length; uint32 m_PathSizeFinish; float m_Timeout; float m_lookAheadDist; float m_desiredSpeed; float m_currentSpeed; float m_minDistance; float m_maxDistance; int m_TargetEntity; Threat m_Threat; bool m_Circular; public: typedef GenericAStarSolver, ClosedListFlight, NodeContainerFlight> ASTARSOLVER; typedef stl::PoolAllocator SolverAllocator; private: ASTARSOLVER* m_Solver; std::vector m_PathOut; std::vector m_Reversed; const CFlightNavRegion2::NavData* m_Graph; static StaticInstance m_Solvers; ASTARSOLVER* AllocateSolver() { return new (m_Solvers->Allocate())ASTARSOLVER; } void DestroySolver(ASTARSOLVER* solver) { solver->~ASTARSOLVER(); m_Solvers->Deallocate(solver); } TargetResult GetTarget (CPipeUser* pPipeUser, Vec3& target) const; EGoalOpResult CalculateTarget (CPipeUser* pPipeUser); bool HandleThreat(CPipeUser* pPipeUser, const Vec3& lookAheadPos); public: COPCrysis2Fly(); COPCrysis2Fly(const COPCrysis2Fly& rhs); COPCrysis2Fly(const XmlNodeRef& node); virtual ~COPCrysis2Fly(); EGoalOpResult Execute(CPipeUser* pPipeUser); void ExecuteDry(CPipeUser* pPipeUser); void Reset(CPipeUser* pPipeUser); void ParseParam (const char* param, const GoalParams& value); void SendEvent (CPipeUser* pPipeUser, const char* eventName); float CheckTargetEntity(const CPipeUser* pPipeUser, const Vec3& lookAheadPos); void Serialize (TSerialize ser); }; class COPCrysis2ChaseTarget : public CGoalOpParallel { typedef CGoalOpParallel Base; enum COPCrysis2ChaseTargetState { C2F_INVALID, C2F_FINDINGLOCATION, C2F_WAITING_LOCATION_RESULT, C2F_PREPARING, C2F_CHASING, C2F_FAILED, C2F_FAILED_TEMP, }; enum TargetResult { C2F_NO_TARGET, C2F_TARGET_FOUND, C2F_SET_PATH, }; struct CandidateLocation { Vec3 point; size_t index; float fraction; float score; bool operator<(const CandidateLocation& other) const { return score > other.score; } }; typedef std::vector Candidates; COPCrysis2ChaseTargetState m_State; EAIRegister m_target; Vec3 m_destination; Vec3 m_nextDestination; float m_lookAheadDist; float m_desiredSpeed; float m_distanceMin; float m_distanceMax; QueuedRayID m_visCheckRayID[2]; size_t m_visCheckResultCount; CandidateLocation m_bestLocation; CandidateLocation m_testLocation; ListPositions m_PathOut; ListPositions m_throughOriginBuf; GoalParams m_firePauseParams; TargetResult GetTarget(CPipeUser* pPipeUser, Vec3& target, IAIObject** targetObject = 0) const; EGoalOpResult Chase(CPipeUser* pPipeUser); void TestLocation(const CandidateLocation& location, CPipeUser* pipeUser, const Vec3& target); size_t GatherCandidateLocations(float currentLocationAlong, const ListPositions& path, float pathLength, bool closed, float spacing, const Vec3& target, Candidates& candidates); Candidates m_candidates; void VisCheckRayComplete(const QueuedRayID& rayID, const RayCastResult& result); float CalculateShortestPathTo(const ListPositions& path, bool closed, size_t startIndex, float startSegmentFraction, size_t endIndex, float endSegmentFraction, ListPositions& pathOut); public: COPCrysis2ChaseTarget(); COPCrysis2ChaseTarget(const COPCrysis2ChaseTarget& rhs); COPCrysis2ChaseTarget(const XmlNodeRef& node); virtual ~COPCrysis2ChaseTarget(); EGoalOpResult Execute(CPipeUser* pPipeUser); void ExecuteDry(CPipeUser* pPipeUser); void Reset(CPipeUser* pPipeUser); void ParseParam (const char* param, const GoalParams& value); }; class COPCrysis2FlightFireWeapons : public CGoalOpParallel { enum { AI_REG_INTERNAL_TARGET = AI_REG_LAST + 1, }; enum COPCrysis2FlightFireWeaponsState { eFP_START, eFP_STOP, eFP_DONE, eFP_WAIT, eFP_WAIT_INIT, eFP_PREPARE, eFP_PAUSED, eFP_PAUSED_OVERRIDE, eFP_RUN_INDEFINITELY, }; COPCrysis2FlightFireWeaponsState m_State; COPCrysis2FlightFireWeaponsState m_NextState; Vec3 m_LastTarget; float m_InitCoolDown; float m_WaitTime; float m_minTime; float m_maxTime; float m_PausedTime; float m_PauseOverrideTime; float m_Rotation; uint32 m_SecondaryWeapons; uint32 m_targetId; EAIRegister m_target; bool m_FirePrimary; bool m_OnlyLookAt; public: COPCrysis2FlightFireWeapons(); COPCrysis2FlightFireWeapons(const XmlNodeRef& node); COPCrysis2FlightFireWeapons(EAIRegister reg, float minTime, float maxTime, bool primary, uint32 secondary); virtual ~COPCrysis2FlightFireWeapons(); EGoalOpResult Execute (CPipeUser* pPipeUser); void ExecuteDry (CPipeUser* pPipeUser); void ExecuteShoot (CPipeUser* pPipeUser, const Vec3& targetPos); void Reset (CPipeUser* pPipeUser); bool GetTarget (CPipeUser* pPipeUser, Vec3& target); void ParseParam (const char* param, const GoalParams& value); bool CalculateHitPosPlayer (CPipeUser* pPipeUser, CAIPlayer* targetPlayer, Vec3& target); bool CalculateHitPos (CPipeUser* pPipeUser, CAIObject* targetObject, Vec3& target); void Serialize (TSerialize ser); }; class COPCrysis2Hover : public CGoalOp { enum COPHoverState { CHS_INVALID, CHS_HOVERING, CHS_HOVERING_APPROACH, }; Vec3 m_InitialPos; Vec3 m_InitialForward; Vec3 m_InitialTurn; Vec3 m_CurrentTarget; float m_LastDot; float m_SwitchTime; EAIRegister m_target; bool m_Continous; COPHoverState m_State; COPHoverState m_NextState; public: COPCrysis2Hover(); COPCrysis2Hover(EAIRegister reg, bool continous); COPCrysis2Hover(const XmlNodeRef& node); virtual ~COPCrysis2Hover(); void Reset (CPipeUser* pPipeUser); EGoalOpResult Execute (CPipeUser* pPipeUser); void ExecuteDry (CPipeUser* pPipeUser); bool GetTarget(CPipeUser* pPipeUser, Vec3& target); }; #endif // CRYINCLUDE_CRYAISYSTEM_GAMESPECIFIC_GOALOP_CRYSIS2_H