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.

339 lines
10 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //
  7. //=============================================================================//
  8. #include "cbase.h"
  9. #include "func_suggested_build.h"
  10. #include "tf_shareddefs.h"
  11. #include "tf_obj.h"
  12. #include "triggers.h"
  13. // memdbgon must be the last include file in a .cpp file!!!
  14. #include "tier0/memdbgon.h"
  15. //-----------------------------------------------------------------------------
  16. enum
  17. {
  18. kObjectType_Any,
  19. kObjectType_Sentry,
  20. kObjectType_Dispenser,
  21. kObjectType_TeleporterEntrance,
  22. kObjectType_TeleporterExit,
  23. };
  24. enum
  25. {
  26. kSpawnFlag_BuiltObjectNeverDies = 1 << 0,
  27. };
  28. class CFuncSuggestedBuild : public CBaseTrigger
  29. {
  30. DECLARE_CLASS( CFuncSuggestedBuild, CBaseTrigger );
  31. public:
  32. CFuncSuggestedBuild();
  33. DECLARE_DATADESC();
  34. virtual void Spawn( void );
  35. virtual void Precache( void );
  36. virtual void Activate( void );
  37. // Inputs
  38. void InputSetActive( inputdata_t &inputdata );
  39. void InputSetInactive( inputdata_t &inputdata );
  40. void InputToggleActive( inputdata_t &inputdata );
  41. void SetActive( bool bActive );
  42. bool GetActive() const;
  43. bool MatchesObjectType( int iObjectType, int iObjectMode ) const;
  44. bool IsPointInArea( const Vector &vecPoint );
  45. bool IsFacingRequiredEntity( CBaseObject &baseObject ) const;
  46. void OnBuildInArea( CBaseObject& baseObject );
  47. void OnBuildInAreaNotFacing( CBaseObject& baseObject );
  48. void OnBuildingUpgraded( CBaseObject& baseObject );
  49. private:
  50. bool m_bActive;
  51. int m_iObjectType;
  52. string_t m_sFaceEntityName;
  53. float m_flFaceEntityFOV;
  54. CHandle< CBaseEntity > m_hFaceEntity;
  55. COutputEvent m_outputBuildInsideArea;
  56. COutputEvent m_outputBuildNotFacing;
  57. COutputEvent m_outputBuildingUpgraded;
  58. };
  59. LINK_ENTITY_TO_CLASS( func_suggested_build, CFuncSuggestedBuild);
  60. BEGIN_DATADESC( CFuncSuggestedBuild )
  61. DEFINE_KEYFIELD( m_iObjectType, FIELD_INTEGER, "object_type" ),
  62. DEFINE_KEYFIELD( m_sFaceEntityName, FIELD_STRING, "face_entity" ),
  63. DEFINE_KEYFIELD( m_flFaceEntityFOV, FIELD_FLOAT, "face_entity_fov" ),
  64. // inputs
  65. DEFINE_INPUTFUNC( FIELD_VOID, "SetActive", InputSetActive ),
  66. DEFINE_INPUTFUNC( FIELD_VOID, "SetInactive", InputSetInactive ),
  67. DEFINE_INPUTFUNC( FIELD_VOID, "ToggleActive", InputToggleActive ),
  68. // outputs
  69. DEFINE_OUTPUT( m_outputBuildInsideArea, "OnBuildInsideArea" ),
  70. DEFINE_OUTPUT( m_outputBuildNotFacing, "OnBuildNotFacing" ),
  71. DEFINE_OUTPUT( m_outputBuildingUpgraded, "OnBuildingUpgraded" ),
  72. END_DATADESC()
  73. PRECACHE_REGISTER( func_suggested_build );
  74. const float kDefaultFacingFOV = cos(M_PI);
  75. //-----------------------------------------------------------------------------
  76. // Purpose:
  77. //-----------------------------------------------------------------------------
  78. CFuncSuggestedBuild::CFuncSuggestedBuild()
  79. : CBaseTrigger()
  80. , m_bActive(false)
  81. , m_iObjectType(kObjectType_Any)
  82. , m_flFaceEntityFOV(kDefaultFacingFOV)
  83. {
  84. }
  85. //-----------------------------------------------------------------------------
  86. // Purpose: Initializes the resource zone
  87. //-----------------------------------------------------------------------------
  88. void CFuncSuggestedBuild::Spawn( void )
  89. {
  90. BaseClass::Spawn();
  91. InitTrigger();
  92. m_bActive = true;
  93. }
  94. //-----------------------------------------------------------------------------
  95. // Purpose:
  96. //-----------------------------------------------------------------------------
  97. void CFuncSuggestedBuild::Precache( void )
  98. {
  99. }
  100. //-----------------------------------------------------------------------------
  101. // Purpose:
  102. //-----------------------------------------------------------------------------
  103. void CFuncSuggestedBuild::Activate( void )
  104. {
  105. BaseClass::Activate();
  106. SetActive( true );
  107. m_hFaceEntity = gEntList.FindEntityByName( NULL, m_sFaceEntityName.ToCStr() );
  108. m_flFaceEntityFOV = cos( DEG2RAD( m_flFaceEntityFOV ) );
  109. }
  110. //-----------------------------------------------------------------------------
  111. // Purpose:
  112. //-----------------------------------------------------------------------------
  113. void CFuncSuggestedBuild::InputSetActive( inputdata_t &inputdata )
  114. {
  115. SetActive( true );
  116. }
  117. //-----------------------------------------------------------------------------
  118. // Purpose:
  119. //-----------------------------------------------------------------------------
  120. void CFuncSuggestedBuild::InputSetInactive( inputdata_t &inputdata )
  121. {
  122. SetActive( false );
  123. }
  124. //-----------------------------------------------------------------------------
  125. // Purpose:
  126. //-----------------------------------------------------------------------------
  127. void CFuncSuggestedBuild::InputToggleActive( inputdata_t &inputdata )
  128. {
  129. SetActive( !m_bActive );
  130. }
  131. //-----------------------------------------------------------------------------
  132. // Purpose:
  133. //-----------------------------------------------------------------------------
  134. void CFuncSuggestedBuild::SetActive( bool bActive )
  135. {
  136. m_bActive = bActive;
  137. }
  138. //-----------------------------------------------------------------------------
  139. // Purpose:
  140. //-----------------------------------------------------------------------------
  141. bool CFuncSuggestedBuild::GetActive() const
  142. {
  143. return m_bActive;
  144. }
  145. //-----------------------------------------------------------------------------
  146. // Purpose:
  147. //-----------------------------------------------------------------------------
  148. bool CFuncSuggestedBuild::MatchesObjectType( int iObjectType, int iObjectMode ) const
  149. {
  150. bool bPassesCriteria = true;
  151. switch ( m_iObjectType )
  152. {
  153. case kObjectType_Any:
  154. bPassesCriteria = true;
  155. break;
  156. case kObjectType_Sentry:
  157. bPassesCriteria = iObjectType == OBJ_SENTRYGUN;
  158. break;
  159. case kObjectType_Dispenser:
  160. bPassesCriteria = iObjectType == OBJ_DISPENSER;
  161. break;
  162. case kObjectType_TeleporterEntrance:
  163. bPassesCriteria = iObjectType == OBJ_TELEPORTER && iObjectMode == MODE_TELEPORTER_ENTRANCE;
  164. break;
  165. case kObjectType_TeleporterExit:
  166. bPassesCriteria = iObjectType == OBJ_TELEPORTER && iObjectMode == MODE_TELEPORTER_EXIT;
  167. break;
  168. }
  169. return bPassesCriteria;
  170. }
  171. //-----------------------------------------------------------------------------
  172. // Purpose:
  173. //-----------------------------------------------------------------------------
  174. bool CFuncSuggestedBuild::IsPointInArea( const Vector &vecPoint )
  175. {
  176. Ray_t ray;
  177. trace_t tr;
  178. ICollideable *pCollide = CollisionProp();
  179. ray.Init( vecPoint, vecPoint );
  180. enginetrace->ClipRayToCollideable( ray, MASK_ALL, pCollide, &tr );
  181. return ( tr.startsolid );
  182. }
  183. //-----------------------------------------------------------------------------
  184. // Purpose:
  185. //-----------------------------------------------------------------------------
  186. bool CFuncSuggestedBuild::IsFacingRequiredEntity( CBaseObject &baseObject ) const
  187. {
  188. if ( m_hFaceEntity )
  189. {
  190. // check to see if the object is facing the required entity in 2D
  191. Vector facingDir;
  192. AngleVectors( baseObject.GetAbsAngles(), &facingDir );
  193. Vector toEntity = m_hFaceEntity->GetAbsOrigin() - baseObject.GetAbsOrigin();
  194. toEntity.z = 0;
  195. toEntity.NormalizeInPlace();
  196. if ( toEntity.IsZero() == false )
  197. {
  198. float cosAngle = DotProduct( toEntity, facingDir );
  199. float cosTolerance = m_flFaceEntityFOV;
  200. return cosAngle > cosTolerance;
  201. }
  202. return false;
  203. }
  204. return true;
  205. }
  206. //-----------------------------------------------------------------------------
  207. // Purpose:
  208. //-----------------------------------------------------------------------------
  209. void CFuncSuggestedBuild::OnBuildInArea( CBaseObject& baseObject )
  210. {
  211. m_outputBuildInsideArea.FireOutput( &baseObject, this );
  212. }
  213. //-----------------------------------------------------------------------------
  214. // Purpose:
  215. //-----------------------------------------------------------------------------
  216. void CFuncSuggestedBuild::OnBuildInAreaNotFacing( CBaseObject& baseObject )
  217. {
  218. m_outputBuildNotFacing.FireOutput( &baseObject, this );
  219. }
  220. //-----------------------------------------------------------------------------
  221. // Purpose:
  222. //-----------------------------------------------------------------------------
  223. void CFuncSuggestedBuild::OnBuildingUpgraded( CBaseObject& baseObject )
  224. {
  225. m_outputBuildingUpgraded.FireOutput( &baseObject, this );
  226. }
  227. //-----------------------------------------------------------------------------
  228. // Purpose:
  229. //-----------------------------------------------------------------------------
  230. bool NotifyObjectBuiltInSuggestedArea( CBaseObject &baseObject )
  231. {
  232. const Vector &vecBuildOrigin = baseObject.GetAbsOrigin();
  233. int iObjectType = baseObject.ObjectType();
  234. int iObjectMode = baseObject.GetObjectMode();
  235. CBaseEntity *pEntity = NULL;
  236. while ( ( pEntity = gEntList.FindEntityByClassname( pEntity, "func_suggested_build" ) ) != NULL )
  237. {
  238. CFuncSuggestedBuild *pSuggestedBuild = (CFuncSuggestedBuild *)pEntity;
  239. if ( pSuggestedBuild->GetActive() == false )
  240. {
  241. continue;
  242. }
  243. if ( pSuggestedBuild->MatchesObjectType( iObjectType, iObjectMode ) == false )
  244. {
  245. continue;
  246. }
  247. if ( pSuggestedBuild->IsPointInArea( vecBuildOrigin ) == false )
  248. {
  249. continue;
  250. }
  251. // check orientation last
  252. if ( pSuggestedBuild->IsFacingRequiredEntity( baseObject ) == false )
  253. {
  254. pSuggestedBuild->OnBuildInAreaNotFacing( baseObject );
  255. return true;
  256. }
  257. else
  258. {
  259. // fire off output
  260. pSuggestedBuild->OnBuildInArea( baseObject );
  261. // "transfer" flags
  262. if ( pSuggestedBuild->HasSpawnFlags( kSpawnFlag_BuiltObjectNeverDies ) )
  263. {
  264. baseObject.SetCannotDie( true );
  265. }
  266. return true;
  267. }
  268. }
  269. return false;
  270. }
  271. //-----------------------------------------------------------------------------
  272. // Purpose:
  273. //-----------------------------------------------------------------------------
  274. bool NotifyObjectUpgradedInSuggestedArea( CBaseObject &baseObject )
  275. {
  276. const Vector &vecBuildOrigin = baseObject.GetAbsOrigin();
  277. int iObjectType = baseObject.ObjectType();
  278. int iObjectMode = baseObject.GetObjectMode();
  279. CBaseEntity *pEntity = NULL;
  280. while ( ( pEntity = gEntList.FindEntityByClassname( pEntity, "func_suggested_build" ) ) != NULL )
  281. {
  282. CFuncSuggestedBuild *pSuggestedBuild = (CFuncSuggestedBuild *)pEntity;
  283. if ( pSuggestedBuild->GetActive() == false )
  284. {
  285. continue;
  286. }
  287. if ( pSuggestedBuild->MatchesObjectType( iObjectType, iObjectMode ) == false )
  288. {
  289. continue;
  290. }
  291. if ( pSuggestedBuild->IsPointInArea( vecBuildOrigin ) == false )
  292. {
  293. continue;
  294. }
  295. if ( pSuggestedBuild->IsFacingRequiredEntity( baseObject ) == false )
  296. {
  297. continue;
  298. }
  299. pSuggestedBuild->OnBuildingUpgraded( baseObject );
  300. return true;
  301. }
  302. return false;
  303. }