Counter Strike : Global Offensive Source Code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

641 lines
21 KiB

  1. //========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: Base NPC character with AI
  4. //
  5. //=============================================================================//
  6. #ifndef AI_AGENT_H
  7. #define AI_AGENT_H
  8. #ifdef _WIN32
  9. #pragma once
  10. #endif
  11. #include "ai_debug.h"
  12. #include "ai_default.h"
  13. #include "ai_schedule.h"
  14. #include "ai_condition.h"
  15. #include "ai_task.h"
  16. #include "ai_namespaces.h"
  17. #include "bitstring.h"
  18. class CAI_Agent;
  19. #ifndef DBGFLAG_STRINGS_STRIP
  20. void DevMsg( CAI_Agent *pAI, unsigned flags, PRINTF_FORMAT_STRING const char *pszFormat, ... ) FMTFUNCTION( 3, 4 );
  21. void DevMsg( CAI_Agent *pAI, PRINTF_FORMAT_STRING const char *pszFormat, ... ) FMTFUNCTION( 2, 3 );
  22. #endif
  23. typedef CBitVec<MAX_CONDITIONS> CAI_ScheduleBits;
  24. //=============================================================================
  25. //
  26. // Constants & enumerations
  27. //
  28. //=============================================================================
  29. //
  30. // Debug bits
  31. //
  32. //-------------------------------------
  33. #ifdef AI_MONITOR_FOR_OSCILLATION
  34. struct AIScheduleChoice_t
  35. {
  36. float m_flTimeSelected;
  37. CAI_Schedule *m_pScheduleSelected;
  38. };
  39. #endif//AI_MONITOR_FOR_OSCILLATION
  40. //=============================================================================
  41. //
  42. // Types used by CAI_Agent
  43. //
  44. //=============================================================================
  45. struct AIAgentScheduleState_t
  46. {
  47. int iCurTask;
  48. TaskStatus_e fTaskStatus;
  49. float timeStarted;
  50. float timeCurTaskStarted;
  51. AI_TaskFailureCode_t taskFailureCode;
  52. int iTaskInterrupt;
  53. bool bScheduleWasInterrupted;
  54. DECLARE_SIMPLE_DATADESC();
  55. };
  56. //=============================================================================
  57. //
  58. // class CAI_Agent
  59. //
  60. //=============================================================================
  61. class CAI_Agent
  62. {
  63. public:
  64. //-----------------------------------------------------
  65. //
  66. // Initialization, cleanup, serialization, identity
  67. //
  68. CAI_Agent();
  69. ~CAI_Agent();
  70. //---------------------------------
  71. DECLARE_SIMPLE_DATADESC();
  72. virtual int Save( ISave &save );
  73. virtual int Restore( IRestore &restore );
  74. void SaveConditions( ISave &save, const CAI_ScheduleBits &conditions );
  75. void RestoreConditions( IRestore &restore, CAI_ScheduleBits *pConditions );
  76. //---------------------------------
  77. virtual void Init( void ); // derived calls after Spawn()
  78. // Flaccid implementations to satisfy boilerplate debug code
  79. virtual const char *GetDebugName() { return "CAI_Agent"; }
  80. virtual int entindex() { return -1; }
  81. public:
  82. //-----------------------------------------------------
  83. //
  84. // AI processing - thinking, schedule selection and task running
  85. //
  86. //-----------------------------------------------------
  87. // Thinking, including core thinking, movement, animation
  88. virtual void Think( void );
  89. // Core thinking (schedules & tasks)
  90. virtual void RunAI( void );// core ai function!
  91. // Called to gather up all relevant conditons
  92. virtual void GatherConditions( void );
  93. // Called immediately prior to schedule processing
  94. virtual void PrescheduleThink( void );
  95. // Called immediately after schedule processing
  96. virtual void PostscheduleThink( void ) { return; };
  97. // Notification that the current schedule, if any, is ending and a new one is being selected
  98. virtual void OnScheduleChange( void );
  99. // Notification that a new schedule is about to run its first task
  100. virtual void OnStartSchedule( int scheduleType ) {};
  101. // This function implements a decision tree for the NPC. It is responsible for choosing the next behavior (schedule)
  102. // based on the current conditions and state.
  103. virtual int SelectSchedule( void );
  104. virtual int SelectFailSchedule( int failedSchedule, int failedTask, AI_TaskFailureCode_t taskFailCode );
  105. // After the schedule has been selected, it will be processed by this function so child NPC classes can
  106. // remap base schedules into child-specific behaviors
  107. virtual int TranslateSchedule( int scheduleType ) { return scheduleType; }
  108. virtual void StartTask( const Task_t *pTask );
  109. virtual void RunTask( const Task_t *pTask );
  110. virtual void ClearTransientConditions();
  111. void ForceGatherConditions() { m_bForceConditionsGather = true; } // Force an NPC out of PVS to call GatherConditions on next think
  112. enum
  113. {
  114. SCHED_NONE = 0,
  115. SCHED_FAIL,
  116. NEXT_SCHEDULE,
  117. TASK_INVALID = 0,
  118. TASK_SET_SCHEDULE,
  119. NEXT_TASK,
  120. COND_NONE = 0, // A way for a function to return no condition to get
  121. COND_TASK_FAILED,
  122. COND_SCHEDULE_DONE,
  123. COND_NO_CUSTOM_INTERRUPTS, // Don't call BuildScheduleTestBits for this schedule. Used for schedules that must strictly control their interruptibility.
  124. NEXT_CONDITION,
  125. };
  126. protected:
  127. // Used by derived classes to chain a task to a task that might not be the
  128. // one they are currently handling:
  129. void ChainStartTask( int task, float taskData = 0 ) { Task_t tempTask = { task, taskData }; StartTask( (const Task_t *)&tempTask ); }
  130. void ChainRunTask( int task, float taskData = 0 ) { Task_t tempTask = { task, taskData }; RunTask( (const Task_t *) &tempTask ); }
  131. private:
  132. bool PreThink( void );
  133. void MaintainSchedule( void );
  134. virtual int StartTask ( Task_t *pTask ) { DevMsg( "Called wrong StartTask()\n" ); StartTask( (const Task_t *)pTask ); return 0; } // to ensure correct signature in derived classes
  135. virtual int RunTask ( Task_t *pTask ) { DevMsg( "Called wrong RunTask()\n" ); RunTask( (const Task_t *)pTask ); return 0; } // to ensure correct signature in derived classes
  136. public:
  137. //-----------------------------------------------------
  138. //
  139. // Schedules & tasks
  140. //
  141. //-----------------------------------------------------
  142. void SetSchedule( CAI_Schedule *pNewSchedule );
  143. bool SetSchedule( int localScheduleID );
  144. void SetDefaultFailSchedule( int failSchedule ) { m_failSchedule = failSchedule; }
  145. void ClearSchedule( const char *szReason );
  146. CAI_Schedule * GetCurSchedule() { return m_pSchedule; }
  147. bool IsCurSchedule( int schedId, bool fIdeal = true );
  148. virtual CAI_Schedule *GetSchedule(int localScheduleID);
  149. virtual int GetLocalScheduleId( int globalScheduleID ) { return AI_IdIsLocal( globalScheduleID ) ? globalScheduleID : GetClassScheduleIdSpace()->ScheduleGlobalToLocal( globalScheduleID ); }
  150. virtual int GetGlobalScheduleId( int localScheduleID ) { return AI_IdIsGlobal( localScheduleID ) ? localScheduleID : GetClassScheduleIdSpace()->ScheduleLocalToGlobal( localScheduleID ); }
  151. float GetTimeScheduleStarted() const { return m_ScheduleState.timeStarted; }
  152. //---------------------------------
  153. const Task_t* GetTask( void );
  154. int TaskIsRunning( void );
  155. virtual void TaskFail( AI_TaskFailureCode_t );
  156. void TaskFail( const char *pszGeneralFailText ) { TaskFail( MakeFailCode( pszGeneralFailText ) ); }
  157. void TaskComplete( bool fIgnoreSetFailedCondition = false );
  158. void TaskInterrupt() { m_ScheduleState.iTaskInterrupt++; }
  159. void ClearTaskInterrupt() { m_ScheduleState.iTaskInterrupt = 0; }
  160. int GetTaskInterrupt() const { return m_ScheduleState.iTaskInterrupt; }
  161. void TaskMovementComplete( void );
  162. inline int TaskIsComplete( void ) { return (GetTaskStatus() == TASKSTATUS_COMPLETE); }
  163. virtual const char *TaskName(int taskID);
  164. float GetTimeTaskStarted() const { return m_ScheduleState.timeCurTaskStarted; }
  165. virtual int GetLocalTaskId( int globalTaskId) { return GetClassScheduleIdSpace()->TaskGlobalToLocal( globalTaskId ); }
  166. virtual const char *GetSchedulingErrorName() { return "CAI_Agent"; }
  167. protected:
  168. static bool LoadSchedules(void);
  169. virtual bool LoadedSchedules(void);
  170. virtual void BuildScheduleTestBits( void );
  171. //---------------------------------
  172. // This is the main call to select/translate a schedule
  173. virtual CAI_Schedule *GetNewSchedule( void );
  174. virtual CAI_Schedule *GetFailSchedule( void );
  175. private:
  176. // This function maps the type through TranslateSchedule() and then retrieves the pointer
  177. // to the actual CAI_Schedule from the database of schedules available to this class.
  178. CAI_Schedule * GetScheduleOfType( int scheduleType );
  179. bool FHaveSchedule( void );
  180. bool FScheduleDone ( void );
  181. CAI_Schedule * ScheduleInList( const char *pName, CAI_Schedule **pList, int listCount );
  182. int GetScheduleCurTaskIndex() const { return m_ScheduleState.iCurTask; }
  183. inline int IncScheduleCurTaskIndex();
  184. inline void ResetScheduleCurTaskIndex();
  185. void NextScheduledTask ( void );
  186. bool IsScheduleValid ( void );
  187. // Selecting the ideal state
  188. // Various schedule selections based on NPC_STATE
  189. void OnStartTask( void ) { SetTaskStatus( TASKSTATUS_RUN_MOVE_AND_TASK ); }
  190. void SetTaskStatus( TaskStatus_e status ) { m_ScheduleState.fTaskStatus = status; }
  191. TaskStatus_e GetTaskStatus() const { return m_ScheduleState.fTaskStatus; }
  192. void DiscardScheduleState();
  193. //---------------------------------
  194. CAI_Schedule * m_pSchedule;
  195. int m_IdealSchedule;
  196. AIAgentScheduleState_t m_ScheduleState;
  197. int m_failSchedule; // Schedule type to choose if current schedule fails
  198. public:
  199. //-----------------------------------------------------
  200. //
  201. // Conditions
  202. //
  203. //-----------------------------------------------------
  204. virtual const char* ConditionName(int conditionID);
  205. virtual void RemoveIgnoredConditions ( void );
  206. void SetCondition( int iCondition /*, bool state = true*/ );
  207. bool HasCondition( int iCondition );
  208. bool HasCondition( int iCondition, bool bUseIgnoreConditions );
  209. bool HasInterruptCondition( int iCondition );
  210. bool HasConditionsToInterruptSchedule( int nLocalScheduleID );
  211. void ClearCondition( int iCondition );
  212. void ClearConditions( int *pConditions, int nConditions );
  213. void SetIgnoreConditions( int *pConditions, int nConditions );
  214. void ClearIgnoreConditions( int *pConditions, int nConditions );
  215. bool ConditionInterruptsCurSchedule( int iCondition );
  216. bool ConditionInterruptsSchedule( int schedule, int iCondition );
  217. void SetCustomInterruptCondition( int nCondition );
  218. bool IsCustomInterruptConditionSet( int nCondition );
  219. void ClearCustomInterruptCondition( int nCondition );
  220. void ClearCustomInterruptConditions( void );
  221. bool ConditionsGathered() const { return m_bConditionsGathered; }
  222. const CAI_ScheduleBits &AccessConditionBits() const { return m_Conditions; }
  223. CAI_ScheduleBits & AccessConditionBits() { return m_Conditions; }
  224. private:
  225. CAI_ScheduleBits m_Conditions;
  226. CAI_ScheduleBits m_CustomInterruptConditions; //Bit string assembled by the schedule running, then
  227. //modified by leaf classes to suit their needs
  228. CAI_ScheduleBits m_ConditionsPreIgnore;
  229. CAI_ScheduleBits m_InverseIgnoreConditions;
  230. bool m_bForceConditionsGather;
  231. bool m_bConditionsGathered;
  232. public:
  233. //-----------------------------------------------------
  234. //
  235. // Core mapped data structures
  236. //
  237. // String Registries for default AI Shared by all CBaseNPCs
  238. // These are used only during initialization and in debug
  239. //-----------------------------------------------------
  240. static void InitSchedulingTables();
  241. static CAI_GlobalScheduleNamespace *GetSchedulingSymbols() { return &gm_SchedulingSymbols; }
  242. static CAI_ClassScheduleIdSpace &AccessClassScheduleIdSpaceDirect() { return gm_ClassScheduleIdSpace; }
  243. virtual CAI_ClassScheduleIdSpace * GetClassScheduleIdSpace() { return &gm_ClassScheduleIdSpace; }
  244. static int GetScheduleID (const char* schedName);
  245. static int GetConditionID (const char* condName);
  246. static int GetTaskID (const char* taskName);
  247. private:
  248. friend class CAI_SystemHook;
  249. friend class CAI_SchedulesManager;
  250. static bool LoadDefaultSchedules(void);
  251. static void InitDefaultScheduleSR(void);
  252. static void InitDefaultTaskSR(void);
  253. static void InitDefaultConditionSR(void);
  254. static CAI_GlobalScheduleNamespace gm_SchedulingSymbols;
  255. static CAI_ClassScheduleIdSpace gm_ClassScheduleIdSpace;
  256. public:
  257. //----------------------------------------------------
  258. // Debugging tools
  259. //
  260. // -----------------------------
  261. // Debuging Fields and Methods
  262. // -----------------------------
  263. int m_AgentDebugOverlays;
  264. Vector m_vecAgentDebugOverlaysPos;
  265. const char* m_failText; // Text of why it failed
  266. const char* m_interruptText; // Text of why schedule interrupted
  267. CAI_Schedule* m_failedSchedule; // The schedule that failed last
  268. CAI_Schedule* m_interuptSchedule; // The schedule that was interrupted last
  269. int m_nDebugCurIndex; // Index used for stepping through AI
  270. void DumpTaskTimings();
  271. virtual int DrawDebugTextOverlays( int text_offset );
  272. void EntityText( int text_offset, const char *text, float flDuration, int r = 255, int g = 255, int b = 255, int a = 255 );
  273. int GetDebugOverlayFlags() {return m_AgentDebugOverlays;}
  274. string_t GetEntityName() { return NULL_STRING; }
  275. };
  276. //-----------------------------------------------------------------------------
  277. //-----------------------------------------------------------------------------
  278. inline int CAI_Agent::IncScheduleCurTaskIndex()
  279. {
  280. m_ScheduleState.iTaskInterrupt = 0;
  281. return ++m_ScheduleState.iCurTask;
  282. }
  283. //-----------------------------------------------------------------------------
  284. //-----------------------------------------------------------------------------
  285. inline void CAI_Agent::ResetScheduleCurTaskIndex()
  286. {
  287. m_ScheduleState.iCurTask = 0;
  288. m_ScheduleState.iTaskInterrupt = 0;
  289. }
  290. // ============================================================================
  291. // Macros for introducing new schedules in sub-classes
  292. //
  293. // Strings registries and schedules use unique ID's for each item, but
  294. // sub-class enumerations are non-unique, so we translate between the
  295. // enumerations and unique ID's
  296. // ============================================================================
  297. #define AI_BEGIN_AGENT_( derivedClass, baseClass ) \
  298. IMPLEMENT_AGENT(derivedClass, baseClass ) \
  299. void derivedClass::InitCustomSchedules( void ) \
  300. { \
  301. typedef derivedClass CNpc; \
  302. typedef baseClass CAgentBase; \
  303. const char *pszClassName = #derivedClass; \
  304. \
  305. CUtlVector<char *> schedulesToLoad; \
  306. CUtlVector<AIScheduleLoadFunc_t> reqiredOthers; \
  307. CAI_AgentNamespaceInfos scheduleIds; \
  308. CAI_AgentNamespaceInfos taskIds; \
  309. CAI_AgentNamespaceInfos conditionIds;
  310. #define AI_BEGIN_AGENT( derivedClass ) \
  311. AI_BEGIN_AGENT_( derivedClass, BaseClass )
  312. //-----------------
  313. #define DEFINE_SCHEDULE( id, text ) \
  314. scheduleIds.PushBack( #id, id ); \
  315. char * g_psz##id = \
  316. "\n Schedule" \
  317. "\n " #id \
  318. text \
  319. "\n"; \
  320. schedulesToLoad.AddToTail( (char *)g_psz##id );
  321. //-----------------
  322. #define DECLARE_CONDITION( id ) \
  323. conditionIds.PushBack( #id, id );
  324. //-----------------
  325. #define DECLARE_TASK( id ) \
  326. taskIds.PushBack( #id, id );
  327. //-----------------
  328. // IDs are stored and then added in order due to constraints in the namespace implementation
  329. #define AI_END_AGENT() \
  330. \
  331. int i; \
  332. \
  333. CNpc::AccessClassScheduleIdSpaceDirect().Init( pszClassName, CAgentBase::GetSchedulingSymbols(), &CAgentBase::AccessClassScheduleIdSpaceDirect() ); \
  334. \
  335. scheduleIds.Sort(); \
  336. taskIds.Sort(); \
  337. conditionIds.Sort(); \
  338. \
  339. for ( i = 0; i < scheduleIds.Count(); i++ ) \
  340. { \
  341. ADD_CUSTOM_SCHEDULE_NAMED( CNpc, scheduleIds[i].pszName, scheduleIds[i].localId ); \
  342. } \
  343. \
  344. for ( i = 0; i < taskIds.Count(); i++ ) \
  345. { \
  346. ADD_CUSTOM_TASK_NAMED( CNpc, taskIds[i].pszName, taskIds[i].localId ); \
  347. } \
  348. \
  349. for ( i = 0; i < conditionIds.Count(); i++ ) \
  350. { \
  351. if ( AIAgentValidateConditionLimits( conditionIds[i].pszName ) ) \
  352. { \
  353. ADD_CUSTOM_CONDITION_NAMED( CNpc, conditionIds[i].pszName, conditionIds[i].localId ); \
  354. } \
  355. } \
  356. \
  357. for ( i = 0; i < reqiredOthers.Count(); i++ ) \
  358. { \
  359. (*reqiredOthers[i])(); \
  360. } \
  361. \
  362. for ( i = 0; i < schedulesToLoad.Count(); i++ ) \
  363. { \
  364. if ( CNpc::gm_SchedLoadStatus.fValid ) \
  365. { \
  366. CNpc::gm_SchedLoadStatus.fValid = g_AI_AgentSchedulesManager.LoadSchedulesFromBuffer( pszClassName, schedulesToLoad[i], &AccessClassScheduleIdSpaceDirect(), GetSchedulingSymbols() ); \
  367. } \
  368. else \
  369. break; \
  370. } \
  371. }
  372. inline bool AIAgentValidateConditionLimits( const char *pszNewCondition )
  373. {
  374. int nGlobalConditions = CAI_Agent::GetSchedulingSymbols()->NumConditions();
  375. if ( nGlobalConditions >= MAX_CONDITIONS )
  376. {
  377. AssertMsg2( 0, "Exceeded max number of conditions (%d), ignoring condition %s\n", MAX_CONDITIONS, pszNewCondition );
  378. DevWarning( "Exceeded max number of conditions (%d), ignoring condition %s\n", MAX_CONDITIONS, pszNewCondition );
  379. return false;
  380. }
  381. return true;
  382. }
  383. //-------------------------------------
  384. struct AI_AgentNamespaceAddInfo_t
  385. {
  386. AI_AgentNamespaceAddInfo_t( const char *pszName, int localId )
  387. : pszName( pszName ),
  388. localId( localId )
  389. {
  390. }
  391. const char *pszName;
  392. int localId;
  393. };
  394. class CAI_AgentNamespaceInfos : public CUtlVector<AI_AgentNamespaceAddInfo_t>
  395. {
  396. public:
  397. void PushBack( const char *pszName, int localId )
  398. {
  399. AddToTail( AI_AgentNamespaceAddInfo_t( pszName, localId ) );
  400. }
  401. void Sort()
  402. {
  403. CUtlVector<AI_AgentNamespaceAddInfo_t>::Sort( Compare );
  404. }
  405. private:
  406. static int __cdecl Compare(const AI_AgentNamespaceAddInfo_t *pLeft, const AI_AgentNamespaceAddInfo_t *pRight )
  407. {
  408. return pLeft->localId - pRight->localId;
  409. }
  410. };
  411. //-------------------------------------
  412. // Declares the static variables that hold the string registry offset for the new subclass
  413. // as well as the initialization in schedule load functions
  414. struct AI_AgentSchedLoadStatus_t
  415. {
  416. bool fValid;
  417. int signature;
  418. };
  419. // Load schedules pulled out to support stepping through with debugger
  420. inline bool AI_DoLoadSchedules( bool (*pfnBaseLoad)(), void (*pfnInitCustomSchedules)(),
  421. AI_AgentSchedLoadStatus_t *pLoadStatus )
  422. {
  423. (*pfnBaseLoad)();
  424. if (pLoadStatus->signature != g_AI_AgentSchedulesManager.GetScheduleLoadSignature())
  425. {
  426. (*pfnInitCustomSchedules)();
  427. pLoadStatus->fValid = true;
  428. pLoadStatus->signature = g_AI_AgentSchedulesManager.GetScheduleLoadSignature();
  429. }
  430. return pLoadStatus->fValid;
  431. }
  432. //-------------------------------------
  433. typedef bool (*AIScheduleLoadFunc_t)();
  434. // @Note (toml 02-16-03): The following class exists to allow us to establish an anonymous friendship
  435. // in DEFINE_AGENT. The particulars of this implementation is almost entirely
  436. // defined by bugs in MSVC 6.0
  437. class AgentScheduleLoadHelperImpl
  438. {
  439. public:
  440. template <typename T>
  441. static AIScheduleLoadFunc_t AccessScheduleLoadFunc(T *)
  442. {
  443. return (&T::LoadSchedules);
  444. }
  445. };
  446. //-------------------------------------
  447. #define DEFINE_AGENT()\
  448. static AI_AgentSchedLoadStatus_t gm_SchedLoadStatus; \
  449. static CAI_ClassScheduleIdSpace gm_ClassScheduleIdSpace; \
  450. static const char * gm_pszErrorClassName;\
  451. \
  452. static CAI_ClassScheduleIdSpace & AccessClassScheduleIdSpaceDirect() { return gm_ClassScheduleIdSpace; } \
  453. virtual CAI_ClassScheduleIdSpace * GetClassScheduleIdSpace() { return &gm_ClassScheduleIdSpace; } \
  454. virtual const char * GetSchedulingErrorName() { return gm_pszErrorClassName; } \
  455. \
  456. static void InitCustomSchedules(void);\
  457. \
  458. static bool LoadSchedules(void);\
  459. virtual bool LoadedSchedules(void); \
  460. \
  461. friend class AgentScheduleLoadHelperImpl; \
  462. \
  463. class CScheduleLoader \
  464. { \
  465. public: \
  466. CScheduleLoader(); \
  467. } m_ScheduleLoader; \
  468. \
  469. friend class CScheduleLoader;
  470. //-------------------------------------
  471. #define IMPLEMENT_AGENT(derivedClass, baseClass)\
  472. AI_AgentSchedLoadStatus_t derivedClass::gm_SchedLoadStatus = { true, -1 }; \
  473. CAI_ClassScheduleIdSpace derivedClass::gm_ClassScheduleIdSpace; \
  474. const char * derivedClass::gm_pszErrorClassName = #derivedClass; \
  475. \
  476. derivedClass::CScheduleLoader::CScheduleLoader()\
  477. { \
  478. derivedClass::LoadSchedules(); \
  479. } \
  480. \
  481. /* --------------------------------------------- */ \
  482. /* Load schedules for this type of NPC */ \
  483. /* --------------------------------------------- */ \
  484. bool derivedClass::LoadSchedules(void)\
  485. {\
  486. return AI_DoLoadSchedules( derivedClass::baseClass::LoadSchedules, \
  487. derivedClass::InitCustomSchedules, \
  488. &derivedClass::gm_SchedLoadStatus ); \
  489. }\
  490. \
  491. bool derivedClass::LoadedSchedules(void) \
  492. { \
  493. return derivedClass::gm_SchedLoadStatus.fValid;\
  494. }
  495. //-------------------------------------
  496. #define ADD_CUSTOM_SCHEDULE_NAMED(derivedClass,schedName,schedEN)\
  497. if ( !derivedClass::AccessClassScheduleIdSpaceDirect().AddSchedule( schedName, schedEN, derivedClass::gm_pszErrorClassName ) ) return;
  498. #define ADD_CUSTOM_SCHEDULE(derivedClass,schedEN) ADD_CUSTOM_SCHEDULE_NAMED(derivedClass,#schedEN,schedEN)
  499. #define ADD_CUSTOM_TASK_NAMED(derivedClass,taskName,taskEN)\
  500. if ( !derivedClass::AccessClassScheduleIdSpaceDirect().AddTask( taskName, taskEN, derivedClass::gm_pszErrorClassName ) ) return;
  501. #define ADD_CUSTOM_TASK(derivedClass,taskEN) ADD_CUSTOM_TASK_NAMED(derivedClass,#taskEN,taskEN)
  502. #define ADD_CUSTOM_CONDITION_NAMED(derivedClass,condName,condEN)\
  503. if ( !derivedClass::AccessClassScheduleIdSpaceDirect().AddCondition( condName, condEN, derivedClass::gm_pszErrorClassName ) ) return;
  504. #define ADD_CUSTOM_CONDITION(derivedClass,condEN) ADD_CUSTOM_CONDITION_NAMED(derivedClass,#condEN,condEN)
  505. #endif // AI_AGENT_H