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.

586 lines
15 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include "cbase.h"
  8. #include "dod_control_point_master.h"
  9. BEGIN_DATADESC( CControlPointMaster )
  10. DEFINE_KEYFIELD( m_bDisabled, FIELD_BOOLEAN, "StartDisabled" ),
  11. DEFINE_KEYFIELD( m_iTimerLength, FIELD_INTEGER, "cpm_timer_length" ),
  12. DEFINE_INPUTFUNC( FIELD_VOID, "Enable", InputEnable ),
  13. DEFINE_INPUTFUNC( FIELD_VOID, "Disable", InputDisable ),
  14. DEFINE_INPUTFUNC( FIELD_VOID, "RoundInit", InputRoundInit ),
  15. DEFINE_FUNCTION( CPMThink ),
  16. DEFINE_OUTPUT( m_AlliesWinOutput, "OnAlliesWin" ),
  17. DEFINE_OUTPUT( m_AxisWinOutput, "OnAxisWin" ),
  18. DEFINE_INPUTFUNC( FIELD_INTEGER, "AddTimerSeconds", InputAddTimerSeconds ),
  19. END_DATADESC()
  20. LINK_ENTITY_TO_CLASS( dod_control_point_master, CControlPointMaster );
  21. CControlPointMaster::CControlPointMaster()
  22. {
  23. m_bUseTimer = false;
  24. m_iTimerTeam = TEAM_UNASSIGNED;
  25. SetDefLessFunc( m_ControlPoints );
  26. }
  27. void CControlPointMaster::Spawn( void )
  28. {
  29. SetTouch( NULL );
  30. m_bFoundPoints = false;
  31. BaseClass::Spawn();
  32. }
  33. ConVar mp_tickpointinterval( "mp_tickpointinterval", "30", FCVAR_GAMEDLL, "Delay between point gives.", true, 1, false, 0 );
  34. void CControlPointMaster::RoundRespawn( void )
  35. {
  36. m_fGivePointsTime = gpGlobals->curtime + mp_tickpointinterval.GetInt();
  37. }
  38. // KeyValue
  39. // ========
  40. // this function interfaces with the keyvalues set by the mapper
  41. //
  42. // Values
  43. // point_give_delay_time - how often to give time based points ( seconds )
  44. // allies_capture_target - target to fire on allies complete capture
  45. // axis_capture_target - target to fire on axis complete capture
  46. bool CControlPointMaster::KeyValue( const char *szKeyName, const char *szValue )
  47. {
  48. if (FStrEq(szKeyName, "cpm_use_timer"))
  49. {
  50. m_bUseTimer = ( atoi(szValue) > 0 );
  51. }
  52. else if (FStrEq(szKeyName, "cpm_timer_team"))
  53. {
  54. m_iTimerTeam = atoi(szValue);
  55. }
  56. else
  57. {
  58. return CBaseEntity::KeyValue( szKeyName, szValue );
  59. }
  60. return true;
  61. }
  62. void CControlPointMaster::Reset( void )
  63. {
  64. }
  65. bool CControlPointMaster::FindControlPoints( void )
  66. {
  67. //go through all the points
  68. CBaseEntity *pEnt = gEntList.FindEntityByClassname( NULL, "dod_control_point" );
  69. int numFound = 0;
  70. while( pEnt )
  71. {
  72. CControlPoint *pPoint = (CControlPoint *)pEnt;
  73. if( pPoint->IsActive() )
  74. {
  75. int index = pPoint->GetPointIndex();
  76. Assert( index >= 0 );
  77. if( m_ControlPoints.Find( index ) == m_ControlPoints.InvalidIndex())
  78. {
  79. DevMsg( 2, "Adding control point %s with index %d\n", pPoint->GetName(), index );
  80. m_ControlPoints.Insert( index, pPoint );
  81. numFound++;
  82. }
  83. else
  84. {
  85. Warning( "!!!!\nMultiple control points with the same index, duplicates ignored\n!!!!\n" );
  86. UTIL_Remove( pPoint );
  87. }
  88. }
  89. pEnt = gEntList.FindEntityByClassname( pEnt, "dod_control_point" );
  90. }
  91. if( numFound > MAX_CONTROL_POINTS )
  92. {
  93. Warning( "Too many control points! Max is %d\n", MAX_CONTROL_POINTS );
  94. }
  95. //Remap the indeces of the control points so they are 0-based
  96. //======================
  97. unsigned int j;
  98. bool bHandled[MAX_CONTROL_POINTS];
  99. memset( bHandled, 0, sizeof(bHandled) );
  100. unsigned int numPoints = m_ControlPoints.Count();
  101. unsigned int newIndex = 0;
  102. while( newIndex < numPoints )
  103. {
  104. //Find the lowest numbered, unhandled point
  105. int lowestIndex = -1;
  106. int lowestValue = 999;
  107. //find the lowest unhandled index
  108. for( j=0; j<numPoints; j++ )
  109. {
  110. if( !bHandled[j] && m_ControlPoints[j]->GetPointIndex() < lowestValue )
  111. {
  112. lowestIndex = j;
  113. lowestValue = m_ControlPoints[j]->GetPointIndex();
  114. }
  115. }
  116. //Don't examine this point again
  117. Assert( lowestIndex >= 0 );
  118. bHandled[lowestIndex] = true;
  119. //Give it its new index
  120. m_ControlPoints[lowestIndex]->SetPointIndex( newIndex );
  121. newIndex++;
  122. }
  123. if( m_ControlPoints.Count() == 0 )
  124. {
  125. Warning( "Error! No control points found in map!\n");
  126. return false;
  127. }
  128. g_pObjectiveResource->SetNumControlPoints( m_ControlPoints.Count() );
  129. unsigned int i;
  130. for( i=0;i<m_ControlPoints.Count();i++ )
  131. {
  132. CControlPoint *pPoint = m_ControlPoints[i];
  133. int iPointIndex = m_ControlPoints[i]->GetPointIndex();
  134. g_pObjectiveResource->SetOwningTeam( iPointIndex, pPoint->GetOwner() );
  135. g_pObjectiveResource->SetCPVisible( iPointIndex, pPoint->PointIsVisible() );
  136. g_pObjectiveResource->SetCPPosition( iPointIndex, pPoint->GetAbsOrigin() );
  137. g_pObjectiveResource->SetBombsRequired( iPointIndex, pPoint->GetBombsRequired() );
  138. g_pObjectiveResource->SetBombsRemaining( iPointIndex, pPoint->GetBombsRemaining() );
  139. g_pObjectiveResource->SetCPIcons( iPointIndex,
  140. pPoint->GetHudIconIndexForTeam(TEAM_ALLIES),
  141. pPoint->GetHudIconIndexForTeam(TEAM_AXIS),
  142. pPoint->GetHudIconIndexForTeam(TEAM_UNASSIGNED),
  143. pPoint->GetTimerCapHudIcon(),
  144. pPoint->GetBombedHudIcon() );
  145. }
  146. return true;
  147. }
  148. // Think
  149. // =====
  150. // Think is called every 0.1 seconds and checks the status of all the control points
  151. // if one team owns them all, it gives points and resets
  152. // Think also gives the time based points at the specified time intervals
  153. //
  154. // I moved the search for spawn points to the initial think - sometimes the points spawned
  155. // after the master and it wasnt finding them.
  156. void CControlPointMaster::CPMThink( void )
  157. {
  158. // search for all "dod_control_point" entities in the map
  159. // and put them in the array
  160. // only done the first Think
  161. //try to establish if any dod_area_capture ents are linked to our flags
  162. //via dod_point_relay
  163. //if there exists a point relay that has this as the target,
  164. //AND there exists a capture area that has that relay as a target
  165. //then we have our area!
  166. //every think
  167. //go through all the control points and make sure theyre the same as the last think
  168. //check masters
  169. //if they are, do nothing
  170. //else
  171. //
  172. //Note! Only one cpm should ever be active at the same time
  173. //funny things may happen if there are two of em!
  174. //if we are recently mastered on or off, touch the cps
  175. //---------------------------------------------------------------------------
  176. //below here we shouldn't execute unless we are an active control point master
  177. //if the round has been decided, don't do any more thinking
  178. //if this cpm is not active, dont' do any thinking
  179. int iRoundState = DODGameRules()->State_Get();
  180. // No points or triggering new wins if we are not active
  181. if( m_bDisabled || iRoundState != STATE_RND_RUNNING )
  182. {
  183. SetContextThink( &CControlPointMaster::CPMThink, gpGlobals->curtime + 0.2, FLAGS_CONTEXT );
  184. return;
  185. }
  186. // is it time to give time-based points yet?
  187. if( gpGlobals->curtime > m_fGivePointsTime )
  188. {
  189. int AlliesPoints = 0;
  190. int AxisPoints = 0;
  191. //give points based on who owns what
  192. unsigned int i;
  193. for( i=0;i<m_ControlPoints.Count();i++ )
  194. {
  195. switch( m_ControlPoints[i]->GetOwner() )
  196. {
  197. case TEAM_ALLIES:
  198. AlliesPoints += m_ControlPoints[i]->PointValue();
  199. break;
  200. case TEAM_AXIS:
  201. AxisPoints += m_ControlPoints[i]->PointValue();
  202. break;
  203. default:
  204. break;
  205. }
  206. }
  207. //================
  208. //give team points
  209. //================
  210. // See if there are players active on these teams
  211. bool bFoundAllies = ( GetGlobalTeam(TEAM_ALLIES)->GetNumPlayers() > 0 );
  212. bool bFoundAxis = ( GetGlobalTeam(TEAM_AXIS)->GetNumPlayers() > 0 );
  213. bool bReportScore = true;
  214. // don't give team points to a team with no-one on it!
  215. if( AlliesPoints > 0 && bFoundAllies && DODGameRules()->State_Get() == STATE_RND_RUNNING )
  216. {
  217. if( bReportScore )
  218. {
  219. if (AlliesPoints == 1)
  220. UTIL_ClientPrintAll( HUD_PRINTTALK, "#game_score_allie_point" );
  221. else
  222. {
  223. char buf[8];
  224. Q_snprintf( buf, sizeof(buf), "%d", AlliesPoints );
  225. UTIL_ClientPrintAll( HUD_PRINTTALK, "#game_score_allie_points", buf );
  226. }
  227. }
  228. GetGlobalTeam(TEAM_ALLIES)->AddScore( AlliesPoints );
  229. IGameEvent *event = gameeventmanager->CreateEvent( "dod_tick_points" );
  230. if ( event )
  231. {
  232. event->SetInt( "team", TEAM_ALLIES );
  233. event->SetInt( "score", AlliesPoints );
  234. event->SetInt( "totalscore", GetGlobalTeam(TEAM_ALLIES)->GetScore() );
  235. gameeventmanager->FireEvent( event );
  236. }
  237. }
  238. if( AxisPoints > 0 && bFoundAxis && DODGameRules()->State_Get() == STATE_RND_RUNNING )
  239. {
  240. if( bReportScore )
  241. {
  242. if (AxisPoints == 1)
  243. UTIL_ClientPrintAll( HUD_PRINTTALK, "#game_score_axis_point" );
  244. else
  245. {
  246. char buf[8];
  247. Q_snprintf( buf, sizeof(buf), "%d", AxisPoints );
  248. UTIL_ClientPrintAll( HUD_PRINTTALK, "#game_score_axis_points", buf );
  249. }
  250. }
  251. GetGlobalTeam(TEAM_AXIS)->AddScore( AxisPoints );
  252. IGameEvent *event = gameeventmanager->CreateEvent( "dod_tick_points" );
  253. if ( event )
  254. {
  255. event->SetInt( "team", TEAM_AXIS );
  256. event->SetInt( "score", AxisPoints );
  257. event->SetInt( "totalscore", GetGlobalTeam(TEAM_AXIS)->GetScore() );
  258. gameeventmanager->FireEvent( event );
  259. }
  260. }
  261. // the next time we'll give points
  262. m_fGivePointsTime = gpGlobals->curtime + mp_tickpointinterval.GetInt();
  263. }
  264. // If we call this from dod_control_point, this function should never
  265. // trigger a win. but we'll leave it here just incase.
  266. CheckWinConditions();
  267. // the next time we 'think'
  268. SetContextThink( &CControlPointMaster::CPMThink, gpGlobals->curtime + 0.2, FLAGS_CONTEXT );
  269. }
  270. void CControlPointMaster::CheckWinConditions( void )
  271. {
  272. // ============
  273. // Check that the points aren't all held by one team
  274. // if they are this will reset the round
  275. // and will reset all the points
  276. // ============
  277. switch( TeamOwnsAllPoints() )
  278. {
  279. case TEAM_ALLIES: //allies own all
  280. {
  281. TeamWins( TEAM_ALLIES );
  282. }
  283. break;
  284. case TEAM_AXIS: //axis owns all
  285. {
  286. TeamWins( TEAM_AXIS );
  287. }
  288. break;
  289. default:
  290. break;
  291. }
  292. }
  293. void CControlPointMaster::InputRoundInit( inputdata_t &input )
  294. {
  295. //clear out old control points
  296. m_ControlPoints.RemoveAll();
  297. //find the control points
  298. //if successful, do CPMThink
  299. if( FindControlPoints() )
  300. {
  301. SetContextThink( &CControlPointMaster::CPMThink, gpGlobals->curtime + 0.1, FLAGS_CONTEXT );
  302. }
  303. //init the ClientAreas
  304. int index = 0;
  305. CBaseEntity *pEnt = gEntList.FindEntityByClassname( NULL, "dod_capture_area" );
  306. while( pEnt )
  307. {
  308. CAreaCapture *pArea = (CAreaCapture *)pEnt;
  309. Assert( pArea );
  310. pArea->area_SetIndex( index );
  311. index++;
  312. pEnt = gEntList.FindEntityByClassname( pEnt, "dod_capture_area" );
  313. }
  314. g_pObjectiveResource->ResetControlPoints();
  315. }
  316. void CControlPointMaster::FireTeamWinOutput( int iWinningTeam )
  317. {
  318. switch( iWinningTeam )
  319. {
  320. case TEAM_ALLIES:
  321. m_AlliesWinOutput.FireOutput(this,this);
  322. break;
  323. case TEAM_AXIS:
  324. m_AxisWinOutput.FireOutput(this,this);
  325. break;
  326. default:
  327. Assert(0);
  328. break;
  329. }
  330. }
  331. void CControlPointMaster::TeamWins( int iWinningTeam )
  332. {
  333. DODGameRules()->SetWinningTeam( iWinningTeam );
  334. FireTeamWinOutput( iWinningTeam );
  335. }
  336. void CControlPointMaster::BecomeActive( void )
  337. {
  338. Assert( m_bDisabled );
  339. m_bDisabled = false;
  340. }
  341. void CControlPointMaster::BecomeInactive( void )
  342. {
  343. Assert( !m_bDisabled );
  344. m_bDisabled = true;
  345. }
  346. int CControlPointMaster::GetPointOwner( int point )
  347. {
  348. Assert( point >= 0 );
  349. Assert( point < MAX_CONTROL_POINTS );
  350. CControlPoint *pPoint = m_ControlPoints[point];
  351. if( pPoint )
  352. {
  353. return pPoint->GetOwner();
  354. }
  355. else
  356. return TEAM_UNASSIGNED;
  357. }
  358. // TeamOwnsAllPoints
  359. // =================
  360. // This function returns the team that owns all
  361. // the cap points. if its not the case that one
  362. // team owns them all, it returns 0
  363. // New - cps are now broken into groups.
  364. // A team can win by owning all flags within a single group.
  365. // Can be passed an overriding team. If this is not null, the passed team
  366. // number will be used for that cp. Used to predict if that CP changing would
  367. // win the game.
  368. int CControlPointMaster::TeamOwnsAllPoints( CControlPoint *pOverridePoint /* = NULL */, int iOverrideNewTeam /* = TEAM_UNASSIGNED */ )
  369. {
  370. unsigned int i;
  371. int iWinningTeam[MAX_CONTROL_POINT_GROUPS];
  372. for( i=0;i<MAX_CONTROL_POINT_GROUPS;i++ )
  373. {
  374. iWinningTeam[i] = TEAM_INVALID;
  375. }
  376. // if TEAM_INVALID, haven't found a flag for this group yet
  377. // if TEAM_UNASSIGNED, the group is still being contested
  378. // for each control point
  379. for( i=0;i<m_ControlPoints.Count();i++ )
  380. {
  381. int group = m_ControlPoints[i]->GetCPGroup();
  382. int owner = m_ControlPoints[i]->GetOwner();
  383. if ( pOverridePoint == m_ControlPoints[i] )
  384. {
  385. owner = iOverrideNewTeam;
  386. }
  387. // the first one we find in this group, set the win to true
  388. if ( iWinningTeam[group] == TEAM_INVALID )
  389. {
  390. iWinningTeam[group] = owner;
  391. }
  392. // unassigned means this group is already contested, move on
  393. else if ( iWinningTeam[group] == TEAM_UNASSIGNED )
  394. {
  395. continue;
  396. }
  397. // if we find another one in the group that isn't the same owner, set the win to false
  398. else if ( owner != iWinningTeam[group] )
  399. {
  400. iWinningTeam[group] = TEAM_UNASSIGNED;
  401. }
  402. }
  403. // report the first win we find as the winner
  404. for ( i=0;i<MAX_CONTROL_POINT_GROUPS;i++ )
  405. {
  406. if ( iWinningTeam[i] == TEAM_ALLIES || iWinningTeam[i] == TEAM_AXIS )
  407. return iWinningTeam[i];
  408. }
  409. // no wins yet
  410. return TEAM_UNASSIGNED;
  411. }
  412. // an advantage flag is a flag that we've taken that didn't initially
  413. // belong to our team
  414. int CControlPointMaster::CountAdvantageFlags( int team )
  415. {
  416. int numFlags = 0;
  417. unsigned int i;
  418. for( i = 0;i<m_ControlPoints.Count();i++ )
  419. {
  420. CControlPoint *pPoint = m_ControlPoints[i];
  421. if ( pPoint->GetOwner() != pPoint->GetDefaultOwner() )
  422. {
  423. if ( pPoint->GetOwner() == team )
  424. {
  425. // we own a flag we didn't initially
  426. numFlags++;
  427. }
  428. else //
  429. {
  430. // the enemy owns one of our flags
  431. numFlags--;
  432. }
  433. }
  434. }
  435. return numFlags;
  436. }
  437. void CControlPointMaster::InputAddTimerSeconds( inputdata_t &inputdata )
  438. {
  439. DODGameRules()->AddTimerSeconds( inputdata.value.Int() );
  440. }
  441. void CControlPointMaster::GetTimerData( int &iTimerSeconds, int &iTimerWinTeam )
  442. {
  443. iTimerSeconds = m_iTimerLength;
  444. iTimerWinTeam = m_iTimerTeam;
  445. }
  446. bool CControlPointMaster::WouldNewCPOwnerWinGame( CControlPoint *pPoint, int iNewOwner )
  447. {
  448. return ( TeamOwnsAllPoints( pPoint, iNewOwner ) == iNewOwner );
  449. }
  450. int CControlPointMaster::GetNumPoints( void )
  451. {
  452. return m_ControlPoints.Count();
  453. }
  454. CControlPoint *CControlPointMaster::GetCPByIndex( int index )
  455. {
  456. CControlPoint *pPoint = NULL;
  457. if ( index >= 0 && index < (int)m_ControlPoints.Count() )
  458. {
  459. pPoint = m_ControlPoints[index];
  460. }
  461. return pPoint;
  462. }
  463. // custom scoring entity
  464. BEGIN_DATADESC( CDODCustomScoring )
  465. DEFINE_INPUTFUNC( FIELD_INTEGER, "GiveTickPoints", InputGivePoints ),
  466. DEFINE_KEYFIELD( m_iPointTeam, FIELD_INTEGER, "TeamNum" ),
  467. DEFINE_KEYFIELD( m_iTickLength, FIELD_INTEGER, "point_give_delay" ),
  468. DEFINE_KEYFIELD( m_iPointsToGive, FIELD_INTEGER, "point_give_amount" ),
  469. DEFINE_KEYFIELD( m_iNumPointGives, FIELD_INTEGER, "point_give_max_times" ),
  470. DEFINE_THINKFUNC( PointsThink ),
  471. END_DATADESC()
  472. LINK_ENTITY_TO_CLASS( dod_scoring, CDODCustomScoring );