Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

343 lines
9.2 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: CS's custom CPlayerResource
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include "cbase.h"
  8. #include "cs_player.h"
  9. #include "player_resource.h"
  10. #include "cs_simple_hostage.h"
  11. #include "cs_player_resource.h"
  12. #include "weapon_c4.h"
  13. #include <coordsize.h>
  14. #include "cs_bot_manager.h"
  15. #include "cs_gamerules.h"
  16. // Datatable
  17. IMPLEMENT_SERVERCLASS_ST(CCSPlayerResource, DT_CSPlayerResource)
  18. SendPropInt( SENDINFO( m_iPlayerC4 ), 8, SPROP_UNSIGNED ),
  19. SendPropInt( SENDINFO( m_iPlayerVIP ), 8, SPROP_UNSIGNED ),
  20. SendPropVector( SENDINFO(m_vecC4), -1, SPROP_COORD),
  21. SendPropArray3( SENDINFO_ARRAY3(m_bHostageAlive), SendPropInt( SENDINFO_ARRAY(m_bHostageAlive), 1, SPROP_UNSIGNED ) ),
  22. SendPropArray3( SENDINFO_ARRAY3(m_isHostageFollowingSomeone), SendPropInt( SENDINFO_ARRAY(m_isHostageFollowingSomeone), 1, SPROP_UNSIGNED ) ),
  23. SendPropArray3( SENDINFO_ARRAY3(m_iHostageEntityIDs), SendPropInt( SENDINFO_ARRAY(m_iHostageEntityIDs), -1, SPROP_UNSIGNED ) ),
  24. SendPropArray3( SENDINFO_ARRAY3(m_iHostageY), SendPropInt( SENDINFO_ARRAY(m_iHostageY), COORD_INTEGER_BITS+1, 0 ) ),
  25. SendPropArray3( SENDINFO_ARRAY3(m_iHostageX), SendPropInt( SENDINFO_ARRAY(m_iHostageX), COORD_INTEGER_BITS+1, 0 ) ),
  26. SendPropArray3( SENDINFO_ARRAY3(m_iHostageZ), SendPropInt( SENDINFO_ARRAY(m_iHostageZ), COORD_INTEGER_BITS+1, 0 ) ),
  27. SendPropVector( SENDINFO(m_bombsiteCenterA), -1, SPROP_COORD),
  28. SendPropVector( SENDINFO(m_bombsiteCenterB), -1, SPROP_COORD),
  29. SendPropArray3( SENDINFO_ARRAY3(m_hostageRescueX), SendPropInt( SENDINFO_ARRAY(m_hostageRescueX), COORD_INTEGER_BITS+1, 0 ) ),
  30. SendPropArray3( SENDINFO_ARRAY3(m_hostageRescueY), SendPropInt( SENDINFO_ARRAY(m_hostageRescueY), COORD_INTEGER_BITS+1, 0 ) ),
  31. SendPropArray3( SENDINFO_ARRAY3(m_hostageRescueZ), SendPropInt( SENDINFO_ARRAY(m_hostageRescueZ), COORD_INTEGER_BITS+1, 0 ) ),
  32. SendPropBool( SENDINFO( m_bBombSpotted ) ),
  33. SendPropArray3( SENDINFO_ARRAY3(m_bPlayerSpotted), SendPropInt( SENDINFO_ARRAY(m_bPlayerSpotted), 1, SPROP_UNSIGNED ) ),
  34. SendPropArray3( SENDINFO_ARRAY3(m_iMVPs), SendPropInt( SENDINFO_ARRAY(m_iMVPs), COORD_INTEGER_BITS+1, SPROP_UNSIGNED ) ),
  35. SendPropArray3( SENDINFO_ARRAY3(m_bHasDefuser), SendPropInt( SENDINFO_ARRAY(m_bHasDefuser), 1, SPROP_UNSIGNED ) ),
  36. SendPropArray3( SENDINFO_ARRAY3(m_szClan), SendPropStringT( SENDINFO_ARRAY(m_szClan) ) ),
  37. END_SEND_TABLE()
  38. //=============================================================================
  39. // HPE_END
  40. //=============================================================================
  41. BEGIN_DATADESC( CCSPlayerResource )
  42. // DEFINE_ARRAY( m_iPing, FIELD_INTEGER, MAX_PLAYERS+1 ),
  43. // DEFINE_ARRAY( m_iPacketloss, FIELD_INTEGER, MAX_PLAYERS+1 ),
  44. END_DATADESC()
  45. LINK_ENTITY_TO_CLASS( cs_player_manager, CCSPlayerResource );
  46. CCSPlayerResource::CCSPlayerResource( void )
  47. {
  48. }
  49. //--------------------------------------------------------------------------------------------------------
  50. class Spotter
  51. {
  52. public:
  53. Spotter( CBaseEntity *entity, const Vector &target, int spottingTeam )
  54. {
  55. m_targetEntity = entity;
  56. m_target = target;
  57. m_team = spottingTeam;
  58. m_spotted = false;
  59. }
  60. bool operator()( CBasePlayer *player )
  61. {
  62. if ( !player->IsAlive() || player->GetTeamNumber() != m_team )
  63. return true;
  64. CCSPlayer *csPlayer = ToCSPlayer( player );
  65. if ( !csPlayer )
  66. return true;
  67. if ( csPlayer->IsBlind() )
  68. return true;
  69. Vector eye, forward;
  70. player->EyePositionAndVectors( &eye, &forward, NULL, NULL );
  71. Vector path( m_target - eye );
  72. float distance = path.Length();
  73. path.NormalizeInPlace();
  74. float dot = DotProduct( forward, path );
  75. if( (dot > 0.995f )
  76. || (dot > 0.98f && distance < 900)
  77. || (dot > 0.8f && distance < 250)
  78. )
  79. {
  80. trace_t tr;
  81. CTraceFilterSkipTwoEntities filter( player, m_targetEntity, COLLISION_GROUP_DEBRIS );
  82. UTIL_TraceLine( eye, m_target,
  83. (CONTENTS_OPAQUE|CONTENTS_SOLID|CONTENTS_MOVEABLE|CONTENTS_DEBRIS), &filter, &tr );
  84. if( tr.fraction == 1.0f )
  85. {
  86. if ( TheCSBots()->IsLineBlockedBySmoke( eye, m_target ) )
  87. {
  88. return true;
  89. }
  90. m_spotted = true;
  91. return false; // spotted already, so no reason to check for other players spotting the same thing.
  92. }
  93. }
  94. return true;
  95. }
  96. bool Spotted( void ) const
  97. {
  98. return m_spotted;
  99. }
  100. private:
  101. CBaseEntity *m_targetEntity;
  102. Vector m_target;
  103. int m_team;
  104. bool m_spotted;
  105. };
  106. //-----------------------------------------------------------------------------
  107. // Purpose:
  108. //-----------------------------------------------------------------------------
  109. void CCSPlayerResource::UpdatePlayerData( void )
  110. {
  111. int i;
  112. m_iPlayerC4 = 0;
  113. m_iPlayerVIP = 0;
  114. for ( i = 1; i <= gpGlobals->maxClients; i++ )
  115. {
  116. CCSPlayer *pPlayer = (CCSPlayer*)UTIL_PlayerByIndex( i );
  117. if ( pPlayer && pPlayer->IsConnected() )
  118. {
  119. if ( pPlayer->IsVIP() )
  120. {
  121. // we should only have one VIP
  122. Assert( m_iPlayerVIP == 0 );
  123. m_iPlayerVIP = i;
  124. }
  125. if ( pPlayer->HasC4() )
  126. {
  127. // we should only have one bomb
  128. m_iPlayerC4 = i;
  129. }
  130. m_szClan.Set(i, AllocPooledString( pPlayer->GetClanTag() ) );
  131. m_iMVPs.Set(i, pPlayer->GetNumMVPs());
  132. m_bHasDefuser.Set(i, pPlayer->HasDefuser());
  133. }
  134. else
  135. {
  136. m_szClan.Set( i, MAKE_STRING( "" ) );
  137. m_iMVPs.Set( i, 0 );
  138. }
  139. }
  140. CBaseEntity *c4 = NULL;
  141. if ( m_iPlayerC4 == 0 )
  142. {
  143. // no player has C4, update C4 position
  144. if ( g_C4s.Count() > 0 )
  145. {
  146. c4 = g_C4s[0];
  147. m_vecC4 = c4->GetAbsOrigin();
  148. }
  149. else
  150. {
  151. m_vecC4.Init();
  152. }
  153. }
  154. int numHostages = g_Hostages.Count();
  155. for ( i = 0; i < MAX_HOSTAGES; i++ )
  156. {
  157. if ( i >= numHostages )
  158. {
  159. // engine->Con_NPrintf( i, "Dead" );
  160. m_bHostageAlive.Set( i, false );
  161. m_isHostageFollowingSomeone.Set( i, false );
  162. continue;
  163. }
  164. CHostage* pHostage = g_Hostages[i];
  165. m_bHostageAlive.Set( i, pHostage->IsRescuable() );
  166. if ( pHostage->IsValid() )
  167. {
  168. m_iHostageX.Set( i, (int) pHostage->GetAbsOrigin().x );
  169. m_iHostageY.Set( i, (int) pHostage->GetAbsOrigin().y );
  170. m_iHostageZ.Set( i, (int) pHostage->GetAbsOrigin().z );
  171. m_iHostageEntityIDs.Set( i, pHostage->entindex() );
  172. m_isHostageFollowingSomeone.Set( i, pHostage->IsFollowingSomeone() );
  173. // engine->Con_NPrintf( i, "ID:%d Pos:(%.0f,%.0f,%.0f)", pHostage->entindex(), pHostage->GetAbsOrigin().x, pHostage->GetAbsOrigin().y, pHostage->GetAbsOrigin().z );
  174. }
  175. else
  176. {
  177. // engine->Con_NPrintf( i, "Invalid" );
  178. }
  179. }
  180. if( !m_foundGoalPositions )
  181. {
  182. // We only need to update these once a map, but we need the client to know about them.
  183. CBaseEntity* ent = NULL;
  184. while ( ( ent = gEntList.FindEntityByClassname( ent, "func_bomb_target" ) ) != NULL )
  185. {
  186. const Vector &pos = ent->WorldSpaceCenter();
  187. CNavArea *area = TheNavMesh->GetNearestNavArea( pos, true, 10000.0f, false, false );
  188. const char *placeName = (area) ? TheNavMesh->PlaceToName( area->GetPlace() ) : NULL;
  189. if ( placeName == NULL )
  190. {
  191. // The bomb site has no area or place name, so just choose A then B
  192. if ( m_bombsiteCenterA.Get().IsZero() )
  193. {
  194. m_bombsiteCenterA = pos;
  195. }
  196. else
  197. {
  198. m_bombsiteCenterB = pos;
  199. }
  200. }
  201. else
  202. {
  203. // The bomb site has a place name, so choose accordingly
  204. if( FStrEq( placeName, "BombsiteA" ) )
  205. {
  206. m_bombsiteCenterA = pos;
  207. }
  208. else
  209. {
  210. m_bombsiteCenterB = pos;
  211. }
  212. }
  213. m_foundGoalPositions = true;
  214. }
  215. int hostageRescue = 0;
  216. while ( (( ent = gEntList.FindEntityByClassname( ent, "func_hostage_rescue" ) ) != NULL) && (hostageRescue < MAX_HOSTAGE_RESCUES) )
  217. {
  218. const Vector &pos = ent->WorldSpaceCenter();
  219. m_hostageRescueX.Set( hostageRescue, (int) pos.x );
  220. m_hostageRescueY.Set( hostageRescue, (int) pos.y );
  221. m_hostageRescueZ.Set( hostageRescue, (int) pos.z );
  222. hostageRescue++;
  223. m_foundGoalPositions = true;
  224. }
  225. }
  226. bool bombSpotted = false;
  227. if ( c4 )
  228. {
  229. Spotter spotter( c4, m_vecC4, TEAM_CT );
  230. ForEachPlayer( spotter );
  231. if ( spotter.Spotted() )
  232. {
  233. bombSpotted = true;
  234. }
  235. }
  236. for ( int i=0; i < MAX_PLAYERS+1; i++ )
  237. {
  238. CCSPlayer *target = ToCSPlayer( UTIL_PlayerByIndex( i ) );
  239. if ( !target || !target->IsAlive() )
  240. {
  241. m_bPlayerSpotted.Set( i, 0 );
  242. continue;
  243. }
  244. Spotter spotter( target, target->EyePosition(), (target->GetTeamNumber()==TEAM_CT) ? TEAM_TERRORIST : TEAM_CT );
  245. ForEachPlayer( spotter );
  246. if ( spotter.Spotted() )
  247. {
  248. if ( target->HasC4() )
  249. {
  250. bombSpotted = true;
  251. }
  252. m_bPlayerSpotted.Set( i, 1 );
  253. }
  254. else
  255. {
  256. m_bPlayerSpotted.Set( i, 0 );
  257. }
  258. }
  259. if ( bombSpotted )
  260. {
  261. m_bBombSpotted = true;
  262. }
  263. else
  264. {
  265. m_bBombSpotted = false;
  266. }
  267. BaseClass::UpdatePlayerData();
  268. }
  269. void CCSPlayerResource::Spawn( void )
  270. {
  271. m_vecC4.Init();
  272. m_iPlayerC4 = 0;
  273. m_iPlayerVIP = 0;
  274. m_bombsiteCenterA.Init();
  275. m_bombsiteCenterB.Init();
  276. m_foundGoalPositions = false;
  277. for ( int i=0; i < MAX_HOSTAGES; i++ )
  278. {
  279. m_bHostageAlive.Set( i, 0 );
  280. m_isHostageFollowingSomeone.Set( i, 0 );
  281. m_iHostageEntityIDs.Set(i, 0);
  282. }
  283. for ( int i=0; i < MAX_HOSTAGE_RESCUES; i++ )
  284. {
  285. m_hostageRescueX.Set( i, 0 );
  286. m_hostageRescueY.Set( i, 0 );
  287. m_hostageRescueZ.Set( i, 0 );
  288. }
  289. m_bBombSpotted = false;
  290. for ( int i=0; i < MAX_PLAYERS+1; i++ )
  291. {
  292. m_bPlayerSpotted.Set( i, 0 );
  293. m_szClan.Set( i, MAKE_STRING( "" ) );
  294. m_iMVPs.Set( i, 0 );
  295. m_bHasDefuser.Set(i, false);
  296. }
  297. BaseClass::Spawn();
  298. }