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.

464 lines
16 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: An entity that networks the state of the game's objectives.
  4. //
  5. //=============================================================================
  6. #include "cbase.h"
  7. #include "c_team_objectiveresource.h"
  8. #include "igameevents.h"
  9. #include "teamplayroundbased_gamerules.h"
  10. #include "c_baseplayer.h"
  11. // memdbgon must be the last include file in a .cpp file!!!
  12. #include "tier0/memdbgon.h"
  13. #define RESOURCE_THINK_TIME 0.1
  14. extern ConVar mp_capstyle;
  15. extern ConVar mp_capdeteriorate_time;
  16. //-----------------------------------------------------------------------------
  17. // Purpose: Owner recv proxy
  18. //-----------------------------------------------------------------------------
  19. void RecvProxy_Owner( const CRecvProxyData *pData, void *pStruct, void *pOut )
  20. {
  21. // hacks? Not sure how else to get the index of the integer that is
  22. // being transmitted.
  23. int index = pData->m_pRecvProp->GetOffset() / sizeof(int);
  24. ObjectiveResource()->SetOwningTeam( index, pData->m_Value.m_Int );
  25. }
  26. //-----------------------------------------------------------------------------
  27. // Purpose: capper recv proxy
  28. //-----------------------------------------------------------------------------
  29. void RecvProxy_CappingTeam( const CRecvProxyData *pData, void *pStruct, void *pOut )
  30. {
  31. int index = pData->m_pRecvProp->GetOffset() / sizeof(int);
  32. ObjectiveResource()->SetCappingTeam( index, pData->m_Value.m_Int );
  33. }
  34. //-----------------------------------------------------------------------------
  35. // Purpose:
  36. //-----------------------------------------------------------------------------
  37. void RecvProxy_CapLayout( const CRecvProxyData *pData, void *pStruct, void *pOut )
  38. {
  39. ObjectiveResource()->SetCapLayout( pData->m_Value.m_pString );
  40. }
  41. IMPLEMENT_CLIENTCLASS_DT_NOBASE(C_BaseTeamObjectiveResource, DT_BaseTeamObjectiveResource, CBaseTeamObjectiveResource)
  42. RecvPropInt( RECVINFO(m_iTimerToShowInHUD) ),
  43. RecvPropInt( RECVINFO(m_iStopWatchTimer) ),
  44. RecvPropInt( RECVINFO(m_iNumControlPoints) ),
  45. RecvPropBool( RECVINFO(m_bPlayingMiniRounds) ),
  46. RecvPropBool( RECVINFO(m_bControlPointsReset) ),
  47. RecvPropInt( RECVINFO(m_iUpdateCapHudParity) ),
  48. RecvPropArray( RecvPropVector(RECVINFO(m_vCPPositions[0])), m_vCPPositions),
  49. RecvPropArray3( RECVINFO_ARRAY(m_bCPIsVisible), RecvPropInt( RECVINFO(m_bCPIsVisible[0]) ) ),
  50. RecvPropArray3( RECVINFO_ARRAY(m_flLazyCapPerc), RecvPropFloat( RECVINFO(m_flLazyCapPerc[0]) ) ),
  51. RecvPropArray3( RECVINFO_ARRAY(m_iTeamIcons), RecvPropInt( RECVINFO(m_iTeamIcons[0]) ) ),
  52. RecvPropArray3( RECVINFO_ARRAY(m_iTeamOverlays), RecvPropInt( RECVINFO(m_iTeamOverlays[0]) ) ),
  53. RecvPropArray3( RECVINFO_ARRAY(m_iTeamReqCappers), RecvPropInt( RECVINFO(m_iTeamReqCappers[0]) ) ),
  54. RecvPropArray3( RECVINFO_ARRAY(m_flTeamCapTime), RecvPropTime( RECVINFO(m_flTeamCapTime[0]) ) ),
  55. RecvPropArray3( RECVINFO_ARRAY(m_iPreviousPoints), RecvPropInt( RECVINFO(m_iPreviousPoints[0]) ) ),
  56. RecvPropArray3( RECVINFO_ARRAY(m_bTeamCanCap), RecvPropBool( RECVINFO(m_bTeamCanCap[0]) ) ),
  57. RecvPropArray3( RECVINFO_ARRAY(m_iTeamBaseIcons), RecvPropInt( RECVINFO(m_iTeamBaseIcons[0]) ) ),
  58. RecvPropArray3( RECVINFO_ARRAY(m_iBaseControlPoints), RecvPropInt( RECVINFO(m_iBaseControlPoints[0]) ) ),
  59. RecvPropArray3( RECVINFO_ARRAY(m_bInMiniRound), RecvPropBool( RECVINFO(m_bInMiniRound[0]) ) ),
  60. RecvPropArray3( RECVINFO_ARRAY(m_iWarnOnCap), RecvPropInt( RECVINFO(m_iWarnOnCap[0]) ) ),
  61. RecvPropArray( RecvPropString( RECVINFO( m_iszWarnSound[0]) ), m_iszWarnSound ),
  62. RecvPropArray3( RECVINFO_ARRAY(m_flPathDistance), RecvPropFloat( RECVINFO(m_flPathDistance[0]) ) ),
  63. RecvPropArray3( RECVINFO_ARRAY(m_iCPGroup), RecvPropInt( RECVINFO(m_iCPGroup[0]) ) ),
  64. RecvPropArray3( RECVINFO_ARRAY(m_bCPLocked), RecvPropBool( RECVINFO(m_bCPLocked[0]) ) ),
  65. RecvPropArray3( RECVINFO_ARRAY(m_nNumNodeHillData), RecvPropInt( RECVINFO(m_nNumNodeHillData[0]) ) ),
  66. RecvPropArray3( RECVINFO_ARRAY(m_flNodeHillData), RecvPropFloat( RECVINFO(m_flNodeHillData[0]) ) ),
  67. RecvPropArray3( RECVINFO_ARRAY(m_bTrackAlarm), RecvPropBool( RECVINFO(m_bTrackAlarm[0]) ) ),
  68. RecvPropArray3( RECVINFO_ARRAY(m_flUnlockTimes), RecvPropFloat( RECVINFO(m_flUnlockTimes[0]) ) ),
  69. RecvPropArray3( RECVINFO_ARRAY(m_bHillIsDownhill), RecvPropBool( RECVINFO(m_bHillIsDownhill[0]) ) ),
  70. RecvPropArray3( RECVINFO_ARRAY(m_flCPTimerTimes), RecvPropFloat( RECVINFO(m_flCPTimerTimes[0]) ) ),
  71. // state variables
  72. RecvPropArray3( RECVINFO_ARRAY(m_iNumTeamMembers), RecvPropInt( RECVINFO(m_iNumTeamMembers[0]) ) ),
  73. RecvPropArray3( RECVINFO_ARRAY(m_iCappingTeam), RecvPropInt( RECVINFO(m_iCappingTeam[0]), 0, RecvProxy_CappingTeam ) ),
  74. RecvPropArray3( RECVINFO_ARRAY(m_iTeamInZone), RecvPropInt( RECVINFO(m_iTeamInZone[0]) ) ),
  75. RecvPropArray3( RECVINFO_ARRAY(m_bBlocked), RecvPropInt( RECVINFO(m_bBlocked[0]) ) ),
  76. RecvPropArray3( RECVINFO_ARRAY(m_iOwner), RecvPropInt( RECVINFO(m_iOwner[0]), 0, RecvProxy_Owner ) ),
  77. RecvPropArray3( RECVINFO_ARRAY(m_bCPCapRateScalesWithPlayers), RecvPropBool( RECVINFO(m_bCPCapRateScalesWithPlayers[0]) ) ),
  78. RecvPropString( RECVINFO(m_pszCapLayoutInHUD), 0, RecvProxy_CapLayout ),
  79. RecvPropFloat( RECVINFO(m_flCustomPositionX) ),
  80. RecvPropFloat( RECVINFO(m_flCustomPositionY) ),
  81. END_RECV_TABLE()
  82. C_BaseTeamObjectiveResource *g_pObjectiveResource = NULL;
  83. //-----------------------------------------------------------------------------
  84. // Purpose:
  85. //-----------------------------------------------------------------------------
  86. C_BaseTeamObjectiveResource::C_BaseTeamObjectiveResource()
  87. {
  88. m_iNumControlPoints = 0;
  89. m_iPrevNumControlPoints = 0;
  90. m_pszCapLayoutInHUD[0] = 0;
  91. m_iUpdateCapHudParity = 0;
  92. m_bControlPointsReset = false;
  93. int i;
  94. for ( i=0; i < MAX_CONTROL_POINTS; i++ )
  95. {
  96. m_flCapTimeLeft[i] = 0;
  97. m_flCapLastThinkTime[i] = 0;
  98. m_flLastCapWarningTime[i] = 0;
  99. m_bWarnedOnFinalCap[i] = false; // have we warned
  100. m_iWarnOnCap[i] = CP_WARN_NORMAL; // should we warn
  101. m_iCPGroup[i] = -1;
  102. m_iszWarnSound[i][0] = 0; // what sound should be played
  103. m_flLazyCapPerc[i] = 0.0;
  104. m_flUnlockTimes[i] = 0.0;
  105. m_flCPTimerTimes[i] = -1.0;
  106. for ( int team = 0; team < MAX_CONTROL_POINT_TEAMS; team++ )
  107. {
  108. int iTeamIndex = TEAM_ARRAY( i, team );
  109. m_iTeamIcons[ iTeamIndex ] = 0;
  110. m_iTeamOverlays[ iTeamIndex ] = 0;
  111. m_iTeamReqCappers[ iTeamIndex ] = 0;
  112. m_flTeamCapTime[ iTeamIndex ] = 0.0f;
  113. m_iNumTeamMembers[ iTeamIndex ] = 0;
  114. for ( int ipoint = 0; ipoint < MAX_PREVIOUS_POINTS; ipoint++ )
  115. {
  116. int iIntIndex = ipoint + (i * MAX_PREVIOUS_POINTS) + (team * MAX_CONTROL_POINTS * MAX_PREVIOUS_POINTS);
  117. m_iPreviousPoints[ iIntIndex ] = -1;
  118. }
  119. }
  120. }
  121. for ( int team = 0; team < MAX_CONTROL_POINT_TEAMS; team++ )
  122. {
  123. m_iTeamBaseIcons[team] = 0;
  124. }
  125. for ( i=0; i < TEAM_TRAIN_MAX_TEAMS; i++ )
  126. {
  127. m_nNumNodeHillData[i] = 0;
  128. m_bTrainOnHill[i] = false;
  129. }
  130. for ( i=0; i < TEAM_TRAIN_HILLS_ARRAY_SIZE; i++ )
  131. {
  132. m_flNodeHillData[i] = 0;
  133. }
  134. m_flCustomPositionX = -1.f;
  135. m_flCustomPositionY = -1.f;
  136. g_pObjectiveResource = this;
  137. }
  138. //-----------------------------------------------------------------------------
  139. // Purpose:
  140. //-----------------------------------------------------------------------------
  141. C_BaseTeamObjectiveResource::~C_BaseTeamObjectiveResource()
  142. {
  143. g_pObjectiveResource = NULL;
  144. }
  145. //-----------------------------------------------------------------------------
  146. // Purpose:
  147. //-----------------------------------------------------------------------------
  148. void C_BaseTeamObjectiveResource::OnPreDataChanged( DataUpdateType_t updateType )
  149. {
  150. BaseClass::OnPreDataChanged( updateType );
  151. m_iPrevNumControlPoints = m_iNumControlPoints;
  152. m_iOldUpdateCapHudParity = m_iUpdateCapHudParity;
  153. m_bOldControlPointsReset = m_bControlPointsReset;
  154. m_flOldCustomPositionX = m_flCustomPositionX;
  155. m_flOldCustomPositionY = m_flCustomPositionY;
  156. memcpy( m_flOldLazyCapPerc, m_flLazyCapPerc, sizeof(float)*m_iNumControlPoints );
  157. memcpy( m_flOldUnlockTimes, m_flUnlockTimes, sizeof(float)*m_iNumControlPoints );
  158. memcpy( m_flOldCPTimerTimes, m_flCPTimerTimes, sizeof(float)*m_iNumControlPoints );
  159. }
  160. //-----------------------------------------------------------------------------
  161. // Purpose:
  162. //-----------------------------------------------------------------------------
  163. void C_BaseTeamObjectiveResource::OnDataChanged( DataUpdateType_t updateType )
  164. {
  165. BaseClass::OnDataChanged( updateType );
  166. if ( m_bOldControlPointsReset != m_bControlPointsReset || m_iNumControlPoints != m_iPrevNumControlPoints )
  167. {
  168. // Tell everyone we know how many control points we have
  169. IGameEvent *event = gameeventmanager->CreateEvent( "controlpoint_initialized" );
  170. if ( event )
  171. {
  172. gameeventmanager->FireEventClientSide( event );
  173. }
  174. }
  175. if ( m_iUpdateCapHudParity != m_iOldUpdateCapHudParity )
  176. {
  177. UpdateControlPoint( "controlpoint_updateimages" );
  178. }
  179. for ( int i = 0; i < m_iNumControlPoints; i++ )
  180. {
  181. if ( m_flOldLazyCapPerc[i] != m_flLazyCapPerc[i] )
  182. {
  183. m_flCapTimeLeft[i] = m_flLazyCapPerc[i] * m_flTeamCapTime[ TEAM_ARRAY(i,m_iCappingTeam[i]) ];
  184. }
  185. if ( m_flOldUnlockTimes[i] != m_flUnlockTimes[i] )
  186. {
  187. IGameEvent *event = gameeventmanager->CreateEvent( "controlpoint_unlock_updated" );
  188. if ( event )
  189. {
  190. event->SetInt( "index", i );
  191. event->SetFloat( "time", m_flUnlockTimes[i] );
  192. gameeventmanager->FireEventClientSide( event );
  193. }
  194. }
  195. if ( m_flOldCPTimerTimes[i] != m_flCPTimerTimes[i] )
  196. {
  197. IGameEvent *event = gameeventmanager->CreateEvent( "controlpoint_timer_updated" );
  198. if ( event )
  199. {
  200. event->SetInt( "index", i );
  201. event->SetFloat( "time", m_flCPTimerTimes[i] );
  202. gameeventmanager->FireEventClientSide( event );
  203. }
  204. }
  205. }
  206. if ( m_flOldCustomPositionX != m_flCustomPositionX || m_flOldCustomPositionY != m_flCustomPositionY )
  207. {
  208. UpdateControlPoint( "controlpoint_updatelayout" );
  209. }
  210. }
  211. //-----------------------------------------------------------------------------
  212. // Purpose:
  213. //-----------------------------------------------------------------------------
  214. void C_BaseTeamObjectiveResource::UpdateControlPoint( const char *pszEvent, int index_ )
  215. {
  216. IGameEvent *event = gameeventmanager->CreateEvent( pszEvent );
  217. if ( event )
  218. {
  219. event->SetInt( "index", index_ );
  220. gameeventmanager->FireEventClientSide( event );
  221. }
  222. }
  223. //-----------------------------------------------------------------------------
  224. // Purpose:
  225. //-----------------------------------------------------------------------------
  226. float C_BaseTeamObjectiveResource::GetCPCapPercentage( int index_ )
  227. {
  228. Assert( 0 <= index_ && index_ <= m_iNumControlPoints );
  229. float flCapLength = m_flTeamCapTime[ TEAM_ARRAY(index_,m_iCappingTeam[index_]) ];
  230. if( flCapLength <= 0 )
  231. return 0.0f;
  232. float flElapsedTime = flCapLength - m_flCapTimeLeft[index_];
  233. if( flElapsedTime > flCapLength )
  234. return 1.0f;
  235. return ( flElapsedTime / flCapLength );
  236. }
  237. //-----------------------------------------------------------------------------
  238. // Purpose:
  239. //-----------------------------------------------------------------------------
  240. int C_BaseTeamObjectiveResource::GetNumControlPointsOwned( void )
  241. {
  242. C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
  243. if ( !pPlayer )
  244. return 0;
  245. int iTeam = pPlayer->GetTeamNumber();
  246. int nOwned = 0;
  247. for ( int i = 0; i < GetNumControlPoints(); ++i )
  248. {
  249. if ( GetOwningTeam( i ) == iTeam )
  250. {
  251. ++nOwned;
  252. }
  253. }
  254. return nOwned;
  255. }
  256. //-----------------------------------------------------------------------------
  257. // Purpose:
  258. // team -
  259. //-----------------------------------------------------------------------------
  260. void C_BaseTeamObjectiveResource::SetOwningTeam( int index_, int team )
  261. {
  262. if ( team == m_iCappingTeam[index_] )
  263. {
  264. // successful cap, reset things
  265. m_iCappingTeam[index_] = TEAM_UNASSIGNED;
  266. m_flCapTimeLeft[index_] = 0.0f;
  267. m_flCapLastThinkTime[index_] = 0;
  268. }
  269. m_iOwner[index_] = team;
  270. UpdateControlPoint( "controlpoint_updateowner", index_ );
  271. }
  272. //-----------------------------------------------------------------------------
  273. // Purpose:
  274. //-----------------------------------------------------------------------------
  275. void C_BaseTeamObjectiveResource::SetCappingTeam( int index_, int team )
  276. {
  277. if ( team != GetOwningTeam( index_ ) && ( team > LAST_SHARED_TEAM ) )
  278. {
  279. m_flCapTimeLeft[index_] = m_flTeamCapTime[ TEAM_ARRAY( index_,team) ];
  280. }
  281. else
  282. {
  283. m_flCapTimeLeft[index_] = 0.0;
  284. }
  285. m_iCappingTeam[index_] = team;
  286. m_bWarnedOnFinalCap[index_] = false;
  287. m_flCapLastThinkTime[index_] = gpGlobals->curtime;
  288. SetNextClientThink( gpGlobals->curtime + RESOURCE_THINK_TIME );
  289. UpdateControlPoint( "controlpoint_updatecapping", index_ );
  290. }
  291. //-----------------------------------------------------------------------------
  292. // Purpose:
  293. //-----------------------------------------------------------------------------
  294. void C_BaseTeamObjectiveResource::SetCapLayout( const char *pszLayout )
  295. {
  296. Q_strncpy( m_pszCapLayoutInHUD, pszLayout, MAX_CAPLAYOUT_LENGTH );
  297. UpdateControlPoint( "controlpoint_updatelayout" );
  298. }
  299. //-----------------------------------------------------------------------------
  300. // Purpose:
  301. //-----------------------------------------------------------------------------
  302. bool C_BaseTeamObjectiveResource::CapIsBlocked( int index_ )
  303. {
  304. Assert( 0 <= index_ && index_ <= m_iNumControlPoints );
  305. if ( m_flCapTimeLeft[index_] )
  306. {
  307. // Blocked caps have capping teams & cap times, but no players on the point
  308. if ( GetNumPlayersInArea( index_, m_iCappingTeam[index_] ) == 0 )
  309. return true;
  310. }
  311. return false;
  312. }
  313. //-----------------------------------------------------------------------------
  314. // Purpose:
  315. //-----------------------------------------------------------------------------
  316. void C_BaseTeamObjectiveResource::ClientThink()
  317. {
  318. BaseClass::ClientThink();
  319. for ( int i = 0; i < MAX_CONTROL_POINTS; i++ )
  320. {
  321. if ( m_flCapTimeLeft[i] )
  322. {
  323. if ( !IsCPBlocked(i) )
  324. {
  325. bool bDeteriorateNormally = true;
  326. // Make sure there is only 1 team on the cap
  327. int iPlayersCapping = GetNumPlayersInArea( i, GetTeamInZone(i) );
  328. if ( iPlayersCapping > 0 )
  329. {
  330. float flReduction = gpGlobals->curtime - m_flCapLastThinkTime[i];
  331. if ( mp_capstyle.GetInt() == 1 && m_bCPCapRateScalesWithPlayers[i] )
  332. {
  333. // Diminishing returns for successive players.
  334. for ( int iPlayer = 1; iPlayer < iPlayersCapping; iPlayer++ )
  335. {
  336. flReduction += ((gpGlobals->curtime - m_flCapLastThinkTime[i]) / (float)(iPlayer+1));
  337. }
  338. }
  339. if ( GetTeamInZone(i) == m_iCappingTeam[i] )
  340. {
  341. bDeteriorateNormally = false;
  342. m_flCapTimeLeft[i] -= flReduction;
  343. if ( !m_bWarnedOnFinalCap[i] )
  344. {
  345. // If this the local player's team, warn him
  346. C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
  347. if ( pPlayer )
  348. {
  349. if ( m_iCappingTeam[i] != TEAM_UNASSIGNED &&
  350. pPlayer->GetTeamNumber() != m_iCappingTeam[i] &&
  351. GetCapWarningLevel( i ) == CP_WARN_FINALCAP )
  352. {
  353. // Prevent spam
  354. if ( gpGlobals->curtime > ( m_flLastCapWarningTime[i] + 5 ) )
  355. {
  356. pPlayer->EmitSound( GetWarnSound( i ) );
  357. m_bWarnedOnFinalCap[i] = true;
  358. m_flLastCapWarningTime[i] = gpGlobals->curtime;
  359. }
  360. }
  361. }
  362. }
  363. }
  364. else if ( GetOwningTeam(i) == TEAM_UNASSIGNED && GetTeamInZone(i) != TEAM_UNASSIGNED )
  365. {
  366. bDeteriorateNormally = false;
  367. m_flCapTimeLeft[i] += flReduction;
  368. }
  369. }
  370. if ( bDeteriorateNormally )
  371. {
  372. // Caps deteriorate over time
  373. // If we're not cappable at all right now, wipe all progress
  374. if ( TeamplayRoundBasedRules() && TeamplayRoundBasedRules()->TeamMayCapturePoint(m_iCappingTeam[i],i) )
  375. {
  376. float flCapLength = m_flTeamCapTime[ TEAM_ARRAY(i,m_iCappingTeam[i]) ];
  377. float flDecreaseScale = m_bCPCapRateScalesWithPlayers[i] ? mp_capdeteriorate_time.GetFloat() : flCapLength;
  378. float flDecrease = (flCapLength / flDecreaseScale) * (gpGlobals->curtime - m_flCapLastThinkTime[i]);
  379. if ( TeamplayRoundBasedRules() && TeamplayRoundBasedRules()->InOvertime() )
  380. {
  381. flDecrease *= 6;
  382. }
  383. m_flCapTimeLeft[i] += flDecrease;
  384. }
  385. else
  386. {
  387. m_flCapTimeLeft[i] = 0.0;
  388. }
  389. m_bWarnedOnFinalCap[i] = false;
  390. }
  391. }
  392. UpdateControlPoint( "controlpoint_updatelayout", i );
  393. m_flCapLastThinkTime[i] = gpGlobals->curtime;
  394. }
  395. }
  396. SetNextClientThink( gpGlobals->curtime + RESOURCE_THINK_TIME );
  397. }