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.

276 lines
7.9 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: The various ammo types for HL2
  4. //
  5. //=============================================================================//
  6. #include "cbase.h"
  7. #include "props.h"
  8. #include "items.h"
  9. #include "item_dynamic_resupply.h"
  10. // memdbgon must be the last include file in a .cpp file!!!
  11. #include "tier0/memdbgon.h"
  12. const char *pszItemCrateModelName[] =
  13. {
  14. "models/items/item_item_crate.mdl",
  15. "models/items/item_beacon_crate.mdl",
  16. };
  17. //-----------------------------------------------------------------------------
  18. // A breakable crate that drops items
  19. //-----------------------------------------------------------------------------
  20. class CItem_ItemCrate : public CPhysicsProp
  21. {
  22. public:
  23. DECLARE_CLASS( CItem_ItemCrate, CPhysicsProp );
  24. DECLARE_DATADESC();
  25. void Precache( void );
  26. void Spawn( void );
  27. virtual int ObjectCaps() { return BaseClass::ObjectCaps() | FCAP_WCEDIT_POSITION; };
  28. virtual int OnTakeDamage( const CTakeDamageInfo &info );
  29. void InputKill( inputdata_t &data );
  30. virtual void VPhysicsCollision( int index, gamevcollisionevent_t *pEvent );
  31. virtual void OnPhysGunPickup( CBasePlayer *pPhysGunUser, PhysGunPickup_t reason );
  32. protected:
  33. virtual void OnBreak( const Vector &vecVelocity, const AngularImpulse &angVel, CBaseEntity *pBreaker );
  34. private:
  35. // Crate types. Add more!
  36. enum CrateType_t
  37. {
  38. CRATE_SPECIFIC_ITEM = 0,
  39. CRATE_TYPE_COUNT,
  40. };
  41. enum CrateAppearance_t
  42. {
  43. CRATE_APPEARANCE_DEFAULT = 0,
  44. CRATE_APPEARANCE_RADAR_BEACON,
  45. };
  46. private:
  47. CrateType_t m_CrateType;
  48. string_t m_strItemClass;
  49. int m_nItemCount;
  50. string_t m_strAlternateMaster;
  51. CrateAppearance_t m_CrateAppearance;
  52. COutputEvent m_OnCacheInteraction;
  53. };
  54. LINK_ENTITY_TO_CLASS(item_item_crate, CItem_ItemCrate);
  55. //-----------------------------------------------------------------------------
  56. // Save/load:
  57. //-----------------------------------------------------------------------------
  58. BEGIN_DATADESC( CItem_ItemCrate )
  59. DEFINE_KEYFIELD( m_CrateType, FIELD_INTEGER, "CrateType" ),
  60. DEFINE_KEYFIELD( m_strItemClass, FIELD_STRING, "ItemClass" ),
  61. DEFINE_KEYFIELD( m_nItemCount, FIELD_INTEGER, "ItemCount" ),
  62. DEFINE_KEYFIELD( m_strAlternateMaster, FIELD_STRING, "SpecificResupply" ),
  63. DEFINE_KEYFIELD( m_CrateAppearance, FIELD_INTEGER, "CrateAppearance" ),
  64. DEFINE_INPUTFUNC( FIELD_VOID, "Kill", InputKill ),
  65. DEFINE_OUTPUT( m_OnCacheInteraction, "OnCacheInteraction" ),
  66. END_DATADESC()
  67. //-----------------------------------------------------------------------------
  68. // Purpose:
  69. //-----------------------------------------------------------------------------
  70. void CItem_ItemCrate::Precache( void )
  71. {
  72. // Set this here to quiet base prop warnings
  73. PrecacheModel( pszItemCrateModelName[m_CrateAppearance] );
  74. SetModel( pszItemCrateModelName[m_CrateAppearance] );
  75. BaseClass::Precache();
  76. if ( m_CrateType == CRATE_SPECIFIC_ITEM )
  77. {
  78. if ( NULL_STRING != m_strItemClass )
  79. {
  80. // Don't precache if this is a null string.
  81. UTIL_PrecacheOther( STRING(m_strItemClass) );
  82. }
  83. }
  84. }
  85. //-----------------------------------------------------------------------------
  86. // Purpose:
  87. //-----------------------------------------------------------------------------
  88. void CItem_ItemCrate::Spawn( void )
  89. {
  90. if ( g_pGameRules->IsAllowedToSpawn( this ) == false )
  91. {
  92. UTIL_Remove( this );
  93. return;
  94. }
  95. DisableAutoFade();
  96. SetModelName( AllocPooledString( pszItemCrateModelName[m_CrateAppearance] ) );
  97. if ( NULL_STRING == m_strItemClass )
  98. {
  99. Warning( "CItem_ItemCrate(%i): CRATE_SPECIFIC_ITEM with NULL ItemClass string (deleted)!!!\n", entindex() );
  100. UTIL_Remove( this );
  101. return;
  102. }
  103. Precache( );
  104. SetModel( pszItemCrateModelName[m_CrateAppearance] );
  105. AddEFlags( EFL_NO_ROTORWASH_PUSH );
  106. BaseClass::Spawn( );
  107. }
  108. //-----------------------------------------------------------------------------
  109. // Purpose:
  110. // Input : &data -
  111. //-----------------------------------------------------------------------------
  112. void CItem_ItemCrate::InputKill( inputdata_t &data )
  113. {
  114. UTIL_Remove( this );
  115. }
  116. //-----------------------------------------------------------------------------
  117. // Item crates blow up immediately
  118. //-----------------------------------------------------------------------------
  119. int CItem_ItemCrate::OnTakeDamage( const CTakeDamageInfo &info )
  120. {
  121. if ( info.GetDamageType() & DMG_AIRBOAT )
  122. {
  123. CTakeDamageInfo dmgInfo = info;
  124. dmgInfo.ScaleDamage( 10.0 );
  125. return BaseClass::OnTakeDamage( dmgInfo );
  126. }
  127. return BaseClass::OnTakeDamage( info );
  128. }
  129. //-----------------------------------------------------------------------------
  130. // Purpose:
  131. //-----------------------------------------------------------------------------
  132. void CItem_ItemCrate::VPhysicsCollision( int index, gamevcollisionevent_t *pEvent )
  133. {
  134. float flDamageScale = 1.0f;
  135. if ( FClassnameIs( pEvent->pEntities[!index], "prop_vehicle_airboat" ) ||
  136. FClassnameIs( pEvent->pEntities[!index], "prop_vehicle_jeep" ) )
  137. {
  138. flDamageScale = 100.0f;
  139. }
  140. m_impactEnergyScale *= flDamageScale;
  141. BaseClass::VPhysicsCollision( index, pEvent );
  142. m_impactEnergyScale /= flDamageScale;
  143. }
  144. //-----------------------------------------------------------------------------
  145. // Purpose:
  146. //-----------------------------------------------------------------------------
  147. void CItem_ItemCrate::OnBreak( const Vector &vecVelocity, const AngularImpulse &angImpulse, CBaseEntity *pBreaker )
  148. {
  149. // FIXME: We could simply store the name of an entity to put into the crate
  150. // as a string entered in by worldcraft. Should we? I'd do it for sure
  151. // if it was easy to get a dropdown with all entity types in it.
  152. m_OnCacheInteraction.FireOutput(pBreaker,this);
  153. for ( int i = 0; i < m_nItemCount; ++i )
  154. {
  155. CBaseEntity *pSpawn = NULL;
  156. switch( m_CrateType )
  157. {
  158. case CRATE_SPECIFIC_ITEM:
  159. pSpawn = CreateEntityByName( STRING(m_strItemClass) );
  160. break;
  161. default:
  162. break;
  163. }
  164. if ( !pSpawn )
  165. return;
  166. // Give a little randomness...
  167. Vector vecOrigin;
  168. CollisionProp()->RandomPointInBounds( Vector(0.25, 0.25, 0.25), Vector( 0.75, 0.75, 0.75 ), &vecOrigin );
  169. pSpawn->SetAbsOrigin( vecOrigin );
  170. QAngle vecAngles;
  171. vecAngles.x = random->RandomFloat( -20.0f, 20.0f );
  172. vecAngles.y = random->RandomFloat( 0.0f, 360.0f );
  173. vecAngles.z = random->RandomFloat( -20.0f, 20.0f );
  174. pSpawn->SetAbsAngles( vecAngles );
  175. Vector vecActualVelocity;
  176. vecActualVelocity.Random( -10.0f, 10.0f );
  177. // vecActualVelocity += vecVelocity;
  178. pSpawn->SetAbsVelocity( vecActualVelocity );
  179. QAngle angVel;
  180. AngularImpulseToQAngle( angImpulse, angVel );
  181. pSpawn->SetLocalAngularVelocity( angVel );
  182. // If we're creating an item, it can't be picked up until it comes to rest
  183. // But only if it wasn't broken by a vehicle
  184. CItem *pItem = dynamic_cast<CItem*>(pSpawn);
  185. if ( pItem && !pBreaker->GetServerVehicle())
  186. {
  187. pItem->ActivateWhenAtRest();
  188. }
  189. pSpawn->Spawn();
  190. // Avoid missing items drops by a dynamic resupply because they don't think immediately
  191. if ( FClassnameIs( pSpawn, "item_dynamic_resupply" ) )
  192. {
  193. if ( m_strAlternateMaster != NULL_STRING )
  194. {
  195. DynamicResupply_InitFromAlternateMaster( pSpawn, m_strAlternateMaster );
  196. }
  197. if ( i == 0 )
  198. {
  199. pSpawn->AddSpawnFlags( SF_DYNAMICRESUPPLY_ALWAYS_SPAWN );
  200. }
  201. pSpawn->SetNextThink( gpGlobals->curtime );
  202. }
  203. }
  204. }
  205. void CItem_ItemCrate::OnPhysGunPickup( CBasePlayer *pPhysGunUser, PhysGunPickup_t reason )
  206. {
  207. BaseClass::OnPhysGunPickup( pPhysGunUser, reason );
  208. m_OnCacheInteraction.FireOutput( pPhysGunUser, this );
  209. if ( reason == PUNTED_BY_CANNON && m_CrateAppearance != CRATE_APPEARANCE_RADAR_BEACON )
  210. {
  211. Vector vForward;
  212. AngleVectors( pPhysGunUser->EyeAngles(), &vForward, NULL, NULL );
  213. Vector vForce = Pickup_PhysGunLaunchVelocity( this, vForward, PHYSGUN_FORCE_PUNTED );
  214. AngularImpulse angular = AngularImpulse( 0, 0, 0 );
  215. IPhysicsObject *pPhysics = VPhysicsGetObject();
  216. if ( pPhysics )
  217. {
  218. pPhysics->AddVelocity( &vForce, &angular );
  219. }
  220. TakeDamage( CTakeDamageInfo( pPhysGunUser, pPhysGunUser, GetHealth(), DMG_GENERIC ) );
  221. }
  222. }