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.

1859 lines
66 KiB

  1. // NextBotBehaviorEngine.h
  2. // Behavioral system constructed from Actions
  3. // Author: Michael Booth, April 2006
  4. // Copyright (c) 2007 Turtle Rock Studios, Inc. - All Rights Reserved
  5. #ifndef _BEHAVIOR_ENGINE_H_
  6. #define _BEHAVIOR_ENGINE_H_
  7. #include "fmtstr.h"
  8. #include "NextBotEventResponderInterface.h"
  9. #include "NextBotContextualQueryInterface.h"
  10. #include "NextBotDebug.h"
  11. //#define DEBUG_BEHAVIOR_MEMORY
  12. extern ConVar NextBotDebugHistory;
  13. /**
  14. * Notes:
  15. *
  16. * By using return results to cause transitions, we ensure the atomic-ness
  17. * of these transitions. For instance, it is not possible to change to a
  18. * new Action and continue execution of code in the current Action.
  19. *
  20. * Creation and deletion of Actions during transitions allows passing of
  21. * type-safe arguments between Actions via constructors.
  22. *
  23. * Events are propagated to each Action in the hierarchy. If an
  24. * action is suspended for another action, it STILL RECEIVES EVENTS
  25. * that are not handled by the events "above it" in the suspend stack.
  26. * In other words, the active Action gets the first response, and if it
  27. * returns CONTINUE, the Action buried beneath it can process it,
  28. * and so on deeper into the stack of suspended Actions.
  29. *
  30. * About events:
  31. * It is not possible to have event handlers instantaneously change
  32. * state upon return due to out-of-order and recurrence issues, not
  33. * to mention deleting the state out from under itself. Therefore,
  34. * events return DESIRED results, and the highest priority result
  35. * is executed at the next Update().
  36. *
  37. * About buried Actions causing SUSPEND_FOR results:
  38. * If a buried Action reacts to an event by returning a SUSPEND_FOR,
  39. * the new interrupting Action is put at the TOP of the stack, burying
  40. * whatever Action was there.
  41. *
  42. */
  43. // forward declaration
  44. template < typename Actor > class Action;
  45. /**
  46. * The possible consequences of an Action
  47. */
  48. enum ActionResultType
  49. {
  50. CONTINUE, // continue executing this action next frame - nothing has changed
  51. CHANGE_TO, // change actions next frame
  52. SUSPEND_FOR, // put the current action on hold for the new action
  53. DONE, // this action has finished, resume suspended action
  54. SUSTAIN, // for use with event handlers - a way to say "It's important to keep doing what I'm doing"
  55. };
  56. //----------------------------------------------------------------------------------------------
  57. /**
  58. * Actions and Event processors return results derived from this class.
  59. * Do not assemble this yourself - use the Continue(), ChangeTo(), Done(), and SuspendFor()
  60. * methods within Action.
  61. */
  62. template < typename Actor >
  63. struct IActionResult
  64. {
  65. IActionResult( ActionResultType type = CONTINUE, Action< Actor > *action = NULL, const char *reason = NULL )
  66. {
  67. m_type = type;
  68. m_action = action;
  69. m_reason = reason;
  70. }
  71. bool IsDone( void ) const
  72. {
  73. return ( m_type == DONE );
  74. }
  75. bool IsContinue( void ) const
  76. {
  77. return ( m_type == CONTINUE );
  78. }
  79. bool IsRequestingChange( void ) const
  80. {
  81. return ( m_type == CHANGE_TO || m_type == SUSPEND_FOR || m_type == DONE );
  82. }
  83. const char *GetTypeName( void ) const
  84. {
  85. switch ( m_type )
  86. {
  87. case CHANGE_TO: return "CHANGE_TO";
  88. case SUSPEND_FOR: return "SUSPEND_FOR";
  89. case DONE: return "DONE";
  90. case SUSTAIN: return "SUSTAIN";
  91. default:
  92. case CONTINUE: return "CONTINUE";
  93. }
  94. }
  95. ActionResultType m_type;
  96. Action< Actor > *m_action;
  97. const char *m_reason;
  98. };
  99. //----------------------------------------------------------------------------------------------
  100. /**
  101. * When an Action is executed it returns this result.
  102. * Do not assemble this yourself - use the Continue(), ChangeTo(), Done(), and SuspendFor()
  103. * methods within Action.
  104. */
  105. template < typename Actor >
  106. struct ActionResult : public IActionResult< Actor >
  107. {
  108. // this is derived from IActionResult to ensure that ActionResult and EventDesiredResult cannot be silently converted
  109. ActionResult( ActionResultType type = CONTINUE, Action< Actor > *action = NULL, const char *reason = NULL ) : IActionResult< Actor >( type, action, reason ) { }
  110. };
  111. //----------------------------------------------------------------------------------------------
  112. /**
  113. * When an event is processed, it returns this DESIRED result,
  114. * which may or MAY NOT happen, depending on other event results
  115. * that occur simultaneously.
  116. * Do not assemble this yourself - use the TryContinue(), TryChangeTo(), TryDone(), TrySustain(),
  117. * and TrySuspendFor() methods within Action.
  118. */
  119. enum EventResultPriorityType
  120. {
  121. RESULT_NONE, // no result
  122. RESULT_TRY, // use this result, or toss it out, either is ok
  123. RESULT_IMPORTANT, // try extra-hard to use this result
  124. RESULT_CRITICAL // this result must be used - emit an error if it can't be
  125. };
  126. template < typename Actor >
  127. struct EventDesiredResult : public IActionResult< Actor >
  128. {
  129. EventDesiredResult( ActionResultType type = CONTINUE, Action< Actor > *action = NULL, EventResultPriorityType priority = RESULT_TRY, const char *reason = NULL ) : IActionResult< Actor >( type, action, reason )
  130. {
  131. m_priority = priority;
  132. }
  133. EventResultPriorityType m_priority;
  134. };
  135. //-------------------------------------------------------------------------------------------------------------
  136. //-------------------------------------------------------------------------------------------------------------
  137. /**
  138. * A Behavior is the root of an Action hierarchy as well as its container/manager.
  139. * Instantiate a Behavior with the root Action of your behavioral system, and
  140. * call Behavior::Update() to drive it.
  141. */
  142. template < typename Actor >
  143. class Behavior : public INextBotEventResponder, public IContextualQuery
  144. {
  145. public:
  146. DECLARE_CLASS( Behavior, INextBotEventResponder );
  147. Behavior( Action< Actor > *initialAction, const char *name = "" ) : m_name( name )
  148. {
  149. m_action = initialAction;
  150. }
  151. virtual ~Behavior()
  152. {
  153. // dig down to the bottom of the action stack and delete
  154. // that, so we don't leak action memory since action
  155. // destructors intentionally don't delete actions
  156. // "buried" underneath them.
  157. Action< Actor > *bottomAction;
  158. for( bottomAction = m_action; bottomAction && bottomAction->m_buriedUnderMe; bottomAction = bottomAction->m_buriedUnderMe )
  159. ;
  160. if ( bottomAction )
  161. {
  162. delete bottomAction;
  163. }
  164. }
  165. /**
  166. * Reset this Behavior with the given Action. If this Behavior
  167. * was already running, this will delete all current Actions and
  168. * restart the Behavior with the new one.
  169. */
  170. void Reset( Action< Actor > *action )
  171. {
  172. // find "bottom" action (see comment in destructor)
  173. Action< Actor > *bottomAction;
  174. for( bottomAction = m_action; bottomAction && bottomAction->m_buriedUnderMe; bottomAction = bottomAction->m_buriedUnderMe )
  175. ;
  176. if ( bottomAction )
  177. {
  178. delete bottomAction;
  179. }
  180. m_action = action;
  181. }
  182. /**
  183. * Return true if this Behavior contains no actions
  184. */
  185. bool IsEmpty( void ) const
  186. {
  187. return m_action == NULL;
  188. }
  189. /**
  190. * Execute this Behavior
  191. */
  192. void Update( Actor *me, float interval )
  193. {
  194. if ( me == NULL || IsEmpty() )
  195. {
  196. return;
  197. }
  198. m_action = m_action->ApplyResult( me, this, m_action->InvokeUpdate( me, this, interval ) );
  199. if ( m_action && me->IsDebugging( NEXTBOT_BEHAVIOR ) )
  200. {
  201. CFmtStr msg;
  202. me->DisplayDebugText( msg.sprintf( "%s: %s", GetName(), m_action->DebugString() ) );
  203. }
  204. }
  205. /**
  206. * If this Behavior has not been Update'd in a long time,
  207. * call Resume() to let the system know its internal state may
  208. * be out of date.
  209. */
  210. void Resume( Actor *me )
  211. {
  212. if ( me == NULL || IsEmpty() )
  213. {
  214. return;
  215. }
  216. m_action = m_action->ApplyResult( me, this, m_action->OnResume( me, NULL ) );
  217. if ( m_action && me->IsDebugging( NEXTBOT_BEHAVIOR ) )
  218. {
  219. CFmtStr msg;
  220. me->DisplayDebugText( msg.sprintf( "%s: %s", GetName(), m_action->DebugString() ) );
  221. }
  222. }
  223. const char *GetName( void ) const
  224. {
  225. return m_name;
  226. }
  227. // INextBotEventResponder propagation ----------------------------------------------------------------------
  228. virtual INextBotEventResponder *FirstContainedResponder( void ) const
  229. {
  230. return m_action;
  231. }
  232. virtual INextBotEventResponder *NextContainedResponder( INextBotEventResponder *current ) const
  233. {
  234. return NULL;
  235. }
  236. // IContextualQuery propagation ----------------------------------------------------------------------------
  237. virtual QueryResultType ShouldPickUp( const INextBot *me, CBaseEntity *item ) const // if the desired item was available right now, should we pick it up?
  238. {
  239. QueryResultType result = ANSWER_UNDEFINED;
  240. if ( m_action )
  241. {
  242. // find innermost child action
  243. Action< Actor > *action;
  244. for( action = m_action; action->m_child; action = action->m_child )
  245. ;
  246. // work our way through our containers
  247. while( action && result == ANSWER_UNDEFINED )
  248. {
  249. Action< Actor > *containingAction = action->m_parent;
  250. // work our way up the stack
  251. while( action && result == ANSWER_UNDEFINED )
  252. {
  253. result = action->ShouldPickUp( me, item );
  254. action = action->GetActionBuriedUnderMe();
  255. }
  256. action = containingAction;
  257. }
  258. }
  259. return result;
  260. }
  261. virtual QueryResultType ShouldHurry( const INextBot *me ) const // are we in a hurry?
  262. {
  263. QueryResultType result = ANSWER_UNDEFINED;
  264. if ( m_action )
  265. {
  266. // find innermost child action
  267. Action< Actor > *action;
  268. for( action = m_action; action->m_child; action = action->m_child )
  269. ;
  270. // work our way through our containers
  271. while( action && result == ANSWER_UNDEFINED )
  272. {
  273. Action< Actor > *containingAction = action->m_parent;
  274. // work our way up the stack
  275. while( action && result == ANSWER_UNDEFINED )
  276. {
  277. result = action->ShouldHurry( me );
  278. action = action->GetActionBuriedUnderMe();
  279. }
  280. action = containingAction;
  281. }
  282. }
  283. return result;
  284. }
  285. virtual QueryResultType ShouldRetreat( const INextBot *me ) const // is it time to retreat?
  286. {
  287. QueryResultType result = ANSWER_UNDEFINED;
  288. if ( m_action )
  289. {
  290. // find innermost child action
  291. Action< Actor > *action;
  292. for( action = m_action; action->m_child; action = action->m_child )
  293. ;
  294. // work our way through our containers
  295. while( action && result == ANSWER_UNDEFINED )
  296. {
  297. Action< Actor > *containingAction = action->m_parent;
  298. // work our way up the stack
  299. while( action && result == ANSWER_UNDEFINED )
  300. {
  301. result = action->ShouldRetreat( me );
  302. action = action->GetActionBuriedUnderMe();
  303. }
  304. action = containingAction;
  305. }
  306. }
  307. return result;
  308. }
  309. virtual QueryResultType IsHindrance( const INextBot *me, CBaseEntity *blocker ) const // return true if we should wait for 'blocker' that is across our path somewhere up ahead.
  310. {
  311. QueryResultType result = ANSWER_UNDEFINED;
  312. if ( m_action )
  313. {
  314. // find innermost child action
  315. Action< Actor > *action;
  316. for( action = m_action; action->m_child; action = action->m_child )
  317. ;
  318. // work our way through our containers
  319. while( action && result == ANSWER_UNDEFINED )
  320. {
  321. Action< Actor > *containingAction = action->m_parent;
  322. // work our way up the stack
  323. while( action && result == ANSWER_UNDEFINED )
  324. {
  325. result = action->IsHindrance( me, blocker );
  326. action = action->GetActionBuriedUnderMe();
  327. }
  328. action = containingAction;
  329. }
  330. }
  331. return result;
  332. }
  333. virtual Vector SelectTargetPoint( const INextBot *me, const CBaseCombatCharacter *subject ) const // given a subject, return the world space position we should aim at
  334. {
  335. Vector result = vec3_origin;
  336. if ( m_action )
  337. {
  338. // find innermost child action
  339. Action< Actor > *action;
  340. for( action = m_action; action->m_child; action = action->m_child )
  341. ;
  342. // work our way through our containers
  343. while( action && result == vec3_origin )
  344. {
  345. Action< Actor > *containingAction = action->m_parent;
  346. // work our way up the stack
  347. while( action && result == vec3_origin )
  348. {
  349. result = action->SelectTargetPoint( me, subject );
  350. action = action->GetActionBuriedUnderMe();
  351. }
  352. action = containingAction;
  353. }
  354. }
  355. return result;
  356. }
  357. /**
  358. * Allow bot to approve of positions game movement tries to put him into.
  359. * This is most useful for bots derived from CBasePlayer that go through
  360. * the player movement system.
  361. */
  362. virtual QueryResultType IsPositionAllowed( const INextBot *me, const Vector &pos ) const
  363. {
  364. QueryResultType result = ANSWER_UNDEFINED;
  365. if ( m_action )
  366. {
  367. // find innermost child action
  368. Action< Actor > *action;
  369. for( action = m_action; action->m_child; action = action->m_child )
  370. ;
  371. // work our way through our containers
  372. while( action && result == ANSWER_UNDEFINED )
  373. {
  374. Action< Actor > *containingAction = action->m_parent;
  375. // work our way up the stack
  376. while( action && result == ANSWER_UNDEFINED )
  377. {
  378. result = action->IsPositionAllowed( me, pos );
  379. action = action->GetActionBuriedUnderMe();
  380. }
  381. action = containingAction;
  382. }
  383. }
  384. return result;
  385. }
  386. virtual const CKnownEntity *SelectMoreDangerousThreat( const INextBot *me, const CBaseCombatCharacter *subject, const CKnownEntity *threat1, const CKnownEntity *threat2 ) const // return the more dangerous of the two threats, or NULL if we have no opinion
  387. {
  388. const CKnownEntity *result = NULL;
  389. if ( m_action )
  390. {
  391. // find innermost child action
  392. Action< Actor > *action;
  393. for( action = m_action; action->m_child; action = action->m_child )
  394. ;
  395. // work our way through our containers
  396. while( action && result == NULL )
  397. {
  398. Action< Actor > *containingAction = action->m_parent;
  399. // work our way up the stack
  400. while( action && result == NULL )
  401. {
  402. result = action->SelectMoreDangerousThreat( me, subject, threat1, threat2 );
  403. action = action->GetActionBuriedUnderMe();
  404. }
  405. action = containingAction;
  406. }
  407. }
  408. return result;
  409. }
  410. private:
  411. Action< Actor > *m_action;
  412. #define MAX_NAME_LENGTH 32
  413. CFmtStrN< MAX_NAME_LENGTH > m_name;
  414. };
  415. //----------------------------------------------------------------------------------------------
  416. /**
  417. * Something an Actor does.
  418. * Actions can contain Actions, representing the precise context of the Actor's behavior.
  419. * A system of Actions is contained within a Behavior, which acts as the manager
  420. * of the Action system.
  421. */
  422. template < typename Actor >
  423. class Action : public INextBotEventResponder, public IContextualQuery
  424. {
  425. public:
  426. DECLARE_CLASS( Action, INextBotEventResponder );
  427. Action( void );
  428. virtual ~Action();
  429. virtual const char *GetName( void ) const = 0; // return name of this action
  430. virtual bool IsNamed( const char *name ) const; // return true if given name matches the name of this Action
  431. virtual const char *GetFullName( void ) const; // return a temporary string showing the full lineage of this one action
  432. Actor *GetActor( void ) const; // return the Actor performing this Action (valid just before OnStart() is invoked)
  433. //-----------------------------------------------------------------------------------------
  434. /**
  435. * Try to start the Action. Result is immediately processed,
  436. * which can cause an immediate transition, another OnStart(), etc.
  437. * An Action can count on each OnStart() being followed (eventually) with an OnEnd().
  438. */
  439. virtual ActionResult< Actor > OnStart( Actor *me, Action< Actor > *priorAction ) { return Continue(); }
  440. /**
  441. * Do the work of the Action. It is possible for Update to not be
  442. * called between a given OnStart/OnEnd pair due to immediate transitions.
  443. */
  444. virtual ActionResult< Actor > Update( Actor *me, float interval ) { return Continue(); }
  445. // Invoked when an Action is ended for any reason
  446. virtual void OnEnd( Actor *me, Action< Actor > *nextAction ) { }
  447. /*
  448. * When an Action is suspended by a new action.
  449. * Note that only CONTINUE and DONE are valid results. All other results will
  450. * be considered as a CONTINUE.
  451. */
  452. virtual ActionResult< Actor > OnSuspend( Actor *me, Action< Actor > *interruptingAction ) { return Continue(); }
  453. // When an Action is resumed after being suspended
  454. virtual ActionResult< Actor > OnResume( Actor *me, Action< Actor > *interruptingAction ) { return Continue(); }
  455. /**
  456. * To cause a state change, use these methods to create an ActionResult to
  457. * return from OnStart, Update, or OnResume.
  458. */
  459. ActionResult< Actor > Continue( void ) const;
  460. ActionResult< Actor > ChangeTo( Action< Actor > *action, const char *reason = NULL ) const;
  461. ActionResult< Actor > SuspendFor( Action< Actor > *action, const char *reason = NULL ) const;
  462. ActionResult< Actor > Done( const char *reason = NULL ) const;
  463. // create and return an Action to start as sub-action within this Action when it starts
  464. virtual Action< Actor > *InitialContainedAction( Actor *me ) { return NULL; }
  465. //-----------------------------------------------------------------------------------------
  466. /**
  467. * Override the event handler methods below to respond to events that occur during this Action
  468. * NOTE: These are identical to the events in INextBotEventResponder with the addition
  469. * of an actor argument and a return result. Their translators are located in the private area
  470. * below.
  471. */
  472. virtual EventDesiredResult< Actor > OnLeaveGround( Actor *me, CBaseEntity *ground ) { return TryContinue(); }
  473. virtual EventDesiredResult< Actor > OnLandOnGround( Actor *me, CBaseEntity *ground ) { return TryContinue(); }
  474. virtual EventDesiredResult< Actor > OnContact( Actor *me, CBaseEntity *other, CGameTrace *result = NULL ) { return TryContinue(); }
  475. virtual EventDesiredResult< Actor > OnMoveToSuccess( Actor *me, const Path *path ) { return TryContinue(); }
  476. virtual EventDesiredResult< Actor > OnMoveToFailure( Actor *me, const Path *path, MoveToFailureType reason ) { return TryContinue(); }
  477. virtual EventDesiredResult< Actor > OnStuck( Actor *me ) { return TryContinue(); }
  478. virtual EventDesiredResult< Actor > OnUnStuck( Actor *me ) { return TryContinue(); }
  479. virtual EventDesiredResult< Actor > OnPostureChanged( Actor *me ) { return TryContinue(); }
  480. virtual EventDesiredResult< Actor > OnAnimationActivityComplete( Actor *me, int activity ) { return TryContinue(); }
  481. virtual EventDesiredResult< Actor > OnAnimationActivityInterrupted( Actor *me, int activity ) { return TryContinue(); }
  482. virtual EventDesiredResult< Actor > OnAnimationEvent( Actor *me, animevent_t *event ) { return TryContinue(); }
  483. virtual EventDesiredResult< Actor > OnIgnite( Actor *me ) { return TryContinue(); }
  484. virtual EventDesiredResult< Actor > OnInjured( Actor *me, const CTakeDamageInfo &info ) { return TryContinue(); }
  485. virtual EventDesiredResult< Actor > OnKilled( Actor *me, const CTakeDamageInfo &info ) { return TryContinue(); }
  486. virtual EventDesiredResult< Actor > OnOtherKilled( Actor *me, CBaseCombatCharacter *victim, const CTakeDamageInfo &info ) { return TryContinue(); }
  487. virtual EventDesiredResult< Actor > OnSight( Actor *me, CBaseEntity *subject ) { return TryContinue(); }
  488. virtual EventDesiredResult< Actor > OnLostSight( Actor *me, CBaseEntity *subject ) { return TryContinue(); }
  489. virtual EventDesiredResult< Actor > OnSound( Actor *me, CBaseEntity *source, const Vector &pos, KeyValues *keys ) { return TryContinue(); }
  490. virtual EventDesiredResult< Actor > OnSpokeConcept( Actor *me, CBaseCombatCharacter *who, AIConcept_t concept, AI_Response *response ) { return TryContinue(); }
  491. virtual EventDesiredResult< Actor > OnWeaponFired( Actor *me, CBaseCombatCharacter *whoFired, CBaseCombatWeapon *weapon ) { return TryContinue(); }
  492. virtual EventDesiredResult< Actor > OnNavAreaChanged( Actor *me, CNavArea *newArea, CNavArea *oldArea ) { return TryContinue(); }
  493. virtual EventDesiredResult< Actor > OnModelChanged( Actor *me ) { return TryContinue(); }
  494. virtual EventDesiredResult< Actor > OnPickUp( Actor *me, CBaseEntity *item, CBaseCombatCharacter *giver ) { return TryContinue(); }
  495. virtual EventDesiredResult< Actor > OnDrop( Actor *me, CBaseEntity *item ) { return TryContinue(); }
  496. virtual EventDesiredResult< Actor > OnCommandAttack( Actor *me, CBaseEntity *victim ) { return TryContinue(); }
  497. virtual EventDesiredResult< Actor > OnCommandApproach( Actor *me, const Vector &pos, float range ) { return TryContinue(); }
  498. virtual EventDesiredResult< Actor > OnCommandApproach( Actor *me, CBaseEntity *goal ) { return TryContinue(); }
  499. virtual EventDesiredResult< Actor > OnCommandRetreat( Actor *me, CBaseEntity *threat, float range ) { return TryContinue(); }
  500. virtual EventDesiredResult< Actor > OnCommandPause( Actor *me, float duration ) { return TryContinue(); }
  501. virtual EventDesiredResult< Actor > OnCommandResume( Actor *me ) { return TryContinue(); }
  502. virtual EventDesiredResult< Actor > OnCommandString( Actor *me, const char *command ) { return TryContinue(); }
  503. virtual EventDesiredResult< Actor > OnShoved( Actor *me, CBaseEntity *pusher ) { return TryContinue(); }
  504. virtual EventDesiredResult< Actor > OnBlinded( Actor *me, CBaseEntity *blinder ) { return TryContinue(); }
  505. virtual EventDesiredResult< Actor > OnTerritoryContested( Actor *me, int territoryID ) { return TryContinue(); }
  506. virtual EventDesiredResult< Actor > OnTerritoryCaptured( Actor *me, int territoryID ) { return TryContinue(); }
  507. virtual EventDesiredResult< Actor > OnTerritoryLost( Actor *me, int territoryID ) { return TryContinue(); }
  508. virtual EventDesiredResult< Actor > OnWin( Actor *me ) { return TryContinue(); }
  509. virtual EventDesiredResult< Actor > OnLose( Actor *me ) { return TryContinue(); }
  510. #ifdef DOTA_SERVER_DLL
  511. virtual EventDesiredResult< Actor > OnCommandMoveTo( Actor *me, const Vector &pos ) { return TryContinue(); }
  512. virtual EventDesiredResult< Actor > OnCommandMoveToAggressive( Actor *me, const Vector &pos ) { return TryContinue(); }
  513. virtual EventDesiredResult< Actor > OnCommandAttack( Actor *me, CBaseEntity *victim, bool bDeny ) { return TryContinue(); }
  514. virtual EventDesiredResult< Actor > OnCastAbilityNoTarget( Actor *me, CDOTABaseAbility *ability ) { return TryContinue(); }
  515. virtual EventDesiredResult< Actor > OnCastAbilityOnPosition( Actor *me, CDOTABaseAbility *ability, const Vector &pos ) { return TryContinue(); }
  516. virtual EventDesiredResult< Actor > OnCastAbilityOnTarget( Actor *me, CDOTABaseAbility *ability, CBaseEntity *target ) { return TryContinue(); }
  517. virtual EventDesiredResult< Actor > OnDropItem( Actor *me, const Vector &pos, CBaseEntity *item ) { return TryContinue(); }
  518. virtual EventDesiredResult< Actor > OnPickupItem( Actor *me, CBaseEntity *item ) { return TryContinue(); }
  519. virtual EventDesiredResult< Actor > OnPickupRune( Actor *me, CBaseEntity *item ) { return TryContinue(); }
  520. virtual EventDesiredResult< Actor > OnStop( Actor *me ) { return TryContinue(); }
  521. virtual EventDesiredResult< Actor > OnFriendThreatened( Actor *me, CBaseEntity *friendly, CBaseEntity *threat ) { return TryContinue(); }
  522. virtual EventDesiredResult< Actor > OnCancelAttack( Actor *me, CBaseEntity *pTarget ) { return TryContinue(); }
  523. virtual EventDesiredResult< Actor > OnDominated( Actor *me ) { return TryContinue(); }
  524. virtual EventDesiredResult< Actor > OnWarped( Actor *me, Vector vStartPos ) { return TryContinue(); }
  525. #endif
  526. /**
  527. * Event handlers must return one of these.
  528. */
  529. EventDesiredResult< Actor > TryContinue( EventResultPriorityType priority = RESULT_TRY ) const;
  530. EventDesiredResult< Actor > TryChangeTo( Action< Actor > *action, EventResultPriorityType priority = RESULT_TRY, const char *reason = NULL ) const;
  531. EventDesiredResult< Actor > TrySuspendFor( Action< Actor > *action, EventResultPriorityType priority = RESULT_TRY, const char *reason = NULL ) const;
  532. EventDesiredResult< Actor > TryDone( EventResultPriorityType priority = RESULT_TRY, const char *reason = NULL ) const;
  533. EventDesiredResult< Actor > TryToSustain( EventResultPriorityType priority = RESULT_TRY, const char *reason = NULL ) const;
  534. //-----------------------------------------------------------------------------------------
  535. Action< Actor > *GetActiveChildAction( void ) const;
  536. Action< Actor > *GetParentAction( void ) const; // the Action that I'm running inside of
  537. bool IsSuspended( void ) const; // return true if we are currently suspended for another Action
  538. const char *DebugString( void ) const; // return a temporary string describing the current action stack for debugging
  539. /**
  540. * Sometimes we want to pass through other NextBots. OnContact() will always
  541. * be invoked, but collision resolution can be skipped if this
  542. * method returns false.
  543. */
  544. virtual bool IsAbleToBlockMovementOf( const INextBot *botInMotion ) const { return true; }
  545. // INextBotEventResponder propagation ----------------------------------------------------------------------
  546. virtual INextBotEventResponder *FirstContainedResponder( void ) const;
  547. virtual INextBotEventResponder *NextContainedResponder( INextBotEventResponder *current ) const;
  548. private:
  549. /**
  550. * These macros are used below to translate INextBotEventResponder event methods
  551. * into Action event handler methods
  552. */
  553. #define PROCESS_EVENT( METHOD ) \
  554. { \
  555. if ( !m_isStarted ) \
  556. return; \
  557. \
  558. Action< Actor > *_action = this; \
  559. EventDesiredResult< Actor > _result; \
  560. \
  561. while( _action ) \
  562. { \
  563. if ( m_actor && (m_actor->IsDebugging(NEXTBOT_EVENTS) || NextBotDebugHistory.GetBool())) \
  564. { \
  565. m_actor->DebugConColorMsg( NEXTBOT_EVENTS, Color( 100, 100, 100, 255 ), "%3.2f: %s:%s: %s received EVENT %s\n", gpGlobals->curtime, m_actor->GetDebugIdentifier(), m_behavior->GetName(), _action->GetFullName(), #METHOD ); \
  566. } \
  567. _result = _action->METHOD( m_actor ); \
  568. if ( !_result.IsContinue() ) \
  569. break; \
  570. _action = _action->GetActionBuriedUnderMe(); \
  571. } \
  572. \
  573. if ( _action ) \
  574. { \
  575. if ( m_actor && _result.IsRequestingChange() && (m_actor->IsDebugging(NEXTBOT_BEHAVIOR) || NextBotDebugHistory.GetBool()) ) \
  576. { \
  577. m_actor->DebugConColorMsg( NEXTBOT_BEHAVIOR, Color( 255, 255, 0, 255 ), "%3.2f: %s:%s: ", gpGlobals->curtime, m_actor->GetDebugIdentifier(), m_behavior->GetName() ); \
  578. m_actor->DebugConColorMsg( NEXTBOT_BEHAVIOR, Color( 255, 255, 255, 255 ), "%s ", _action->GetFullName() ); \
  579. m_actor->DebugConColorMsg( NEXTBOT_BEHAVIOR, Color( 255, 255, 0, 255 ), "reponded to EVENT %s with ", #METHOD ); \
  580. m_actor->DebugConColorMsg( NEXTBOT_BEHAVIOR, Color( 255, 0, 0, 255 ), "%s %s ", _result.GetTypeName(), _result.m_action ? _result.m_action->GetName() : "" ); \
  581. m_actor->DebugConColorMsg( NEXTBOT_BEHAVIOR, Color( 0, 255, 0, 255 ), "%s\n", _result.m_reason ? _result.m_reason : "" ); \
  582. } \
  583. \
  584. _action->StorePendingEventResult( _result, #METHOD ); \
  585. } \
  586. \
  587. INextBotEventResponder::METHOD(); \
  588. }
  589. #define PROCESS_EVENT_WITH_1_ARG( METHOD, ARG1 ) \
  590. { \
  591. if ( !m_isStarted ) \
  592. return; \
  593. \
  594. Action< Actor > *_action = this; \
  595. EventDesiredResult< Actor > _result; \
  596. \
  597. while( _action ) \
  598. { \
  599. if ( m_actor && (m_actor->IsDebugging(NEXTBOT_EVENTS) || NextBotDebugHistory.GetBool()) ) \
  600. { \
  601. m_actor->DebugConColorMsg( NEXTBOT_EVENTS, Color( 100, 100, 100, 255 ), "%3.2f: %s:%s: %s received EVENT %s\n", gpGlobals->curtime, m_actor->GetDebugIdentifier(), m_behavior->GetName(), _action->GetFullName(), #METHOD ); \
  602. } \
  603. _result = _action->METHOD( m_actor, ARG1 ); \
  604. if ( !_result.IsContinue() ) \
  605. break; \
  606. _action = _action->GetActionBuriedUnderMe(); \
  607. } \
  608. \
  609. if ( _action ) \
  610. { \
  611. if ( m_actor && (m_actor->IsDebugging(NEXTBOT_BEHAVIOR) || NextBotDebugHistory.GetBool()) && _result.IsRequestingChange() && _action ) \
  612. { \
  613. m_actor->DebugConColorMsg( NEXTBOT_BEHAVIOR, Color( 255, 255, 0, 255 ), "%3.2f: %s:%s: ", gpGlobals->curtime, m_actor->GetDebugIdentifier(), m_behavior->GetName() ); \
  614. m_actor->DebugConColorMsg( NEXTBOT_BEHAVIOR, Color( 255, 255, 255, 255 ), "%s ", _action->GetFullName() ); \
  615. m_actor->DebugConColorMsg( NEXTBOT_BEHAVIOR, Color( 255, 255, 0, 255 ), "reponded to EVENT %s with ", #METHOD ); \
  616. m_actor->DebugConColorMsg( NEXTBOT_BEHAVIOR, Color( 255, 0, 0, 255 ), "%s %s ", _result.GetTypeName(), _result.m_action ? _result.m_action->GetName() : "" ); \
  617. m_actor->DebugConColorMsg( NEXTBOT_BEHAVIOR, Color( 0, 255, 0, 255 ), "%s\n", _result.m_reason ? _result.m_reason : "" ); \
  618. } \
  619. \
  620. _action->StorePendingEventResult( _result, #METHOD ); \
  621. } \
  622. \
  623. INextBotEventResponder::METHOD( ARG1 ); \
  624. }
  625. #define PROCESS_EVENT_WITH_2_ARGS( METHOD, ARG1, ARG2 ) \
  626. { \
  627. if ( !m_isStarted ) \
  628. return; \
  629. \
  630. Action< Actor > *_action = this; \
  631. EventDesiredResult< Actor > _result; \
  632. \
  633. while( _action ) \
  634. { \
  635. if ( m_actor && (m_actor->IsDebugging(NEXTBOT_EVENTS) || NextBotDebugHistory.GetBool()) ) \
  636. { \
  637. m_actor->DebugConColorMsg( NEXTBOT_EVENTS, Color( 100, 100, 100, 255 ), "%3.2f: %s:%s: %s received EVENT %s\n", gpGlobals->curtime, m_actor->GetDebugIdentifier(), m_behavior->GetName(), _action->GetFullName(), #METHOD ); \
  638. } \
  639. _result = _action->METHOD( m_actor, ARG1, ARG2 ); \
  640. if ( !_result.IsContinue() ) \
  641. break; \
  642. _action = _action->GetActionBuriedUnderMe(); \
  643. } \
  644. \
  645. if ( _action ) \
  646. { \
  647. if ( m_actor && (m_actor->IsDebugging(NEXTBOT_BEHAVIOR) || NextBotDebugHistory.GetBool()) && _result.IsRequestingChange() && _action ) \
  648. { \
  649. m_actor->DebugConColorMsg( NEXTBOT_BEHAVIOR, Color( 255, 255, 0, 255 ), "%3.2f: %s:%s: ", gpGlobals->curtime, m_actor->GetDebugIdentifier(), m_behavior->GetName() ); \
  650. m_actor->DebugConColorMsg( NEXTBOT_BEHAVIOR, Color( 255, 255, 255, 255 ), "%s ", _action->GetFullName() ); \
  651. m_actor->DebugConColorMsg( NEXTBOT_BEHAVIOR, Color( 255, 255, 0, 255 ), "reponded to EVENT %s with ", #METHOD ); \
  652. m_actor->DebugConColorMsg( NEXTBOT_BEHAVIOR, Color( 255, 0, 0, 255 ), "%s %s ", _result.GetTypeName(), _result.m_action ? _result.m_action->GetName() : "" ); \
  653. m_actor->DebugConColorMsg( NEXTBOT_BEHAVIOR, Color( 0, 255, 0, 255 ), "%s\n", _result.m_reason ? _result.m_reason : "" ); \
  654. } \
  655. \
  656. _action->StorePendingEventResult( _result, #METHOD ); \
  657. } \
  658. \
  659. INextBotEventResponder::METHOD( ARG1, ARG2 ); \
  660. }
  661. #define PROCESS_EVENT_WITH_3_ARGS( METHOD, ARG1, ARG2, ARG3 ) \
  662. { \
  663. if ( !m_isStarted ) \
  664. return; \
  665. \
  666. Action< Actor > *_action = this; \
  667. EventDesiredResult< Actor > _result; \
  668. \
  669. while( _action ) \
  670. { \
  671. if ( m_actor && (m_actor->IsDebugging(NEXTBOT_EVENTS) || NextBotDebugHistory.GetBool()) ) \
  672. { \
  673. m_actor->DebugConColorMsg( NEXTBOT_EVENTS, Color( 100, 100, 100, 255 ), "%3.2f: %s:%s: %s received EVENT %s\n", gpGlobals->curtime, m_actor->GetDebugIdentifier(), m_behavior->GetName(), _action->GetFullName(), #METHOD ); \
  674. } \
  675. _result = _action->METHOD( m_actor, ARG1, ARG2, ARG3 ); \
  676. if ( !_result.IsContinue() ) \
  677. break; \
  678. _action = _action->GetActionBuriedUnderMe(); \
  679. } \
  680. \
  681. if ( _action ) \
  682. { \
  683. if ( m_actor && (m_actor->IsDebugging(NEXTBOT_BEHAVIOR) || NextBotDebugHistory.GetBool()) && _result.IsRequestingChange() && _action ) \
  684. { \
  685. m_actor->DebugConColorMsg( NEXTBOT_BEHAVIOR, Color( 255, 255, 0, 255 ), "%3.2f: %s:%s: ", gpGlobals->curtime, m_actor->GetDebugIdentifier(), m_behavior->GetName() ); \
  686. m_actor->DebugConColorMsg( NEXTBOT_BEHAVIOR, Color( 255, 255, 255, 255 ), "%s ", _action->GetFullName() ); \
  687. m_actor->DebugConColorMsg( NEXTBOT_BEHAVIOR, Color( 255, 255, 0, 255 ), "reponded to EVENT %s with ", #METHOD ); \
  688. m_actor->DebugConColorMsg( NEXTBOT_BEHAVIOR, Color( 255, 0, 0, 255 ), "%s %s ", _result.GetTypeName(), _result.m_action ? _result.m_action->GetName() : "" ); \
  689. m_actor->DebugConColorMsg( NEXTBOT_BEHAVIOR, Color( 0, 255, 0, 255 ), "%s\n", _result.m_reason ? _result.m_reason : "" ); \
  690. } \
  691. \
  692. _action->StorePendingEventResult( _result, #METHOD ); \
  693. } \
  694. \
  695. INextBotEventResponder::METHOD( ARG1, ARG2, ARG3 ); \
  696. }
  697. /**
  698. * Translate incoming events into Action events
  699. * DO NOT OVERRIDE THESE METHODS
  700. */
  701. virtual void OnLeaveGround( CBaseEntity *ground ) { PROCESS_EVENT_WITH_1_ARG( OnLeaveGround, ground ); }
  702. virtual void OnLandOnGround( CBaseEntity *ground ) { PROCESS_EVENT_WITH_1_ARG( OnLandOnGround, ground ); }
  703. virtual void OnContact( CBaseEntity *other, CGameTrace *result ) { PROCESS_EVENT_WITH_2_ARGS( OnContact, other, result ); }
  704. virtual void OnMoveToSuccess( const Path *path ) { PROCESS_EVENT_WITH_1_ARG( OnMoveToSuccess, path ); }
  705. virtual void OnMoveToFailure( const Path *path, MoveToFailureType reason ) { PROCESS_EVENT_WITH_2_ARGS( OnMoveToFailure, path, reason ); }
  706. virtual void OnStuck( void ) { PROCESS_EVENT( OnStuck ); }
  707. virtual void OnUnStuck( void ) { PROCESS_EVENT( OnUnStuck ); }
  708. virtual void OnPostureChanged( void ) { PROCESS_EVENT( OnPostureChanged ); }
  709. virtual void OnAnimationActivityComplete( int activity ) { PROCESS_EVENT_WITH_1_ARG( OnAnimationActivityComplete, activity ); }
  710. virtual void OnAnimationActivityInterrupted( int activity ) { PROCESS_EVENT_WITH_1_ARG( OnAnimationActivityInterrupted, activity ); }
  711. virtual void OnAnimationEvent( animevent_t *event ) { PROCESS_EVENT_WITH_1_ARG( OnAnimationEvent, event ); }
  712. virtual void OnIgnite( void ) { PROCESS_EVENT( OnIgnite ); }
  713. virtual void OnInjured( const CTakeDamageInfo &info ) { PROCESS_EVENT_WITH_1_ARG( OnInjured, info ); }
  714. virtual void OnKilled( const CTakeDamageInfo &info ) { PROCESS_EVENT_WITH_1_ARG( OnKilled, info ); }
  715. virtual void OnOtherKilled( CBaseCombatCharacter *victim, const CTakeDamageInfo &info ) { PROCESS_EVENT_WITH_2_ARGS( OnOtherKilled, victim, info ); }
  716. virtual void OnSight( CBaseEntity *subject ) { PROCESS_EVENT_WITH_1_ARG( OnSight, subject ); }
  717. virtual void OnLostSight( CBaseEntity *subject ) { PROCESS_EVENT_WITH_1_ARG( OnLostSight, subject ); }
  718. virtual void OnSound( CBaseEntity *source, const Vector &pos, KeyValues *keys ) { PROCESS_EVENT_WITH_3_ARGS( OnSound, source, pos, keys ); }
  719. virtual void OnSpokeConcept( CBaseCombatCharacter *who, AIConcept_t concept, AI_Response *response ) { PROCESS_EVENT_WITH_3_ARGS( OnSpokeConcept, who, concept, response ); }
  720. virtual void OnWeaponFired( CBaseCombatCharacter *whoFired, CBaseCombatWeapon *weapon ) { PROCESS_EVENT_WITH_2_ARGS( OnWeaponFired, whoFired, weapon ); }
  721. virtual void OnNavAreaChanged( CNavArea *newArea, CNavArea *oldArea ) { PROCESS_EVENT_WITH_2_ARGS( OnNavAreaChanged, newArea, oldArea ); }
  722. virtual void OnModelChanged( void ) { PROCESS_EVENT( OnModelChanged ); }
  723. virtual void OnPickUp( CBaseEntity *item, CBaseCombatCharacter *giver ) { PROCESS_EVENT_WITH_2_ARGS( OnPickUp, item, giver ); }
  724. virtual void OnDrop( CBaseEntity *item ) { PROCESS_EVENT_WITH_1_ARG( OnDrop, item ); }
  725. virtual void OnCommandAttack( CBaseEntity *victim ) { PROCESS_EVENT_WITH_1_ARG( OnCommandAttack, victim ); }
  726. virtual void OnCommandApproach( const Vector &pos, float range ) { PROCESS_EVENT_WITH_2_ARGS( OnCommandApproach, pos, range ); }
  727. virtual void OnCommandApproach( CBaseEntity *goal ) { PROCESS_EVENT_WITH_1_ARG( OnCommandApproach, goal ); }
  728. virtual void OnCommandRetreat( CBaseEntity *threat, float range ) { PROCESS_EVENT_WITH_2_ARGS( OnCommandRetreat, threat, range ); }
  729. virtual void OnCommandPause( float duration ) { PROCESS_EVENT_WITH_1_ARG( OnCommandPause, duration ); }
  730. virtual void OnCommandResume( void ) { PROCESS_EVENT( OnCommandResume ); }
  731. virtual void OnCommandString( const char *command ) { PROCESS_EVENT_WITH_1_ARG( OnCommandString, command ); }
  732. virtual void OnShoved( CBaseEntity *pusher ) { PROCESS_EVENT_WITH_1_ARG( OnShoved, pusher ); }
  733. virtual void OnBlinded( CBaseEntity *blinder ) { PROCESS_EVENT_WITH_1_ARG( OnBlinded, blinder ); }
  734. virtual void OnTerritoryContested( int territoryID ) { PROCESS_EVENT_WITH_1_ARG( OnTerritoryContested, territoryID ); }
  735. virtual void OnTerritoryCaptured( int territoryID ) { PROCESS_EVENT_WITH_1_ARG( OnTerritoryCaptured, territoryID ); }
  736. virtual void OnTerritoryLost( int territoryID ) { PROCESS_EVENT_WITH_1_ARG( OnTerritoryLost, territoryID ); }
  737. virtual void OnWin( void ) { PROCESS_EVENT( OnWin ); }
  738. virtual void OnLose( void ) { PROCESS_EVENT( OnLose ); }
  739. #ifdef DOTA_SERVER_DLL
  740. virtual void OnCommandMoveTo( const Vector &pos ) { PROCESS_EVENT_WITH_1_ARG( OnCommandMoveTo, pos ); }
  741. virtual void OnCommandMoveToAggressive( const Vector &pos ) { PROCESS_EVENT_WITH_1_ARG( OnCommandMoveToAggressive, pos ); }
  742. virtual void OnCommandAttack( CBaseEntity *victim, bool bDeny ) { PROCESS_EVENT_WITH_2_ARGS( OnCommandAttack, victim, bDeny ); }
  743. virtual void OnCastAbilityNoTarget( CDOTABaseAbility *ability ) { PROCESS_EVENT_WITH_1_ARG( OnCastAbilityNoTarget, ability ); }
  744. virtual void OnCastAbilityOnPosition( CDOTABaseAbility *ability, const Vector &pos ) { PROCESS_EVENT_WITH_2_ARGS( OnCastAbilityOnPosition, ability, pos ); }
  745. virtual void OnCastAbilityOnTarget( CDOTABaseAbility *ability, CBaseEntity *target ) { PROCESS_EVENT_WITH_2_ARGS( OnCastAbilityOnTarget, ability, target ); }
  746. virtual void OnDropItem( const Vector &pos, CBaseEntity *item ) { PROCESS_EVENT_WITH_2_ARGS( OnDropItem, pos, item ); }
  747. virtual void OnPickupItem( CBaseEntity *item ) { PROCESS_EVENT_WITH_1_ARG( OnPickupItem, item ); }
  748. virtual void OnPickupRune( CBaseEntity *item ) { PROCESS_EVENT_WITH_1_ARG( OnPickupRune, item ); }
  749. virtual void OnStop() { PROCESS_EVENT( OnStop ); }
  750. virtual void OnFriendThreatened( CBaseEntity *friendly, CBaseEntity *threat ) { PROCESS_EVENT_WITH_2_ARGS( OnFriendThreatened, friendly, threat ); }
  751. virtual void OnCancelAttack( CBaseEntity *pTarget ) { PROCESS_EVENT_WITH_1_ARG( OnCancelAttack, pTarget ); }
  752. virtual void OnDominated() { PROCESS_EVENT( OnDominated ); }
  753. virtual void OnWarped( Vector vStartPos ) { PROCESS_EVENT_WITH_1_ARG( OnWarped, vStartPos ); }
  754. #endif
  755. friend class Behavior< Actor>; // the containing Behavior class
  756. Behavior< Actor > *m_behavior; // the Behavior this Action is part of
  757. Action< Actor > *m_parent; // the Action that contains us
  758. Action< Actor > *m_child; // the ACTIVE Action we contain, top of the stack. Use m_buriedUnderMe, m_coveringMe on the child to traverse to other suspended children
  759. Action< Actor > *m_buriedUnderMe; // the Action just "under" us in the stack that we will resume to when we finish
  760. Action< Actor > *m_coveringMe; // the Action just "above" us in the stack that will resume to us when it finishes
  761. Actor *m_actor; // only valid after OnStart()
  762. mutable EventDesiredResult< Actor > m_eventResult; // set by event handlers
  763. bool m_isStarted; // Action doesn't start until OnStart() is invoked
  764. bool m_isSuspended; // are we suspended for another Action
  765. Action< Actor > *GetActionBuriedUnderMe( void ) const // return Action just "under" us that we will resume to when we finish
  766. {
  767. return m_buriedUnderMe;
  768. }
  769. Action< Actor > *GetActionCoveringMe( void ) const // return Action just "above" us that will resume to us when it finishes
  770. {
  771. return m_coveringMe;
  772. }
  773. /**
  774. * If any Action buried underneath me has either exited
  775. * or is changing to a different Action, we're "out of scope"
  776. */
  777. bool IsOutOfScope( void ) const
  778. {
  779. for( Action< Actor > *under = GetActionBuriedUnderMe(); under; under = under->GetActionBuriedUnderMe() )
  780. {
  781. if ( under->m_eventResult.m_type == CHANGE_TO ||
  782. under->m_eventResult.m_type == DONE )
  783. {
  784. return true;
  785. }
  786. }
  787. return false;
  788. }
  789. /**
  790. * Process any pending events with the stack. This is called
  791. * by the active Action on the top of the stack, and walks
  792. * through any buried Actions checking for pending event results.
  793. */
  794. ActionResult< Actor > ProcessPendingEvents( void ) const
  795. {
  796. // if an event has requested a change, honor it
  797. if ( m_eventResult.IsRequestingChange() )
  798. {
  799. ActionResult< Actor > result( m_eventResult.m_type, m_eventResult.m_action, m_eventResult.m_reason );
  800. // clear event result in case this change is a suspend and we later resume this action
  801. m_eventResult = TryContinue( RESULT_NONE );
  802. return result;
  803. }
  804. // check for pending event changes buried in the stack
  805. Action< Actor > *under = GetActionBuriedUnderMe();
  806. while( under )
  807. {
  808. if ( under->m_eventResult.m_type == SUSPEND_FOR )
  809. {
  810. // process this pending event in-place and push new Action on the top of the stack
  811. ActionResult< Actor > result( under->m_eventResult.m_type, under->m_eventResult.m_action, under->m_eventResult.m_reason );
  812. // clear event result in case this change is a suspend and we later resume this action
  813. under->m_eventResult = TryContinue( RESULT_NONE );
  814. return result;
  815. }
  816. under = under->GetActionBuriedUnderMe();
  817. }
  818. return Continue();
  819. }
  820. // given the result of this Action's work, apply the result to potentially cause a state transition
  821. Action< Actor > * ApplyResult( Actor *me, Behavior< Actor > *behavior, ActionResult< Actor > result );
  822. /**
  823. * The methods below do the bookkeeping of each event, propagate the activity through the hierarchy,
  824. * and invoke the virtual event for each.
  825. */
  826. ActionResult< Actor > InvokeOnStart( Actor *me, Behavior< Actor > *behavior, Action< Actor > *priorAction, Action< Actor > *buriedUnderMeAction );
  827. ActionResult< Actor > InvokeUpdate( Actor *me, Behavior< Actor > *behavior, float interval );
  828. void InvokeOnEnd( Actor *me, Behavior< Actor > *behavior, Action< Actor > *nextAction );
  829. Action< Actor > * InvokeOnSuspend( Actor *me, Behavior< Actor > *behavior, Action< Actor > *interruptingAction );
  830. ActionResult< Actor > InvokeOnResume( Actor *me, Behavior< Actor > *behavior, Action< Actor > *interruptingAction );
  831. /**
  832. * Store the given event result, attending to priorities
  833. */
  834. void StorePendingEventResult( const EventDesiredResult< Actor > &result, const char *eventName )
  835. {
  836. if ( result.IsContinue() )
  837. {
  838. return;
  839. }
  840. if ( result.m_priority > m_eventResult.m_priority )
  841. {
  842. // new result is more important - destroy the replaced action
  843. if ( result.m_priority != RESULT_NONE && m_eventResult.m_action )
  844. {
  845. delete m_eventResult.m_action;
  846. }
  847. m_eventResult = result;
  848. }
  849. else if ( result.m_priority == m_eventResult.m_priority && m_eventResult.m_type == SUSTAIN )
  850. {
  851. // same priority as existing SUSTAIN, override
  852. // destroy the replaced action
  853. if ( m_eventResult.m_action )
  854. {
  855. delete m_eventResult.m_action;
  856. }
  857. m_eventResult = result;
  858. }
  859. else
  860. {
  861. // new result is equal or lower priority than previously stored result - discard it
  862. if ( result.m_priority == RESULT_CRITICAL )
  863. {
  864. if ( developer.GetBool() )
  865. {
  866. DevMsg( "%3.2f: WARNING: %s::%s() RESULT_CRITICAL collision\n", gpGlobals->curtime, GetName(), eventName );
  867. }
  868. }
  869. if ( result.m_action )
  870. {
  871. // destroy the unused action
  872. delete result.m_action;
  873. }
  874. }
  875. }
  876. char *BuildDecoratedName( char *name, const Action< Actor > *action ) const; // recursive name outMsg for DebugString()
  877. void PrintStateToConsole( void ) const;
  878. };
  879. //-------------------------------------------------------------------------------------------
  880. template < typename Actor >
  881. Action< Actor >::Action( void )
  882. {
  883. m_parent = NULL;
  884. m_child = NULL;
  885. m_buriedUnderMe = NULL;
  886. m_coveringMe = NULL;
  887. m_actor = NULL;
  888. m_behavior = NULL;
  889. m_isStarted = false;
  890. m_isSuspended = false;
  891. m_eventResult = TryContinue( RESULT_NONE );
  892. #ifdef DEBUG_BEHAVIOR_MEMORY
  893. ConColorMsg( Color( 255, 0, 255, 255 ), "%3.2f: NEW %0X\n", gpGlobals->curtime, this );
  894. #endif
  895. }
  896. //-------------------------------------------------------------------------------------------
  897. template < typename Actor >
  898. Action< Actor >::~Action()
  899. {
  900. #ifdef DEBUG_BEHAVIOR_MEMORY
  901. ConColorMsg( Color( 255, 0, 255, 255 ), "%3.2f: DELETE %0X\n", gpGlobals->curtime, this );
  902. #endif
  903. if ( m_parent )
  904. {
  905. // if I'm my parent's active child, update parent's pointer
  906. if ( m_parent->m_child == this )
  907. {
  908. m_parent->m_child = m_buriedUnderMe;
  909. }
  910. }
  911. // delete all my children.
  912. // our m_child pointer always points to the topmost
  913. // child in the stack, so work our way back thru the
  914. // 'buried' children and delete them.
  915. Action< Actor > *child, *next = NULL;
  916. for( child = m_child; child; child = next )
  917. {
  918. next = child->m_buriedUnderMe;
  919. delete child;
  920. }
  921. if ( m_buriedUnderMe )
  922. {
  923. // we're going away, so my buried sibling is now on top
  924. m_buriedUnderMe->m_coveringMe = NULL;
  925. }
  926. // delete any actions stacked on top of me
  927. if ( m_coveringMe )
  928. {
  929. // recursion will march down the chain
  930. delete m_coveringMe;
  931. }
  932. // delete any pending event result
  933. if ( m_eventResult.m_action )
  934. {
  935. delete m_eventResult.m_action;
  936. }
  937. }
  938. template < typename Actor >
  939. bool Action< Actor >::IsNamed( const char *name ) const
  940. {
  941. return FStrEq( GetName(), name );
  942. }
  943. template < typename Actor >
  944. Actor *Action< Actor >::GetActor( void ) const
  945. {
  946. return m_actor;
  947. }
  948. template < typename Actor >
  949. ActionResult< Actor > Action< Actor >::Continue( void ) const
  950. {
  951. return ActionResult< Actor >( CONTINUE, NULL, NULL );
  952. }
  953. template < typename Actor >
  954. ActionResult< Actor > Action< Actor >::ChangeTo( Action< Actor > *action, const char *reason ) const
  955. {
  956. return ActionResult< Actor >( CHANGE_TO, action, reason );
  957. }
  958. template < typename Actor >
  959. ActionResult< Actor > Action< Actor >::SuspendFor( Action< Actor > *action, const char *reason ) const
  960. {
  961. // clear any pending transitions requested by events, or this SuspendFor will
  962. // immediately be out of scope
  963. m_eventResult = TryContinue( RESULT_NONE );
  964. return ActionResult< Actor >( SUSPEND_FOR, action, reason );
  965. }
  966. template < typename Actor >
  967. ActionResult< Actor > Action< Actor >::Done( const char *reason ) const
  968. {
  969. return ActionResult< Actor >( DONE, NULL, reason );
  970. }
  971. //-------------------------------------------------------------------------------------------
  972. template < typename Actor >
  973. EventDesiredResult< Actor > Action< Actor >::TryContinue( EventResultPriorityType priority ) const
  974. {
  975. return EventDesiredResult< Actor >( CONTINUE, NULL, priority );
  976. }
  977. template < typename Actor >
  978. EventDesiredResult< Actor > Action< Actor >::TryChangeTo( Action< Actor > *action, EventResultPriorityType priority, const char *reason ) const
  979. {
  980. return EventDesiredResult< Actor >( CHANGE_TO, action, priority, reason );
  981. }
  982. template < typename Actor >
  983. EventDesiredResult< Actor > Action< Actor >::TrySuspendFor( Action< Actor > *action, EventResultPriorityType priority, const char *reason ) const
  984. {
  985. return EventDesiredResult< Actor >( SUSPEND_FOR, action, priority, reason );
  986. }
  987. template < typename Actor >
  988. EventDesiredResult< Actor > Action< Actor >::TryDone( EventResultPriorityType priority, const char *reason /*= NULL*/ ) const
  989. {
  990. return EventDesiredResult< Actor >( DONE, NULL, priority, reason );
  991. }
  992. template < typename Actor >
  993. EventDesiredResult< Actor > Action< Actor >::TryToSustain( EventResultPriorityType priority, const char *reason /*= NULL*/ ) const
  994. {
  995. return EventDesiredResult< Actor >( SUSTAIN, NULL, priority, reason );
  996. }
  997. //-------------------------------------------------------------------------------------------
  998. template < typename Actor >
  999. Action< Actor > *Action< Actor >::GetActiveChildAction( void ) const
  1000. {
  1001. return m_child;
  1002. }
  1003. //-------------------------------------------------------------------------------------------
  1004. // the Action that I'm running inside of
  1005. template < typename Actor >
  1006. Action< Actor > *Action< Actor >::GetParentAction( void ) const
  1007. {
  1008. return m_parent;
  1009. }
  1010. //-------------------------------------------------------------------------------------------
  1011. /**
  1012. * Return true if we are currently suspended for another Action
  1013. */
  1014. template < typename Actor >
  1015. bool Action< Actor >::IsSuspended( void ) const
  1016. {
  1017. return m_isSuspended;
  1018. }
  1019. //-------------------------------------------------------------------------------------------
  1020. /**
  1021. * Start this Action.
  1022. * The act of calling InvokeOnStart is the edge case that 'enters' a state.
  1023. */
  1024. template < typename Actor >
  1025. ActionResult< Actor > Action< Actor >::InvokeOnStart( Actor *me, Behavior< Actor > *behavior, Action< Actor > *priorAction, Action< Actor > *buriedUnderMeAction )
  1026. {
  1027. // debug display
  1028. if ( (me->IsDebugging(NEXTBOT_BEHAVIOR) || NextBotDebugHistory.GetBool()) )
  1029. {
  1030. me->DebugConColorMsg( NEXTBOT_BEHAVIOR, Color( 255, 255, 150, 255 ), "%3.2f: %s:%s: ", gpGlobals->curtime, me->GetDebugIdentifier(), behavior->GetName() );
  1031. me->DebugConColorMsg( NEXTBOT_BEHAVIOR, Color( 0, 255, 0, 255 ), " STARTING " );
  1032. me->DebugConColorMsg( NEXTBOT_BEHAVIOR, Color( 255, 255, 255, 255 ), GetName() );
  1033. me->DebugConColorMsg( NEXTBOT_BEHAVIOR, Color( 255, 255, 255, 255 ), "\n" );
  1034. }
  1035. // these value must be valid before invoking OnStart, in case an OnSuspend happens
  1036. m_isStarted = true;
  1037. m_actor = me;
  1038. m_behavior = behavior;
  1039. // maintain parent/child relationship during transitions
  1040. if ( priorAction )
  1041. {
  1042. m_parent = priorAction->m_parent;
  1043. }
  1044. if ( m_parent )
  1045. {
  1046. // child pointer of an Action always points to the ACTIVE child
  1047. // parent pointers are set when child Actions are instantiated
  1048. m_parent->m_child = this;
  1049. }
  1050. // maintain stack pointers
  1051. m_buriedUnderMe = buriedUnderMeAction;
  1052. if ( buriedUnderMeAction )
  1053. {
  1054. buriedUnderMeAction->m_coveringMe = this;
  1055. }
  1056. // we are always on top of the stack. if our priorAction was buried, it cleared
  1057. // everything covering it when it ended (which happens before we start)
  1058. m_coveringMe = NULL;
  1059. // start the optional child action
  1060. m_child = InitialContainedAction( me );
  1061. if ( m_child )
  1062. {
  1063. // define initial parent/child relationship
  1064. m_child->m_parent = this;
  1065. m_child = m_child->ApplyResult( me, behavior, ChangeTo( m_child, "Starting child Action" ) );
  1066. }
  1067. // start ourselves
  1068. ActionResult< Actor > result = OnStart( me, priorAction );
  1069. return result;
  1070. }
  1071. //-------------------------------------------------------------------------------------------
  1072. template < typename Actor >
  1073. ActionResult< Actor > Action< Actor >::InvokeUpdate( Actor *me, Behavior< Actor > *behavior, float interval )
  1074. {
  1075. // an explicit "out of scope" check is needed here to prevent any
  1076. // pending events causing an out of scope action to linger
  1077. if ( IsOutOfScope() )
  1078. {
  1079. // exit self to make this Action active and allow result to take effect on its next Update
  1080. return Done( "Out of scope" );
  1081. }
  1082. if ( !m_isStarted )
  1083. {
  1084. // this Action has not yet begun - start it
  1085. return ChangeTo( this, "Starting Action" );
  1086. }
  1087. // honor any pending event results
  1088. ActionResult< Actor > eventResult = ProcessPendingEvents();
  1089. if ( !eventResult.IsContinue() )
  1090. {
  1091. return eventResult;
  1092. }
  1093. // update our child action first, since it has the most specific behavior
  1094. if ( m_child )
  1095. {
  1096. m_child = m_child->ApplyResult( me, behavior, m_child->InvokeUpdate( me, behavior, interval ) );
  1097. }
  1098. // update ourselves
  1099. ActionResult< Actor > result = Update( me, interval );
  1100. return result;
  1101. }
  1102. //-------------------------------------------------------------------------------------------
  1103. /**
  1104. * This method calls the virtual OnEnd() method for the Action, its children, and Actions
  1105. * stacked on top of it.
  1106. * It does NOT delete resources, or disturb pointer relationships, because this Action
  1107. * needs to remain valid for a short while as an argument to OnStart(), OnSuspend(), etc for
  1108. * the next Action.
  1109. * The destructor for the Action frees memory for this Action, its children, etc.
  1110. */
  1111. template < typename Actor >
  1112. void Action< Actor >::InvokeOnEnd( Actor *me, Behavior< Actor > *behavior, Action< Actor > *nextAction )
  1113. {
  1114. if ( !m_isStarted )
  1115. {
  1116. // we are not started (or never were)
  1117. return;
  1118. }
  1119. if ( me->IsDebugging( NEXTBOT_BEHAVIOR ) || NextBotDebugHistory.GetBool() )
  1120. {
  1121. me->DebugConColorMsg( NEXTBOT_BEHAVIOR, Color( 255, 255, 150, 255 ), "%3.2f: %s:%s: ", gpGlobals->curtime, me->GetDebugIdentifier(), behavior->GetName() );
  1122. me->DebugConColorMsg( NEXTBOT_BEHAVIOR, Color( 255, 0, 0, 255 ), " ENDING " );
  1123. me->DebugConColorMsg( NEXTBOT_BEHAVIOR, Color( 255, 255, 255, 255 ), GetName() );
  1124. me->DebugConColorMsg( NEXTBOT_BEHAVIOR, Color( 255, 255, 255, 255 ), "\n" );
  1125. }
  1126. // we are no longer started
  1127. m_isStarted = false;
  1128. // tell child Action(s) to leave (but don't disturb the list itself)
  1129. Action< Actor > *child, *next = NULL;
  1130. for( child = m_child; child; child = next )
  1131. {
  1132. next = child->m_buriedUnderMe;
  1133. child->InvokeOnEnd( me, behavior, nextAction );
  1134. }
  1135. // leave ourself
  1136. OnEnd( me, nextAction );
  1137. // leave any Actions stacked on top of me
  1138. if ( m_coveringMe )
  1139. {
  1140. m_coveringMe->InvokeOnEnd( me, behavior, nextAction );
  1141. }
  1142. }
  1143. //-------------------------------------------------------------------------------------------
  1144. /**
  1145. * Just invoke OnSuspend - when the interrupting Action is started it will
  1146. * update our buried/covered pointers.
  1147. * OnSuspend may cause this Action to exit.
  1148. */
  1149. template < typename Actor >
  1150. Action< Actor > * Action< Actor >::InvokeOnSuspend( Actor *me, Behavior< Actor > *behavior, Action< Actor > *interruptingAction )
  1151. {
  1152. if ( me->IsDebugging( NEXTBOT_BEHAVIOR ) || NextBotDebugHistory.GetBool() )
  1153. {
  1154. me->DebugConColorMsg( NEXTBOT_BEHAVIOR, Color( 255, 255, 150, 255 ), "%3.2f: %s:%s: ", gpGlobals->curtime, me->GetDebugIdentifier(), behavior->GetName() );
  1155. me->DebugConColorMsg( NEXTBOT_BEHAVIOR, Color( 255, 0, 255, 255 ), " SUSPENDING " );
  1156. me->DebugConColorMsg( NEXTBOT_BEHAVIOR, Color( 255, 255, 255, 255 ), GetName() );
  1157. me->DebugConColorMsg( NEXTBOT_BEHAVIOR, Color( 255, 255, 255, 255 ), "\n" );
  1158. }
  1159. // suspend child Action
  1160. if ( m_child )
  1161. {
  1162. m_child = m_child->InvokeOnSuspend( me, behavior, interruptingAction );
  1163. }
  1164. // suspend ourselves
  1165. m_isSuspended = true;
  1166. ActionResult< Actor > result = OnSuspend( me, interruptingAction );
  1167. if ( result.IsDone() )
  1168. {
  1169. // we want to be replaced instead of suspended
  1170. InvokeOnEnd( me, behavior, NULL );
  1171. Action< Actor > * buried = GetActionBuriedUnderMe();
  1172. delete this;
  1173. // new Action on top of the stack
  1174. return buried;
  1175. }
  1176. // we are still on top of the stack at this moment
  1177. return this;
  1178. }
  1179. //-------------------------------------------------------------------------------------------
  1180. template < typename Actor >
  1181. ActionResult< Actor > Action< Actor >::InvokeOnResume( Actor *me, Behavior< Actor > *behavior, Action< Actor > *interruptingAction )
  1182. {
  1183. if ( me->IsDebugging( NEXTBOT_BEHAVIOR ) || NextBotDebugHistory.GetBool() )
  1184. {
  1185. me->DebugConColorMsg( NEXTBOT_BEHAVIOR, Color( 255, 255, 150, 255 ), "%3.2f: %s:%s: ", gpGlobals->curtime, me->GetDebugIdentifier(), behavior->GetName() );
  1186. me->DebugConColorMsg( NEXTBOT_BEHAVIOR, Color( 255, 0, 255, 255 ), " RESUMING " );
  1187. me->DebugConColorMsg( NEXTBOT_BEHAVIOR, Color( 255, 255, 255, 255 ), GetName() );
  1188. me->DebugConColorMsg( NEXTBOT_BEHAVIOR, Color( 255, 255, 255, 255 ), "\n" );
  1189. }
  1190. if ( !m_isSuspended )
  1191. {
  1192. // we were never suspended
  1193. return Continue();
  1194. }
  1195. if ( m_eventResult.IsRequestingChange() )
  1196. {
  1197. // this Action is not actually being Resumed, because a change
  1198. // is already pending from a prior event
  1199. return Continue();
  1200. }
  1201. // resume ourselves
  1202. m_isSuspended = false;
  1203. m_coveringMe = NULL;
  1204. if ( m_parent )
  1205. {
  1206. // we are once again our parent's active child
  1207. m_parent->m_child = this;
  1208. }
  1209. // resume child Action
  1210. if ( m_child )
  1211. {
  1212. m_child = m_child->ApplyResult( me, behavior, m_child->InvokeOnResume( me, behavior, interruptingAction ) );
  1213. }
  1214. // actually resume ourselves
  1215. ActionResult< Actor > result = OnResume( me, interruptingAction );
  1216. return result;
  1217. }
  1218. //-------------------------------------------------------------------------------------------
  1219. /**
  1220. * Given the result of this Action's work, apply the result to potentially create a new Action
  1221. */
  1222. template < typename Actor >
  1223. Action< Actor > *Action< Actor >::ApplyResult( Actor *me, Behavior< Actor > *behavior, ActionResult< Actor > result )
  1224. {
  1225. Action< Actor > *newAction = result.m_action;
  1226. switch( result.m_type )
  1227. {
  1228. //-----------------------------------------------------------------------------------------------------
  1229. // transition to new Action
  1230. case CHANGE_TO:
  1231. {
  1232. if ( newAction == NULL )
  1233. {
  1234. DevMsg( "Error: Attempted CHANGE_TO to a NULL Action\n" );
  1235. AssertMsg( false, "Action: Attempted CHANGE_TO to a NULL Action" );
  1236. return this;
  1237. }
  1238. // debug display
  1239. if ( me->IsDebugging( NEXTBOT_BEHAVIOR ) || NextBotDebugHistory.GetBool() )
  1240. {
  1241. me->DebugConColorMsg( NEXTBOT_BEHAVIOR, Color( 255, 255, 150, 255 ), "%3.2f: %s:%s: ", gpGlobals->curtime, me->GetDebugIdentifier(), behavior->GetName() );
  1242. if ( this == newAction )
  1243. {
  1244. me->DebugConColorMsg( NEXTBOT_BEHAVIOR, Color( 255, 0, 0, 255 ), "START " );
  1245. me->DebugConColorMsg( NEXTBOT_BEHAVIOR, Color( 255, 255, 255, 255 ), newAction->GetName() );
  1246. }
  1247. else
  1248. {
  1249. me->DebugConColorMsg( NEXTBOT_BEHAVIOR, Color( 255, 255, 255, 255 ), this->GetName() );
  1250. me->DebugConColorMsg( NEXTBOT_BEHAVIOR, Color( 255, 0, 0, 255 ), " CHANGE_TO " );
  1251. me->DebugConColorMsg( NEXTBOT_BEHAVIOR, Color( 255, 255, 255, 255 ), newAction->GetName() );
  1252. }
  1253. if ( result.m_reason )
  1254. {
  1255. me->DebugConColorMsg( NEXTBOT_BEHAVIOR, Color( 150, 255, 150, 255 ), " (%s)\n", result.m_reason );
  1256. }
  1257. else
  1258. {
  1259. me->DebugConColorMsg( NEXTBOT_BEHAVIOR, Color( 255, 255, 255, 255 ), "\n" );
  1260. }
  1261. }
  1262. // we are done
  1263. this->InvokeOnEnd( me, behavior, newAction );
  1264. // start the new Action
  1265. ActionResult< Actor > startResult = newAction->InvokeOnStart( me, behavior, this, this->m_buriedUnderMe );
  1266. // discard ended action
  1267. if ( this != newAction )
  1268. {
  1269. delete this;
  1270. }
  1271. // debug display
  1272. if ( me->IsDebugging( NEXTBOT_BEHAVIOR ) )
  1273. {
  1274. newAction->PrintStateToConsole();
  1275. }
  1276. // apply result of starting the Action
  1277. return newAction->ApplyResult( me, behavior, startResult );
  1278. }
  1279. //-----------------------------------------------------------------------------------------------------
  1280. // temporarily suspend ourselves for the newAction, covering it on the stack
  1281. case SUSPEND_FOR:
  1282. {
  1283. // interrupting Action always goes on the TOP of the stack - find it
  1284. Action< Actor > *topAction = this;
  1285. while ( topAction->m_coveringMe )
  1286. {
  1287. topAction = topAction->m_coveringMe;
  1288. }
  1289. // debug display
  1290. if ( me->IsDebugging( NEXTBOT_BEHAVIOR ) || NextBotDebugHistory.GetBool() )
  1291. {
  1292. me->DebugConColorMsg( NEXTBOT_BEHAVIOR, Color( 255, 255, 150, 255 ), "%3.2f: %s:%s: ", gpGlobals->curtime, me->GetDebugIdentifier(), behavior->GetName() );
  1293. me->DebugConColorMsg( NEXTBOT_BEHAVIOR, Color( 255, 255, 255, 255 ), this->GetName() );
  1294. me->DebugConColorMsg( NEXTBOT_BEHAVIOR, Color( 255, 0, 255, 255 ), " caused " );
  1295. me->DebugConColorMsg( NEXTBOT_BEHAVIOR, Color( 255, 255, 255, 255 ), topAction->GetName() );
  1296. me->DebugConColorMsg( NEXTBOT_BEHAVIOR, Color( 255, 0, 255, 255 ), " to SUSPEND_FOR " );
  1297. me->DebugConColorMsg( NEXTBOT_BEHAVIOR, Color( 255, 255, 255, 255 ), newAction->GetName() );
  1298. if ( result.m_reason )
  1299. {
  1300. me->DebugConColorMsg( NEXTBOT_BEHAVIOR, Color( 150, 255, 150, 255 ), " (%s)\n", result.m_reason );
  1301. }
  1302. else
  1303. {
  1304. me->DebugConColorMsg( NEXTBOT_BEHAVIOR, Color( 255, 255, 255, 255 ), "\n" );
  1305. }
  1306. }
  1307. // suspend the Action we just covered up
  1308. topAction = topAction->InvokeOnSuspend( me, behavior, newAction );
  1309. // begin the interrupting Action.
  1310. ActionResult< Actor > startResult = newAction->InvokeOnStart( me, behavior, topAction, topAction );
  1311. // debug display
  1312. if ( me->IsDebugging( NEXTBOT_BEHAVIOR ) )
  1313. {
  1314. newAction->PrintStateToConsole();
  1315. }
  1316. return newAction->ApplyResult( me, behavior, startResult );
  1317. }
  1318. //-----------------------------------------------------------------------------------------------------
  1319. case DONE:
  1320. {
  1321. // resume buried action
  1322. Action< Actor > *resumedAction = this->m_buriedUnderMe;
  1323. // we are finished
  1324. this->InvokeOnEnd( me, behavior, resumedAction );
  1325. // debug display
  1326. if ( me->IsDebugging( NEXTBOT_BEHAVIOR ) || NextBotDebugHistory.GetBool() )
  1327. {
  1328. me->DebugConColorMsg( NEXTBOT_BEHAVIOR, Color( 255, 255, 150, 255 ), "%3.2f: %s:%s: ", gpGlobals->curtime, me->GetDebugIdentifier(), behavior->GetName() );
  1329. me->DebugConColorMsg( NEXTBOT_BEHAVIOR, Color( 255, 255, 255, 255 ), this->GetName() );
  1330. if ( resumedAction )
  1331. {
  1332. me->DebugConColorMsg( NEXTBOT_BEHAVIOR, Color( 0, 255, 0, 255 ), " DONE, RESUME " );
  1333. me->DebugConColorMsg( NEXTBOT_BEHAVIOR, Color( 255, 255, 255, 255 ), resumedAction->GetName() );
  1334. }
  1335. else
  1336. {
  1337. me->DebugConColorMsg( NEXTBOT_BEHAVIOR, Color( 0, 255, 0, 255 ), " DONE." );
  1338. }
  1339. if ( result.m_reason )
  1340. {
  1341. me->DebugConColorMsg( NEXTBOT_BEHAVIOR, Color( 150, 255, 150, 255 ), " (%s)\n", result.m_reason );
  1342. }
  1343. else
  1344. {
  1345. me->DebugConColorMsg( NEXTBOT_BEHAVIOR, Color( 255, 255, 255, 255 ), "\n" );
  1346. }
  1347. }
  1348. if ( resumedAction == NULL )
  1349. {
  1350. // all Actions complete
  1351. delete this;
  1352. return NULL;
  1353. }
  1354. // resume uncovered action
  1355. ActionResult< Actor > resumeResult = resumedAction->InvokeOnResume( me, behavior, this );
  1356. // debug display
  1357. if ( me->IsDebugging( NEXTBOT_BEHAVIOR ) )
  1358. {
  1359. resumedAction->PrintStateToConsole();
  1360. }
  1361. // discard ended action
  1362. delete this;
  1363. // apply result of OnResume()
  1364. return resumedAction->ApplyResult( me, behavior, resumeResult );
  1365. }
  1366. case CONTINUE:
  1367. case SUSTAIN:
  1368. default:
  1369. {
  1370. // no change, continue the current action next frame
  1371. return this;
  1372. }
  1373. }
  1374. }
  1375. //-------------------------------------------------------------------------------------------
  1376. /**
  1377. * Propagate events to sub actions
  1378. */
  1379. template < typename Actor >
  1380. INextBotEventResponder *Action< Actor >::FirstContainedResponder( void ) const
  1381. {
  1382. return GetActiveChildAction();
  1383. }
  1384. template < typename Actor >
  1385. INextBotEventResponder *Action< Actor >::NextContainedResponder( INextBotEventResponder *current ) const
  1386. {
  1387. return NULL;
  1388. }
  1389. //-------------------------------------------------------------------------------------------
  1390. /**
  1391. * Return a temporary string describing the current action stack for debugging
  1392. */
  1393. template < typename Actor >
  1394. const char *Action< Actor >::DebugString( void ) const
  1395. {
  1396. static char str[ 256 ];
  1397. str[0] = '\000';
  1398. // find root
  1399. const Action< Actor > *root = this;
  1400. while ( root->m_parent )
  1401. {
  1402. root = root->m_parent;
  1403. }
  1404. return BuildDecoratedName( str, root );
  1405. }
  1406. //-------------------------------------------------------------------------------------------
  1407. template < typename Actor >
  1408. char *Action< Actor >::BuildDecoratedName( char *name, const Action< Actor > *action ) const
  1409. {
  1410. const int fudge = 256;
  1411. // add the name of the given action
  1412. Q_strcat( name, action->GetName(), fudge );
  1413. // add any contained actions
  1414. const Action< Actor > *child = action->GetActiveChildAction();
  1415. if ( child )
  1416. {
  1417. Q_strcat( name, "( ", fudge );
  1418. BuildDecoratedName( name, child );
  1419. Q_strcat( name, " )", fudge );
  1420. }
  1421. // append buried actions
  1422. const Action< Actor > *buried = action->GetActionBuriedUnderMe();
  1423. if ( buried )
  1424. {
  1425. Q_strcat( name, "<<", fudge );
  1426. BuildDecoratedName( name, buried );
  1427. }
  1428. return name;
  1429. }
  1430. //-------------------------------------------------------------------------------------------
  1431. /**
  1432. * Return a temporary string showing the full lineage of this one action
  1433. */
  1434. template < typename Actor >
  1435. const char *Action< Actor >::GetFullName( void ) const
  1436. {
  1437. const int fudge = 256;
  1438. static char str[ fudge ];
  1439. str[0] = '\000';
  1440. const int maxStack = 64;
  1441. const char *nameStack[ maxStack ];
  1442. int stackIndex = 0;
  1443. for( const Action< Actor > *action = this;
  1444. stackIndex < maxStack && action;
  1445. action = action->m_parent )
  1446. {
  1447. nameStack[ stackIndex++ ] = action->GetName();
  1448. }
  1449. // assemble name
  1450. int i;
  1451. for( i = stackIndex-1; i; --i )
  1452. {
  1453. Q_strcat( str, nameStack[ i ], fudge );
  1454. Q_strcat( str, "/", fudge );
  1455. }
  1456. Q_strcat( str, nameStack[ 0 ], fudge );
  1457. /*
  1458. for( i = 0; i < stackIndex-1; ++i )
  1459. {
  1460. Q_strcat( str, " )", fudge );
  1461. }
  1462. */
  1463. return str;
  1464. }
  1465. //-------------------------------------------------------------------------------------------
  1466. template < typename Actor >
  1467. void Action< Actor >::PrintStateToConsole( void ) const
  1468. {
  1469. // emit the Behavior name
  1470. //ConColorMsg( Color( 255, 255, 255, 255 ), "%s: ", m_behavior->GetName() );
  1471. // build the state string
  1472. const char *msg = DebugString();
  1473. const int colorCount = 6;
  1474. Color colorTable[ colorCount ];
  1475. colorTable[ 0 ].SetColor( 255, 150, 150, 255 );
  1476. colorTable[ 1 ].SetColor( 150, 255, 150, 255 );
  1477. colorTable[ 2 ].SetColor( 150, 150, 255, 255 );
  1478. colorTable[ 3 ].SetColor( 255, 255, 150, 255 );
  1479. colorTable[ 4 ].SetColor( 50, 255, 255, 255 );
  1480. colorTable[ 5 ].SetColor( 255, 150, 255, 255 );
  1481. // output the color-coded state string
  1482. const int maxBufferSize = 256;
  1483. char buffer[ maxBufferSize ];
  1484. int colorIndex = 0;
  1485. int buriedLevel = 0;
  1486. char *outMsg = buffer;
  1487. for( const char *c = msg; *c != '\000'; ++c )
  1488. {
  1489. *outMsg = *c;
  1490. ++outMsg;
  1491. if ( *c == '(' )
  1492. {
  1493. *outMsg = '\000';
  1494. Color color = colorTable[ colorIndex ];
  1495. if ( buriedLevel )
  1496. {
  1497. // draw buried labels darkly
  1498. color.SetColor( color.r() * 0.5, color.g() * 0.5, color.b() * 0.5, 255 );
  1499. ++buriedLevel;
  1500. }
  1501. ConColorMsg( color, buffer );
  1502. colorIndex = ( colorIndex + 1 ) % colorCount;
  1503. outMsg = buffer;
  1504. }
  1505. else if ( *c == ')' )
  1506. {
  1507. // emit the closing paren with next batch
  1508. --outMsg;
  1509. *outMsg = '\000';
  1510. Color color = colorTable[ colorIndex ];
  1511. if ( buriedLevel )
  1512. {
  1513. // draw buried labels darkly
  1514. color.SetColor( color.r() * 0.5, color.g() * 0.5, color.b() * 0.5, 255 );
  1515. --buriedLevel;
  1516. }
  1517. ConColorMsg( color, buffer );
  1518. --colorIndex;
  1519. if ( colorIndex < 0 )
  1520. colorIndex = colorCount-1;
  1521. outMsg = buffer;
  1522. *outMsg = ')';
  1523. ++outMsg;
  1524. }
  1525. else if ( *c == '<' && buriedLevel == 0 )
  1526. {
  1527. // caught a "<<" stack push
  1528. ++c;
  1529. *outMsg = '<';
  1530. ++outMsg;
  1531. *outMsg = '\000';
  1532. // output active substring at full brightness
  1533. ConColorMsg( colorTable[ colorIndex ], buffer );
  1534. outMsg = buffer;
  1535. // from here until end of Action, use dim colors
  1536. buriedLevel = 1;
  1537. }
  1538. }
  1539. *outMsg = '\000';
  1540. ConColorMsg( colorTable[ colorIndex ], buffer );
  1541. ConColorMsg( colorTable[ colorIndex ], "\n\n" );
  1542. }
  1543. #endif // _BEHAVIOR_ENGINE_H_