//========= Copyright Valve Corporation, All rights reserved. ============// // // Purpose: Hint node utilities and functions. // // $NoKeywords: $ //=============================================================================// #ifndef AI_HINT_H #define AI_HINT_H #pragma once #include "ai_initutils.h" #include "tier1/utlmap.h" // Flags for FindHintNode #define bits_HINT_NODE_NONE 0x00000000 #define bits_HINT_NODE_VISIBLE 0x00000001 #define bits_HINT_NODE_NEAREST 0x00000002 // Choose the node nearest me #define bits_HINT_NODE_RANDOM \ 0x00000004 // Find a random hintnode meeting other criteria #define bits_HINT_NODE_CLEAR \ 0x00000008 // Only choose nodes that have clear room for my bounding box // (requires NPC) #define bits_HINT_NODE_USE_GROUP \ 0x00000010 // Use the NPC's hintgroup when searching for a node (requires // NPC) #define bits_HINT_NODE_VISIBLE_TO_PLAYER 0x00000020 #define bits_HINT_NODE_NOT_VISIBLE_TO_PLAYER 0x00000040 #define bits_HINT_NODE_REPORT_FAILURES 0x00000080 #define bits_HINT_NODE_IN_VIEWCONE 0x00000100 #define bits_HINT_NODE_IN_AIMCONE 0x00000200 #define bits_HINT_NPC_IN_NODE_FOV \ 0x00000400 // Is the searcher inside the hint node's FOV? #define bits_HINT_NOT_CLOSE_TO_ENEMY \ 0x00000800 // Hint must not be within 30 feet of my enemy #define bits_HINT_HAS_LOS_TO_PLAYER \ 0x00001000 // Like VISIBLE_TO_PLAYER but doesn't care about player's facing #define bits_HAS_EYEPOSITION_LOS_TO_PLAYER \ 0x00002000 // Like HAS LOS TO PLAYER, but checks NPC's eye position at the // node, not node origin. //----------------------------------------------------------------------------- // // hints - these MUST coincide with the HINTS listed under // info_node in the FGD file! // // For debugging, they must also coincide with g_pszHintDescriptions. // //----------------------------------------------------------------------------- enum Hint_e { HINT_ANY = -1, HINT_NONE = 0, HINT_NOT_USED_WORLD_DOOR, HINT_WORLD_WINDOW, HINT_NOT_USED_WORLD_BUTTON, HINT_NOT_USED_WORLD_MACHINERY, HINT_NOT_USED_WORLD_LEDGE, HINT_NOT_USED_WORLD_LIGHT_SOURCE, HINT_NOT_USED_WORLD_HEAT_SOURCE, HINT_NOT_USED_WORLD_BLINKING_LIGHT, HINT_NOT_USED_WORLD_BRIGHT_COLORS, HINT_NOT_USED_WORLD_HUMAN_BLOOD, HINT_NOT_USED_WORLD_ALIEN_BLOOD, HINT_WORLD_WORK_POSITION, HINT_WORLD_VISUALLY_INTERESTING, HINT_WORLD_VISUALLY_INTERESTING_DONT_AIM, HINT_WORLD_INHIBIT_COMBINE_MINES, HINT_WORLD_VISUALLY_INTERESTING_STEALTH, HINT_TACTICAL_COVER_MED = 100, HINT_TACTICAL_COVER_LOW, HINT_TACTICAL_SPAWN, HINT_TACTICAL_PINCH, // Exit / entrance to an arena HINT_NOT_USED_TACTICAL_GUARD, HINT_TACTICAL_ENEMY_DISADVANTAGED, // Disadvantageous position for the // enemy HINT_NOT_USED_HEALTH_KIT, HINT_NOT_USED_URBAN_STREETCORNER = 200, HINT_NOT_USED_URBAN_STREETLAMP, HINT_NOT_USED_URBAN_DARK_SPOT, HINT_NOT_USED_URBAN_POSTER, HINT_NOT_USED_URBAN_SHELTER, HINT_NOT_USED_ASSASSIN_SECLUDED = 300, HINT_NOT_USED_ASSASSIN_RAFTERS, HINT_NOT_USED_ASSASSIN_GROUND, HINT_NOT_USED_ASSASSIN_MONKEYBARS, HINT_ANTLION_BURROW_POINT = 400, HINT_ANTLION_THUMPER_FLEE_POINT, HINT_HEADCRAB_BURROW_POINT = 450, HINT_HEADCRAB_EXIT_POD_POINT, HINT_NOT_USED_ROLLER_PATROL_POINT = 500, HINT_NOT_USED_ROLLER_CLEANUP_POINT, HINT_NOT_USED_PSTORM_ROCK_SPAWN = 600, HINT_CROW_FLYTO_POINT = 700, // TF2 Hints HINT_BUG_PATROL_POINT = 800, // HL2 Hints HINT_FOLLOW_WAIT_POINT = 900, HINT_JUMP_OVERRIDE = 901, HINT_PLAYER_SQUAD_TRANSITON_POINT = 902, HINT_NPC_EXIT_POINT = 903, HINT_STRIDER_NODE = 904, HINT_PLAYER_ALLY_MOVE_AWAY_DEST = 950, HINT_PLAYER_ALLY_FEAR_DEST, // HL1 port hints HINT_HL1_WORLD_MACHINERY = 1000, HINT_HL1_WORLD_BLINKING_LIGHT, HINT_HL1_WORLD_HUMAN_BLOOD, HINT_HL1_WORLD_ALIEN_BLOOD, // CS port hints HINT_CSTRIKE_HOSTAGE_ESCAPE = 1100, }; const char *GetHintTypeDescription(Hint_e iHintType); const char *GetHintTypeDescription(CAI_Hint *pHint); //----------------------------------------------------------------------------- // CHintCriteria //----------------------------------------------------------------------------- class CHintCriteria { public: CHintCriteria(); ~CHintCriteria(); bool HasFlag(int bitmask) const { return (m_iFlags & bitmask) != 0; } void SetFlag(int bitmask); void ClearFlag(int bitmask); void SetGroup(string_t group); string_t GetGroup(void) const { return m_strGroup; } int GetFirstHintType(void) const { return m_iFirstHintType; } int GetLastHintType(void) const { return m_iLastHintType; } bool MatchesHintType(int hintType) const; bool MatchesSingleHintType() const; bool HasIncludeZones(void) const { return (m_zoneInclude.Count() != 0); } bool HasExcludeZones(void) const { return (m_zoneExclude.Count() != 0); } void AddIncludePosition(const Vector &position, float radius); void AddExcludePosition(const Vector &position, float radius); void SetHintType(int hintType); void SetHintTypeRange(int firstType, int lastType); void AddHintType(int hintType); bool InIncludedZone(const Vector &testPosition) const; bool InExcludedZone(const Vector &testPosition) const; int NumHintTypes() const; int GetHintType(int idx) const; private: struct hintZone_t { Vector position; float radiussqr; }; typedef CUtlVector zoneList_t; void AddZone(zoneList_t &list, const Vector &position, float radius); bool InZone(const zoneList_t &zone, const Vector &testPosition) const; CUtlVector m_HintTypes; int m_iFlags; int m_iFirstHintType; int m_iLastHintType; string_t m_strGroup; zoneList_t m_zoneInclude; zoneList_t m_zoneExclude; }; class CAI_Node; //----------------------------------------------------------------------------- // CAI_HintManager //----------------------------------------------------------------------------- DECLARE_POINTER_HANDLE(AIHintIter_t); class CAIHintVector : public CUtlVector { public: CAIHintVector() : CUtlVector(1, 0) {} CAIHintVector(const CAIHintVector &src) { CopyArray(src.Base(), src.Count()); } CAIHintVector &operator=(const CAIHintVector &src) { CopyArray(src.Base(), src.Count()); return *this; } }; class CAI_HintManager { friend class CAI_Hint; public: // Hint node creation static CAI_Hint *CreateHint(HintNodeData *pNodeData, const char *pMapData = NULL); static void DrawHintOverlays(float flDrawDuration); static void AddHint(CAI_Hint *pTestHint); static void RemoveHint(CAI_Hint *pTestHint); static void AddHintByType(CAI_Hint *pHint); static void RemoveHintByType(CAI_Hint *pHintToRemove); // Interface for searching the hint node list static CAI_Hint *FindHint(CAI_BaseNPC *pNPC, const Vector &position, const CHintCriteria &hintCriteria); static CAI_Hint *FindHint(CAI_BaseNPC *pNPC, const CHintCriteria &hintCriteria); static CAI_Hint *FindHint(const Vector &position, const CHintCriteria &hintCriteria); static CAI_Hint *FindHint(CAI_BaseNPC *pNPC, Hint_e nHintType, int nFlags, float flMaxDist, const Vector *pMaxDistFrom = NULL); // Purpose: Finds a random suitable hint within the requested radious of the // npc static CAI_Hint *FindHintRandom(CAI_BaseNPC *pNPC, const Vector &position, const CHintCriteria &hintCriteria); static int FindAllHints(CAI_BaseNPC *pNPC, const Vector &position, const CHintCriteria &hintCriteria, CUtlVector *pResult); static int FindAllHints(const Vector &position, const CHintCriteria &hintCriteria, CUtlVector *pResult) { return FindAllHints(NULL, position, hintCriteria, pResult); } static int FindAllHints(CAI_BaseNPC *pNPC, const CHintCriteria &hintCriteria, CUtlVector *pResult) { return FindAllHints(pNPC, pNPC->GetAbsOrigin(), hintCriteria, pResult); } static int GetFlags(const char *token); static CAI_Hint *GetFirstHint(AIHintIter_t *pIter); static CAI_Hint *GetNextHint(AIHintIter_t *pIter); static void DumpHints(); static void ValidateHints(); private: enum { // MUST BE POWER OF 2 HINT_HISTORY = (1 << 3), HINT_HISTORY_MASK = (HINT_HISTORY - 1) }; static CAI_Hint *AddFoundHint(CAI_Hint *hint); static int GetFoundHintCount(); static CAI_Hint *GetFoundHint(int index); static CAI_Hint *GetLastFoundHint(); static void ResetFoundHints(); static bool IsInFoundHintList(CAI_Hint *hint); static int gm_nFoundHintIndex; static CAI_Hint *gm_pLastFoundHints[HINT_HISTORY]; // Last used hint static CAIHintVector gm_AllHints; // A linked list of all hints static CUtlMap gm_TypedHints; }; //----------------------------------------------------------------------------- // CAI_Hint //----------------------------------------------------------------------------- class CAI_Hint : public CServerOnlyEntity { DECLARE_CLASS(CAI_Hint, CServerOnlyEntity); public: CAI_Hint(void); ~CAI_Hint(void); // Interface for specific nodes bool Lock(CBaseEntity *pNPC); // Makes unavailable for hints void Unlock(float delay = 0.0); // Makes available for hints after delay bool IsLocked(void); // Whether this node is available for use. bool IsLockedBy( CBaseEntity *pNPC); // Whether this node is available for use. void GetPosition(CBaseCombatCharacter *pBCC, Vector *vPosition); void GetPosition(Hull_t hull, Vector *vPosition); Vector GetDirection(void); float Yaw(void); CAI_Node *GetNode(void); string_t GetGroup(void) const { return m_NodeData.strGroup; } CBaseEntity *User(void) const { return m_hHintOwner; }; Hint_e HintType(void) const { return (Hint_e)m_NodeData.nHintType; }; void SetHintType(int hintType, bool force = false); string_t HintActivityName(void) const { return m_NodeData.iszActivityName; } int GetTargetNode(void) const { return m_nTargetNodeID; } bool IsDisabled(void) const { return (m_NodeData.iDisabled != 0); } void SetDisabled(bool bDisabled) { m_NodeData.iDisabled = bDisabled; } void DisableForSeconds(float flSeconds); void EnableThink(); void FixupTargetNode(); void NPCStartedUsing(CAI_BaseNPC *pNPC); void NPCStoppedUsing(CAI_BaseNPC *pNPC); HintIgnoreFacing_t GetIgnoreFacing() const { return m_NodeData.fIgnoreFacing; } NPC_STATE GetMinState() const { return m_NodeData.minState; } NPC_STATE GetMaxState() const { return m_NodeData.maxState; } int GetNodeId() { return m_NodeData.nNodeID; } int GetWCId() { return m_NodeData.nWCNodeID; } bool HintMatchesCriteria(CAI_BaseNPC *pNPC, const CHintCriteria &hintCriteria, const Vector &position, float *flNearestDistance, bool bIgnoreLock = false, bool bIgnoreHintType = false); bool IsInNodeFOV(CBaseEntity *pOther); private: void Spawn(void); virtual void Activate(); virtual void UpdateOnRemove(void); int DrawDebugTextOverlays(void); virtual int ObjectCaps(void) { return (BaseClass::ObjectCaps() & ~FCAP_ACROSS_TRANSITION); } virtual void OnRestore(); bool IsViewable(void); // Input handlers void InputEnableHint(inputdata_t &inputdata); void InputDisableHint(inputdata_t &inputdata); private: HintNodeData m_NodeData; int m_nTargetNodeID; EHANDLE m_hHintOwner; // Is hint locked (being used by NPC / NPC en-route // to use it) float m_flNextUseTime; // When can I be used again? COutputEHANDLE m_OnNPCStartedUsing; // Triggered when an NPC has actively // begun to use the node. COutputEHANDLE m_OnNPCStoppedUsing; // Triggered when an NPC has finished // using this node. float m_nodeFOV; Vector m_vecForward; // The next hint in list of all hints friend class CAI_HintManager; DECLARE_DATADESC(); }; #define SF_ALLOW_JUMP_UP 65536 #endif // AI_HINT_H