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

424 lines
14 KiB

  1. //========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //
  7. //=============================================================================//
  8. #include "cbase.h"
  9. #include "entityoutput.h"
  10. #include "TemplateEntities.h"
  11. #include "point_template.h"
  12. // memdbgon must be the last include file in a .cpp file!!!
  13. #include "tier0/memdbgon.h"
  14. #define SF_ENTMAKER_AUTOSPAWN 0x0001
  15. #define SF_ENTMAKER_WAITFORDESTRUCTION 0x0002
  16. #define SF_ENTMAKER_IGNOREFACING 0x0004
  17. #define SF_ENTMAKER_CHECK_FOR_SPACE 0x0008
  18. #define SF_ENTMAKER_CHECK_PLAYER_LOOKING 0x0010
  19. //extern ScriptClassDesc_t * GetScriptDesc( CBaseEntity * );
  20. //-----------------------------------------------------------------------------
  21. // Purpose: An entity that mapmakers can use to ensure there's a required entity never runs out.
  22. // i.e. physics cannisters that need to be used.
  23. //-----------------------------------------------------------------------------
  24. class CEnvEntityMaker : public CPointEntity
  25. {
  26. DECLARE_CLASS( CEnvEntityMaker, CPointEntity );
  27. public:
  28. DECLARE_DATADESC();
  29. DECLARE_ENT_SCRIPTDESC();
  30. virtual void Spawn( void );
  31. virtual void Activate( void );
  32. void SpawnEntity( Vector vecAlternateOrigin = vec3_invalid, QAngle vecAlternateAngles = vec3_angle );
  33. void CheckSpawnThink( void );
  34. void InputForceSpawn( inputdata_t &inputdata );
  35. void InputForceSpawnAtEntityOrigin( inputdata_t &inputdata );
  36. void SpawnEntityFromScript();
  37. void SpawnEntityAtEntityOriginFromScript( HSCRIPT hEntity );
  38. void SpawnEntityAtNamedEntityOriginFromScript( const char *pszName );
  39. void SpawnEntityAtLocationFromScript( const Vector &vecAlternateOrigin, const Vector &vecAlternateAngles );
  40. private:
  41. CPointTemplate *FindTemplate();
  42. bool HasRoomToSpawn();
  43. bool IsPlayerLooking();
  44. Vector m_vecEntityMins;
  45. Vector m_vecEntityMaxs;
  46. EHANDLE m_hCurrentInstance;
  47. EHANDLE m_hCurrentBlocker; // Last entity that blocked us spawning something
  48. Vector m_vecBlockerOrigin;
  49. // Movement after spawn
  50. QAngle m_angPostSpawnDirection;
  51. float m_flPostSpawnDirectionVariance;
  52. float m_flPostSpawnSpeed;
  53. bool m_bPostSpawnUseAngles;
  54. string_t m_iszTemplate;
  55. COutputEvent m_pOutputOnSpawned;
  56. COutputEvent m_pOutputOnFailedSpawn;
  57. };
  58. BEGIN_DATADESC( CEnvEntityMaker )
  59. // DEFINE_FIELD( m_vecEntityMins, FIELD_VECTOR ),
  60. // DEFINE_FIELD( m_vecEntityMaxs, FIELD_VECTOR ),
  61. DEFINE_FIELD( m_hCurrentInstance, FIELD_EHANDLE ),
  62. DEFINE_FIELD( m_hCurrentBlocker, FIELD_EHANDLE ),
  63. DEFINE_FIELD( m_vecBlockerOrigin, FIELD_VECTOR ),
  64. DEFINE_KEYFIELD( m_iszTemplate, FIELD_STRING, "EntityTemplate" ),
  65. DEFINE_KEYFIELD( m_angPostSpawnDirection, FIELD_VECTOR, "PostSpawnDirection" ),
  66. DEFINE_KEYFIELD( m_flPostSpawnDirectionVariance, FIELD_FLOAT, "PostSpawnDirectionVariance" ),
  67. DEFINE_KEYFIELD( m_flPostSpawnSpeed, FIELD_FLOAT, "PostSpawnSpeed" ),
  68. DEFINE_KEYFIELD( m_bPostSpawnUseAngles, FIELD_BOOLEAN, "PostSpawnInheritAngles" ),
  69. // Outputs
  70. DEFINE_OUTPUT( m_pOutputOnSpawned, "OnEntitySpawned" ),
  71. DEFINE_OUTPUT( m_pOutputOnFailedSpawn, "OnEntityFailedSpawn" ),
  72. // Inputs
  73. DEFINE_INPUTFUNC( FIELD_VOID, "ForceSpawn", InputForceSpawn ),
  74. DEFINE_INPUTFUNC( FIELD_STRING, "ForceSpawnAtEntityOrigin", InputForceSpawnAtEntityOrigin ),
  75. // Functions
  76. DEFINE_THINKFUNC( CheckSpawnThink ),
  77. END_DATADESC()
  78. BEGIN_ENT_SCRIPTDESC( CEnvEntityMaker, CBaseEntity, "env_entity_maker" )
  79. DEFINE_SCRIPTFUNC_NAMED( SpawnEntityFromScript, "SpawnEntity", "Create an entity at the location of the maker" )
  80. DEFINE_SCRIPTFUNC_NAMED( SpawnEntityAtEntityOriginFromScript, "SpawnEntityAtEntityOrigin", "Create an entity at the location of a specified entity instance" )
  81. DEFINE_SCRIPTFUNC_NAMED( SpawnEntityAtNamedEntityOriginFromScript, "SpawnEntityAtNamedEntityOrigin", "Create an entity at the location of a named entity" )
  82. DEFINE_SCRIPTFUNC_NAMED( SpawnEntityAtLocationFromScript, "SpawnEntityAtLocation", "Create an entity at a specified location and orientaton, orientation is Euler angle in degrees (pitch, yaw, roll)" )
  83. END_SCRIPTDESC()
  84. LINK_ENTITY_TO_CLASS( env_entity_maker, CEnvEntityMaker );
  85. //-----------------------------------------------------------------------------
  86. // Purpose:
  87. //-----------------------------------------------------------------------------
  88. void CEnvEntityMaker::Spawn( void )
  89. {
  90. m_vecEntityMins = vec3_origin;
  91. m_vecEntityMaxs = vec3_origin;
  92. m_hCurrentInstance = NULL;
  93. m_hCurrentBlocker = NULL;
  94. m_vecBlockerOrigin = vec3_origin;
  95. }
  96. //-----------------------------------------------------------------------------
  97. // Purpose:
  98. //-----------------------------------------------------------------------------
  99. void CEnvEntityMaker::Activate( void )
  100. {
  101. BaseClass::Activate();
  102. // check for valid template
  103. if ( m_iszTemplate == NULL_STRING )
  104. {
  105. Warning( "env_entity_maker %s has no template entity!\n", GetEntityName().ToCStr() );
  106. UTIL_Remove( this );
  107. return;
  108. }
  109. // Spawn an instance
  110. if ( m_spawnflags & SF_ENTMAKER_AUTOSPAWN )
  111. {
  112. SpawnEntity();
  113. }
  114. }
  115. //-----------------------------------------------------------------------------
  116. // Purpose:
  117. //-----------------------------------------------------------------------------
  118. CPointTemplate *CEnvEntityMaker::FindTemplate()
  119. {
  120. // Find our point_template
  121. CPointTemplate *pTemplate = dynamic_cast<CPointTemplate *>(gEntList.FindEntityByName( NULL, STRING(m_iszTemplate) ));
  122. if ( !pTemplate )
  123. {
  124. Warning( "env_entity_maker %s failed to find template %s.\n", GetEntityName().ToCStr(), STRING(m_iszTemplate) );
  125. }
  126. return pTemplate;
  127. }
  128. //-----------------------------------------------------------------------------
  129. // Purpose: Spawn an instance of the entity
  130. //-----------------------------------------------------------------------------
  131. void CEnvEntityMaker::SpawnEntity( Vector vecAlternateOrigin, QAngle vecAlternateAngles )
  132. {
  133. CPointTemplate *pTemplate = FindTemplate();
  134. if (!pTemplate)
  135. return;
  136. // Spawn our template
  137. Vector vecSpawnOrigin = GetAbsOrigin();
  138. QAngle vecSpawnAngles = GetAbsAngles();
  139. if( vecAlternateOrigin != vec3_invalid )
  140. {
  141. // We have a valid alternate origin and angles. Use those instead
  142. // of spawning the items at my own origin and angles.
  143. vecSpawnOrigin = vecAlternateOrigin;
  144. vecSpawnAngles = vecAlternateAngles;
  145. }
  146. CUtlVector<CBaseEntity*> hNewEntities;
  147. if ( !pTemplate->CreateInstance( vecSpawnOrigin, vecSpawnAngles, &hNewEntities, this ) )
  148. return;
  149. //Adrian: oops we couldn't spawn the entity (or entities) for some reason!
  150. if ( hNewEntities.Count() == 0 )
  151. return;
  152. m_hCurrentInstance = hNewEntities[0];
  153. // Assume it'll block us
  154. m_hCurrentBlocker = m_hCurrentInstance;
  155. m_vecBlockerOrigin = m_hCurrentBlocker->GetAbsOrigin();
  156. // Store off the mins & maxs the first time we spawn
  157. if ( m_vecEntityMins == vec3_origin )
  158. {
  159. m_hCurrentInstance->CollisionProp()->WorldSpaceAABB( &m_vecEntityMins, &m_vecEntityMaxs );
  160. m_vecEntityMins -= m_hCurrentInstance->GetAbsOrigin();
  161. m_vecEntityMaxs -= m_hCurrentInstance->GetAbsOrigin();
  162. }
  163. // Fire our output
  164. m_pOutputOnSpawned.FireOutput( this, this );
  165. // Start thinking
  166. if ( m_spawnflags & SF_ENTMAKER_AUTOSPAWN )
  167. {
  168. SetThink( &CEnvEntityMaker::CheckSpawnThink );
  169. SetNextThink( gpGlobals->curtime + 0.5f );
  170. }
  171. // If we have a specified post spawn speed, apply it to all spawned entities
  172. if ( m_flPostSpawnSpeed )
  173. {
  174. for ( int i = 0; i < hNewEntities.Count(); i++ )
  175. {
  176. CBaseEntity *pEntity = hNewEntities[i];
  177. if ( pEntity->GetMoveType() == MOVETYPE_NONE )
  178. continue;
  179. // Calculate a velocity for this entity
  180. Vector vForward,vRight,vUp;
  181. QAngle angSpawnDir( m_angPostSpawnDirection );
  182. if ( m_bPostSpawnUseAngles )
  183. {
  184. if ( GetParent() )
  185. {
  186. angSpawnDir += GetParent()->GetAbsAngles();
  187. }
  188. else
  189. {
  190. angSpawnDir += GetAbsAngles();
  191. }
  192. }
  193. AngleVectors( angSpawnDir, &vForward, &vRight, &vUp );
  194. Vector vecShootDir = vForward;
  195. vecShootDir += vRight * random->RandomFloat(-1, 1) * m_flPostSpawnDirectionVariance;
  196. vecShootDir += vForward * random->RandomFloat(-1, 1) * m_flPostSpawnDirectionVariance;
  197. vecShootDir += vUp * random->RandomFloat(-1, 1) * m_flPostSpawnDirectionVariance;
  198. VectorNormalize( vecShootDir );
  199. vecShootDir *= m_flPostSpawnSpeed;
  200. // Apply it to the entity
  201. IPhysicsObject *pPhysicsObject = pEntity->VPhysicsGetObject();
  202. if ( pPhysicsObject )
  203. {
  204. pPhysicsObject->AddVelocity(&vecShootDir, NULL);
  205. }
  206. else
  207. {
  208. pEntity->SetAbsVelocity( vecShootDir );
  209. }
  210. }
  211. }
  212. pTemplate->CreationComplete( hNewEntities );
  213. }
  214. //-----------------------------------------------------------------------------
  215. // Purpose: Spawn an instance of the entity
  216. //-----------------------------------------------------------------------------
  217. void CEnvEntityMaker::SpawnEntityFromScript()
  218. {
  219. SpawnEntity();
  220. }
  221. //-----------------------------------------------------------------------------
  222. // Purpose: Spawn an instance of the entity
  223. //-----------------------------------------------------------------------------
  224. void CEnvEntityMaker::SpawnEntityAtEntityOriginFromScript( HSCRIPT hEntity )
  225. {
  226. CBaseEntity *pTargetEntity = ToEnt( hEntity );
  227. if ( pTargetEntity )
  228. {
  229. SpawnEntity( pTargetEntity->GetAbsOrigin(), pTargetEntity->GetAbsAngles() );
  230. }
  231. }
  232. //-----------------------------------------------------------------------------
  233. // Purpose: Spawn an instance of the entity
  234. //-----------------------------------------------------------------------------
  235. void CEnvEntityMaker::SpawnEntityAtNamedEntityOriginFromScript( const char *pszName )
  236. {
  237. CBaseEntity *pTargetEntity = gEntList.FindEntityByName( NULL, pszName, this, NULL, NULL );
  238. if( pTargetEntity )
  239. {
  240. SpawnEntity( pTargetEntity->GetAbsOrigin(), pTargetEntity->GetAbsAngles() );
  241. }
  242. }
  243. //-----------------------------------------------------------------------------
  244. // Purpose: Spawn an instance of the entity
  245. //-----------------------------------------------------------------------------
  246. void CEnvEntityMaker::SpawnEntityAtLocationFromScript( const Vector &vecAlternateOrigin, const Vector &vecAlternateAngles )
  247. {
  248. SpawnEntity( vecAlternateOrigin, *((QAngle *)&vecAlternateAngles) );
  249. }
  250. //-----------------------------------------------------------------------------
  251. // Purpose: Returns whether or not the template entities can fit if spawned.
  252. // Input : pBlocker - Returns blocker unless NULL.
  253. //-----------------------------------------------------------------------------
  254. bool CEnvEntityMaker::HasRoomToSpawn()
  255. {
  256. // Do we have a blocker from last time?
  257. if ( m_hCurrentBlocker )
  258. {
  259. // If it hasn't moved, abort immediately
  260. if ( m_vecBlockerOrigin == m_hCurrentBlocker->GetAbsOrigin() )
  261. {
  262. return false;
  263. }
  264. }
  265. // Check to see if there's enough room to spawn
  266. trace_t tr;
  267. UTIL_TraceHull( GetAbsOrigin(), GetAbsOrigin(), m_vecEntityMins, m_vecEntityMaxs, MASK_SOLID, this, COLLISION_GROUP_NONE, &tr );
  268. if ( tr.m_pEnt || tr.startsolid )
  269. {
  270. // Store off our blocker to check later
  271. m_hCurrentBlocker = tr.m_pEnt;
  272. if ( m_hCurrentBlocker )
  273. {
  274. m_vecBlockerOrigin = m_hCurrentBlocker->GetAbsOrigin();
  275. }
  276. return false;
  277. }
  278. return true;
  279. }
  280. //-----------------------------------------------------------------------------
  281. // Purpose: Returns true if the player is looking towards us.
  282. //-----------------------------------------------------------------------------
  283. bool CEnvEntityMaker::IsPlayerLooking()
  284. {
  285. for ( int i = 1; i <= gpGlobals->maxClients; i++ )
  286. {
  287. CBasePlayer *pPlayer = UTIL_PlayerByIndex( i );
  288. if ( pPlayer )
  289. {
  290. // Only spawn if the player's looking away from me
  291. Vector vLookDir = pPlayer->EyeDirection3D();
  292. Vector vTargetDir = GetAbsOrigin() - pPlayer->EyePosition();
  293. VectorNormalize( vTargetDir );
  294. float fDotPr = DotProduct( vLookDir,vTargetDir );
  295. if ( fDotPr > 0 )
  296. return true;
  297. }
  298. }
  299. return false;
  300. }
  301. //-----------------------------------------------------------------------------
  302. // Purpose: Check to see if we should spawn another instance
  303. //-----------------------------------------------------------------------------
  304. void CEnvEntityMaker::CheckSpawnThink( void )
  305. {
  306. SetNextThink( gpGlobals->curtime + 0.5f );
  307. // Do we have an instance?
  308. if ( m_hCurrentInstance )
  309. {
  310. // If Wait-For-Destruction is set, abort immediately
  311. if ( m_spawnflags & SF_ENTMAKER_WAITFORDESTRUCTION )
  312. return;
  313. }
  314. // Check to see if there's enough room to spawn
  315. if ( !HasRoomToSpawn() )
  316. return;
  317. // We're clear, now check to see if the player's looking
  318. if ( !( HasSpawnFlags( SF_ENTMAKER_IGNOREFACING ) ) && IsPlayerLooking() )
  319. return;
  320. // Clear, no player watching, so spawn!
  321. SpawnEntity();
  322. }
  323. //-----------------------------------------------------------------------------
  324. // Purpose: Spawns the entities, checking for space if flagged to do so.
  325. //-----------------------------------------------------------------------------
  326. void CEnvEntityMaker::InputForceSpawn( inputdata_t &inputdata )
  327. {
  328. CPointTemplate *pTemplate = FindTemplate();
  329. if (!pTemplate)
  330. return;
  331. if ( HasSpawnFlags( SF_ENTMAKER_CHECK_FOR_SPACE ) && !HasRoomToSpawn() )
  332. {
  333. m_pOutputOnFailedSpawn.FireOutput( this, this );
  334. return;
  335. }
  336. if ( HasSpawnFlags( SF_ENTMAKER_CHECK_PLAYER_LOOKING ) && IsPlayerLooking() )
  337. {
  338. m_pOutputOnFailedSpawn.FireOutput( this, this );
  339. return;
  340. }
  341. SpawnEntity();
  342. }
  343. //-----------------------------------------------------------------------------
  344. //-----------------------------------------------------------------------------
  345. void CEnvEntityMaker::InputForceSpawnAtEntityOrigin( inputdata_t &inputdata )
  346. {
  347. CBaseEntity *pTargetEntity = gEntList.FindEntityByName( NULL, inputdata.value.String(), this, inputdata.pActivator, inputdata.pCaller );
  348. if( pTargetEntity )
  349. {
  350. SpawnEntity( pTargetEntity->GetAbsOrigin(), pTargetEntity->GetAbsAngles() );
  351. }
  352. }