Team Fortress 2 Source Code as on 22/4/2020
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.

1936 lines
68 KiB

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