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.

211 lines
8.1 KiB

  1. // NextBotIntentionInterface.h
  2. // Interface for intentional thinking
  3. // Author: Michael Booth, April 2005
  4. //========= Copyright Valve Corporation, All rights reserved. ============//
  5. #ifndef _NEXT_BOT_INTENTION_INTERFACE_H_
  6. #define _NEXT_BOT_INTENTION_INTERFACE_H_
  7. #include "NextBotComponentInterface.h"
  8. #include "NextBotContextualQueryInterface.h"
  9. class INextBot;
  10. //
  11. // Insert this macro in your INextBot-derived class declaration to
  12. // create a IIntention-derived class that handles the bookkeeping
  13. // of instantiating a Behavior with an initial Action and updating it.
  14. //
  15. #define DECLARE_INTENTION_INTERFACE( Actor ) \
  16. \
  17. class Actor##Intention : public IIntention \
  18. { \
  19. public: \
  20. Actor##Intention( Actor *me ); \
  21. virtual ~Actor##Intention(); \
  22. virtual void Reset( void ); \
  23. virtual void Update( void ); \
  24. virtual INextBotEventResponder *FirstContainedResponder( void ) const { return m_behavior; } \
  25. virtual INextBotEventResponder *NextContainedResponder( INextBotEventResponder *current ) const { return NULL; } \
  26. private: \
  27. Behavior< Actor > *m_behavior; \
  28. }; \
  29. \
  30. public: virtual IIntention *GetIntentionInterface( void ) const { return m_intention; } \
  31. private: Actor##Intention *m_intention; \
  32. public:
  33. //
  34. // Use this macro to create the implementation code for the IIntention-derived class
  35. // declared above. Since this requires InitialAction, it must occur after
  36. // that Action has been declared, so it can be new'd here.
  37. //
  38. #define IMPLEMENT_INTENTION_INTERFACE( Actor, InitialAction ) \
  39. Actor::Actor##Intention::Actor##Intention( Actor *me ) : IIntention( me ) { m_behavior = new Behavior< Actor >( new InitialAction ); } \
  40. Actor::Actor##Intention::~Actor##Intention() { delete m_behavior; } \
  41. void Actor::Actor##Intention::Reset( void ) { delete m_behavior; m_behavior = new Behavior< Actor >( new InitialAction ); } \
  42. void Actor::Actor##Intention::Update( void ) { m_behavior->Update( static_cast< Actor * >( GetBot() ), GetUpdateInterval() ); }
  43. //
  44. // Use this macro in the constructor of your bot to allocate the IIntention-derived class
  45. //
  46. #define ALLOCATE_INTENTION_INTERFACE( Actor ) { m_intention = new Actor##Intention( this ); }
  47. //
  48. // Use this macro in the destructor of your bot to deallocate the IIntention-derived class
  49. //
  50. #define DEALLOCATE_INTENTION_INTERFACE { if ( m_intention ) delete m_intention; }
  51. //----------------------------------------------------------------------------------------------------------------
  52. /**
  53. * The interface for intentional thinking.
  54. * The assumption is that this is a container for one or more concurrent Behaviors.
  55. * The "primary" Behavior is the FirstContainedResponder, and so on.
  56. * IContextualQuery requests are prioritized in contained responder order, such that the first responder
  57. * that returns a definitive answer is accepted. WITHIN a given responder (ie: a Behavior), the deepest child
  58. * Behavior in the active stack is asked first, then its parent, and so on, allowing the most specific active
  59. * Behavior to override the query responses of its more general parent Behaviors.
  60. */
  61. class IIntention : public INextBotComponent, public IContextualQuery
  62. {
  63. public:
  64. IIntention( INextBot *bot ) : INextBotComponent( bot ) { }
  65. virtual ~IIntention() { }
  66. virtual void Reset( void ) { INextBotComponent::Reset(); } // reset to initial state
  67. virtual void Update( void ) { } // update internal state
  68. // IContextualQuery propagation --------------------------------
  69. virtual QueryResultType ShouldPickUp( const INextBot *me, CBaseEntity *item ) const; // if the desired item was available right now, should we pick it up?
  70. virtual QueryResultType ShouldHurry( const INextBot *me ) const; // are we in a hurry?
  71. virtual QueryResultType ShouldRetreat( const INextBot *me ) const; // is it time to retreat?
  72. virtual QueryResultType ShouldAttack( const INextBot *me, const CKnownEntity *them ) const; // should we attack "them"?
  73. 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.
  74. virtual Vector SelectTargetPoint( const INextBot *me, const CBaseCombatCharacter *subject ) const; // given a subject, return the world space position we should aim at
  75. virtual QueryResultType IsPositionAllowed( const INextBot *me, const Vector &pos ) const; // is the a place we can be?
  76. virtual const CKnownEntity * SelectMoreDangerousThreat( const INextBot *me,
  77. const CBaseCombatCharacter *subject, // the subject of the danger
  78. const CKnownEntity *threat1,
  79. const CKnownEntity *threat2 ) const; // return the more dangerous of the two threats, or NULL if we have no opinion
  80. // NOTE: As further queries are added, update the Behavior class to propagate them
  81. };
  82. inline QueryResultType IIntention::ShouldPickUp( const INextBot *me, CBaseEntity *item ) const
  83. {
  84. for ( INextBotEventResponder *sub = FirstContainedResponder(); sub; sub = NextContainedResponder( sub ) )
  85. {
  86. const IContextualQuery *query = dynamic_cast< const IContextualQuery * >( sub );
  87. if ( query )
  88. {
  89. // return the response of the first responder that gives a definitive answer
  90. QueryResultType result = query->ShouldPickUp( me, item );
  91. if ( result != ANSWER_UNDEFINED )
  92. {
  93. return result;
  94. }
  95. }
  96. }
  97. return ANSWER_UNDEFINED;
  98. }
  99. inline QueryResultType IIntention::ShouldHurry( const INextBot *me ) const
  100. {
  101. for ( INextBotEventResponder *sub = FirstContainedResponder(); sub; sub = NextContainedResponder( sub ) )
  102. {
  103. const IContextualQuery *query = dynamic_cast< const IContextualQuery * >( sub );
  104. if ( query )
  105. {
  106. // return the response of the first responder that gives a definitive answer
  107. QueryResultType result = query->ShouldHurry( me );
  108. if ( result != ANSWER_UNDEFINED )
  109. {
  110. return result;
  111. }
  112. }
  113. }
  114. return ANSWER_UNDEFINED;
  115. }
  116. inline QueryResultType IIntention::ShouldRetreat( const INextBot *me ) const
  117. {
  118. for ( INextBotEventResponder *sub = FirstContainedResponder(); sub; sub = NextContainedResponder( sub ) )
  119. {
  120. const IContextualQuery *query = dynamic_cast< const IContextualQuery * >( sub );
  121. if ( query )
  122. {
  123. // return the response of the first responder that gives a definitive answer
  124. QueryResultType result = query->ShouldRetreat( me );
  125. if ( result != ANSWER_UNDEFINED )
  126. {
  127. return result;
  128. }
  129. }
  130. }
  131. return ANSWER_UNDEFINED;
  132. }
  133. inline QueryResultType IIntention::ShouldAttack( const INextBot *me, const CKnownEntity *them ) const
  134. {
  135. for ( INextBotEventResponder *sub = FirstContainedResponder(); sub; sub = NextContainedResponder( sub ) )
  136. {
  137. const IContextualQuery *query = dynamic_cast< const IContextualQuery * >( sub );
  138. if ( query )
  139. {
  140. // return the response of the first responder that gives a definitive answer
  141. QueryResultType result = query->ShouldAttack( me, them );
  142. if ( result != ANSWER_UNDEFINED )
  143. {
  144. return result;
  145. }
  146. }
  147. }
  148. return ANSWER_UNDEFINED;
  149. }
  150. inline QueryResultType IIntention::IsHindrance( const INextBot *me, CBaseEntity *blocker ) const
  151. {
  152. for ( INextBotEventResponder *sub = FirstContainedResponder(); sub; sub = NextContainedResponder( sub ) )
  153. {
  154. const IContextualQuery *query = dynamic_cast< const IContextualQuery * >( sub );
  155. if ( query )
  156. {
  157. // return the response of the first responder that gives a definitive answer
  158. QueryResultType result = query->IsHindrance( me, blocker );
  159. if ( result != ANSWER_UNDEFINED )
  160. {
  161. return result;
  162. }
  163. }
  164. }
  165. return ANSWER_UNDEFINED;
  166. }
  167. inline QueryResultType IIntention::IsPositionAllowed( const INextBot *me, const Vector &pos ) const
  168. {
  169. for ( INextBotEventResponder *sub = FirstContainedResponder(); sub; sub = NextContainedResponder( sub ) )
  170. {
  171. const IContextualQuery *query = dynamic_cast< const IContextualQuery * >( sub );
  172. if ( query )
  173. {
  174. // return the response of the first responder that gives a definitive answer
  175. QueryResultType result = query->IsPositionAllowed( me, pos );
  176. if ( result != ANSWER_UNDEFINED )
  177. {
  178. return result;
  179. }
  180. }
  181. }
  182. return ANSWER_UNDEFINED;
  183. }
  184. #endif // _NEXT_BOT_INTENTION_INTERFACE_H_