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.

493 lines
13 KiB

  1. //===== Copyright � 1996-2005, Valve Corporation, All rights reserved. ======//
  2. //
  3. // Purpose: Handling for the base world item. Most of this was moved from items.cpp.
  4. //
  5. // $NoKeywords: $
  6. //===========================================================================//
  7. #include "cbase.h"
  8. #include "player.h"
  9. #include "items.h"
  10. #include "gamerules.h"
  11. #include "engine/IEngineSound.h"
  12. #include "iservervehicle.h"
  13. #include "physics_saverestore.h"
  14. // memdbgon must be the last include file in a .cpp file!!!
  15. #include "tier0/memdbgon.h"
  16. #define ITEM_PICKUP_BOX_BLOAT 24
  17. class CWorldItem : public CBaseAnimating
  18. {
  19. DECLARE_DATADESC();
  20. public:
  21. DECLARE_CLASS( CWorldItem, CBaseAnimating );
  22. bool KeyValue( const char *szKeyName, const char *szValue );
  23. void Spawn( void );
  24. int m_iType;
  25. };
  26. LINK_ENTITY_TO_CLASS(world_items, CWorldItem);
  27. BEGIN_DATADESC( CWorldItem )
  28. DEFINE_FIELD( m_iType, FIELD_INTEGER ),
  29. END_DATADESC()
  30. bool CWorldItem::KeyValue( const char *szKeyName, const char *szValue )
  31. {
  32. if (FStrEq(szKeyName, "type"))
  33. {
  34. m_iType = atoi(szValue);
  35. }
  36. else
  37. return BaseClass::KeyValue( szKeyName, szValue );
  38. return true;
  39. }
  40. void CWorldItem::Spawn( void )
  41. {
  42. CBaseEntity *pEntity = NULL;
  43. switch (m_iType)
  44. {
  45. case 44: // ITEM_BATTERY:
  46. pEntity = CBaseEntity::Create( "item_battery", GetLocalOrigin(), GetLocalAngles() );
  47. break;
  48. case 45: // ITEM_SUIT:
  49. pEntity = CBaseEntity::Create( "item_suit", GetLocalOrigin(), GetLocalAngles() );
  50. break;
  51. }
  52. if (!pEntity)
  53. {
  54. Warning("unable to create world_item %d\n", m_iType );
  55. }
  56. else
  57. {
  58. pEntity->m_target = m_target;
  59. pEntity->SetName( GetEntityName() );
  60. pEntity->ClearSpawnFlags();
  61. pEntity->AddSpawnFlags( m_spawnflags );
  62. }
  63. UTIL_RemoveImmediate( this );
  64. }
  65. BEGIN_DATADESC( CItem )
  66. DEFINE_FIELD( m_bActivateWhenAtRest, FIELD_BOOLEAN ),
  67. DEFINE_FIELD( m_vOriginalSpawnOrigin, FIELD_POSITION_VECTOR ),
  68. DEFINE_FIELD( m_vOriginalSpawnAngles, FIELD_VECTOR ),
  69. DEFINE_PHYSPTR( m_pConstraint ),
  70. // Function Pointers
  71. DEFINE_ENTITYFUNC( ItemTouch ),
  72. DEFINE_THINKFUNC( Materialize ),
  73. DEFINE_THINKFUNC( ComeToRest ),
  74. // Outputs
  75. DEFINE_OUTPUT( m_OnPlayerTouch, "OnPlayerTouch" ),
  76. DEFINE_OUTPUT( m_OnCacheInteraction, "OnCacheInteraction" ),
  77. END_DATADESC()
  78. //-----------------------------------------------------------------------------
  79. // Constructor
  80. //-----------------------------------------------------------------------------
  81. CItem::CItem()
  82. {
  83. m_bActivateWhenAtRest = false;
  84. }
  85. CItem::~CItem()
  86. {
  87. if ( m_pConstraint )
  88. {
  89. physenv->DestroyConstraint( m_pConstraint );
  90. m_pConstraint = NULL;
  91. }
  92. }
  93. bool CItem::CreateItemVPhysicsObject( void )
  94. {
  95. // Create the object in the physics system
  96. int nSolidFlags = GetSolidFlags() | FSOLID_NOT_STANDABLE;
  97. if ( !m_bActivateWhenAtRest )
  98. {
  99. nSolidFlags |= FSOLID_TRIGGER;
  100. }
  101. if ( VPhysicsInitNormal( SOLID_VPHYSICS, nSolidFlags, false ) == NULL )
  102. {
  103. SetSolid( SOLID_BBOX );
  104. AddSolidFlags( nSolidFlags );
  105. // If it's not physical, drop it to the floor
  106. if (UTIL_DropToFloor(this, MASK_SOLID) == 0)
  107. {
  108. Warning( "Item %s fell out of level at %f,%f,%f\n", GetClassname(), GetAbsOrigin().x, GetAbsOrigin().y, GetAbsOrigin().z);
  109. UTIL_Remove( this );
  110. return false;
  111. }
  112. }
  113. return true;
  114. }
  115. //-----------------------------------------------------------------------------
  116. // Purpose:
  117. //-----------------------------------------------------------------------------
  118. void CItem::Spawn( void )
  119. {
  120. SetNetworkQuantizeOriginAngAngles( true );
  121. if ( g_pGameRules->IsAllowedToSpawn( this ) == false )
  122. {
  123. UTIL_Remove( this );
  124. return;
  125. }
  126. SetMoveType( MOVETYPE_FLYGRAVITY );
  127. SetSolid( SOLID_BBOX );
  128. SetBlocksLOS( false );
  129. AddEFlags( EFL_NO_ROTORWASH_PUSH );
  130. if( IsGameConsole() )
  131. {
  132. AddEffects( EF_ITEM_BLINK );
  133. }
  134. // This will make them not collide with the player, but will collide
  135. // against other items + weapons
  136. SetCollisionGroup( COLLISION_GROUP_WEAPON );
  137. if( HasBloatedCollision() )
  138. {
  139. CollisionProp()->UseTriggerBounds( true, ITEM_PICKUP_BOX_BLOAT );
  140. }
  141. SetTouch(&CItem::ItemTouch);
  142. if ( CreateItemVPhysicsObject() == false )
  143. return;
  144. m_takedamage = DAMAGE_EVENTS_ONLY;
  145. #if !defined( CLIENT_DLL )
  146. // Constrained start?
  147. if ( HasSpawnFlags( SF_ITEM_START_CONSTRAINED ) )
  148. {
  149. //Constrain the weapon in place
  150. IPhysicsObject *pReferenceObject, *pAttachedObject;
  151. pReferenceObject = g_PhysWorldObject;
  152. pAttachedObject = VPhysicsGetObject();
  153. if ( pReferenceObject && pAttachedObject )
  154. {
  155. constraint_fixedparams_t fixed;
  156. fixed.Defaults();
  157. fixed.InitWithCurrentObjectState( pReferenceObject, pAttachedObject );
  158. fixed.constraint.forceLimit = lbs2kg( 10000 );
  159. fixed.constraint.torqueLimit = lbs2kg( 10000 );
  160. m_pConstraint = physenv->CreateFixedConstraint( pReferenceObject, pAttachedObject, NULL, fixed );
  161. m_pConstraint->SetGameData( (void *) this );
  162. }
  163. }
  164. #endif //CLIENT_DLL
  165. Vector origin = GetAbsOrigin();
  166. QAngle angles = GetAbsAngles();
  167. NetworkQuantize( origin, angles );
  168. SetAbsOrigin( origin );
  169. SetAbsAngles( angles );
  170. }
  171. void CItem::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
  172. {
  173. CBasePlayer *pPlayer = ToBasePlayer( pActivator );
  174. if ( pPlayer )
  175. {
  176. pPlayer->PickupObject( this );
  177. }
  178. }
  179. extern int gEvilImpulse101;
  180. //-----------------------------------------------------------------------------
  181. // Activate when at rest, but don't allow pickup until then
  182. //-----------------------------------------------------------------------------
  183. void CItem::ActivateWhenAtRest( float flTime /* = 0.5f */ )
  184. {
  185. RemoveSolidFlags( FSOLID_TRIGGER );
  186. m_bActivateWhenAtRest = true;
  187. SetThink( &CItem::ComeToRest );
  188. SetNextThink( gpGlobals->curtime + flTime );
  189. }
  190. //-----------------------------------------------------------------------------
  191. // Become touchable when we are at rest
  192. //-----------------------------------------------------------------------------
  193. void CItem::OnEntityEvent( EntityEvent_t event, void *pEventData )
  194. {
  195. BaseClass::OnEntityEvent( event, pEventData );
  196. if( event == ENTITY_EVENT_WATER_TOUCH && m_bActivateWhenAtRest )
  197. {
  198. // Check if we are stomping on someone else's think function
  199. Assert( m_pfnThink == nullptr || m_pfnThink == static_cast <void (CBaseEntity::*)(void)>(&CItem::ComeToRest) );
  200. // Delay rest for a sec, to avoid changing collision
  201. // properties inside a collision callback.
  202. SetThink( &CItem::ComeToRest );
  203. SetNextThink( gpGlobals->curtime + 0.1f );
  204. }
  205. }
  206. //-----------------------------------------------------------------------------
  207. // Become touchable when we are at rest
  208. //-----------------------------------------------------------------------------
  209. void CItem::ComeToRest( void )
  210. {
  211. if ( m_bActivateWhenAtRest )
  212. {
  213. m_bActivateWhenAtRest = false;
  214. AddSolidFlags( FSOLID_TRIGGER );
  215. SetThink( NULL );
  216. }
  217. }
  218. //-----------------------------------------------------------------------------
  219. // Purpose: Used to tell whether an item may be picked up by the player. This
  220. // accounts for solid obstructions being in the way.
  221. // Input : *pItem - item in question
  222. // *pPlayer - player attempting the pickup
  223. // Output : Returns true on success, false on failure.
  224. //-----------------------------------------------------------------------------
  225. bool UTIL_ItemCanBeTouchedByPlayer( CBaseEntity *pItem, CBasePlayer *pPlayer )
  226. {
  227. if ( pItem == NULL || pPlayer == NULL )
  228. return false;
  229. // For now, always allow a vehicle riding player to pick up things they're driving over
  230. if ( pPlayer->IsInAVehicle() )
  231. return true;
  232. // Get our test positions
  233. Vector vecStartPos;
  234. IPhysicsObject *pPhysObj = pItem->VPhysicsGetObject();
  235. if ( pPhysObj != NULL )
  236. {
  237. // Use the physics hull's center
  238. QAngle vecAngles;
  239. pPhysObj->GetPosition( &vecStartPos, &vecAngles );
  240. }
  241. else
  242. {
  243. // Use the generic bbox center
  244. vecStartPos = pItem->CollisionProp()->WorldSpaceCenter();
  245. }
  246. Vector vecEndPos = pPlayer->EyePosition();
  247. // FIXME: This is the simple first try solution towards the problem. We need to take edges and shape more into account
  248. // for this to be fully robust.
  249. // Trace between to see if we're occluded
  250. trace_t tr;
  251. CTraceFilterSkipTwoEntities filter( pPlayer, pItem, COLLISION_GROUP_PLAYER_MOVEMENT );
  252. UTIL_TraceLine( vecStartPos, vecEndPos, MASK_SOLID, &filter, &tr );
  253. // Occluded
  254. // FIXME: For now, we exclude starting in solid because there are cases where this doesn't matter
  255. if ( tr.fraction < 1.0f )
  256. return false;
  257. return true;
  258. }
  259. //-----------------------------------------------------------------------------
  260. // Purpose: Whether or not the item can be touched and picked up by the player, taking
  261. // into account obstructions and other hinderances
  262. // Output : Returns true on success, false on failure.
  263. //-----------------------------------------------------------------------------
  264. bool CItem::ItemCanBeTouchedByPlayer( CBasePlayer *pPlayer )
  265. {
  266. return UTIL_ItemCanBeTouchedByPlayer( this, pPlayer );
  267. }
  268. //-----------------------------------------------------------------------------
  269. // Purpose:
  270. // Input : pOther -
  271. //-----------------------------------------------------------------------------
  272. void CItem::ItemTouch( CBaseEntity *pOther )
  273. {
  274. ItemTouchInternal( pOther, false );
  275. }
  276. void CItem::ItemForceTouch( CBaseEntity *pOther )
  277. {
  278. ItemTouchInternal( pOther, true );
  279. }
  280. void CItem::ItemTouchInternal( CBaseEntity *pOther, bool bForceTouch )
  281. {
  282. // Vehicles can touch items + pick them up
  283. if ( pOther->GetServerVehicle() )
  284. {
  285. pOther = pOther->GetServerVehicle()->GetPassenger();
  286. if ( !pOther )
  287. return;
  288. }
  289. // if it's not a player, ignore
  290. if ( !pOther->IsPlayer() )
  291. return;
  292. CBasePlayer *pPlayer = (CBasePlayer *)pOther;
  293. // Must be a valid pickup scenario (no blocking). Though this is a more expensive
  294. // check than some that follow, this has to be first Obecause it's the only one
  295. // that inhibits firing the output OnCacheInteraction.
  296. if ( !bForceTouch && ItemCanBeTouchedByPlayer( pPlayer ) == false )
  297. return;
  298. m_OnCacheInteraction.FireOutput(pOther, this);
  299. // Can I even pick stuff up?
  300. if ( !pPlayer->IsAllowedToPickupWeapons() )
  301. return;
  302. // ok, a player is touching this item, but can he have it?
  303. if ( !g_pGameRules->CanHaveItem( pPlayer, this ) )
  304. {
  305. // no? Ignore the touch.
  306. return;
  307. }
  308. if ( MyTouch( pPlayer ) )
  309. {
  310. m_OnPlayerTouch.FireOutput(pOther, this);
  311. SetTouch( NULL );
  312. SetThink( NULL );
  313. // player grabbed the item.
  314. g_pGameRules->PlayerGotItem( pPlayer, this );
  315. if ( g_pGameRules->ItemShouldRespawn( this ) == GR_ITEM_RESPAWN_YES )
  316. {
  317. Respawn();
  318. }
  319. else
  320. {
  321. UTIL_Remove( this );
  322. }
  323. }
  324. else if (gEvilImpulse101)
  325. {
  326. UTIL_Remove( this );
  327. }
  328. }
  329. CBaseEntity* CItem::Respawn( void )
  330. {
  331. SetTouch( NULL );
  332. AddEffects( EF_NODRAW );
  333. VPhysicsDestroyObject();
  334. SetMoveType( MOVETYPE_NONE );
  335. SetSolid( SOLID_BBOX );
  336. AddSolidFlags( FSOLID_TRIGGER );
  337. UTIL_SetOrigin( this, g_pGameRules->VecItemRespawnSpot( this ) );// blip to whereever you should respawn.
  338. SetAbsAngles( g_pGameRules->VecItemRespawnAngles( this ) );// set the angles.
  339. #if !defined( TF_DLL )
  340. UTIL_DropToFloor( this, MASK_SOLID );
  341. #endif
  342. RemoveAllDecals(); //remove any decals
  343. SetThink ( &CItem::Materialize );
  344. SetNextThink( gpGlobals->curtime + g_pGameRules->FlItemRespawnTime( this ) );
  345. return this;
  346. }
  347. void CItem::Materialize( void )
  348. {
  349. CreateItemVPhysicsObject();
  350. if ( IsEffectActive( EF_NODRAW ) )
  351. {
  352. // changing from invisible state to visible.
  353. // this sound no longer exists
  354. // EmitSound( "Item.Materialize" );
  355. RemoveEffects( EF_NODRAW );
  356. DoMuzzleFlash();
  357. }
  358. SetTouch( &CItem::ItemTouch );
  359. }
  360. //-----------------------------------------------------------------------------
  361. // Purpose:
  362. //-----------------------------------------------------------------------------
  363. void CItem::Precache()
  364. {
  365. BaseClass::Precache();
  366. // this sound no longer exists
  367. // PrecacheScriptSound( "Item.Materialize" );
  368. }
  369. //-----------------------------------------------------------------------------
  370. // Purpose:
  371. // Input : *pPhysGunUser -
  372. // PICKED_UP_BY_CANNON -
  373. //-----------------------------------------------------------------------------
  374. void CItem::OnPhysGunPickup( CBasePlayer *pPhysGunUser, PhysGunPickup_t reason )
  375. {
  376. m_OnCacheInteraction.FireOutput(pPhysGunUser, this);
  377. if ( reason == PICKED_UP_BY_CANNON )
  378. {
  379. // Expand the pickup box
  380. CollisionProp()->UseTriggerBounds( true, ITEM_PICKUP_BOX_BLOAT * 2 );
  381. if( m_pConstraint != NULL )
  382. {
  383. physenv->DestroyConstraint( m_pConstraint );
  384. m_pConstraint = NULL;
  385. }
  386. }
  387. }
  388. //-----------------------------------------------------------------------------
  389. // Purpose:
  390. // Input : *pPhysGunUser -
  391. // reason -
  392. //-----------------------------------------------------------------------------
  393. void CItem::OnPhysGunDrop( CBasePlayer *pPhysGunUser, PhysGunDrop_t reason )
  394. {
  395. // Restore the pickup box to the original
  396. CollisionProp()->UseTriggerBounds( true, ITEM_PICKUP_BOX_BLOAT );
  397. }