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.

8998 lines
272 KiB

  1. //======= Copyright (c) 1996-2009, Valve Corporation, All rights reserved. ======
  2. //
  3. // Purpose: The base class from which all game entities are derived.
  4. //
  5. //===============================================================================
  6. #include "cbase.h"
  7. #include "globalstate.h"
  8. #include "isaverestore.h"
  9. #include "client.h"
  10. #include "decals.h"
  11. #include "gamerules.h"
  12. #include "entityapi.h"
  13. #include "entitylist.h"
  14. #include "eventqueue.h"
  15. #include "hierarchy.h"
  16. #include "basecombatweapon.h"
  17. #include "const.h"
  18. #include "player.h" // For debug draw sending
  19. #include "ndebugoverlay.h"
  20. #include "physics.h"
  21. #include "model_types.h"
  22. #include "team.h"
  23. #include "sendproxy.h"
  24. #include "IEffects.h"
  25. #include "vstdlib/random.h"
  26. #include "baseentity.h"
  27. #include "collisionutils.h"
  28. #include "coordsize.h"
  29. #include "animation.h"
  30. #include "tier1/strtools.h"
  31. #include "engine/IEngineSound.h"
  32. #include "physics_saverestore.h"
  33. #include "saverestore_utlvector.h"
  34. #include "bone_setup.h"
  35. #include "vcollide_parse.h"
  36. #include "filters.h"
  37. #include "te_effect_dispatch.h"
  38. #include "ai_criteria.h"
  39. #include "ai_responsesystem.h"
  40. #include "world.h"
  41. #include "globals.h"
  42. #include "saverestoretypes.h"
  43. #include "SkyCamera.h"
  44. #include "sceneentity.h"
  45. #include "game.h"
  46. #include "tier0/vprof.h"
  47. #include "ai_basenpc.h"
  48. #include "iservervehicle.h"
  49. #include "eventlist.h"
  50. #include "scriptevent.h"
  51. #include "SoundEmitterSystem/isoundemittersystembase.h"
  52. #include "UtlCachedFileData.h"
  53. #include "utlbuffer.h"
  54. #include "positionwatcher.h"
  55. #include "movetype_push.h"
  56. #include "tier0/icommandline.h"
  57. #include "vphysics/friction.h"
  58. #include <ctype.h>
  59. #include "datacache/imdlcache.h"
  60. #include "ModelSoundsCache.h"
  61. #include "env_debughistory.h"
  62. #include "tier1/utlstring.h"
  63. #include "vscript_server.h"
  64. #include "toolframework/itoolframework.h"
  65. #include "videocfg/videocfg.h"
  66. #include "vstdlib/ikeyvaluessystem.h"
  67. #include "ilagcompensationmanager.h"
  68. #include "bittools.h"
  69. #include "cellcoord.h"
  70. #include "sendprop_priorities.h"
  71. #include "videocfg/videocfg.h"
  72. #include "tier0/stackstats.h"
  73. #if defined ( PORTAL2 )
  74. #include "PortalSimulation.h"
  75. #endif
  76. // memdbgon must be the last include file in a .cpp file!!!
  77. #include "tier0/memdbgon.h"
  78. extern bool g_bTestMoveTypeStepSimulation;
  79. extern ConVar sv_vehicle_autoaim_scale;
  80. // Init static class variables
  81. bool CBaseEntity::m_bInDebugSelect = false; // Used for selection in debug overlays
  82. int CBaseEntity::m_nDebugPlayer = -1; // Player doing the selection
  83. // This can be set before creating an entity to force it to use a particular edict.
  84. edict_t *g_pForceAttachEdict = NULL;
  85. bool CBaseEntity::m_bDebugPause = false; // Whether entity i/o is paused.
  86. int CBaseEntity::m_nDebugSteps = 1; // Number of entity outputs to fire before pausing again.
  87. bool CBaseEntity::sm_bDisableTouchFuncs = false; // Disables PhysicsTouch and PhysicsStartTouch function calls
  88. int CBaseEntity::m_nPredictionRandomSeed = -1;
  89. int CBaseEntity::m_nPredictionRandomSeedServer = -1;
  90. CBasePlayer *CBaseEntity::m_pPredictionPlayer = NULL;
  91. // Used to make sure nobody calls UpdateTransmitState directly.
  92. int g_nInsideDispatchUpdateTransmitState = 0;
  93. // When this is false, throw an assert in debug when GetAbsAnything is called. Used when hierachy is incomplete/invalid.
  94. bool CBaseEntity::s_bAbsQueriesValid = true;
  95. ConVar sv_netvisdist( "sv_netvisdist", "10000", FCVAR_CHEAT | FCVAR_DEVELOPMENTONLY, "Test networking visibility distance" );
  96. ConVar ent_show_contexts( "ent_show_contexts", "0", 0, "Show entity contexts in ent_text display" );
  97. ConVar sv_script_think_interval("sv_script_think_interval", "0.1");
  98. // This table encodes edict data.
  99. void SendProxy_AnimTime( const SendProp *pProp, const void *pStruct, const void *pVarData, DVariant *pOut, int iElement, int objectID )
  100. {
  101. CBaseEntity *pEntity = (CBaseEntity *)pStruct;
  102. #if defined( _DEBUG )
  103. CBaseAnimating *pAnimating = pEntity->GetBaseAnimating();
  104. Assert( pAnimating );
  105. if ( pAnimating )
  106. {
  107. Assert( !pAnimating->IsUsingClientSideAnimation() );
  108. }
  109. #endif
  110. int ticknumber = TIME_TO_TICKS( pEntity->m_flAnimTime );
  111. // Tickbase is current tick rounded down to closes 100 ticks
  112. int tickbase = gpGlobals->GetNetworkBase( gpGlobals->tickcount, pEntity->entindex() );
  113. int addt = 0;
  114. // If it's within the last tick interval through the current one, then we can encode it
  115. if ( ticknumber >= ( tickbase - 100 ) )
  116. {
  117. addt = ( ticknumber - tickbase ) & 0xFF;
  118. }
  119. pOut->m_Int = addt;
  120. }
  121. // This table encodes edict data.
  122. void SendProxy_SimulationTime( const SendProp *pProp, const void *pStruct, const void *pVarData, DVariant *pOut, int iElement, int objectID )
  123. {
  124. CBaseEntity *pEntity = (CBaseEntity *)pStruct;
  125. int ticknumber = TIME_TO_TICKS( pEntity->m_flSimulationTime );
  126. // tickbase is current tick rounded down to closest 100 ticks
  127. int tickbase = gpGlobals->GetNetworkBase( gpGlobals->tickcount, pEntity->entindex() );
  128. int addt = 0;
  129. if ( ticknumber >= tickbase )
  130. {
  131. addt = ( ticknumber - tickbase ) & 0xff;
  132. }
  133. pOut->m_Int = addt;
  134. }
  135. void* SendProxy_ClientSideAnimation( const SendProp *pProp, const void *pStruct, const void *pVarData, CSendProxyRecipients *pRecipients, int objectID )
  136. {
  137. CBaseEntity *pEntity = (CBaseEntity *)pStruct;
  138. CBaseAnimating *pAnimating = pEntity->GetBaseAnimating();
  139. if ( pAnimating && !pAnimating->IsUsingClientSideAnimation() )
  140. return (void*)pVarData;
  141. else
  142. return NULL; // Don't send animtime unless the client needs it.
  143. }
  144. REGISTER_SEND_PROXY_NON_MODIFIED_POINTER( SendProxy_ClientSideAnimation );
  145. BEGIN_SEND_TABLE_NOBASE( CBaseEntity, DT_AnimTimeMustBeFirst )
  146. // NOTE: Animtime must be sent before origin and angles ( from pev ) because it has a
  147. // proxy on the client that stores off the old values before writing in the new values and
  148. // if it is sent after the new values, then it will only have the new origin and studio model, etc.
  149. // interpolation will be busted
  150. SendPropInt (SENDINFO(m_flAnimTime), 8, SPROP_UNSIGNED|SPROP_CHANGES_OFTEN|SPROP_ENCODED_AGAINST_TICKCOUNT, SendProxy_AnimTime),
  151. END_SEND_TABLE()
  152. #if !defined( NO_ENTITY_PREDICTION ) && defined( USE_PREDICTABLEID )
  153. BEGIN_SEND_TABLE_NOBASE( CBaseEntity, DT_PredictableId )
  154. SendPropPredictableId( SENDINFO( m_PredictableID ) ),
  155. SendPropInt( SENDINFO( m_bIsPlayerSimulated ), 1, SPROP_UNSIGNED ),
  156. END_SEND_TABLE()
  157. #endif
  158. void BuildMergedPlayerIndexListForSplitUser( int nPlayerIndex, CUtlVector< int > &list )
  159. {
  160. CBasePlayer *pl = static_cast< CBasePlayer * >( CBaseEntity::Instance( nPlayerIndex ) );
  161. Assert( pl );
  162. if ( !pl )
  163. return;
  164. int nRootPlayer = nPlayerIndex;
  165. bool bIsSplit = engine->IsSplitScreenPlayer( nPlayerIndex );
  166. if ( bIsSplit )
  167. {
  168. edict_t *ed = engine->GetSplitScreenPlayerAttachToEdict( nPlayerIndex );
  169. if ( ed )
  170. {
  171. nRootPlayer = ENTINDEX( ed );
  172. }
  173. }
  174. // Now use root player to build list
  175. list.AddToTail( nRootPlayer );
  176. for ( int i = 1; i < MAX_SPLITSCREEN_PLAYERS; ++i )
  177. {
  178. edict_t *ed = engine->GetSplitScreenPlayerForEdict( nRootPlayer, i ) ;
  179. if ( ed )
  180. {
  181. list.AddToTail( ENTINDEX( ed ) );
  182. }
  183. }
  184. }
  185. #if !defined( NO_ENTITY_PREDICTION ) && defined( USE_PREDICTABLEID )
  186. static void* SendProxy_SendPredictableId( const SendProp *pProp, const void *pStruct, const void *pVarData, CSendProxyRecipients *pRecipients, int objectID )
  187. {
  188. CBaseEntity *pEntity = (CBaseEntity *)pStruct;
  189. if ( !pEntity || !pEntity->m_PredictableID->IsActive() )
  190. return NULL;
  191. int id_player_index = pEntity->m_PredictableID->GetPlayer();
  192. CUtlVector< int > rList;
  193. BuildMergedPlayerIndexListForSplitUser( id_player_index, rList );
  194. pRecipients->ClearAllRecipients();
  195. FOR_EACH_VEC( rList, i )
  196. {
  197. pRecipients->SetRecipient( rList[ i ] );
  198. }
  199. return ( void * )pVarData;
  200. }
  201. REGISTER_SEND_PROXY_NON_MODIFIED_POINTER( SendProxy_SendPredictableId );
  202. #endif
  203. /*
  204. //--------------------------------------------------------------------------------------------------------
  205. // Origin debugging
  206. //--------------------------------------------------------------------------------------------------------
  207. #if (defined(_WIN32) && (!defined(_GAMECONSOLE) ) )
  208. #include "filesystem.h"
  209. struct SOriginDebugFP
  210. {
  211. SOriginDebugFP()
  212. {
  213. m_originDebugFP = NULL;
  214. }
  215. ~SOriginDebugFP()
  216. {
  217. if ( m_originDebugFP )
  218. {
  219. filesystem->Close( m_originDebugFP );
  220. m_originDebugFP = NULL;
  221. m_count = 0;
  222. }
  223. }
  224. FileHandle_t m_originDebugFP;
  225. int m_count;
  226. };
  227. static SOriginDebugFP sOriginDebugFP;
  228. ConVar sv_lognetorigindeltas( "sv_lognetorigindeltas", "0", FCVAR_CHEAT | FCVAR_DEVELOPMENTONLY, "Log entity origins" );
  229. static void LogNetOriginDeltas( CBaseEntity *entity, Vector const *v )
  230. {
  231. if ( !sv_lognetorigindeltas.GetBool() )
  232. {
  233. if ( sOriginDebugFP.m_originDebugFP )
  234. {
  235. filesystem->Close( sOriginDebugFP.m_originDebugFP );
  236. sOriginDebugFP.m_originDebugFP = NULL;
  237. sOriginDebugFP.m_count = 0;
  238. }
  239. return;
  240. }
  241. if ( !sOriginDebugFP.m_originDebugFP )
  242. {
  243. char logFileName[MAX_PATH];
  244. V_snprintf( logFileName, ARRAYSIZE( logFileName ), "origin_server_%s.csv",
  245. gpGlobals->mapname.ToCStr() );
  246. sOriginDebugFP.m_originDebugFP = filesystem->Open( logFileName, "wt" );
  247. if ( sOriginDebugFP.m_originDebugFP )
  248. {
  249. filesystem->FPrintf( sOriginDebugFP.m_originDebugFP,
  250. "Count"
  251. ",Class"
  252. ",Index"
  253. ",X"
  254. ",Y"
  255. ",Z"
  256. "\n" );
  257. }
  258. }
  259. if ( sOriginDebugFP.m_originDebugFP )
  260. {
  261. filesystem->FPrintf( sOriginDebugFP.m_originDebugFP,
  262. "%d,%s,%d,%6.4f,%6.4f,%6.4f\n",
  263. sOriginDebugFP.m_count++,
  264. entity->GetClassname(),
  265. entity->entindex(),
  266. v->x,
  267. v->y,
  268. v->z );
  269. }
  270. }
  271. #endif // (defined(_WIN32) && (!defined(_GAMECONSOLE) ) )
  272. */
  273. //--------------------------------------------------------------------------------------------------------
  274. void SendProxy_Origin( const SendProp *pProp, const void *pStruct, const void *pData, DVariant *pOut, int iElement, int objectID )
  275. {
  276. CBaseEntity *entity = (CBaseEntity*)pStruct;
  277. Assert( entity );
  278. const Vector *v;
  279. if ( !entity->UseStepSimulationNetworkOrigin( &v ) )
  280. {
  281. v = &entity->GetLocalOrigin();
  282. }
  283. pOut->m_Vector[ 0 ] = v->x;
  284. pOut->m_Vector[ 1 ] = v->y;
  285. pOut->m_Vector[ 2 ] = v->z;
  286. }
  287. //--------------------------------------------------------------------------------------------------------
  288. // Used when breaking up origin, note we still have to deal with StepSimulation
  289. //--------------------------------------------------------------------------------------------------------
  290. void SendProxy_OriginXY( const SendProp *pProp, const void *pStruct, const void *pData, DVariant *pOut, int iElement, int objectID )
  291. {
  292. CBaseEntity *entity = (CBaseEntity*)pStruct;
  293. Assert( entity );
  294. const Vector *v;
  295. if ( !entity->UseStepSimulationNetworkOrigin( &v ) )
  296. {
  297. v = &entity->GetLocalOrigin();
  298. }
  299. pOut->m_Vector[ 0 ] = v->x;
  300. pOut->m_Vector[ 1 ] = v->y;
  301. }
  302. //--------------------------------------------------------------------------------------------------------
  303. // Used when breaking up origin, note we still have to deal with StepSimulation
  304. //--------------------------------------------------------------------------------------------------------
  305. void SendProxy_OriginZ( const SendProp *pProp, const void *pStruct, const void *pData, DVariant *pOut, int iElement, int objectID )
  306. {
  307. CBaseEntity *entity = (CBaseEntity*)pStruct;
  308. Assert( entity );
  309. const Vector *v;
  310. if ( !entity->UseStepSimulationNetworkOrigin( &v ) )
  311. {
  312. v = &entity->GetLocalOrigin();
  313. }
  314. pOut->m_Float = v->z;
  315. }
  316. static float const cellEpsilon = 0.001f;
  317. void CBaseEntity::SendProxy_CellX( const SendProp *pProp, const void *pStruct, const void *pData, DVariant *pOut, int iElement, int objectID)
  318. {
  319. CBaseEntity *entity = (CBaseEntity*)pStruct;
  320. Assert( entity );
  321. const Vector *v;
  322. int cell[3];
  323. if ( entity->UseStepSimulationNetworkOrigin( &v, cell ) )
  324. {
  325. pOut->m_Int = cell[0];
  326. }
  327. else
  328. {
  329. pOut->m_Int = *((int*)pData);
  330. }
  331. }
  332. void CBaseEntity::SendProxy_CellY( const SendProp *pProp, const void *pStruct, const void *pData, DVariant *pOut, int iElement, int objectID)
  333. {
  334. CBaseEntity *entity = (CBaseEntity*)pStruct;
  335. Assert( entity );
  336. const Vector *v;
  337. int cell[3];
  338. if ( entity->UseStepSimulationNetworkOrigin( &v, cell ) )
  339. {
  340. pOut->m_Int = cell[1];
  341. }
  342. else
  343. {
  344. pOut->m_Int = *((int*)pData);
  345. }
  346. }
  347. void CBaseEntity::SendProxy_CellZ( const SendProp *pProp, const void *pStruct, const void *pData, DVariant *pOut, int iElement, int objectID)
  348. {
  349. CBaseEntity *entity = (CBaseEntity*)pStruct;
  350. Assert( entity );
  351. const Vector *v;
  352. int cell[3];
  353. if ( entity->UseStepSimulationNetworkOrigin( &v, cell ) )
  354. {
  355. pOut->m_Int = cell[2];
  356. }
  357. else
  358. {
  359. pOut->m_Int = *((int*)pData);
  360. }
  361. }
  362. //--------------------------------------------------------------------------------------------------------
  363. // The origin is adjusted to be relative to current cell
  364. //--------------------------------------------------------------------------------------------------------
  365. void CBaseEntity::SendProxy_CellOrigin( const SendProp *pProp, const void *pStruct, const void *pData, DVariant *pOut, int iElement, int objectID )
  366. {
  367. CBaseEntity *entity = (CBaseEntity*)pStruct;
  368. Assert( entity );
  369. const Vector *v;
  370. int cell[3];
  371. if ( !entity->UseStepSimulationNetworkOrigin( &v, cell ) )
  372. {
  373. v = &entity->GetLocalOrigin();
  374. cell[0] = entity->m_cellX;
  375. cell[1] = entity->m_cellY;
  376. cell[2] = entity->m_cellZ;
  377. }
  378. register int const cellwidth = entity->m_cellwidth; // Load it into a register
  379. Assert( cell[0] == CellFromCoord( cellwidth, v->x ) );
  380. Assert( cell[1] == CellFromCoord( cellwidth, v->y ) );
  381. Assert( cell[2] == CellFromCoord( cellwidth, v->z ) );
  382. // Adjust based on cell size
  383. pOut->m_Vector[ 0 ] = CellInCoord( cellwidth, cell[0], v->x );
  384. pOut->m_Vector[ 1 ] = CellInCoord( cellwidth, cell[1], v->y );
  385. pOut->m_Vector[ 2 ] = CellInCoord( cellwidth, cell[2], v->z );
  386. Assert( pOut->m_Vector[ 0 ] >= 0.0f );
  387. Assert( pOut->m_Vector[ 1 ] >= 0.0f );
  388. Assert( pOut->m_Vector[ 2 ] >= 0.0f );
  389. Assert( fabs( CoordFromCell( cellwidth, cell[0], pOut->m_Vector[ 0 ] ) - v->x ) < cellEpsilon );
  390. Assert( fabs( CoordFromCell( cellwidth, cell[1], pOut->m_Vector[ 1 ] ) - v->y ) < cellEpsilon );
  391. Assert( fabs( CoordFromCell( cellwidth, cell[2], pOut->m_Vector[ 2 ] ) - v->z ) < cellEpsilon );
  392. }
  393. //--------------------------------------------------------------------------------------------------------
  394. // The origin is adjusted to be relative to current cell
  395. //--------------------------------------------------------------------------------------------------------
  396. void CBaseEntity::SendProxy_CellOriginXY( const SendProp *pProp, const void *pStruct, const void *pData, DVariant *pOut, int iElement, int objectID )
  397. {
  398. CBaseEntity *entity = (CBaseEntity*)pStruct;
  399. Assert( entity );
  400. const Vector *v;
  401. int cell[3];
  402. if ( !entity->UseStepSimulationNetworkOrigin( &v, cell ) )
  403. {
  404. v = &entity->GetLocalOrigin();
  405. cell[0] = entity->m_cellX;
  406. cell[1] = entity->m_cellY;
  407. }
  408. register int const cellwidth = entity->m_cellwidth; // Load it into a register
  409. Assert( cell[0] == CellFromCoord( cellwidth, v->x ) );
  410. Assert( cell[1] == CellFromCoord( cellwidth, v->y ) );
  411. pOut->m_Vector[ 0 ] = CellInCoord( cellwidth, cell[0], v->x );
  412. pOut->m_Vector[ 1 ] = CellInCoord( cellwidth, cell[1], v->y );
  413. Assert( pOut->m_Vector[ 0 ] >= 0.0f );
  414. Assert( pOut->m_Vector[ 1 ] >= 0.0f );
  415. Assert( fabs( CoordFromCell( cellwidth, cell[0], pOut->m_Vector[ 0 ] ) - v->x ) < cellEpsilon );
  416. Assert( fabs( CoordFromCell( cellwidth, cell[1], pOut->m_Vector[ 1 ] ) - v->y ) < cellEpsilon );
  417. }
  418. //--------------------------------------------------------------------------------------------------------
  419. // The origin is adjusted to be relative to current cell
  420. //--------------------------------------------------------------------------------------------------------
  421. void CBaseEntity::SendProxy_CellOriginZ( const SendProp *pProp, const void *pStruct, const void *pData, DVariant *pOut, int iElement, int objectID )
  422. {
  423. CBaseEntity *entity = (CBaseEntity*)pStruct;
  424. Assert( entity );
  425. const Vector *v;
  426. int cell[3];
  427. if ( !entity->UseStepSimulationNetworkOrigin( &v, cell ) )
  428. {
  429. v = &entity->GetLocalOrigin();
  430. cell[2] = entity->m_cellZ;
  431. }
  432. register int const cellwidth = entity->m_cellwidth; // Load it into a register
  433. Assert( cell[2] == CellFromCoord( cellwidth, v->z ) );
  434. pOut->m_Float = CellInCoord( cellwidth, cell[2], v->z );
  435. Assert( pOut->m_Float >= 0.0f );
  436. Assert( fabs( CoordFromCell( cellwidth, cell[2], pOut->m_Float ) - v->z ) < cellEpsilon );
  437. }
  438. void SendProxy_Angles( const SendProp *pProp, const void *pStruct, const void *pData, DVariant *pOut, int iElement, int objectID )
  439. {
  440. CBaseEntity *entity = (CBaseEntity*)pStruct;
  441. Assert( entity );
  442. const QAngle *a;
  443. if ( !entity->UseStepSimulationNetworkAngles( &a ) )
  444. {
  445. a = &entity->GetLocalAngles();
  446. }
  447. pOut->m_Vector[ 0 ] = anglemod( a->x );
  448. pOut->m_Vector[ 1 ] = anglemod( a->y );
  449. pOut->m_Vector[ 2 ] = anglemod( a->z );
  450. }
  451. #if PREDICTION_ERROR_CHECK_LEVEL > 1
  452. const int SENDPROP_ANGROTATION_DEFAULT_BITS = -1;
  453. const int SENDPROP_VECORIGIN_FLAGS = SPROP_NOSCALE|SPROP_CHANGES_OFTEN;
  454. #else
  455. const int SENDPROP_ANGROTATION_DEFAULT_BITS = 13;
  456. const int SENDPROP_VECORIGIN_FLAGS = SPROP_CELL_COORD|SPROP_CHANGES_OFTEN;
  457. #endif
  458. // This table encodes the CBaseEntity data.
  459. IMPLEMENT_SERVERCLASS_ST_NOBASE( CBaseEntity, DT_BaseEntity )
  460. SendPropDataTable( "AnimTimeMustBeFirst", 0, &REFERENCE_SEND_TABLE(DT_AnimTimeMustBeFirst), SendProxy_ClientSideAnimation ),
  461. SendPropInt (SENDINFO(m_flSimulationTime), SIMULATION_TIME_WINDOW_BITS, SPROP_UNSIGNED|SPROP_CHANGES_OFTEN|SPROP_ENCODED_AGAINST_TICKCOUNT, SendProxy_SimulationTime, SENDPROP_SIMULATION_TIME_PRIORITY ),
  462. #if defined(ENABLE_CREATE_TIME)
  463. SendPropFloat (SENDINFO( m_flCreateTime ) ),
  464. #endif
  465. SendPropInt (SENDINFO(m_cellbits), MINIMUM_BITS_NEEDED( 32 ), SPROP_UNSIGNED, 0, SENDPROP_CELL_INFO_PRIORITY ),
  466. // SendPropArray (SendPropInt(SENDINFO_ARRAY(m_cellXY), CELL_COUNT_BITS( CELL_BASEENTITY_ORIGIN_CELL_BITS ), SPROP_UNSIGNED|SPROP_CHANGES_OFTEN ), m_cellXY),
  467. SendPropInt (SENDINFO(m_cellX), CELL_COUNT_BITS( CELL_BASEENTITY_ORIGIN_CELL_BITS ), SPROP_UNSIGNED, CBaseEntity::SendProxy_CellX, SENDPROP_CELL_INFO_PRIORITY ), // 32 priority in the send table
  468. SendPropInt (SENDINFO(m_cellY), CELL_COUNT_BITS( CELL_BASEENTITY_ORIGIN_CELL_BITS ), SPROP_UNSIGNED, CBaseEntity::SendProxy_CellY, SENDPROP_CELL_INFO_PRIORITY ),
  469. SendPropInt (SENDINFO(m_cellZ), CELL_COUNT_BITS( CELL_BASEENTITY_ORIGIN_CELL_BITS ), SPROP_UNSIGNED, CBaseEntity::SendProxy_CellZ, SENDPROP_CELL_INFO_PRIORITY ),
  470. SendPropVector (SENDINFO(m_vecOrigin), CELL_BASEENTITY_ORIGIN_CELL_BITS, SENDPROP_VECORIGIN_FLAGS, 0.0f, HIGH_DEFAULT, CBaseEntity::SendProxy_CellOrigin ),
  471. SendPropModelIndex(SENDINFO(m_nModelIndex)),
  472. SendPropDataTable( SENDINFO_DT( m_Collision ), &REFERENCE_SEND_TABLE(DT_CollisionProperty) ),
  473. SendPropInt (SENDINFO(m_nRenderFX), 8, SPROP_UNSIGNED ),
  474. SendPropInt (SENDINFO(m_nRenderMode), 8, SPROP_UNSIGNED ),
  475. SendPropInt (SENDINFO(m_fEffects), EF_MAX_BITS, SPROP_UNSIGNED),
  476. SendPropInt (SENDINFO(m_clrRender), 32, SPROP_UNSIGNED, SendProxy_Color32ToInt32 ),
  477. SendPropInt (SENDINFO(m_iTeamNum), TEAMNUM_NUM_BITS, 0),
  478. SendPropInt (SENDINFO(m_iPendingTeamNum), TEAMNUM_NUM_BITS, 0),
  479. #ifdef INFESTED_DLL
  480. SendPropInt (SENDINFO(m_CollisionGroup), 6, SPROP_UNSIGNED),
  481. #else
  482. SendPropInt (SENDINFO(m_CollisionGroup), 5, SPROP_UNSIGNED),
  483. #endif
  484. SendPropFloat (SENDINFO(m_flElasticity), 0, SPROP_COORD),
  485. SendPropFloat (SENDINFO(m_flShadowCastDistance), 12, SPROP_UNSIGNED ),
  486. SendPropEHandle (SENDINFO(m_hOwnerEntity)),
  487. SendPropEHandle (SENDINFO(m_hEffectEntity)),
  488. SendPropEHandle (SENDINFO_NAME(m_hMoveParent, moveparent)),
  489. SendPropInt (SENDINFO(m_iParentAttachment), NUM_PARENTATTACHMENT_BITS, SPROP_UNSIGNED),
  490. SendPropStringT( SENDINFO( m_iName ) ),
  491. #ifdef PORTAL2
  492. SendPropStringT( SENDINFO( m_iSignifierName ) ),
  493. #endif // PORTAL2
  494. SendPropInt (SENDINFO_NAME( m_MoveType, movetype ), MOVETYPE_MAX_BITS, SPROP_UNSIGNED ),
  495. SendPropInt (SENDINFO_NAME( m_MoveCollide, movecollide ), MOVECOLLIDE_MAX_BITS, SPROP_UNSIGNED ),
  496. #if PREDICTION_ERROR_CHECK_LEVEL > 1
  497. SendPropVector (SENDINFO(m_angRotation), SENDPROP_ANGROTATION_DEFAULT_BITS, SPROP_NOSCALE|SPROP_CHANGES_OFTEN, 0, HIGH_DEFAULT, SendProxy_Angles ),
  498. #else
  499. SendPropQAngles (SENDINFO(m_angRotation), SENDPROP_ANGROTATION_DEFAULT_BITS, SPROP_CHANGES_OFTEN, SendProxy_Angles ),
  500. #endif
  501. SendPropInt ( SENDINFO( m_iTextureFrameIndex ), 8, SPROP_UNSIGNED ),
  502. #if defined ( PORTAL2 )
  503. SendPropInt ( SENDINFO( m_iObjectCapsCache ), 6, SPROP_UNSIGNED ),
  504. #endif
  505. #if !defined( NO_ENTITY_PREDICTION ) && defined( USE_PREDICTABLEID )
  506. SendPropEHandle (SENDINFO(m_hPlayerSimulationOwner)),
  507. SendPropDataTable( "predictable_id", 0, &REFERENCE_SEND_TABLE( DT_PredictableId ), SendProxy_SendPredictableId ),
  508. #endif
  509. // FIXME: Collapse into another flag field?
  510. SendPropInt( SENDINFO(m_bSimulatedEveryTick), 1, SPROP_UNSIGNED ),
  511. SendPropInt( SENDINFO(m_bAnimatedEveryTick), 1, SPROP_UNSIGNED ),
  512. SendPropBool( SENDINFO( m_bAlternateSorting )),
  513. SendPropBool( SENDINFO( m_bSpotted )),
  514. SendPropArray3( SENDINFO_ARRAY3(m_bSpottedByMask), SendPropInt( SENDINFO_ARRAY( m_bSpottedByMask ), -1, SPROP_UNSIGNED ) ),
  515. SendPropBool( SENDINFO( m_bIsAutoaimTarget )),
  516. // Fading
  517. SendPropFloat( SENDINFO( m_fadeMinDist ), 0, SPROP_NOSCALE ),
  518. SendPropFloat( SENDINFO( m_fadeMaxDist ), 0, SPROP_NOSCALE ),
  519. SendPropFloat( SENDINFO( m_flFadeScale ), 0, SPROP_NOSCALE ),
  520. #if 1
  521. // #ifndef _GAMECONSOLE -- X360 client and Win32 XLSP dedicated server need equivalent SendTables
  522. SendPropInt( SENDINFO(m_nMinCPULevel), CPU_LEVEL_BIT_COUNT, SPROP_UNSIGNED ),
  523. SendPropInt( SENDINFO(m_nMaxCPULevel), CPU_LEVEL_BIT_COUNT, SPROP_UNSIGNED ),
  524. SendPropInt( SENDINFO(m_nMinGPULevel), GPU_LEVEL_BIT_COUNT, SPROP_UNSIGNED ),
  525. SendPropInt( SENDINFO(m_nMaxGPULevel), GPU_LEVEL_BIT_COUNT, SPROP_UNSIGNED ),
  526. #endif
  527. SendPropFloat(SENDINFO( m_flUseLookAtAngle ) ),
  528. SendPropFloat( SENDINFO( m_flLastMadeNoiseTime ) ),
  529. END_SEND_TABLE()
  530. //-----------------------------------------------------------------------------
  531. bool EntityNamesMatchCStrings( const char *pszQuery, const char *pszNameToMatch )
  532. {
  533. while ( *pszNameToMatch && *pszQuery )
  534. {
  535. char cName = *pszNameToMatch;
  536. char cQuery = *pszQuery;
  537. if ( cName != cQuery && tolower(cName) != tolower(cQuery) ) // people almost always use lowercase, so assume that first
  538. break;
  539. ++pszNameToMatch;
  540. ++pszQuery;
  541. }
  542. if ( *pszQuery == 0 && *pszNameToMatch == 0 )
  543. return true;
  544. // @TODO (toml 03-18-03): Perhaps support real wildcards. Right now, only thing supported is trailing *
  545. if ( *pszQuery == '*' )
  546. return true;
  547. return false;
  548. }
  549. //-----------------------------------------------------------------------------
  550. CBaseEntity::CBaseEntity( bool bServerOnly )
  551. {
  552. COMPILE_TIME_ASSERT( MOVETYPE_LAST < (1 << MOVETYPE_MAX_BITS) );
  553. COMPILE_TIME_ASSERT( MOVECOLLIDE_COUNT < (1 << MOVECOLLIDE_MAX_BITS) );
  554. // Fix CPU_LEVEL_BIT_COUNT/GPU_LEVEL_BIT_COUNT here if necessary
  555. COMPILE_TIME_ASSERT( CPU_LEVEL_PC_COUNT+1 <= (1 << CPU_LEVEL_BIT_COUNT) );
  556. COMPILE_TIME_ASSERT( GPU_LEVEL_PC_COUNT+1 <= (1 << GPU_LEVEL_BIT_COUNT) );
  557. #ifdef _DEBUG
  558. // necessary since in debug, we initialize vectors to NAN for debugging
  559. m_vecAngVelocity.Init();
  560. m_vecAbsOrigin.Init();
  561. m_angAbsRotation.Init();
  562. // m_vecAbsAngVelocity.Init();
  563. m_vecViewOffset.Init();
  564. m_vecBaseVelocity.GetForModify().Init();
  565. m_vecVelocity.Init();
  566. m_vecAbsVelocity.Init();
  567. #endif
  568. SetCellBits();
  569. UpdateCell();
  570. m_bAlternateSorting = false;
  571. m_CollisionGroup = COLLISION_GROUP_NONE;
  572. m_iParentAttachment = 0;
  573. CollisionProp()->Init( this );
  574. NetworkProp()->Init( this );
  575. m_bForcePurgeFixedupStrings = false;
  576. m_fadeMinDist = 0;
  577. m_fadeMaxDist = 0;
  578. m_flFadeScale = 0.0f;
  579. // NOTE: THIS MUST APPEAR BEFORE ANY SetMoveType() or SetNextThink() calls
  580. AddEFlags( EFL_NO_THINK_FUNCTION | EFL_NO_GAME_PHYSICS_SIMULATION | EFL_USE_PARTITION_WHEN_NOT_SOLID );
  581. // clear debug overlays
  582. m_debugOverlays = 0;
  583. m_pTimedOverlay = NULL;
  584. m_pPhysicsObject = NULL;
  585. m_flElasticity = 1.0f;
  586. m_flShadowCastDistance = m_flDesiredShadowCastDistance = 0;
  587. SetRenderColor( 255, 255, 255 );
  588. SetRenderAlpha( 255 );
  589. m_iPendingTeamNum = m_iTeamNum = m_iInitialTeamNum = TEAM_UNASSIGNED;
  590. m_nLastThinkTick = gpGlobals->tickcount;
  591. m_nSimulationTick = -1;
  592. SetIdentityMatrix( m_rgflCoordinateFrame );
  593. m_pBlocker = NULL;
  594. #if _DEBUG
  595. m_iCurrentThinkContext = NO_THINK_CONTEXT;
  596. #endif
  597. m_nWaterTouch = m_nSlimeTouch = 0;
  598. SetSolid( SOLID_NONE );
  599. ClearSolidFlags();
  600. SetMoveType( MOVETYPE_NONE );
  601. SetOwnerEntity( NULL );
  602. SetCheckUntouch( false );
  603. SetModelIndex( 0 );
  604. SetModelName( NULL_STRING );
  605. m_nTransmitStateOwnedCounter = 0;
  606. SetCollisionBounds( vec3_origin, vec3_origin );
  607. ClearFlags();
  608. SetFriction( 1.0f );
  609. if ( bServerOnly )
  610. {
  611. AddEFlags( EFL_SERVER_ONLY );
  612. }
  613. NetworkProp()->MarkPVSInformationDirty();
  614. AddEFlags( EFL_USE_PARTITION_WHEN_NOT_SOLID );
  615. m_pPrevByClass = m_pNextByClass = NULL;
  616. m_ListByClass = (UtlHashHandle_t)~0;
  617. SetNetworkQuantizeOriginAngAngles( false );
  618. #if defined(ENABLE_CREATE_TIME)
  619. m_flCreateTime = 0.0f;
  620. #endif
  621. m_pEvent = NULL;
  622. #ifdef PORTAL2
  623. m_iSignifierName = NULL_STRING;
  624. #endif // PORTAL2
  625. m_bSpotted = false;
  626. ClearSpottedBy();
  627. m_nSpotRules = 0;
  628. m_fLastSpotCheck = 0.0f;
  629. m_bIsAutoaimTarget = false;
  630. m_flUseLookAtAngle = DEFAULT_LOOK_AT_USE_ANGLE;
  631. m_flLastMadeNoiseTime = 0.0f;
  632. }
  633. //-----------------------------------------------------------------------------
  634. // Purpose: Scale up our physics hull and test against the new one
  635. // Input : *pNewCollide - New collision hull
  636. //-----------------------------------------------------------------------------
  637. void CBaseEntity::SetScaledPhysics( IPhysicsObject *pNewObject )
  638. {
  639. if ( pNewObject )
  640. {
  641. AddSolidFlags( FSOLID_CUSTOMBOXTEST | FSOLID_CUSTOMRAYTEST );
  642. }
  643. else
  644. {
  645. RemoveSolidFlags( FSOLID_CUSTOMBOXTEST | FSOLID_CUSTOMRAYTEST );
  646. }
  647. }
  648. extern bool g_bDisableEhandleAccess;
  649. //-----------------------------------------------------------------------------
  650. // Purpose: See note below
  651. //-----------------------------------------------------------------------------
  652. CBaseEntity::~CBaseEntity( )
  653. {
  654. // FIXME: This can't be called from UpdateOnRemove! There's at least one
  655. // case where friction sounds are added between the call to UpdateOnRemove + ~CBaseEntity
  656. PhysCleanupFrictionSounds( this );
  657. // In debug make sure that we don't call delete on an entity without setting
  658. // the disable flag first!
  659. // EHANDLE accessors will check, in debug, for access to entities during destruction of
  660. // another entity.
  661. // That kind of operation should only occur in UpdateOnRemove calls
  662. // Deletion should only occur via UTIL_Remove(Immediate) calls, not via naked delete calls
  663. Assert( g_bDisableEhandleAccess );
  664. VPhysicsDestroyObject();
  665. // Need to remove references to this entity before EHANDLES go null
  666. {
  667. g_bDisableEhandleAccess = false;
  668. CBaseEntity::PhysicsRemoveTouchedList( this );
  669. CBaseEntity::PhysicsRemoveGroundList( this );
  670. DestroyAllDataObjects();
  671. g_bDisableEhandleAccess = true;
  672. // Remove this entity from the ent list (NOTE: This Makes EHANDLES go NULL)
  673. gEntList.RemoveEntity( GetRefEHandle() );
  674. }
  675. }
  676. void CBaseEntity::PostConstructor( const char *szClassname )
  677. {
  678. NetworkProp()->CacheServerClass();
  679. if ( szClassname )
  680. {
  681. SetClassname(szClassname);
  682. }
  683. Assert( m_iClassname != NULL_STRING && STRING(m_iClassname) != NULL );
  684. // Possibly get an edict, and add self to global list of entites.
  685. if ( IsEFlagSet( EFL_SERVER_ONLY ) )
  686. {
  687. gEntList.AddNonNetworkableEntity( this );
  688. }
  689. else
  690. {
  691. // Certain entities set up their edicts in the constructor
  692. if ( !IsEFlagSet( EFL_NO_AUTO_EDICT_ATTACH ) )
  693. {
  694. NetworkProp()->AttachEdict( g_pForceAttachEdict );
  695. g_pForceAttachEdict = NULL;
  696. }
  697. // Some ents like the player override the AttachEdict function and do it at a different time.
  698. // While precaching, they don't ever have an edict, so we don't need to add them to
  699. // the entity list in that case.
  700. if ( edict() )
  701. {
  702. gEntList.AddNetworkableEntity( this, entindex() );
  703. // Cache our IServerNetworkable pointer for the engine for fast access.
  704. if ( edict() )
  705. edict()->m_pNetworkable = NetworkProp();
  706. }
  707. InitSharedVars();
  708. }
  709. CheckHasThinkFunction( false );
  710. CheckHasGamePhysicsSimulation();
  711. }
  712. //-----------------------------------------------------------------------------
  713. // Purpose: Called after player becomes active in the game
  714. //-----------------------------------------------------------------------------
  715. void CBaseEntity::PostClientActive( void )
  716. {
  717. }
  718. //-----------------------------------------------------------------------------
  719. // Purpose: Verifies that this entity's data description is valid in debug builds.
  720. //-----------------------------------------------------------------------------
  721. #ifdef _DEBUG
  722. typedef CUtlVector< const char * > KeyValueNameList_t;
  723. static void AddDataMapFieldNamesToList( KeyValueNameList_t &list, datamap_t *pDataMap )
  724. {
  725. while (pDataMap != NULL)
  726. {
  727. for (int i = 0; i < pDataMap->dataNumFields; i++)
  728. {
  729. typedescription_t *pField = &pDataMap->dataDesc[i];
  730. if (pField->fieldType == FIELD_EMBEDDED)
  731. {
  732. AddDataMapFieldNamesToList( list, pField->td );
  733. continue;
  734. }
  735. if (pField->flags & FTYPEDESC_KEY)
  736. {
  737. list.AddToTail( pField->externalName );
  738. }
  739. }
  740. pDataMap = pDataMap->baseMap;
  741. }
  742. }
  743. void CBaseEntity::ValidateDataDescription(void)
  744. {
  745. // Multiple key fields that have the same name are not allowed - it creates an
  746. // ambiguity when trying to parse keyvalues and outputs.
  747. datamap_t *pDataMap = GetDataDescMap();
  748. if ((pDataMap == NULL) || pDataMap->bValidityChecked)
  749. return;
  750. pDataMap->bValidityChecked = true;
  751. // Let's generate a list of all keyvalue strings in the entire hierarchy...
  752. KeyValueNameList_t names(128);
  753. AddDataMapFieldNamesToList( names, pDataMap );
  754. for (int i = names.Count(); --i > 0; )
  755. {
  756. for (int j = i - 1; --j >= 0; )
  757. {
  758. if (!Q_stricmp(names[i], names[j]))
  759. {
  760. DevMsg( "%s has multiple data description entries for \"%s\"\n", STRING(m_iClassname), names[i]);
  761. break;
  762. }
  763. }
  764. }
  765. }
  766. #endif // _DEBUG
  767. //-----------------------------------------------------------------------------
  768. // Sets the collision bounds + the size
  769. //-----------------------------------------------------------------------------
  770. void CBaseEntity::SetCollisionBounds( const Vector& mins, const Vector &maxs )
  771. {
  772. m_Collision.SetCollisionBounds( mins, maxs );
  773. }
  774. //-----------------------------------------------------------------------------
  775. // Vscript: Gets the min collision bounds, centered on object
  776. //-----------------------------------------------------------------------------
  777. const Vector& CBaseEntity::ScriptGetBoundingMins( void )
  778. {
  779. return m_Collision.OBBMins();
  780. }
  781. //-----------------------------------------------------------------------------
  782. // Vscript: Gets the max collision bounds, centered on object
  783. //-----------------------------------------------------------------------------
  784. const Vector& CBaseEntity::ScriptGetBoundingMaxs( void )
  785. {
  786. return m_Collision.OBBMaxs();
  787. }
  788. void CBaseEntity::StopFollowingEntity( )
  789. {
  790. if( !IsFollowingEntity() )
  791. {
  792. Assert( IsEffectActive( EF_BONEMERGE ) == 0 );
  793. return;
  794. }
  795. SetParent( NULL );
  796. RemoveEffects( EF_BONEMERGE );
  797. RemoveSolidFlags( FSOLID_NOT_SOLID );
  798. SetMoveType( MOVETYPE_NONE );
  799. CollisionRulesChanged();
  800. }
  801. bool CBaseEntity::IsFollowingEntity()
  802. {
  803. return IsEffectActive( EF_BONEMERGE ) && (GetMoveType() == MOVETYPE_NONE) && GetMoveParent();
  804. }
  805. CBaseEntity *CBaseEntity::GetFollowedEntity()
  806. {
  807. if (!IsFollowingEntity())
  808. return NULL;
  809. return GetMoveParent();
  810. }
  811. void CBaseEntity::SetClassname( const char *className )
  812. {
  813. m_iClassname = AllocPooledString( className );
  814. #ifdef PORTAL2
  815. m_iSignifierName = m_iClassname;
  816. #endif // PORTAL2
  817. }
  818. // position to shoot at
  819. Vector CBaseEntity::BodyTarget( const Vector &posSrc, bool bNoisy)
  820. {
  821. return WorldSpaceCenter( );
  822. }
  823. // return the position of my head. someone's trying to attack it.
  824. Vector CBaseEntity::HeadTarget( const Vector &posSrc )
  825. {
  826. return EyePosition();
  827. }
  828. //-----------------------------------------------------------------------------
  829. // Methods related to fade distance
  830. //-----------------------------------------------------------------------------
  831. void CBaseEntity::SetFadeDistance( float minFadeDist, float maxFadeDist )
  832. {
  833. m_fadeMinDist = minFadeDist;
  834. m_fadeMaxDist = maxFadeDist;
  835. }
  836. void CBaseEntity::SetGlobalFadeScale( float flFadeScale )
  837. {
  838. m_flFadeScale = flFadeScale;
  839. }
  840. float CBaseEntity::GetGlobalFadeScale() const
  841. {
  842. return m_flFadeScale;
  843. }
  844. struct TimedOverlay_t
  845. {
  846. char *msg;
  847. int msgEndTime;
  848. int msgStartTime;
  849. TimedOverlay_t *pNextTimedOverlay;
  850. };
  851. //-----------------------------------------------------------------------------
  852. // Purpose: Display an error message on the entity
  853. // Input :
  854. // Output :
  855. //-----------------------------------------------------------------------------
  856. void CBaseEntity::AddTimedOverlay( const char *msg, int endTime )
  857. {
  858. TimedOverlay_t *pNewTO = new TimedOverlay_t;
  859. int len = strlen(msg);
  860. pNewTO->msg = new char[len + 1];
  861. Q_strncpy(pNewTO->msg,msg, len+1);
  862. pNewTO->msgEndTime = gpGlobals->curtime + endTime;
  863. pNewTO->msgStartTime = gpGlobals->curtime;
  864. pNewTO->pNextTimedOverlay = m_pTimedOverlay;
  865. m_pTimedOverlay = pNewTO;
  866. }
  867. //-----------------------------------------------------------------------------
  868. // Purpose: Send debug overlay box to the client
  869. // Input :
  870. // Output :
  871. //-----------------------------------------------------------------------------
  872. void CBaseEntity::DrawBBoxOverlay( float flDuration )
  873. {
  874. if (edict())
  875. {
  876. NDebugOverlay::EntityBounds(this, 255, 100, 0, 0, flDuration );
  877. if ( CollisionProp()->IsSolidFlagSet( FSOLID_USE_TRIGGER_BOUNDS ) )
  878. {
  879. Vector vecTriggerMins, vecTriggerMaxs;
  880. CollisionProp()->WorldSpaceTriggerBounds( &vecTriggerMins, &vecTriggerMaxs );
  881. Vector center = 0.5f * (vecTriggerMins + vecTriggerMaxs);
  882. Vector extents = vecTriggerMaxs - center;
  883. NDebugOverlay::Box(center, -extents, extents, 0, 255, 255, 0, flDuration );
  884. }
  885. }
  886. }
  887. void CBaseEntity::DrawAbsBoxOverlay()
  888. {
  889. int red = 0;
  890. int green = 200;
  891. if ( VPhysicsGetObject() && VPhysicsGetObject()->IsAsleep() )
  892. {
  893. red = 90;
  894. green = 120;
  895. }
  896. if (edict())
  897. {
  898. // Surrounding boxes are axially aligned, so ignore angles
  899. Vector vecSurroundMins, vecSurroundMaxs;
  900. CollisionProp()->WorldSpaceSurroundingBounds( &vecSurroundMins, &vecSurroundMaxs );
  901. Vector center = 0.5f * (vecSurroundMins + vecSurroundMaxs);
  902. Vector extents = vecSurroundMaxs - center;
  903. NDebugOverlay::Box(center, -extents, extents, red, green, 0, 0 ,0);
  904. }
  905. }
  906. void CBaseEntity::DrawRBoxOverlay()
  907. {
  908. }
  909. //-----------------------------------------------------------------------------
  910. // Purpose: Draws an axis overlay at the origin and angles of the entity
  911. //-----------------------------------------------------------------------------
  912. void CBaseEntity::SendDebugPivotOverlay( void )
  913. {
  914. if ( edict() )
  915. {
  916. NDebugOverlay::Axis( GetAbsOrigin(), GetAbsAngles(), 20, true, 0 );
  917. }
  918. }
  919. //------------------------------------------------------------------------------
  920. // Purpose : Add new entity positioned overlay text
  921. // Input : How many lines to offset text from origin
  922. // The text to print
  923. // How long to display text
  924. // The color of the text
  925. // Output :
  926. //------------------------------------------------------------------------------
  927. void CBaseEntity::EntityText( int text_offset, const char *text, float duration, int r, int g, int b, int a )
  928. {
  929. Vector origin;
  930. Vector vecLocalCenter;
  931. VectorAdd( m_Collision.OBBMins(), m_Collision.OBBMaxs(), vecLocalCenter );
  932. vecLocalCenter *= 0.5f;
  933. if ( ( m_Collision.GetCollisionAngles() == vec3_angle ) || ( vecLocalCenter == vec3_origin ) )
  934. {
  935. VectorAdd( vecLocalCenter, m_Collision.GetCollisionOrigin(), origin );
  936. }
  937. else
  938. {
  939. VectorTransform( vecLocalCenter, m_Collision.CollisionToWorldTransform(), origin );
  940. }
  941. NDebugOverlay::EntityTextAtPosition( origin, text_offset, text, duration, r, g, b, a );
  942. }
  943. //------------------------------------------------------------------------------
  944. // Purpose :
  945. // Input :
  946. // Output :
  947. //------------------------------------------------------------------------------
  948. void CBaseEntity::DrawTimedOverlays(void)
  949. {
  950. // Draw name first if I have an overlay or am in message mode
  951. if ((m_debugOverlays & OVERLAY_MESSAGE_BIT))
  952. {
  953. char tempstr[512];
  954. Q_snprintf( tempstr, sizeof( tempstr ), "[%s]", GetDebugName() );
  955. EntityText(0,tempstr, 0);
  956. }
  957. // Now draw overlays
  958. TimedOverlay_t* pTO = m_pTimedOverlay;
  959. TimedOverlay_t* pNextTO = NULL;
  960. TimedOverlay_t* pLastTO = NULL;
  961. int nCount = 1; // Offset by one
  962. while (pTO)
  963. {
  964. pNextTO = pTO->pNextTimedOverlay;
  965. // Remove old messages unless messages are paused
  966. if ((!CBaseEntity::Debug_IsPaused() && gpGlobals->curtime > pTO->msgEndTime) ||
  967. (nCount > 10))
  968. {
  969. if (pLastTO)
  970. {
  971. pLastTO->pNextTimedOverlay = pNextTO;
  972. }
  973. else
  974. {
  975. m_pTimedOverlay = pNextTO;
  976. }
  977. delete pTO->msg;
  978. delete pTO;
  979. }
  980. else
  981. {
  982. int nAlpha = 0;
  983. // If messages aren't paused fade out
  984. if (!CBaseEntity::Debug_IsPaused())
  985. {
  986. nAlpha = 255*((gpGlobals->curtime - pTO->msgStartTime)/(pTO->msgEndTime - pTO->msgStartTime));
  987. }
  988. int r = 185;
  989. int g = 145;
  990. int b = 145;
  991. // Brighter when new message
  992. if (nAlpha < 50)
  993. {
  994. r = 255;
  995. g = 205;
  996. b = 205;
  997. }
  998. if (nAlpha < 0) nAlpha = 0;
  999. EntityText(nCount,pTO->msg, 0.0, r, g, b, 255-nAlpha);
  1000. nCount++;
  1001. pLastTO = pTO;
  1002. }
  1003. pTO = pNextTO;
  1004. }
  1005. }
  1006. void CBaseEntity::DrawVPhysicsObjectCenterAndContactPoints(IPhysicsObject *obj)
  1007. {
  1008. if ( obj == NULL ) return;
  1009. Vector massCenter = obj->GetMassCenterLocalSpace();
  1010. Vector worldPos;
  1011. obj->LocalToWorld( &worldPos, massCenter );
  1012. NDebugOverlay::Cross3D( worldPos, 12, 255, 0, 0, false, 0 );
  1013. DebugDrawContactPoints(obj);
  1014. if ( GetMoveType() != MOVETYPE_VPHYSICS )
  1015. {
  1016. Vector pos;
  1017. QAngle angles;
  1018. obj->GetPosition( &pos, &angles );
  1019. float dist = (pos - GetAbsOrigin()).Length();
  1020. Vector axis;
  1021. float deltaAngle;
  1022. RotationDeltaAxisAngle( angles, GetAbsAngles(), axis, deltaAngle );
  1023. if ( dist > 2 || fabsf(deltaAngle) > 2 )
  1024. {
  1025. Vector mins, maxs;
  1026. if ( obj->GetCollide() )
  1027. {
  1028. physcollision->CollideGetAABB( &mins, &maxs, obj->GetCollide(), vec3_origin, vec3_angle );
  1029. }
  1030. else
  1031. {
  1032. mins = WorldAlignMins();
  1033. maxs = WorldAlignMins();
  1034. }
  1035. NDebugOverlay::BoxAngles( pos, mins, maxs, angles, 255, 255, 0, 16, 0 );
  1036. }
  1037. }
  1038. }
  1039. //-----------------------------------------------------------------------------
  1040. // Purpose: Draw all overlays (should be implemented by subclass to add
  1041. // any additional non-text overlays)
  1042. // Input :
  1043. // Output : Current text offset from the top
  1044. //-----------------------------------------------------------------------------
  1045. ConVar autoaim_viewing_client("autoaim_viewing_client", "1", FCVAR_DEVELOPMENTONLY );
  1046. void CBaseEntity::DrawDebugGeometryOverlays(void)
  1047. {
  1048. DrawTimedOverlays();
  1049. DrawDebugTextOverlays();
  1050. if (m_debugOverlays & OVERLAY_NAME_BIT)
  1051. {
  1052. EntityText(0,GetDebugName(), 0);
  1053. }
  1054. if (m_debugOverlays & OVERLAY_BBOX_BIT)
  1055. {
  1056. DrawBBoxOverlay();
  1057. }
  1058. if (m_debugOverlays & OVERLAY_ABSBOX_BIT )
  1059. {
  1060. DrawAbsBoxOverlay();
  1061. }
  1062. if (m_debugOverlays & OVERLAY_PIVOT_BIT)
  1063. {
  1064. SendDebugPivotOverlay();
  1065. }
  1066. if( m_debugOverlays & OVERLAY_RBOX_BIT )
  1067. {
  1068. DrawRBoxOverlay();
  1069. }
  1070. if ( m_debugOverlays & (OVERLAY_BBOX_BIT|OVERLAY_PIVOT_BIT) )
  1071. {
  1072. // draw mass center and contact points
  1073. DrawVPhysicsObjectCenterAndContactPoints(VPhysicsGetObject());
  1074. IPhysicsObject *pList[VPHYSICS_MAX_OBJECT_LIST_COUNT];
  1075. int count = VPhysicsGetObjectList( pList, ARRAYSIZE(pList) );
  1076. for ( int i = 0; i < count; i++ )
  1077. {
  1078. DrawVPhysicsObjectCenterAndContactPoints(pList[i]);
  1079. }
  1080. }
  1081. if ( m_debugOverlays & OVERLAY_SHOW_BLOCKSLOS )
  1082. {
  1083. if ( BlocksLOS() )
  1084. {
  1085. NDebugOverlay::EntityBounds(this, 255, 255, 255, 0, 0 );
  1086. }
  1087. }
  1088. if ( ( m_debugOverlays & OVERLAY_AUTOAIM_BIT ) && (GetFlags()&FL_AIMTARGET) && AI_GetSinglePlayer() != NULL )
  1089. {
  1090. // Crude, but it gets the point across.
  1091. Vector vecCenter = GetAutoAimCenter();
  1092. Vector vecRight, vecUp, vecDiag;
  1093. CBasePlayer *pPlayer = AI_GetSinglePlayer();
  1094. float radius = GetAutoAimRadius();
  1095. QAngle angles = pPlayer->EyeAngles();
  1096. AngleVectors( angles, NULL, &vecRight, &vecUp );
  1097. int r,g,b;
  1098. if( ((int)gpGlobals->curtime) % 2 == 1 )
  1099. {
  1100. r = 255;
  1101. g = 255;
  1102. b = 255;
  1103. if( pPlayer->GetActiveWeapon() != NULL )
  1104. radius *= pPlayer->GetActiveWeapon()->WeaponAutoAimScale();
  1105. }
  1106. else
  1107. {
  1108. r = 255;g=0;b=0;
  1109. if( !ShouldAttractAutoAim(pPlayer) )
  1110. {
  1111. g = 255;
  1112. }
  1113. }
  1114. if( pPlayer->IsInAVehicle() )
  1115. {
  1116. radius *= sv_vehicle_autoaim_scale.GetFloat();
  1117. }
  1118. NDebugOverlay::Line( vecCenter, vecCenter + vecRight * radius, r, g, b, true, 0.1 );
  1119. NDebugOverlay::Line( vecCenter, vecCenter - vecRight * radius, r, g, b, true, 0.1 );
  1120. NDebugOverlay::Line( vecCenter, vecCenter + vecUp * radius, r, g, b, true, 0.1 );
  1121. NDebugOverlay::Line( vecCenter, vecCenter - vecUp * radius, r, g, b, true, 0.1 );
  1122. vecDiag = vecRight + vecUp;
  1123. VectorNormalize( vecDiag );
  1124. NDebugOverlay::Line( vecCenter - vecDiag * radius, vecCenter + vecDiag * radius, r, g, b, true, 0.1 );
  1125. vecDiag = vecRight - vecUp;
  1126. VectorNormalize( vecDiag );
  1127. NDebugOverlay::Line( vecCenter - vecDiag * radius, vecCenter + vecDiag * radius, r, g, b, true, 0.1 );
  1128. }
  1129. }
  1130. static ConVar debug_overlay_fullposition( "debug_overlay_fullposition",
  1131. #if defined( _DEBUG )
  1132. "1"
  1133. #else
  1134. "0"
  1135. #endif
  1136. );
  1137. //-----------------------------------------------------------------------------
  1138. // Purpose: Draw any text overlays (override in subclass to add additional text)
  1139. // Output : Current text offset from the top
  1140. //-----------------------------------------------------------------------------
  1141. int CBaseEntity::DrawDebugTextOverlays(void)
  1142. {
  1143. int offset = 1;
  1144. if (m_debugOverlays & OVERLAY_TEXT_BIT)
  1145. {
  1146. int r = 0;
  1147. int g = 255;
  1148. int b = 0;
  1149. char tempstr[512];
  1150. Q_snprintf( tempstr, sizeof(tempstr), "(%d) Name: %s (%s)", entindex(), GetDebugName(), GetClassname() );
  1151. EntityText(offset,tempstr, 0,r,g,b);
  1152. offset++;
  1153. if( m_iGlobalname != NULL_STRING )
  1154. {
  1155. Q_snprintf( tempstr, sizeof(tempstr), "GLOBALNAME: %s", STRING( m_iGlobalname ) );
  1156. EntityText(offset,tempstr, 0);
  1157. offset++;
  1158. }
  1159. if (debug_overlay_fullposition.GetBool() )
  1160. {
  1161. Vector vecOrigin = GetAbsOrigin();
  1162. Q_snprintf( tempstr, sizeof(tempstr), "pos: (%f, %f, %f)\n", vecOrigin.x, vecOrigin.y, vecOrigin.z );
  1163. EntityText( offset, tempstr, 0 );
  1164. offset++;
  1165. QAngle angOrientation = GetAbsAngles();
  1166. Q_snprintf( tempstr, sizeof(tempstr), "ang: (%f, %f, %f)\n", angOrientation.x, angOrientation.y, angOrientation.z );
  1167. EntityText( offset, tempstr, 0 );
  1168. offset++;
  1169. Q_snprintf( tempstr, sizeof(tempstr), "cell: (%d, %d, %d)\n", m_cellX.Get(), m_cellY.Get(), m_cellZ.Get() );
  1170. EntityText( offset, tempstr, 0 );
  1171. offset++;
  1172. register int const cellwidth = m_cellwidth; // Load it into a register
  1173. Vector cellOrigin;
  1174. cellOrigin.x = CellInCoord( cellwidth, m_cellX, m_vecOrigin->x );
  1175. cellOrigin.y = CellInCoord( cellwidth, m_cellY, m_vecOrigin->y );
  1176. cellOrigin.z = CellInCoord( cellwidth, m_cellZ, m_vecOrigin->z );
  1177. Q_snprintf( tempstr, sizeof(tempstr), "celloffset: (%f, %f, %f)\n", cellOrigin.x, cellOrigin.y, cellOrigin.z );
  1178. EntityText( offset, tempstr, 0 );
  1179. offset++;
  1180. }
  1181. else
  1182. {
  1183. Vector vecOrigin = GetAbsOrigin();
  1184. Q_snprintf( tempstr, sizeof(tempstr), "Position: %0.3f, %0.3f, %0.3f\n", vecOrigin.x, vecOrigin.y, vecOrigin.z );
  1185. EntityText( offset, tempstr, 0 );
  1186. offset++;
  1187. }
  1188. if ( !BlocksLOS() )
  1189. {
  1190. EntityText(offset,"Doesn't block LOS",0);
  1191. offset++;
  1192. }
  1193. if ( GetModelName() != NULL_STRING || GetBaseAnimating() )
  1194. {
  1195. Q_snprintf(tempstr, sizeof(tempstr), "Model:%s", STRING(GetModelName()) );
  1196. EntityText(offset,tempstr,0,255,255,0);
  1197. offset++;
  1198. }
  1199. if( m_hDamageFilter.Get() != NULL )
  1200. {
  1201. Q_snprintf( tempstr, sizeof(tempstr), "DAMAGE FILTER:%s", m_hDamageFilter->GetDebugName() );
  1202. EntityText( offset,tempstr,0,r,g,b);
  1203. offset++;
  1204. }
  1205. if ( ent_show_contexts.GetBool() )
  1206. {
  1207. int count = GetContextCount();
  1208. if ( count )
  1209. {
  1210. for ( int i = 0; i < count; ++i )
  1211. {
  1212. Q_snprintf(tempstr, sizeof(tempstr),"Context: %s:%s", GetContextName( i ), GetContextValue( i ) );
  1213. EntityText( offset, tempstr, 0,r,g,b);
  1214. offset++;
  1215. }
  1216. }
  1217. }
  1218. Q_snprintf(tempstr, sizeof(tempstr), "Flags :%d", GetFlags() );
  1219. EntityText(offset,tempstr,0);
  1220. offset++;
  1221. Q_snprintf(tempstr, sizeof(tempstr), "Effects :%d (EF_NODRAW=%d)", GetEffects(), GetEffects() & EF_NODRAW );
  1222. EntityText(offset,tempstr,0);
  1223. offset++;
  1224. #if defined ( PORTAL2 )
  1225. Q_snprintf(tempstr, sizeof(tempstr), "In Portal Environment: %s", (CPortalSimulator::GetSimulatorThatOwnsEntity(this))?("yes"):("no") );
  1226. EntityText(offset,tempstr,0);
  1227. offset++;
  1228. #endif
  1229. }
  1230. if (m_debugOverlays & OVERLAY_VIEWOFFSET)
  1231. {
  1232. NDebugOverlay::Cross3D( EyePosition(), 16, 255, 0, 0, true, 0.05f );
  1233. }
  1234. return offset;
  1235. }
  1236. void CBaseEntity::SetParent( string_t newParent, CBaseEntity *pActivator, int iAttachment )
  1237. {
  1238. // find and notify the new parent
  1239. CBaseEntity *pParent = gEntList.FindEntityByName( NULL, newParent, NULL, pActivator );
  1240. // debug check
  1241. if ( newParent != NULL_STRING && pParent == NULL )
  1242. {
  1243. Msg( "Entity %s(%s) has bad parent %s\n", STRING(m_iClassname), GetDebugName(), STRING(newParent) );
  1244. }
  1245. else
  1246. {
  1247. // make sure there isn't any ambiguity
  1248. if ( gEntList.FindEntityByName( pParent, newParent, NULL, pActivator ) )
  1249. {
  1250. Msg( "Entity %s(%s) is ambiguously parented to %s, because there is more than one entity by that name.\n", STRING(m_iClassname), GetDebugName(), STRING(newParent) );
  1251. }
  1252. SetParent( pParent, iAttachment );
  1253. }
  1254. }
  1255. //-----------------------------------------------------------------------------
  1256. // Purpose: Move our points from parent to worldspace
  1257. // Input : *pParent - Parent to use as reference
  1258. //-----------------------------------------------------------------------------
  1259. void CBaseEntity::TransformStepData_ParentToWorld( CBaseEntity *pParent )
  1260. {
  1261. // Fix up our step simulation points to be in the proper local space
  1262. StepSimulationData *step = (StepSimulationData *) GetDataObject( STEPSIMULATION );
  1263. if ( step != NULL )
  1264. {
  1265. // Convert our positions
  1266. UTIL_ParentToWorldSpace( pParent, step->m_Previous2.vecOrigin, step->m_Previous2.qRotation );
  1267. UTIL_ParentToWorldSpace( pParent, step->m_Previous.vecOrigin, step->m_Previous.qRotation );
  1268. }
  1269. }
  1270. //-----------------------------------------------------------------------------
  1271. // Purpose: Move step data between two parent-spaces
  1272. // Input : *pOldParent - parent we were attached to
  1273. // *pNewParent - parent we're now attached to
  1274. //-----------------------------------------------------------------------------
  1275. void CBaseEntity::TransformStepData_ParentToParent( CBaseEntity *pOldParent, CBaseEntity *pNewParent )
  1276. {
  1277. // Fix up our step simulation points to be in the proper local space
  1278. StepSimulationData *step = (StepSimulationData *) GetDataObject( STEPSIMULATION );
  1279. if ( step != NULL )
  1280. {
  1281. // Convert our positions
  1282. UTIL_ParentToWorldSpace( pOldParent, step->m_Previous2.vecOrigin, step->m_Previous2.qRotation );
  1283. UTIL_WorldToParentSpace( pNewParent, step->m_Previous2.vecOrigin, step->m_Previous2.qRotation );
  1284. UTIL_ParentToWorldSpace( pOldParent, step->m_Previous.vecOrigin, step->m_Previous.qRotation );
  1285. UTIL_WorldToParentSpace( pNewParent, step->m_Previous.vecOrigin, step->m_Previous.qRotation );
  1286. }
  1287. }
  1288. //-----------------------------------------------------------------------------
  1289. // Purpose: After parenting to an object, we need to also correctly translate our
  1290. // step stimulation positions and angles into that parent space. Otherwise
  1291. // we end up splining between two different world spaces.
  1292. //-----------------------------------------------------------------------------
  1293. void CBaseEntity::TransformStepData_WorldToParent( CBaseEntity *pParent )
  1294. {
  1295. // Fix up our step simulation points to be in the proper local space
  1296. StepSimulationData *step = (StepSimulationData *) GetDataObject( STEPSIMULATION );
  1297. if ( step != NULL )
  1298. {
  1299. // Convert our positions
  1300. UTIL_WorldToParentSpace( pParent, step->m_Previous2.vecOrigin, step->m_Previous2.qRotation );
  1301. UTIL_WorldToParentSpace( pParent, step->m_Previous.vecOrigin, step->m_Previous.qRotation );
  1302. }
  1303. }
  1304. //-----------------------------------------------------------------------------
  1305. // Purpose: Sets the movement parent of this entity. This entity will be moved
  1306. // to a local coordinate calculated from its current absolute offset
  1307. // from the parent entity and will then follow the parent entity.
  1308. // Input : pParentEntity - This entity's new parent in the movement hierarchy.
  1309. //-----------------------------------------------------------------------------
  1310. void CBaseEntity::SetParent( CBaseEntity *pParentEntity, int iAttachment )
  1311. {
  1312. // If they didn't specify an attachment, use our current
  1313. if ( iAttachment == -1 )
  1314. {
  1315. iAttachment = m_iParentAttachment;
  1316. }
  1317. bool bWasNotParented = ( GetParent() == NULL );
  1318. CBaseEntity *pOldParent = m_pParent;
  1319. // notify the old parent of the loss
  1320. UnlinkFromParent( this );
  1321. // set the new name
  1322. m_pParent = pParentEntity;
  1323. if ( m_pParent == this )
  1324. {
  1325. // should never set parent to 'this' - makes no sense
  1326. Assert(0);
  1327. m_pParent = NULL;
  1328. }
  1329. if ( m_pParent == NULL )
  1330. {
  1331. m_iParent = NULL_STRING;
  1332. // Transform step data from parent to worldspace
  1333. TransformStepData_ParentToWorld( pOldParent );
  1334. UpdatePhysicsShadowToCurrentPosition(0);
  1335. return;
  1336. }
  1337. m_iParent = m_pParent->m_iName;
  1338. RemoveSolidFlags( FSOLID_ROOT_PARENT_ALIGNED );
  1339. if ( pParentEntity )
  1340. {
  1341. if ( const_cast<CBaseEntity *>(pParentEntity)->GetRootMoveParent()->GetSolid() == SOLID_BSP )
  1342. {
  1343. AddSolidFlags( FSOLID_ROOT_PARENT_ALIGNED );
  1344. }
  1345. else
  1346. {
  1347. if ( GetSolid() == SOLID_BSP )
  1348. {
  1349. // Must be SOLID_VPHYSICS because parent might rotate
  1350. SetSolid( SOLID_VPHYSICS );
  1351. }
  1352. }
  1353. }
  1354. // set the move parent if we have one
  1355. if ( edict() )
  1356. {
  1357. // add ourselves to the list
  1358. LinkChild( m_pParent, this );
  1359. m_iParentAttachment = (char)iAttachment;
  1360. EntityMatrix matrix, childMatrix;
  1361. matrix.InitFromEntity( const_cast<CBaseEntity *>(pParentEntity), m_iParentAttachment ); // parent->world
  1362. childMatrix.InitFromEntityLocal( this ); // child->world
  1363. Vector localOrigin = matrix.WorldToLocal( GetLocalOrigin() );
  1364. // I have the axes of local space in world space. (childMatrix)
  1365. // I want to compute those world space axes in the parent's local space
  1366. // and set that transform (as angles) on the child's object so the net
  1367. // result is that the child is now in parent space, but still oriented the same way
  1368. VMatrix tmp = matrix.Transpose(); // world->parent
  1369. tmp.MatrixMul( childMatrix, matrix ); // child->parent
  1370. QAngle angles;
  1371. MatrixToAngles( matrix, angles );
  1372. SetLocalAngles( angles );
  1373. UTIL_SetOrigin( this, localOrigin );
  1374. // Move our step data into the correct space
  1375. if ( bWasNotParented )
  1376. {
  1377. // Transform step data from world to parent-space
  1378. TransformStepData_WorldToParent( this );
  1379. }
  1380. else
  1381. {
  1382. // Transform step data between parent-spaces
  1383. TransformStepData_ParentToParent( pOldParent, this );
  1384. }
  1385. }
  1386. if ( VPhysicsGetObject() )
  1387. {
  1388. if ( VPhysicsGetObject()->IsStatic())
  1389. {
  1390. if ( VPhysicsGetObject()->IsAttachedToConstraint(false) )
  1391. {
  1392. Warning("SetParent on static object, all constraints attached to %s (%s)will now be broken!\n", GetDebugName(), GetClassname() );
  1393. }
  1394. VPhysicsDestroyObject();
  1395. VPhysicsInitShadow(false, false);
  1396. }
  1397. else
  1398. {
  1399. UpdatePhysicsShadowToCurrentPosition(0);
  1400. }
  1401. }
  1402. CollisionRulesChanged();
  1403. }
  1404. //-----------------------------------------------------------------------------
  1405. // Purpose:
  1406. //-----------------------------------------------------------------------------
  1407. void CBaseEntity::ValidateEntityConnections()
  1408. {
  1409. if ( m_target == NULL_STRING )
  1410. return;
  1411. if ( ClassMatches( "scripted_*" ) ||
  1412. ClassMatches( "trigger_relay" ) ||
  1413. ClassMatches( "trigger_auto" ) ||
  1414. ClassMatches( "path_*" ) ||
  1415. ClassMatches( "monster_*" ) ||
  1416. ClassMatches( "trigger_teleport" ) ||
  1417. ClassMatches( "func_train" ) ||
  1418. ClassMatches( "func_tracktrain" ) ||
  1419. ClassMatches( "func_plat*" ) ||
  1420. ClassMatches( "npc_*" ) ||
  1421. ClassMatches( "info_big*" ) ||
  1422. ClassMatches( "env_texturetoggle" ) ||
  1423. ClassMatches( "env_render" ) ||
  1424. ClassMatches( "func_areaportalwindow") ||
  1425. ClassMatches( "point_view*") ||
  1426. ClassMatches( "func_traincontrols" ) ||
  1427. ClassMatches( "multisource" ) ||
  1428. ClassMatches( "xen_plant*" ) )
  1429. return;
  1430. datamap_t *dmap = GetDataDescMap();
  1431. while ( dmap )
  1432. {
  1433. int fields = dmap->dataNumFields;
  1434. for ( int i = 0; i < fields; i++ )
  1435. {
  1436. typedescription_t *dataDesc = &dmap->dataDesc[i];
  1437. if ( ( dataDesc->fieldType == FIELD_CUSTOM ) && ( dataDesc->flags & FTYPEDESC_OUTPUT ) )
  1438. {
  1439. CBaseEntityOutput *pOutput = (CBaseEntityOutput *)((intp)this + (int)dataDesc->fieldOffset);
  1440. if ( pOutput->NumberOfElements() )
  1441. return;
  1442. }
  1443. }
  1444. dmap = dmap->baseMap;
  1445. }
  1446. Vector vecLoc = WorldSpaceCenter();
  1447. Warning("---------------------------------\n");
  1448. Warning( "Entity %s - (%s) has a target and NO OUTPUTS\n", GetDebugName(), GetClassname() );
  1449. Warning( "Location %f %f %f\n", vecLoc.x, vecLoc.y, vecLoc.z );
  1450. Warning("---------------------------------\n");
  1451. }
  1452. //-----------------------------------------------------------------------------
  1453. // Purpose:
  1454. //-----------------------------------------------------------------------------
  1455. void CBaseEntity::FireNamedOutput( const char *pszOutput, variant_t variant, CBaseEntity *pActivator, CBaseEntity *pCaller, float flDelay )
  1456. {
  1457. if ( pszOutput == NULL )
  1458. return;
  1459. CBaseEntityOutput *pOutput = FindNamedOutput( pszOutput );
  1460. if ( pOutput )
  1461. {
  1462. pOutput->FireOutput( variant, pActivator, pCaller, flDelay );
  1463. return;
  1464. }
  1465. }
  1466. CBaseEntityOutput *CBaseEntity::FindNamedOutput( const char *pszOutput )
  1467. {
  1468. if ( pszOutput == NULL )
  1469. return NULL;
  1470. datamap_t *dmap = GetDataDescMap();
  1471. while ( dmap )
  1472. {
  1473. int fields = dmap->dataNumFields;
  1474. for ( int i = 0; i < fields; i++ )
  1475. {
  1476. typedescription_t *dataDesc = &dmap->dataDesc[i];
  1477. if ( ( dataDesc->fieldType == FIELD_CUSTOM ) && ( dataDesc->flags & FTYPEDESC_OUTPUT ) )
  1478. {
  1479. CBaseEntityOutput *pOutput = ( CBaseEntityOutput * )( ( intp )this + ( int )dataDesc->fieldOffset );
  1480. if ( !Q_stricmp( dataDesc->externalName, pszOutput ) )
  1481. {
  1482. return pOutput;
  1483. }
  1484. }
  1485. }
  1486. dmap = dmap->baseMap;
  1487. }
  1488. return NULL;
  1489. }
  1490. void CBaseEntity::Activate( void )
  1491. {
  1492. #ifdef DEBUG
  1493. extern bool g_bCheckForChainedActivate;
  1494. extern bool g_bReceivedChainedActivate;
  1495. if ( g_bCheckForChainedActivate && g_bReceivedChainedActivate )
  1496. {
  1497. AssertMsg2( false, "Multiple calls to base class Activate() by %s (a %s)!\n", GetDebugName(), GetClassname() );
  1498. }
  1499. g_bReceivedChainedActivate = true;
  1500. #endif
  1501. // NOTE: This forces a team change so that stuff in the level
  1502. // that starts out on a team correctly changes team
  1503. if (m_iInitialTeamNum)
  1504. {
  1505. ChangeTeam( m_iInitialTeamNum );
  1506. }
  1507. // Get a handle to my damage filter entity if there is one.
  1508. if ( m_iszDamageFilterName != NULL_STRING )
  1509. {
  1510. m_hDamageFilter = gEntList.FindEntityByName( NULL, m_iszDamageFilterName );
  1511. }
  1512. // Add any non-null context strings to our context vector
  1513. if ( m_iszResponseContext != NULL_STRING )
  1514. {
  1515. AddContext( m_iszResponseContext.ToCStr() );
  1516. }
  1517. #if defined ( PORTAL2 )
  1518. UpdateObjectCapsCache();
  1519. #endif
  1520. }
  1521. //////////////////////////// old CBaseEntity stuff ///////////////////////////////////
  1522. // give health.
  1523. // Returns the amount of health actually taken.
  1524. int CBaseEntity::TakeHealth( float flHealth, int bitsDamageType )
  1525. {
  1526. if ( !edict() || m_takedamage < DAMAGE_YES )
  1527. return 0;
  1528. int iMax = GetMaxHealth();
  1529. // heal
  1530. if ( m_iHealth >= iMax )
  1531. return 0;
  1532. const int oldHealth = m_iHealth;
  1533. m_iHealth += flHealth;
  1534. if (m_iHealth > iMax)
  1535. m_iHealth = iMax;
  1536. return m_iHealth - oldHealth;
  1537. }
  1538. // inflict damage on this entity. bitsDamageType indicates type of damage inflicted, ie: DMG_CRUSH
  1539. int CBaseEntity::OnTakeDamage( const CTakeDamageInfo &info )
  1540. {
  1541. Vector vecTemp;
  1542. if ( !edict() || !m_takedamage )
  1543. return 0;
  1544. if ( info.GetInflictor() )
  1545. {
  1546. vecTemp = info.GetInflictor()->WorldSpaceCenter() - ( WorldSpaceCenter() );
  1547. }
  1548. else
  1549. {
  1550. vecTemp.Init( 1, 0, 0 );
  1551. }
  1552. // this global is still used for glass and other non-NPC killables, along with decals.
  1553. g_vecAttackDir = vecTemp;
  1554. VectorNormalize(g_vecAttackDir);
  1555. // save damage based on the target's armor level
  1556. // figure momentum add (don't let hurt brushes or other triggers move player)
  1557. // physics objects have their own calcs for this: (don't let fire move things around!)
  1558. if ( !IsEFlagSet( EFL_NO_DAMAGE_FORCES ) )
  1559. {
  1560. if ( ( GetMoveType() == MOVETYPE_VPHYSICS ) )
  1561. {
  1562. VPhysicsTakeDamage( info );
  1563. }
  1564. else
  1565. {
  1566. if ( info.GetInflictor() && (GetMoveType() == MOVETYPE_WALK || GetMoveType() == MOVETYPE_STEP) &&
  1567. !info.GetAttacker()->IsSolidFlagSet(FSOLID_TRIGGER) )
  1568. {
  1569. Vector vecDir, vecInflictorCentroid;
  1570. vecDir = WorldSpaceCenter( );
  1571. vecInflictorCentroid = info.GetInflictor()->WorldSpaceCenter( );
  1572. vecDir -= vecInflictorCentroid;
  1573. VectorNormalize( vecDir );
  1574. float flForce = info.GetDamage() * ((32 * 32 * 72.0) / (WorldAlignSize().x * WorldAlignSize().y * WorldAlignSize().z)) * 5;
  1575. if (flForce > 1000.0)
  1576. flForce = 1000.0;
  1577. ApplyAbsVelocityImpulse( vecDir * flForce );
  1578. }
  1579. }
  1580. }
  1581. if ( m_takedamage != DAMAGE_EVENTS_ONLY )
  1582. {
  1583. // do the damage
  1584. m_iHealth -= info.GetDamage();
  1585. if (m_iHealth <= 0)
  1586. {
  1587. Event_Killed( info );
  1588. return 0;
  1589. }
  1590. }
  1591. return 1;
  1592. }
  1593. //-----------------------------------------------------------------------------
  1594. // Purpose: Scale damage done and call OnTakeDamage
  1595. //-----------------------------------------------------------------------------
  1596. void CBaseEntity::TakeDamage( const CTakeDamageInfo &inputInfo )
  1597. {
  1598. if ( !g_pGameRules )
  1599. return;
  1600. bool bHasPhysicsForceDamage = !g_pGameRules->Damage_NoPhysicsForce( inputInfo.GetDamageType() );
  1601. if ( bHasPhysicsForceDamage && inputInfo.GetDamageType() != DMG_GENERIC )
  1602. {
  1603. // If you hit this assert, you've called TakeDamage with a damage type that requires a physics damage
  1604. // force & position without specifying one or both of them. Decide whether your damage that's causing
  1605. // this is something you believe should impart physics force on the receiver. If it is, you need to
  1606. // setup the damage force & position inside the CTakeDamageInfo (Utility functions for this are in
  1607. // takedamageinfo.cpp. If you think the damage shouldn't cause force (unlikely!) then you can set the
  1608. // damage type to DMG_GENERIC, or | DMG_CRUSH if you need to preserve the damage type for purposes of HUD display.
  1609. if ( inputInfo.GetDamageForce() == vec3_origin || inputInfo.GetDamagePosition() == vec3_origin )
  1610. {
  1611. static int warningCount = 0;
  1612. if ( ++warningCount < 10 )
  1613. {
  1614. if ( inputInfo.GetDamageForce() == vec3_origin )
  1615. {
  1616. DevWarning( "CBaseEntity::TakeDamage: with inputInfo.GetDamageForce() == vec3_origin\n" );
  1617. }
  1618. if ( inputInfo.GetDamagePosition() == vec3_origin )
  1619. {
  1620. DevWarning( "CBaseEntity::TakeDamage: with inputInfo.GetDamagePosition() == vec3_origin\n" );
  1621. }
  1622. }
  1623. }
  1624. }
  1625. // Make sure our damage filter allows the damage.
  1626. if ( !PassesDamageFilter( inputInfo ))
  1627. {
  1628. return;
  1629. }
  1630. if( !g_pGameRules->AllowDamage(this, inputInfo) )
  1631. {
  1632. return;
  1633. }
  1634. if ( PhysIsInCallback() )
  1635. {
  1636. PhysCallbackDamage( this, inputInfo );
  1637. }
  1638. else
  1639. {
  1640. CTakeDamageInfo info = inputInfo;
  1641. // Scale the damage by the attacker's modifier.
  1642. if ( info.GetAttacker() )
  1643. {
  1644. info.ScaleDamage( info.GetAttacker()->GetAttackDamageScale( this ) );
  1645. }
  1646. // Scale the damage by my own modifiers
  1647. info.ScaleDamage( GetReceivedDamageScale( info.GetAttacker() ) );
  1648. //Msg("%s took %.2f Damage, at %.2f\n", GetClassname(), info.GetDamage(), gpGlobals->curtime );
  1649. OnTakeDamage( info );
  1650. }
  1651. }
  1652. //-----------------------------------------------------------------------------
  1653. // Purpose: Returns a value that scales all damage done by this entity.
  1654. //-----------------------------------------------------------------------------
  1655. float CBaseEntity::GetAttackDamageScale( CBaseEntity *pVictim )
  1656. {
  1657. float flScale = 1;
  1658. #if ENABLE_DAMAGE_MODIFIERS
  1659. FOR_EACH_LL( m_DamageModifiers, i )
  1660. {
  1661. if ( !m_DamageModifiers[i]->IsDamageDoneToMe() )
  1662. {
  1663. flScale *= m_DamageModifiers[i]->GetModifier();
  1664. }
  1665. }
  1666. #endif
  1667. return flScale;
  1668. }
  1669. //-----------------------------------------------------------------------------
  1670. // Purpose: Returns a value that scales all damage done to this entity
  1671. //-----------------------------------------------------------------------------
  1672. float CBaseEntity::GetReceivedDamageScale( CBaseEntity *pAttacker )
  1673. {
  1674. float flScale = 1;
  1675. #if ENABLE_DAMAGE_MODIFIERS
  1676. FOR_EACH_LL( m_DamageModifiers, i )
  1677. {
  1678. if ( m_DamageModifiers[i]->IsDamageDoneToMe() )
  1679. {
  1680. flScale *= m_DamageModifiers[i]->GetModifier();
  1681. }
  1682. }
  1683. #endif
  1684. return flScale;
  1685. }
  1686. //-----------------------------------------------------------------------------
  1687. // Purpose: Applies forces to our physics object in response to damage.
  1688. //-----------------------------------------------------------------------------
  1689. int CBaseEntity::VPhysicsTakeDamage( const CTakeDamageInfo &info )
  1690. {
  1691. // don't let physics impacts or fire cause objects to move (again)
  1692. bool bNoPhysicsForceDamage = g_pGameRules->Damage_NoPhysicsForce( info.GetDamageType() );
  1693. if ( bNoPhysicsForceDamage || info.GetDamageType() == DMG_GENERIC )
  1694. return 1;
  1695. // Bash/Shooting wants to set 0 force to not shove heavy physics props at all
  1696. if ( (info.GetDamageType() & (DMG_BULLET | DMG_CLUB)) && info.GetDamageForce().IsZero() )
  1697. return 1;
  1698. Assert(VPhysicsGetObject() != NULL);
  1699. if ( VPhysicsGetObject() )
  1700. {
  1701. Vector force = info.GetDamageForce();
  1702. Vector offset = info.GetDamagePosition();
  1703. // If you hit this assert, you've called TakeDamage with a damage type that requires a physics damage
  1704. // force & position without specifying one or both of them. Decide whether your damage that's causing
  1705. // this is something you believe should impart physics force on the receiver. If it is, you need to
  1706. // setup the damage force & position inside the CTakeDamageInfo (Utility functions for this are in
  1707. // takedamageinfo.cpp. If you think the damage shouldn't cause force (unlikely!) then you can set the
  1708. // damage type to DMG_GENERIC, or | DMG_CRUSH if you need to preserve the damage type for purposes of HUD display.
  1709. Assert( force != vec3_origin && offset != vec3_origin );
  1710. unsigned short gameFlags = VPhysicsGetObject()->GetGameFlags();
  1711. if ( gameFlags & FVPHYSICS_PLAYER_HELD )
  1712. {
  1713. // if the player is holding the object, use it's real mass (player holding reduced the mass)
  1714. CBasePlayer *pPlayer = UTIL_GetLocalPlayer();
  1715. if ( pPlayer )
  1716. {
  1717. float mass = pPlayer->GetHeldObjectMass( VPhysicsGetObject() );
  1718. if ( mass != 0.0f )
  1719. {
  1720. float ratio = VPhysicsGetObject()->GetMass() / mass;
  1721. force *= ratio;
  1722. }
  1723. }
  1724. }
  1725. else if ( (gameFlags & FVPHYSICS_PART_OF_RAGDOLL) && (gameFlags & FVPHYSICS_CONSTRAINT_STATIC) )
  1726. {
  1727. IPhysicsObject *pList[VPHYSICS_MAX_OBJECT_LIST_COUNT];
  1728. int count = VPhysicsGetObjectList( pList, ARRAYSIZE(pList) );
  1729. for ( int i = 0; i < count; i++ )
  1730. {
  1731. if ( !(pList[i]->GetGameFlags() & FVPHYSICS_CONSTRAINT_STATIC) )
  1732. {
  1733. pList[i]->ApplyForceOffset( force, offset );
  1734. return 1;
  1735. }
  1736. }
  1737. }
  1738. VPhysicsGetObject()->ApplyForceOffset( force, offset );
  1739. }
  1740. return 1;
  1741. }
  1742. // Character killed (only fired once)
  1743. void CBaseEntity::Event_Killed( const CTakeDamageInfo &info )
  1744. {
  1745. if( info.GetAttacker() )
  1746. {
  1747. info.GetAttacker()->Event_KilledOther(this, info);
  1748. }
  1749. m_takedamage = DAMAGE_NO;
  1750. m_lifeState = LIFE_DEAD;
  1751. UTIL_Remove( this );
  1752. }
  1753. //-----------------------------------------------------------------------------
  1754. // Purpose: helper method to send a game event when this entity is killed. Note:
  1755. // gets called specifically for particular entities (mostly NPC), this
  1756. // does not get called for every entity
  1757. //-----------------------------------------------------------------------------
  1758. void CBaseEntity::SendOnKilledGameEvent( const CTakeDamageInfo &info )
  1759. {
  1760. IGameEvent *event = gameeventmanager->CreateEvent( "entity_killed" );
  1761. if ( event )
  1762. {
  1763. event->SetInt( "entindex_killed", entindex() );
  1764. if ( info.GetAttacker())
  1765. {
  1766. event->SetInt( "entindex_attacker", info.GetAttacker()->entindex() );
  1767. }
  1768. if ( info.GetInflictor())
  1769. {
  1770. event->SetInt( "entindex_inflictor", info.GetInflictor()->entindex() );
  1771. }
  1772. event->SetInt( "damagebits", info.GetDamageType() );
  1773. gameeventmanager->FireEvent( event );
  1774. }
  1775. }
  1776. bool CBaseEntity::HasTarget( string_t targetname )
  1777. {
  1778. if( targetname != NULL_STRING && m_target != NULL_STRING )
  1779. return FStrEq(STRING(targetname), STRING(m_target) );
  1780. else
  1781. return false;
  1782. }
  1783. CBaseEntity *CBaseEntity::GetNextTarget( void )
  1784. {
  1785. if ( !m_target )
  1786. return NULL;
  1787. return gEntList.FindEntityByName( NULL, m_target );
  1788. }
  1789. class CThinkContextsSaveDataOps : public CDefSaveRestoreOps
  1790. {
  1791. virtual void Save( const SaveRestoreFieldInfo_t &fieldInfo, ISave *pSave )
  1792. {
  1793. AssertMsg( fieldInfo.pTypeDesc->fieldSize == 1, "CThinkContextsSaveDataOps does not support arrays");
  1794. // Write out the vector
  1795. CUtlVector< thinkfunc_t > *pUtlVector = (CUtlVector< thinkfunc_t > *)fieldInfo.pField;
  1796. SaveUtlVector( pSave, pUtlVector, FIELD_EMBEDDED );
  1797. // Get our owner
  1798. CBaseEntity *pOwner = (CBaseEntity*)fieldInfo.pOwner;
  1799. pSave->StartBlock();
  1800. // Now write out all the functions
  1801. for ( int i = 0; i < pUtlVector->Count(); i++ )
  1802. {
  1803. inputfunc_t *ppV = (inputfunc_t *)&((*pUtlVector)[i].m_pfnThink);
  1804. bool bHasFunc = (*ppV != NULL);
  1805. pSave->WriteBool( &bHasFunc, 1 );
  1806. if ( bHasFunc )
  1807. {
  1808. pSave->WriteFunction( pOwner->GetDataDescMap(), "m_pfnThink", ppV, 1 );
  1809. }
  1810. }
  1811. pSave->EndBlock();
  1812. }
  1813. virtual void Restore( const SaveRestoreFieldInfo_t &fieldInfo, IRestore *pRestore )
  1814. {
  1815. AssertMsg( fieldInfo.pTypeDesc->fieldSize == 1, "CThinkContextsSaveDataOps does not support arrays");
  1816. // Read in the vector
  1817. CUtlVector< thinkfunc_t > *pUtlVector = (CUtlVector< thinkfunc_t > *)fieldInfo.pField;
  1818. RestoreUtlVector( pRestore, pUtlVector, FIELD_EMBEDDED );
  1819. // Get our owner
  1820. CBaseEntity *pOwner = (CBaseEntity*)fieldInfo.pOwner;
  1821. pRestore->StartBlock();
  1822. // Now read in all the functions
  1823. for ( int i = 0; i < pUtlVector->Count(); i++ )
  1824. {
  1825. bool bHasFunc;
  1826. pRestore->ReadBool( &bHasFunc, 1 );
  1827. inputfunc_t *ppV = (inputfunc_t *)&((*pUtlVector)[i].m_pfnThink);
  1828. if ( bHasFunc )
  1829. {
  1830. SaveRestoreRecordHeader_t header;
  1831. pRestore->ReadHeader( &header );
  1832. pRestore->ReadFunction( pOwner->GetDataDescMap(), ppV, 1, header.size );
  1833. }
  1834. else
  1835. {
  1836. *ppV = NULL;
  1837. }
  1838. }
  1839. pRestore->EndBlock();
  1840. }
  1841. virtual bool IsEmpty( const SaveRestoreFieldInfo_t &fieldInfo )
  1842. {
  1843. CUtlVector< thinkfunc_t > *pUtlVector = (CUtlVector< thinkfunc_t > *)fieldInfo.pField;
  1844. return ( pUtlVector->Count() == 0 );
  1845. }
  1846. virtual void MakeEmpty( const SaveRestoreFieldInfo_t &fieldInfo )
  1847. {
  1848. BASEPTR pFunc = *((BASEPTR*)fieldInfo.pField);
  1849. pFunc = NULL;
  1850. }
  1851. };
  1852. CThinkContextsSaveDataOps g_ThinkContextsSaveDataOps;
  1853. ISaveRestoreOps *thinkcontextFuncs = &g_ThinkContextsSaveDataOps;
  1854. BEGIN_SIMPLE_DATADESC( thinkfunc_t )
  1855. DEFINE_FIELD( m_iszContext, FIELD_STRING ),
  1856. // DEFINE_FIELD( m_pfnThink, FIELD_FUNCTION ), // Manually written
  1857. DEFINE_FIELD( m_nNextThinkTick, FIELD_TICK ),
  1858. DEFINE_FIELD( m_nLastThinkTick, FIELD_TICK ),
  1859. END_DATADESC()
  1860. BEGIN_SIMPLE_DATADESC( ResponseContext_t )
  1861. DEFINE_FIELD( m_iszName, FIELD_STRING ),
  1862. DEFINE_FIELD( m_iszValue, FIELD_STRING ),
  1863. DEFINE_FIELD( m_fExpirationTime, FIELD_TIME ),
  1864. END_DATADESC()
  1865. BEGIN_DATADESC_NO_BASE( CBaseEntity )
  1866. DEFINE_KEYFIELD( m_iClassname, FIELD_STRING, "classname" ),
  1867. DEFINE_GLOBAL_KEYFIELD( m_iGlobalname, FIELD_STRING, "globalname" ),
  1868. DEFINE_KEYFIELD( m_iParent, FIELD_STRING, "parentname" ),
  1869. DEFINE_KEYFIELD( m_nMinCPULevel, FIELD_CHARACTER, "mincpulevel" ),
  1870. DEFINE_KEYFIELD( m_nMaxCPULevel, FIELD_CHARACTER, "maxcpulevel" ),
  1871. DEFINE_KEYFIELD( m_nMinGPULevel, FIELD_CHARACTER, "mingpulevel" ),
  1872. DEFINE_KEYFIELD( m_nMaxGPULevel, FIELD_CHARACTER, "maxgpulevel" ),
  1873. DEFINE_KEYFIELD( m_iHammerID, FIELD_INTEGER, "hammerid" ), // save ID numbers so that entities can be tracked between save/restore and vmf
  1874. DEFINE_KEYFIELD( m_flSpeed, FIELD_FLOAT, "speed" ),
  1875. DEFINE_KEYFIELD( m_nRenderFX, FIELD_CHARACTER, "renderfx" ),
  1876. DEFINE_KEYFIELD( m_nRenderMode, FIELD_CHARACTER, "rendermode" ),
  1877. // Consider moving to CBaseAnimating?
  1878. DEFINE_FIELD( m_flPrevAnimTime, FIELD_TIME ),
  1879. DEFINE_FIELD( m_flAnimTime, FIELD_TIME ),
  1880. DEFINE_FIELD( m_flSimulationTime, FIELD_TIME ),
  1881. #if defined(ENABLE_CREATE_TIME)
  1882. DEFINE_FIELD( m_flCreateTime, FIELD_TIME ),
  1883. #endif
  1884. DEFINE_FIELD( m_nLastThinkTick, FIELD_TICK ),
  1885. DEFINE_FIELD( m_iszScriptId, FIELD_STRING ),
  1886. // m_ScriptScope;
  1887. // m_hScriptInstance;
  1888. DEFINE_KEYFIELD( m_iszVScripts, FIELD_STRING, "vscripts" ),
  1889. DEFINE_KEYFIELD( m_iszScriptThinkFunction, FIELD_STRING, "thinkfunction" ),
  1890. DEFINE_KEYFIELD( m_nNextThinkTick, FIELD_TICK, "nextthink" ),
  1891. DEFINE_KEYFIELD( m_fEffects, FIELD_INTEGER, "effects" ),
  1892. DEFINE_KEYFIELD( m_clrRender, FIELD_COLOR32, "rendercolor" ),
  1893. DEFINE_GLOBAL_KEYFIELD( m_nModelIndex, FIELD_SHORT, "modelindex" ),
  1894. #if !defined( NO_ENTITY_PREDICTION ) && defined( USE_PREDICTABLEID )
  1895. // DEFINE_FIELD( m_PredictableID, CPredictableId ),
  1896. #endif
  1897. DEFINE_FIELD( touchStamp, FIELD_INTEGER ),
  1898. DEFINE_CUSTOM_FIELD( m_aThinkFunctions, thinkcontextFuncs ),
  1899. // m_iCurrentThinkContext (not saved, debug field only, and think transient to boot)
  1900. DEFINE_UTLVECTOR(m_ResponseContexts, FIELD_EMBEDDED),
  1901. DEFINE_KEYFIELD( m_iszResponseContext, FIELD_STRING, "ResponseContext" ),
  1902. DEFINE_FIELD( m_pfnThink, FIELD_FUNCTION ),
  1903. DEFINE_FIELD( m_pfnTouch, FIELD_FUNCTION ),
  1904. DEFINE_FIELD( m_pfnUse, FIELD_FUNCTION ),
  1905. DEFINE_FIELD( m_pfnBlocked, FIELD_FUNCTION ),
  1906. DEFINE_FIELD( m_pfnMoveDone, FIELD_FUNCTION ),
  1907. DEFINE_FIELD( m_lifeState, FIELD_CHARACTER ),
  1908. DEFINE_FIELD( m_takedamage, FIELD_CHARACTER ),
  1909. DEFINE_KEYFIELD( m_iMaxHealth, FIELD_INTEGER, "max_health" ),
  1910. DEFINE_KEYFIELD( m_iHealth, FIELD_INTEGER, "health" ),
  1911. // DEFINE_FIELD( m_pLink, FIELD_CLASSPTR ),
  1912. DEFINE_KEYFIELD( m_bIsAutoaimTarget, FIELD_BOOLEAN, "is_autoaim_target" ),
  1913. DEFINE_KEYFIELD( m_target, FIELD_STRING, "target" ),
  1914. DEFINE_KEYFIELD( m_iszDamageFilterName, FIELD_STRING, "damagefilter" ),
  1915. DEFINE_FIELD( m_hDamageFilter, FIELD_EHANDLE ),
  1916. DEFINE_FIELD( m_debugOverlays, FIELD_INTEGER ),
  1917. DEFINE_GLOBAL_FIELD( m_pParent, FIELD_EHANDLE ),
  1918. DEFINE_FIELD( m_iParentAttachment, FIELD_CHARACTER ),
  1919. DEFINE_GLOBAL_FIELD( m_hMoveParent, FIELD_EHANDLE ),
  1920. DEFINE_GLOBAL_FIELD( m_hMoveChild, FIELD_EHANDLE ),
  1921. DEFINE_GLOBAL_FIELD( m_hMovePeer, FIELD_EHANDLE ),
  1922. DEFINE_FIELD( m_iEFlags, FIELD_INTEGER ),
  1923. DEFINE_FIELD( m_iName, FIELD_STRING ),
  1924. #ifdef PORTAL2
  1925. DEFINE_FIELD( m_iSignifierName, FIELD_STRING ),
  1926. #endif // PORTAL2
  1927. DEFINE_EMBEDDED( m_Collision ),
  1928. DEFINE_EMBEDDED( m_Network ),
  1929. DEFINE_KEYFIELD( m_MoveType, FIELD_CHARACTER, "MoveType" ),
  1930. DEFINE_FIELD( m_MoveCollide, FIELD_CHARACTER ),
  1931. DEFINE_FIELD( m_hOwnerEntity, FIELD_EHANDLE ),
  1932. DEFINE_KEYFIELD( m_CollisionGroup, FIELD_INTEGER, "CollisionGroup" ),
  1933. DEFINE_PHYSPTR( m_pPhysicsObject),
  1934. DEFINE_FIELD( m_flElasticity, FIELD_FLOAT ),
  1935. DEFINE_KEYFIELD( m_flShadowCastDistance, FIELD_FLOAT, "shadowcastdist" ),
  1936. DEFINE_FIELD( m_flDesiredShadowCastDistance, FIELD_FLOAT ),
  1937. DEFINE_INPUT( m_iInitialTeamNum, FIELD_INTEGER, "TeamNum" ),
  1938. DEFINE_KEYFIELD( m_iTeamNum, FIELD_INTEGER, "teamnumber" ),
  1939. DEFINE_KEYFIELD( m_iPendingTeamNum, FIELD_INTEGER, "pendingteamnumber" ),
  1940. // DEFINE_FIELD( m_bSentLastFrame, FIELD_INTEGER ),
  1941. #if defined ( PORTAL2 )
  1942. DEFINE_FIELD( m_iObjectCapsCache, FIELD_INTEGER ),
  1943. #endif
  1944. DEFINE_FIELD( m_hGroundEntity, FIELD_EHANDLE ),
  1945. DEFINE_FIELD( m_flGroundChangeTime, FIELD_TIME ),
  1946. DEFINE_GLOBAL_KEYFIELD( m_ModelName, FIELD_MODELNAME, "model" ),
  1947. DEFINE_KEYFIELD( m_AIAddOn, FIELD_STRING, "addon" ),
  1948. DEFINE_KEYFIELD( m_vecBaseVelocity, FIELD_VECTOR, "basevelocity" ),
  1949. DEFINE_FIELD( m_vecAbsVelocity, FIELD_VECTOR ),
  1950. DEFINE_KEYFIELD( m_vecAngVelocity, FIELD_VECTOR, "avelocity" ),
  1951. // DEFINE_FIELD( m_vecAbsAngVelocity, FIELD_VECTOR ),
  1952. DEFINE_ARRAY( m_rgflCoordinateFrame, FIELD_FLOAT, 12 ), // NOTE: MUST BE IN LOCAL SPACE, NOT POSITION_VECTOR!!! (see CBaseEntity::Restore)
  1953. DEFINE_KEYFIELD( m_nWaterLevel, FIELD_CHARACTER, "waterlevel" ),
  1954. DEFINE_FIELD( m_nWaterType, FIELD_CHARACTER ),
  1955. DEFINE_FIELD( m_pBlocker, FIELD_EHANDLE ),
  1956. DEFINE_KEYFIELD( m_flGravity, FIELD_FLOAT, "gravity" ),
  1957. DEFINE_KEYFIELD( m_flFriction, FIELD_FLOAT, "friction" ),
  1958. // Local time is local to each object. It doesn't need to be re-based if the clock
  1959. // changes. Therefore it is saved as a FIELD_FLOAT, not a FIELD_TIME
  1960. DEFINE_KEYFIELD( m_flLocalTime, FIELD_FLOAT, "ltime" ),
  1961. DEFINE_FIELD( m_flVPhysicsUpdateLocalTime, FIELD_FLOAT ),
  1962. DEFINE_FIELD( m_flMoveDoneTime, FIELD_FLOAT ),
  1963. // DEFINE_FIELD( m_nPushEnumCount, FIELD_INTEGER ),
  1964. DEFINE_FIELD( m_vecAbsOrigin, FIELD_POSITION_VECTOR ),
  1965. DEFINE_KEYFIELD( m_vecVelocity, FIELD_VECTOR, "velocity" ),
  1966. DEFINE_KEYFIELD( m_iTextureFrameIndex, FIELD_CHARACTER, "texframeindex" ),
  1967. DEFINE_FIELD( m_bSimulatedEveryTick, FIELD_BOOLEAN ),
  1968. DEFINE_FIELD( m_bAnimatedEveryTick, FIELD_BOOLEAN ),
  1969. DEFINE_FIELD( m_bAlternateSorting, FIELD_BOOLEAN ),
  1970. //DEFINE_FIELD( m_bSpotted, FIELD_BOOLEAN ),
  1971. DEFINE_KEYFIELD( m_spawnflags, FIELD_INTEGER, "spawnflags" ),
  1972. DEFINE_FIELD( m_nTransmitStateOwnedCounter, FIELD_CHARACTER ),
  1973. DEFINE_FIELD( m_angAbsRotation, FIELD_VECTOR ),
  1974. DEFINE_FIELD( m_vecOrigin, FIELD_VECTOR ), // NOTE: MUST BE IN LOCAL SPACE, NOT POSITION_VECTOR!!! (see CBaseEntity::Restore)
  1975. DEFINE_FIELD( m_angRotation, FIELD_VECTOR ),
  1976. DEFINE_FIELD( m_bClientSideRagdoll, FIELD_BOOLEAN ),
  1977. DEFINE_KEYFIELD( m_vecViewOffset, FIELD_VECTOR, "view_ofs" ),
  1978. DEFINE_FIELD( m_fFlags, FIELD_INTEGER ),
  1979. #if !defined( NO_ENTITY_PREDICTION )
  1980. // DEFINE_FIELD( m_bIsPlayerSimulated, FIELD_INTEGER ),
  1981. // DEFINE_FIELD( m_hPlayerSimulationOwner, FIELD_EHANDLE ),
  1982. #endif
  1983. // DEFINE_FIELD( m_pTimedOverlay, TimedOverlay_t* ),
  1984. DEFINE_FIELD( m_nSimulationTick, FIELD_TICK ),
  1985. // DEFINE_FIELD( m_RefEHandle, CBaseHandle ),
  1986. // DEFINE_FIELD( m_nWaterTouch, FIELD_INTEGER ),
  1987. // DEFINE_FIELD( m_nSlimeTouch, FIELD_INTEGER ),
  1988. DEFINE_FIELD( m_flNavIgnoreUntilTime, FIELD_TIME ),
  1989. // DEFINE_FIELD( m_bToolRecording, FIELD_BOOLEAN ),
  1990. // DEFINE_FIELD( m_ToolHandle, FIELD_INTEGER ),
  1991. // NOTE: This is tricky. TeamNum must be saved, but we can't directly
  1992. // read it in, because we can only set it after the team entity has been read in,
  1993. // which may or may not actually occur before the entity is parsed.
  1994. // Therefore, we set the TeamNum from the InitialTeamNum in Activate
  1995. DEFINE_INPUTFUNC( FIELD_INTEGER, "SetTeam", InputSetTeam ),
  1996. DEFINE_INPUT( m_fadeMinDist, FIELD_FLOAT, "fademindist" ),
  1997. DEFINE_INPUT( m_fadeMaxDist, FIELD_FLOAT, "fademaxdist" ),
  1998. DEFINE_KEYFIELD( m_flFadeScale, FIELD_FLOAT, "fadescale" ),
  1999. DEFINE_INPUTFUNC( FIELD_VOID, "Kill", InputKill ),
  2000. DEFINE_INPUTFUNC( FIELD_VOID, "KillHierarchy", InputKillHierarchy ),
  2001. DEFINE_INPUTFUNC( FIELD_VOID, "Use", InputUse ),
  2002. DEFINE_INPUTFUNC( FIELD_INTEGER, "Alpha", InputAlpha ),
  2003. DEFINE_INPUTFUNC( FIELD_BOOLEAN, "AlternativeSorting", InputAlternativeSorting ),
  2004. DEFINE_INPUTFUNC( FIELD_COLOR32, "Color", InputColor ),
  2005. DEFINE_INPUTFUNC( FIELD_STRING, "SetParent", InputSetParent ),
  2006. DEFINE_INPUTFUNC( FIELD_STRING, "SetParentAttachment", InputSetParentAttachment ),
  2007. DEFINE_INPUTFUNC( FIELD_STRING, "SetParentAttachmentMaintainOffset", InputSetParentAttachmentMaintainOffset ),
  2008. DEFINE_INPUTFUNC( FIELD_VOID, "ClearParent", InputClearParent ),
  2009. DEFINE_INPUTFUNC( FIELD_STRING, "SetLocalOrigin", InputSetLocalOrigin ),
  2010. DEFINE_INPUTFUNC( FIELD_STRING, "SetLocalAngles", InputSetLocalAngles ),
  2011. DEFINE_INPUTFUNC( FIELD_STRING, "SetDamageFilter", InputSetDamageFilter ),
  2012. DEFINE_INPUTFUNC( FIELD_VOID, "EnableDamageForces", InputEnableDamageForces ),
  2013. DEFINE_INPUTFUNC( FIELD_VOID, "DisableDamageForces", InputDisableDamageForces ),
  2014. DEFINE_INPUTFUNC( FIELD_STRING, "DispatchResponse", InputDispatchResponse ),
  2015. // Entity I/O methods to alter context
  2016. DEFINE_INPUTFUNC( FIELD_STRING, "AddContext", InputAddContext ),
  2017. DEFINE_INPUTFUNC( FIELD_STRING, "RemoveContext", InputRemoveContext ),
  2018. DEFINE_INPUTFUNC( FIELD_STRING, "ClearContext", InputClearContext ),
  2019. DEFINE_INPUTFUNC( FIELD_VOID, "DisableShadow", InputDisableShadow ),
  2020. DEFINE_INPUTFUNC( FIELD_VOID, "EnableShadow", InputEnableShadow ),
  2021. DEFINE_INPUTFUNC( FIELD_VOID, "DisableDraw", InputDisableDraw ),
  2022. DEFINE_INPUTFUNC( FIELD_VOID, "EnableDraw", InputEnableDraw ),
  2023. DEFINE_INPUTFUNC( FIELD_VOID, "DisableReceivingFlashlight", InputDisableReceivingFlashlight ),
  2024. DEFINE_INPUTFUNC( FIELD_VOID, "EnableReceivingFlashlight", InputEnableReceivingFlashlight ),
  2025. DEFINE_INPUTFUNC( FIELD_VOID, "DisableDrawInFastReflection", InputDisableDrawInFastReflection ),
  2026. DEFINE_INPUTFUNC( FIELD_VOID, "EnableDrawInFastReflection", InputEnableDrawInFastReflection ),
  2027. DEFINE_INPUTFUNC( FIELD_STRING, "AddOutput", InputAddOutput ),
  2028. DEFINE_INPUTFUNC( FIELD_STRING, "FireUser1", InputFireUser1 ),
  2029. DEFINE_INPUTFUNC( FIELD_STRING, "FireUser2", InputFireUser2 ),
  2030. DEFINE_INPUTFUNC( FIELD_STRING, "FireUser3", InputFireUser3 ),
  2031. DEFINE_INPUTFUNC( FIELD_STRING, "FireUser4", InputFireUser4 ),
  2032. DEFINE_INPUTFUNC( FIELD_STRING, "RunScriptFile", InputRunScriptFile ),
  2033. DEFINE_INPUTFUNC( FIELD_STRING, "RunScriptCode", InputRunScript ),
  2034. DEFINE_INPUTFUNC( FIELD_STRING, "CallScriptFunction", InputCallScriptFunction ),
  2035. #ifdef PORTAL2
  2036. DEFINE_INPUTFUNC( FIELD_VOID, "RemovePaint", InputRemovePaint ),
  2037. #endif
  2038. DEFINE_OUTPUT( m_OnUser1, "OnUser1" ),
  2039. DEFINE_OUTPUT( m_OnUser2, "OnUser2" ),
  2040. DEFINE_OUTPUT( m_OnUser3, "OnUser3" ),
  2041. DEFINE_OUTPUT( m_OnUser4, "OnUser4" ),
  2042. // Function Pointers
  2043. DEFINE_FUNCTION( SUB_Remove ),
  2044. DEFINE_FUNCTION( SUB_DoNothing ),
  2045. DEFINE_FUNCTION( SUB_StartFadeOut ),
  2046. DEFINE_FUNCTION( SUB_StartFadeOutInstant ),
  2047. DEFINE_FUNCTION( SUB_FadeOut ),
  2048. DEFINE_FUNCTION( SUB_Vanish ),
  2049. DEFINE_FUNCTION( SUB_CallUseToggle ),
  2050. DEFINE_THINKFUNC( ShadowCastDistThink ),
  2051. #if defined(ENABLE_FRICTION_OVERRIDE)
  2052. DEFINE_THINKFUNC( FrictionRevertThink ),
  2053. #endif
  2054. DEFINE_THINKFUNC( ScriptThink ),
  2055. DEFINE_FIELD( m_hEffectEntity, FIELD_EHANDLE ),
  2056. //DEFINE_FIELD( m_DamageModifiers, FIELD_?? ), // can't save?
  2057. // DEFINE_FIELD( m_fDataObjectTypes, FIELD_INTEGER ),
  2058. DEFINE_KEYFIELD( m_bLagCompensate, FIELD_BOOLEAN, "LagCompensate" ),
  2059. DEFINE_FIELD( m_bForcePurgeFixedupStrings, FIELD_BOOLEAN ),
  2060. DEFINE_FIELD( m_flUseLookAtAngle, FIELD_FLOAT ),
  2061. END_DATADESC()
  2062. DEFINE_SCRIPT_INSTANCE_HELPER( CBaseEntity, &g_BaseEntityScriptInstanceHelper )
  2063. BEGIN_ENT_SCRIPTDESC_ROOT( CBaseEntity, "Root class of all server-side entities" )
  2064. DEFINE_SCRIPTFUNC_NAMED( ConnectOutputToScript, "ConnectOutput", "Adds an I/O connection that will call the named function when the specified output fires" )
  2065. DEFINE_SCRIPTFUNC_NAMED( DisconnectOutputFromScript, "DisconnectOutput", "Removes a connected script function from an I/O event." )
  2066. DEFINE_SCRIPTFUNC( GetHealth, "" )
  2067. DEFINE_SCRIPTFUNC( SetHealth, "" )
  2068. DEFINE_SCRIPTFUNC( GetMaxHealth, "" )
  2069. DEFINE_SCRIPTFUNC( SetMaxHealth, "" )
  2070. DEFINE_SCRIPTFUNC( SetModel, "" )
  2071. DEFINE_SCRIPTFUNC_NAMED( ScriptGetModelName, "GetModelName", "Returns the name of the model" )
  2072. DEFINE_SCRIPTFUNC_NAMED( ScriptEmitSound, "EmitSound", "Plays a sound from this entity." )
  2073. DEFINE_SCRIPTFUNC_NAMED( ScriptStopSound, "StopSound", "Stops a sound on this entity." )
  2074. DEFINE_SCRIPTFUNC_NAMED( VScriptPrecacheScriptSound, "PrecacheSoundScript", "Precache a sound for later playing." )
  2075. DEFINE_SCRIPTFUNC_NAMED( ScriptSoundDuration, "GetSoundDuration", "Returns float duration of the sound. Takes soundname and optional actormodelname.")
  2076. DEFINE_SCRIPTFUNC( GetClassname, "" )
  2077. DEFINE_SCRIPTFUNC_NAMED( GetEntityNameAsCStr, "GetName", "" )
  2078. DEFINE_SCRIPTFUNC( GetPreTemplateName, "Get the entity name stripped of template unique decoration" )
  2079. DEFINE_SCRIPTFUNC_NAMED( GetAbsOrigin, "GetOrigin", "" )
  2080. DEFINE_SCRIPTFUNC( SetAbsOrigin, "SetAbsOrigin" )
  2081. DEFINE_SCRIPTFUNC_NAMED( ScriptSetOrigin, "SetOrigin", "" )
  2082. DEFINE_SCRIPTFUNC_NAMED( ScriptGetForward, "GetForwardVector", "Get the forward vector of the entity" )
  2083. DEFINE_SCRIPTFUNC_NAMED( ScriptGetLeft, "GetLeftVector", "Get the left vector of the entity" )
  2084. DEFINE_SCRIPTFUNC_NAMED( ScriptGetUp, "GetUpVector", "Get the up vector of the entity" )
  2085. DEFINE_SCRIPTFUNC_NAMED( ScriptSetForward, "SetForwardVector", "Set the orientation of the entity to have this forward vector" )
  2086. DEFINE_SCRIPTFUNC_NAMED( GetAbsVelocity, "GetVelocity", "" )
  2087. DEFINE_SCRIPTFUNC_NAMED( SetAbsVelocity, "SetVelocity", "" )
  2088. DEFINE_SCRIPTFUNC_NAMED( ScriptSetLocalAngularVelocity, "SetAngularVelocity", "Set the local angular velocity - takes float pitch,yaw,roll velocities" )
  2089. DEFINE_SCRIPTFUNC_NAMED( ScriptGetLocalAngularVelocity, "GetAngularVelocity", "Get the local angular velocity - returns a vector of pitch,yaw,roll" )
  2090. DEFINE_SCRIPTFUNC_NAMED( WorldSpaceCenter, "GetCenter", "Get vector to center of object - absolute coords")
  2091. DEFINE_SCRIPTFUNC_NAMED( ScriptEyePosition, "EyePosition", "Get vector to eye position - absolute coords")
  2092. DEFINE_SCRIPTFUNC_NAMED( ScriptSetAngles, "SetAngles", "Set entity pitch, yaw, roll")
  2093. DEFINE_SCRIPTFUNC_NAMED( ScriptGetAngles, "GetAngles", "Get entity pitch, yaw, roll as a vector")
  2094. DEFINE_SCRIPTFUNC_NAMED( ScriptSetSize, "SetSize", "" )
  2095. DEFINE_SCRIPTFUNC_NAMED( ScriptGetBoundingMins, "GetBoundingMins", "Get a vector containing min bounds, centered on object")
  2096. DEFINE_SCRIPTFUNC_NAMED( ScriptGetBoundingMaxs, "GetBoundingMaxs", "Get a vector containing max bounds, centered on object")
  2097. DEFINE_SCRIPTFUNC_NAMED( ScriptUtilRemove, "Destroy", "" )
  2098. DEFINE_SCRIPTFUNC_NAMED( ScriptSetOwner, "SetOwner", "" )
  2099. DEFINE_SCRIPTFUNC_NAMED( GetTeamNumber, "GetTeam", "" )
  2100. DEFINE_SCRIPTFUNC_NAMED( ChangeTeam, "SetTeam", "" )
  2101. DEFINE_SCRIPTFUNC_NAMED( ScriptGetMoveParent, "GetMoveParent", "If in hierarchy, retrieves the entity's parent" )
  2102. DEFINE_SCRIPTFUNC_NAMED( ScriptGetRootMoveParent, "GetRootMoveParent", "If in hierarchy, walks up the hierarchy to find the root parent" )
  2103. DEFINE_SCRIPTFUNC_NAMED( ScriptFirstMoveChild, "FirstMoveChild", "" )
  2104. DEFINE_SCRIPTFUNC_NAMED( ScriptNextMovePeer, "NextMovePeer", "" )
  2105. DEFINE_SCRIPTFUNC_NAMED( KeyValueFromString, "__KeyValueFromString", SCRIPT_HIDE )
  2106. DEFINE_SCRIPTFUNC_NAMED( KeyValueFromFloat, "__KeyValueFromFloat", SCRIPT_HIDE )
  2107. DEFINE_SCRIPTFUNC_NAMED( KeyValueFromInt, "__KeyValueFromInt", SCRIPT_HIDE )
  2108. DEFINE_SCRIPTFUNC_NAMED( KeyValueFromVector, "__KeyValueFromVector", SCRIPT_HIDE )
  2109. DEFINE_SCRIPTFUNC_NAMED( ScriptGetModelKeyValues, "GetModelKeyValues", "Get a KeyValue class instance on this entity's model")
  2110. DEFINE_SCRIPTFUNC_NAMED( ScriptPrecacheModel, "PrecacheModel", "" )
  2111. DEFINE_SCRIPTFUNC_NAMED( ScriptPrecacheScriptSound, "PrecacheScriptSound", "" )
  2112. DEFINE_SCRIPTFUNC( ValidateScriptScope, "Ensure that an entity's script scope has been created" )
  2113. DEFINE_SCRIPTFUNC( GetScriptScope, "Retrieve the script-side data associated with an entity" )
  2114. DEFINE_SCRIPTFUNC( GetScriptId, "Retrieve the unique identifier used to refer to the entity within the scripting system" )
  2115. DEFINE_SCRIPTFUNC_NAMED( GetScriptOwnerEntity, "GetOwner", "Gets this entity's owner" )
  2116. DEFINE_SCRIPTFUNC_NAMED( SetScriptOwnerEntity, "SetOwner", "Sets this entity's owner" )
  2117. DEFINE_SCRIPTFUNC( entindex, "" )
  2118. END_SCRIPTDESC();
  2119. // For code error checking
  2120. extern bool g_bReceivedChainedUpdateOnRemove;
  2121. //-----------------------------------------------------------------------------
  2122. // Purpose: Called just prior to object destruction
  2123. // Entities that need to unlink themselves from other entities should do the unlinking
  2124. // here rather than in their destructor. The reason why is that when the global entity list
  2125. // is told to Clear(), it first takes a pass through all active entities and calls UTIL_Remove
  2126. // on each such entity. Then it calls the delete function on each deleted entity in the list.
  2127. // In the old code, the objects were simply destroyed in order and there was no guarantee that the
  2128. // destructor of one object would not try to access another object that might already have been
  2129. // destructed (especially since the entity list order is more or less random!).
  2130. // NOTE: You should never call delete directly on an entity (there's an assert now), see note
  2131. // at CBaseEntity::~CBaseEntity for more information.
  2132. //
  2133. // NOTE: You should chain to BaseClass::UpdateOnRemove after doing your own cleanup code, e.g.:
  2134. //
  2135. // void CDerived::UpdateOnRemove( void )
  2136. // {
  2137. // ... cleanup code
  2138. // ...
  2139. //
  2140. // BaseClass::UpdateOnRemove();
  2141. // }
  2142. //
  2143. // In general, this function updates global tables that need to know about entities being removed
  2144. //-----------------------------------------------------------------------------
  2145. void CBaseEntity::UpdateOnRemove( void )
  2146. {
  2147. g_bReceivedChainedUpdateOnRemove = true;
  2148. // Virtual call to shut down any looping sounds.
  2149. StopLoopingSounds();
  2150. // Remove from lag compensation 'extra' list
  2151. if ( ShouldLagCompensate() )
  2152. {
  2153. lagcompensation->RemoveAdditionalEntity( this );
  2154. }
  2155. // Notifies entity listeners, etc
  2156. gEntList.NotifyRemoveEntity( this );
  2157. if ( edict() )
  2158. {
  2159. AddFlag( FL_KILLME );
  2160. /* <<TODO>>
  2161. if ( GetFlags() & FL_GRAPHED )
  2162. {
  2163. // this entity was a LinkEnt in the world node graph, so we must remove it from
  2164. // the graph since we are removing it from the world.
  2165. for ( int i = 0 ; i < WorldGraph.m_cLinks ; i++ )
  2166. {
  2167. if ( WorldGraph.m_pLinkPool [ i ].m_pLinkEnt == pev )
  2168. {
  2169. // if this link has a link ent which is the same ent that is removing itself, remove it!
  2170. WorldGraph.m_pLinkPool [ i ].m_pLinkEnt = NULL;
  2171. }
  2172. }
  2173. }
  2174. */
  2175. }
  2176. if ( m_iGlobalname != NULL_STRING )
  2177. {
  2178. // NOTE: During level shutdown the global list will suppress this
  2179. // it assumes your changing levels or the game will end
  2180. // causing the whole list to be flushed
  2181. GlobalEntity_SetState( m_iGlobalname, GLOBAL_DEAD );
  2182. }
  2183. // Remove the fixed up name from this entity
  2184. // we need to do this now since we will set the name to nothing later
  2185. if( m_bForcePurgeFixedupStrings )
  2186. {
  2187. if( m_iName.Get() != NULL_STRING )
  2188. {
  2189. RemovePooledString( STRING( m_iName.Get() ) );
  2190. }
  2191. if( m_iszScriptId != NULL_STRING )
  2192. {
  2193. RemovePooledString( STRING( m_iszScriptId ) );
  2194. }
  2195. }
  2196. VPhysicsDestroyObject();
  2197. // This is only here to allow the MOVETYPE_NONE to be set without the
  2198. // assertion triggering. Why do we bother setting the MOVETYPE to none here?
  2199. RemoveEffects( EF_BONEMERGE );
  2200. SetMoveType(MOVETYPE_NONE);
  2201. // If we have a parent, unlink from it.
  2202. UnlinkFromParent( this );
  2203. // Any children still connected are orphans, mark all for delete
  2204. CUtlVector<CBaseEntity *> childrenList;
  2205. GetAllChildren( this, childrenList );
  2206. if ( childrenList.Count() )
  2207. {
  2208. DevMsg( 2, "Warning: Deleting orphaned children of %s\n", GetClassname() );
  2209. for ( int i = childrenList.Count()-1; i >= 0; --i )
  2210. {
  2211. UTIL_Remove( childrenList[i] );
  2212. }
  2213. }
  2214. SetGroundEntity( NULL );
  2215. if ( m_hScriptInstance )
  2216. {
  2217. g_pScriptVM->RemoveInstance( m_hScriptInstance );
  2218. m_hScriptInstance = NULL;
  2219. }
  2220. }
  2221. //-----------------------------------------------------------------------------
  2222. // capabilities
  2223. //-----------------------------------------------------------------------------
  2224. int CBaseEntity::ObjectCaps( void )
  2225. {
  2226. #if 1
  2227. model_t *pModel = GetModel();
  2228. bool bIsBrush = ( pModel && modelinfo->GetModelType( pModel ) == mod_brush );
  2229. // We inherit our parent's use capabilities so that we can forward use commands
  2230. // to our parent.
  2231. CBaseEntity *pParent = GetParent();
  2232. if ( pParent )
  2233. {
  2234. int caps = pParent->ObjectCaps();
  2235. if ( !bIsBrush )
  2236. caps &= ( FCAP_ACROSS_TRANSITION | FCAP_IMPULSE_USE | FCAP_CONTINUOUS_USE | FCAP_ONOFF_USE | FCAP_DIRECTIONAL_USE );
  2237. else
  2238. caps &= ( FCAP_IMPULSE_USE | FCAP_CONTINUOUS_USE | FCAP_ONOFF_USE | FCAP_DIRECTIONAL_USE );
  2239. if ( pParent->IsPlayer() )
  2240. caps |= FCAP_ACROSS_TRANSITION;
  2241. return caps;
  2242. }
  2243. else if ( !bIsBrush )
  2244. {
  2245. return FCAP_ACROSS_TRANSITION;
  2246. }
  2247. return 0;
  2248. #else
  2249. // We inherit our parent's use capabilities so that we can forward use commands
  2250. // to our parent.
  2251. int parentCaps = 0;
  2252. if (GetParent())
  2253. {
  2254. parentCaps = GetParent()->ObjectCaps();
  2255. parentCaps &= ( FCAP_IMPULSE_USE | FCAP_CONTINUOUS_USE | FCAP_ONOFF_USE | FCAP_DIRECTIONAL_USE );
  2256. }
  2257. model_t *pModel = GetModel();
  2258. if ( pModel && modelinfo->GetModelType( pModel ) == mod_brush )
  2259. return parentCaps;
  2260. return FCAP_ACROSS_TRANSITION | parentCaps;
  2261. #endif
  2262. }
  2263. #if defined ( PORTAL2 )
  2264. void CBaseEntity::UpdateObjectCapsCache( void )
  2265. {
  2266. // Send the first six bits of the object caps to the client
  2267. // those should be the +use logic capabilities
  2268. m_iObjectCapsCache = 0x0000003f & ObjectCaps();
  2269. }
  2270. #endif
  2271. void CBaseEntity::StartTouch( CBaseEntity *pOther )
  2272. {
  2273. // notify parent
  2274. if ( m_pParent != NULL )
  2275. m_pParent->StartTouch( pOther );
  2276. }
  2277. void CBaseEntity::Touch( CBaseEntity *pOther )
  2278. {
  2279. if ( m_pfnTouch )
  2280. (this->*m_pfnTouch)( pOther );
  2281. // notify parent of touch
  2282. if ( m_pParent != NULL )
  2283. m_pParent->Touch( pOther );
  2284. }
  2285. void CBaseEntity::EndTouch( CBaseEntity *pOther )
  2286. {
  2287. // notify parent
  2288. if ( m_pParent != NULL )
  2289. {
  2290. m_pParent->EndTouch( pOther );
  2291. }
  2292. }
  2293. //-----------------------------------------------------------------------------
  2294. // Purpose: Dispatches blocked events to this entity's blocked handler, set via SetBlocked.
  2295. // Input : pOther - The entity that is blocking us.
  2296. //-----------------------------------------------------------------------------
  2297. void CBaseEntity::Blocked( CBaseEntity *pOther )
  2298. {
  2299. if ( m_pfnBlocked )
  2300. {
  2301. (this->*m_pfnBlocked)( pOther );
  2302. }
  2303. //
  2304. // Forward the blocked event to our parent, if any.
  2305. //
  2306. if ( m_pParent != NULL )
  2307. {
  2308. m_pParent->Blocked( pOther );
  2309. }
  2310. }
  2311. //-----------------------------------------------------------------------------
  2312. // Purpose: Dispatches use events to this entity's use handler, set via SetUse.
  2313. // Input : pActivator -
  2314. // pCaller -
  2315. // useType -
  2316. // value -
  2317. //-----------------------------------------------------------------------------
  2318. void CBaseEntity::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
  2319. {
  2320. if ( m_pfnUse != NULL )
  2321. {
  2322. (this->*m_pfnUse)( pActivator, pCaller, useType, value );
  2323. }
  2324. else
  2325. {
  2326. //
  2327. // We don't handle use events. Forward to our parent, if any.
  2328. //
  2329. if ( m_pParent != NULL )
  2330. {
  2331. m_pParent->Use( pActivator, pCaller, useType, value );
  2332. }
  2333. }
  2334. }
  2335. static CBaseEntity *FindPhysicsBlocker( IPhysicsObject *pPhysics, physicspushlist_t &list, const Vector &pushVel )
  2336. {
  2337. IPhysicsFrictionSnapshot *pSnapshot = pPhysics->CreateFrictionSnapshot();
  2338. CBaseEntity *pBlocker = NULL;
  2339. float maxForce = 0;
  2340. while ( pSnapshot->IsValid() )
  2341. {
  2342. IPhysicsObject *pOther = pSnapshot->GetObject(1);
  2343. CBaseEntity *pOtherEntity = static_cast<CBaseEntity *>(pOther->GetGameData());
  2344. bool inList = false;
  2345. for ( int i = 0; i < list.pushedCount; i++ )
  2346. {
  2347. if ( pOtherEntity == list.pushedEnts[i] )
  2348. {
  2349. inList = true;
  2350. break;
  2351. }
  2352. }
  2353. Vector normal;
  2354. pSnapshot->GetSurfaceNormal(normal);
  2355. float dot = DotProduct( pushVel, pSnapshot->GetNormalForce() * normal );
  2356. if ( !pBlocker || (!inList && dot > maxForce) )
  2357. {
  2358. pBlocker = pOtherEntity;
  2359. if ( !inList )
  2360. {
  2361. maxForce = dot;
  2362. }
  2363. }
  2364. pSnapshot->NextFrictionData();
  2365. }
  2366. pPhysics->DestroyFrictionSnapshot( pSnapshot );
  2367. return pBlocker;
  2368. }
  2369. struct pushblock_t
  2370. {
  2371. physicspushlist_t *pList;
  2372. CBaseEntity *pRootParent;
  2373. CBaseEntity *pBlockedEntity;
  2374. float moveBackFraction;
  2375. float movetime;
  2376. };
  2377. static void ComputePushStartMatrix( matrix3x4_t &start, CBaseEntity *pEntity, const pushblock_t &params )
  2378. {
  2379. Vector localOrigin;
  2380. QAngle localAngles;
  2381. if ( params.pList )
  2382. {
  2383. localOrigin = params.pList->localOrigin;
  2384. localAngles = params.pList->localAngles;
  2385. }
  2386. else
  2387. {
  2388. localOrigin = params.pRootParent->GetAbsOrigin() - params.pRootParent->GetAbsVelocity() * params.movetime;
  2389. localAngles = params.pRootParent->GetAbsAngles() - params.pRootParent->GetLocalAngularVelocity() * params.movetime;
  2390. }
  2391. matrix3x4_t xform, delta;
  2392. AngleMatrix( localAngles, localOrigin, xform );
  2393. matrix3x4_t srcInv;
  2394. // xform = src(-1) * dest
  2395. MatrixInvert( params.pRootParent->EntityToWorldTransform(), srcInv );
  2396. ConcatTransforms( xform, srcInv, delta );
  2397. ConcatTransforms( delta, pEntity->EntityToWorldTransform(), start );
  2398. }
  2399. #define DEBUG_PUSH_MESSAGES 0
  2400. static void CheckPushedEntity( CBaseEntity *pEntity, pushblock_t &params )
  2401. {
  2402. IPhysicsObject *pPhysics = pEntity->VPhysicsGetObject();
  2403. if ( !pPhysics )
  2404. return;
  2405. // somehow we've got a static or motion disabled physics object in hierarchy!
  2406. // This is not allowed! Don't test blocking in that case.
  2407. Assert(pPhysics->IsMoveable());
  2408. if ( !pPhysics->IsMoveable() || !pPhysics->GetShadowController() )
  2409. {
  2410. #if DEBUG_PUSH_MESSAGES
  2411. Msg("Blocking %s, not moveable!\n", pEntity->GetClassname());
  2412. #endif
  2413. return;
  2414. }
  2415. bool checkrot = true;
  2416. bool checkmove = true;
  2417. Vector origin;
  2418. QAngle angles;
  2419. pPhysics->GetShadowPosition( &origin, &angles );
  2420. float fraction = -1.0f;
  2421. matrix3x4_t parentDelta;
  2422. if ( pEntity == params.pRootParent )
  2423. {
  2424. if ( pEntity->GetLocalAngularVelocity() == vec3_angle )
  2425. checkrot = false;
  2426. if ( pEntity->GetLocalVelocity() == vec3_origin)
  2427. checkmove = false;
  2428. }
  2429. else
  2430. {
  2431. #if DEBUG_PUSH_MESSAGES
  2432. if ( pPhysics->IsAttachedToConstraint(false))
  2433. {
  2434. Msg("Warning, hierarchical entity is attached to a constraint %s\n", pEntity->GetClassname());
  2435. }
  2436. #endif
  2437. }
  2438. if ( checkmove )
  2439. {
  2440. // project error onto the axis of movement
  2441. Vector dir = pEntity->GetAbsVelocity();
  2442. float speed = VectorNormalize(dir);
  2443. Vector targetPos;
  2444. pPhysics->GetShadowController()->GetTargetPosition( &targetPos, NULL );
  2445. float targetAmount = DotProduct(targetPos, dir);
  2446. float currentAmount = DotProduct(origin, dir);
  2447. float entityAmount = DotProduct(pEntity->GetAbsOrigin(), dir);
  2448. // if target and entity origin are not in sync, then the position of the entity was updated
  2449. // by something outside of push physics
  2450. if ( (targetAmount - entityAmount) > 1 )
  2451. {
  2452. pEntity->UpdatePhysicsShadowToCurrentPosition(0);
  2453. #if DEBUG_PUSH_MESSAGES
  2454. Warning("Someone slammed the position of a %s\n", pEntity->GetClassname() );
  2455. #endif
  2456. }
  2457. else
  2458. {
  2459. float dist = targetAmount - currentAmount;
  2460. if ( dist > 1 )
  2461. {
  2462. #if DEBUG_PUSH_MESSAGES
  2463. const char *pName = pEntity->GetClassname();
  2464. Msg( "%s blocked by %.2f units\n", pName, dist );
  2465. #endif
  2466. float movementAmount = targetAmount - (speed * params.movetime);
  2467. if ( pEntity == params.pRootParent )
  2468. {
  2469. if ( params.pList )
  2470. {
  2471. Vector localVel = pEntity->GetLocalVelocity();
  2472. VectorNormalize(localVel);
  2473. float localTargetAmt = DotProduct(pEntity->GetLocalOrigin(), localVel);
  2474. movementAmount = targetAmount + DotProduct(params.pList->localOrigin, localVel) - localTargetAmt;
  2475. }
  2476. }
  2477. else
  2478. {
  2479. matrix3x4_t start;
  2480. ComputePushStartMatrix( start, pEntity, params );
  2481. Vector startPos;
  2482. MatrixPosition( start, startPos );
  2483. movementAmount = DotProduct(startPos, dir);
  2484. }
  2485. float expectedDist = targetAmount - movementAmount;
  2486. // compute the fraction to move back the AI to match the physics
  2487. if ( expectedDist <= 0 )
  2488. {
  2489. fraction = 1;
  2490. }
  2491. else
  2492. {
  2493. fraction = dist / expectedDist;
  2494. fraction = clamp(fraction, 0, 1);
  2495. }
  2496. }
  2497. }
  2498. }
  2499. if ( checkrot )
  2500. {
  2501. Vector axis;
  2502. float deltaAngle;
  2503. RotationDeltaAxisAngle( angles, pEntity->GetAbsAngles(), axis, deltaAngle );
  2504. if ( fabsf(deltaAngle) > 0.5f )
  2505. {
  2506. Vector targetAxis;
  2507. QAngle targetRot;
  2508. float deltaTargetAngle;
  2509. pPhysics->GetShadowController()->GetTargetPosition( NULL, &targetRot );
  2510. RotationDeltaAxisAngle( angles, targetRot, targetAxis, deltaTargetAngle );
  2511. if ( fabsf(deltaTargetAngle) > 0.01f )
  2512. {
  2513. float expectedDist = deltaAngle;
  2514. #if DEBUG_PUSH_MESSAGES
  2515. const char *pName = pEntity->GetClassname();
  2516. Msg( "%s blocked by %.2f degrees\n", pName, deltaAngle );
  2517. if ( pPhysics->IsAsleep() )
  2518. {
  2519. Msg("Asleep while blocked?\n");
  2520. }
  2521. if ( pPhysics->GetGameFlags() & FVPHYSICS_PENETRATING )
  2522. {
  2523. Msg("Blocking for penetration!\n");
  2524. }
  2525. #endif
  2526. if ( pEntity == params.pRootParent )
  2527. {
  2528. expectedDist = pEntity->GetLocalAngularVelocity().Length() * params.movetime;
  2529. }
  2530. else
  2531. {
  2532. matrix3x4_t start;
  2533. ComputePushStartMatrix( start, pEntity, params );
  2534. Vector startAxis;
  2535. float startAngle;
  2536. Vector startPos;
  2537. QAngle startAngles;
  2538. MatrixAngles( start, startAngles, startPos );
  2539. RotationDeltaAxisAngle( startAngles, pEntity->GetAbsAngles(), startAxis, startAngle );
  2540. expectedDist = startAngle * DotProduct( startAxis, axis );
  2541. }
  2542. float t = expectedDist != 0.0f ? fabsf(deltaAngle / expectedDist) : 1.0f;
  2543. t = clamp(t,0,1);
  2544. fraction = MAX(fraction, t);
  2545. }
  2546. else
  2547. {
  2548. pEntity->UpdatePhysicsShadowToCurrentPosition(0);
  2549. #if DEBUG_PUSH_MESSAGES
  2550. Warning("Someone slammed the position of a %s\n", pEntity->GetClassname() );
  2551. #endif
  2552. }
  2553. }
  2554. }
  2555. if ( fraction >= params.moveBackFraction && sv_phys_props_block_movers.GetBool() )
  2556. {
  2557. params.moveBackFraction = fraction;
  2558. params.pBlockedEntity = pEntity;
  2559. }
  2560. }
  2561. void CBaseEntity::VPhysicsUpdatePusher( IPhysicsObject *pPhysics )
  2562. {
  2563. float movetime = m_flLocalTime - m_flVPhysicsUpdateLocalTime;
  2564. if (movetime <= 0 )
  2565. return;
  2566. // only reconcile pushers on the final vphysics tick
  2567. if ( !PhysIsFinalTick() )
  2568. return;
  2569. Vector origin;
  2570. QAngle angles;
  2571. // physics updated the shadow, so check to see if I got blocked
  2572. // NOTE: SOLID_BSP cannont compute consistent collisions wrt vphysics, so
  2573. // don't allow vphysics to block. Assume game physics has handled it.
  2574. if ( GetSolid() != SOLID_BSP && pPhysics->GetShadowPosition( &origin, &angles ) )
  2575. {
  2576. CUtlVector<CBaseEntity *> list;
  2577. GetAllInHierarchy( this, list );
  2578. //NDebugOverlay::BoxAngles( origin, CollisionProp()->OBBMins(), CollisionProp()->OBBMaxs(), angles, 255,0,0,0, gpGlobals->frametime);
  2579. physicspushlist_t *pList = NULL;
  2580. if ( HasDataObjectType(PHYSICSPUSHLIST) )
  2581. {
  2582. pList = (physicspushlist_t *)GetDataObject( PHYSICSPUSHLIST );
  2583. Assert(pList);
  2584. }
  2585. bool checkrot = (GetLocalAngularVelocity() != vec3_angle) ? true : false;
  2586. bool checkmove = (GetLocalVelocity() != vec3_origin) ? true : false;
  2587. pushblock_t params;
  2588. params.pRootParent = this;
  2589. params.pList = pList;
  2590. params.pBlockedEntity = NULL;
  2591. params.moveBackFraction = 0.0f;
  2592. params.movetime = movetime;
  2593. for ( int i = 0; i < list.Count(); i++ )
  2594. {
  2595. if ( list[i]->IsSolid() )
  2596. {
  2597. CheckPushedEntity( list[i], params );
  2598. }
  2599. }
  2600. float physLocalTime = m_flLocalTime;
  2601. if ( params.pBlockedEntity )
  2602. {
  2603. float moveback = movetime * params.moveBackFraction;
  2604. if ( moveback > 0 )
  2605. {
  2606. physLocalTime = m_flLocalTime - moveback;
  2607. // add 1% noise for bouncing in collision.
  2608. if ( physLocalTime <= (m_flVPhysicsUpdateLocalTime + movetime * 0.99f) )
  2609. {
  2610. CBaseEntity *pBlocked = NULL;
  2611. IPhysicsObject *pOther;
  2612. if ( params.pBlockedEntity->VPhysicsGetObject()->GetContactPoint( NULL, &pOther ) )
  2613. {
  2614. pBlocked = static_cast<CBaseEntity *>(pOther->GetGameData());
  2615. }
  2616. // UNDONE: Need to traverse hierarchy here? Shouldn't.
  2617. if ( pList )
  2618. {
  2619. SetLocalOrigin( pList->localOrigin );
  2620. SetLocalAngles( pList->localAngles );
  2621. physLocalTime = pList->localMoveTime;
  2622. for ( int i = 0; i < pList->pushedCount; i++ )
  2623. {
  2624. CBaseEntity *pEntity = pList->pushedEnts[i];
  2625. if ( !pEntity )
  2626. continue;
  2627. pEntity->SetAbsOrigin( pEntity->GetAbsOrigin() - pList->pushVec[i] );
  2628. }
  2629. CBaseEntity *pPhysicsBlocker = FindPhysicsBlocker( VPhysicsGetObject(), *pList, pList->pushVec[0] );
  2630. if ( pPhysicsBlocker )
  2631. {
  2632. pBlocked = pPhysicsBlocker;
  2633. }
  2634. }
  2635. else
  2636. {
  2637. Vector origin = GetLocalOrigin();
  2638. QAngle angles = GetLocalAngles();
  2639. if ( checkmove )
  2640. {
  2641. origin -= GetLocalVelocity() * moveback;
  2642. }
  2643. if ( checkrot )
  2644. {
  2645. // BUGBUG: This is pretty hack-tastic!
  2646. angles -= GetLocalAngularVelocity() * moveback;
  2647. }
  2648. SetLocalOrigin( origin );
  2649. SetLocalAngles( angles );
  2650. }
  2651. if ( pBlocked )
  2652. {
  2653. Blocked( pBlocked );
  2654. }
  2655. m_flLocalTime = physLocalTime;
  2656. }
  2657. }
  2658. }
  2659. }
  2660. // this data is no longer useful, free the memory
  2661. if ( HasDataObjectType(PHYSICSPUSHLIST) )
  2662. {
  2663. DestroyDataObject( PHYSICSPUSHLIST );
  2664. }
  2665. m_flVPhysicsUpdateLocalTime = m_flLocalTime;
  2666. if ( m_flMoveDoneTime <= m_flLocalTime && m_flMoveDoneTime > 0 )
  2667. {
  2668. SetMoveDoneTime( -1 );
  2669. MoveDone();
  2670. }
  2671. }
  2672. void CBaseEntity::SetMoveDoneTime( float flDelay )
  2673. {
  2674. if (flDelay >= 0)
  2675. {
  2676. m_flMoveDoneTime = GetLocalTime() + flDelay;
  2677. }
  2678. else
  2679. {
  2680. m_flMoveDoneTime = -1;
  2681. }
  2682. CheckHasGamePhysicsSimulation();
  2683. }
  2684. //-----------------------------------------------------------------------------
  2685. // Purpose: Relinks all of a parents children into the collision tree
  2686. //-----------------------------------------------------------------------------
  2687. void CBaseEntity::PhysicsRelinkChildren( float dt )
  2688. {
  2689. CBaseEntity *child;
  2690. // iterate through all children
  2691. for ( child = FirstMoveChild(); child != NULL; child = child->NextMovePeer() )
  2692. {
  2693. if ( child->IsSolid() || child->IsSolidFlagSet(FSOLID_TRIGGER) )
  2694. {
  2695. child->PhysicsTouchTriggers();
  2696. }
  2697. //
  2698. // Update their physics shadows. We should never have any children of
  2699. // movetype VPHYSICS.
  2700. //
  2701. if ( child->GetMoveType() != MOVETYPE_VPHYSICS )
  2702. {
  2703. child->UpdatePhysicsShadowToCurrentPosition( dt );
  2704. }
  2705. else if ( child->GetOwnerEntity() != this )
  2706. {
  2707. // the only case where this is valid is if this entity is an attached ragdoll.
  2708. // So assert here to catch the non-ragdoll case.
  2709. Assert( 0 );
  2710. }
  2711. if ( child->FirstMoveChild() )
  2712. {
  2713. child->PhysicsRelinkChildren(dt);
  2714. }
  2715. }
  2716. }
  2717. void CBaseEntity::VPhysicsShadowCollision( int index, gamevcollisionevent_t *pEvent )
  2718. {
  2719. }
  2720. void CBaseEntity::VPhysicsCollision( int index, gamevcollisionevent_t *pEvent )
  2721. {
  2722. // filter out ragdoll props hitting other parts of itself too often
  2723. // UNDONE: Store a sound time for this entity (not just this pair of objects)
  2724. // and filter repeats on that?
  2725. int otherIndex = !index;
  2726. CBaseEntity *pHitEntity = pEvent->pEntities[otherIndex];
  2727. // Don't make sounds / effects if neither entity is MOVETYPE_VPHYSICS. The game
  2728. // physics should have done so.
  2729. if ( GetMoveType() != MOVETYPE_VPHYSICS && pHitEntity->GetMoveType() != MOVETYPE_VPHYSICS )
  2730. return;
  2731. if ( pEvent->deltaCollisionTime < 0.5 && (pHitEntity == this) )
  2732. return;
  2733. // don't make noise for hidden/invisible/sky materials
  2734. surfacedata_t *phit = physprops->GetSurfaceData( pEvent->surfaceProps[otherIndex] );
  2735. const surfacedata_t *pprops = physprops->GetSurfaceData( pEvent->surfaceProps[index] );
  2736. if ( phit->game.material == 'X' || pprops->game.material == 'X' )
  2737. return;
  2738. if ( pHitEntity == this )
  2739. {
  2740. PhysCollisionSound( this, pEvent->pObjects[index], CHAN_BODY, pEvent->surfaceProps[index], pEvent->surfaceProps[otherIndex], pEvent->deltaCollisionTime, pEvent->collisionSpeed );
  2741. }
  2742. else
  2743. {
  2744. PhysCollisionSound( this, pEvent->pObjects[index], CHAN_STATIC, pEvent->surfaceProps[index], pEvent->surfaceProps[otherIndex], pEvent->deltaCollisionTime, pEvent->collisionSpeed );
  2745. }
  2746. PhysCollisionScreenShake( pEvent, index );
  2747. #if HL2_EPISODIC
  2748. // episodic does something different for when advisor shields are struck
  2749. if ( phit->game.material == 'Z' || pprops->game.material == 'Z')
  2750. {
  2751. PhysCollisionWarpEffect( pEvent, phit );
  2752. }
  2753. else
  2754. {
  2755. PhysCollisionDust( pEvent, phit );
  2756. }
  2757. #else
  2758. PhysCollisionDust( pEvent, phit );
  2759. #endif
  2760. }
  2761. void CBaseEntity::VPhysicsFriction( IPhysicsObject *pObject, float energy, int surfaceProps, int surfacePropsHit )
  2762. {
  2763. PhysFrictionSound( this, pObject, energy, surfaceProps, surfacePropsHit );
  2764. }
  2765. // Tells the physics shadow to update it's target to the current position
  2766. void CBaseEntity::UpdatePhysicsShadowToCurrentPosition( float deltaTime )
  2767. {
  2768. if ( GetMoveType() != MOVETYPE_VPHYSICS )
  2769. {
  2770. IPhysicsObject *pPhys = VPhysicsGetObject();
  2771. if ( pPhys )
  2772. {
  2773. pPhys->UpdateShadow( GetAbsOrigin(), GetAbsAngles(), false, deltaTime );
  2774. }
  2775. }
  2776. }
  2777. int CBaseEntity::VPhysicsGetObjectList( IPhysicsObject **pList, int listMax )
  2778. {
  2779. IPhysicsObject *pPhys = VPhysicsGetObject();
  2780. if ( pPhys )
  2781. {
  2782. // multi-object entities must implement this function
  2783. Assert( !(pPhys->GetGameFlags() & FVPHYSICS_MULTIOBJECT_ENTITY) );
  2784. if ( listMax > 0 )
  2785. {
  2786. pList[0] = pPhys;
  2787. return 1;
  2788. }
  2789. }
  2790. return 0;
  2791. }
  2792. //-----------------------------------------------------------------------------
  2793. //-----------------------------------------------------------------------------
  2794. bool CBaseEntity::VPhysicsIsFlesh( void )
  2795. {
  2796. IPhysicsObject *pList[VPHYSICS_MAX_OBJECT_LIST_COUNT];
  2797. int count = VPhysicsGetObjectList( pList, ARRAYSIZE(pList) );
  2798. for ( int i = 0; i < count; i++ )
  2799. {
  2800. int material = pList[i]->GetMaterialIndex();
  2801. const surfacedata_t *pSurfaceData = physprops->GetSurfaceData( material );
  2802. // Is flesh ?, don't allow pickup
  2803. if ( pSurfaceData->game.material == CHAR_TEX_ANTLION || pSurfaceData->game.material == CHAR_TEX_FLESH || pSurfaceData->game.material == CHAR_TEX_BLOODYFLESH || pSurfaceData->game.material == CHAR_TEX_ALIENFLESH )
  2804. return true;
  2805. }
  2806. return false;
  2807. }
  2808. bool CBaseEntity::Intersects( CBaseEntity *pOther )
  2809. {
  2810. if ( !edict() || !pOther->edict() )
  2811. return false;
  2812. CCollisionProperty *pMyProp = CollisionProp();
  2813. CCollisionProperty *pOtherProp = pOther->CollisionProp();
  2814. return IsOBBIntersectingOBB(
  2815. pMyProp->GetCollisionOrigin(), pMyProp->GetCollisionAngles(), pMyProp->OBBMins(), pMyProp->OBBMaxs(),
  2816. pOtherProp->GetCollisionOrigin(), pOtherProp->GetCollisionAngles(), pOtherProp->OBBMins(), pOtherProp->OBBMaxs() );
  2817. }
  2818. extern ConVar ai_LOS_mode;
  2819. // With RUNTIME STACK TRANSLATION enabled, you get a few additional cvars which let you debug exactly where
  2820. // FVisible calls are coming from.
  2821. // To use,
  2822. // Uncomment the #define ENABLE_RUNTIME_STACK_TRANSLATION line in stacktools.h
  2823. // vpc +game /allgames /nofpo to disable frame pointer omission in *ALL COMPILED PROJECTS*
  2824. // rebuild everything
  2825. #ifdef ENABLE_STACK_STATS_GATHERING
  2826. //#define FVIS_STACK_TRACKING
  2827. #endif
  2828. #if defined( FVIS_STACK_TRACKING )
  2829. struct Count_t ///< simple wrapper so I get a default constructor
  2830. {
  2831. DECLARE_CALLSTACKSTATSTRUCT();
  2832. Count_t() : i(0) {};
  2833. Count_t(int a) : i(a) {};
  2834. unsigned int i;
  2835. };
  2836. BEGIN_STATSTRUCTDESCRIPTION( Count_t )
  2837. END_STATSTRUCTDESCRIPTION()
  2838. static CCallStackStatsGatherer<Count_t, 16> s_FVisCallStackInfo;
  2839. void CC_FVis_Stack_Reset( const CCommand& args )
  2840. {
  2841. s_FVisCallStackInfo.Reset();
  2842. }
  2843. static ConCommand perf_fvis_stacks_reset("perf_fvis_stacks_reset", CC_FVis_Stack_Reset, "Resets CBaseEntity::FVisible stacktrace counts", FCVAR_CHEAT);
  2844. void CC_FVis_Stack_Dump( const CCommand& args )
  2845. {
  2846. int count = s_FVisCallStackInfo.NumEntries();
  2847. for (int i = 0 ; i < count ; ++i)
  2848. {
  2849. Msg( "\t%d calls:\n", s_FVisCallStackInfo.GetEntry(i) );
  2850. // print call stack
  2851. // TranslateStackInfo( const void * const *pCallStack, int iCallStackCount, tchar *szOutput, int iOutBufferSize, const tchar *szEntrySeparator, TranslateStackInfo_StyleFlags_t style = TSISTYLEFLAG_DEFAULT );
  2852. char outBuf[1024];
  2853. TranslateStackInfo( s_FVisCallStackInfo.GetCallStackForIndex(i), s_FVisCallStackInfo.CapturedCallStackLength, outBuf, 1023, "\n", (TranslateStackInfo_StyleFlags_t)(TSISTYLEFLAG_MODULENAME | TSISTYLEFLAG_SYMBOLNAME | TSISTYLEFLAG_SHORTPATH ) );
  2854. Msg( outBuf );
  2855. Msg( "\n\n" );
  2856. }
  2857. }
  2858. static ConCommand perf_fvis_stacks_dump("perf_fvis_stacks_dump", CC_FVis_Stack_Dump, "Dump info on all CBaseEntity::FVisible stack traces to console", FCVAR_CHEAT);
  2859. ConVar perf_fvis_stacks_trace( "perf_fvis_stacks_trace", "0", FCVAR_CHEAT, "Enable to get detailed perf on fvis" );
  2860. #endif
  2861. //=========================================================
  2862. // FVisible - returns true if a line can be traced from
  2863. // the caller's eyes to the target
  2864. //=========================================================
  2865. bool CBaseEntity::FVisible( CBaseEntity *pEntity, int traceMask, CBaseEntity **ppBlocker )
  2866. {
  2867. VPROF( "CBaseEntity::FVisible" );
  2868. #if defined( FVIS_STACK_TRACKING )
  2869. if ( perf_fvis_stacks_trace.GetBool() )
  2870. {
  2871. CCallStackStatsGatherer_StructAccessor_AutoLock<Count_t> accessor = s_FVisCallStackInfo.GetEntry(); //( CCallStackStorage( s_FVisCallStackInfo.StackFunction, 1 ) );
  2872. accessor->i += 1;
  2873. }
  2874. #endif
  2875. if ( pEntity->GetFlags() & FL_NOTARGET )
  2876. return false;
  2877. Vector vecLookerOrigin = EyePosition();//look through the caller's 'eyes'
  2878. Vector vecTargetOrigin = pEntity->EyePosition();
  2879. trace_t tr;
  2880. if ( ai_LOS_mode.GetBool() )
  2881. {
  2882. UTIL_TraceLine(vecLookerOrigin, vecTargetOrigin, traceMask, this, COLLISION_GROUP_NONE, &tr);
  2883. }
  2884. else
  2885. {
  2886. // If we're doing an LOS search, include NPCs.
  2887. if ( traceMask == MASK_BLOCKLOS )
  2888. {
  2889. traceMask = MASK_BLOCKLOS_AND_NPCS;
  2890. }
  2891. // Player sees through nodraw
  2892. if ( IsPlayer() )
  2893. {
  2894. traceMask &= ~CONTENTS_BLOCKLOS;
  2895. }
  2896. // Use the custom LOS trace filter
  2897. CTraceFilterLOS traceFilter( this, COLLISION_GROUP_NONE, pEntity );
  2898. UTIL_TraceLine( vecLookerOrigin, vecTargetOrigin, traceMask, &traceFilter, &tr );
  2899. }
  2900. if (tr.fraction != 1.0 || tr.startsolid )
  2901. {
  2902. // If we hit the entity we're looking for, it's visible
  2903. if ( tr.m_pEnt == pEntity )
  2904. return true;
  2905. // Got line of sight on the vehicle the player is driving!
  2906. if ( pEntity && pEntity->IsPlayer() )
  2907. {
  2908. CBasePlayer *pPlayer = assert_cast<CBasePlayer*>( pEntity );
  2909. if ( tr.m_pEnt == pPlayer->GetVehicleEntity() )
  2910. return true;
  2911. }
  2912. if (ppBlocker)
  2913. {
  2914. *ppBlocker = tr.m_pEnt;
  2915. }
  2916. return false;// Line of sight is not established
  2917. }
  2918. return true;// line of sight is valid.
  2919. }
  2920. //=========================================================
  2921. // FVisible - returns true if a line can be traced from
  2922. // the caller's eyes to the wished position.
  2923. //=========================================================
  2924. bool CBaseEntity::FVisible( const Vector &vecTarget, int traceMask, CBaseEntity **ppBlocker )
  2925. {
  2926. VPROF( "CBaseEntity::FVisible" );
  2927. #if defined( FVIS_STACK_TRACKING )
  2928. if ( perf_fvis_stacks_trace.GetBool() )
  2929. {
  2930. CCallStackStatsGatherer_StructAccessor_AutoLock<Count_t> accessor = s_FVisCallStackInfo.GetEntry(); //( CCallStackStorage( s_FVisCallStackInfo.StackFunction, 1 ) );
  2931. accessor->i += 1;
  2932. }
  2933. #endif
  2934. trace_t tr;
  2935. Vector vecLookerOrigin = EyePosition();// look through the caller's 'eyes'
  2936. if ( ai_LOS_mode.GetBool() )
  2937. {
  2938. UTIL_TraceLine( vecLookerOrigin, vecTarget, traceMask, this, COLLISION_GROUP_NONE, &tr);
  2939. }
  2940. else
  2941. {
  2942. // If we're doing an LOS search, include NPCs.
  2943. if ( traceMask == MASK_BLOCKLOS )
  2944. {
  2945. traceMask = MASK_BLOCKLOS_AND_NPCS;
  2946. }
  2947. // Player sees through nodraw and blocklos
  2948. if ( IsPlayer() )
  2949. {
  2950. traceMask |= CONTENTS_IGNORE_NODRAW_OPAQUE;
  2951. traceMask &= ~CONTENTS_BLOCKLOS;
  2952. }
  2953. // Use the custom LOS trace filter
  2954. CTraceFilterLOS traceFilter( this, COLLISION_GROUP_NONE );
  2955. UTIL_TraceLine( vecLookerOrigin, vecTarget, traceMask, &traceFilter, &tr );
  2956. }
  2957. if (tr.fraction != 1.0)
  2958. {
  2959. if (ppBlocker)
  2960. {
  2961. *ppBlocker = tr.m_pEnt;
  2962. }
  2963. return false;// Line of sight is not established
  2964. }
  2965. return true;// line of sight is valid.
  2966. }
  2967. extern ConVar ai_debug_los;
  2968. //-----------------------------------------------------------------------------
  2969. // Purpose: Turn on prop LOS debugging mode
  2970. //-----------------------------------------------------------------------------
  2971. void CC_AI_LOS_Debug( IConVar *var, const char *pOldString, float flOldValue )
  2972. {
  2973. int iLOSMode = ai_debug_los.GetInt();
  2974. for ( CBaseEntity *pEntity = gEntList.FirstEnt(); pEntity != NULL; pEntity = gEntList.NextEnt(pEntity) )
  2975. {
  2976. if ( iLOSMode == 1 && pEntity->IsSolid() )
  2977. {
  2978. pEntity->m_debugOverlays |= OVERLAY_SHOW_BLOCKSLOS;
  2979. }
  2980. else if ( iLOSMode == 2 )
  2981. {
  2982. pEntity->m_debugOverlays |= OVERLAY_SHOW_BLOCKSLOS;
  2983. }
  2984. else
  2985. {
  2986. pEntity->m_debugOverlays &= ~OVERLAY_SHOW_BLOCKSLOS;
  2987. }
  2988. }
  2989. }
  2990. ConVar ai_debug_los("ai_debug_los", "0", FCVAR_CHEAT, "NPC Line-Of-Sight debug mode. If 1, solid entities that block NPC LOC will be highlighted with white bounding boxes. If 2, it'll show non-solid entities that would do it if they were solid.", CC_AI_LOS_Debug );
  2991. Class_T CBaseEntity::Classify ( void )
  2992. {
  2993. return CLASS_NONE;
  2994. }
  2995. float CBaseEntity::GetAutoAimRadius()
  2996. {
  2997. if( g_pGameRules->GetAutoAimMode() == AUTOAIM_ON_CONSOLE )
  2998. return 48.0f;
  2999. else
  3000. return 24.0f;
  3001. }
  3002. //-----------------------------------------------------------------------------
  3003. // Changes the shadow cast distance over time
  3004. //-----------------------------------------------------------------------------
  3005. void CBaseEntity::ShadowCastDistThink( )
  3006. {
  3007. SetShadowCastDistance( m_flDesiredShadowCastDistance );
  3008. SetContextThink( NULL, gpGlobals->curtime, "ShadowCastDistThink" );
  3009. }
  3010. void CBaseEntity::SetShadowCastDistance( float flDesiredDistance, float flDelay )
  3011. {
  3012. m_flDesiredShadowCastDistance = flDesiredDistance;
  3013. if ( m_flDesiredShadowCastDistance != m_flShadowCastDistance )
  3014. {
  3015. SetContextThink( &CBaseEntity::ShadowCastDistThink, gpGlobals->curtime + flDelay, "ShadowCastDistThink" );
  3016. }
  3017. }
  3018. /*
  3019. ================
  3020. TraceAttack
  3021. ================
  3022. */
  3023. //-----------------------------------------------------------------------------
  3024. // Purpose: Returns whether a damage info can damage this entity.
  3025. //-----------------------------------------------------------------------------
  3026. bool CBaseEntity::PassesDamageFilter( const CTakeDamageInfo &info )
  3027. {
  3028. if (m_hDamageFilter)
  3029. {
  3030. CBaseFilter *pFilter = (CBaseFilter *)(m_hDamageFilter.Get());
  3031. return pFilter->PassesDamageFilter(info);
  3032. }
  3033. return true;
  3034. }
  3035. bool CBaseEntity::NameMatchesComplex( const char *pszNameOrWildcard )
  3036. {
  3037. if ( !Q_stricmp( "!player", pszNameOrWildcard) )
  3038. return IsPlayer();
  3039. return EntityNamesMatch( pszNameOrWildcard, m_iName );
  3040. }
  3041. bool CBaseEntity::ClassMatchesComplex( const char *pszClassOrWildcard )
  3042. {
  3043. return EntityNamesMatch( pszClassOrWildcard, m_iClassname );
  3044. }
  3045. void CBaseEntity::MakeDormant( void )
  3046. {
  3047. AddEFlags( EFL_DORMANT );
  3048. // disable thinking for dormant entities
  3049. SetThink( NULL );
  3050. if ( !edict() )
  3051. return;
  3052. SETBITS( m_iEFlags, EFL_DORMANT );
  3053. // Don't touch
  3054. AddSolidFlags( FSOLID_NOT_SOLID );
  3055. // Don't move
  3056. SetMoveType( MOVETYPE_NONE );
  3057. // Don't draw
  3058. AddEffects( EF_NODRAW );
  3059. // Don't think
  3060. SetNextThink( TICK_NEVER_THINK );
  3061. }
  3062. int CBaseEntity::IsDormant( void )
  3063. {
  3064. return IsEFlagSet( EFL_DORMANT );
  3065. }
  3066. bool CBaseEntity::IsInWorld( void ) const
  3067. {
  3068. if ( !edict() )
  3069. return true;
  3070. // position
  3071. if (GetAbsOrigin().x >= MAX_COORD_INTEGER) return false;
  3072. if (GetAbsOrigin().y >= MAX_COORD_INTEGER) return false;
  3073. if (GetAbsOrigin().z >= MAX_COORD_INTEGER) return false;
  3074. if (GetAbsOrigin().x <= MIN_COORD_INTEGER) return false;
  3075. if (GetAbsOrigin().y <= MIN_COORD_INTEGER) return false;
  3076. if (GetAbsOrigin().z <= MIN_COORD_INTEGER) return false;
  3077. // speed
  3078. if (GetAbsVelocity().x >= 2000) return false;
  3079. if (GetAbsVelocity().y >= 2000) return false;
  3080. if (GetAbsVelocity().z >= 2000) return false;
  3081. if (GetAbsVelocity().x <= -2000) return false;
  3082. if (GetAbsVelocity().y <= -2000) return false;
  3083. if (GetAbsVelocity().z <= -2000) return false;
  3084. return true;
  3085. }
  3086. bool CBaseEntity::IsViewable( void )
  3087. {
  3088. if ( IsEffectActive( EF_NODRAW ) )
  3089. {
  3090. return false;
  3091. }
  3092. if (IsBSPModel())
  3093. {
  3094. if (GetMoveType() != MOVETYPE_NONE)
  3095. {
  3096. return true;
  3097. }
  3098. }
  3099. else if (GetModelIndex() != 0)
  3100. {
  3101. // check for total transparency???
  3102. return true;
  3103. }
  3104. return false;
  3105. }
  3106. int CBaseEntity::ShouldToggle( USE_TYPE useType, int currentState )
  3107. {
  3108. if ( useType != USE_TOGGLE && useType != USE_SET )
  3109. {
  3110. if ( (currentState && useType == USE_ON) || (!currentState && useType == USE_OFF) )
  3111. return 0;
  3112. }
  3113. return 1;
  3114. }
  3115. // NOTE: szName must be a pointer to constant memory, e.g. "NPC_class" because the entity
  3116. // will keep a pointer to it after this call.
  3117. CBaseEntity *CBaseEntity::Create( const char *szName, const Vector &vecOrigin, const QAngle &vecAngles, CBaseEntity *pOwner )
  3118. {
  3119. CBaseEntity *pEntity = CreateNoSpawn( szName, vecOrigin, vecAngles, pOwner );
  3120. DispatchSpawn( pEntity );
  3121. return pEntity;
  3122. }
  3123. // NOTE: szName must be a pointer to constant memory, e.g. "NPC_class" because the entity
  3124. // will keep a pointer to it after this call.
  3125. CBaseEntity * CBaseEntity::CreateNoSpawn( const char *szName, const Vector &vecOrigin, const QAngle &vecAngles, CBaseEntity *pOwner )
  3126. {
  3127. CBaseEntity *pEntity = CreateEntityByName( szName, -1, false );
  3128. if ( !pEntity )
  3129. {
  3130. Assert( !"CreateNoSpawn: only works for CBaseEntities" );
  3131. return NULL;
  3132. }
  3133. pEntity->SetLocalOrigin( vecOrigin );
  3134. pEntity->SetLocalAngles( vecAngles );
  3135. pEntity->SetOwnerEntity( pOwner );
  3136. gEntList.NotifyCreateEntity( pEntity );
  3137. return pEntity;
  3138. }
  3139. Vector CBaseEntity::GetSoundEmissionOrigin() const
  3140. {
  3141. return WorldSpaceCenter();
  3142. }
  3143. //-----------------------------------------------------------------------------
  3144. // Purpose: Saves the current object out to disk, by iterating through the objects
  3145. // data description hierarchy
  3146. // Input : &save - save buffer which the class data is written to
  3147. // Output : int - 0 if the save failed, 1 on success
  3148. //-----------------------------------------------------------------------------
  3149. int CBaseEntity::Save( ISave &save )
  3150. {
  3151. // loop through the data description list, saving each data desc block
  3152. int status = SaveDataDescBlock( save, GetDataDescMap() );
  3153. return status;
  3154. }
  3155. //-----------------------------------------------------------------------------
  3156. // Purpose: Recursively saves all the classes in an object, in reverse order (top down)
  3157. // Output : int 0 on failure, 1 on success
  3158. //-----------------------------------------------------------------------------
  3159. int CBaseEntity::SaveDataDescBlock( ISave &save, datamap_t *dmap )
  3160. {
  3161. return save.WriteAll( this, dmap );
  3162. }
  3163. //-----------------------------------------------------------------------------
  3164. // Purpose: Restores the current object from disk, by iterating through the objects
  3165. // data description hierarchy
  3166. // Input : &restore - restore buffer which the class data is read from
  3167. // Output : int - 0 if the restore failed, 1 on success
  3168. //-----------------------------------------------------------------------------
  3169. int CBaseEntity::Restore( IRestore &restore )
  3170. {
  3171. // This is essential to getting the spatial partition info correct
  3172. CollisionProp()->DestroyPartitionHandle();
  3173. // loops through the data description list, restoring each data desc block in order
  3174. int status = RestoreDataDescBlock( restore, GetDataDescMap() );
  3175. // ---------------------------------------------------------------
  3176. // HACKHACK: We don't know the space of these vectors until now
  3177. // if they are worldspace, fix them up.
  3178. // ---------------------------------------------------------------
  3179. {
  3180. CGameSaveRestoreInfo *pGameInfo = restore.GetGameSaveRestoreInfo();
  3181. Vector parentSpaceOffset = pGameInfo->modelSpaceOffset;
  3182. if ( !GetParent() )
  3183. {
  3184. // parent is the world, so parent space is worldspace
  3185. // so update with the worldspace leveltransition transform
  3186. parentSpaceOffset += pGameInfo->GetLandmark();
  3187. }
  3188. // NOTE: Do *not* use GetAbsOrigin() here because it will
  3189. // try to recompute m_rgflCoordinateFrame!
  3190. MatrixSetColumn( m_vecAbsOrigin, 3, m_rgflCoordinateFrame );
  3191. m_vecOrigin += parentSpaceOffset;
  3192. }
  3193. // Gotta do this after the coordframe is set up as it depends on it.
  3194. // By definition, the surrounding bounds are dirty
  3195. // Also, twiddling with the flags here ensures it gets added to the KD tree dirty list
  3196. // (We don't want to use the saved version of this flag)
  3197. RemoveEFlags( EFL_DIRTY_SPATIAL_PARTITION );
  3198. CollisionProp()->MarkSurroundingBoundsDirty();
  3199. if ( edict() && GetModelIndex() != 0 && GetModelName() != NULL_STRING && restore.GetPrecacheMode() )
  3200. {
  3201. PrecacheModel( STRING( GetModelName() ) );
  3202. //Adrian: We should only need to do this after we precache. No point in setting the model again.
  3203. SetModelIndex( modelinfo->GetModelIndex( STRING(GetModelName() ) ) );
  3204. }
  3205. // Restablish ground entity
  3206. if ( m_hGroundEntity != NULL )
  3207. {
  3208. m_hGroundEntity->AddEntityToGroundList( this );
  3209. }
  3210. // Tracker 22129
  3211. // This is a hack to make sure that the entity is added to the AddPostClientMessageEntity
  3212. // list so that EF_NOINTERP can be cleared at the end of the frame. Otherwise, a restored entity
  3213. // with this flag will not interpolate until the next time the flag is set. ywb
  3214. if ( IsEffectActive( EF_NOINTERP ) )
  3215. {
  3216. AddEffects( EF_NOINTERP );
  3217. }
  3218. // Ensure our cell is current
  3219. UpdateCell();
  3220. return status;
  3221. }
  3222. //-----------------------------------------------------------------------------
  3223. // handler to do stuff before you are saved
  3224. //-----------------------------------------------------------------------------
  3225. void CBaseEntity::OnSave( IEntitySaveUtils *pUtils )
  3226. {
  3227. // Here, we must force recomputation of all abs data so it gets saved correctly
  3228. // We can't leave the dirty bits set because the loader can't cope with it.
  3229. CalcAbsolutePosition();
  3230. CalcAbsoluteVelocity();
  3231. }
  3232. //-----------------------------------------------------------------------------
  3233. // handler to do stuff after you are restored
  3234. //-----------------------------------------------------------------------------
  3235. void CBaseEntity::OnRestore()
  3236. {
  3237. gEntList.UpdateName( this );
  3238. SimThink_EntityChanged( this );
  3239. // touchlinks get recomputed
  3240. if ( IsEFlagSet( EFL_CHECK_UNTOUCH ) )
  3241. {
  3242. RemoveEFlags( EFL_CHECK_UNTOUCH );
  3243. SetCheckUntouch( true );
  3244. }
  3245. // disable touch functions while we recreate the touch links between entities
  3246. // NOTE: We don't do this on transitions, because we'd miss the OnStartTouch call!
  3247. #if !defined(HL2_DLL) || ( defined(HL2_DLL) && defined(HL2_EPISODIC) )
  3248. CBaseEntity::sm_bDisableTouchFuncs = ( gpGlobals->eLoadType != MapLoad_Transition );
  3249. PhysicsTouchTriggers();
  3250. CBaseEntity::sm_bDisableTouchFuncs = false;
  3251. #endif // HL2_EPISODIC
  3252. //Adrian: If I'm restoring with these fields it means I've become a client side ragdoll.
  3253. //Don't create another one, just wait until is my time of being removed.
  3254. if ( GetFlags() & FL_TRANSRAGDOLL )
  3255. {
  3256. m_nRenderFX = kRenderFxNone;
  3257. AddEffects( EF_NODRAW );
  3258. RemoveFlag( FL_DISSOLVING | FL_ONFIRE );
  3259. }
  3260. if ( m_pParent )
  3261. {
  3262. CBaseEntity *pChild = m_pParent->FirstMoveChild();
  3263. while ( pChild )
  3264. {
  3265. if ( pChild == this )
  3266. break;
  3267. pChild = pChild->NextMovePeer();
  3268. }
  3269. if ( pChild != this )
  3270. {
  3271. #if _DEBUG
  3272. // generally this means you've got something marked FCAP_DONT_SAVE
  3273. // in a hierarchy. That's probably ok given this fixup, but the hierarhcy
  3274. // linked list is just saved/loaded in-place
  3275. Warning("Fixing up parent on %s\n", GetClassname() );
  3276. #endif
  3277. // We only need to be back in the parent's list because we're already in the right place and with the right data
  3278. LinkChild( m_pParent, this );
  3279. }
  3280. }
  3281. // We're not save/loading the PVS dirty state. Assume everything is dirty after a restore
  3282. NetworkProp()->MarkPVSInformationDirty();
  3283. }
  3284. //-----------------------------------------------------------------------------
  3285. // Purpose: Recursively restores all the classes in an object, in reverse order (top down)
  3286. // Output : int 0 on failure, 1 on success
  3287. //-----------------------------------------------------------------------------
  3288. int CBaseEntity::RestoreDataDescBlock( IRestore &restore, datamap_t *dmap )
  3289. {
  3290. return restore.ReadAll( this, dmap );
  3291. }
  3292. //-----------------------------------------------------------------------------
  3293. bool CBaseEntity::ShouldSavePhysics()
  3294. {
  3295. return true;
  3296. }
  3297. //-----------------------------------------------------------------------------
  3298. #include "tier0/memdbgoff.h"
  3299. //-----------------------------------------------------------------------------
  3300. // CBaseEntity new/delete
  3301. // allocates and frees memory for itself from the engine->
  3302. // All fields in the object are all initialized to 0.
  3303. //-----------------------------------------------------------------------------
  3304. void *CBaseEntity::operator new( size_t stAllocateBlock )
  3305. {
  3306. // call into engine to get memory
  3307. Assert( stAllocateBlock != 0 );
  3308. return calloc( 1, stAllocateBlock );
  3309. };
  3310. void *CBaseEntity::operator new( size_t stAllocateBlock, int nBlockUse, const char *pFileName, int nLine )
  3311. {
  3312. // call into engine to get memory
  3313. Assert( stAllocateBlock != 0 );
  3314. return MemAlloc_InlineCallocMemset( MemAlloc_Alloc(stAllocateBlock, pFileName, nLine), 1, stAllocateBlock );
  3315. }
  3316. void CBaseEntity::operator delete( void *pMem )
  3317. {
  3318. // get the engine to free the memory
  3319. free( pMem );
  3320. }
  3321. #include "tier0/memdbgon.h"
  3322. #ifdef _DEBUG
  3323. void CBaseEntity::FunctionCheck( inputfunc_t pFunction, const char *name )
  3324. {
  3325. #ifdef USES_SAVERESTORE
  3326. // Note, if you crash here and your class is using multiple inheritance, it is
  3327. // probably the case that CBaseEntity (or a descendant) is not the first
  3328. // class in your list of ancestors, which it must be.
  3329. if ( pFunction && !UTIL_FunctionToName( GetDataDescMap(), pFunction ) )
  3330. {
  3331. Warning( "FUNCTION NOT IN TABLE!: %s:%s (%08lx)\n", STRING(m_iClassname), name, *reinterpret_cast<uint32*>(&pFunction) );
  3332. Assert(0);
  3333. }
  3334. #endif
  3335. }
  3336. #endif
  3337. bool CBaseEntity::TestCollision( const Ray_t &ray, unsigned int mask, trace_t& trace )
  3338. {
  3339. return false;
  3340. }
  3341. //-----------------------------------------------------------------------------
  3342. // Perform hitbox test, returns true *if hitboxes were tested at all*!!
  3343. //-----------------------------------------------------------------------------
  3344. bool CBaseEntity::TestHitboxes( const Ray_t &ray, unsigned int fContentsMask, trace_t& tr )
  3345. {
  3346. return false;
  3347. }
  3348. void CBaseEntity::SetOwnerEntity( CBaseEntity* pOwner )
  3349. {
  3350. if ( m_hOwnerEntity.Get() != pOwner )
  3351. {
  3352. m_hOwnerEntity = pOwner;
  3353. CollisionRulesChanged();
  3354. }
  3355. }
  3356. void CBaseEntity::SetMoveType( MoveType_t val, MoveCollide_t moveCollide )
  3357. {
  3358. #ifdef _DEBUG
  3359. // Make sure the move type + move collide are compatible...
  3360. if ((val != MOVETYPE_FLY) && (val != MOVETYPE_FLYGRAVITY))
  3361. {
  3362. Assert( moveCollide == MOVECOLLIDE_DEFAULT );
  3363. }
  3364. if ( m_MoveType == MOVETYPE_VPHYSICS && val != m_MoveType )
  3365. {
  3366. if ( VPhysicsGetObject() && val != MOVETYPE_NONE )
  3367. {
  3368. // What am I supposed to do with the physics object if
  3369. // you're changing away from MOVETYPE_VPHYSICS without making the object
  3370. // shadow? This isn't likely to work, assert.
  3371. // You probably meant to call VPhysicsInitShadow() instead of VPhysicsInitNormal()!
  3372. Assert( VPhysicsGetObject()->GetShadowController() );
  3373. }
  3374. }
  3375. #endif
  3376. if ( m_MoveType == val )
  3377. {
  3378. m_MoveCollide = moveCollide;
  3379. return;
  3380. }
  3381. if ( m_MoveType == MOVETYPE_NOCLIP && val != m_MoveType )
  3382. {
  3383. RemoveEFlags( EFL_NOCLIP_ACTIVE );
  3384. }
  3385. // This is needed to the removal of MOVETYPE_FOLLOW:
  3386. // We can't transition from follow to a different movetype directly
  3387. // or the leaf code will break.
  3388. Assert( !IsEffectActive( EF_BONEMERGE ) );
  3389. if ( IsPushableMoveType(val) != IsPushableMoveType(m_MoveType) )
  3390. {
  3391. CollisionProp()->MarkPartitionHandleDirty();
  3392. }
  3393. m_MoveType = val;
  3394. m_MoveCollide = moveCollide;
  3395. CollisionRulesChanged();
  3396. switch( m_MoveType )
  3397. {
  3398. case MOVETYPE_WALK:
  3399. {
  3400. SetSimulatedEveryTick( true );
  3401. SetAnimatedEveryTick( true );
  3402. }
  3403. break;
  3404. case MOVETYPE_STEP:
  3405. {
  3406. // This will probably go away once I remove the cvar that controls the test code
  3407. SetSimulatedEveryTick( g_bTestMoveTypeStepSimulation ? true : false );
  3408. SetAnimatedEveryTick( false );
  3409. }
  3410. break;
  3411. case MOVETYPE_FLY:
  3412. case MOVETYPE_FLYGRAVITY:
  3413. {
  3414. // Initialize our water state, because these movetypes care about transitions in/out of water
  3415. UpdateWaterState();
  3416. }
  3417. break;
  3418. default:
  3419. {
  3420. SetSimulatedEveryTick( true );
  3421. SetAnimatedEveryTick( false );
  3422. }
  3423. }
  3424. // This will probably go away or be handled in a better way once I remove the cvar that controls the test code
  3425. CheckStepSimulationChanged();
  3426. CheckHasGamePhysicsSimulation();
  3427. }
  3428. void CBaseEntity::Spawn( void )
  3429. {
  3430. }
  3431. // Post KeyValues/Map data parsing hook
  3432. void CBaseEntity::OnParseMapDataFinished()
  3433. {
  3434. // Add to lag compensation list
  3435. if ( ShouldLagCompensate() )
  3436. {
  3437. lagcompensation->AddAdditionalEntity( this );
  3438. }
  3439. }
  3440. CBaseEntity* CBaseEntity::Instance( const CBaseHandle &hEnt )
  3441. {
  3442. return gEntList.GetBaseEntity( hEnt );
  3443. }
  3444. int CBaseEntity::GetTransmitState( void )
  3445. {
  3446. edict_t *ed = edict();
  3447. if ( !ed )
  3448. return 0;
  3449. return ed->m_fStateFlags;
  3450. }
  3451. int CBaseEntity::SetTransmitState( int nFlag)
  3452. {
  3453. edict_t *ed = edict();
  3454. if ( !ed )
  3455. return 0;
  3456. // clear current flags = check ShouldTransmit()
  3457. ed->ClearTransmitState();
  3458. int oldFlags = ed->m_fStateFlags;
  3459. ed->m_fStateFlags |= nFlag;
  3460. // Tell the engine (used for a network backdoor optimization).
  3461. if ( (oldFlags & FL_EDICT_DONTSEND) != (ed->m_fStateFlags & FL_EDICT_DONTSEND) )
  3462. engine->NotifyEdictFlagsChange( entindex() );
  3463. return ed->m_fStateFlags;
  3464. }
  3465. int CBaseEntity::UpdateTransmitState()
  3466. {
  3467. // If you get this assert, you should be calling DispatchUpdateTransmitState
  3468. // instead of UpdateTransmitState.
  3469. Assert( g_nInsideDispatchUpdateTransmitState > 0 );
  3470. #ifdef DOTA_DLL
  3471. return SetTransmitState( FL_EDICT_FULLCHECK );
  3472. #endif
  3473. // If an object is the moveparent of something else, don't skip it just because it's marked EF_NODRAW or else
  3474. // the client won't have a proper origin for the child since the hierarchy won't be correctly transmitted down
  3475. if ( IsEffectActive( EF_NODRAW ) &&
  3476. !m_hMoveChild.Get() )
  3477. {
  3478. return SetTransmitState( FL_EDICT_DONTSEND );
  3479. }
  3480. if ( !IsEFlagSet( EFL_FORCE_CHECK_TRANSMIT ) )
  3481. {
  3482. if ( !GetModelIndex() || !GetModelName() )
  3483. {
  3484. return SetTransmitState( FL_EDICT_DONTSEND );
  3485. }
  3486. }
  3487. // Always send the world
  3488. if ( GetModelIndex() == 1 )
  3489. {
  3490. return SetTransmitState( FL_EDICT_ALWAYS );
  3491. }
  3492. if ( IsEFlagSet( EFL_IN_SKYBOX ) )
  3493. {
  3494. return SetTransmitState( FL_EDICT_ALWAYS );
  3495. }
  3496. // by default cull against PVS
  3497. return SetTransmitState( FL_EDICT_PVSCHECK );
  3498. }
  3499. int CBaseEntity::DispatchUpdateTransmitState()
  3500. {
  3501. edict_t *ed = edict();
  3502. if ( m_nTransmitStateOwnedCounter != 0 )
  3503. return ed ? ed->m_fStateFlags : 0;
  3504. g_nInsideDispatchUpdateTransmitState++;
  3505. int ret = UpdateTransmitState();
  3506. g_nInsideDispatchUpdateTransmitState--;
  3507. return ret;
  3508. }
  3509. //-----------------------------------------------------------------------------
  3510. // Purpose: Note, an entity can override the send table ( e.g., to send less data or to send minimal data for
  3511. // objects ( prob. players ) that are not in the pvs.
  3512. // Input : **ppSendTable -
  3513. // *recipient -
  3514. // *pvs -
  3515. // Output : Returns true on success, false on failure.
  3516. //-----------------------------------------------------------------------------
  3517. int CBaseEntity::ShouldTransmit( const CCheckTransmitInfo *pInfo )
  3518. {
  3519. int fFlags = DispatchUpdateTransmitState();
  3520. if ( fFlags & FL_EDICT_PVSCHECK )
  3521. {
  3522. return FL_EDICT_PVSCHECK;
  3523. }
  3524. else if ( fFlags & FL_EDICT_ALWAYS )
  3525. {
  3526. return FL_EDICT_ALWAYS;
  3527. }
  3528. else if ( fFlags & FL_EDICT_DONTSEND )
  3529. {
  3530. return FL_EDICT_DONTSEND;
  3531. }
  3532. // if ( IsToolRecording() )
  3533. // {
  3534. // return FL_EDICT_ALWAYS;
  3535. // }
  3536. CBaseEntity *pRecipientEntity = CBaseEntity::Instance( pInfo->m_pClientEnt );
  3537. Assert( pRecipientEntity->IsPlayer() );
  3538. CBasePlayer *pRecipientPlayer = static_cast<CBasePlayer*>( pRecipientEntity );
  3539. // FIXME: Refactor once notion of "team" is moved into HL2 code
  3540. // Team rules may tell us that we should
  3541. if ( pRecipientPlayer->GetTeam() )
  3542. {
  3543. int iRet = pRecipientPlayer->GetTeam()->ShouldTransmitToPlayer( pRecipientPlayer, this );
  3544. if ( iRet )
  3545. return iRet;
  3546. }
  3547. // by default do a PVS check
  3548. return FL_EDICT_PVSCHECK;
  3549. }
  3550. //-----------------------------------------------------------------------------
  3551. // Rules about which entities need to transmit along with me
  3552. //-----------------------------------------------------------------------------
  3553. void CBaseEntity::SetTransmit( CCheckTransmitInfo *pInfo, bool bAlways )
  3554. {
  3555. int index = entindex();
  3556. // Are we already marked for transmission?
  3557. if ( pInfo->m_pTransmitEdict->Get( index ) )
  3558. return;
  3559. CServerNetworkProperty *pNetworkParent = NetworkProp()->GetNetworkParent();
  3560. pInfo->m_pTransmitEdict->Set( index );
  3561. // HLTV/Replay need to know if this entity is culled by PVS limits
  3562. if ( pInfo->m_pTransmitAlways )
  3563. {
  3564. // in HLTV/Replay mode always transmit entitys with move-parents
  3565. // HLTV/Replay can't resolve the mode-parents relationships
  3566. if ( bAlways || pNetworkParent )
  3567. {
  3568. // tell HLTV/Replay that this entity is always transmitted
  3569. pInfo->m_pTransmitAlways->Set( index );
  3570. }
  3571. else
  3572. {
  3573. // HLTV/Replay will PVS cull this entity, so update the
  3574. // node/cluster infos if necessary
  3575. m_Network.RecomputePVSInformation();
  3576. }
  3577. }
  3578. // Force our aiment and move parent to be sent.
  3579. if ( pNetworkParent )
  3580. {
  3581. CBaseEntity *pMoveParent = pNetworkParent->GetBaseEntity();
  3582. pMoveParent->SetTransmit( pInfo, bAlways );
  3583. }
  3584. }
  3585. //-----------------------------------------------------------------------------
  3586. // Returns which skybox the entity is in
  3587. //-----------------------------------------------------------------------------
  3588. CSkyCamera *CBaseEntity::GetEntitySkybox()
  3589. {
  3590. int area = engine->GetArea( WorldSpaceCenter() );
  3591. CSkyCamera *pCur = GetSkyCameraList();
  3592. while ( pCur )
  3593. {
  3594. if ( engine->CheckAreasConnected( area, pCur->m_skyboxData.area ) )
  3595. return pCur;
  3596. pCur = pCur->m_pNext;
  3597. }
  3598. return NULL;
  3599. }
  3600. bool CBaseEntity::DetectInSkybox()
  3601. {
  3602. if ( GetEntitySkybox() != NULL )
  3603. {
  3604. AddEFlags( EFL_IN_SKYBOX );
  3605. return true;
  3606. }
  3607. RemoveEFlags( EFL_IN_SKYBOX );
  3608. return false;
  3609. }
  3610. //------------------------------------------------------------------------------
  3611. // Computes a world-aligned bounding box that surrounds everything in the entity
  3612. //------------------------------------------------------------------------------
  3613. void CBaseEntity::ComputeWorldSpaceSurroundingBox( Vector *pMins, Vector *pMaxs )
  3614. {
  3615. // Should never get here.. only use USE_GAME_CODE with bounding boxes
  3616. // if you have an implementation for this method
  3617. Assert( 0 );
  3618. }
  3619. //------------------------------------------------------------------------------
  3620. // Purpose : If name exists returns name, otherwise returns classname
  3621. // Input :
  3622. // Output :
  3623. //------------------------------------------------------------------------------
  3624. const char *CBaseEntity::GetDebugName(void)
  3625. {
  3626. if ( this == NULL )
  3627. return "<<null>>";
  3628. if ( m_iName.Get() != NULL_STRING )
  3629. {
  3630. return STRING(m_iName.Get());
  3631. }
  3632. else
  3633. {
  3634. if ( ToBasePlayer( this ) )
  3635. {
  3636. return ToBasePlayer( this )->GetPlayerName();
  3637. }
  3638. return STRING(m_iClassname);
  3639. }
  3640. }
  3641. //------------------------------------------------------------------------------
  3642. // Purpose :
  3643. // Input :
  3644. // Output :
  3645. //------------------------------------------------------------------------------
  3646. void CBaseEntity::DrawInputOverlay(const char *szInputName, CBaseEntity *pCaller, variant_t Value)
  3647. {
  3648. char bigstring[1024];
  3649. if ( Value.FieldType() == FIELD_INTEGER )
  3650. {
  3651. Q_snprintf( bigstring,sizeof(bigstring), "%3.1f (%s,%d) <-- (%s)\n", gpGlobals->curtime, szInputName, Value.Int(), pCaller ? pCaller->GetDebugName() : NULL);
  3652. }
  3653. else if ( Value.FieldType() == FIELD_STRING )
  3654. {
  3655. Q_snprintf( bigstring,sizeof(bigstring), "%3.1f (%s,%s) <-- (%s)\n", gpGlobals->curtime, szInputName, Value.String(), pCaller ? pCaller->GetDebugName() : NULL);
  3656. }
  3657. else
  3658. {
  3659. Q_snprintf( bigstring,sizeof(bigstring), "%3.1f (%s) <-- (%s)\n", gpGlobals->curtime, szInputName, pCaller ? pCaller->GetDebugName() : NULL);
  3660. }
  3661. AddTimedOverlay(bigstring, 10.0);
  3662. if ( Value.FieldType() == FIELD_INTEGER )
  3663. {
  3664. DevMsg( 2, "input: (%s,%d) -> (%s,%s), from (%s)\n", szInputName, Value.Int(), STRING(m_iClassname), GetDebugName(), pCaller ? pCaller->GetDebugName() : NULL);
  3665. }
  3666. else if ( Value.FieldType() == FIELD_STRING )
  3667. {
  3668. DevMsg( 2, "input: (%s,%s) -> (%s,%s), from (%s)\n", szInputName, Value.String(), STRING(m_iClassname), GetDebugName(), pCaller ? pCaller->GetDebugName() : NULL);
  3669. }
  3670. else
  3671. DevMsg( 2, "input: (%s) -> (%s,%s), from (%s)\n", szInputName, STRING(m_iClassname), GetDebugName(), pCaller ? pCaller->GetDebugName() : NULL);
  3672. }
  3673. //------------------------------------------------------------------------------
  3674. // Purpose :
  3675. // Input :
  3676. // Output :
  3677. //------------------------------------------------------------------------------
  3678. void CBaseEntity::DrawOutputOverlay(CEventAction *ev)
  3679. {
  3680. // Print to entity
  3681. char bigstring[1024];
  3682. if ( ev->m_flDelay )
  3683. {
  3684. Q_snprintf( bigstring,sizeof(bigstring), "%3.1f (%s) --> (%s),%.1f) \n", gpGlobals->curtime, STRING(ev->m_iTargetInput), STRING(ev->m_iTarget), ev->m_flDelay);
  3685. }
  3686. else
  3687. {
  3688. Q_snprintf( bigstring,sizeof(bigstring), "%3.1f (%s) --> (%s)\n", gpGlobals->curtime, STRING(ev->m_iTargetInput), STRING(ev->m_iTarget));
  3689. }
  3690. AddTimedOverlay(bigstring, 10.0);
  3691. // Now print to the console
  3692. if ( ev->m_flDelay )
  3693. {
  3694. DevMsg( 2, "output: (%s,%s) -> (%s,%s,%.1f)\n", STRING(m_iClassname), GetDebugName(), STRING(ev->m_iTarget), STRING(ev->m_iTargetInput), ev->m_flDelay );
  3695. }
  3696. else
  3697. {
  3698. DevMsg( 2, "output: (%s,%s) -> (%s,%s)\n", STRING(m_iClassname), GetDebugName(), STRING(ev->m_iTarget), STRING(ev->m_iTargetInput) );
  3699. }
  3700. }
  3701. //-----------------------------------------------------------------------------
  3702. // Entity events... these are events targetted to a particular entity
  3703. // Each event defines its own well-defined event data structure
  3704. //-----------------------------------------------------------------------------
  3705. void CBaseEntity::OnEntityEvent( EntityEvent_t event, void *pEventData )
  3706. {
  3707. switch( event )
  3708. {
  3709. case ENTITY_EVENT_WATER_TOUCH:
  3710. {
  3711. int nContents = size_cast< int >( (intp)pEventData );
  3712. if ( !nContents || (nContents & CONTENTS_WATER) )
  3713. {
  3714. ++m_nWaterTouch;
  3715. }
  3716. if ( nContents & CONTENTS_SLIME )
  3717. {
  3718. ++m_nSlimeTouch;
  3719. }
  3720. }
  3721. break;
  3722. case ENTITY_EVENT_WATER_UNTOUCH:
  3723. {
  3724. int nContents = size_cast< int >( (intp)pEventData );
  3725. if ( !nContents || (nContents & CONTENTS_WATER) )
  3726. {
  3727. --m_nWaterTouch;
  3728. }
  3729. if ( nContents & CONTENTS_SLIME )
  3730. {
  3731. --m_nSlimeTouch;
  3732. }
  3733. }
  3734. break;
  3735. default:
  3736. return;
  3737. }
  3738. // Only do this for vphysics objects
  3739. if ( GetMoveType() != MOVETYPE_VPHYSICS )
  3740. return;
  3741. int nNewContents = 0;
  3742. if ( m_nWaterTouch > 0 )
  3743. {
  3744. nNewContents |= CONTENTS_WATER;
  3745. }
  3746. if ( m_nSlimeTouch > 0 )
  3747. {
  3748. nNewContents |= CONTENTS_SLIME;
  3749. }
  3750. if (( nNewContents & MASK_WATER ) == 0)
  3751. {
  3752. SetWaterLevel( 0 );
  3753. SetWaterType( CONTENTS_EMPTY );
  3754. return;
  3755. }
  3756. SetWaterLevel( 1 );
  3757. SetWaterType( nNewContents );
  3758. }
  3759. ConVar ent_messages_draw( "ent_messages_draw", "0", FCVAR_CHEAT, "Visualizes all entity input/output activity." );
  3760. //-----------------------------------------------------------------------------
  3761. // Purpose: calls the appropriate message mapped function in the entity according
  3762. // to the fired action.
  3763. // Input : char *szInputName - input destination
  3764. // *pActivator - entity which initiated this sequence of actions
  3765. // *pCaller - entity from which this event is sent
  3766. // Output : Returns true on success, false on failure.
  3767. //-----------------------------------------------------------------------------
  3768. bool CBaseEntity::AcceptInput( const char *szInputName, CBaseEntity *pActivator, CBaseEntity *pCaller, variant_t Value, int outputID )
  3769. {
  3770. if ( ent_messages_draw.GetBool() )
  3771. {
  3772. if ( pCaller != NULL )
  3773. {
  3774. NDebugOverlay::Line( pCaller->GetAbsOrigin(), GetAbsOrigin(), 255, 255, 255, false, 3 );
  3775. NDebugOverlay::Box( pCaller->GetAbsOrigin(), Vector(-4, -4, -4), Vector(4, 4, 4), 255, 0, 0, 0, 3 );
  3776. }
  3777. NDebugOverlay::Text( GetAbsOrigin(), szInputName, false, 3 );
  3778. NDebugOverlay::Box( GetAbsOrigin(), Vector(-4, -4, -4), Vector(4, 4, 4), 0, 255, 0, 0, 3 );
  3779. }
  3780. // loop through the data description list, restoring each data desc block
  3781. for ( datamap_t *dmap = GetDataDescMap(); dmap != NULL; dmap = dmap->baseMap )
  3782. {
  3783. // search through all the actions in the data description, looking for a match
  3784. for ( int i = 0; i < dmap->dataNumFields; i++ )
  3785. {
  3786. if ( dmap->dataDesc[i].flags & FTYPEDESC_INPUT )
  3787. {
  3788. if ( !Q_stricmp(dmap->dataDesc[i].externalName, szInputName) )
  3789. {
  3790. // found a match
  3791. if ( developer.GetBool() )
  3792. {
  3793. char szBuffer[256];
  3794. // mapper debug message
  3795. if (pCaller != NULL)
  3796. {
  3797. Q_snprintf( szBuffer, sizeof(szBuffer), "(%0.2f) input %s: %s.%s(%s)\n", gpGlobals->curtime, STRING(pCaller->m_iName.Get()), GetDebugName(), szInputName, Value.String() );
  3798. }
  3799. else
  3800. {
  3801. Q_snprintf( szBuffer, sizeof(szBuffer), "(%0.2f) input <NULL>: %s.%s(%s)\n", gpGlobals->curtime, GetDebugName(), szInputName, Value.String() );
  3802. }
  3803. DevMsg( 2, "%s", szBuffer );
  3804. ADD_DEBUG_HISTORY( HISTORY_ENTITY_IO, szBuffer );
  3805. if (m_debugOverlays & OVERLAY_MESSAGE_BIT)
  3806. {
  3807. DrawInputOverlay(szInputName,pCaller,Value);
  3808. }
  3809. }
  3810. // convert the value if necessary
  3811. if ( Value.FieldType() != dmap->dataDesc[i].fieldType )
  3812. {
  3813. if ( !(Value.FieldType() == FIELD_VOID && dmap->dataDesc[i].fieldType == FIELD_STRING) ) // allow empty strings
  3814. {
  3815. if ( !Value.Convert( (fieldtype_t)dmap->dataDesc[i].fieldType ) )
  3816. {
  3817. // bad conversion
  3818. Warning( "!! ERROR: bad input/output link:\n!! %s(%s,%s) doesn't match type from %s(%s)\n",
  3819. STRING(m_iClassname), GetDebugName(), szInputName,
  3820. ( pCaller != NULL ) ? STRING(pCaller->m_iClassname) : "<null>",
  3821. ( pCaller != NULL ) ? STRING(pCaller->m_iName.Get()) : "<null>" );
  3822. return false;
  3823. }
  3824. }
  3825. }
  3826. // call the input handler, or if there is none just set the value
  3827. inputfunc_t pfnInput = dmap->dataDesc[i].inputFunc;
  3828. if ( pfnInput )
  3829. {
  3830. // Package the data into a struct for passing to the input handler.
  3831. inputdata_t data;
  3832. data.pActivator = pActivator;
  3833. data.pCaller = pCaller;
  3834. data.value = Value;
  3835. data.nOutputID = outputID;
  3836. // Now, see if there's a function named Input<Name of Input> in this entity's script file.
  3837. // If so, execute it and let it decide whether to allow the default behavior to also execute.
  3838. bool bCallInputFunc = true; // Always assume default behavior (do call the input function)
  3839. ScriptVariant_t functionReturn;
  3840. if ( m_ScriptScope.IsInitialized() )
  3841. {
  3842. char szScriptFunctionName[255];
  3843. Q_strcpy( szScriptFunctionName, "Input" );
  3844. Q_strcat( szScriptFunctionName, szInputName, 255 );
  3845. g_pScriptVM->SetValue( "activator", ( pActivator ) ? ScriptVariant_t( pActivator->GetScriptInstance() ) : SCRIPT_VARIANT_NULL );
  3846. g_pScriptVM->SetValue( "caller", ( pCaller ) ? ScriptVariant_t( pCaller->GetScriptInstance() ) : SCRIPT_VARIANT_NULL );
  3847. if( CallScriptFunction( szScriptFunctionName, &functionReturn ) )
  3848. {
  3849. bCallInputFunc = functionReturn.m_bool;
  3850. }
  3851. }
  3852. if( bCallInputFunc )
  3853. {
  3854. (this->*pfnInput)( data );
  3855. }
  3856. if ( m_ScriptScope.IsInitialized() )
  3857. {
  3858. g_pScriptVM->ClearValue( "activator" );
  3859. g_pScriptVM->ClearValue( "caller" );
  3860. }
  3861. }
  3862. else if ( dmap->dataDesc[i].flags & FTYPEDESC_KEY )
  3863. {
  3864. // set the value directly
  3865. Value.SetOther( ((char*)this) + dmap->dataDesc[i].fieldOffset);
  3866. // TODO: if this becomes evil and causes too many full entity updates, then we should make
  3867. // a macro like this:
  3868. //
  3869. // define MAKE_INPUTVAR(x) void Note##x##Modified() { x.GetForModify(); }
  3870. //
  3871. // Then the datadesc points at that function and we call it here. The only pain is to add
  3872. // that function for all the DEFINE_INPUT calls.
  3873. NetworkStateChanged();
  3874. }
  3875. return true;
  3876. }
  3877. }
  3878. }
  3879. }
  3880. DevMsg( 2, "unhandled input: (%s) -> (%s,%s)\n", szInputName, STRING(m_iClassname), GetDebugName()/*,", from (%s,%s)" STRING(pCaller->m_iClassname), STRING(pCaller->m_iName)*/ );
  3881. return false;
  3882. }
  3883. //-----------------------------------------------------------------------------
  3884. // Purpose: Input handler for the entity alpha.
  3885. // Input : nAlpha - Alpha value (0 - 255).
  3886. //-----------------------------------------------------------------------------
  3887. void CBaseEntity::InputAlpha( inputdata_t &inputdata )
  3888. {
  3889. SetRenderAlpha( clamp( inputdata.value.Int(), 0, 255 ) );
  3890. }
  3891. //-----------------------------------------------------------------------------
  3892. // Activate alternative sorting
  3893. //-----------------------------------------------------------------------------
  3894. void CBaseEntity::InputAlternativeSorting( inputdata_t &inputdata )
  3895. {
  3896. m_bAlternateSorting = inputdata.value.Bool();
  3897. }
  3898. //-----------------------------------------------------------------------------
  3899. // Purpose: Input handler for the entity color. Ignores alpha since that is handled
  3900. // by a separate input handler.
  3901. // Input : Color32 new value for color (alpha is ignored).
  3902. //-----------------------------------------------------------------------------
  3903. void CBaseEntity::InputColor( inputdata_t &inputdata )
  3904. {
  3905. color32 clr = inputdata.value.Color32();
  3906. SetRenderColor( clr.r, clr.g, clr.b );
  3907. }
  3908. //-----------------------------------------------------------------------------
  3909. // Purpose: Called whenever the entity is 'Used'. This can be when a player hits
  3910. // use, or when an entity targets it without an output name (legacy entities)
  3911. //-----------------------------------------------------------------------------
  3912. void CBaseEntity::InputUse( inputdata_t &inputdata )
  3913. {
  3914. Use( inputdata.pActivator, inputdata.pCaller, (USE_TYPE)inputdata.nOutputID, 0 );
  3915. IGameEvent *event = gameeventmanager->CreateEvent( "player_use" );
  3916. if ( event )
  3917. {
  3918. event->SetInt( "userid", inputdata.pActivator && inputdata.pActivator->IsPlayer() ? static_cast< CBasePlayer* >( inputdata.pActivator )->GetUserID() : 0 );
  3919. event->SetInt( "entity", entindex() );
  3920. gameeventmanager->FireEvent( event );
  3921. }
  3922. }
  3923. //-----------------------------------------------------------------------------
  3924. // Purpose: Reads an output variable, by string name, from an entity
  3925. // Input : char *varName - the string name of the variable
  3926. // variant_t *var - the value is stored here
  3927. // Output : Returns true on success, false on failure.
  3928. //-----------------------------------------------------------------------------
  3929. bool CBaseEntity::ReadKeyField( const char *varName, variant_t *var )
  3930. {
  3931. if ( !varName )
  3932. return false;
  3933. // loop through the data description list, restoring each data desc block
  3934. for ( datamap_t *dmap = GetDataDescMap(); dmap != NULL; dmap = dmap->baseMap )
  3935. {
  3936. // search through all the readable fields in the data description, looking for a match
  3937. for ( int i = 0; i < dmap->dataNumFields; i++ )
  3938. {
  3939. if ( dmap->dataDesc[i].flags & (FTYPEDESC_OUTPUT | FTYPEDESC_KEY) )
  3940. {
  3941. if ( !Q_stricmp(dmap->dataDesc[i].externalName, varName) )
  3942. {
  3943. var->Set( dmap->dataDesc[i].fieldType, ((char*)this) + dmap->dataDesc[i].fieldOffset);
  3944. return true;
  3945. }
  3946. }
  3947. }
  3948. }
  3949. return false;
  3950. }
  3951. //-----------------------------------------------------------------------------
  3952. // Purpose: Sets the damage filter on the object
  3953. //-----------------------------------------------------------------------------
  3954. void CBaseEntity::InputEnableDamageForces( inputdata_t &inputdata )
  3955. {
  3956. RemoveEFlags( EFL_NO_DAMAGE_FORCES );
  3957. }
  3958. void CBaseEntity::InputDisableDamageForces( inputdata_t &inputdata )
  3959. {
  3960. AddEFlags( EFL_NO_DAMAGE_FORCES );
  3961. }
  3962. //-----------------------------------------------------------------------------
  3963. // Purpose: Sets the damage filter on the object
  3964. //-----------------------------------------------------------------------------
  3965. void CBaseEntity::InputSetDamageFilter( inputdata_t &inputdata )
  3966. {
  3967. // Get a handle to my damage filter entity if there is one.
  3968. m_iszDamageFilterName = inputdata.value.StringID();
  3969. if ( m_iszDamageFilterName != NULL_STRING )
  3970. {
  3971. m_hDamageFilter = gEntList.FindEntityByName( NULL, m_iszDamageFilterName );
  3972. }
  3973. else
  3974. {
  3975. m_hDamageFilter = NULL;
  3976. }
  3977. }
  3978. //-----------------------------------------------------------------------------
  3979. // Purpose: Marks the entity for deletion
  3980. //-----------------------------------------------------------------------------
  3981. void CBaseEntity::InputKill( inputdata_t &inputdata )
  3982. {
  3983. // tell owner ( if any ) that we're dead.This is mostly for NPCMaker functionality.
  3984. CBaseEntity *pOwner = GetOwnerEntity();
  3985. if ( pOwner )
  3986. {
  3987. pOwner->DeathNotice( this );
  3988. SetOwnerEntity( NULL );
  3989. }
  3990. if( IsPlayer() )
  3991. {
  3992. //never just delete players
  3993. engine->ServerCommand( UTIL_VarArgs( "kickid %d CBaseEntity::InputKill()\n", engine->GetPlayerUserId( edict() ) ) );
  3994. }
  3995. else
  3996. {
  3997. UTIL_Remove( this );
  3998. }
  3999. }
  4000. void CBaseEntity::InputKillHierarchy( inputdata_t &inputdata )
  4001. {
  4002. CBaseEntity *pChild, *pNext;
  4003. for ( pChild = FirstMoveChild(); pChild; pChild = pNext )
  4004. {
  4005. pNext = pChild->NextMovePeer();
  4006. pChild->InputKillHierarchy( inputdata );
  4007. }
  4008. // tell owner ( if any ) that we're dead. This is mostly for NPCMaker functionality.
  4009. CBaseEntity *pOwner = GetOwnerEntity();
  4010. if ( pOwner )
  4011. {
  4012. pOwner->DeathNotice( this );
  4013. SetOwnerEntity( NULL );
  4014. }
  4015. UTIL_Remove( this );
  4016. }
  4017. //------------------------------------------------------------------------------
  4018. // Purpose: Input handler for changing this entity's movement parent.
  4019. //------------------------------------------------------------------------------
  4020. void CBaseEntity::InputSetParent( inputdata_t &inputdata )
  4021. {
  4022. // If we had a parent attachment, clear it, because it's no longer valid.
  4023. if ( m_iParentAttachment )
  4024. {
  4025. m_iParentAttachment = 0;
  4026. }
  4027. SetParent( inputdata.value.StringID(), inputdata.pActivator );
  4028. }
  4029. //------------------------------------------------------------------------------
  4030. // Purpose:
  4031. //------------------------------------------------------------------------------
  4032. void CBaseEntity::SetParentAttachment( const char *szInputName, const char *szAttachment, bool bMaintainOffset )
  4033. {
  4034. // Must have a parent
  4035. if ( !m_pParent )
  4036. {
  4037. Warning("ERROR: Tried to %s for entity %s (%s), but it has no parent.\n", szInputName, GetClassname(), GetDebugName() );
  4038. return;
  4039. }
  4040. // Valid only on CBaseAnimating
  4041. CBaseAnimating *pAnimating = m_pParent->GetBaseAnimating();
  4042. if ( !pAnimating )
  4043. {
  4044. Warning("ERROR: Tried to %s for entity %s (%s), but its parent has no model.\n", szInputName, GetClassname(), GetDebugName() );
  4045. return;
  4046. }
  4047. // Lookup the attachment
  4048. int iAttachment = pAnimating->LookupAttachment( szAttachment );
  4049. if ( !iAttachment )
  4050. {
  4051. Warning("ERROR: Tried to %s for entity %s (%s), but it has no attachment named %s.\n", szInputName, GetClassname(), GetDebugName(), szAttachment );
  4052. return;
  4053. }
  4054. m_iParentAttachment = iAttachment;
  4055. SetParent( m_pParent, m_iParentAttachment );
  4056. // Now move myself directly onto the attachment point
  4057. SetMoveType( MOVETYPE_NONE );
  4058. if ( !bMaintainOffset )
  4059. {
  4060. SetLocalOrigin( vec3_origin );
  4061. SetLocalAngles( vec3_angle );
  4062. }
  4063. }
  4064. //-----------------------------------------------------------------------------
  4065. // Purpose: Input handler for changing this entity's movement parent's attachment point
  4066. //-----------------------------------------------------------------------------
  4067. void CBaseEntity::InputSetParentAttachment( inputdata_t &inputdata )
  4068. {
  4069. SetParentAttachment( "SetParentAttachment", inputdata.value.String(), false );
  4070. }
  4071. //-----------------------------------------------------------------------------
  4072. // Purpose: Input handler for changing this entity's movement parent's attachment point
  4073. //-----------------------------------------------------------------------------
  4074. void CBaseEntity::InputSetParentAttachmentMaintainOffset( inputdata_t &inputdata )
  4075. {
  4076. SetParentAttachment( "SetParentAttachmentMaintainOffset", inputdata.value.String(), true );
  4077. }
  4078. //------------------------------------------------------------------------------
  4079. // Purpose: Input handler for clearing this entity's movement parent.
  4080. //------------------------------------------------------------------------------
  4081. void CBaseEntity::InputClearParent( inputdata_t &inputdata )
  4082. {
  4083. SetParent( NULL );
  4084. }
  4085. //------------------------------------------------------------------------------
  4086. // Purpose: Input handler for setting the entities local origin
  4087. //------------------------------------------------------------------------------
  4088. void CBaseEntity::InputSetLocalOrigin( inputdata_t &inputdata )
  4089. {
  4090. Vector tmpVec;
  4091. if (sscanf(inputdata.value.String(), "[%f %f %f]", &tmpVec[0], &tmpVec[1], &tmpVec[2]) == 0)
  4092. {
  4093. // Try sucking out 3 floats with no []s
  4094. sscanf(inputdata.value.String(), "%f %f %f", &tmpVec[0], &tmpVec[1], &tmpVec[2]);
  4095. }
  4096. // DevMsg("%s : InputSetLocalOrigin( %f %f %f )\n", GetDebugName(), tmpVec.x, tmpVec.y, tmpVec.z );
  4097. SetLocalOrigin( tmpVec );
  4098. }
  4099. //------------------------------------------------------------------------------
  4100. // Purpose: Input handler for setting the entities local angles
  4101. //------------------------------------------------------------------------------
  4102. void CBaseEntity::InputSetLocalAngles( inputdata_t &inputdata )
  4103. {
  4104. Vector tmpVec;
  4105. if (sscanf(inputdata.value.String(), "[%f %f %f]", &tmpVec[0], &tmpVec[1], &tmpVec[2]) == 0)
  4106. {
  4107. // Try sucking out 3 floats with no []s
  4108. sscanf(inputdata.value.String(), "%f %f %f", &tmpVec[0], &tmpVec[1], &tmpVec[2]);
  4109. }
  4110. // DevMsg("%s : InputSetLocalAngles( %f %f %f )\n", GetDebugName(), tmpVec.x, tmpVec.y, tmpVec.z );
  4111. QAngle angles( tmpVec.x, tmpVec.y, tmpVec.z );
  4112. SetLocalAngles( angles );
  4113. }
  4114. //------------------------------------------------------------------------------
  4115. // Purpose : Returns velcocity of base entity. If physically simulated gets
  4116. // velocity from physics object
  4117. // Input :
  4118. // Output :
  4119. //------------------------------------------------------------------------------
  4120. void CBaseEntity::GetVelocity(Vector *vVelocity, AngularImpulse *vAngVelocity)
  4121. {
  4122. if (GetMoveType()==MOVETYPE_VPHYSICS && m_pPhysicsObject)
  4123. {
  4124. m_pPhysicsObject->GetVelocity(vVelocity,vAngVelocity);
  4125. }
  4126. else
  4127. {
  4128. if (vVelocity != NULL)
  4129. {
  4130. *vVelocity = GetAbsVelocity();
  4131. }
  4132. if (vAngVelocity != NULL)
  4133. {
  4134. QAngle tmp = GetLocalAngularVelocity();
  4135. QAngleToAngularImpulse( tmp, *vAngVelocity );
  4136. }
  4137. }
  4138. }
  4139. bool CBaseEntity::IsMoving()
  4140. {
  4141. Vector velocity;
  4142. GetVelocity( &velocity, NULL );
  4143. return velocity != vec3_origin;
  4144. }
  4145. //-----------------------------------------------------------------------------
  4146. // Purpose: Retrieves the coordinate frame for this entity.
  4147. // Input : forward - Receives the entity's forward vector.
  4148. // right - Receives the entity's right vector.
  4149. // up - Receives the entity's up vector.
  4150. //-----------------------------------------------------------------------------
  4151. void CBaseEntity::GetVectors(Vector* pForward, Vector* pRight, Vector* pUp) const
  4152. {
  4153. // This call is necessary to cause m_rgflCoordinateFrame to be recomputed
  4154. const matrix3x4_t &entityToWorld = EntityToWorldTransform();
  4155. if (pForward != NULL)
  4156. {
  4157. MatrixGetColumn( entityToWorld, 0, *pForward );
  4158. }
  4159. if (pRight != NULL)
  4160. {
  4161. MatrixGetColumn( entityToWorld, 1, *pRight );
  4162. *pRight *= -1.0f;
  4163. }
  4164. if (pUp != NULL)
  4165. {
  4166. MatrixGetColumn( entityToWorld, 2, *pUp );
  4167. }
  4168. }
  4169. //-----------------------------------------------------------------------------
  4170. // Purpose: Sets the model, validates that it's of the appropriate type
  4171. // Input : *szModelName -
  4172. //-----------------------------------------------------------------------------
  4173. void CBaseEntity::SetModel( const char *szModelName )
  4174. {
  4175. int modelIndex = modelinfo->GetModelIndex( szModelName );
  4176. const model_t *model = modelinfo->GetModel( modelIndex );
  4177. if ( model && modelinfo->GetModelType( model ) != mod_brush )
  4178. {
  4179. Msg( "Setting CBaseEntity to non-brush model %s\n", szModelName );
  4180. }
  4181. UTIL_SetModel( this, szModelName );
  4182. }
  4183. //------------------------------------------------------------------------------
  4184. CStudioHdr *CBaseEntity::OnNewModel()
  4185. {
  4186. // Do nothing.
  4187. return NULL;
  4188. }
  4189. //-----------------------------------------------------------------------------
  4190. // Purpose: Called once per frame after the server frame loop has finished and after all messages being
  4191. // sent to clients have been sent. NOTE: Only called if scheduled via AddPostClientMessageEntity() !
  4192. //-----------------------------------------------------------------------------
  4193. void CBaseEntity::PostClientMessagesSent( void )
  4194. {
  4195. // Remove nointerp flags from entity after every frame
  4196. if ( IsEffectActive( EF_NOINTERP ) )
  4197. {
  4198. RemoveEffects( EF_NOINTERP );
  4199. }
  4200. }
  4201. //================================================================================
  4202. // TEAM HANDLING
  4203. //================================================================================
  4204. void CBaseEntity::InputSetTeam( inputdata_t &inputdata )
  4205. {
  4206. if ( IsPlayer() )
  4207. return;
  4208. ChangeTeam( inputdata.value.Int() );
  4209. }
  4210. //-----------------------------------------------------------------------------
  4211. // Purpose: Put the entity in the specified team
  4212. //-----------------------------------------------------------------------------
  4213. void CBaseEntity::ChangeTeam( int iTeamNum )
  4214. {
  4215. m_iTeamNum = iTeamNum;
  4216. }
  4217. //-----------------------------------------------------------------------------
  4218. // Get the Team this entity is on
  4219. //-----------------------------------------------------------------------------
  4220. CTeam *CBaseEntity::GetTeam( void ) const
  4221. {
  4222. return GetGlobalTeam( m_iTeamNum );
  4223. }
  4224. //-----------------------------------------------------------------------------
  4225. // Purpose: Returns true if these players are both in at least one team together
  4226. //-----------------------------------------------------------------------------
  4227. bool CBaseEntity::InSameTeam( CBaseEntity *pEntity ) const
  4228. {
  4229. if ( !pEntity )
  4230. return false;
  4231. return ( pEntity->GetTeam() == GetTeam() );
  4232. }
  4233. //-----------------------------------------------------------------------------
  4234. // Purpose: Returns the string name of the players team
  4235. //-----------------------------------------------------------------------------
  4236. const char *CBaseEntity::TeamID( void ) const
  4237. {
  4238. if ( GetTeam() == NULL )
  4239. return "";
  4240. return GetTeam()->GetName();
  4241. }
  4242. //-----------------------------------------------------------------------------
  4243. // Purpose: Returns true if the player is on the same team
  4244. //-----------------------------------------------------------------------------
  4245. bool CBaseEntity::IsInTeam( CTeam *pTeam ) const
  4246. {
  4247. return ( GetTeam() == pTeam );
  4248. }
  4249. //-----------------------------------------------------------------------------
  4250. // Purpose:
  4251. //-----------------------------------------------------------------------------
  4252. int CBaseEntity::GetTeamNumber( void ) const
  4253. {
  4254. return m_iTeamNum;
  4255. }
  4256. //-----------------------------------------------------------------------------
  4257. // Purpose:
  4258. //-----------------------------------------------------------------------------
  4259. int CBaseEntity::GetPendingTeamNumber( void ) const
  4260. {
  4261. return m_iPendingTeamNum;
  4262. }
  4263. //-----------------------------------------------------------------------------
  4264. // Purpose:
  4265. //-----------------------------------------------------------------------------
  4266. bool CBaseEntity::IsInAnyTeam( void ) const
  4267. {
  4268. return ( GetTeam() != NULL );
  4269. }
  4270. //-----------------------------------------------------------------------------
  4271. // Purpose: Returns the type of damage that this entity inflicts.
  4272. //-----------------------------------------------------------------------------
  4273. int CBaseEntity::GetDamageType() const
  4274. {
  4275. return DMG_GENERIC;
  4276. }
  4277. //-----------------------------------------------------------------------------
  4278. // process notification
  4279. //-----------------------------------------------------------------------------
  4280. void CBaseEntity::NotifySystemEvent( CBaseEntity *pNotify, notify_system_event_t eventType, const notify_system_event_params_t &params )
  4281. {
  4282. }
  4283. //-----------------------------------------------------------------------------
  4284. // Purpose: Holds an entity's previous abs origin and angles at the time of
  4285. // teleportation. Used for child & constrained entity fixup to prevent
  4286. // lazy updates of abs origins and angles from messing things up.
  4287. //-----------------------------------------------------------------------------
  4288. struct TeleportListEntry_t
  4289. {
  4290. CBaseEntity *pEntity;
  4291. Vector prevAbsOrigin;
  4292. QAngle prevAbsAngles;
  4293. };
  4294. static void TeleportEntity( CBaseEntity *pSourceEntity, TeleportListEntry_t &entry, const Vector *newPosition, const QAngle *newAngles, const Vector *newVelocity, bool bUseSlowHighAccuracyContacts )
  4295. {
  4296. CBaseEntity *pTeleport = entry.pEntity;
  4297. Vector prevOrigin = entry.prevAbsOrigin;
  4298. QAngle prevAngles = entry.prevAbsAngles;
  4299. int nSolidFlags = pTeleport->GetSolidFlags();
  4300. IPhysicsObject *pPhys = pTeleport->VPhysicsGetObject();
  4301. bool bEnablePhysCollision = false;
  4302. // by default we use a slow method that keeps contacts accurate.
  4303. // when desired it is possible to use a quicker method that trades off accuracy to save CPU
  4304. if ( pPhys && bUseSlowHighAccuracyContacts )
  4305. {
  4306. bEnablePhysCollision = pPhys->IsCollisionEnabled();
  4307. if ( bEnablePhysCollision )
  4308. {
  4309. pPhys->EnableCollisions( false );
  4310. }
  4311. pTeleport->AddSolidFlags( FSOLID_NOT_SOLID );
  4312. }
  4313. // I'm teleporting myself
  4314. if ( pSourceEntity == pTeleport )
  4315. {
  4316. if ( newAngles )
  4317. {
  4318. pTeleport->SetLocalAngles( *newAngles );
  4319. if ( pTeleport->IsPlayer() )
  4320. {
  4321. CBasePlayer *pPlayer = (CBasePlayer *)pTeleport;
  4322. pPlayer->SnapEyeAngles( *newAngles );
  4323. }
  4324. }
  4325. if ( newVelocity )
  4326. {
  4327. if ( !pPhys || pTeleport->GetMoveType() != MOVETYPE_VPHYSICS )
  4328. {
  4329. pTeleport->SetAbsVelocity( *newVelocity );
  4330. }
  4331. pTeleport->SetBaseVelocity( vec3_origin );
  4332. }
  4333. if ( newPosition )
  4334. {
  4335. pTeleport->AddEffects( EF_NOINTERP );
  4336. UTIL_SetOrigin( pTeleport, *newPosition );
  4337. }
  4338. }
  4339. else
  4340. {
  4341. // My parent is teleporting, just update my position & physics
  4342. pTeleport->CalcAbsolutePosition();
  4343. }
  4344. // handle physics objects / shadows
  4345. if ( pPhys )
  4346. {
  4347. if ( newVelocity )
  4348. {
  4349. pPhys->SetVelocity( newVelocity, NULL );
  4350. }
  4351. const QAngle *rotAngles = &pTeleport->GetAbsAngles();
  4352. // don't rotate physics on players or bbox entities
  4353. if (pTeleport->IsPlayer() || pTeleport->GetSolid() == SOLID_BBOX )
  4354. {
  4355. if ( newAngles )
  4356. {
  4357. rotAngles = newAngles;
  4358. }
  4359. else
  4360. {
  4361. rotAngles = &vec3_angle;
  4362. }
  4363. }
  4364. pPhys->SetPosition( pTeleport->GetAbsOrigin(), *rotAngles, bUseSlowHighAccuracyContacts );
  4365. }
  4366. g_pNotify->ReportTeleportEvent( pTeleport, prevOrigin, prevAngles, true );
  4367. if ( pPhys && bUseSlowHighAccuracyContacts )
  4368. {
  4369. pTeleport->SetSolidFlags( nSolidFlags );
  4370. if ( bEnablePhysCollision )
  4371. {
  4372. pPhys->EnableCollisions( true );
  4373. }
  4374. }
  4375. }
  4376. //-----------------------------------------------------------------------------
  4377. // Purpose: Recurses an entity hierarchy and fills out a list of all entities
  4378. // in the hierarchy with their current origins and angles.
  4379. //
  4380. // This list is necessary to keep lazy updates of abs origins and angles
  4381. // from messing up our child/constrained entity fixup.
  4382. //-----------------------------------------------------------------------------
  4383. static void BuildTeleportList_r( CBaseEntity *pTeleport, CUtlVector<TeleportListEntry_t> &teleportList )
  4384. {
  4385. TeleportListEntry_t entry;
  4386. entry.pEntity = pTeleport;
  4387. entry.prevAbsOrigin = pTeleport->GetAbsOrigin();
  4388. entry.prevAbsAngles = pTeleport->GetAbsAngles();
  4389. teleportList.AddToTail( entry );
  4390. CBaseEntity *pList = pTeleport->FirstMoveChild();
  4391. while ( pList )
  4392. {
  4393. BuildTeleportList_r( pList, teleportList );
  4394. pList = pList->NextMovePeer();
  4395. }
  4396. }
  4397. static CUtlVector<CBaseEntity *> g_TeleportStack;
  4398. void CBaseEntity::Teleport( const Vector *newPosition, const QAngle *newAngles, const Vector *newVelocity, bool bUseSlowHighAccuracyContacts )
  4399. {
  4400. if ( g_TeleportStack.Find( this ) >= 0 )
  4401. return;
  4402. int index = g_TeleportStack.AddToTail( this );
  4403. CUtlVector<TeleportListEntry_t> teleportList;
  4404. BuildTeleportList_r( this, teleportList );
  4405. int i;
  4406. for ( i = 0; i < teleportList.Count(); i++)
  4407. {
  4408. TeleportEntity( this, teleportList[i], newPosition, newAngles, newVelocity, bUseSlowHighAccuracyContacts );
  4409. }
  4410. Assert( g_TeleportStack[index] == this );
  4411. g_TeleportStack.FastRemove( index );
  4412. // FIXME: add an initializer function to StepSimulationData
  4413. StepSimulationData *step = ( StepSimulationData * )GetDataObject( STEPSIMULATION );
  4414. if (step)
  4415. {
  4416. Q_memset( step, 0, sizeof( *step ) );
  4417. }
  4418. }
  4419. // Stuff implemented for weapon prediction code
  4420. void CBaseEntity::SetSize( const Vector &vecMin, const Vector &vecMax )
  4421. {
  4422. UTIL_SetSize( this, vecMin, vecMax );
  4423. }
  4424. CStudioHdr *ModelSoundsCache_LoadModel( const char *filename )
  4425. {
  4426. // Load the file
  4427. int idx = engine->PrecacheModel( filename, true );
  4428. if ( idx != -1 )
  4429. {
  4430. model_t *mdl = (model_t *)modelinfo->GetModel( idx );
  4431. if ( mdl )
  4432. {
  4433. CStudioHdr *studioHdr = new CStudioHdr( modelinfo->GetStudiomodel( mdl ), mdlcache );
  4434. if ( studioHdr->IsValid() )
  4435. {
  4436. return studioHdr;
  4437. }
  4438. }
  4439. }
  4440. return NULL;
  4441. }
  4442. void ModelSoundsCache_FinishModel( CStudioHdr *hdr )
  4443. {
  4444. Assert( hdr );
  4445. delete hdr;
  4446. }
  4447. void ModelSoundsCache_PrecacheScriptSound( const char *soundname )
  4448. {
  4449. CBaseEntity::PrecacheScriptSound( soundname );
  4450. }
  4451. static CUtlCachedFileData< CModelSoundsCache > g_ModelSoundsCache( "modelsounds.cache", MODELSOUNDSCACHE_VERSION, 0, UTL_CACHED_FILE_USE_FILESIZE, false );
  4452. void ClearModelSoundsCache()
  4453. {
  4454. if ( IsGameConsole() || engine->IsCreatingXboxReslist() )
  4455. {
  4456. return;
  4457. }
  4458. g_ModelSoundsCache.Reload();
  4459. }
  4460. //-----------------------------------------------------------------------------
  4461. // Purpose:
  4462. // Output : Returns true on success, false on failure.
  4463. //-----------------------------------------------------------------------------
  4464. bool ModelSoundsCacheInit()
  4465. {
  4466. if ( IsGameConsole() || engine->IsCreatingXboxReslist() )
  4467. {
  4468. return true;
  4469. }
  4470. return g_ModelSoundsCache.Init();
  4471. }
  4472. //-----------------------------------------------------------------------------
  4473. // Purpose:
  4474. //-----------------------------------------------------------------------------
  4475. void ModelSoundsCacheShutdown()
  4476. {
  4477. if ( IsGameConsole() || engine->IsCreatingXboxReslist() )
  4478. {
  4479. return;
  4480. }
  4481. g_ModelSoundsCache.Shutdown();
  4482. }
  4483. static CUtlSymbolTable g_ModelSoundsSymbolHelper( 0, 32, true );
  4484. class CModelSoundsCacheSaver: public CAutoGameSystem
  4485. {
  4486. public:
  4487. CModelSoundsCacheSaver( const char *name ) : CAutoGameSystem( name )
  4488. {
  4489. }
  4490. virtual void LevelInitPostEntity()
  4491. {
  4492. if ( IsGameConsole() )
  4493. {
  4494. return;
  4495. }
  4496. if ( g_ModelSoundsCache.IsDirty() )
  4497. {
  4498. g_ModelSoundsCache.Save();
  4499. }
  4500. }
  4501. virtual void LevelShutdownPostEntity()
  4502. {
  4503. if ( IsGameConsole() )
  4504. {
  4505. // Unforunate that this table must persist through duration of level.
  4506. // It is the common case that PrecacheModel() still gets called (and needs this table),
  4507. // after LevelInitPostEntity, as PrecacheModel() redundantly precaches.
  4508. g_ModelSoundsSymbolHelper.RemoveAll();
  4509. return;
  4510. }
  4511. if ( g_ModelSoundsCache.IsDirty() )
  4512. {
  4513. g_ModelSoundsCache.Save();
  4514. }
  4515. }
  4516. };
  4517. static CModelSoundsCacheSaver g_ModelSoundsCacheSaver( "CModelSoundsCacheSaver" );
  4518. //#define WATCHACCESS
  4519. #if defined( WATCHACCESS )
  4520. static bool g_bWatching = true;
  4521. void ModelLogFunc( const char *fileName, const char *accessType )
  4522. {
  4523. if ( g_bWatching && !CBaseEntity::IsPrecacheAllowed() )
  4524. {
  4525. if ( Q_stristr( fileName, ".vcd" ) )
  4526. {
  4527. Msg( "%s\n", fileName );
  4528. }
  4529. }
  4530. }
  4531. class CWatchForModelAccess: public CAutoGameSystem
  4532. {
  4533. public:
  4534. virtual bool Init()
  4535. {
  4536. filesystem->AddLoggingFunc(&ModelLogFunc);
  4537. return true;
  4538. }
  4539. virtual void Shutdown()
  4540. {
  4541. filesystem->RemoveLoggingFunc(&ModelLogFunc);
  4542. }
  4543. };
  4544. static CWatchForModelAccess g_WatchForModels;
  4545. #endif
  4546. // HACK: This must match the #define in cl_animevent.h in the client .dll code!!!
  4547. #define CL_EVENT_SOUND 5004
  4548. #define CL_EVENT_FOOTSTEP_LEFT 6004
  4549. #define CL_EVENT_FOOTSTEP_RIGHT 6005
  4550. #define CL_EVENT_MFOOTSTEP_LEFT 6006
  4551. #define CL_EVENT_MFOOTSTEP_RIGHT 6007
  4552. //-----------------------------------------------------------------------------
  4553. // Precache model sound. Requires a local symbol table to prevent
  4554. // a very expensive call to PrecacheScriptSound().
  4555. //-----------------------------------------------------------------------------
  4556. void CBaseEntity::PrecacheSoundHelper( const char *pName )
  4557. {
  4558. if ( !IsGameConsole() )
  4559. {
  4560. // 360 only
  4561. Assert( 0 );
  4562. return;
  4563. }
  4564. if ( !pName || !pName[0] )
  4565. {
  4566. return;
  4567. }
  4568. if ( UTL_INVAL_SYMBOL == g_ModelSoundsSymbolHelper.Find( pName ) )
  4569. {
  4570. g_ModelSoundsSymbolHelper.AddString( pName );
  4571. // very expensive, only call when required
  4572. PrecacheScriptSound( pName );
  4573. }
  4574. }
  4575. class CModelPrecacheSystem : public CAutoGameSystem
  4576. {
  4577. public:
  4578. CModelPrecacheSystem() : CAutoGameSystem( "CModelPrecacheSystem" ), m_RepeatCounts( 0, 0, DefLessFunc( int ) )
  4579. {
  4580. }
  4581. // Level init, shutdown
  4582. virtual void LevelShutdownPreEntity()
  4583. {
  4584. m_RepeatCounts.Purge();
  4585. }
  4586. bool ShouldPrecache( int nModelIndex )
  4587. {
  4588. int slot = m_RepeatCounts.Find( nModelIndex );
  4589. if ( slot != m_RepeatCounts.InvalidIndex() )
  4590. {
  4591. m_RepeatCounts[ slot ]++;
  4592. return false;
  4593. }
  4594. m_RepeatCounts.Insert( nModelIndex, 0 );
  4595. return true;
  4596. }
  4597. private:
  4598. CUtlMap< int, int > m_RepeatCounts;
  4599. };
  4600. static CModelPrecacheSystem g_ModelPrecacheSystem;
  4601. //-----------------------------------------------------------------------------
  4602. // Precache model components
  4603. //-----------------------------------------------------------------------------
  4604. void CBaseEntity::PrecacheModelComponents( int nModelIndex )
  4605. {
  4606. if ( !g_ModelPrecacheSystem.ShouldPrecache( nModelIndex ) )
  4607. return;
  4608. model_t *pModel = (model_t *)modelinfo->GetModel( nModelIndex );
  4609. if ( !pModel || modelinfo->GetModelType( pModel ) != mod_studio )
  4610. {
  4611. return;
  4612. }
  4613. // sounds
  4614. if ( IsPC() )
  4615. {
  4616. const char *name = modelinfo->GetModelName( pModel );
  4617. if ( !g_ModelSoundsCache.EntryExists( name ) )
  4618. {
  4619. char extension[ 8 ];
  4620. Q_ExtractFileExtension( name, extension, sizeof( extension ) );
  4621. if ( Q_stristr( extension, "mdl" ) )
  4622. {
  4623. DevMsg( 2, "Late precache of %s, need to rebuild modelsounds.cache\n", name );
  4624. }
  4625. else
  4626. {
  4627. if ( !extension[ 0 ] )
  4628. {
  4629. Warning( "Precache of %s ambigious (no extension specified)\n", name );
  4630. }
  4631. else
  4632. {
  4633. Warning( "Late precache of %s (file missing?)\n", name );
  4634. }
  4635. return;
  4636. }
  4637. }
  4638. CModelSoundsCache *entry = g_ModelSoundsCache.Get( name );
  4639. Assert( entry );
  4640. if ( entry )
  4641. {
  4642. entry->PrecacheSoundList();
  4643. }
  4644. }
  4645. // particles
  4646. {
  4647. // Check keyvalues for auto-emitting particles
  4648. KeyValues *pModelKeyValues = new KeyValues("");
  4649. KeyValues::AutoDelete autodelete_pModelKeyValues( pModelKeyValues );
  4650. if ( pModelKeyValues->LoadFromBuffer( modelinfo->GetModelName( pModel ), modelinfo->GetModelKeyValueText( pModel ) ) )
  4651. {
  4652. static int keyParticles = KeyValuesSystem()->GetSymbolForString( "Particles" );
  4653. static int keyName = KeyValuesSystem()->GetSymbolForString( "name" );
  4654. KeyValues *pParticleEffects = pModelKeyValues->FindKey(keyParticles);
  4655. if ( pParticleEffects )
  4656. {
  4657. // Start grabbing the sounds and slotting them in
  4658. for ( KeyValues *pSingleEffect = pParticleEffects->GetFirstSubKey(); pSingleEffect; pSingleEffect = pSingleEffect->GetNextKey() )
  4659. {
  4660. const char *pParticleEffectName = pSingleEffect->GetString( keyName, "" );
  4661. PrecacheParticleSystem( pParticleEffectName );
  4662. }
  4663. }
  4664. }
  4665. }
  4666. // model anim event owned components
  4667. {
  4668. // Check animevents for particle events
  4669. CStudioHdr studioHdr( modelinfo->GetStudiomodel( pModel ), mdlcache );
  4670. if ( studioHdr.IsValid() )
  4671. {
  4672. // force animation event resolution!!!
  4673. VerifySequenceIndex( &studioHdr );
  4674. int nSeqCount = studioHdr.GetNumSeq();
  4675. for ( int i = 0; i < nSeqCount; ++i )
  4676. {
  4677. mstudioseqdesc_t &seq = studioHdr.pSeqdesc( i );
  4678. int nEventCount = seq.numevents;
  4679. for ( int j = 0; j < nEventCount; ++j )
  4680. {
  4681. mstudioevent_t *pEvent = (mstudioevent_for_client_server_t*)seq.pEvent( j );
  4682. int nEvent = pEvent->Event();
  4683. if ( !( pEvent->type & AE_TYPE_NEWEVENTSYSTEM ) || ( pEvent->type & AE_TYPE_CLIENT ) )
  4684. {
  4685. if ( nEvent == AE_CL_CREATE_PARTICLE_EFFECT )
  4686. {
  4687. char token[256];
  4688. const char *pOptions = pEvent->pszOptions();
  4689. nexttoken( token, pOptions, ' ' );
  4690. if ( token )
  4691. {
  4692. PrecacheParticleSystem( token );
  4693. }
  4694. continue;
  4695. }
  4696. }
  4697. // 360 precaches the model sounds now at init time, the cost is now ~250 msecs worst case.
  4698. // The disk based solution was not needed. Now at runtime partly due to already crawling the sequences
  4699. // for the particles and the expensive part was redundant PrecacheScriptSound(), which is now prevented
  4700. // by a local symbol table.
  4701. if ( IsGameConsole() )
  4702. {
  4703. switch ( nEvent )
  4704. {
  4705. default:
  4706. {
  4707. if ( ( pEvent->type & AE_TYPE_NEWEVENTSYSTEM ) && ( nEvent == AE_SV_PLAYSOUND ) )
  4708. {
  4709. PrecacheSoundHelper( pEvent->pszOptions() );
  4710. }
  4711. }
  4712. break;
  4713. case CL_EVENT_FOOTSTEP_LEFT:
  4714. case CL_EVENT_FOOTSTEP_RIGHT:
  4715. {
  4716. char soundname[256];
  4717. char const *options = pEvent->pszOptions();
  4718. if ( !options || !options[0] )
  4719. {
  4720. options = "NPC_CombineS";
  4721. }
  4722. Q_snprintf( soundname, sizeof( soundname ), "%s.RunFootstepLeft", options );
  4723. PrecacheSoundHelper( soundname );
  4724. Q_snprintf( soundname, sizeof( soundname ), "%s.RunFootstepRight", options );
  4725. PrecacheSoundHelper( soundname );
  4726. Q_snprintf( soundname, sizeof( soundname ), "%s.FootstepLeft", options );
  4727. PrecacheSoundHelper( soundname );
  4728. Q_snprintf( soundname, sizeof( soundname ), "%s.FootstepRight", options );
  4729. PrecacheSoundHelper( soundname );
  4730. }
  4731. break;
  4732. case AE_CL_PLAYSOUND:
  4733. {
  4734. if ( !( pEvent->type & AE_TYPE_CLIENT ) )
  4735. break;
  4736. if ( pEvent->pszOptions()[0] )
  4737. {
  4738. PrecacheSoundHelper( pEvent->pszOptions() );
  4739. }
  4740. else
  4741. {
  4742. Warning( "-- Error --: empty soundname, .qc error on AE_CL_PLAYSOUND in model %s, sequence %s, animevent # %i\n",
  4743. studioHdr.GetRenderHdr()->pszName(), seq.pszLabel(), j+1 );
  4744. }
  4745. }
  4746. break;
  4747. case CL_EVENT_SOUND:
  4748. case SCRIPT_EVENT_SOUND:
  4749. case SCRIPT_EVENT_SOUND_VOICE:
  4750. {
  4751. PrecacheSoundHelper( pEvent->pszOptions() );
  4752. }
  4753. break;
  4754. }
  4755. }
  4756. }
  4757. }
  4758. }
  4759. }
  4760. }
  4761. //-----------------------------------------------------------------------------
  4762. // Purpose: Add model to level precache list
  4763. // Input : *name - model name
  4764. // Output : int -- model index for model
  4765. //-----------------------------------------------------------------------------
  4766. int CBaseEntity::PrecacheModel( const char *name, bool bPreload )
  4767. {
  4768. if ( !name || !*name )
  4769. {
  4770. Msg( "Attempting to precache model, but model name is NULL\n");
  4771. return -1;
  4772. }
  4773. // Warn on out of order precache
  4774. if ( !CBaseEntity::IsPrecacheAllowed() )
  4775. {
  4776. if ( !engine->IsModelPrecached( name ) )
  4777. {
  4778. Assert( !"CBaseEntity::PrecacheModel: too late" );
  4779. Warning( "Late precache of %s\n", name );
  4780. }
  4781. }
  4782. #if defined( WATCHACCESS )
  4783. else
  4784. {
  4785. g_bWatching = false;
  4786. }
  4787. #endif
  4788. int idx = engine->PrecacheModel( name, bPreload );
  4789. if ( idx != -1 )
  4790. {
  4791. PrecacheModelComponents( idx );
  4792. }
  4793. #if defined( WATCHACCESS )
  4794. g_bWatching = true;
  4795. #endif
  4796. return idx;
  4797. }
  4798. //-----------------------------------------------------------------------------
  4799. // Purpose:
  4800. //-----------------------------------------------------------------------------
  4801. void CBaseEntity::Remove( )
  4802. {
  4803. UTIL_Remove( this );
  4804. }
  4805. //-----------------------------------------------------------------------------
  4806. // VScript access to model's key values
  4807. // for iteration and value access, use:
  4808. // ScriptFindKey, ScriptGetFirstSubKey, ScriptGetString,
  4809. // ScriptGetInt, ScriptGetFloat, ScriptGetNextKey
  4810. //-----------------------------------------------------------------------------
  4811. HSCRIPT CBaseEntity::ScriptGetModelKeyValues( void )
  4812. {
  4813. KeyValues *pModelKeyValues = new KeyValues("");
  4814. HSCRIPT hScript = NULL;
  4815. const char *pszModelName = modelinfo->GetModelName( GetModel() );
  4816. const char *pBuffer = modelinfo->GetModelKeyValueText( GetModel() ) ;
  4817. if ( pModelKeyValues->LoadFromBuffer( pszModelName, pBuffer ) )
  4818. {
  4819. // UNDONE: how does destructor get called on this
  4820. m_pScriptModelKeyValues = new CScriptKeyValues( pModelKeyValues );
  4821. // UNDONE: who calls ReleaseInstance on this??? Does name need to be unique???
  4822. hScript = g_pScriptVM->RegisterInstance( m_pScriptModelKeyValues );
  4823. /*
  4824. KeyValues *pParticleEffects = pModelKeyValues->FindKey("Particles");
  4825. if ( pParticleEffects )
  4826. {
  4827. // Start grabbing the sounds and slotting them in
  4828. for ( KeyValues *pSingleEffect = pParticleEffects->GetFirstSubKey(); pSingleEffect; pSingleEffect = pSingleEffect->GetNextKey() )
  4829. {
  4830. const char *pParticleEffectName = pSingleEffect->GetString( "name", "" );
  4831. PrecacheParticleSystem( pParticleEffectName );
  4832. }
  4833. }
  4834. */
  4835. }
  4836. return hScript;
  4837. }
  4838. //------------------------------------------------------------------------------
  4839. // Purpose :
  4840. // Input :
  4841. // Output :
  4842. //------------------------------------------------------------------------------
  4843. void CBaseEntity::ScriptPrecacheModel( const char *name )
  4844. {
  4845. PrecacheModel( name );
  4846. }
  4847. //------------------------------------------------------------------------------
  4848. // Purpose :
  4849. // Input :
  4850. // Output :
  4851. //------------------------------------------------------------------------------
  4852. void CBaseEntity::ScriptPrecacheScriptSound( const char *name )
  4853. {
  4854. PrecacheScriptSound( name );
  4855. }
  4856. // Entity degugging console commands
  4857. extern void SetDebugBits( CBasePlayer* pPlayer, const char *name, int bit );
  4858. extern CBaseEntity *GetNextCommandEntity( CBasePlayer *pPlayer, const char *name, CBaseEntity *ent );
  4859. //------------------------------------------------------------------------------
  4860. // Purpose :
  4861. // Input :
  4862. // Output :
  4863. //------------------------------------------------------------------------------
  4864. void ConsoleFireTargets( CBasePlayer *pPlayer, const char *name)
  4865. {
  4866. // If no name was given use the picker
  4867. if (FStrEq(name,""))
  4868. {
  4869. CBaseEntity *pEntity = pPlayer ? pPlayer->FindPickerEntity() : NULL;
  4870. if ( pEntity && !pEntity->IsMarkedForDeletion())
  4871. {
  4872. Msg( "[%03d] Found: %s, firing\n", gpGlobals->tickcount%1000, pEntity->GetDebugName());
  4873. pEntity->Use( pPlayer, pPlayer, USE_TOGGLE, 0 );
  4874. return;
  4875. }
  4876. }
  4877. // Otherwise use name or classname
  4878. FireTargets( name, pPlayer, pPlayer, USE_TOGGLE, 0 );
  4879. }
  4880. //------------------------------------------------------------------------------
  4881. //------------------------------------------------------------------------------
  4882. void DumpScriptScope( CBasePlayer* pPlayer, const char *name)
  4883. {
  4884. CBaseEntity *pEntity = NULL;
  4885. while ( (pEntity = GetNextCommandEntity( pPlayer, name, pEntity )) != NULL )
  4886. {
  4887. if( pEntity->m_ScriptScope.IsInitialized() )
  4888. {
  4889. Msg("----Script Dump for entity %s\n", pEntity->GetDebugName() );
  4890. HSCRIPT hDumpScopeFunc = g_pScriptVM->LookupFunction( "__DumpScope" );
  4891. g_pScriptVM->Call( hDumpScopeFunc, NULL, true, NULL, 1,(HSCRIPT)pEntity->m_ScriptScope );
  4892. Msg("----End Script Dump\n" );
  4893. }
  4894. else
  4895. {
  4896. DevWarning( "ent_script_dump: Entity %s has no script scope!\n", pEntity->GetDebugName() );
  4897. }
  4898. }
  4899. }
  4900. //------------------------------------------------------------------------------
  4901. // Purpose :
  4902. // Input :
  4903. // Output :
  4904. //------------------------------------------------------------------------------
  4905. void CC_Ent_Name( const CCommand& args )
  4906. {
  4907. SetDebugBits(UTIL_GetCommandClient(),args[1],OVERLAY_NAME_BIT);
  4908. }
  4909. static ConCommand ent_name("ent_name", CC_Ent_Name, 0, FCVAR_CHEAT);
  4910. //------------------------------------------------------------------------------
  4911. void CC_Ent_Text( const CCommand& args )
  4912. {
  4913. SetDebugBits(UTIL_GetCommandClient(),args[1],OVERLAY_TEXT_BIT);
  4914. }
  4915. static ConCommand ent_text("ent_text", CC_Ent_Text, "Displays text debugging information about the given entity(ies) on top of the entity (See Overlay Text)\n\tArguments: {entity_name} / {class_name} / no argument picks what player is looking at ", FCVAR_CHEAT);
  4916. //------------------------------------------------------------------------------
  4917. void CC_Ent_Script_Dump( const CCommand& args )
  4918. {
  4919. DumpScriptScope(UTIL_GetCommandClient(),args[1]);
  4920. }
  4921. static ConCommand ent_script_dump("ent_script_dump", CC_Ent_Script_Dump, "Dumps the names and values of this entity's script scope to the console\n\tArguments: {entity_name} / {class_name} / no argument picks what player is looking at ", FCVAR_CHEAT);
  4922. //------------------------------------------------------------------------------
  4923. void CC_Ent_BBox( const CCommand& args )
  4924. {
  4925. SetDebugBits(UTIL_GetCommandClient(),args[1],OVERLAY_BBOX_BIT);
  4926. }
  4927. static ConCommand ent_bbox("ent_bbox", CC_Ent_BBox, "Displays the movement bounding box for the given entity(ies) in orange. Some entites will also display entity specific overlays.\n\tArguments: {entity_name} / {class_name} / no argument picks what player is looking at ", FCVAR_CHEAT);
  4928. //------------------------------------------------------------------------------
  4929. void CC_Ent_AbsBox( const CCommand& args )
  4930. {
  4931. SetDebugBits(UTIL_GetCommandClient(),args[1],OVERLAY_ABSBOX_BIT);
  4932. }
  4933. static ConCommand ent_absbox("ent_absbox", CC_Ent_AbsBox, "Displays the total bounding box for the given entity(s) in green. Some entites will also display entity specific overlays.\n\tArguments: {entity_name} / {class_name} / no argument picks what player is looking at ", FCVAR_CHEAT);
  4934. //------------------------------------------------------------------------------
  4935. void CC_Ent_RBox( const CCommand& args )
  4936. {
  4937. SetDebugBits(UTIL_GetCommandClient(),args[1],OVERLAY_RBOX_BIT);
  4938. }
  4939. static ConCommand ent_rbox("ent_rbox", CC_Ent_RBox, "Displays the total bounding box for the given entity(s) in green. Some entites will also display entity specific overlays.\n\tArguments: {entity_name} / {class_name} / no argument picks what player is looking at ", FCVAR_CHEAT);
  4940. //------------------------------------------------------------------------------
  4941. void CC_Ent_AttachmentPoints( const CCommand& args )
  4942. {
  4943. SetDebugBits(UTIL_GetCommandClient(),args[1],OVERLAY_ATTACHMENTS_BIT);
  4944. }
  4945. static ConCommand ent_attachments("ent_attachments", CC_Ent_AttachmentPoints, "Displays the attachment points on an entity.\n\tArguments: {entity_name} / {class_name} / no argument picks what player is looking at ", FCVAR_CHEAT);
  4946. //------------------------------------------------------------------------------
  4947. void CC_Ent_ViewOffset( const CCommand& args )
  4948. {
  4949. SetDebugBits(UTIL_GetCommandClient(),args[1],OVERLAY_VIEWOFFSET);
  4950. }
  4951. static ConCommand ent_viewoffset("ent_viewoffset", CC_Ent_ViewOffset, "Displays the eye position for the given entity(ies) in red.\n\tArguments: {entity_name} / {class_name} / no argument picks what player is looking at ", FCVAR_CHEAT);
  4952. //------------------------------------------------------------------------------
  4953. void CC_Ent_Remove( const CCommand& args )
  4954. {
  4955. CBaseEntity *pEntity = NULL;
  4956. // If no name was given set bits based on the picked
  4957. if ( FStrEq( args[1],"") )
  4958. {
  4959. pEntity = UTIL_GetCommandClient() ? UTIL_GetCommandClient()->FindPickerEntity() : NULL;
  4960. }
  4961. else
  4962. {
  4963. int index = atoi( args[1] );
  4964. if ( index )
  4965. {
  4966. pEntity = CBaseEntity::Instance( index );
  4967. }
  4968. else
  4969. {
  4970. // Otherwise set bits based on name or classname
  4971. CBaseEntity *ent = NULL;
  4972. while ( (ent = gEntList.NextEnt(ent)) != NULL )
  4973. {
  4974. if ( (ent->GetEntityName() != NULL_STRING && FStrEq(args[1], STRING(ent->GetEntityName()))) ||
  4975. (ent->m_iClassname != NULL_STRING && FStrEq(args[1], STRING(ent->m_iClassname))) ||
  4976. (ent->GetClassname()!=NULL && FStrEq(args[1], ent->GetClassname())))
  4977. {
  4978. pEntity = ent;
  4979. break;
  4980. }
  4981. }
  4982. }
  4983. }
  4984. // Found one?
  4985. if ( pEntity )
  4986. {
  4987. Msg( "Removed %s(%s)\n", STRING(pEntity->m_iClassname), pEntity->GetDebugName() );
  4988. UTIL_Remove( pEntity );
  4989. }
  4990. }
  4991. static ConCommand ent_remove("ent_remove", CC_Ent_Remove, "Removes the given entity(s)\n\tArguments: {entity_name} / {class_name} / no argument picks what player is looking at ", FCVAR_CHEAT);
  4992. //------------------------------------------------------------------------------
  4993. void CC_Ent_RemoveAll( const CCommand& args )
  4994. {
  4995. // If no name was given remove based on the picked
  4996. if ( args.ArgC() < 2 )
  4997. {
  4998. Msg( "Removes all entities of the specified type\n\tArguments: {entity_name} / {class_name}\n" );
  4999. }
  5000. else
  5001. {
  5002. // Otherwise remove based on name or classname
  5003. int iCount = 0;
  5004. CBaseEntity *ent = NULL;
  5005. while ( (ent = gEntList.NextEnt(ent)) != NULL )
  5006. {
  5007. if ( (ent->GetEntityName() != NULL_STRING && FStrEq(args[1], STRING(ent->GetEntityName()))) ||
  5008. (ent->m_iClassname != NULL_STRING && FStrEq(args[1], STRING(ent->m_iClassname))) ||
  5009. (ent->GetClassname()!=NULL && FStrEq(args[1], ent->GetClassname())))
  5010. {
  5011. UTIL_Remove( ent );
  5012. iCount++;
  5013. }
  5014. }
  5015. if ( iCount )
  5016. {
  5017. Msg( "Removed %d %s's\n", iCount, args[1] );
  5018. }
  5019. else
  5020. {
  5021. Msg( "No %s found.\n", args[1] );
  5022. }
  5023. }
  5024. }
  5025. static ConCommand ent_remove_all("ent_remove_all", CC_Ent_RemoveAll, "Removes all entities of the specified type\n\tArguments: {entity_name} / {class_name} ", FCVAR_CHEAT);
  5026. //------------------------------------------------------------------------------
  5027. void CC_Ent_SetName( const CCommand& args )
  5028. {
  5029. CBaseEntity *pEntity = NULL;
  5030. if ( args.ArgC() < 1 )
  5031. {
  5032. CBasePlayer *pPlayer = ToBasePlayer( UTIL_GetCommandClient() );
  5033. if (!pPlayer)
  5034. return;
  5035. ClientPrint( pPlayer, HUD_PRINTCONSOLE, "Usage:\n ent_setname <new name> <entity name>\n" );
  5036. }
  5037. else
  5038. {
  5039. // If no name was given set bits based on the picked
  5040. if ( FStrEq( args[2],"") )
  5041. {
  5042. pEntity = UTIL_GetCommandClient() ? UTIL_GetCommandClient()->FindPickerEntity() : NULL;
  5043. }
  5044. else
  5045. {
  5046. // Otherwise set bits based on name or classname
  5047. CBaseEntity *ent = NULL;
  5048. while ( (ent = gEntList.NextEnt(ent)) != NULL )
  5049. {
  5050. if ( (ent->GetEntityName() != NULL_STRING && FStrEq(args[1], STRING(ent->GetEntityName()))) ||
  5051. (ent->m_iClassname != NULL_STRING && FStrEq(args[1], STRING(ent->m_iClassname))) ||
  5052. (ent->GetClassname()!=NULL && FStrEq(args[1], ent->GetClassname())))
  5053. {
  5054. pEntity = ent;
  5055. break;
  5056. }
  5057. }
  5058. }
  5059. // Found one?
  5060. if ( pEntity )
  5061. {
  5062. Msg( "Set the name of %s to %s\n", STRING(pEntity->m_iClassname), args[1] );
  5063. pEntity->SetName( AllocPooledString( args[1] ) );
  5064. }
  5065. }
  5066. }
  5067. static ConCommand ent_setname("ent_setname", CC_Ent_SetName, "Sets the targetname of the given entity(s)\n\tArguments: {new entity name} {entity_name} / {class_name} / no argument picks what player is looking at ", FCVAR_CHEAT);
  5068. //------------------------------------------------------------------------------
  5069. void CC_Find_Ent( const CCommand& args )
  5070. {
  5071. if ( args.ArgC() < 2 )
  5072. {
  5073. Msg( "Format: find_ent <substring>\n" );
  5074. return;
  5075. }
  5076. int iCount = 0;
  5077. const char *pszSubString = args[1];
  5078. Msg("Searching for entities with class/target name containing substring: '%s'\n", pszSubString );
  5079. CBaseEntity *ent = NULL;
  5080. while ( (ent = gEntList.NextEnt(ent)) != NULL )
  5081. {
  5082. const char *pszClassname = ent->GetClassname();
  5083. const char *pszTargetname = STRING(ent->GetEntityName());
  5084. bool bMatches = false;
  5085. if ( pszClassname && pszClassname[0] )
  5086. {
  5087. if ( Q_stristr( pszClassname, pszSubString ) )
  5088. {
  5089. bMatches = true;
  5090. }
  5091. }
  5092. if ( !bMatches && pszTargetname && pszTargetname[0] )
  5093. {
  5094. if ( Q_stristr( pszTargetname, pszSubString ) )
  5095. {
  5096. bMatches = true;
  5097. }
  5098. }
  5099. if ( bMatches )
  5100. {
  5101. iCount++;
  5102. Msg(" '%s' : '%s' (entindex %d) \n", ent->GetClassname(), ent->GetEntityName().ToCStr(), ent->entindex() );
  5103. }
  5104. }
  5105. Msg("Found %d matches.\n", iCount);
  5106. }
  5107. static ConCommand find_ent("find_ent", CC_Find_Ent, "Find and list all entities with classnames or targetnames that contain the specified substring.\nFormat: find_ent <substring>\n", FCVAR_CHEAT);
  5108. //------------------------------------------------------------------------------
  5109. void CC_Find_Ent_Index( const CCommand& args )
  5110. {
  5111. if ( args.ArgC() < 2 )
  5112. {
  5113. Msg( "Format: find_ent_index <index>\n" );
  5114. return;
  5115. }
  5116. int iIndex = atoi(args[1]);
  5117. CBaseEntity *pEnt = UTIL_EntityByIndex( iIndex );
  5118. if ( pEnt )
  5119. {
  5120. Msg(" '%s' : '%s' (entindex %d) \n", pEnt->GetClassname(), pEnt->GetEntityName().ToCStr(), iIndex );
  5121. }
  5122. else
  5123. {
  5124. Msg("Found no entity at %d.\n", iIndex);
  5125. }
  5126. }
  5127. static ConCommand find_ent_index("find_ent_index", CC_Find_Ent_Index, "Display data for entity matching specified index.\nFormat: find_ent_index <index>\n", FCVAR_CHEAT);
  5128. void DumpEntity( CBaseEntity *ent )
  5129. {
  5130. for ( datamap_t *dmap = ent->GetDataDescMap(); dmap != NULL; dmap = dmap->baseMap )
  5131. {
  5132. // search through all the actions in the data description, printing out details
  5133. for ( int i = 0; i < dmap->dataNumFields; i++ )
  5134. {
  5135. variant_t var;
  5136. if ( ent->ReadKeyField( dmap->dataDesc[i].externalName, &var) )
  5137. {
  5138. char buf[256];
  5139. buf[0] = 0;
  5140. switch( var.FieldType() )
  5141. {
  5142. case FIELD_STRING:
  5143. Q_strncpy( buf, var.String() ,sizeof(buf));
  5144. break;
  5145. case FIELD_INTEGER:
  5146. if ( var.Int() )
  5147. Q_snprintf( buf,sizeof(buf), "%d", var.Int() );
  5148. break;
  5149. case FIELD_FLOAT:
  5150. if ( var.Float() )
  5151. Q_snprintf( buf,sizeof(buf), "%.2f", var.Float() );
  5152. break;
  5153. case FIELD_EHANDLE:
  5154. {
  5155. // get the entities name
  5156. if ( var.Entity() )
  5157. {
  5158. Q_snprintf( buf,sizeof(buf), "%s", STRING(var.Entity()->GetEntityName()) );
  5159. }
  5160. }
  5161. break;
  5162. }
  5163. // don't print out the duplicate keys
  5164. if ( !Q_stricmp("parentname",dmap->dataDesc[i].externalName) || !Q_stricmp("targetname",dmap->dataDesc[i].externalName) )
  5165. continue;
  5166. // don't print out empty keys
  5167. if ( buf[0] )
  5168. {
  5169. Msg( " %s: %s\n", dmap->dataDesc[i].externalName, buf );
  5170. }
  5171. }
  5172. }
  5173. }
  5174. }
  5175. // Purpose :
  5176. //------------------------------------------------------------------------------
  5177. void CC_Ent_Dump( const CCommand& args )
  5178. {
  5179. CBasePlayer *pPlayer = ToBasePlayer( UTIL_GetCommandClient() );
  5180. if (!pPlayer)
  5181. {
  5182. return;
  5183. }
  5184. if ( args.ArgC() < 2 )
  5185. {
  5186. ClientPrint( pPlayer, HUD_PRINTCONSOLE, "Usage:\n ent_dump <entity name/index/class>\n" );
  5187. }
  5188. else
  5189. {
  5190. bool bFound = false;
  5191. CBaseEntity *pEntity = NULL;
  5192. while ( (pEntity = GetNextCommandEntity( pPlayer, args[1], pEntity )) != NULL )
  5193. {
  5194. bFound = true;
  5195. DumpEntity( pEntity );
  5196. }
  5197. if ( !bFound )
  5198. {
  5199. ClientPrint( pPlayer, HUD_PRINTCONSOLE, "ent_dump: no such entity" );
  5200. }
  5201. }
  5202. }
  5203. static ConCommand ent_dump("ent_dump", CC_Ent_Dump, "Usage:\n ent_dump <entity name>\n", FCVAR_CHEAT);
  5204. //------------------------------------------------------------------------------
  5205. // Purpose :
  5206. // Input :
  5207. // Output :
  5208. //------------------------------------------------------------------------------
  5209. void CC_Ent_FireTarget( const CCommand& args )
  5210. {
  5211. ConsoleFireTargets(UTIL_GetCommandClient(),args[1]);
  5212. }
  5213. static ConCommand firetarget("firetarget", CC_Ent_FireTarget, 0, FCVAR_CHEAT);
  5214. static bool UtlStringLessFunc( const CUtlString &lhs, const CUtlString &rhs )
  5215. {
  5216. return Q_stricmp( lhs.String(), rhs.String() ) < 0;
  5217. }
  5218. class CEntFireAutoCompletionFunctor : public ICommandCallback, public ICommandCompletionCallback
  5219. {
  5220. public:
  5221. virtual void CommandCallback( const CCommand &command )
  5222. {
  5223. CBasePlayer *pPlayer = ToBasePlayer( UTIL_GetCommandClient() );
  5224. if (!pPlayer)
  5225. {
  5226. return;
  5227. }
  5228. // fires a command from the console
  5229. if ( command.ArgC() < 2 )
  5230. {
  5231. ClientPrint( pPlayer, HUD_PRINTCONSOLE, "Usage:\n ent_fire <target> [action] [value] [delay]\n" );
  5232. }
  5233. else
  5234. {
  5235. const char *target = "", *action = "Use";
  5236. variant_t value;
  5237. int delay = 0;
  5238. target = STRING( AllocPooledString(command.Arg( 1 ) ) );
  5239. // Don't allow them to run anything on a point_servercommand unless they're the host player. Otherwise they can ent_fire
  5240. // and run any command on the server. Admittedly, they can only do the ent_fire if sv_cheats is on, but
  5241. // people complained about users resetting the rcon password if the server briefly turned on cheats like this:
  5242. // give point_servercommand
  5243. // ent_fire point_servercommand command "rcon_password mynewpassword"
  5244. if ( gpGlobals->maxClients > 1 && V_stricmp( target, "point_servercommand" ) == 0 )
  5245. {
  5246. if ( engine->IsDedicatedServer() )
  5247. return;
  5248. CBasePlayer *pHostPlayer = UTIL_GetListenServerHost();
  5249. if ( pPlayer != pHostPlayer )
  5250. return;
  5251. }
  5252. if ( command.ArgC() >= 3 )
  5253. {
  5254. action = STRING( AllocPooledString(command.Arg( 2 )) );
  5255. }
  5256. if ( command.ArgC() >= 4 )
  5257. {
  5258. value.SetString( AllocPooledString(command.Arg( 3 )) );
  5259. }
  5260. if ( command.ArgC() >= 5 )
  5261. {
  5262. delay = atoi( command.Arg( 4 ) );
  5263. }
  5264. g_EventQueue.AddEvent( target, action, value, delay, pPlayer, pPlayer );
  5265. }
  5266. }
  5267. virtual int CommandCompletionCallback( const char *partial, CUtlVector< CUtlString > &commands )
  5268. {
  5269. if ( !g_pGameRules )
  5270. {
  5271. return 0;
  5272. }
  5273. const char *cmdname = "ent_fire";
  5274. char *substring = (char *)partial;
  5275. if ( Q_strstr( partial, cmdname ) )
  5276. {
  5277. substring = (char *)partial + strlen( cmdname ) + 1;
  5278. }
  5279. int checklen = 0;
  5280. char *space = Q_strstr( substring, " " );
  5281. if ( space )
  5282. {
  5283. return EntFire_AutoCompleteInput( partial, commands );;
  5284. }
  5285. else
  5286. {
  5287. checklen = Q_strlen( substring );
  5288. }
  5289. CUtlRBTree< CUtlString > symbols( 0, 0, UtlStringLessFunc );
  5290. CBaseEntity *pos = NULL;
  5291. while ( ( pos = gEntList.NextEnt( pos ) ) != NULL )
  5292. {
  5293. // Check target name against partial string
  5294. if ( pos->GetEntityName() == NULL_STRING )
  5295. continue;
  5296. if ( Q_strnicmp( STRING( pos->GetEntityName() ), substring, checklen ) )
  5297. continue;
  5298. CUtlString sym = STRING( pos->GetEntityName() );
  5299. int idx = symbols.Find( sym );
  5300. if ( idx == symbols.InvalidIndex() )
  5301. {
  5302. symbols.Insert( sym );
  5303. }
  5304. // Too many
  5305. if ( symbols.Count() >= COMMAND_COMPLETION_MAXITEMS )
  5306. break;
  5307. }
  5308. // Now fill in the results
  5309. for ( int i = symbols.FirstInorder(); i != symbols.InvalidIndex(); i = symbols.NextInorder( i ) )
  5310. {
  5311. const char *name = symbols[ i ].String();
  5312. char buf[ 512 ];
  5313. Q_strncpy( buf, name, sizeof( buf ) );
  5314. Q_strlower( buf );
  5315. CUtlString command;
  5316. command = CFmtStr( "%s %s", cmdname, buf );
  5317. commands.AddToTail( command );
  5318. }
  5319. return symbols.Count();
  5320. }
  5321. private:
  5322. int EntFire_AutoCompleteInput( const char *partial, CUtlVector< CUtlString > &commands )
  5323. {
  5324. const char *cmdname = "ent_fire";
  5325. char *substring = (char *)partial;
  5326. if ( Q_strstr( partial, cmdname ) )
  5327. {
  5328. substring = (char *)partial + strlen( cmdname ) + 1;
  5329. }
  5330. int checklen = 0;
  5331. char *space = Q_strstr( substring, " " );
  5332. if ( !space )
  5333. {
  5334. Assert( !"CC_EntFireAutoCompleteInputFunc is broken\n" );
  5335. return 0;
  5336. }
  5337. checklen = Q_strlen( substring );
  5338. char targetEntity[ 256 ];
  5339. targetEntity[0] = 0;
  5340. int nEntityNameLength = (space-substring);
  5341. Q_strncat( targetEntity, substring, sizeof( targetEntity ), nEntityNameLength );
  5342. // Find the target entity by name
  5343. CBaseEntity *target = gEntList.FindEntityByName( NULL, targetEntity );
  5344. if ( target == NULL )
  5345. return 0;
  5346. CUtlRBTree< CUtlString > symbols( 0, 0, UtlStringLessFunc );
  5347. // Find the next portion of the text chain, if any (removing space)
  5348. int nInputNameLength = (checklen-nEntityNameLength-1);
  5349. // Starting past the last space, this is the remainder of the string
  5350. char *inputPartial = ( checklen > nEntityNameLength ) ? (space+1) : NULL;
  5351. for ( datamap_t *dmap = target->GetDataDescMap(); dmap != NULL; dmap = dmap->baseMap )
  5352. {
  5353. // Make sure we don't keep adding things in if the satisfied the limit
  5354. if ( symbols.Count() >= COMMAND_COMPLETION_MAXITEMS )
  5355. break;
  5356. int c = dmap->dataNumFields;
  5357. for ( int i = 0; i < c; i++ )
  5358. {
  5359. typedescription_t *field = &dmap->dataDesc[ i ];
  5360. // Only want inputs
  5361. if ( !( field->flags & FTYPEDESC_INPUT ) )
  5362. continue;
  5363. // Only want input functions
  5364. if ( field->flags & FTYPEDESC_SAVE )
  5365. continue;
  5366. // See if we've got a partial string for the input name already
  5367. if ( inputPartial != NULL )
  5368. {
  5369. if ( Q_strnicmp( inputPartial, field->externalName, nInputNameLength ) )
  5370. continue;
  5371. }
  5372. CUtlString sym = field->externalName;
  5373. int idx = symbols.Find( sym );
  5374. if ( idx == symbols.InvalidIndex() )
  5375. {
  5376. symbols.Insert( sym );
  5377. }
  5378. // Too many items have been added
  5379. if ( symbols.Count() >= COMMAND_COMPLETION_MAXITEMS )
  5380. break;
  5381. }
  5382. }
  5383. // Now fill in the results
  5384. for ( int i = symbols.FirstInorder(); i != symbols.InvalidIndex(); i = symbols.NextInorder( i ) )
  5385. {
  5386. const char *name = symbols[ i ].String();
  5387. char buf[ 512 ];
  5388. Q_strncpy( buf, name, sizeof( buf ) );
  5389. Q_strlower( buf );
  5390. CUtlString command;
  5391. command = CFmtStr( "%s %s %s", cmdname, targetEntity, buf );
  5392. commands.AddToTail( command );
  5393. }
  5394. return symbols.Count();
  5395. }
  5396. };
  5397. static CEntFireAutoCompletionFunctor g_EntFireAutoComplete;
  5398. static ConCommand ent_fire("ent_fire", &g_EntFireAutoComplete, "Usage:\n ent_fire <target> [action] [value] [delay]\n", FCVAR_CHEAT, &g_EntFireAutoComplete );
  5399. void CC_Ent_CancelPendingEntFires( const CCommand& args )
  5400. {
  5401. if ( !UTIL_IsCommandIssuedByServerAdmin() )
  5402. return;
  5403. CBasePlayer *pPlayer = ToBasePlayer( UTIL_GetCommandClient() );
  5404. if (!pPlayer)
  5405. return;
  5406. g_EventQueue.CancelEvents( pPlayer );
  5407. }
  5408. static ConCommand ent_cancelpendingentfires("ent_cancelpendingentfires", CC_Ent_CancelPendingEntFires, "Cancels all ent_fire created outputs that are currently waiting for their delay to expire." );
  5409. //------------------------------------------------------------------------------
  5410. // Purpose :
  5411. // Input :
  5412. // Output :
  5413. //------------------------------------------------------------------------------
  5414. void CC_Ent_Info( const CCommand& args )
  5415. {
  5416. CBasePlayer *pPlayer = ToBasePlayer( UTIL_GetCommandClient() );
  5417. if (!pPlayer)
  5418. {
  5419. return;
  5420. }
  5421. if ( args.ArgC() < 2 )
  5422. {
  5423. ClientPrint( pPlayer, HUD_PRINTCONSOLE, "Usage:\n ent_info <class name>\n" );
  5424. }
  5425. else
  5426. {
  5427. // iterate through all the ents printing out their details
  5428. CBaseEntity *ent = CreateEntityByName( args[1] );
  5429. if ( ent )
  5430. {
  5431. datamap_t *dmap;
  5432. for ( dmap = ent->GetDataDescMap(); dmap != NULL; dmap = dmap->baseMap )
  5433. {
  5434. // search through all the actions in the data description, printing out details
  5435. for ( int i = 0; i < dmap->dataNumFields; i++ )
  5436. {
  5437. if ( dmap->dataDesc[i].flags & FTYPEDESC_OUTPUT )
  5438. {
  5439. ClientPrint( pPlayer, HUD_PRINTCONSOLE, UTIL_VarArgs(" output: %s\n", dmap->dataDesc[i].externalName) );
  5440. }
  5441. }
  5442. }
  5443. for ( dmap = ent->GetDataDescMap(); dmap != NULL; dmap = dmap->baseMap )
  5444. {
  5445. // search through all the actions in the data description, printing out details
  5446. for ( int i = 0; i < dmap->dataNumFields; i++ )
  5447. {
  5448. if ( dmap->dataDesc[i].flags & FTYPEDESC_INPUT )
  5449. {
  5450. ClientPrint( pPlayer, HUD_PRINTCONSOLE, UTIL_VarArgs(" input: %s\n", dmap->dataDesc[i].externalName) );
  5451. }
  5452. }
  5453. }
  5454. delete ent;
  5455. }
  5456. else
  5457. {
  5458. ClientPrint( pPlayer, HUD_PRINTCONSOLE, UTIL_VarArgs("no such entity %s\n", args[1]) );
  5459. }
  5460. }
  5461. }
  5462. static ConCommand ent_info("ent_info", CC_Ent_Info, "Usage:\n ent_info <class name>\n", FCVAR_CHEAT);
  5463. //------------------------------------------------------------------------------
  5464. // Purpose :
  5465. // Input :
  5466. // Output :
  5467. //------------------------------------------------------------------------------
  5468. void CC_Ent_Messages( const CCommand& args )
  5469. {
  5470. SetDebugBits(UTIL_GetCommandClient(),args[1],OVERLAY_MESSAGE_BIT);
  5471. }
  5472. static ConCommand ent_messages("ent_messages", CC_Ent_Messages ,"Toggles input/output message display for the selected entity(ies). The name of the entity will be displayed as well as any messages that it sends or receives.\n\tArguments: {entity_name} / {class_name} / no argument picks what player is looking at", FCVAR_CHEAT);
  5473. //------------------------------------------------------------------------------
  5474. // Purpose :
  5475. // Input :
  5476. // Output :
  5477. //------------------------------------------------------------------------------
  5478. void CC_Ent_Pause( void )
  5479. {
  5480. if (CBaseEntity::Debug_IsPaused())
  5481. {
  5482. Msg( "Resuming entity I/O events\n" );
  5483. CBaseEntity::Debug_Pause(false);
  5484. }
  5485. else
  5486. {
  5487. Msg( "Pausing entity I/O events\n" );
  5488. CBaseEntity::Debug_Pause(true);
  5489. }
  5490. }
  5491. static ConCommand ent_pause("ent_pause", CC_Ent_Pause, "Toggles pausing of input/output message processing for entities. When turned on processing of all message will stop. Any messages displayed with 'ent_messages' will stop fading and be displayed indefinitely. To step through the messages one by one use 'ent_step'.", FCVAR_CHEAT);
  5492. //------------------------------------------------------------------------------
  5493. // Purpose : Enables the entity picker, revelaing debug information about the
  5494. // entity under the crosshair.
  5495. // Input : an optional command line argument "full" enables all debug info.
  5496. // Output :
  5497. //------------------------------------------------------------------------------
  5498. void CC_Ent_Picker( void )
  5499. {
  5500. CBaseEntity::m_bInDebugSelect = CBaseEntity::m_bInDebugSelect ? false : true;
  5501. // Remember the player that's making this request
  5502. CBaseEntity::m_nDebugPlayer = UTIL_GetCommandClientIndex();
  5503. }
  5504. static ConCommand picker("picker", CC_Ent_Picker, "Toggles 'picker' mode. When picker is on, the bounding box, pivot and debugging text is displayed for whatever entity the player is looking at.\n\tArguments: full - enables all debug information", FCVAR_CHEAT);
  5505. //------------------------------------------------------------------------------
  5506. // Purpose :
  5507. // Input :
  5508. // Output :
  5509. //------------------------------------------------------------------------------
  5510. void CC_Ent_Pivot( const CCommand& args )
  5511. {
  5512. SetDebugBits(UTIL_GetCommandClient(),args[1],OVERLAY_PIVOT_BIT);
  5513. }
  5514. static ConCommand ent_pivot("ent_pivot", CC_Ent_Pivot, "Displays the pivot for the given entity(ies).\n\t(y=up=green, z=forward=blue, x=left=red). \n\tArguments: {entity_name} / {class_name} / no argument picks what player is looking at ", FCVAR_CHEAT);
  5515. //------------------------------------------------------------------------------
  5516. // Purpose :
  5517. // Input :
  5518. // Output :
  5519. //------------------------------------------------------------------------------
  5520. void CC_Ent_Step( const CCommand& args )
  5521. {
  5522. int nSteps = atoi(args[1]);
  5523. if (nSteps <= 0)
  5524. {
  5525. nSteps = 1;
  5526. }
  5527. CBaseEntity::Debug_SetSteps(nSteps);
  5528. }
  5529. static ConCommand ent_step("ent_step", CC_Ent_Step, "When 'ent_pause' is set this will step through one waiting input / output message at a time.", FCVAR_CHEAT);
  5530. void CBaseEntity::SetCheckUntouch( bool check )
  5531. {
  5532. // Invalidate touchstamp
  5533. if ( check )
  5534. {
  5535. touchStamp++;
  5536. if ( !IsEFlagSet( EFL_CHECK_UNTOUCH ) )
  5537. {
  5538. AddEFlags( EFL_CHECK_UNTOUCH );
  5539. EntityTouch_Add( this );
  5540. }
  5541. }
  5542. else
  5543. {
  5544. RemoveEFlags( EFL_CHECK_UNTOUCH );
  5545. EntityTouch_Remove( this );
  5546. }
  5547. }
  5548. model_t *CBaseEntity::GetModel( void )
  5549. {
  5550. return (model_t *)modelinfo->GetModel( GetModelIndex() );
  5551. }
  5552. //-----------------------------------------------------------------------------
  5553. // Purpose: Calculates the absolute position of an edict in the world
  5554. // assumes the parent's absolute origin has already been calculated
  5555. //-----------------------------------------------------------------------------
  5556. void CBaseEntity::CalcAbsolutePosition( void )
  5557. {
  5558. if (!IsEFlagSet( EFL_DIRTY_ABSTRANSFORM ))
  5559. return;
  5560. RemoveEFlags( EFL_DIRTY_ABSTRANSFORM );
  5561. // Plop the entity->parent matrix into m_rgflCoordinateFrame
  5562. AngleMatrix( m_angRotation, m_vecOrigin, m_rgflCoordinateFrame );
  5563. CBaseEntity *pMoveParent = GetMoveParent();
  5564. if ( !pMoveParent )
  5565. {
  5566. // no move parent, so just copy existing values
  5567. m_vecAbsOrigin = m_vecOrigin;
  5568. m_angAbsRotation = m_angRotation;
  5569. if ( HasDataObjectType( POSITIONWATCHER ) )
  5570. {
  5571. ReportPositionChanged( this );
  5572. }
  5573. return;
  5574. }
  5575. // concatenate with our parent's transform
  5576. matrix3x4a_t tmpMatrix;
  5577. matrix3x4a_t scratchSpace;
  5578. ConcatTransforms( GetParentToWorldTransform( scratchSpace ), m_rgflCoordinateFrame, tmpMatrix );
  5579. MatrixCopy( tmpMatrix, m_rgflCoordinateFrame );
  5580. // pull our absolute position out of the matrix
  5581. MatrixGetColumn( m_rgflCoordinateFrame, 3, m_vecAbsOrigin );
  5582. // if we have any angles, we have to extract our absolute angles from our matrix
  5583. if (( m_angRotation == vec3_angle ) && ( m_iParentAttachment == 0 ))
  5584. {
  5585. // just copy our parent's absolute angles
  5586. VectorCopy( pMoveParent->GetAbsAngles(), m_angAbsRotation );
  5587. }
  5588. else
  5589. {
  5590. MatrixAngles( m_rgflCoordinateFrame, m_angAbsRotation );
  5591. }
  5592. if ( HasDataObjectType( POSITIONWATCHER ) )
  5593. {
  5594. ReportPositionChanged( this );
  5595. }
  5596. }
  5597. void CBaseEntity::CalcAbsoluteVelocity()
  5598. {
  5599. if (!IsEFlagSet( EFL_DIRTY_ABSVELOCITY ))
  5600. return;
  5601. RemoveEFlags( EFL_DIRTY_ABSVELOCITY );
  5602. CBaseEntity *pMoveParent = GetMoveParent();
  5603. if ( !pMoveParent )
  5604. {
  5605. m_vecAbsVelocity = m_vecVelocity;
  5606. return;
  5607. }
  5608. // This transforms the local velocity into world space
  5609. VectorRotate( m_vecVelocity, pMoveParent->EntityToWorldTransform(), m_vecAbsVelocity );
  5610. // Now add in the parent abs velocity
  5611. m_vecAbsVelocity += pMoveParent->GetAbsVelocity();
  5612. }
  5613. // FIXME: While we're using (dPitch, dYaw, dRoll) as our local angular velocity
  5614. // representation, we can't actually solve this problem
  5615. /*
  5616. void CBaseEntity::CalcAbsoluteAngularVelocity()
  5617. {
  5618. if (!IsEFlagSet( EFL_DIRTY_ABSANGVELOCITY ))
  5619. return;
  5620. RemoveEFlags( EFL_DIRTY_ABSANGVELOCITY );
  5621. CBaseEntity *pMoveParent = GetMoveParent();
  5622. if ( !pMoveParent )
  5623. {
  5624. m_vecAbsAngVelocity = m_vecAngVelocity;
  5625. return;
  5626. }
  5627. // This transforms the local ang velocity into world space
  5628. matrix3x4_t angVelToParent, angVelToWorld;
  5629. AngleMatrix( m_vecAngVelocity, angVelToParent );
  5630. ConcatTransforms( pMoveParent->EntityToWorldTransform(), angVelToParent, angVelToWorld );
  5631. MatrixAngles( angVelToWorld, m_vecAbsAngVelocity );
  5632. }
  5633. */
  5634. //-----------------------------------------------------------------------------
  5635. // Computes the abs position of a point specified in local space
  5636. //-----------------------------------------------------------------------------
  5637. void CBaseEntity::ComputeAbsPosition( const Vector &vecLocalPosition, Vector *pAbsPosition )
  5638. {
  5639. CBaseEntity *pMoveParent = GetMoveParent();
  5640. if ( !pMoveParent )
  5641. {
  5642. *pAbsPosition = vecLocalPosition;
  5643. }
  5644. else
  5645. {
  5646. VectorTransform( vecLocalPosition, pMoveParent->EntityToWorldTransform(), *pAbsPosition );
  5647. }
  5648. }
  5649. //-----------------------------------------------------------------------------
  5650. // Computes the abs position of a point specified in local space
  5651. //-----------------------------------------------------------------------------
  5652. void CBaseEntity::ComputeAbsDirection( const Vector &vecLocalDirection, Vector *pAbsDirection )
  5653. {
  5654. CBaseEntity *pMoveParent = GetMoveParent();
  5655. if ( !pMoveParent )
  5656. {
  5657. *pAbsDirection = vecLocalDirection;
  5658. }
  5659. else
  5660. {
  5661. VectorRotate( vecLocalDirection, pMoveParent->EntityToWorldTransform(), *pAbsDirection );
  5662. }
  5663. }
  5664. matrix3x4_t& CBaseEntity::GetParentToWorldTransform( matrix3x4_t &tempMatrix )
  5665. {
  5666. CBaseEntity *pMoveParent = GetMoveParent();
  5667. if ( !pMoveParent )
  5668. {
  5669. Assert( false );
  5670. SetIdentityMatrix( tempMatrix );
  5671. return tempMatrix;
  5672. }
  5673. if ( m_iParentAttachment != 0 )
  5674. {
  5675. MDLCACHE_CRITICAL_SECTION();
  5676. CBaseAnimating *pAnimating = pMoveParent->GetBaseAnimating();
  5677. if ( pAnimating && pAnimating->GetAttachment( m_iParentAttachment, tempMatrix ) )
  5678. {
  5679. return tempMatrix;
  5680. }
  5681. }
  5682. // If we fall through to here, then just use the move parent's abs origin and angles.
  5683. return pMoveParent->EntityToWorldTransform();
  5684. }
  5685. //-----------------------------------------------------------------------------
  5686. // These methods recompute local versions as well as set abs versions
  5687. //-----------------------------------------------------------------------------
  5688. void CBaseEntity::SetAbsOrigin( const Vector& absOrigin )
  5689. {
  5690. AssertMsg( absOrigin.IsValid(), "Invalid origin set" );
  5691. // This is necessary to get the other fields of m_rgflCoordinateFrame ok
  5692. CalcAbsolutePosition();
  5693. if ( m_vecAbsOrigin == absOrigin )
  5694. return;
  5695. // All children are invalid, but we are not
  5696. InvalidatePhysicsRecursive( POSITION_CHANGED );
  5697. RemoveEFlags( EFL_DIRTY_ABSTRANSFORM );
  5698. m_vecAbsOrigin = absOrigin;
  5699. MatrixSetColumn( absOrigin, 3, m_rgflCoordinateFrame );
  5700. Vector vecNewOrigin;
  5701. CBaseEntity *pMoveParent = GetMoveParent();
  5702. if (!pMoveParent)
  5703. {
  5704. vecNewOrigin = absOrigin;
  5705. }
  5706. else
  5707. {
  5708. matrix3x4_t tempMat;
  5709. matrix3x4_t &parentTransform = GetParentToWorldTransform( tempMat );
  5710. // Moveparent case: transform the abs position into local space
  5711. VectorITransform( absOrigin, parentTransform, vecNewOrigin );
  5712. }
  5713. if (m_vecOrigin != vecNewOrigin)
  5714. {
  5715. m_vecOrigin = vecNewOrigin;
  5716. SetSimulationTime( gpGlobals->curtime );
  5717. UpdateCell();
  5718. }
  5719. if ( HasDataObjectType( POSITIONWATCHER ) )
  5720. {
  5721. ReportPositionChanged( this );
  5722. }
  5723. }
  5724. void CBaseEntity::SetAbsAngles( const QAngle& absAngles )
  5725. {
  5726. // This is necessary to get the other fields of m_rgflCoordinateFrame ok
  5727. CalcAbsolutePosition();
  5728. // FIXME: The normalize caused problems in server code like momentary_rot_button that isn't
  5729. // handling things like +/-180 degrees properly. This should be revisited.
  5730. //QAngle angleNormalize( AngleNormalize( absAngles.x ), AngleNormalize( absAngles.y ), AngleNormalize( absAngles.z ) );
  5731. if ( m_angAbsRotation == absAngles )
  5732. return;
  5733. // All children are invalid, but we are not
  5734. InvalidatePhysicsRecursive( ANGLES_CHANGED );
  5735. RemoveEFlags( EFL_DIRTY_ABSTRANSFORM );
  5736. m_angAbsRotation = absAngles;
  5737. AngleMatrix( absAngles, m_rgflCoordinateFrame );
  5738. MatrixSetColumn( m_vecAbsOrigin, 3, m_rgflCoordinateFrame );
  5739. QAngle angNewRotation;
  5740. CBaseEntity *pMoveParent = GetMoveParent();
  5741. if (!pMoveParent)
  5742. {
  5743. angNewRotation = absAngles;
  5744. }
  5745. else
  5746. {
  5747. if ( m_angAbsRotation == pMoveParent->GetAbsAngles() )
  5748. {
  5749. angNewRotation.Init( );
  5750. }
  5751. else
  5752. {
  5753. // Moveparent case: transform the abs transform into local space
  5754. matrix3x4_t worldToParent, localMatrix;
  5755. MatrixInvert( pMoveParent->EntityToWorldTransform(), worldToParent );
  5756. ConcatTransforms( worldToParent, m_rgflCoordinateFrame, localMatrix );
  5757. MatrixAngles( localMatrix, angNewRotation );
  5758. }
  5759. }
  5760. if (m_angRotation != angNewRotation)
  5761. {
  5762. m_angRotation = angNewRotation;
  5763. SetSimulationTime( gpGlobals->curtime );
  5764. // PRB TODO : HACK FIX
  5765. // This call fixes the fact that this network var does not get set for some derived classes (eg chickens)
  5766. // Since we are so close to CERT this will have to do for now, but needs re-visiting.
  5767. m_angRotation.GetForModify();
  5768. }
  5769. }
  5770. void CBaseEntity::SetAbsVelocity( const Vector &vecAbsVelocity )
  5771. {
  5772. if ( m_vecAbsVelocity == vecAbsVelocity )
  5773. return;
  5774. // The abs velocity won't be dirty since we're setting it here
  5775. // All children are invalid, but we are not
  5776. InvalidatePhysicsRecursive( VELOCITY_CHANGED );
  5777. RemoveEFlags( EFL_DIRTY_ABSVELOCITY );
  5778. Assert( vecAbsVelocity.IsValid() );
  5779. m_vecAbsVelocity = vecAbsVelocity;
  5780. // NOTE: Do *not* do a network state change in this case.
  5781. // m_vecVelocity is only networked for the player, which is not manual mode
  5782. CBaseEntity *pMoveParent = GetMoveParent();
  5783. if (!pMoveParent)
  5784. {
  5785. m_vecVelocity = vecAbsVelocity;
  5786. return;
  5787. }
  5788. // First subtract out the parent's abs velocity to get a relative
  5789. // velocity measured in world space
  5790. Vector relVelocity;
  5791. VectorSubtract( vecAbsVelocity, pMoveParent->GetAbsVelocity(), relVelocity );
  5792. // Transform relative velocity into parent space
  5793. Vector vNew;
  5794. VectorIRotate( relVelocity, pMoveParent->EntityToWorldTransform(), vNew );
  5795. m_vecVelocity = vNew;
  5796. }
  5797. // FIXME: While we're using (dPitch, dYaw, dRoll) as our local angular velocity
  5798. // representation, we can't actually solve this problem
  5799. /*
  5800. void CBaseEntity::SetAbsAngularVelocity( const QAngle &vecAbsAngVelocity )
  5801. {
  5802. // The abs velocity won't be dirty since we're setting it here
  5803. // All children are invalid, but we are not
  5804. InvalidatePhysicsRecursive( EFL_DIRTY_ABSANGVELOCITY );
  5805. RemoveEFlags( EFL_DIRTY_ABSANGVELOCITY );
  5806. m_vecAbsAngVelocity = vecAbsAngVelocity;
  5807. CBaseEntity *pMoveParent = GetMoveParent();
  5808. if (!pMoveParent)
  5809. {
  5810. m_vecAngVelocity = vecAbsAngVelocity;
  5811. return;
  5812. }
  5813. // NOTE: We *can't* subtract out parent ang velocity, it's nonsensical
  5814. matrix3x4_t entityToWorld;
  5815. AngleMatrix( vecAbsAngVelocity, entityToWorld );
  5816. // Moveparent case: transform the abs relative angular vel into local space
  5817. matrix3x4_t worldToParent, localMatrix;
  5818. MatrixInvert( pMoveParent->EntityToWorldTransform(), worldToParent );
  5819. ConcatTransforms( worldToParent, entityToWorld, localMatrix );
  5820. MatrixAngles( localMatrix, m_vecAngVelocity );
  5821. }
  5822. */
  5823. //-----------------------------------------------------------------------------
  5824. // Methods that modify local physics state, and let us know to compute abs state later
  5825. //-----------------------------------------------------------------------------
  5826. void CBaseEntity::SetLocalOrigin( const Vector& origin )
  5827. {
  5828. // Safety check against NaN or really huge numbers
  5829. if ( !IsEntityPositionReasonable( origin ) )
  5830. {
  5831. if ( CheckEmitReasonablePhysicsSpew() )
  5832. {
  5833. Warning( "Bad SetLocalOrigin(%f,%f,%f) on %s\n", origin.x, origin.y, origin.z, GetDebugName() );
  5834. }
  5835. Assert( false );
  5836. return;
  5837. }
  5838. if (m_vecOrigin != origin)
  5839. {
  5840. // Sanity check to make sure the origin is valid.
  5841. #ifdef _DEBUG
  5842. float largeVal = 1024 * 128;
  5843. Assert( origin.x >= -largeVal && origin.x <= largeVal );
  5844. Assert( origin.y >= -largeVal && origin.y <= largeVal );
  5845. Assert( origin.z >= -largeVal && origin.z <= largeVal );
  5846. #endif
  5847. InvalidatePhysicsRecursive( POSITION_CHANGED );
  5848. // Call set direct which flags it for change immediately, no need to check
  5849. // for change we already did!
  5850. m_vecOrigin.SetDirect( origin );
  5851. SetSimulationTime( gpGlobals->curtime );
  5852. UpdateCell();
  5853. }
  5854. }
  5855. void CBaseEntity::SetLocalAngles( const QAngle& angles )
  5856. {
  5857. // NOTE: The angle normalize is a little expensive, but we can save
  5858. // a bunch of time in interpolation if we don't have to invalidate everything
  5859. // and sometimes it's off by a normalization amount
  5860. // FIXME: The normalize caused problems in server code like momentary_rot_button that isn't
  5861. // handling things like +/-180 degrees properly. This should be revisited.
  5862. //QAngle angleNormalize( AngleNormalize( angles.x ), AngleNormalize( angles.y ), AngleNormalize( angles.z ) );
  5863. // Safety check against NaN or really huge numbers
  5864. if ( !IsEntityQAngleReasonable( angles ) )
  5865. {
  5866. Warning( "Bad SetLocalAngles(%f,%f,%f) on %s\n", angles.x, angles.y, angles.z, GetDebugName() );
  5867. Assert( false );
  5868. return;
  5869. }
  5870. if (m_angRotation != angles)
  5871. {
  5872. InvalidatePhysicsRecursive( ANGLES_CHANGED );
  5873. m_angRotation.SetDirect( angles );
  5874. SetSimulationTime( gpGlobals->curtime );
  5875. }
  5876. }
  5877. void CBaseEntity::SetLocalVelocity( const Vector &inVecVelocity )
  5878. {
  5879. Vector vecVelocity = inVecVelocity;
  5880. // Safety check against NaN's or really huge numbers, which can explode physics
  5881. switch ( CheckEntityVelocity( vecVelocity ) )
  5882. {
  5883. case -1:
  5884. Warning( "Discarding SetLocalVelocity(%f,%f,%f) on %s\n", vecVelocity.x, vecVelocity.y, vecVelocity.z, GetDebugName() );
  5885. Assert( false );
  5886. return;
  5887. case 0:
  5888. if ( CheckEmitReasonablePhysicsSpew() )
  5889. {
  5890. Warning( "Clamping SetLocalVelocity(%f,%f,%f) on %s\n", vecVelocity.x, vecVelocity.y, vecVelocity.z, GetDebugName() );
  5891. }
  5892. break;
  5893. default:
  5894. break;
  5895. }
  5896. if (m_vecVelocity != vecVelocity)
  5897. {
  5898. InvalidatePhysicsRecursive( VELOCITY_CHANGED );
  5899. m_vecVelocity.SetDirect( vecVelocity );
  5900. }
  5901. }
  5902. void CBaseEntity::SetLocalAngularVelocity( const QAngle &vecAngVelocity )
  5903. {
  5904. // Safety check against NaN's or really huge numbers
  5905. if ( !IsEntityQAngleVelReasonable( vecAngVelocity ) )
  5906. {
  5907. if ( CheckEmitReasonablePhysicsSpew() )
  5908. {
  5909. Warning( "Bad SetLocalAngularVelocity(%f,%f,%f) on %s\n", vecAngVelocity.x, vecAngVelocity.y, vecAngVelocity.z, GetDebugName() );
  5910. }
  5911. Assert( false );
  5912. return;
  5913. }
  5914. if (m_vecAngVelocity != vecAngVelocity)
  5915. {
  5916. // InvalidatePhysicsRecursive( EFL_DIRTY_ABSANGVELOCITY );
  5917. m_vecAngVelocity = vecAngVelocity;
  5918. }
  5919. }
  5920. void CBaseEntity::ScriptSetLocalAngularVelocity( float pitchVel, float yawVel, float rollVel )
  5921. {
  5922. QAngle qa;
  5923. qa.Init(pitchVel,yawVel,rollVel);
  5924. SetLocalAngularVelocity(qa);
  5925. }
  5926. const Vector &CBaseEntity::ScriptGetLocalAngularVelocity( void )
  5927. {
  5928. QAngle qa = GetLocalAngularVelocity();
  5929. static Vector v;
  5930. v.x = qa.x;
  5931. v.y = qa.y;
  5932. v.z = qa.z;
  5933. return v;
  5934. }
  5935. //-----------------------------------------------------------------------------
  5936. // Sets the local position from a transform
  5937. //-----------------------------------------------------------------------------
  5938. void CBaseEntity::SetLocalTransform( const matrix3x4_t &localTransform )
  5939. {
  5940. // FIXME: Should angles go away? Should we just use transforms?
  5941. Vector vecLocalOrigin;
  5942. QAngle vecLocalAngles;
  5943. MatrixGetColumn( localTransform, 3, vecLocalOrigin );
  5944. MatrixAngles( localTransform, vecLocalAngles );
  5945. SetLocalOrigin( vecLocalOrigin );
  5946. SetLocalAngles( vecLocalAngles );
  5947. }
  5948. //-----------------------------------------------------------------------------
  5949. // Adjust the number of cell bits
  5950. //-----------------------------------------------------------------------------
  5951. void CBaseEntity::SetCellBits( int cellbits )
  5952. {
  5953. m_cellbits = cellbits;
  5954. m_cellwidth = ( 1 << cellbits );
  5955. UpdateCell();
  5956. }
  5957. //-----------------------------------------------------------------------------
  5958. // Called when the origin changes and recomputes cell
  5959. //-----------------------------------------------------------------------------
  5960. void CBaseEntity::UpdateCell()
  5961. {
  5962. register int const cellwidth = m_cellwidth; // Load it into a register
  5963. m_cellX = CellFromCoord( cellwidth, m_vecOrigin.GetX() );
  5964. m_cellY = CellFromCoord( cellwidth, m_vecOrigin.GetY() );
  5965. m_cellZ = CellFromCoord( cellwidth, m_vecOrigin.GetZ() );
  5966. // PRB TODO : HACK fix for hostage warping.
  5967. // Somehow the above code does not flag the network vars as modified, but below does...
  5968. // Needs revisiting, but at this stage it fixes our bug
  5969. m_cellX.GetForModify();
  5970. m_cellY.GetForModify();
  5971. m_cellZ.GetForModify();
  5972. }
  5973. //-----------------------------------------------------------------------------
  5974. // Is the entity floating?
  5975. //-----------------------------------------------------------------------------
  5976. bool CBaseEntity::IsFloating()
  5977. {
  5978. if ( !IsEFlagSet(EFL_TOUCHING_FLUID) )
  5979. return false;
  5980. IPhysicsObject *pObject = VPhysicsGetObject();
  5981. if ( !pObject )
  5982. return false;
  5983. int nMaterialIndex = pObject->GetMaterialIndex();
  5984. float flDensity;
  5985. float flThickness;
  5986. float flFriction;
  5987. float flElasticity;
  5988. physprops->GetPhysicsProperties( nMaterialIndex, &flDensity,
  5989. &flThickness, &flFriction, &flElasticity );
  5990. // FIXME: This really only works for water at the moment..
  5991. // Owing the check for density == 1000
  5992. return (flDensity < 1000.0f);
  5993. }
  5994. //-----------------------------------------------------------------------------
  5995. // Purpose: Created predictable and sets up Id. Note that persist is ignored on the server.
  5996. // Input : *classname -
  5997. // *module -
  5998. // line -
  5999. // persist -
  6000. // Output : CBaseEntity
  6001. //-----------------------------------------------------------------------------
  6002. CBaseEntity *CBaseEntity::CreatePredictedEntityByName( const char *classname, const char *module, int line, bool persist /* = false */ )
  6003. {
  6004. #if !defined( NO_ENTITY_PREDICTION ) && defined( USE_PREDICTABLEID )
  6005. CBasePlayer *player = CBaseEntity::GetPredictionPlayer();
  6006. Assert( player );
  6007. CBaseEntity *ent = NULL;
  6008. int command_number = player->CurrentCommandNumber();
  6009. int player_index = player->entindex() - 1;
  6010. CPredictableId testId;
  6011. testId.Init( player_index, command_number, classname, module, line );
  6012. ent = CreateEntityByName( classname );
  6013. // No factory???
  6014. if ( !ent )
  6015. return NULL;
  6016. ent->SetPredictionEligible( true );
  6017. // Set up "shared" id number
  6018. ent->m_PredictableID.GetForModify().SetRaw( testId.GetRaw() );
  6019. return ent;
  6020. #else
  6021. return NULL;
  6022. #endif
  6023. }
  6024. void CBaseEntity::SetPredictionEligible( bool canpredict )
  6025. {
  6026. // Nothing in game code m_bPredictionEligible = canpredict;
  6027. }
  6028. //-----------------------------------------------------------------------------
  6029. // These could be virtual, but only the player is overriding them
  6030. // NOTE: If you make any of these virtual, remove this implementation!!!
  6031. //-----------------------------------------------------------------------------
  6032. void CBaseEntity::AddPoints( int score, bool bAllowNegativeScore )
  6033. {
  6034. CBasePlayer *pPlayer = ToBasePlayer(this);
  6035. if ( pPlayer )
  6036. {
  6037. pPlayer->CBasePlayer::AddPoints( score, bAllowNegativeScore );
  6038. }
  6039. }
  6040. void CBaseEntity::AddPointsToTeam( int score, bool bAllowNegativeScore )
  6041. {
  6042. CBasePlayer *pPlayer = ToBasePlayer(this);
  6043. if ( pPlayer )
  6044. {
  6045. pPlayer->CBasePlayer::AddPointsToTeam( score, bAllowNegativeScore );
  6046. }
  6047. }
  6048. void CBaseEntity::ViewPunch( const QAngle &angleOffset )
  6049. {
  6050. CBasePlayer *pPlayer = ToBasePlayer(this);
  6051. if ( pPlayer )
  6052. {
  6053. pPlayer->CBasePlayer::ViewPunch( angleOffset );
  6054. }
  6055. }
  6056. void CBaseEntity::VelocityPunch( const Vector &vecForce )
  6057. {
  6058. CBasePlayer *pPlayer = ToBasePlayer(this);
  6059. if ( pPlayer )
  6060. {
  6061. pPlayer->CBasePlayer::VelocityPunch( vecForce );
  6062. }
  6063. }
  6064. //-----------------------------------------------------------------------------
  6065. //-----------------------------------------------------------------------------
  6066. // Purpose: Tell clients to remove all decals from this entity
  6067. //-----------------------------------------------------------------------------
  6068. void CBaseEntity::RemoveAllDecals( void )
  6069. {
  6070. EntityMessageBegin( this );
  6071. WRITE_BYTE( BASEENTITY_MSG_REMOVE_DECALS );
  6072. MessageEnd();
  6073. }
  6074. //-----------------------------------------------------------------------------
  6075. // Purpose:
  6076. // Input : set -
  6077. //-----------------------------------------------------------------------------
  6078. void CBaseEntity::ModifyOrAppendCriteria( AI_CriteriaSet& set )
  6079. {
  6080. // TODO
  6081. // Append chapter/day?
  6082. set.AppendCriteria( "randomnum", UTIL_VarArgs("%d", RandomInt(0,100)) );
  6083. // Append map name
  6084. set.AppendCriteria( "map", gpGlobals->mapname.ToCStr() );
  6085. // Append our classname and game name
  6086. set.AppendCriteria( "classname", GetClassname() );
  6087. set.AppendCriteria( "name", GetEntityName().ToCStr() );
  6088. // Append our health
  6089. set.AppendCriteria( "health", UTIL_VarArgs( "%i", GetHealth() ) );
  6090. float healthfrac = 0.0f;
  6091. if ( GetMaxHealth() > 0 )
  6092. {
  6093. healthfrac = (float)GetHealth() / (float)GetMaxHealth();
  6094. }
  6095. set.AppendCriteria( "healthfrac", UTIL_VarArgs( "%.3f", healthfrac ) );
  6096. // Go through all the global states and append them
  6097. for ( int i = 0; i < GlobalEntity_GetNumGlobals(); i++ )
  6098. {
  6099. const char *szGlobalName = GlobalEntity_GetName(i);
  6100. int iGlobalState = (int)GlobalEntity_GetStateByIndex(i);
  6101. set.AppendCriteria( szGlobalName, UTIL_VarArgs( "%i", iGlobalState ) );
  6102. }
  6103. // Append anything from I/O or keyvalues pairs
  6104. AppendContextToCriteria( set );
  6105. if( hl2_episodic.GetBool() )
  6106. {
  6107. set.AppendCriteria( "episodic", "1" );
  6108. }
  6109. // Append anything from world I/O/keyvalues with "world" as prefix
  6110. CWorld *world = assert_cast< CWorld * >( CBaseEntity::Instance( INDEXENT( 0 ) ) );
  6111. if ( world )
  6112. {
  6113. world->AppendContextToCriteria( set, "world" );
  6114. }
  6115. }
  6116. //-----------------------------------------------------------------------------
  6117. // Purpose:
  6118. // Input : set -
  6119. // "" -
  6120. //-----------------------------------------------------------------------------
  6121. void CBaseEntity::AppendContextToCriteria( AI_CriteriaSet& set, const char *prefix /*= ""*/ )
  6122. {
  6123. RemoveExpiredConcepts();
  6124. int c = GetContextCount();
  6125. int i;
  6126. char sz[ 128 ];
  6127. for ( i = 0; i < c; i++ )
  6128. {
  6129. const char *name = GetContextName( i );
  6130. const char *value = GetContextValue( i );
  6131. Q_snprintf( sz, sizeof( sz ), "%s%s", prefix, name );
  6132. set.AppendCriteria( sz, value );
  6133. }
  6134. }
  6135. //-----------------------------------------------------------------------------
  6136. // Purpose: Removes expired concepts from list
  6137. // Output :
  6138. //-----------------------------------------------------------------------------
  6139. void CBaseEntity::RemoveExpiredConcepts( void )
  6140. {
  6141. int c = GetContextCount();
  6142. int i;
  6143. for ( i = 0; i < c; i++ )
  6144. {
  6145. if ( ContextExpired( i ) )
  6146. {
  6147. m_ResponseContexts.Remove( i );
  6148. c--;
  6149. i--;
  6150. continue;
  6151. }
  6152. }
  6153. }
  6154. //-----------------------------------------------------------------------------
  6155. // Purpose: Get current context count
  6156. // Output : int
  6157. //-----------------------------------------------------------------------------
  6158. int CBaseEntity::GetContextCount() const
  6159. {
  6160. return m_ResponseContexts.Count();
  6161. }
  6162. //-----------------------------------------------------------------------------
  6163. // Purpose:
  6164. // Input : index -
  6165. // Output : const char
  6166. //-----------------------------------------------------------------------------
  6167. const char *CBaseEntity::GetContextName( int index ) const
  6168. {
  6169. if ( index < 0 || index >= m_ResponseContexts.Count() )
  6170. {
  6171. Assert( 0 );
  6172. return "";
  6173. }
  6174. return m_ResponseContexts[ index ].m_iszName.ToCStr();
  6175. }
  6176. //-----------------------------------------------------------------------------
  6177. // Purpose:
  6178. // Input : index -
  6179. // Output : const char
  6180. //-----------------------------------------------------------------------------
  6181. const char *CBaseEntity::GetContextValue( int index ) const
  6182. {
  6183. if ( index < 0 || index >= m_ResponseContexts.Count() )
  6184. {
  6185. Assert( 0 );
  6186. return "";
  6187. }
  6188. return m_ResponseContexts[ index ].m_iszValue.ToCStr();
  6189. }
  6190. //-----------------------------------------------------------------------------
  6191. // Purpose: remove all contexts set on this entity
  6192. //-----------------------------------------------------------------------------
  6193. void CBaseEntity::ClearAllContexts( )
  6194. {
  6195. m_ResponseContexts.RemoveAll();
  6196. }
  6197. //-----------------------------------------------------------------------------
  6198. // Purpose: Check if context has expired
  6199. // Input : index -
  6200. // Output : bool
  6201. //-----------------------------------------------------------------------------
  6202. bool CBaseEntity::ContextExpired( int index ) const
  6203. {
  6204. if ( index < 0 || index >= m_ResponseContexts.Count() )
  6205. {
  6206. Assert( 0 );
  6207. return true;
  6208. }
  6209. if ( !m_ResponseContexts[ index ].m_fExpirationTime )
  6210. {
  6211. return false;
  6212. }
  6213. return ( m_ResponseContexts[ index ].m_fExpirationTime <= gpGlobals->curtime );
  6214. }
  6215. //-----------------------------------------------------------------------------
  6216. // Purpose: Search for index of named context string
  6217. // Input : *name -
  6218. // Output : int
  6219. //-----------------------------------------------------------------------------
  6220. int CBaseEntity::FindContextByName( const char *name ) const
  6221. {
  6222. int c = m_ResponseContexts.Count();
  6223. for ( int i = 0; i < c; i++ )
  6224. {
  6225. if ( FStrEq( name, GetContextName( i ) ) )
  6226. return i;
  6227. }
  6228. return -1;
  6229. }
  6230. //-----------------------------------------------------------------------------
  6231. // Purpose:
  6232. // Input : inputdata -
  6233. //-----------------------------------------------------------------------------
  6234. void CBaseEntity::InputAddContext( inputdata_t& inputdata )
  6235. {
  6236. const char *contextName = inputdata.value.String();
  6237. AddContext( contextName );
  6238. }
  6239. //-----------------------------------------------------------------------------
  6240. // Purpose: User inputs. These fire the corresponding user outputs, and are
  6241. // a means of forwarding messages through !activator to a target known
  6242. // known by !activator but not by the targetting entity.
  6243. //
  6244. // For example, say you have three identical trains, following the same
  6245. // path. Each train has a sprite in hierarchy with it that needs to
  6246. // toggle on/off as it passes each path_track. You would hook each train's
  6247. // OnUser1 output to it's sprite's Toggle input, then connect each path_track's
  6248. // OnPass output to !activator's FireUser1 input.
  6249. //-----------------------------------------------------------------------------
  6250. void CBaseEntity::InputFireUser1( inputdata_t& inputdata )
  6251. {
  6252. m_OnUser1.FireOutput( inputdata.pActivator, this );
  6253. }
  6254. void CBaseEntity::InputFireUser2( inputdata_t& inputdata )
  6255. {
  6256. m_OnUser2.FireOutput( inputdata.pActivator, this );
  6257. }
  6258. void CBaseEntity::InputFireUser3( inputdata_t& inputdata )
  6259. {
  6260. m_OnUser3.FireOutput( inputdata.pActivator, this );
  6261. }
  6262. void CBaseEntity::InputFireUser4( inputdata_t& inputdata )
  6263. {
  6264. m_OnUser4.FireOutput( inputdata.pActivator, this );
  6265. }
  6266. //---------------------------------------------------------
  6267. // Use the string as the filename of a script file
  6268. // that should be loaded from disk, compiled, and run.
  6269. //---------------------------------------------------------
  6270. void CBaseEntity::InputRunScriptFile( inputdata_t& inputdata )
  6271. {
  6272. RunScriptFile( inputdata.value.String() );
  6273. }
  6274. //---------------------------------------------------------
  6275. // Send the string to the VM as source code and execute it
  6276. //---------------------------------------------------------
  6277. void CBaseEntity::InputRunScript( inputdata_t& inputdata )
  6278. {
  6279. RunScript( inputdata.value.String(), "InputRunScript" );
  6280. }
  6281. //---------------------------------------------------------
  6282. // Make an explicit function call.
  6283. //---------------------------------------------------------
  6284. void CBaseEntity::InputCallScriptFunction( inputdata_t& inputdata )
  6285. {
  6286. CallScriptFunction( inputdata.value.String(), NULL );
  6287. }
  6288. #ifdef PORTAL2
  6289. //---------------------------------------------------------
  6290. // Remove paint from entity with BSP model.
  6291. //---------------------------------------------------------
  6292. void CBaseEntity::InputRemovePaint( inputdata_t &inputdata )
  6293. {
  6294. if ( engine->HasPaintmap() && IsBSPModel() )
  6295. {
  6296. engine->RemovePaint( GetModel() );
  6297. CBroadcastRecipientFilter filter;
  6298. filter.MakeReliable();
  6299. UserMessageBegin( filter, "RemovePaint" );
  6300. WRITE_EHANDLE( this );
  6301. MessageEnd();
  6302. }
  6303. }
  6304. #endif
  6305. // #define VMPROFILE // define to profile vscript calls
  6306. #ifdef VMPROFILE
  6307. float g_debugCumulativeTime = 0.0;
  6308. float g_debugCounter = 0;
  6309. #define START_VMPROFILE float debugStartTime = Plat_FloatTime();
  6310. #define UPDATE_VMPROFILE \
  6311. g_debugCumulativeTime += Plat_FloatTime() - debugStartTime; \
  6312. g_debugCounter++; \
  6313. if ( g_debugCounter >= 500 ) \
  6314. { \
  6315. DevMsg("***VSCRIPT PROFILE***: %s %s: %6.4f milliseconds\n", "500 vscript function calls", "", g_debugCumulativeTime*1000.0 ); \
  6316. g_debugCounter = 0; \
  6317. g_debugCumulativeTime = 0.0; \
  6318. } \
  6319. #else
  6320. #define START_VMPROFILE
  6321. #define UPDATE_VMPROFILE
  6322. #endif // VMPROFILE
  6323. //-----------------------------------------------------------------------------
  6324. // Returns true if the function was located and called. false otherwise.
  6325. // NOTE: Assumes the function takes no parameters at the moment.
  6326. //-----------------------------------------------------------------------------
  6327. bool CBaseEntity::CallScriptFunction( const char *pFunctionName, ScriptVariant_t *pFunctionReturn )
  6328. {
  6329. START_VMPROFILE
  6330. if( !ValidateScriptScope() )
  6331. {
  6332. DevMsg("\n***\nFAILED to create private ScriptScope. ABORTING script\n***\n");
  6333. return false;
  6334. }
  6335. HSCRIPT hFunc = m_ScriptScope.LookupFunction( pFunctionName );
  6336. if( hFunc )
  6337. {
  6338. // Kind of a hack to make glados.nut easier to work with...
  6339. // When a script function is called by connecting the function to an entity output,
  6340. // the entity who is connected to the output and who has this function in their scope
  6341. // will be set to 'owninginstance'. In this situation, it can be a different instance than 'self'.
  6342. g_pScriptVM->SetValue( "owninginstance", ScriptVariant_t( GetScriptInstance() ) );
  6343. m_ScriptScope.Call( hFunc, pFunctionReturn );
  6344. m_ScriptScope.ReleaseFunction( hFunc );
  6345. g_pScriptVM->ClearValue( "owninginstance" );
  6346. UPDATE_VMPROFILE
  6347. return true;
  6348. }
  6349. return false;
  6350. }
  6351. //-----------------------------------------------------------------------------
  6352. //-----------------------------------------------------------------------------
  6353. void CBaseEntity::ConnectOutputToScript( const char *pszOutput, const char *pszScriptFunc )
  6354. {
  6355. CBaseEntityOutput *pOutput = FindNamedOutput( pszOutput );
  6356. if ( !pOutput )
  6357. {
  6358. DevMsg( 2, "Script failed to find output \"%s\"\n", pszOutput );
  6359. return;
  6360. }
  6361. string_t iszSelf = AllocPooledString( "!self" ); // @TODO: cache this [4/25/2008 tom]
  6362. CEventAction *pAction = pOutput->GetFirstAction();
  6363. while ( pAction )
  6364. {
  6365. if ( pAction->m_iTarget == iszSelf &&
  6366. pAction->m_flDelay == 0 &&
  6367. pAction->m_nTimesToFire == EVENT_FIRE_ALWAYS &&
  6368. V_strcmp( STRING(pAction->m_iTargetInput), "CallScriptFunction" ) == 0 &&
  6369. V_strcmp( STRING(pAction->m_iParameter), pszScriptFunc ) == 0 )
  6370. {
  6371. return;
  6372. }
  6373. pAction = pAction->m_pNext;
  6374. }
  6375. pAction = new CEventAction( NULL );
  6376. pAction->m_iTarget = iszSelf;
  6377. pAction->m_iTargetInput = AllocPooledString( "CallScriptFunction" );
  6378. pAction->m_iParameter = AllocPooledString( pszScriptFunc );
  6379. pOutput->AddEventAction( pAction );
  6380. }
  6381. //-----------------------------------------------------------------------------
  6382. //-----------------------------------------------------------------------------
  6383. void CBaseEntity::DisconnectOutputFromScript( const char *pszOutput, const char *pszScriptFunc )
  6384. {
  6385. CBaseEntityOutput *pOutput = FindNamedOutput( pszOutput );
  6386. if ( !pOutput )
  6387. {
  6388. DevMsg( 2, "Script failed to find output \"%s\"\n", pszOutput );
  6389. return;
  6390. }
  6391. string_t iszSelf = AllocPooledString( "!self" ); // @TODO: cache this [4/25/2008 tom]
  6392. CEventAction *pAction = pOutput->GetFirstAction();
  6393. while ( pAction )
  6394. {
  6395. if ( pAction->m_iTarget == iszSelf &&
  6396. pAction->m_flDelay == 0 &&
  6397. pAction->m_nTimesToFire == EVENT_FIRE_ALWAYS &&
  6398. V_strcmp( STRING(pAction->m_iTargetInput), "CallScriptFunction" ) == 0 &&
  6399. V_strcmp( STRING(pAction->m_iParameter), pszScriptFunc ) == 0 )
  6400. {
  6401. pOutput->RemoveEventAction( pAction );
  6402. delete pAction;
  6403. return;
  6404. }
  6405. pAction = pAction->m_pNext;
  6406. }
  6407. }
  6408. //-----------------------------------------------------------------------------
  6409. //-----------------------------------------------------------------------------
  6410. void CBaseEntity::ScriptThink( void )
  6411. {
  6412. ScriptVariant_t varThinkRetVal;
  6413. if( CallScriptFunction( m_iszScriptThinkFunction.ToCStr(), &varThinkRetVal ) )
  6414. {
  6415. float flThinkFrequency = 0.0f;
  6416. if ( !varThinkRetVal.AssignTo( &flThinkFrequency ) )
  6417. {
  6418. // use default think interval if script think function doesn't provide one
  6419. flThinkFrequency = sv_script_think_interval.GetFloat();
  6420. }
  6421. SetContextThink( &CBaseEntity::ScriptThink,
  6422. gpGlobals->curtime + flThinkFrequency, "ScriptThink" );
  6423. }
  6424. else
  6425. {
  6426. DevWarning("%s FAILED to call script think function %s!\n", GetDebugName(), STRING(m_iszScriptThinkFunction) );
  6427. }
  6428. }
  6429. //-----------------------------------------------------------------------------
  6430. //-----------------------------------------------------------------------------
  6431. const char *CBaseEntity::GetScriptId()
  6432. {
  6433. return STRING( m_iszScriptThinkFunction );
  6434. }
  6435. //-----------------------------------------------------------------------------
  6436. //-----------------------------------------------------------------------------
  6437. HSCRIPT CBaseEntity::GetScriptScope()
  6438. {
  6439. return m_ScriptScope;
  6440. }
  6441. //-----------------------------------------------------------------------------
  6442. //-----------------------------------------------------------------------------
  6443. HSCRIPT CBaseEntity::ScriptGetMoveParent( void )
  6444. {
  6445. return ToHScript( GetMoveParent() );
  6446. }
  6447. //-----------------------------------------------------------------------------
  6448. //-----------------------------------------------------------------------------
  6449. HSCRIPT CBaseEntity::ScriptGetRootMoveParent()
  6450. {
  6451. return ToHScript( GetRootMoveParent() );
  6452. }
  6453. //-----------------------------------------------------------------------------
  6454. //-----------------------------------------------------------------------------
  6455. HSCRIPT CBaseEntity::ScriptFirstMoveChild( void )
  6456. {
  6457. return ToHScript( FirstMoveChild() );
  6458. }
  6459. //-----------------------------------------------------------------------------
  6460. //-----------------------------------------------------------------------------
  6461. HSCRIPT CBaseEntity::ScriptNextMovePeer( void )
  6462. {
  6463. return ToHScript( NextMovePeer() );
  6464. }
  6465. //-----------------------------------------------------------------------------
  6466. // Purpose: Load, compile, and run a script file from disk.
  6467. // Input : *pScriptFile - The filename of the script file.
  6468. // bUseRootScope - If true, runs this script in the root scope, not
  6469. // in this entity's private scope.
  6470. //-----------------------------------------------------------------------------
  6471. bool CBaseEntity::RunScriptFile( const char *pScriptFile, bool bUseRootScope )
  6472. {
  6473. if( !ValidateScriptScope() )
  6474. {
  6475. DevMsg("\n***\nFAILED to create private ScriptScope. ABORTING script\n***\n");
  6476. return false;
  6477. }
  6478. if( bUseRootScope )
  6479. {
  6480. return VScriptRunScript( pScriptFile );
  6481. }
  6482. else
  6483. {
  6484. return VScriptRunScript( pScriptFile, m_ScriptScope, true );
  6485. }
  6486. }
  6487. //-----------------------------------------------------------------------------
  6488. // Purpose: Compile and execute a discrete string of script source code
  6489. // Input : *pScriptText - A string containing script code to compile and run
  6490. //-----------------------------------------------------------------------------
  6491. bool CBaseEntity::RunScript( const char *pScriptText, const char *pDebugFilename )
  6492. {
  6493. if( !ValidateScriptScope() )
  6494. {
  6495. DevMsg("\n***\nFAILED to create private ScriptScope. ABORTING script\n***\n");
  6496. return false;
  6497. }
  6498. if( m_ScriptScope.Run( pScriptText, pDebugFilename ) == SCRIPT_ERROR )
  6499. {
  6500. DevWarning(" Entity %s encountered an error in RunScript()\n", GetDebugName() );
  6501. }
  6502. return true;
  6503. }
  6504. //-----------------------------------------------------------------------------
  6505. // Purpose: given a string context1:value1,context2:value2,... tokenize and
  6506. // add its data to this object.
  6507. // Input : *contextName -
  6508. //-----------------------------------------------------------------------------
  6509. void CBaseEntity::AddContext( const char *contextName )
  6510. {
  6511. char key[ 128 ];
  6512. char value[ 128 ];
  6513. float duration;
  6514. #ifdef TERROR // from changelist 729204 . Ifdef'd out because not tested outside L4D yet.
  6515. CWorld * const world = assert_cast< CWorld * >( CBaseEntity::Instance( INDEXENT( 0 ) ) );
  6516. #endif
  6517. const char *p = contextName;
  6518. while ( p )
  6519. {
  6520. duration = 0.0f;
  6521. p = SplitContext( p, key, sizeof( key ), value, sizeof( value ), &duration, contextName );
  6522. if ( duration )
  6523. {
  6524. duration += gpGlobals->curtime;
  6525. }
  6526. #ifdef TERROR
  6527. // Egregious last-minute hack. If a specific context is prefixed with a '$', then
  6528. // apply it to the World instead of to this character. The proper way to fix this
  6529. // would be to do away with this insane mechanism of writing contexts out into a
  6530. // string and then parsing it back apart again after calling a member function
  6531. // on the receiving character; but that's way too big to deal with at this stage
  6532. // of L4D2. ( this hack dated 9/4/09 )
  6533. if ( key[0] == AI_CriteriaSet::kAPPLYTOWORLDPREFIX && world && world != this )
  6534. {
  6535. world->AddContext( key+1, value, duration );
  6536. }
  6537. else
  6538. {
  6539. AddContext( key, value, duration );
  6540. }
  6541. #else
  6542. AddContext( key, value, duration );
  6543. #endif
  6544. }
  6545. }
  6546. #include "ai_speech.h"
  6547. //-----------------------------------------------------------------------------
  6548. // Purpose: add exactly one context key,value pair to this object
  6549. // Input : inputdata -
  6550. //-----------------------------------------------------------------------------
  6551. void CBaseEntity::AddContext( const char *pKey, const char *pValue, float duration )
  6552. {
  6553. int iIndex = FindContextByName( pKey );
  6554. if ( iIndex != -1 )
  6555. {
  6556. // Set the existing context to the new value
  6557. char buf[64];
  6558. if ( RR::CApplyContextOperator::FindOperator( pValue )->Apply(
  6559. m_ResponseContexts[iIndex].m_iszValue.ToCStr(), pValue, buf, sizeof(buf) ) )
  6560. {
  6561. m_ResponseContexts[iIndex].m_iszValue = AllocPooledString( buf );
  6562. }
  6563. else
  6564. {
  6565. Warning( "RR: could not apply operator %s to prior value %s\n",
  6566. pValue, m_ResponseContexts[iIndex].m_iszValue.ToCStr() );
  6567. m_ResponseContexts[iIndex].m_iszValue = AllocPooledString( pValue );
  6568. }
  6569. m_ResponseContexts[iIndex].m_fExpirationTime = duration;
  6570. }
  6571. else
  6572. {
  6573. ResponseContext_t newContext;
  6574. newContext.m_iszName = AllocPooledString( pKey );
  6575. // Create a new context with the appropriate value ( some operators assume 0 on nonexistent prior )
  6576. char buf[64];
  6577. if ( RR::CApplyContextOperator::FindOperator( pValue )->Apply(
  6578. NULL, pValue, buf, sizeof(buf) ) )
  6579. {
  6580. newContext.m_iszValue = AllocPooledString( buf );
  6581. }
  6582. else
  6583. {
  6584. newContext.m_iszValue = AllocPooledString( pValue );
  6585. }
  6586. newContext.m_fExpirationTime = duration;
  6587. m_ResponseContexts.AddToTail( newContext );
  6588. }
  6589. }
  6590. //-----------------------------------------------------------------------------
  6591. // Purpose:
  6592. // Input : inputdata -
  6593. //-----------------------------------------------------------------------------
  6594. void CBaseEntity::InputRemoveContext( inputdata_t& inputdata )
  6595. {
  6596. const char *contextName = inputdata.value.String();
  6597. int idx = FindContextByName( contextName );
  6598. if ( idx == -1 )
  6599. return;
  6600. m_ResponseContexts.Remove( idx );
  6601. }
  6602. //-----------------------------------------------------------------------------
  6603. // Purpose:
  6604. // Input : inputdata -
  6605. //-----------------------------------------------------------------------------
  6606. void CBaseEntity::InputClearContext( inputdata_t& inputdata )
  6607. {
  6608. m_ResponseContexts.RemoveAll();
  6609. }
  6610. //-----------------------------------------------------------------------------
  6611. // Purpose:
  6612. // Output : IResponseSystem
  6613. //-----------------------------------------------------------------------------
  6614. IResponseSystem *CBaseEntity::GetResponseSystem()
  6615. {
  6616. #ifndef INFESTED_DLL
  6617. return NULL;
  6618. #else
  6619. extern IResponseSystem *g_pResponseSystem;
  6620. return g_pResponseSystem;
  6621. #endif
  6622. }
  6623. //-----------------------------------------------------------------------------
  6624. // Purpose:
  6625. // Input : inputdata -
  6626. //-----------------------------------------------------------------------------
  6627. void CBaseEntity::InputDispatchResponse( inputdata_t& inputdata )
  6628. {
  6629. DispatchResponse( inputdata.value.String() );
  6630. }
  6631. //-----------------------------------------------------------------------------
  6632. //-----------------------------------------------------------------------------
  6633. void CBaseEntity::InputDisableShadow( inputdata_t &inputdata )
  6634. {
  6635. AddEffects( EF_NOSHADOW );
  6636. }
  6637. //-----------------------------------------------------------------------------
  6638. //-----------------------------------------------------------------------------
  6639. void CBaseEntity::InputEnableShadow( inputdata_t &inputdata )
  6640. {
  6641. RemoveEffects( EF_NOSHADOW );
  6642. }
  6643. //-----------------------------------------------------------------------------
  6644. //-----------------------------------------------------------------------------
  6645. void CBaseEntity::InputDisableReceivingFlashlight( inputdata_t &inputdata )
  6646. {
  6647. AddEffects( EF_NOFLASHLIGHT );
  6648. }
  6649. //-----------------------------------------------------------------------------
  6650. //-----------------------------------------------------------------------------
  6651. void CBaseEntity::InputEnableReceivingFlashlight( inputdata_t &inputdata )
  6652. {
  6653. RemoveEffects( EF_NOFLASHLIGHT );
  6654. }
  6655. //-----------------------------------------------------------------------------
  6656. //-----------------------------------------------------------------------------
  6657. void CBaseEntity::InputDisableDrawInFastReflection( inputdata_t &inputdata )
  6658. {
  6659. RemoveEffects( EF_MARKED_FOR_FAST_REFLECTION );
  6660. }
  6661. //-----------------------------------------------------------------------------
  6662. //-----------------------------------------------------------------------------
  6663. void CBaseEntity::InputEnableDrawInFastReflection( inputdata_t &inputdata )
  6664. {
  6665. AddEffects( EF_MARKED_FOR_FAST_REFLECTION );
  6666. }
  6667. //-----------------------------------------------------------------------------
  6668. //-----------------------------------------------------------------------------
  6669. void CBaseEntity::InputDisableDraw( inputdata_t &inputdata )
  6670. {
  6671. AddEffects( EF_NODRAW );
  6672. }
  6673. //-----------------------------------------------------------------------------
  6674. //-----------------------------------------------------------------------------
  6675. void CBaseEntity::InputEnableDraw( inputdata_t &inputdata )
  6676. {
  6677. RemoveEffects( EF_NODRAW );
  6678. }
  6679. //-----------------------------------------------------------------------------
  6680. // Purpose: An input to add a new connection from this entity
  6681. // Input : &inputdata -
  6682. //-----------------------------------------------------------------------------
  6683. void CBaseEntity::InputAddOutput( inputdata_t &inputdata )
  6684. {
  6685. char sOutputName[MAX_PATH];
  6686. Q_strncpy( sOutputName, inputdata.value.String(), sizeof(sOutputName) );
  6687. char *sChar = strchr( sOutputName, ' ' );
  6688. if ( sChar )
  6689. {
  6690. *sChar = '\0';
  6691. // Now replace all the :'s in the string with ,'s.
  6692. // Has to be done this way because Hammer doesn't allow ,'s inside parameters.
  6693. char *sColon = strchr( sChar+1, ':' );
  6694. while ( sColon )
  6695. {
  6696. *sColon = ',';
  6697. sColon = strchr( sChar+1, ':' );
  6698. }
  6699. KeyValue( sOutputName, sChar+1 );
  6700. }
  6701. else
  6702. {
  6703. Warning("AddOutput input fired with bad string. Format: <output name> <targetname>,<inputname>,<parameter>,<delay>,<max times to fire (-1 == infinite)>\n");
  6704. }
  6705. }
  6706. #include "ai_speech.h"
  6707. //-----------------------------------------------------------------------------
  6708. // Purpose:
  6709. // Input : *conceptName -
  6710. //-----------------------------------------------------------------------------
  6711. void CBaseEntity::DispatchResponse( const char *conceptName )
  6712. {
  6713. IResponseSystem *rs = GetResponseSystem();
  6714. if ( !rs )
  6715. return;
  6716. AI_CriteriaSet set;
  6717. // Always include the concept name
  6718. set.AppendCriteria( "concept", conceptName, CONCEPT_WEIGHT );
  6719. // Let NPC fill in most match criteria
  6720. ModifyOrAppendCriteria( set );
  6721. // Append local player criteria to set,too
  6722. CBasePlayer *pPlayer = UTIL_GetLocalPlayer();
  6723. if( pPlayer )
  6724. pPlayer->ModifyOrAppendPlayerCriteria( set );
  6725. // Now that we have a criteria set, ask for a suitable response
  6726. AI_Response result;
  6727. bool found = rs->FindBestResponse( set, result );
  6728. if ( !found )
  6729. {
  6730. return;
  6731. }
  6732. // Handle the response here...
  6733. char response[ 256 ];
  6734. result.GetResponse( response, sizeof( response ) );
  6735. switch ( result.GetType() )
  6736. {
  6737. case ResponseRules::RESPONSE_SPEAK:
  6738. {
  6739. EmitSound( response );
  6740. }
  6741. break;
  6742. case ResponseRules::RESPONSE_SENTENCE:
  6743. {
  6744. int sentenceIndex = SENTENCEG_Lookup( response );
  6745. if( sentenceIndex == -1 )
  6746. {
  6747. // sentence not found
  6748. break;
  6749. }
  6750. // FIXME: Get pitch from npc?
  6751. CPASAttenuationFilter filter( this );
  6752. CBaseEntity::EmitSentenceByIndex( filter, entindex(), CHAN_VOICE, sentenceIndex, 1, result.GetSoundLevel(), 0, PITCH_NORM );
  6753. }
  6754. break;
  6755. case ResponseRules::RESPONSE_SCENE:
  6756. {
  6757. // Try to fire scene w/o an actor
  6758. InstancedScriptedScene( NULL, response );
  6759. }
  6760. break;
  6761. case ResponseRules::RESPONSE_PRINT:
  6762. {
  6763. }
  6764. break;
  6765. case ResponseRules::RESPONSE_ENTITYIO:
  6766. {
  6767. CAI_Expresser::FireEntIOFromResponse( response, this );
  6768. break;
  6769. }
  6770. default:
  6771. // Don't know how to handle .vcds!!!
  6772. break;
  6773. }
  6774. }
  6775. //-----------------------------------------------------------------------------
  6776. // Purpose:
  6777. //-----------------------------------------------------------------------------
  6778. void CBaseEntity::DumpResponseCriteria( void )
  6779. {
  6780. Msg("----------------------------------------------\n");
  6781. Msg("RESPONSE CRITERIA FOR: %s (%s)\n", GetClassname(), GetDebugName() );
  6782. AI_CriteriaSet set;
  6783. // Let NPC fill in most match criteria
  6784. ModifyOrAppendCriteria( set );
  6785. // Append local player criteria to set,too
  6786. CBasePlayer *pPlayer = UTIL_GetLocalPlayer();
  6787. if ( pPlayer )
  6788. {
  6789. pPlayer->ModifyOrAppendPlayerCriteria( set );
  6790. }
  6791. // Now dump it all to console
  6792. set.Describe();
  6793. }
  6794. //------------------------------------------------------------------------------
  6795. void CC_Ent_Show_Response_Criteria( const CCommand& args )
  6796. {
  6797. CBaseEntity *pEntity = NULL;
  6798. while ( (pEntity = GetNextCommandEntity( UTIL_GetCommandClient(), args[1], pEntity )) != NULL )
  6799. {
  6800. pEntity->DumpResponseCriteria();
  6801. }
  6802. }
  6803. static ConCommand ent_show_response_criteria("ent_show_response_criteria", CC_Ent_Show_Response_Criteria, "Print, to the console, an entity's current criteria set used to select responses.\n\tArguments: {entity_name} / {class_name} / no argument picks what player is looking at ", FCVAR_CHEAT);
  6804. //------------------------------------------------------------------------------
  6805. // Purpose: Show an entity's autoaim radius
  6806. //------------------------------------------------------------------------------
  6807. void CC_Ent_Autoaim( const CCommand& args )
  6808. {
  6809. SetDebugBits( UTIL_GetCommandClient(),args[1], OVERLAY_AUTOAIM_BIT );
  6810. }
  6811. static ConCommand ent_autoaim("ent_autoaim", CC_Ent_Autoaim, "Displays the entity's autoaim radius.\n\tArguments: {entity_name} / {class_name} / no argument picks what player is looking at", FCVAR_CHEAT );
  6812. //-----------------------------------------------------------------------------
  6813. // Purpose:
  6814. //-----------------------------------------------------------------------------
  6815. CAI_BaseNPC *CBaseEntity::MyNPCPointer( void )
  6816. {
  6817. if ( IsNPC() )
  6818. return assert_cast<CAI_BaseNPC *>(this);
  6819. return NULL;
  6820. }
  6821. ConVar step_spline( "step_spline", "0" );
  6822. //-----------------------------------------------------------------------------
  6823. // Purpose: Run one tick's worth of faked simulation
  6824. // Input : *step -
  6825. //-----------------------------------------------------------------------------
  6826. void CBaseEntity::ComputeStepSimulationNetwork( StepSimulationData *step )
  6827. {
  6828. if ( !step )
  6829. {
  6830. Assert( !"ComputeStepSimulationNetworkOriginAndAngles with NULL step\n" );
  6831. return;
  6832. }
  6833. // Don't run again if we've already calculated this tick
  6834. if ( step->m_nLastProcessTickCount == gpGlobals->tickcount )
  6835. {
  6836. return;
  6837. }
  6838. step->m_nLastProcessTickCount = gpGlobals->tickcount;
  6839. // Origin
  6840. // It's inactive
  6841. if ( step->m_bOriginActive )
  6842. {
  6843. // First see if any external code moved the entity
  6844. if ( GetStepOrigin() != step->m_Next.vecOrigin )
  6845. {
  6846. step->m_bOriginActive = false;
  6847. }
  6848. else
  6849. {
  6850. // Compute interpolated info based on tick interval
  6851. float frac = 1.0f;
  6852. int tickdelta = step->m_Next.nTickCount - step->m_Previous.nTickCount;
  6853. if ( tickdelta > 0 )
  6854. {
  6855. frac = (float)( gpGlobals->tickcount - step->m_Previous.nTickCount ) / (float) tickdelta;
  6856. frac = clamp( frac, 0.0f, 1.0f );
  6857. }
  6858. if (step->m_Previous2.nTickCount == 0 || step->m_Previous2.nTickCount >= step->m_Previous.nTickCount)
  6859. {
  6860. Vector delta = step->m_Next.vecOrigin - step->m_Previous.vecOrigin;
  6861. VectorMA( step->m_Previous.vecOrigin, frac, delta, step->m_vecNetworkOrigin );
  6862. // m_vecNetworkOrigin get network in place of m_vecOrigin in the SendProxy_Origin so it needs to mark the entities state as changed.
  6863. NetworkStateChanged();
  6864. }
  6865. else if (!step_spline.GetBool())
  6866. {
  6867. StepSimulationStep *pOlder = &step->m_Previous;
  6868. StepSimulationStep *pNewer = &step->m_Next;
  6869. if (step->m_Discontinuity.nTickCount > step->m_Previous.nTickCount)
  6870. {
  6871. if (gpGlobals->tickcount > step->m_Discontinuity.nTickCount)
  6872. {
  6873. pOlder = &step->m_Discontinuity;
  6874. }
  6875. else
  6876. {
  6877. pNewer = &step->m_Discontinuity;
  6878. }
  6879. tickdelta = pNewer->nTickCount - pOlder->nTickCount;
  6880. if ( tickdelta > 0 )
  6881. {
  6882. frac = (float)( gpGlobals->tickcount - pOlder->nTickCount ) / (float) tickdelta;
  6883. frac = clamp( frac, 0.0f, 1.0f );
  6884. }
  6885. }
  6886. Vector delta = pNewer->vecOrigin - pOlder->vecOrigin;
  6887. VectorMA( pOlder->vecOrigin, frac, delta, step->m_vecNetworkOrigin );
  6888. // m_vecNetworkOrigin get network in place of m_vecOrigin in the SendProxy_Origin so it needs to mark the entities state as changed.
  6889. NetworkStateChanged();
  6890. }
  6891. else
  6892. {
  6893. Hermite_Spline( step->m_Previous2.vecOrigin, step->m_Previous.vecOrigin, step->m_Next.vecOrigin, frac, step->m_vecNetworkOrigin );
  6894. // m_vecNetworkOrigin get network in place of m_vecOrigin in the SendProxy_Origin so it needs to mark the entities state as changed.
  6895. NetworkStateChanged();
  6896. }
  6897. // Calculate the cell of this origin
  6898. register int const cellwidth = m_cellwidth; // Load it into a register
  6899. step->m_networkCell[0] = CellFromCoord( cellwidth, step->m_vecNetworkOrigin[0] );
  6900. step->m_networkCell[1] = CellFromCoord( cellwidth, step->m_vecNetworkOrigin[1] );
  6901. step->m_networkCell[2] = CellFromCoord( cellwidth, step->m_vecNetworkOrigin[2] );
  6902. }
  6903. }
  6904. // Angles
  6905. if ( step->m_bAnglesActive )
  6906. {
  6907. // See if external code changed the orientation of the entity
  6908. if ( GetStepAngles() != step->m_angNextRotation )
  6909. {
  6910. step->m_bAnglesActive = false;
  6911. }
  6912. else
  6913. {
  6914. // Compute interpolated info based on tick interval
  6915. float frac = 1.0f;
  6916. int tickdelta = step->m_Next.nTickCount - step->m_Previous.nTickCount;
  6917. if ( tickdelta > 0 )
  6918. {
  6919. frac = (float)( gpGlobals->tickcount - step->m_Previous.nTickCount ) / (float) tickdelta;
  6920. frac = clamp( frac, 0.0f, 1.0f );
  6921. }
  6922. if (step->m_Previous2.nTickCount == 0 || step->m_Previous2.nTickCount >= step->m_Previous.nTickCount)
  6923. {
  6924. // Pure blend between start/end orientations
  6925. Quaternion outangles;
  6926. QuaternionBlend( step->m_Previous.qRotation, step->m_Next.qRotation, frac, outangles );
  6927. QuaternionAngles( outangles, step->m_angNetworkAngles );
  6928. }
  6929. else if (!step_spline.GetBool())
  6930. {
  6931. StepSimulationStep *pOlder = &step->m_Previous;
  6932. StepSimulationStep *pNewer = &step->m_Next;
  6933. if (step->m_Discontinuity.nTickCount > step->m_Previous.nTickCount)
  6934. {
  6935. if (gpGlobals->tickcount > step->m_Discontinuity.nTickCount)
  6936. {
  6937. pOlder = &step->m_Discontinuity;
  6938. }
  6939. else
  6940. {
  6941. pNewer = &step->m_Discontinuity;
  6942. }
  6943. tickdelta = pNewer->nTickCount - pOlder->nTickCount;
  6944. if ( tickdelta > 0 )
  6945. {
  6946. frac = (float)( gpGlobals->tickcount - pOlder->nTickCount ) / (float) tickdelta;
  6947. frac = clamp( frac, 0.0f, 1.0f );
  6948. }
  6949. }
  6950. // Pure blend between start/end orientations
  6951. Quaternion outangles;
  6952. QuaternionBlend( pOlder->qRotation, pNewer->qRotation, frac, outangles );
  6953. QuaternionAngles( outangles, step->m_angNetworkAngles );
  6954. }
  6955. else
  6956. {
  6957. // FIXME: enable spline interpolation when turning is debounced.
  6958. Quaternion outangles;
  6959. Hermite_Spline( step->m_Previous2.qRotation, step->m_Previous.qRotation, step->m_Next.qRotation, frac, outangles );
  6960. QuaternionAngles( outangles, step->m_angNetworkAngles );
  6961. }
  6962. }
  6963. }
  6964. }
  6965. //-----------------------------------------------------------------------------
  6966. bool CBaseEntity::UseStepSimulationNetworkOrigin( const Vector **out_v, int cell[3] )
  6967. {
  6968. Assert( out_v );
  6969. if ( g_bTestMoveTypeStepSimulation &&
  6970. GetMoveType() == MOVETYPE_STEP &&
  6971. HasDataObjectType( STEPSIMULATION ) )
  6972. {
  6973. StepSimulationData *step = ( StepSimulationData * )GetDataObject( STEPSIMULATION );
  6974. ComputeStepSimulationNetwork( step );
  6975. *out_v = &step->m_vecNetworkOrigin;
  6976. if ( cell )
  6977. {
  6978. cell[0] = step->m_networkCell[0];
  6979. cell[1] = step->m_networkCell[1];
  6980. cell[2] = step->m_networkCell[2];
  6981. }
  6982. return step->m_bOriginActive;
  6983. }
  6984. return false;
  6985. }
  6986. //-----------------------------------------------------------------------------
  6987. bool CBaseEntity::UseStepSimulationNetworkAngles( const QAngle **out_a )
  6988. {
  6989. Assert( out_a );
  6990. if ( g_bTestMoveTypeStepSimulation &&
  6991. GetMoveType() == MOVETYPE_STEP &&
  6992. HasDataObjectType( STEPSIMULATION ) )
  6993. {
  6994. StepSimulationData *step = ( StepSimulationData * )GetDataObject( STEPSIMULATION );
  6995. ComputeStepSimulationNetwork( step );
  6996. *out_a = &step->m_angNetworkAngles;
  6997. return step->m_bAnglesActive;
  6998. }
  6999. return false;
  7000. }
  7001. //-----------------------------------------------------------------------------
  7002. // Purpose:
  7003. //-----------------------------------------------------------------------------
  7004. bool CBaseEntity::AddStepDiscontinuity( float flTime, const Vector &vecOrigin, const QAngle &vecAngles )
  7005. {
  7006. if ((GetMoveType() != MOVETYPE_STEP ) || !HasDataObjectType( STEPSIMULATION ) )
  7007. {
  7008. return false;
  7009. }
  7010. StepSimulationData *step = ( StepSimulationData * )GetDataObject( STEPSIMULATION );
  7011. if (!step)
  7012. {
  7013. Assert( 0 );
  7014. return false;
  7015. }
  7016. step->m_Discontinuity.nTickCount = TIME_TO_TICKS( flTime );
  7017. step->m_Discontinuity.vecOrigin = vecOrigin;
  7018. AngleQuaternion( vecAngles, step->m_Discontinuity.qRotation );
  7019. return true;
  7020. }
  7021. Vector CBaseEntity::GetStepOrigin( void ) const
  7022. {
  7023. return GetLocalOrigin();
  7024. }
  7025. QAngle CBaseEntity::GetStepAngles( void ) const
  7026. {
  7027. return GetLocalAngles();
  7028. }
  7029. //-----------------------------------------------------------------------------
  7030. // Purpose: For each client who appears to be a valid recipient, checks the client has disabled CC and if so, removes them from
  7031. // the recipient list.
  7032. // Input : filter -
  7033. //-----------------------------------------------------------------------------
  7034. void CBaseEntity::RemoveRecipientsIfNotCloseCaptioning( CRecipientFilter& filter )
  7035. {
  7036. int c = filter.GetRecipientCount();
  7037. for ( int i = c - 1; i >= 0; --i )
  7038. {
  7039. int playerIndex = filter.GetRecipientIndex( i );
  7040. CBasePlayer *player = static_cast< CBasePlayer * >( CBaseEntity::Instance( playerIndex ) );
  7041. if ( !player )
  7042. continue;
  7043. const char *cvarvalue = engine->GetClientConVarValue( playerIndex, "closecaption" );
  7044. Assert( cvarvalue );
  7045. if ( !cvarvalue[ 0 ] )
  7046. continue;
  7047. int value = atoi( cvarvalue );
  7048. // No close captions?
  7049. if ( value == 0 )
  7050. {
  7051. filter.RemoveRecipient( player );
  7052. }
  7053. }
  7054. }
  7055. //-----------------------------------------------------------------------------
  7056. // Purpose: Wrapper to emit a sentence and also a close caption token for the sentence as appropriate.
  7057. // Input : filter -
  7058. // iEntIndex -
  7059. // iChannel -
  7060. // iSentenceIndex -
  7061. // flVolume -
  7062. // iSoundlevel -
  7063. // iFlags -
  7064. // iPitch -
  7065. // bUpdatePositions -
  7066. // soundtime -
  7067. //-----------------------------------------------------------------------------
  7068. void CBaseEntity::EmitSentenceByIndex( IRecipientFilter& filter, int iEntIndex, int iChannel, int iSentenceIndex,
  7069. float flVolume, soundlevel_t iSoundlevel, int iFlags /*= 0*/, int iPitch /*=PITCH_NORM*/,
  7070. const Vector *pOrigin /*=NULL*/, const Vector *pDirection /*=NULL*/,
  7071. bool bUpdatePositions /*=true*/, float soundtime /*=0.0f*/ )
  7072. {
  7073. CUtlVector< Vector > dummy;
  7074. enginesound->EmitSentenceByIndex( filter, iEntIndex, iChannel, iSentenceIndex,
  7075. flVolume, iSoundlevel, 0, iFlags, iPitch, pOrigin, pDirection, &dummy, bUpdatePositions, soundtime );
  7076. }
  7077. void CBaseEntity::SetRefEHandle( const CBaseHandle &handle )
  7078. {
  7079. m_RefEHandle = handle;
  7080. if ( edict() )
  7081. {
  7082. edict()->m_NetworkSerialNumber = (m_RefEHandle.GetSerialNumber() & (1 << NUM_NETWORKED_EHANDLE_SERIAL_NUMBER_BITS) - 1);
  7083. }
  7084. }
  7085. bool CPointEntity::KeyValue( const char *szKeyName, const char *szValue )
  7086. {
  7087. if ( FStrEq( szKeyName, "mins" ) || FStrEq( szKeyName, "maxs" ) )
  7088. {
  7089. Warning("Warning! Can't specify mins/maxs for point entities! (%s)\n", GetClassname() );
  7090. return true;
  7091. }
  7092. return BaseClass::KeyValue( szKeyName, szValue );
  7093. }
  7094. bool CServerOnlyPointEntity::KeyValue( const char *szKeyName, const char *szValue )
  7095. {
  7096. if ( FStrEq( szKeyName, "mins" ) || FStrEq( szKeyName, "maxs" ) )
  7097. {
  7098. Warning("Warning! Can't specify mins/maxs for point entities! (%s)\n", GetClassname() );
  7099. return true;
  7100. }
  7101. return BaseClass::KeyValue( szKeyName, szValue );
  7102. }
  7103. bool CLogicalEntity::KeyValue( const char *szKeyName, const char *szValue )
  7104. {
  7105. if ( FStrEq( szKeyName, "mins" ) || FStrEq( szKeyName, "maxs" ) )
  7106. {
  7107. Warning("Warning! Can't specify mins/maxs for point entities! (%s)\n", GetClassname() );
  7108. return true;
  7109. }
  7110. return BaseClass::KeyValue( szKeyName, szValue );
  7111. }
  7112. //-----------------------------------------------------------------------------
  7113. // Purpose: Sets the entity invisible, and makes it remove itself on the next frame
  7114. //-----------------------------------------------------------------------------
  7115. void CBaseEntity::RemoveDeferred( void )
  7116. {
  7117. // Set our next think to remove us
  7118. SetThink( &CBaseEntity::SUB_Remove );
  7119. SetNextThink( gpGlobals->curtime + 0.1f );
  7120. // Hide us completely
  7121. AddEffects( EF_NODRAW );
  7122. AddSolidFlags( FSOLID_NOT_SOLID );
  7123. SetMoveType( MOVETYPE_NONE );
  7124. }
  7125. #define MIN_CORPSE_FADE_TIME 10.0
  7126. #define MIN_CORPSE_FADE_DIST 256.0
  7127. #define MAX_CORPSE_FADE_DIST 1500.0
  7128. //
  7129. // fade out - slowly fades a entity out, then removes it.
  7130. //
  7131. // DON'T USE ME FOR GIBS AND STUFF IN MULTIPLAYER!
  7132. // SET A FUTURE THINK AND A RENDERMODE!!
  7133. void CBaseEntity::SUB_StartFadeOut( float delay, bool notSolid )
  7134. {
  7135. SetThink( &CBaseEntity::SUB_FadeOut );
  7136. SetNextThink( gpGlobals->curtime + delay );
  7137. SetRenderAlpha( 255 );
  7138. m_nRenderMode = kRenderNormal;
  7139. if ( notSolid )
  7140. {
  7141. AddSolidFlags( FSOLID_NOT_SOLID );
  7142. SetLocalAngularVelocity( vec3_angle );
  7143. }
  7144. }
  7145. void CBaseEntity::SUB_StartFadeOutInstant()
  7146. {
  7147. SUB_StartFadeOut( 0, true );
  7148. }
  7149. //-----------------------------------------------------------------------------
  7150. // Purpose: Vanish when players aren't looking
  7151. //-----------------------------------------------------------------------------
  7152. void CBaseEntity::SUB_Vanish( void )
  7153. {
  7154. //Always think again next frame
  7155. SetNextThink( gpGlobals->curtime + 0.1f );
  7156. CBasePlayer *pPlayer;
  7157. //Get all players
  7158. for ( int i = 1; i <= gpGlobals->maxClients; i++ )
  7159. {
  7160. //Get the next client
  7161. if ( ( pPlayer = UTIL_PlayerByIndex( i ) ) != NULL )
  7162. {
  7163. Vector corpseDir = (GetAbsOrigin() - pPlayer->WorldSpaceCenter() );
  7164. float flDistSqr = corpseDir.LengthSqr();
  7165. //If the player is close enough, don't fade out
  7166. if ( flDistSqr < (MIN_CORPSE_FADE_DIST*MIN_CORPSE_FADE_DIST) )
  7167. return;
  7168. // If the player's far enough away, we don't care about looking at it
  7169. if ( flDistSqr < (MAX_CORPSE_FADE_DIST*MAX_CORPSE_FADE_DIST) )
  7170. {
  7171. VectorNormalize( corpseDir );
  7172. Vector plForward;
  7173. pPlayer->EyeVectors( &plForward );
  7174. float dot = plForward.Dot( corpseDir );
  7175. if ( dot > 0.0f )
  7176. return;
  7177. }
  7178. }
  7179. }
  7180. //If we're here, then we can vanish safely
  7181. m_iHealth = 0;
  7182. SetThink( &CBaseEntity::SUB_Remove );
  7183. }
  7184. void CBaseEntity::SUB_PerformFadeOut( void )
  7185. {
  7186. float dt = gpGlobals->frametime;
  7187. if ( dt > 0.1f )
  7188. {
  7189. dt = 0.1f;
  7190. }
  7191. m_nRenderMode = kRenderTransTexture;
  7192. int speed = MAX(1,256*dt); // fade out over 1 second
  7193. SetRenderAlpha( UTIL_Approach( 0, m_clrRender->a, speed ) );
  7194. }
  7195. bool CBaseEntity::SUB_AllowedToFade( void )
  7196. {
  7197. if( VPhysicsGetObject() )
  7198. {
  7199. if( VPhysicsGetObject()->GetGameFlags() & FVPHYSICS_PLAYER_HELD || GetEFlags() & EFL_IS_BEING_LIFTED_BY_BARNACLE )
  7200. return false;
  7201. }
  7202. // only keep fading things active on the high end
  7203. #if !defined( PORTAL2 )
  7204. if ( !IsGameConsole() )
  7205. {
  7206. CBasePlayer *pPlayer = ( AI_IsSinglePlayer() ) ? UTIL_GetLocalPlayer() : NULL;
  7207. if ( pPlayer && pPlayer->FInViewCone( this ) )
  7208. return false;
  7209. }
  7210. #endif
  7211. return true;
  7212. }
  7213. //-----------------------------------------------------------------------------
  7214. // Purpose: Fade out slowly
  7215. //-----------------------------------------------------------------------------
  7216. void CBaseEntity::SUB_FadeOut( void )
  7217. {
  7218. if ( SUB_AllowedToFade() == false )
  7219. {
  7220. SetNextThink( gpGlobals->curtime + 1 );
  7221. SetRenderAlpha( 255 );
  7222. return;
  7223. }
  7224. SUB_PerformFadeOut();
  7225. if ( m_clrRender->a == 0 )
  7226. {
  7227. UTIL_Remove(this);
  7228. }
  7229. else
  7230. {
  7231. SetNextThink( gpGlobals->curtime );
  7232. }
  7233. }
  7234. //-----------------------------------------------------------------------------
  7235. //
  7236. //-----------------------------------------------------------------------------
  7237. HSCRIPT CBaseEntity::GetScriptInstance()
  7238. {
  7239. if ( !m_hScriptInstance )
  7240. {
  7241. if ( m_iszScriptId == NULL_STRING )
  7242. {
  7243. char *szName = (char *)stackalloc( 1024 );
  7244. g_pScriptVM->GenerateUniqueKey( ( m_iName.Get() != NULL_STRING ) ? STRING(GetEntityName()) : GetClassname(), szName, 1024 );
  7245. m_iszScriptId = AllocPooledString( szName );
  7246. }
  7247. m_hScriptInstance = g_pScriptVM->RegisterInstance( GetScriptDesc(), this );
  7248. g_pScriptVM->SetInstanceUniqeId( m_hScriptInstance, STRING(m_iszScriptId) );
  7249. }
  7250. return m_hScriptInstance;
  7251. }
  7252. //-----------------------------------------------------------------------------
  7253. // Using my edict, cook up a unique VScript scope that's private to me, and
  7254. // persistent.
  7255. //-----------------------------------------------------------------------------
  7256. bool CBaseEntity::ValidateScriptScope()
  7257. {
  7258. if ( !m_ScriptScope.IsInitialized() )
  7259. {
  7260. if( scriptmanager == NULL )
  7261. {
  7262. ExecuteOnce( DevMsg( "Cannot execute script because scripting is disabled (-scripting)\n" ) );
  7263. return false;
  7264. }
  7265. if( g_pScriptVM == NULL )
  7266. {
  7267. ExecuteOnce( DevMsg(" Cannot execute script because there is no available VM\n" ) );
  7268. return false;
  7269. }
  7270. // Force instance creation
  7271. GetScriptInstance();
  7272. EHANDLE hThis;
  7273. hThis.Set( this );
  7274. bool bResult = m_ScriptScope.Init( STRING(m_iszScriptId) );
  7275. if( !bResult )
  7276. {
  7277. DevMsg("%s couldn't create ScriptScope!\n", GetDebugName() );
  7278. return false;
  7279. }
  7280. g_pScriptVM->SetValue( m_ScriptScope, "self", GetScriptInstance() );
  7281. }
  7282. return true;
  7283. }
  7284. //-----------------------------------------------------------------------------
  7285. // Purpose: Run all of the vscript files that are set in this entity's VSCRIPTS
  7286. // field in Hammer. The list is space-delimited.
  7287. //-----------------------------------------------------------------------------
  7288. void CBaseEntity::RunVScripts()
  7289. {
  7290. if( m_iszVScripts == NULL_STRING )
  7291. {
  7292. return;
  7293. }
  7294. ValidateScriptScope();
  7295. // All functions we want to have call chained instead of overwritten
  7296. // by other scripts in this entities list.
  7297. static const char * sCallChainFunctions[] =
  7298. {
  7299. "OnPostSpawn",
  7300. "Precache"
  7301. };
  7302. ScriptLanguage_t language = g_pScriptVM->GetLanguage();
  7303. // Make a call chainer for each in this entities scope
  7304. for ( int j = 0; j < ARRAYSIZE( sCallChainFunctions ); ++j )
  7305. {
  7306. if ( language == SL_PYTHON )
  7307. {
  7308. // UNDONE - handle call chaining in python
  7309. ;
  7310. }
  7311. else if ( language == SL_SQUIRREL )
  7312. {
  7313. //TODO: For perf, this should be precompiled and the %s should be passed as a parameter
  7314. HSCRIPT hCreateChainScript = g_pScriptVM->CompileScript( CFmtStr( "%sCallChain <- CSimpleCallChainer(\"%s\", self.GetScriptScope(), true)", sCallChainFunctions[j], sCallChainFunctions[j] ) );
  7315. g_pScriptVM->Run( hCreateChainScript, (HSCRIPT)m_ScriptScope );
  7316. g_pScriptVM->ReleaseScript( hCreateChainScript );
  7317. }
  7318. }
  7319. char szScriptsList[255];
  7320. V_strcpy_safe( szScriptsList, STRING(m_iszVScripts) );
  7321. CUtlStringList szScripts;
  7322. V_SplitString( szScriptsList, " ", szScripts);
  7323. for( int i = 0 ; i < szScripts.Count() ; i++ )
  7324. {
  7325. Log_Msg( LOG_VScript, "%s executing script: %s\n", GetDebugName(), szScripts[i] );
  7326. RunScriptFile( szScripts[i], IsWorld() );
  7327. for ( int j = 0; j < ARRAYSIZE( sCallChainFunctions ); ++j )
  7328. {
  7329. if ( language == SL_PYTHON )
  7330. {
  7331. // UNDONE - handle call chaining in python
  7332. ;
  7333. }
  7334. else if ( language == SL_SQUIRREL )
  7335. {
  7336. //TODO: For perf, this should be precompiled and the %s should be passed as a parameter.
  7337. HSCRIPT hRunPostScriptExecute = g_pScriptVM->CompileScript( CFmtStr( "%sCallChain.PostScriptExecute()", sCallChainFunctions[j] ) );
  7338. g_pScriptVM->Run( hRunPostScriptExecute, (HSCRIPT)m_ScriptScope );
  7339. g_pScriptVM->ReleaseScript( hRunPostScriptExecute );
  7340. }
  7341. }
  7342. }
  7343. if( m_iszScriptThinkFunction != NULL_STRING )
  7344. {
  7345. SetContextThink( &CBaseEntity::ScriptThink, gpGlobals->curtime + sv_script_think_interval.GetFloat(), "ScriptThink" );
  7346. }
  7347. }
  7348. //--------------------------------------------------------------------------------------------------
  7349. // This is called during entity spawning and after restore to allow scripts to precache any
  7350. // resources they need.
  7351. //--------------------------------------------------------------------------------------------------
  7352. void CBaseEntity::RunPrecacheScripts( void )
  7353. {
  7354. if( m_iszVScripts == NULL_STRING )
  7355. {
  7356. return;
  7357. }
  7358. HSCRIPT hScriptPrecache = m_ScriptScope.LookupFunction( "DispatchPrecache" );
  7359. if ( hScriptPrecache )
  7360. {
  7361. g_pScriptVM->Call( hScriptPrecache, m_ScriptScope );
  7362. m_ScriptScope.ReleaseFunction( hScriptPrecache );
  7363. }
  7364. }
  7365. void CBaseEntity::RunOnPostSpawnScripts( void )
  7366. {
  7367. if( m_iszVScripts == NULL_STRING )
  7368. {
  7369. return;
  7370. }
  7371. HSCRIPT hFuncConnect = g_pScriptVM->LookupFunction("ConnectOutputs");
  7372. if ( hFuncConnect )
  7373. {
  7374. g_pScriptVM->Call( hFuncConnect, NULL, true, NULL, (HSCRIPT)m_ScriptScope );
  7375. g_pScriptVM->ReleaseFunction( hFuncConnect );
  7376. }
  7377. HSCRIPT hFuncDisp = m_ScriptScope.LookupFunction( "DispatchOnPostSpawn" );
  7378. if ( hFuncDisp )
  7379. {
  7380. variant_t variant;
  7381. variant.SetString( MAKE_STRING("DispatchOnPostSpawn") );
  7382. g_EventQueue.AddEvent( this, "CallScriptFunction", variant, 0, this, this );
  7383. m_ScriptScope.ReleaseFunction( hFuncDisp );
  7384. }
  7385. }
  7386. HSCRIPT CBaseEntity::GetScriptOwnerEntity()
  7387. {
  7388. return ToHScript( GetOwnerEntity() );
  7389. }
  7390. void CBaseEntity::SetScriptOwnerEntity( HSCRIPT pOwner )
  7391. {
  7392. SetOwnerEntity( ToEnt( pOwner ) );
  7393. }
  7394. inline bool AnyPlayersInHierarchy_R( CBaseEntity *pEnt )
  7395. {
  7396. if ( pEnt->IsPlayer() )
  7397. return true;
  7398. for ( CBaseEntity *pCur = pEnt->FirstMoveChild(); pCur; pCur=pCur->NextMovePeer() )
  7399. {
  7400. if ( AnyPlayersInHierarchy_R( pCur ) )
  7401. return true;
  7402. }
  7403. return false;
  7404. }
  7405. void CBaseEntity::RecalcHasPlayerChildBit()
  7406. {
  7407. if ( AnyPlayersInHierarchy_R( this ) )
  7408. AddEFlags( EFL_HAS_PLAYER_CHILD );
  7409. else
  7410. RemoveEFlags( EFL_HAS_PLAYER_CHILD );
  7411. }
  7412. bool CBaseEntity::DoesHavePlayerChild()
  7413. {
  7414. return IsEFlagSet( EFL_HAS_PLAYER_CHILD );
  7415. }
  7416. void CBaseEntity::SetFriction( float flFriction )
  7417. {
  7418. m_flFriction = flFriction;
  7419. #if defined(ENABLE_FRICTION_OVERRIDE)
  7420. if ( GetIndexForThinkContext( "FrictionRevertThink" ) != NO_THINK_CONTEXT )
  7421. {
  7422. SetContextThink( NULL, TICK_NEVER_THINK, "FrictionRevertThink" );
  7423. }
  7424. #endif
  7425. }
  7426. #if defined(ENABLE_FRICTION_OVERRIDE)
  7427. void CBaseEntity::FrictionRevertThink( void )
  7428. {
  7429. SetFriction( m_flOverriddenFriction );
  7430. }
  7431. void CBaseEntity::OverrideFriction( float duration, float friction )
  7432. {
  7433. if ( GetIndexForThinkContext( "FrictionRevertThink" ) == NO_THINK_CONTEXT || GetNextThinkTick( "FrictionRevertThink" ) == TICK_NEVER_THINK )
  7434. {
  7435. // not already overriding friction. this is what we'll restore to.
  7436. m_flOverriddenFriction = m_flFriction;
  7437. }
  7438. m_flFriction = friction;
  7439. SetContextThink( &CBaseEntity::FrictionRevertThink, gpGlobals->curtime + duration, "FrictionRevertThink" );
  7440. }
  7441. #endif
  7442. void CBaseEntity::SetNetworkQuantizeOriginAngAngles( bool bQuantize )
  7443. {
  7444. m_bNetworkQuantizeOriginAndAngles = bQuantize;
  7445. }
  7446. // NOTE: This only quantizes to the default entity precision currently used by CBaseEntity!!!
  7447. void CBaseEntity::NetworkQuantize( Vector &org, QAngle &angles )
  7448. {
  7449. #if PREDICTION_ERROR_CHECK_LEVEL < 2
  7450. // Angles are sent with 13 (SENDPROP_ANGROTATION_DEFAULT_BITS)bits to represent 0 -> 359.??? (SPROP_ROUNDDOWN)
  7451. const float QUANTIZE_MIN_ANGLE = 0.0f;
  7452. const float QUANTIZE_MAX_ANGLE = 360.0f - 360.0f / (float)( 1 << SENDPROP_ANGROTATION_DEFAULT_BITS );
  7453. const unsigned long QUANTIZE_HIGH_VALUE = ((1 << (unsigned long)SENDPROP_ANGROTATION_DEFAULT_BITS) - 1);
  7454. const double QUANTIZE_RANGE = QUANTIZE_MAX_ANGLE - QUANTIZE_MIN_ANGLE;
  7455. const float QUANTIZE_HIGHLOWMULTIPLIER = QUANTIZE_HIGH_VALUE / QUANTIZE_RANGE;
  7456. if ( !m_bNetworkQuantizeOriginAndAngles )
  7457. return;
  7458. if ( !( SENDPROP_VECORIGIN_FLAGS & SPROP_NOSCALE ) )
  7459. {
  7460. COMPILE_TIME_ASSERT( SENDPROP_VECORIGIN_FLAGS & ( SPROP_COORD | SPROP_CELL_COORD ) );
  7461. COMPILE_TIME_ASSERT( !(SENDPROP_VECORIGIN_FLAGS & ( SPROP_COORD_MP_LOWPRECISION | SPROP_COORD_MP_INTEGRAL ) ) );
  7462. for ( int i = 0 ; i < 3; ++i )
  7463. {
  7464. // Crop to exact bit precision
  7465. int tmp = RoundFloatToInt( org[ i ] * COORD_DENOMINATOR );
  7466. org[ i ] = (float)tmp * COORD_RESOLUTION;
  7467. }
  7468. }
  7469. if ( SENDPROP_ANGROTATION_DEFAULT_BITS != -1 )
  7470. {
  7471. for ( int i = 0 ; i < 3; ++i )
  7472. {
  7473. float flAngNormalized = anglemod( angles[ i ] );
  7474. float flAngle = ( flAngNormalized - QUANTIZE_MIN_ANGLE ) * QUANTIZE_HIGHLOWMULTIPLIER;
  7475. unsigned int uiAngle = RoundFloatToUnsignedLong( flAngle );
  7476. angles[ i ] = QUANTIZE_MIN_ANGLE + (float)uiAngle / QUANTIZE_HIGHLOWMULTIPLIER;
  7477. }
  7478. }
  7479. #endif
  7480. }
  7481. //------------------------------------------------------------------------------
  7482. bool CBaseEntity::ShouldLagCompensate() const
  7483. {
  7484. return m_bLagCompensate;
  7485. }
  7486. //------------------------------------------------------------------------------
  7487. void CBaseEntity::SetPendingTeamNum( int nTeamID )
  7488. {
  7489. m_iPendingTeamNum = nTeamID;
  7490. }
  7491. void CBaseEntity::ClearSpotRule( int bRuleFlags )
  7492. {
  7493. m_nSpotRules = m_nSpotRules & ~bRuleFlags;
  7494. }
  7495. void CBaseEntity::SetSpotRules( int nRuleFlags )
  7496. {
  7497. m_nSpotRules |= nRuleFlags;
  7498. }
  7499. bool CBaseEntity::IsSpotted()
  7500. {
  7501. return m_bSpotted;
  7502. }
  7503. void CBaseEntity::SetIsSpotted( bool bSpotted )
  7504. {
  7505. m_bSpotted = bSpotted;
  7506. }
  7507. void CBaseEntity::ClearSpottedBy( void )
  7508. {
  7509. for ( int i = 0; i < kNumSpottedByMask; i++ )
  7510. m_bSpottedByMask.Set(i,0);
  7511. }
  7512. void CBaseEntity::SetIsSpottedBy( int nPlayerEntIndex )
  7513. {
  7514. Assert( nPlayerEntIndex > 0 && nPlayerEntIndex <= MAX_PLAYERS );
  7515. if ( nPlayerEntIndex > 0 && nPlayerEntIndex <= MAX_PLAYERS )
  7516. {
  7517. int maskBitIndex = nPlayerEntIndex - 1; // player ents start at 1
  7518. int maskIndex = BitVec_Int( maskBitIndex );
  7519. m_bSpottedByMask.Set( maskIndex, m_bSpottedByMask.Get( maskIndex ) | BitVec_Bit( maskBitIndex ) );
  7520. }
  7521. }
  7522. int CBaseEntity::GetSpotRules( void )
  7523. {
  7524. return m_nSpotRules;
  7525. }
  7526. bool CBaseEntity::CanBeSpotted( void )
  7527. {
  7528. return ( m_nSpotRules != 0 );
  7529. }
  7530. //------------------------------------------------------------------------------
  7531. // Purpose: Create an NPC of the given type
  7532. //------------------------------------------------------------------------------
  7533. void CC_Ent_Create( const CCommand& args )
  7534. {
  7535. MDLCACHE_CRITICAL_SECTION();
  7536. bool allowPrecache = CBaseEntity::IsPrecacheAllowed();
  7537. CBaseEntity::SetAllowPrecache( true );
  7538. // Try to create entity
  7539. CBaseEntity *entity = dynamic_cast< CBaseEntity * >( CreateEntityByName(args[1]) );
  7540. if (entity)
  7541. {
  7542. if ( entity->IsPlayer() )
  7543. {
  7544. AssertMsg( false, "Cannot ent_create players!" );
  7545. Warning( "Cannot ent_create players!\n" );
  7546. UTIL_Remove( entity );
  7547. }
  7548. else
  7549. {
  7550. entity->Precache();
  7551. DispatchSpawn(entity);
  7552. // Now attempt to drop into the world
  7553. CBasePlayer* pPlayer = UTIL_GetCommandClient();
  7554. trace_t tr;
  7555. Vector forward;
  7556. pPlayer->EyeVectors( &forward );
  7557. UTIL_TraceLine(pPlayer->EyePosition(),
  7558. pPlayer->EyePosition() + forward * MAX_TRACE_LENGTH,MASK_SOLID,
  7559. pPlayer, COLLISION_GROUP_NONE, &tr );
  7560. if ( tr.fraction != 1.0 )
  7561. {
  7562. // Raise the end position a little up off the floor, place the npc and drop him down
  7563. tr.endpos.z += 12;
  7564. QAngle vecOppositePlayerAngles = pPlayer->GetAbsAngles();
  7565. vecOppositePlayerAngles[YAW] += 180;
  7566. entity->Teleport( &tr.endpos, &vecOppositePlayerAngles, NULL );
  7567. UTIL_DropToFloor( entity, MASK_SOLID );
  7568. }
  7569. }
  7570. }
  7571. CBaseEntity::SetAllowPrecache( allowPrecache );
  7572. }
  7573. static ConCommand ent_create("ent_create", CC_Ent_Create, "Creates an entity of the given type where the player is looking.", FCVAR_GAMEDLL | FCVAR_CHEAT);
  7574. //------------------------------------------------------------------------------
  7575. // Purpose: Teleport a specified entity to where the player is looking
  7576. //------------------------------------------------------------------------------
  7577. bool CC_GetCommandEnt( const CCommand& args, CBaseEntity **ent, Vector *vecTargetPoint, QAngle *vecPlayerAngle )
  7578. {
  7579. // Find the entity
  7580. *ent = NULL;
  7581. // First try using it as an entindex
  7582. int iEntIndex = atoi( args[1] );
  7583. if ( iEntIndex )
  7584. {
  7585. *ent = CBaseEntity::Instance( iEntIndex );
  7586. }
  7587. else
  7588. {
  7589. // Try finding it by name
  7590. *ent = gEntList.FindEntityByName( NULL, args[1] );
  7591. if ( !*ent )
  7592. {
  7593. // Finally, try finding it by classname
  7594. *ent = gEntList.FindEntityByClassname( NULL, args[1] );
  7595. }
  7596. }
  7597. if ( !*ent )
  7598. {
  7599. Msg( "Couldn't find any entity named '%s'\n", args[1] );
  7600. return false;
  7601. }
  7602. CBasePlayer *pPlayer = UTIL_GetCommandClient();
  7603. if ( vecTargetPoint )
  7604. {
  7605. trace_t tr;
  7606. Vector forward;
  7607. pPlayer->EyeVectors( &forward );
  7608. UTIL_TraceLine(pPlayer->EyePosition(),
  7609. pPlayer->EyePosition() + forward * MAX_TRACE_LENGTH,MASK_NPCSOLID,
  7610. pPlayer, COLLISION_GROUP_NONE, &tr );
  7611. if ( tr.fraction != 1.0 )
  7612. {
  7613. *vecTargetPoint = tr.endpos;
  7614. }
  7615. }
  7616. if ( vecPlayerAngle )
  7617. {
  7618. *vecPlayerAngle = pPlayer->EyeAngles();
  7619. }
  7620. return true;
  7621. }
  7622. //------------------------------------------------------------------------------
  7623. // Purpose: Teleport a specified entity to where the player is looking
  7624. //------------------------------------------------------------------------------
  7625. void CC_Ent_Teleport( const CCommand& args )
  7626. {
  7627. if ( args.ArgC() < 2 )
  7628. {
  7629. Msg( "Format: ent_teleport <entity name>\n" );
  7630. return;
  7631. }
  7632. CBaseEntity *pEnt;
  7633. Vector vecTargetPoint;
  7634. if ( CC_GetCommandEnt( args, &pEnt, &vecTargetPoint, NULL ) )
  7635. {
  7636. pEnt->Teleport( &vecTargetPoint, NULL, NULL );
  7637. }
  7638. }
  7639. static ConCommand ent_teleport("ent_teleport", CC_Ent_Teleport, "Teleport the specified entity to where the player is looking.\n\tFormat: ent_teleport <entity name>", FCVAR_CHEAT);
  7640. //------------------------------------------------------------------------------
  7641. // Purpose: Orient a specified entity to match the player's angles
  7642. //------------------------------------------------------------------------------
  7643. void CC_Ent_Orient( const CCommand& args )
  7644. {
  7645. if ( args.ArgC() < 2 )
  7646. {
  7647. Msg( "Format: ent_orient <entity name> <optional: allangles>\n" );
  7648. return;
  7649. }
  7650. CBaseEntity *pEnt;
  7651. QAngle vecPlayerAngles;
  7652. if ( CC_GetCommandEnt( args, &pEnt, NULL, &vecPlayerAngles ) )
  7653. {
  7654. QAngle vecEntAngles = pEnt->GetAbsAngles();
  7655. if ( args.ArgC() == 3 && StringHasPrefixCaseSensitive( args[2], "allangles" ) )
  7656. {
  7657. vecEntAngles = vecPlayerAngles;
  7658. }
  7659. else
  7660. {
  7661. vecEntAngles[YAW] = vecPlayerAngles[YAW];
  7662. }
  7663. pEnt->SetAbsAngles( vecEntAngles );
  7664. }
  7665. }
  7666. static ConCommand ent_orient("ent_orient", CC_Ent_Orient, "Orient the specified entity to match the player's angles. By default, only orients target entity's YAW. Use the 'allangles' option to orient on all axis.\n\tFormat: ent_orient <entity name> <optional: allangles>", FCVAR_CHEAT);