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.

3131 lines
88 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================//
  6. #include "cbase.h"
  7. #include "tfc_mapitems.h"
  8. #include "tfc_shareddefs.h"
  9. #include "tfc_player.h"
  10. #include "tfc_gamerules.h"
  11. #include "tfc_timer.h"
  12. #include "tfc_team.h"
  13. bool ActivateDoResults(CTFGoal *Goal, CTFCPlayer *AP, CTFGoal *ActivatingGoal);
  14. bool ActivationSucceeded(CTFGoal *Goal, CTFCPlayer *AP, CTFGoal *ActivatingGoal);
  15. void DoResults(CTFGoal *Goal, CTFCPlayer *AP, BOOL bAddBonuses);
  16. // ---------------------------------------------------------------------------------------- //
  17. // Global helpers.
  18. // ---------------------------------------------------------------------------------------- //
  19. const char* GetTeamName( int iTeam )
  20. {
  21. if ( iTeam == 0 )
  22. {
  23. return "SPECTATOR";
  24. }
  25. else
  26. {
  27. CTeam *pTeam = GetGlobalTeam( iTeam );
  28. if ( pTeam )
  29. return pTeam->GetName();
  30. else
  31. return "UNKNOWN TEAM";
  32. }
  33. }
  34. //===========================================
  35. int GetTeamCheckTeam( const char *pTargetName )
  36. {
  37. CBaseEntity *pEntity = gEntList.FindEntityByName( NULL, pTargetName );
  38. if ( pEntity )
  39. {
  40. if ( !strcmp( pEntity->GetClassname(), "info_tf_teamcheck" ) )
  41. return pEntity->GetTeamNumber();
  42. }
  43. return 0;
  44. }
  45. //=========================================================================
  46. // Displays the state of a GoalItem
  47. void DisplayItemStatus(CTFGoal *Goal, CTFCPlayer *Player, CTFGoalItem *Item)
  48. {
  49. MDEBUG( Msg( "Displaying Item Status\nItem goal_no : %d\n", Item->goal_no) );
  50. // If we have a teamcheck entity, use it instead
  51. if ( Item->owned_by_teamcheck != NULL_STRING )
  52. Item->owned_by = GetTeamCheckTeam( STRING(Item->owned_by_teamcheck) );
  53. if (Item->goal_state == TFGS_ACTIVE)
  54. {
  55. MDEBUG( Msg( " Item is ACTIVE\n") );
  56. if ( (Goal->team_str_carried != NULL_STRING) || (Goal->non_team_str_carried != NULL_STRING) )
  57. {
  58. CBaseEntity *pOwner = Item->GetOwnerEntity();
  59. if (Player->GetTeamNumber() == Item->owned_by)
  60. {
  61. if (Player == Item->GetOwnerEntity())
  62. ClientPrint( Player, HUD_PRINTTALK, STRING(Goal->team_str_carried), "you" );
  63. else
  64. ClientPrint( Player, HUD_PRINTTALK, STRING(Goal->team_str_carried), STRING(pOwner->GetEntityName()) );
  65. }
  66. else
  67. {
  68. if (Player == Item->GetOwnerEntity())
  69. ClientPrint( Player, HUD_PRINTTALK, STRING(Goal->non_team_str_carried), "you" );
  70. else
  71. ClientPrint( Player, HUD_PRINTTALK, STRING(Goal->non_team_str_carried), STRING(pOwner->GetEntityName()) );
  72. }
  73. }
  74. }
  75. else if (Item->GetAbsOrigin() != Item->oldorigin)
  76. {
  77. MDEBUG( Msg( " Item has MOVED\n") );
  78. if ( (Goal->team_str_moved != NULL_STRING) || (Goal->non_team_str_moved != NULL_STRING) )
  79. {
  80. if (Player->GetTeamNumber() == Item->owned_by)
  81. ClientPrint( Player, HUD_PRINTTALK, STRING(Goal->team_str_moved) );
  82. else
  83. ClientPrint( Player, HUD_PRINTTALK, STRING(Goal->non_team_str_moved) );
  84. }
  85. }
  86. else
  87. {
  88. MDEBUG( Msg( " Item is AT HOME\n") );
  89. if ( Goal->team_str_home != NULL_STRING || Goal->non_team_str_home != NULL_STRING )
  90. {
  91. if (Player->GetTeamNumber() == Item->owned_by)
  92. ClientPrint( Player, HUD_PRINTTALK, STRING(Goal->team_str_home) );
  93. else
  94. ClientPrint( Player, HUD_PRINTTALK, STRING(Goal->non_team_str_home) );
  95. }
  96. }
  97. }
  98. //=========================================================================
  99. // Inactivates a Teamspawn point
  100. void InactivateSpawn(CTFSpawn *Spawn)
  101. {
  102. Spawn->goal_state = TFGS_REMOVED;
  103. }
  104. //=========================================================================
  105. // Activates a Teamspawn point
  106. void ActivateSpawn(CTFSpawn *Spawn)
  107. {
  108. Spawn->goal_state = TFGS_INACTIVE;
  109. }
  110. //=========================================================================
  111. // Increase the score of a team
  112. void TeamFortress_TeamIncreaseScore(int tno, int scoretoadd)
  113. {
  114. if ( tno == 0 )
  115. return;
  116. CTeam *pTeam = GetGlobalTeam( tno );
  117. if ( !pTeam )
  118. return;
  119. pTeam->AddScore( scoretoadd );
  120. }
  121. // Returns true if the AP's carrying at least 1 of the items in the group
  122. bool HasItemFromGroup( CBaseEntity *AP, int iGroupNo )
  123. {
  124. // Find all items in the group
  125. CBaseEntity *pEnt = gEntList.FindEntityByClassname( NULL, "item_tfgoal" );
  126. while ( pEnt )
  127. {
  128. CTFGoalItem *pGoal = dynamic_cast<CTFGoalItem*>( pEnt );
  129. if ( (pGoal->group_no == iGroupNo) && (pGoal->GetOwnerEntity() == AP) )
  130. return true;
  131. pEnt = gEntList.FindEntityByClassname( pEnt, "item_tfgoal" );
  132. }
  133. return false;
  134. }
  135. //=========================================================================
  136. // Returns true if all the goals in the specified group are in the specified state
  137. bool AllGoalsInState( int iGroupNo, int iState )
  138. {
  139. // Find all goals in the group
  140. CBaseEntity *pEnt = gEntList.FindEntityByClassname( NULL, "info_tfgoal" );
  141. while ( pEnt )
  142. {
  143. CTFGoal *pGoal = dynamic_cast< CTFGoal* >( pEnt );
  144. if ( pGoal )
  145. {
  146. if (pGoal->group_no == iGroupNo)
  147. {
  148. // All Goals in the group must be in the specified state
  149. if (pGoal->goal_state != iState)
  150. return false;
  151. }
  152. }
  153. pEnt = gEntList.FindEntityByClassname( pEnt, "info_tfgoal" );
  154. }
  155. return true;
  156. }
  157. // Return the item with a goal_no equal to ino
  158. CTFGoalItem* Finditem(int ino)
  159. {
  160. CBaseEntity *pEnt = gEntList.FindEntityByClassname( NULL, "item_tfgoal" );
  161. while ( pEnt )
  162. {
  163. CTFGoalItem *pGoal = dynamic_cast<CTFGoalItem*>( pEnt );
  164. if (pGoal && pGoal->goal_no == ino)
  165. return pGoal;
  166. pEnt = gEntList.FindEntityByClassname( pEnt, "item_tfgoal" );
  167. }
  168. // Goal does not exist
  169. Warning("Could not find an item with a goal_no of %d.\n", ino);
  170. return NULL;
  171. }
  172. //=========================================================================
  173. // Return the TeamSpawn with a goal_no equal to gno
  174. CTFSpawn* Findteamspawn(int gno)
  175. {
  176. // Search by netname
  177. //TFCTODO: I think FindEntityByClassname will do the same thing.
  178. //CBaseEntity *pEnt = UTIL_FindEntityByString( NULL, "netname", "info_player_teamspawn" );
  179. CBaseEntity *pEnt = gEntList.FindEntityByClassname( NULL, "info_player_teamspawn" );
  180. while ( pEnt )
  181. {
  182. CTFSpawn *pSpawn = dynamic_cast<CTFSpawn*>( pEnt );
  183. if ( pSpawn )
  184. {
  185. if (pSpawn->goal_no == gno)
  186. return pSpawn;
  187. }
  188. pEnt = gEntList.FindEntityByClassname( pEnt, "info_player_teamspawn" );
  189. }
  190. // Goal does not exist
  191. Warning("Could not find a Teamspawn with a goal_no of %d.\n", gno);
  192. return NULL;
  193. }
  194. //=========================================================================
  195. // Return the goal with a goal_no equal to gno
  196. CTFGoal* Findgoal(int gno)
  197. {
  198. CBaseEntity *pEnt = gEntList.FindEntityByClassname( NULL, "item_tfgoal" );
  199. while ( pEnt )
  200. {
  201. CTFGoal *pGoal = dynamic_cast<CTFGoal*>( pEnt );
  202. if (pGoal && pGoal->goal_no == gno)
  203. return pGoal;
  204. pEnt = gEntList.FindEntityByClassname( pEnt, "item_tfgoal" );
  205. }
  206. // Goal does not exist
  207. Warning("Could not find a goal with a goal_no of %d.\n", gno);
  208. return NULL;
  209. }
  210. //=========================================================================
  211. // Remove a Timer/Goal
  212. void RemoveGoal(CTFGoal *pGoal)
  213. {
  214. pGoal->AddSolidFlags( FSOLID_NOT_SOLID );
  215. pGoal->goal_state = TFGS_REMOVED;
  216. pGoal->AddEffects( EF_NODRAW );
  217. }
  218. //=========================================================================
  219. // Return true if the player meets the AP criteria
  220. bool APMeetsCriteria(CTFGoal *Goal, CTFCPlayer *AP)
  221. {
  222. MDEBUG(Warning("==========================\n"));
  223. MDEBUG(Warning("AP Criteria Checking\n"));
  224. MDEBUG(Warning(UTIL_VarArgs("Goal: %s", STRING(Goal->edict()->netname))));
  225. CTFGoal *pGoal;
  226. CTFGoalItem *pItem;
  227. if (AP != NULL && AP->Classify() == CLASS_PLAYER)
  228. {
  229. MDEBUG(Warning(UTIL_VarArgs("\nAP : %s\n", AP->GetPlayerName())));
  230. // If a player of a specific team can only activate this
  231. if (Goal->GetTeamNumber())
  232. {
  233. MDEBUG(Warning(" Checking team."));
  234. if (Goal->GetTeamNumber() != AP->GetTeamNumber())
  235. return false;
  236. if ( !AP->IsAlive() ) // don't want dead or dying players activating this
  237. return false;
  238. MDEBUG(Warning("passed.\n"));
  239. }
  240. // If a player in a team specified by a teamcheck entity can activate this
  241. if (Goal->teamcheck != NULL_STRING)
  242. {
  243. MDEBUG(Warning(" Checking teamcheck entity."));
  244. if ( AP->GetTeamNumber() != GetTeamCheckTeam( STRING(Goal->teamcheck) ) )
  245. return false;
  246. MDEBUG(Warning(" passed.\n"));
  247. }
  248. // If a player of a specific class can only activate this
  249. if (Goal->playerclass)
  250. {
  251. MDEBUG(Warning(" Checking class."));
  252. if (Goal->playerclass != AP->m_Shared.GetPlayerClass())
  253. return false;
  254. MDEBUG(Warning("passed.\n"));
  255. }
  256. // If this activation needs a GoalItem, make sure the player has it
  257. if (Goal->items_allowed)
  258. {
  259. MDEBUG(Warning(" Checking items."));
  260. pItem = Finditem(Goal->items_allowed);
  261. if (!pItem)
  262. return false;
  263. if (pItem->GetOwnerEntity() != AP)
  264. return false;
  265. MDEBUG(Warning("passed.\n"));
  266. }
  267. }
  268. // Check Goal states
  269. if (Goal->if_goal_is_active)
  270. {
  271. MDEBUG(Warning(" Checking if_goal_is_active."));
  272. pGoal = Findgoal(Goal->if_goal_is_active);
  273. if (!pGoal)
  274. return false;
  275. if (pGoal->goal_state != TFGS_ACTIVE)
  276. return false;
  277. MDEBUG(Warning("passed.\n"));
  278. }
  279. if (Goal->if_goal_is_inactive)
  280. {
  281. MDEBUG(Warning(" Checking if_goal_is_inactive."));
  282. pGoal = Findgoal(Goal->if_goal_is_inactive);
  283. if (!pGoal)
  284. return false;
  285. if (pGoal->goal_state != TFGS_INACTIVE)
  286. return false;
  287. MDEBUG(Warning("passed.\n"));
  288. }
  289. if (Goal->if_goal_is_removed)
  290. {
  291. MDEBUG(Warning(" Checking if_goal_is_removed."));
  292. pGoal = Findgoal(Goal->if_goal_is_removed);
  293. if (!pGoal)
  294. return false;
  295. if (pGoal->goal_state != TFGS_REMOVED)
  296. return false;
  297. MDEBUG(Warning("passed.\n"));
  298. }
  299. // Check Group States
  300. if (Goal->if_group_is_active)
  301. {
  302. MDEBUG(Warning(" Checking if_group_is_active."));
  303. if ( !AllGoalsInState(Goal->if_group_is_active, TFGS_ACTIVE) )
  304. return false;
  305. MDEBUG(Warning("passed.\n"));
  306. }
  307. if (Goal->if_group_is_inactive)
  308. {
  309. MDEBUG(Warning(" Checking if_group_is_inactive."));
  310. if ( !AllGoalsInState(Goal->if_group_is_inactive, TFGS_INACTIVE) )
  311. return false;
  312. MDEBUG(Warning("passed.\n"));
  313. }
  314. if (Goal->if_group_is_removed)
  315. {
  316. MDEBUG(Warning(" Checking if_group_is_removed."));
  317. if ( !AllGoalsInState(Goal->if_group_is_removed, TFGS_REMOVED) )
  318. return false;
  319. MDEBUG(Warning("passed.\n"));
  320. }
  321. // Check Item States
  322. if (Goal->if_item_has_moved)
  323. {
  324. MDEBUG(Warning(" Checking if_item_has_moved."));
  325. // Find the item
  326. pItem = Finditem(Goal->if_item_has_moved);
  327. if (!pItem)
  328. return false;
  329. if (pItem->goal_state != TFGS_ACTIVE && pItem->GetAbsOrigin() == pItem->oldorigin)
  330. return false;
  331. MDEBUG(Warning("passed.\n"));
  332. }
  333. if (Goal->if_item_hasnt_moved)
  334. {
  335. MDEBUG(Warning(" Checking if_item_hasnt_moved."));
  336. // Find the item
  337. pItem = Finditem(Goal->if_item_hasnt_moved);
  338. if (!pItem)
  339. return false;
  340. if (pItem->goal_state == TFGS_ACTIVE || pItem->GetAbsOrigin() != pItem->oldorigin )
  341. return false;
  342. MDEBUG(Warning("passed.\n"));
  343. }
  344. // Check Items being carried
  345. if (AP != NULL && AP->Classify() == CLASS_PLAYER)
  346. {
  347. if (Goal->has_item_from_group)
  348. {
  349. MDEBUG(Warning(" Checking has_item_from_group."));
  350. if ( !HasItemFromGroup(AP, Goal->has_item_from_group) )
  351. return false;
  352. MDEBUG(Warning("passed.\n"));
  353. }
  354. if (Goal->hasnt_item_from_group)
  355. {
  356. MDEBUG(Warning(" Checking hasnt_item_from_group."));
  357. if ( HasItemFromGroup(AP, Goal->hasnt_item_from_group) )
  358. return false;
  359. MDEBUG(Warning("passed.\n"));
  360. }
  361. }
  362. MDEBUG(Warning("Criteria passed.\n"));
  363. return true;
  364. }
  365. //=========================================================================
  366. // Return true if the Entity should activate
  367. bool ShouldActivate(CTFGoal *Goal, CTFCPlayer *AP)
  368. {
  369. #ifdef MAP_DEBUG
  370. Warning(UTIL_VarArgs("\nDoIActivate: ", Goal->edict()->netname ? STRING(Goal->edict()->netname) : STRING(Goal->edict()->classname)));
  371. if (AP)
  372. Warning(UTIL_VarArgs(", AP: %s\n", AP->GetPlayerName()));
  373. #endif
  374. // Abort if it's already active
  375. if (Goal->goal_state == TFGS_ACTIVE)
  376. {
  377. MDEBUG(Warning("-- Goal already active --\n"));
  378. return false;
  379. }
  380. // Abort if it's been removed
  381. if (Goal->goal_state == TFGS_REMOVED)
  382. {
  383. MDEBUG(Warning("-- Goal is in Removed state --\n"));
  384. return false;
  385. }
  386. // Abort if it's been activated already and its activation's being delayed
  387. if (Goal->goal_state == TFGS_DELAYED)
  388. {
  389. MDEBUG(Warning("-- Goal is being Delayed --\n"));
  390. return false;
  391. }
  392. // See if the AP matches the criteria
  393. bool bAPMet = APMeetsCriteria(Goal, AP);
  394. bool bAct = false;
  395. bool bRevAct;
  396. if ( FClassnameIs(Goal,"item_tfgoal") )
  397. bRevAct = (Goal->goal_activation & TFGI_REVERSE_AP) != 0;
  398. else
  399. bRevAct = (Goal->goal_activation & TFGA_REVERSE_AP) != 0;
  400. // Does the AP match the AP Criteria?
  401. if (bAPMet)
  402. {
  403. MDEBUG(Warning("-- Criteria met --\n"));
  404. if (!bRevAct)
  405. bAct = true;
  406. }
  407. else
  408. {
  409. MDEBUG(Warning("-- Criteria not met --\n"));
  410. if (bRevAct)
  411. {
  412. MDEBUG(Warning("Reverse Activation\n"));
  413. bAct = true;
  414. }
  415. }
  416. #ifdef MAP_DEBUG
  417. if (bAct)
  418. Warning("Activation.\n");
  419. else
  420. Warning("NO Activation.\n");
  421. #endif
  422. return bAct;
  423. };
  424. //=========================================================================
  425. // Return TRUE if the player is affected by the goal
  426. BOOL IsAffectedBy(CTFGoal *Goal, CTFCPlayer *Player, CTFCPlayer *AP)
  427. {
  428. // Don't affect anyone who isn't alive or is in Observer mode
  429. if (Player->m_Shared.GetPlayerClass() == PC_UNDEFINED)
  430. return FALSE;
  431. // Same Environment Check
  432. if (Goal->goal_effects & TFGE_SAME_ENVIRONMENT)
  433. {
  434. int iEnviron = UTIL_PointContents( Goal->GetAbsOrigin() );
  435. if ( UTIL_PointContents( Player->GetAbsOrigin() ) != iEnviron )
  436. return FALSE;
  437. }
  438. if (Goal->t_length != 0)
  439. {
  440. // Within radius?
  441. if ((Goal->GetAbsOrigin() - Player->GetAbsOrigin()).Length() <= Goal->t_length)
  442. {
  443. // Obstructed by walls?
  444. if (Goal->goal_effects & TFGE_WALL)
  445. {
  446. trace_t tr;
  447. UTIL_TraceLine ( Goal->GetAbsOrigin(), Player->WorldSpaceCenter(), MASK_SOLID, Goal, COLLISION_GROUP_NONE, &tr );
  448. if ( tr.fraction == 1.0 )
  449. return TRUE;
  450. }
  451. else
  452. {
  453. return TRUE;
  454. }
  455. }
  456. }
  457. if ( Goal->Classify() != CLASS_TFGOAL_TIMER && AP != NULL )
  458. {
  459. // Spawnpoints always affect the player who spawns on them
  460. if ((Goal->Classify() == CLASS_TFSPAWN) && (Player == AP))
  461. return TRUE;
  462. if ((Goal->goal_effects & TFGE_AP) && (Player == AP))
  463. return TRUE;
  464. if ((Goal->goal_effects & TFGE_AP_TEAM) && (AP->GetTeamNumber() == Player->GetTeamNumber()))
  465. return TRUE;
  466. }
  467. if (Goal->goal_effects & TFGE_NOT_AP_TEAM)
  468. {
  469. if (AP == NULL || AP->GetTeamNumber() != Player->GetTeamNumber())
  470. return TRUE;
  471. }
  472. if ((Goal->goal_effects & TFGE_NOT_AP) && (Player != AP))
  473. return TRUE;
  474. if ((Goal->maxammo_shells != 0) && (Player->GetTeamNumber() == Goal->maxammo_shells))
  475. return TRUE;
  476. if ((Goal->maxammo_nails != 0) && (Player->GetTeamNumber() != Goal->maxammo_nails))
  477. return TRUE;
  478. return FALSE;
  479. }
  480. //=========================================================================
  481. // Do all the checking of Item Groups
  482. void DoItemGroupWork(CTFGoalItem *Item, CTFCPlayer *AP)
  483. {
  484. if (Item->distance != 0)
  485. {
  486. if (Item->pain_finished == 0)
  487. {
  488. // No goal specified in .pain_finished. Print error.
  489. Warning( "GoalItem %d has .distance specified, but no .pain_finished\n", Item->goal_no );
  490. }
  491. BOOL bAllCarried = TRUE;
  492. // Find all items
  493. CBaseEntity *pEnt = gEntList.FindEntityByClassname( NULL, "item_tfgoal" );
  494. while ( pEnt && bAllCarried )
  495. {
  496. CTFGoalItem *pItem = dynamic_cast<CTFGoalItem*>( pEnt );
  497. if ( pItem )
  498. {
  499. if (pItem->group_no == Item->distance && pItem->goal_state != TFGS_ACTIVE)
  500. bAllCarried = FALSE;
  501. }
  502. pEnt = gEntList.FindEntityByClassname( pEnt, "item_tfgoal" );
  503. }
  504. if (bAllCarried)
  505. {
  506. CTFGoal *pGoal = Findgoal(Item->pain_finished);
  507. if (pGoal)
  508. DoResults(pGoal, AP, (Item->goal_result & TFGR_ADD_BONUSES));
  509. }
  510. }
  511. if (Item->speed != 0)
  512. {
  513. if (Item->attack_finished == 0)
  514. {
  515. // No goal specified in .attack_finished. Print error.
  516. Warning( "GoalItem %d has .speed specified, but no .attack_finished\n", Item->goal_no );
  517. }
  518. BOOL bAllCarried = TRUE;
  519. CBaseEntity *pCarrier = NULL;
  520. // Find all goals
  521. CBaseEntity *pEnt = gEntList.FindEntityByClassname( NULL, "item_tfgoal" );
  522. while ( pEnt && bAllCarried )
  523. {
  524. CTFGoalItem *pItem = dynamic_cast<CTFGoalItem*>( pEnt );
  525. if ( pItem )
  526. {
  527. if (pItem->group_no == Item->speed)
  528. {
  529. if (pItem->goal_state != TFGS_ACTIVE)
  530. bAllCarried = FALSE;
  531. else if (!pCarrier) // Store Player
  532. pCarrier = pItem->GetOwnerEntity();
  533. else if (pCarrier != pItem->GetOwnerEntity()) // Need to all be carried by the same player
  534. bAllCarried = FALSE;
  535. }
  536. }
  537. pEnt = gEntList.FindEntityByClassname( pEnt, "item_tfgoal" );
  538. }
  539. if (bAllCarried)
  540. {
  541. CTFGoal *pGoal = Findgoal(Item->attack_finished);
  542. if (pGoal)
  543. DoResults(pGoal, AP, (Item->goal_result & TFGR_ADD_BONUSES));
  544. }
  545. }
  546. }
  547. //=========================================================================
  548. // Remove any results applied to this player by the Goal
  549. // Used when a GoalItem is dropped/removed
  550. void RemoveResults(CTFGoal *Goal, CTFCPlayer *pPlayer)
  551. {
  552. // Only remove the stats if the player has been affected
  553. // by this item. This is needed because the player may have
  554. // died since being affected
  555. if ( FClassnameIs( Goal, "item_tfgoal" ) )
  556. {
  557. if (!(pPlayer->item_list & Goal->item_list))
  558. return;
  559. if (Goal->goal_activation & TFGI_DONTREMOVERES)
  560. return;
  561. // Remove the affected flag
  562. pPlayer->item_list &= ~(Goal->item_list);
  563. }
  564. if (Goal->GetHealth() > 0)
  565. pPlayer->TakeDamage( CTakeDamageInfo( Goal, Goal, Goal->GetHealth(), DMG_IGNOREARMOR ) );
  566. if (Goal->GetHealth() < 0)
  567. pPlayer->TakeHealth( (0 - Goal->GetHealth()), 0 );
  568. pPlayer->lives -= Goal->lives;
  569. pPlayer->armortype -= Goal->armortype;
  570. pPlayer->SetArmorValue( pPlayer->ArmorValue() - Goal->armorvalue );
  571. pPlayer->armorclass &= ~(Goal->armorclass);
  572. if (Goal->frags)
  573. {
  574. pPlayer->TF_AddFrags(Goal->frags);
  575. }
  576. pPlayer->RemoveAmmo( Goal->ammo_shells, TFC_AMMO_SHELLS );
  577. pPlayer->RemoveAmmo( Goal->ammo_nails, TFC_AMMO_NAILS );
  578. pPlayer->RemoveAmmo( Goal->ammo_rockets, TFC_AMMO_ROCKETS );
  579. pPlayer->RemoveAmmo( Goal->ammo_cells, TFC_AMMO_CELLS );
  580. pPlayer->RemoveAmmo( Goal->ammo_medikit, TFC_AMMO_MEDIKIT );
  581. pPlayer->RemoveAmmo( Goal->ammo_detpack, TFC_AMMO_DETPACK );
  582. // Detpacks
  583. //TFCTODO: this should be handled in the GiveAmmo functions..
  584. // if (pPlayer->ammo_detpack > pPlayer->maxammo_detpack)
  585. // pPlayer->ammo_detpack = pPlayer->maxammo_detpack;
  586. // Grenades
  587. pPlayer->RemoveAmmo( Goal->no_grenades_1, TFC_AMMO_GRENADES1 );
  588. pPlayer->RemoveAmmo( Goal->no_grenades_2, TFC_AMMO_GRENADES2 );
  589. // If they had a primed grenade, and they don't have any more of
  590. // that type of grenade, unprime it and remove it.
  591. if (pPlayer->m_Shared.GetStateFlags() & TFSTATE_GRENPRIMED)
  592. {
  593. if (pPlayer->GetAmmoCount( TFC_AMMO_GRENADES2 ) <= 0 || pPlayer->GetAmmoCount( TFC_AMMO_GRENADES1 ) <= 0)
  594. {
  595. pPlayer->m_Shared.RemoveStateFlags( TFSTATE_GRENPRIMED );
  596. pPlayer->m_Shared.RemoveStateFlags( TFSTATE_GRENTHROWING );
  597. pPlayer->bRemoveGrenade = TRUE;
  598. }
  599. }
  600. BOOL puinvin = FALSE;
  601. BOOL puinvis = FALSE;
  602. BOOL puquad = FALSE;
  603. BOOL purad = FALSE;
  604. // Make sure we don't remove an effect another Goal is also supplying
  605. CBaseEntity *pEnt = gEntList.FindEntityByClassname( NULL, "item_tfgoal" );
  606. while ( pEnt )
  607. {
  608. CTFGoalItem *pItem = dynamic_cast<CTFGoalItem*>( pEnt );
  609. if ( pItem )
  610. {
  611. if ( (pItem->GetOwnerEntity() == pPlayer) && (pEnt != Goal) )
  612. {
  613. if (pItem->invincible_finished > 0)
  614. puinvin = TRUE;
  615. if (pItem->invisible_finished > 0)
  616. puinvis = TRUE;
  617. if (pItem->super_damage_finished > 0)
  618. puquad = TRUE;
  619. if (pItem->radsuit_finished > 0)
  620. purad = TRUE;
  621. }
  622. }
  623. pEnt = gEntList.FindEntityByClassname( pEnt, "item_tfgoal" );
  624. }
  625. // Remove all powerups
  626. if ((Goal->invincible_finished > 0) && (!puinvin))
  627. {
  628. // if its a GoalItem, powerup was permanent, so we remove TFSTATE flag
  629. pPlayer->m_Shared.RemoveStateFlags( TFSTATE_INVINCIBLE );
  630. pPlayer->m_Shared.AddItemFlags( IT_INVULNERABILITY );
  631. pPlayer->invincible_finished = gpGlobals->curtime + Goal->invincible_finished;
  632. }
  633. if ((Goal->invisible_finished > 0) && (!puinvis))
  634. {
  635. // if its a GoalItem, powerup was permanent, so we remove TFSTATE flag
  636. pPlayer->m_Shared.RemoveStateFlags( TFSTATE_INVISIBLE );
  637. pPlayer->m_Shared.AddItemFlags( IT_INVISIBILITY );
  638. pPlayer->invisible_finished = gpGlobals->curtime + Goal->invisible_finished;
  639. }
  640. if ((Goal->super_damage_finished > 0) && (!puquad))
  641. {
  642. // if its a GoalItem, powerup was permanent, so we remove TFSTATE flag
  643. pPlayer->m_Shared.RemoveStateFlags( TFSTATE_QUAD );
  644. pPlayer->m_Shared.AddItemFlags( IT_QUAD );
  645. pPlayer->super_damage_finished = gpGlobals->curtime + Goal->super_damage_finished;
  646. }
  647. if ((Goal->radsuit_finished > 0) && (!purad))
  648. {
  649. // if its a GoalItem, powerup was permanent, so we remove TFSTATE flag
  650. pPlayer->m_Shared.RemoveStateFlags( TFSTATE_RADSUIT );
  651. pPlayer->m_Shared.AddItemFlags( IT_SUIT );
  652. pPlayer->radsuit_finished = gpGlobals->curtime + Goal->radsuit_finished;
  653. }
  654. // Now apply the pev->playerclass limitations & Redisplay Ammo counts
  655. pPlayer->TeamFortress_CheckClassStats();
  656. //W_SetCurrentAmmo ();
  657. if (Goal->replacement_model != NULL_STRING)
  658. {
  659. // is it the same goal that gave us the replacment model?
  660. if (pPlayer->replacement_model == Goal->replacement_model)
  661. {
  662. pPlayer->replacement_model = NULL_STRING;
  663. pPlayer->replacement_model_body = 0;
  664. pPlayer->replacement_model_skin = 0;
  665. pPlayer->replacement_model_flags = 0;
  666. pPlayer->TeamFortress_SetSkin();
  667. }
  668. }
  669. }
  670. //=========================================================================
  671. // Give the GoalItem to a Player.
  672. void tfgoalitem_GiveToPlayer(CTFGoalItem *Item, CTFCPlayer *AP, CTFGoal *Goal)
  673. {
  674. MDEBUG(Warning( "Giving %s to %s\n", Item->GetEntityName().ToCStr(), AP->GetPlayerName()));
  675. // Don't let it re-drop
  676. if (Item->redrop_count)
  677. Item->SetThink( NULL );
  678. Item->SetOwnerEntity( AP );
  679. // Remove it from the map
  680. Item->FollowEntity( AP );
  681. // Play carry animations
  682. if (Item->GetModelName() != NULL_STRING)
  683. {
  684. Item->RemoveEffects( EF_NODRAW );
  685. Item->SetSequence( Item->LookupSequence( "carried" ) );
  686. if (Item->GetSequence() != -1)
  687. {
  688. Item->ResetSequenceInfo();
  689. Item->m_flCycle = 0;
  690. }
  691. }
  692. Item->AddSolidFlags( FSOLID_NOT_SOLID );
  693. // Do the deeds on the player
  694. if (Item->goal_activation & TFGI_GLOW)
  695. AP->AddEffects( EF_BRIGHTLIGHT ); //TFCTODO: this used to be EF_BRIGHTFIELD.. make sure it's the same
  696. if (Item->goal_activation & TFGI_SLOW)
  697. AP->TeamFortress_SetSpeed();
  698. if (Item->speed_reduction)
  699. AP->TeamFortress_SetSpeed();
  700. if (Item->goal_activation & TFGI_ITEMGLOWS)
  701. {
  702. Item->m_nRenderFX = kRenderFxNone;
  703. Item->SetRenderColor( 0, 0, 0, 0 );
  704. }
  705. // Light up console icons
  706. if (Item->items & IT_KEY1)
  707. AP->m_Shared.AddItemFlags( IT_KEY1 );
  708. if (Item->items & IT_KEY2)
  709. AP->m_Shared.AddItemFlags( IT_KEY2 );
  710. if (Item->items & IT_KEY3)
  711. AP->m_Shared.AddItemFlags( IT_KEY3 );
  712. if (Item->items & IT_KEY4)
  713. AP->m_Shared.AddItemFlags( IT_KEY4 );
  714. // Only do the results if we're allowed to
  715. if (Goal != Item)
  716. {
  717. if (Goal->goal_result & TFGR_NO_ITEM_RESULTS)
  718. {
  719. Item->goal_state = TFGS_ACTIVE;
  720. return;
  721. }
  722. }
  723. MDEBUG(Warning("Doing item results...\n"));
  724. // Prevent the Player from disguising themself if applicable
  725. if (Item->goal_result & TFGR_REMOVE_DISGUISE)
  726. AP->is_unableto_spy_or_teleport = 1;
  727. // Do the Results, adding the bonuses
  728. DoResults(Item, AP, TRUE);
  729. // Check the Item Group Stuff
  730. DoItemGroupWork(Item, AP);
  731. }
  732. //=========================================================================
  733. // Drop the item
  734. void tfgoalitem_drop(CTFGoalItem *Item, BOOL PAlive, CTFCPlayer *P)
  735. {
  736. CBaseEntity *pOwner = Item->GetOwnerEntity();
  737. // Backup origin for retry at the drop
  738. if ( FBitSet( pOwner->GetFlags(), FL_DUCKING ) )
  739. Item->redrop_origin = pOwner->GetAbsOrigin() + Vector(0, 0, 26);
  740. else
  741. Item->redrop_origin = pOwner->GetAbsOrigin() + Vector(0, 0, 8);
  742. Item->redrop_count = 0;
  743. Item->SetTouch( &CTFGoalItem::item_tfgoal_touch );
  744. Item->DoDrop( Item->redrop_origin );
  745. Item->SetOwnerEntity( P );
  746. if (PAlive)
  747. {
  748. Vector vForward, vUp;
  749. AngleVectors( P->EyeAngles(), &vForward, NULL, &vUp );
  750. Item->SetAbsVelocity( (vForward * 400) + (vUp * 200) );
  751. Item->SetTouch( NULL );
  752. Item->SetThink( &CTFGoalItem::tfgoalitem_droptouch ); // give it 0.75 seconds
  753. Item->SetNextThink( gpGlobals->curtime + 0.75 ); // and then set it's touch func
  754. // Prevent the dropping player from picking it up for longer
  755. Item->enemy = P;
  756. Item->m_flDroppedAt = gpGlobals->curtime;
  757. }
  758. }
  759. //=========================================================================
  760. // Remove the GoalItem from a Player.
  761. void tfgoalitem_RemoveFromPlayer(CTFGoalItem *Item, CTFCPlayer *AP, int iMethod)
  762. {
  763. MDEBUG(Warning("Removing %s from %s\n", STRING(Item->pev->netname), STRING(AP->pev->netname)));
  764. // If we have a teamcheck entity, use it instead
  765. if ( Item->owned_by_teamcheck != NULL_STRING )
  766. Item->owned_by = GetTeamCheckTeam( STRING(Item->owned_by_teamcheck) );
  767. BOOL lighton = FALSE;
  768. BOOL slowon = FALSE;
  769. BOOL key1on = FALSE;
  770. BOOL key2on = FALSE;
  771. BOOL key3on = FALSE;
  772. BOOL key4on = FALSE;
  773. BOOL spyoff = FALSE;
  774. // Remove the effects from the player
  775. // Make sure we don't remove an effect another Goal is also supplying
  776. CBaseEntity *pEnt = gEntList.FindEntityByClassname( NULL, "item_tfgoal" );
  777. while ( pEnt )
  778. {
  779. CTFGoalItem *pItem = dynamic_cast<CTFGoalItem*>( pEnt );
  780. if ( pItem )
  781. {
  782. if ( (pItem->GetOwnerEntity() == AP) && (pEnt != Item) )
  783. {
  784. if (pItem->goal_activation & TFGI_GLOW)
  785. lighton = TRUE;
  786. if (pItem->goal_activation & TFGI_SLOW)
  787. slowon = TRUE;
  788. if (pItem->items & IT_KEY1)
  789. key1on = TRUE;
  790. if (pItem->items & IT_KEY2)
  791. key2on = TRUE;
  792. if (pItem->items & IT_KEY3)
  793. key3on = TRUE;
  794. if (pItem->items & IT_KEY4)
  795. key4on = TRUE;
  796. if (pItem->goal_result & TFGR_REMOVE_DISGUISE)
  797. spyoff = TRUE;
  798. }
  799. }
  800. pEnt = gEntList.FindEntityByClassname( pEnt, "item_tfgoal" );
  801. }
  802. // Check Powerups too
  803. if (!lighton)
  804. {
  805. if (AP->invincible_finished > gpGlobals->curtime + 3)
  806. lighton = TRUE;
  807. else if (AP->super_damage_finished > gpGlobals->curtime + 3)
  808. lighton = TRUE;
  809. }
  810. if (!lighton)
  811. {
  812. //TFCTODO: Add support for EF_BRIGHTFIELD if necessary.
  813. //AP->RemoveEffects( EF_BRIGHTFIELD );
  814. AP->RemoveEffects( EF_BRIGHTLIGHT );
  815. }
  816. if (Item->goal_activation & TFGI_ITEMGLOWS)
  817. {
  818. Item->m_nRenderFX = kRenderFxGlowShell;
  819. if (Item->owned_by > 0 && Item->owned_by <= 4)
  820. Item->m_clrRender = Vector255ToRGBColor( rgbcolors[Item->owned_by] );
  821. else
  822. Item->m_clrRender = Vector255ToRGBColor( rgbcolors[0] );
  823. Item->SetRenderColorA( 100 ); // Shell size
  824. }
  825. // Remove the Spy prevention
  826. if (!spyoff)
  827. AP->is_unableto_spy_or_teleport = FALSE;
  828. // Remove the lit console key icons
  829. if (!key1on)
  830. AP->m_Shared.RemoveItemFlags( IT_KEY1 );
  831. if (!key2on)
  832. AP->m_Shared.RemoveItemFlags( IT_KEY2 );
  833. if (!key3on)
  834. AP->m_Shared.RemoveItemFlags( IT_KEY3 );
  835. if (!key4on)
  836. AP->m_Shared.RemoveItemFlags( IT_KEY4 );
  837. // Remove AP Modifications
  838. // Go through all the players and do any results
  839. for ( int i = 1; i <= gpGlobals->maxClients; i++ )
  840. {
  841. CTFCPlayer *pPlayer = ToTFCPlayer( UTIL_PlayerByIndex( i ) );
  842. if ( pPlayer && IsAffectedBy(Item, pPlayer, AP) )
  843. RemoveResults(Item, pPlayer);
  844. }
  845. // Setup animations
  846. if (Item->GetModelName() != NULL_STRING)
  847. {
  848. Item->SetSequence( Item->LookupSequence( "not_carried" ) );
  849. if (Item->GetSequence() != -1)
  850. {
  851. Item->ResetSequenceInfo();
  852. Item->m_flCycle = 0;
  853. }
  854. }
  855. // Return it to the starting point if the flag is set
  856. if (iMethod == GI_DROP_PLAYERDEATH || iMethod == GI_DROP_PLAYERDROP)
  857. {
  858. // Do messages
  859. for ( int i = 1; i <= gpGlobals->maxClients; i++ )
  860. {
  861. CBasePlayer *pPlayer = UTIL_PlayerByIndex( i );
  862. if ( !pPlayer )
  863. continue;
  864. if (pPlayer->GetTeamNumber() == Item->owned_by)
  865. {
  866. if (Item->team_drop != NULL_STRING)
  867. UTIL_ShowMessage( STRING(Item->team_drop), pPlayer );
  868. if (Item->netname_team_drop != NULL_STRING)
  869. ClientPrint( pPlayer, HUD_PRINTNOTIFY, STRING(Item->netname_team_drop), AP->GetPlayerName() );
  870. // Old printing
  871. if (Item->org_team_drop != NULL_STRING)
  872. ClientPrint( pPlayer, HUD_PRINTCENTER, STRING(Item->org_team_drop) );
  873. }
  874. else // (pPlayer->GetTeamNumber() != Item->owned_by)
  875. {
  876. if (Item->non_team_drop != NULL_STRING)
  877. UTIL_ShowMessage( STRING(Item->non_team_drop), pPlayer );
  878. if (Item->netname_non_team_drop != NULL_STRING)
  879. ClientPrint( pPlayer, HUD_PRINTNOTIFY, STRING(Item->netname_non_team_drop), AP->GetPlayerName() );
  880. // Old printing
  881. if (Item->org_non_team_drop != NULL_STRING)
  882. ClientPrint( pPlayer, HUD_PRINTCENTER, STRING(Item->org_non_team_drop) );
  883. }
  884. }
  885. // Drop it if the flag is set
  886. if (Item->goal_activation & TFGI_RETURN_DROP)
  887. {
  888. CTimer *pTimer = Timer_CreateTimer( Item, TF_TIMER_RETURNITEM );
  889. pTimer->m_flNextThink = gpGlobals->curtime + 0.5f;
  890. if (iMethod == GI_DROP_PLAYERDEATH)
  891. pTimer->weapon = GI_RET_DROP_DEAD;
  892. else
  893. pTimer->weapon = GI_RET_DROP_LIVING;
  894. }
  895. else if (Item->goal_activation & TFGI_DROP)
  896. {
  897. if ( (iMethod == GI_DROP_PLAYERDROP) && (Item->goal_activation & TFGI_CANBEDROPPED) )
  898. tfgoalitem_drop(Item, TRUE, AP);
  899. else
  900. tfgoalitem_drop(Item, FALSE, AP);
  901. }
  902. else
  903. {
  904. // Remove the Item
  905. Item->SetOwnerEntity( NULL );
  906. Item->SetNextThink( gpGlobals->curtime );
  907. Item->SetThink( &CBaseEntity::SUB_Remove );
  908. AP->TeamFortress_SetSpeed();
  909. return;
  910. }
  911. Item->SetOwnerEntity( NULL );
  912. Item->RemoveFlag( FL_ONGROUND );
  913. UTIL_SetSize(Item, Item->goal_min, Item->goal_max);
  914. AP->TeamFortress_SetSpeed();
  915. }
  916. else if (iMethod == GI_DROP_REMOVEGOAL)
  917. {
  918. Item->SetOwnerEntity( NULL );
  919. if (Item->goal_activation & TFGI_RETURN_GOAL)
  920. {
  921. CTimer *pTimer = Timer_CreateTimer( Item, TF_TIMER_RETURNITEM );
  922. pTimer->m_flNextThink = gpGlobals->curtime + 0.5;
  923. pTimer->weapon = GI_RET_GOAL;
  924. AP->TeamFortress_SetSpeed();
  925. return;
  926. }
  927. // Don't remove it, since it may be given away again later
  928. Item->AddSolidFlags( FSOLID_NOT_SOLID );
  929. Item->AddEffects( EF_NODRAW );
  930. Item->StopFollowingEntity();
  931. AP->TeamFortress_SetSpeed();
  932. }
  933. }
  934. //=========================================================================
  935. // Apply modifications to the Player passed in
  936. void Apply_Results(CTFGoal *Goal, CTFCPlayer *Player, CTFCPlayer *AP, BOOL bAddBonuses)
  937. {
  938. MDEBUG( Warning("Applying Results from %s to %s\n", STRING(Goal->pev->netname), STRING(Player->pev->netname)) );
  939. // If this is a goalitem, record the fact that this player
  940. // has been affected by it.
  941. if ( FClassnameIs(Goal, "item_tfgoal") )
  942. Player->item_list |= Goal->item_list;
  943. if (Player == AP)
  944. {
  945. // Alter the team score
  946. if (Goal->count != 0 && Player->GetTeamNumber() > 0)
  947. {
  948. TeamFortress_TeamIncreaseScore(Player->GetTeamNumber(), Goal->count);
  949. // Display short team scores
  950. //TeamFortress_TeamShowScores(FALSE, NULL);
  951. }
  952. }
  953. // Apply Stats, only if told to
  954. if (bAddBonuses)
  955. {
  956. MDEBUG( Warning("Adding bonuses.\n") );
  957. // Some results are not applied to dead players
  958. if ( Player->IsAlive() )
  959. {
  960. if (Goal->GetHealth() > 0)
  961. Player->TakeHealth(Goal->GetHealth(), 0);
  962. if (Goal->GetHealth() < 0)
  963. {
  964. // Make sure we don't gib them, because it creates too many entities if
  965. // a lot of players are affected by this Goal.
  966. Player->TakeDamage( CTakeDamageInfo( Goal, Goal, (0 - Goal->GetHealth()), DMG_IGNOREARMOR | DMG_NEVERGIB ) );
  967. }
  968. }
  969. // The player may be dead now, so check again
  970. if ( Player->IsAlive() )
  971. {
  972. if (Goal->armortype > 0)
  973. Player->armortype = Goal->armortype;
  974. else if (Goal->armorvalue > 0)
  975. Player->armortype = Player->armor_allowed;
  976. Player->IncrementArmorValue( Goal->armorvalue );
  977. if (Goal->armorclass > 0)
  978. Player->armorclass = Goal->armorclass;
  979. Player->GiveAmmo( Goal->ammo_shells, TFC_AMMO_SHELLS );
  980. Player->GiveAmmo( Goal->ammo_nails, TFC_AMMO_NAILS );
  981. Player->GiveAmmo( Goal->ammo_rockets, TFC_AMMO_ROCKETS );
  982. Player->GiveAmmo( Goal->ammo_cells, TFC_AMMO_CELLS );
  983. Player->GiveAmmo( Goal->ammo_medikit, TFC_AMMO_MEDIKIT );
  984. Player->GiveAmmo( Goal->ammo_detpack, TFC_AMMO_DETPACK );
  985. #ifdef TFCTODO // do this when grenades are implemented.
  986. // Grenades
  987. if ( Player->tp_grenades_1 != GR_TYPE_NONE )
  988. Player->no_grenades_1 += Goal->no_grenades_1;
  989. if ( Player->tp_grenades_2 != GR_TYPE_NONE )
  990. Player->no_grenades_2 += Goal->no_grenades_2;
  991. // If they had a primed grenade, and they don't have any more of
  992. // that type of grenade, unprime it and remove it.
  993. if (Player->tfstate & TFSTATE_GRENPRIMED)
  994. {
  995. if ( (Player->m_iPrimedGrenType == 1 && Player->no_grenades_1 <= 0 && Goal->no_grenades_1 < 0) ||
  996. (Player->m_iPrimedGrenType == 2 && Player->no_grenades_2 <= 0 && Goal->no_grenades_2 < 0) )
  997. {
  998. Player->tfstate &= ~TFSTATE_GRENPRIMED;
  999. Player->tfstate &= ~TFSTATE_GRENTHROWING;
  1000. Player->bRemoveGrenade = TRUE;
  1001. }
  1002. }
  1003. #endif
  1004. // Apply any powerups
  1005. if (Goal->invincible_finished > 0)
  1006. {
  1007. Player->m_Shared.AddItemFlags( IT_INVULNERABILITY );
  1008. Player->invincible_finished = gpGlobals->curtime + Goal->invincible_finished;
  1009. // if its a GoalItem, powerup is permanent, so we use TFSTATE flags
  1010. if ( FClassnameIs(Goal, "item_tfgoal") )
  1011. {
  1012. Player->m_Shared.AddStateFlags( TFSTATE_INVINCIBLE );
  1013. Player->invincible_finished = gpGlobals->curtime + 666;
  1014. }
  1015. // Force it to recalculate shell color
  1016. Player->m_nRenderFX = kRenderFxNone;
  1017. }
  1018. if (Goal->invisible_finished > 0)
  1019. {
  1020. Player->m_Shared.AddItemFlags( IT_INVISIBILITY );
  1021. Player->invisible_finished = gpGlobals->curtime + Goal->invisible_finished;
  1022. // if its a GoalItem, powerup is permanent, so we use TFSTATE flags
  1023. if ( FClassnameIs(Goal, "item_tfgoal") )
  1024. {
  1025. Player->m_Shared.AddStateFlags( TFSTATE_INVISIBLE );
  1026. Player->invisible_finished = gpGlobals->curtime + 666;
  1027. }
  1028. // Force it to recalculate shell color
  1029. Player->m_nRenderFX = kRenderFxNone;
  1030. }
  1031. if (Goal->super_damage_finished > 0)
  1032. {
  1033. Player->m_Shared.AddItemFlags( IT_QUAD );
  1034. Player->super_damage_finished = gpGlobals->curtime + Goal->super_damage_finished;
  1035. // if its a GoalItem, powerup is permanent, so we use TFSTATE flags
  1036. if ( FClassnameIs(Goal, "item_tfgoal") )
  1037. {
  1038. Player->m_Shared.AddStateFlags( TFSTATE_QUAD );
  1039. Player->super_damage_finished = gpGlobals->curtime + 666;
  1040. }
  1041. // Force it to recalculate shell color
  1042. Player->m_nRenderFX = kRenderFxNone;
  1043. }
  1044. if (Goal->radsuit_finished > 0)
  1045. {
  1046. Player->m_Shared.AddItemFlags( IT_SUIT );
  1047. Player->radsuit_finished = gpGlobals->curtime + Goal->radsuit_finished;
  1048. // if its a GoalItem, powerup is permanent, so we use TFSTATE flags
  1049. if ( FClassnameIs(Goal, "item_tfgoal") )
  1050. {
  1051. Player->m_Shared.AddStateFlags( TFSTATE_RADSUIT );
  1052. Player->radsuit_finished = gpGlobals->curtime + 666;
  1053. }
  1054. }
  1055. }
  1056. // These results are applied to dead and living players
  1057. Player->lives += Goal->lives;
  1058. if ( Goal->frags != 0 )
  1059. Player->TF_AddFrags(Goal->frags);
  1060. // Now apply the m_Shared.GetPlayerClass() limitations & Redisplay Ammo counts
  1061. Player->TeamFortress_CheckClassStats();
  1062. }
  1063. #ifdef MAP_DEBUG
  1064. else
  1065. ALERT( at_console, "NOT Adding bonuses.\n" );
  1066. #endif
  1067. // If the Goal resets Spy skin/color then do it
  1068. if (Player->m_Shared.GetPlayerClass() == PC_SPY && Goal->goal_result & TFGR_REMOVE_DISGUISE)
  1069. {
  1070. //TFCTODO: looks like this isn't actually used anywhere.
  1071. //Player->immune_to_check = gpGlobals->curtime + 10;
  1072. Player->Spy_RemoveDisguise();
  1073. }
  1074. // If there's a GoalItem for this goal, give it to the player
  1075. // GoalItems use "items" for the console lights... so don't do it for items.
  1076. if ( Goal->items != 0 && !FClassnameIs(Goal,"item_tfgoal") )
  1077. {
  1078. // Find the item
  1079. CTFGoalItem *pItem = Finditem(Goal->items);
  1080. // Don't give them the item if it's the item that just affected them
  1081. if (pItem != NULL && pItem != Goal)
  1082. tfgoalitem_GiveToPlayer(pItem, Player, Goal);
  1083. }
  1084. // If this goal removes an item from the player, remove it
  1085. if (Goal->axhitme != 0)
  1086. {
  1087. CTFGoalItem *pItem = Finditem(Goal->axhitme);
  1088. if (pItem->GetOwnerEntity() == Player)
  1089. tfgoalitem_RemoveFromPlayer(pItem, Player, GI_DROP_REMOVEGOAL);
  1090. }
  1091. // if this goal removes a group of items from the player, remove them
  1092. if (Goal->remove_item_group != 0)
  1093. {
  1094. // Find all items in the group
  1095. CTFGoalItem *pItemToRemove = NULL;
  1096. CBaseEntity *pEnt = gEntList.FindEntityByClassname( NULL, "item_tfgoal" );
  1097. while ( pEnt )
  1098. {
  1099. CTFGoalItem *pItem = dynamic_cast<CTFGoalItem*>( pEnt );
  1100. if ( pItem )
  1101. {
  1102. if ( (pItem->group_no == Goal->remove_item_group) && (pItem->GetOwnerEntity() == Player) )
  1103. pItemToRemove = pItem;
  1104. // need to cycle before removing it from the player, because it may be destroyed
  1105. pEnt = gEntList.FindEntityByClassname( pEnt, "item_tfgoal" );
  1106. if (pItemToRemove)
  1107. {
  1108. tfgoalitem_RemoveFromPlayer(pItemToRemove, Player, GI_DROP_REMOVEGOAL);
  1109. pItemToRemove = NULL;
  1110. }
  1111. }
  1112. }
  1113. }
  1114. // Display all the item statuses
  1115. Player->DisplayLocalItemStatus(Goal);
  1116. // Destroy buildings
  1117. if (Goal->goal_result & TFGR_DESTROY_BUILDINGS)
  1118. {
  1119. Player->no_sentry_message = TRUE;
  1120. Player->no_dispenser_message = TRUE;
  1121. Player->no_entry_teleporter_message = TRUE;
  1122. Player->no_exit_teleporter_message = TRUE;
  1123. Player->Engineer_RemoveBuildings();
  1124. Player->TeamFortress_RemoveLiveGrenades();
  1125. Player->TeamFortress_RemoveRockets();
  1126. Player->RemovePipebombs();
  1127. // is the player setting a detpack?
  1128. if ( Player->is_detpacking )
  1129. {
  1130. Player->TeamFortress_DetpackStop();
  1131. }
  1132. else
  1133. {
  1134. // does the player have a detpack in the world?
  1135. if ( Player->TeamFortress_RemoveDetpacks() )
  1136. {
  1137. Player->GiveAmmo( 1, TFC_AMMO_DETPACK );
  1138. }
  1139. }
  1140. }
  1141. // Force respawns
  1142. if (Goal->goal_result & TFGR_FORCE_RESPAWN)
  1143. {
  1144. // Only if they're alive
  1145. if ( Player->IsAlive() )
  1146. Player->ForceRespawn();
  1147. }
  1148. if (Goal->replacement_model != NULL_STRING)
  1149. {
  1150. // if we don't already have a replacement_model
  1151. if ( !Player->replacement_model )
  1152. {
  1153. Player->replacement_model = Goal->replacement_model;
  1154. Player->replacement_model_body = Goal->replacement_model_body;
  1155. Player->replacement_model_skin = Goal->replacement_model_skin;
  1156. Player->replacement_model_flags = Goal->replacement_model_flags;
  1157. Player->TeamFortress_SetSkin();
  1158. }
  1159. }
  1160. }
  1161. //=========================================================================
  1162. // Use (Triggered) function for Goals
  1163. void EndRound( CTFGoal *pGoal )
  1164. {
  1165. // fade everyones screen
  1166. color32 clr;
  1167. memset( &clr, 0, sizeof( clr ) );
  1168. UTIL_ScreenFadeAll( clr, 0.3, pGoal->m_flEndRoundTime, FFADE_MODULATE | FFADE_OUT );
  1169. // Display Long TeamScores to everyone
  1170. TeamFortress_TeamShowScores(TRUE, NULL);
  1171. int highestScore = -99990;
  1172. int winningTeam = 1;
  1173. const char *winnerMsg = "";
  1174. // Only do team score check if the win one is set
  1175. if ( pGoal->m_iszEndRoundMsg_Team1_Win != NULL_STRING )
  1176. {
  1177. // work out which team won
  1178. for ( int i = 1; i <= 4; i++ )
  1179. {
  1180. int teamScore = TeamFortress_TeamGetScoreFrags( i );
  1181. if ( teamScore > highestScore )
  1182. {
  1183. winningTeam = i;
  1184. highestScore = teamScore;
  1185. }
  1186. }
  1187. // work out the winning msg
  1188. switch ( winningTeam )
  1189. {
  1190. case 1: winnerMsg = STRING(pGoal->m_iszEndRoundMsg_Team1_Win); break;
  1191. case 2: winnerMsg = STRING(pGoal->m_iszEndRoundMsg_Team2_Win); break;
  1192. case 3: winnerMsg = STRING(pGoal->m_iszEndRoundMsg_Team3_Win); break;
  1193. case 4: winnerMsg = STRING(pGoal->m_iszEndRoundMsg_Team4_Win); break;
  1194. };
  1195. }
  1196. // Prevent players from moving and shooting
  1197. no_cease_fire_text = TRUE;
  1198. cease_fire = TRUE;
  1199. // Send out the messages
  1200. CTFCPlayer *client = NULL;
  1201. while ( ((client = (CTFCPlayer*)gEntList.FindEntityByClassname( client, "player" )) != NULL) && (!FNullEnt(client->edict())) )
  1202. {
  1203. if ( !client )
  1204. continue;
  1205. // Freeze all the players
  1206. if ( client->IsObserver() == FALSE )
  1207. {
  1208. //TFCTODO implement something for this?
  1209. // iuser4 stops firing on the clients
  1210. //client->pev->iuser4 = TRUE;
  1211. //TFCTODO: implement HIDEHUD_WEAPONS, or is it the same as HIDEHUD_WEAPONSELECTION?
  1212. //client->m_Local.m_iHideHUD |= (HIDEHUD_HEALTH | HIDEHUD_WEAPONS);
  1213. client->m_Local.m_iHideHUD |= (HIDEHUD_HEALTH | HIDEHUD_WEAPONSELECTION);
  1214. client->m_Shared.AddStateFlags( TFSTATE_CANT_MOVE );
  1215. }
  1216. client->TeamFortress_SetSpeed();
  1217. // Owned by and Non owned by take precedence
  1218. if ( pGoal->m_iszEndRoundMsg_OwnedBy != NULL_STRING && ( client->GetTeamNumber() == pGoal->owned_by ) )
  1219. {
  1220. UTIL_ShowMessage( STRING( pGoal->m_iszEndRoundMsg_OwnedBy ), client );
  1221. }
  1222. else if ( pGoal->m_iszEndRoundMsg_NonOwnedBy != NULL_STRING && ( client->GetTeamNumber() != pGoal->owned_by ) )
  1223. {
  1224. UTIL_ShowMessage( STRING( pGoal->m_iszEndRoundMsg_NonOwnedBy ), client );
  1225. }
  1226. else if ( pGoal->m_iszEndRoundMsg_Team1_Win != NULL_STRING && client->GetTeamNumber() == winningTeam )
  1227. {
  1228. UTIL_ShowMessage( winnerMsg, client );
  1229. }
  1230. else
  1231. {
  1232. const char *loserMsg = "";
  1233. // work out the loser message and send it to them
  1234. if ( pGoal->m_iszEndRoundMsg_Team1_Win != NULL_STRING )
  1235. {
  1236. switch ( client->GetTeamNumber() )
  1237. {
  1238. case 1: loserMsg = STRING(pGoal->m_iszEndRoundMsg_Team1_Lose); break;
  1239. case 2: loserMsg = STRING(pGoal->m_iszEndRoundMsg_Team2_Lose); break;
  1240. case 3: loserMsg = STRING(pGoal->m_iszEndRoundMsg_Team3_Lose); break;
  1241. case 4: loserMsg = STRING(pGoal->m_iszEndRoundMsg_Team4_Lose); break;
  1242. };
  1243. }
  1244. else
  1245. {
  1246. switch ( client->GetTeamNumber() )
  1247. {
  1248. case 1: loserMsg = STRING(pGoal->m_iszEndRoundMsg_Team1); break;
  1249. case 2: loserMsg = STRING(pGoal->m_iszEndRoundMsg_Team2); break;
  1250. case 3: loserMsg = STRING(pGoal->m_iszEndRoundMsg_Team3); break;
  1251. case 4: loserMsg = STRING(pGoal->m_iszEndRoundMsg_Team4); break;
  1252. };
  1253. }
  1254. UTIL_ShowMessage( loserMsg, client );
  1255. }
  1256. }
  1257. // Create a timer to remove the EndRound in the specified time
  1258. CTimer *pTimer = Timer_CreateTimer( pGoal, TF_TIMER_ENDROUND );
  1259. //pTimer->SetThink( &CBaseEntity::EndRoundEnd );
  1260. pTimer->m_flNextThink = gpGlobals->curtime + pGoal->m_flEndRoundTime;
  1261. }
  1262. //=========================================================================
  1263. // Inactivate a Timer/Goal
  1264. void InactivateGoal(CTFGoal *Goal)
  1265. {
  1266. MDEBUG( Warning("Inactivating %s", STRING(Goal->pev->netname)) );
  1267. if (Goal->goal_state == TFGS_ACTIVE)
  1268. {
  1269. MDEBUG( Warning("... succeeded.\n") );
  1270. // Not a timer goal
  1271. if (Goal->Classify() != CLASS_TFGOAL_TIMER)
  1272. {
  1273. if ( Goal->goal_activation & TFGI_SOLID && (Goal->Classify() == CLASS_TFGOAL || Goal->Classify() == CLASS_TFGOAL_ITEM) )
  1274. Goal->SetSolid( SOLID_BBOX );
  1275. else
  1276. Goal->AddSolidFlags( FSOLID_TRIGGER );
  1277. }
  1278. Goal->goal_state = TFGS_INACTIVE;
  1279. const char *pModel = STRING( Goal->GetModelName() );
  1280. if (pModel && pModel[0] != '*')
  1281. Goal->RemoveEffects( EF_NODRAW );
  1282. }
  1283. #ifdef MAP_DEBUG
  1284. else
  1285. Warning("... failed. Goal is %s\n", g_szStates[Goal->goal_state]);
  1286. #endif
  1287. }
  1288. //=========================================================================
  1289. // Restores a Timer/Goal
  1290. void RestoreGoal(CTFGoal *Goal)
  1291. {
  1292. MDEBUG( Warning("Attempting to Restore %s", STRING(Goal->pev->netname)) );
  1293. if (Goal->goal_state == TFGS_REMOVED)
  1294. {
  1295. MDEBUG( Warning("... succeeded.\n") );
  1296. // Not a timer goal
  1297. if (Goal->search_time == 0)
  1298. {
  1299. if (Goal->goal_activation & TFGI_SOLID && FClassnameIs(Goal, "item_tfgoal") )
  1300. Goal->SetSolid( SOLID_BBOX );
  1301. else
  1302. Goal->AddSolidFlags( FSOLID_TRIGGER );
  1303. }
  1304. else
  1305. Goal->SetNextThink( gpGlobals->curtime + Goal->search_time );
  1306. Goal->goal_state = TFGS_INACTIVE;
  1307. const char *pModel = STRING(Goal->GetModelName());
  1308. if (pModel[0] != '*')
  1309. Goal->RemoveEffects( EF_NODRAW );
  1310. }
  1311. #ifdef MAP_DEBUG
  1312. else
  1313. Warning("... failed. Goal is %s\n", g_szStates[Goal->goal_state]);
  1314. #endif
  1315. }
  1316. //=========================================================================
  1317. // Do all the activation/inactivation/etc of Goal Groups
  1318. void DoGroupWork(CTFGoal *Goal, CTFCPlayer *AP)
  1319. {
  1320. #ifdef MAP_DEBUG
  1321. if (Goal->all_active || Goal->activate_group_no || Goal->inactivate_group_no || Goal->restore_group_no || Goal->remove_group_no)
  1322. Warning("Doing Groupwork...\n");
  1323. #endif
  1324. // Check all goals activated flag
  1325. if (Goal->all_active != 0)
  1326. {
  1327. if (Goal->last_impulse == 0)
  1328. {
  1329. // No goal specified in .last_impulse. Print error.
  1330. Warning("Goal %d has .all_active specified, but no .last_impulse\n", Goal->goal_no);
  1331. }
  1332. else
  1333. {
  1334. MDEBUG( Warning("All Active Group Check.\n") );
  1335. BOOL bAllSet = TRUE;
  1336. // Find all goals
  1337. CBaseEntity *pEnt = gEntList.FindEntityByClassname( NULL, "info_tfgoal" );
  1338. while ( pEnt && bAllSet)
  1339. {
  1340. CTFGoal *pGoal = dynamic_cast< CTFGoal* >( pEnt );
  1341. if ( pGoal )
  1342. {
  1343. if (pGoal->group_no == Goal->all_active && pGoal->goal_state != TFGS_ACTIVE)
  1344. bAllSet = FALSE;
  1345. }
  1346. pEnt = gEntList.FindEntityByClassname( pEnt, "info_tfgoal" );
  1347. }
  1348. // If all goals in this group are activated, do it
  1349. if (bAllSet)
  1350. {
  1351. MDEBUG( Warning("All Active, Activating last_impulse.\n") );
  1352. CTFGoal *pGoal = Findgoal(Goal->last_impulse);
  1353. if (pGoal)
  1354. DoResults(pGoal, AP, (Goal->goal_result & TFGR_ADD_BONUSES));
  1355. }
  1356. #ifdef MAP_DEBUG
  1357. else
  1358. {
  1359. Warning("Not all Active.\n");
  1360. }
  1361. #endif
  1362. }
  1363. }
  1364. // Check Activate all in the group flag
  1365. if (Goal->activate_group_no != 0)
  1366. {
  1367. // Find all goals
  1368. CBaseEntity *pEnt = gEntList.FindEntityByClassname( NULL, "info_tfgoal" );
  1369. while ( pEnt )
  1370. {
  1371. CTFGoal *pGoal = dynamic_cast< CTFGoal* >( pEnt );
  1372. if ( pGoal )
  1373. {
  1374. if (pGoal->group_no == Goal->activate_group_no)
  1375. ActivateDoResults(pGoal, AP, Goal);
  1376. }
  1377. pEnt = gEntList.FindEntityByClassname( pEnt, "info_tfgoal" );
  1378. }
  1379. }
  1380. // Check Inactivate all in the group flag
  1381. if (Goal->inactivate_group_no != 0)
  1382. {
  1383. // Find all goals
  1384. CBaseEntity *pEnt = gEntList.FindEntityByClassname( NULL, "info_tfgoal" );
  1385. while ( pEnt )
  1386. {
  1387. CTFGoal *pGoal = dynamic_cast< CTFGoal* >( pEnt );
  1388. if ( pGoal )
  1389. {
  1390. if (pGoal->group_no == Goal->inactivate_group_no)
  1391. InactivateGoal(pGoal);
  1392. }
  1393. pEnt = gEntList.FindEntityByClassname( pEnt, "info_tfgoal" );
  1394. }
  1395. }
  1396. // Check Remove all in the group flag
  1397. if (Goal->remove_group_no != 0)
  1398. {
  1399. // Find all goals
  1400. CBaseEntity *pEnt = gEntList.FindEntityByClassname( NULL, "info_tfgoal" );
  1401. while ( pEnt )
  1402. {
  1403. CTFGoal *pGoal = dynamic_cast< CTFGoal* >( pEnt );
  1404. if ( pGoal )
  1405. {
  1406. if (pGoal->group_no == Goal->remove_group_no)
  1407. RemoveGoal(pGoal);
  1408. }
  1409. pEnt = gEntList.FindEntityByClassname( pEnt, "info_tfgoal" );
  1410. }
  1411. }
  1412. // Check Restore all in the group flag
  1413. if (Goal->restore_group_no != 0)
  1414. {
  1415. // Find all goals
  1416. CBaseEntity *pEnt = gEntList.FindEntityByClassname( NULL, "info_tfgoal" );
  1417. while ( pEnt )
  1418. {
  1419. CTFGoal *pGoal = dynamic_cast< CTFGoal* >( pEnt );
  1420. if ( pGoal )
  1421. {
  1422. if (pGoal->group_no == Goal->restore_group_no)
  1423. RestoreGoal(pGoal);
  1424. }
  1425. pEnt = gEntList.FindEntityByClassname( pEnt, "info_tfgoal" );
  1426. }
  1427. }
  1428. #ifdef MAP_DEBUG
  1429. if (Goal->remove_spawngroup || Goal->restore_spawngroup)
  1430. Warning("Doing SpawnGroupwork...\n");
  1431. #endif
  1432. }
  1433. //=========================================================================
  1434. // Do all the activation/inactivation/etc of individual Goals
  1435. void DoGoalWork(CTFGoal *Goal, CTFCPlayer *AP)
  1436. {
  1437. #ifdef MAP_DEBUG
  1438. if (Goal->activate_goal_no || Goal->inactivate_goal_no || Goal->restore_goal_no || Goal->remove_goal_no || Goal->return_item_no)
  1439. Warning("Doing Goalwork...\n");
  1440. #endif
  1441. // If another goal should be activated, activate it
  1442. if (Goal->activate_goal_no != 0)
  1443. {
  1444. CTFGoal *pFoundGoal = Findgoal(Goal->activate_goal_no);
  1445. if (pFoundGoal)
  1446. ActivateDoResults(pFoundGoal, AP, Goal);
  1447. }
  1448. // If another goal should be inactivated, inactivate it
  1449. if (Goal->inactivate_goal_no != 0)
  1450. {
  1451. CTFGoal *pFoundGoal = Findgoal(Goal->inactivate_goal_no);
  1452. if (pFoundGoal)
  1453. InactivateGoal(pFoundGoal);
  1454. }
  1455. // If another goal should be restored, restore it
  1456. if (Goal->restore_goal_no != 0)
  1457. {
  1458. CTFGoal *pFoundGoal = Findgoal(Goal->restore_goal_no);
  1459. if (pFoundGoal)
  1460. RestoreGoal(pFoundGoal);
  1461. }
  1462. // If another goal should be removed, remove it
  1463. if (Goal->remove_goal_no != 0)
  1464. {
  1465. CTFGoal *pFoundGoal = Findgoal(Goal->remove_goal_no);
  1466. if (pFoundGoal)
  1467. RemoveGoal(pFoundGoal);
  1468. }
  1469. // If a GoalItem should be returned, return it
  1470. if (Goal->return_item_no != 0)
  1471. {
  1472. CTFGoalItem *pFoundGoal = Finditem(Goal->return_item_no);
  1473. if (pFoundGoal)
  1474. {
  1475. CBaseEntity *pOwner = pFoundGoal->GetOwnerEntity();
  1476. Assert( dynamic_cast<CTFCPlayer*>( pOwner ) );
  1477. if (pFoundGoal->goal_state == TFGS_ACTIVE)
  1478. tfgoalitem_RemoveFromPlayer(pFoundGoal, (CTFCPlayer*)pOwner, GI_DROP_REMOVEGOAL);
  1479. // Setup a ReturnItem timer
  1480. CTimer *pTimer = Timer_CreateTimer( pFoundGoal, TF_TIMER_RETURNITEM );
  1481. pTimer->weapon = GI_RET_TIME;
  1482. pTimer->m_flNextThink = gpGlobals->curtime + 0.1;
  1483. pFoundGoal->AddSolidFlags( FSOLID_NOT_SOLID );
  1484. }
  1485. }
  1486. #ifdef MAP_DEBUG
  1487. if (Goal->remove_spawnpoint || Goal->restore_spawnpoint)
  1488. Warning("Doing Spawnwork...\n");
  1489. #endif
  1490. // Spawnpoint behaviour
  1491. if (Goal->remove_spawnpoint != 0)
  1492. {
  1493. CTFSpawn *pFoundGoal = Findteamspawn(Goal->remove_spawnpoint);
  1494. if (pFoundGoal)
  1495. InactivateSpawn(pFoundGoal);
  1496. }
  1497. if (Goal->restore_spawnpoint != 0)
  1498. {
  1499. CTFSpawn *pFoundGoal = Findteamspawn(Goal->restore_spawnpoint);
  1500. if (pFoundGoal)
  1501. {
  1502. if (pFoundGoal->goal_state == TFGS_REMOVED)
  1503. ActivateSpawn(pFoundGoal);
  1504. }
  1505. }
  1506. }
  1507. //=========================================================================
  1508. // Do all the activation/removal of Quake Triggers
  1509. void DoTriggerWork(CTFGoal *Goal, CTFCPlayer *AP)
  1510. {
  1511. // remove killtargets
  1512. if (Goal->killtarget != NULL_STRING)
  1513. {
  1514. MDEBUG( Warning("Doing Triggerwork...\n") );
  1515. MDEBUG( Warning("Killing Target(s): %s\n", STRING(Goal->killtarget)) );
  1516. CBaseEntity *pentKillTarget = gEntList.FindEntityByName( NULL, STRING(Goal->killtarget) );
  1517. while ( pentKillTarget )
  1518. {
  1519. UTIL_Remove( pentKillTarget );
  1520. pentKillTarget = gEntList.FindEntityByName( pentKillTarget, STRING(Goal->killtarget) );
  1521. }
  1522. }
  1523. // fire targets
  1524. if (Goal->target != NULL_STRING)
  1525. {
  1526. MDEBUG( Warning("Doing Triggerwork...\n") );
  1527. MDEBUG( ALERT( at_console, "Activating Target(s): %s\n", STRING(Goal->pev->target) ) );
  1528. CBaseEntity *pentTarget = gEntList.FindEntityByName( NULL, STRING(Goal->target) );
  1529. while ( pentTarget )
  1530. {
  1531. CBaseEntity *pTarget = pentTarget;
  1532. if ( !(pTarget->GetFlags() & FL_KILLME) )
  1533. pTarget->Use( AP, Goal, USE_TOGGLE, 0 );
  1534. pentTarget = gEntList.FindEntityByName( pentTarget, STRING(Goal->target) );
  1535. }
  1536. }
  1537. }
  1538. //=========================================================================
  1539. // Setup the way this Timer/Goal/Item will respawn
  1540. void SetupRespawn(CTFGoal *pGoal)
  1541. {
  1542. MDEBUG( Warning("Setting up Respawn...\n") );
  1543. pGoal->m_bAddBonuses = FALSE;
  1544. // Check status of respawn for this goal
  1545. // Single Activation, do nothing
  1546. if (pGoal->goal_result & TFGR_SINGLE)
  1547. {
  1548. RemoveGoal(pGoal);
  1549. return;
  1550. }
  1551. // Timer Goal?
  1552. if (pGoal->Classify() == CLASS_TFGOAL_TIMER)
  1553. {
  1554. InactivateGoal(pGoal);
  1555. pGoal->SetThink( &CTFGoal::tfgoal_timer_tick );
  1556. pGoal->SetNextThink( gpGlobals->curtime + pGoal->search_time );
  1557. return;
  1558. }
  1559. // Respawn Activation, set up respawn
  1560. if (pGoal->wait > 0)
  1561. {
  1562. pGoal->SetThink(&CTFGoal::DoRespawn);
  1563. pGoal->SetNextThink( gpGlobals->curtime + pGoal->wait );
  1564. return;
  1565. }
  1566. // Permanently active goal?
  1567. else if (pGoal->wait == -1)
  1568. return;
  1569. // Otherwise, it's a Multiple Goal
  1570. InactivateGoal(pGoal);
  1571. }
  1572. //=========================================================================
  1573. // Do the results for the Timer/Goal/Item
  1574. void DoResults(CTFGoal *Goal, CTFCPlayer *AP, BOOL bAddBonuses)
  1575. {
  1576. // Can't activate during PreMatch time
  1577. if ( (TFCGameRules()->IsInPreMatch()) && (Goal->Classify() != CLASS_TFGOAL_TIMER) )
  1578. return;
  1579. // Is the goal already activated?
  1580. // This check is needed for goals which are being activated by other goals
  1581. if (Goal->goal_state == TFGS_ACTIVE)
  1582. return;
  1583. // Delayed Activation?
  1584. if (Goal->delay_time > 0 && Goal->goal_state != TFGS_DELAYED)
  1585. {
  1586. MDEBUG( Warning("Delaying Results of %s\n", STRING(Goal->edict()->netname)) );
  1587. Goal->goal_state = TFGS_DELAYED;
  1588. Timer_CreateTimer( Goal, TF_TIMER_DELAYEDGOAL );
  1589. Goal->enemy = AP;
  1590. Goal->SetThink( &CTFGoal::DelayedResult );
  1591. Goal->SetNextThink( gpGlobals->curtime + Goal->delay_time );
  1592. Goal->weapon = bAddBonuses;
  1593. return;
  1594. }
  1595. // If we have a teamcheck entity, use it instead
  1596. if ( Goal->owned_by_teamcheck != NULL_STRING )
  1597. Goal->owned_by = GetTeamCheckTeam( STRING(Goal->owned_by_teamcheck) );
  1598. Goal->goal_state = TFGS_INACTIVE;
  1599. // if it's a TF goal, removes it's model
  1600. if ( Goal->Classify() == CLASS_TFGOAL || Goal->Classify() == CLASS_TFGOAL_TIMER )
  1601. Goal->AddEffects( EF_NODRAW );
  1602. #ifdef MAP_DEBUG
  1603. Warning("---= Activation =---\n");
  1604. if (AP)
  1605. Warning("Goal: %s\nAP : %s\n", STRING(Goal->edict()->netname), AP->GetPlayerName());
  1606. else
  1607. Warning("Goal: %s\nAP : NONE\n", STRING(Goal->edict()->netname));
  1608. if (bAddBonuses)
  1609. Warning(" adding bonuses\n-=================-\n");
  1610. else
  1611. Warning("NOT adding bonuses\n-=================-\n");
  1612. #endif
  1613. // Make the sound
  1614. if (Goal->noise != NULL_STRING)
  1615. {
  1616. Goal->EmitSound( STRING( Goal->noise ) );
  1617. }
  1618. // Increase scores
  1619. BOOL bDumpScores = FALSE;
  1620. int i;
  1621. for ( i = 0; i <= 3; i++)
  1622. {
  1623. if (Goal->increase_team[i] != 0)
  1624. {
  1625. TeamFortress_TeamIncreaseScore(i + 1, Goal->increase_team[i]);
  1626. bDumpScores = TRUE;
  1627. }
  1628. }
  1629. // Increase the score of the team that owns this entity
  1630. if ( ( Goal->increase_team_owned_by != 0 ) && ( Goal->owned_by != 0 ) )
  1631. {
  1632. TeamFortress_TeamIncreaseScore( Goal->owned_by, Goal->increase_team_owned_by );
  1633. bDumpScores = TRUE;
  1634. }
  1635. // CTF Map support
  1636. if (TFCGameRules()->CTF_Map == TRUE && AP != NULL)
  1637. {
  1638. if (Goal->goal_no == CTF_FLAG1 || Goal->goal_no == CTF_FLAG1 || Goal->goal_no == CTF_DROPOFF1 || Goal->goal_no == CTF_DROPOFF1)
  1639. {
  1640. // Do Messaging
  1641. for ( int i = 1; i <= gpGlobals->maxClients; i++ )
  1642. {
  1643. CTFCPlayer *pPlayer = ToTFCPlayer( UTIL_PlayerByIndex( i ) );
  1644. if ( !pPlayer )
  1645. continue;
  1646. if ( (pPlayer->GetTeamNumber() == 2 && Goal->goal_no == CTF_FLAG1) || (pPlayer->GetTeamNumber() == 1 && Goal->goal_no == CTF_FLAG2) )
  1647. {
  1648. if (pPlayer == AP)
  1649. ClientPrint( pPlayer, HUD_PRINTCENTER, "You got the enemy flag!\n\nReturn to base!");
  1650. else
  1651. ClientPrint( pPlayer, HUD_PRINTCENTER, "Your team GOT the ENEMY flag!!");
  1652. }
  1653. else if (Goal->goal_no == CTF_FLAG1 || Goal->goal_no == CTF_FLAG2)
  1654. {
  1655. ClientPrint( pPlayer, HUD_PRINTCENTER, "Your flag has been TAKEN!!");
  1656. }
  1657. else if ( (pPlayer->GetTeamNumber() == 2 && Goal->goal_no == CTF_DROPOFF1) || (pPlayer->GetTeamNumber() == 1 && Goal->goal_no == CTF_DROPOFF2) )
  1658. {
  1659. if (pPlayer == AP)
  1660. ClientPrint( pPlayer, HUD_PRINTCENTER, "You CAPTURED the FLAG!!");
  1661. else
  1662. ClientPrint( pPlayer, HUD_PRINTCENTER, "Your flag was CAPTURED!!");
  1663. }
  1664. else if (Goal->goal_no == CTF_DROPOFF1 || Goal->goal_no == CTF_DROPOFF2)
  1665. {
  1666. ClientPrint( pPlayer, HUD_PRINTCENTER, "Your team CAPTURED the flag!!");
  1667. }
  1668. }
  1669. const char *pTeamName = "SPECTATOR";
  1670. if ( AP->GetTeamNumber() != 0 )
  1671. {
  1672. CTeam *pTeam = GetGlobalTeam( AP->GetTeamNumber() );
  1673. if ( pTeam )
  1674. pTeamName = pTeam->GetName();
  1675. }
  1676. // Console Prints
  1677. switch(Goal->goal_no)
  1678. {
  1679. case CTF_FLAG1:
  1680. UTIL_ClientPrintAll( HUD_PRINTNOTIFY, UTIL_VarArgs("%s GOT the BLUE flag!", AP->GetPlayerName()) );
  1681. UTIL_LogPrintf("\"%s<%i><%s>\" triggered \"Stole_Blue_Flag\"\n",
  1682. AP->GetPlayerName(),
  1683. AP->GetUserID(),
  1684. pTeamName );
  1685. AP->m_Shared.AddItemFlags( IT_KEY1 );
  1686. break;
  1687. case CTF_FLAG2:
  1688. UTIL_ClientPrintAll( HUD_PRINTNOTIFY, UTIL_VarArgs("%s GOT the RED flag!", AP->GetPlayerName()) );
  1689. UTIL_LogPrintf("\"%s<%i><%s>\" triggered \"Stole_Red_Flag\"\n",
  1690. AP->GetPlayerName(),
  1691. AP->GetUserID(),
  1692. pTeamName );
  1693. AP->m_Shared.AddItemFlags( IT_KEY2 );
  1694. break;
  1695. case CTF_DROPOFF1:
  1696. UTIL_ClientPrintAll( HUD_PRINTNOTIFY, UTIL_VarArgs("%s CAPTURED the RED flag!", AP->GetPlayerName()) );
  1697. UTIL_LogPrintf("\"%s<%i><%s>\" triggered \"Captured_Red_Flag\"\n",
  1698. AP->GetPlayerName(),
  1699. AP->GetUserID(),
  1700. pTeamName );
  1701. AP->m_Shared.RemoveItemFlags( IT_KEY2 );
  1702. break;
  1703. case CTF_DROPOFF2:
  1704. UTIL_ClientPrintAll( HUD_PRINTNOTIFY, UTIL_VarArgs("%s CAPTURED the BLUE flag!", AP->GetPlayerName()) );
  1705. UTIL_LogPrintf("\"%s<%i><%s>\" triggered \"Captured_Blue_Flag\"\n",
  1706. AP->GetPlayerName(),
  1707. AP->GetUserID(),
  1708. pTeamName );
  1709. AP->m_Shared.RemoveItemFlags( IT_KEY1 );
  1710. break;
  1711. default:
  1712. break;
  1713. }
  1714. }
  1715. }
  1716. // Do Spawnpoint work before cycling players, so Forced respawn players work correctly.
  1717. if (Goal->remove_spawngroup != 0)
  1718. {
  1719. // Find all goals
  1720. //TFCTODO: I think FindEntityByClassname will do the same thing.
  1721. //CBaseEntity *pEnt = UTIL_FindEntityByString( NULL, "netname", "info_player_teamspawn" );
  1722. CBaseEntity *pEnt = gEntList.FindEntityByClassname( NULL, "info_player_teamspawn" );
  1723. while ( pEnt )
  1724. {
  1725. CTFSpawn *pSpawn = dynamic_cast<CTFSpawn*>( pEnt );
  1726. if ( pSpawn )
  1727. {
  1728. if ( pSpawn->group_no == Goal->remove_spawngroup)
  1729. InactivateSpawn(pSpawn);
  1730. }
  1731. pEnt = gEntList.FindEntityByClassname( pEnt, "info_player_teamspawn" );
  1732. }
  1733. }
  1734. if (Goal->restore_spawngroup != 0)
  1735. {
  1736. // Find all goals
  1737. //TFCTODO: I think FindEntityByClassname will do the same thing.
  1738. //CBaseEntity *pEnt = UTIL_FindEntityByString( NULL, "netname", "info_player_teamspawn" );
  1739. CBaseEntity *pEnt = gEntList.FindEntityByClassname( NULL, "info_player_teamspawn" );
  1740. while ( pEnt )
  1741. {
  1742. CTFSpawn *pSpawn = dynamic_cast<CTFSpawn*>( pEnt );
  1743. if ( pSpawn )
  1744. {
  1745. if (pSpawn->group_no == Goal->restore_spawngroup)
  1746. ActivateSpawn(pSpawn);
  1747. }
  1748. pEnt = gEntList.FindEntityByClassname( pEnt, "info_player_teamspawn" );
  1749. }
  1750. }
  1751. // Go through all the players and do any results
  1752. if ( Goal->broadcast != NULL_STRING && TFCGameRules()->CTF_Map == FALSE )
  1753. {
  1754. UTIL_LogPrintf("World triggered \"%s\"\n", STRING(Goal->broadcast) );
  1755. }
  1756. if ( Goal->netname_broadcast != NULL_STRING && TFCGameRules()->CTF_Map == FALSE && AP != NULL )
  1757. {
  1758. UTIL_LogPrintf("\"%s<%i><%s>\" triggered \"%s\"\n",
  1759. AP->GetPlayerName(),
  1760. AP->GetUserID(),
  1761. ( AP->GetTeamNumber() != 0 ) ? GetTeamName( AP->GetTeamNumber() ) : "SPECTATOR",
  1762. STRING(Goal->netname_broadcast) );
  1763. }
  1764. BOOL bGotOne = FALSE;
  1765. for ( i = 1; i <= gpGlobals->maxClients; i++ )
  1766. {
  1767. CTFCPlayer *pPlayer = ToTFCPlayer( UTIL_PlayerByIndex( i ) );
  1768. if ( !pPlayer )
  1769. continue;
  1770. // Centerprinting
  1771. if (Goal->broadcast != NULL_STRING && TFCGameRules()->CTF_Map == FALSE)
  1772. UTIL_ShowMessage( STRING(Goal->broadcast), pPlayer );
  1773. if (Goal->netname_broadcast != NULL_STRING && TFCGameRules()->CTF_Map == FALSE && AP != NULL)
  1774. ClientPrint( pPlayer, HUD_PRINTNOTIFY, STRING(Goal->netname_broadcast), AP->GetPlayerName() );
  1775. // Old printing
  1776. if (Goal->org_broadcast != NULL_STRING && TFCGameRules()->CTF_Map == FALSE)
  1777. ClientPrint( pPlayer, HUD_PRINTCENTER, STRING(Goal->org_broadcast) );
  1778. // VOX
  1779. if (Goal->speak != NULL_STRING)
  1780. pPlayer->ClientHearVox( STRING(Goal->speak) );
  1781. if (AP == pPlayer)
  1782. {
  1783. // Spawnpoints handle their own printing elsewhere
  1784. if (Goal->message != NULL_STRING && Goal->Classify() != CLASS_TFSPAWN)
  1785. UTIL_ShowMessage( STRING(Goal->message), pPlayer );
  1786. if (Goal->org_message != NULL_STRING && Goal->Classify() != CLASS_TFSPAWN)
  1787. ClientPrint( pPlayer, HUD_PRINTCENTER, STRING(Goal->org_message) );
  1788. // VOX
  1789. if (Goal->AP_speak != NULL_STRING)
  1790. pPlayer->ClientHearVox( STRING(Goal->AP_speak) );
  1791. }
  1792. else if ( (AP != NULL) && (AP->GetTeamNumber() == pPlayer->GetTeamNumber()) )
  1793. {
  1794. // Text Printing
  1795. if (Goal->owners_team_broadcast != NULL_STRING && pPlayer->GetTeamNumber() == Goal->owned_by)
  1796. UTIL_ShowMessage( STRING(Goal->owners_team_broadcast), pPlayer );
  1797. else if (Goal->non_owners_team_broadcast != NULL_STRING && pPlayer->GetTeamNumber() != Goal->owned_by)
  1798. UTIL_ShowMessage( STRING(Goal->non_owners_team_broadcast), pPlayer );
  1799. else if (Goal->team_broadcast!= NULL_STRING )
  1800. UTIL_ShowMessage( STRING(Goal->team_broadcast), pPlayer );
  1801. // Old Text Printing
  1802. if (Goal->org_owners_team_broadcast != NULL_STRING && pPlayer->GetTeamNumber() == Goal->owned_by)
  1803. ClientPrint( pPlayer, HUD_PRINTCENTER, STRING(Goal->org_owners_team_broadcast) );
  1804. else if (Goal->org_non_owners_team_broadcast != NULL_STRING && pPlayer->GetTeamNumber() != Goal->owned_by)
  1805. ClientPrint( pPlayer, HUD_PRINTCENTER, STRING(Goal->org_non_owners_team_broadcast) );
  1806. else if (Goal->org_team_broadcast!= NULL_STRING )
  1807. ClientPrint( pPlayer, HUD_PRINTCENTER, STRING(Goal->org_team_broadcast) );
  1808. // VOX
  1809. if (Goal->owners_team_speak != NULL_STRING && pPlayer->GetTeamNumber() == Goal->owned_by)
  1810. pPlayer->ClientHearVox( STRING(Goal->owners_team_speak) );
  1811. else if (Goal->non_owners_team_speak != NULL_STRING && pPlayer->GetTeamNumber() != Goal->owned_by)
  1812. pPlayer->ClientHearVox( STRING(Goal->non_owners_team_speak) );
  1813. else if (Goal->team_speak!= NULL_STRING )
  1814. pPlayer->ClientHearVox( STRING(Goal->team_speak) );
  1815. if (Goal->netname_owners_team_broadcast != NULL_STRING && pPlayer->GetTeamNumber() == Goal->owned_by)
  1816. ClientPrint( pPlayer, HUD_PRINTNOTIFY, STRING(Goal->netname_owners_team_broadcast), AP->GetPlayerName() );
  1817. else if (Goal->netname_team_broadcast!= NULL_STRING )
  1818. ClientPrint( pPlayer, HUD_PRINTNOTIFY, STRING(Goal->netname_team_broadcast), AP->GetPlayerName() );
  1819. }
  1820. else
  1821. {
  1822. // Text Printing
  1823. if (Goal->owners_team_broadcast != NULL_STRING && pPlayer->GetTeamNumber() == Goal->owned_by)
  1824. UTIL_ShowMessage( STRING(Goal->owners_team_broadcast), pPlayer );
  1825. else if (Goal->non_owners_team_broadcast != NULL_STRING && pPlayer->GetTeamNumber() != Goal->owned_by)
  1826. UTIL_ShowMessage( STRING(Goal->non_owners_team_broadcast), pPlayer );
  1827. else if (Goal->non_team_broadcast != NULL_STRING )
  1828. UTIL_ShowMessage( STRING(Goal->non_team_broadcast), pPlayer );
  1829. // Old Text Printing
  1830. if (Goal->org_owners_team_broadcast != NULL_STRING && pPlayer->GetTeamNumber() == Goal->owned_by)
  1831. ClientPrint( pPlayer, HUD_PRINTCENTER, STRING(Goal->org_owners_team_broadcast) );
  1832. else if (Goal->org_non_owners_team_broadcast != NULL_STRING && pPlayer->GetTeamNumber() != Goal->owned_by)
  1833. ClientPrint( pPlayer, HUD_PRINTCENTER, STRING(Goal->org_non_owners_team_broadcast) );
  1834. else if (Goal->org_non_team_broadcast!= NULL_STRING )
  1835. ClientPrint( pPlayer, HUD_PRINTCENTER, STRING(Goal->org_non_team_broadcast) );
  1836. // VOX
  1837. if (Goal->owners_team_speak != NULL_STRING && pPlayer->GetTeamNumber() == Goal->owned_by)
  1838. pPlayer->ClientHearVox( STRING(Goal->owners_team_speak) );
  1839. else if (Goal->non_owners_team_speak != NULL_STRING && pPlayer->GetTeamNumber() != Goal->owned_by)
  1840. pPlayer->ClientHearVox( STRING(Goal->non_owners_team_speak) );
  1841. else if (Goal->non_team_speak != NULL_STRING )
  1842. pPlayer->ClientHearVox( STRING(Goal->non_team_speak) );
  1843. if (Goal->netname_owners_team_broadcast != NULL_STRING && pPlayer->GetTeamNumber() == Goal->owned_by && AP != NULL)
  1844. ClientPrint( pPlayer, HUD_PRINTNOTIFY, STRING(Goal->netname_owners_team_broadcast), AP->GetPlayerName() );
  1845. else if (Goal->netname_non_team_broadcast != NULL_STRING && AP != NULL)
  1846. ClientPrint( pPlayer, HUD_PRINTNOTIFY, STRING(Goal->netname_non_team_broadcast), AP->GetPlayerName() );
  1847. }
  1848. if (IsAffectedBy(Goal, pPlayer, AP))
  1849. {
  1850. // If its a Timer Goal, see if it needs to check Criteria again
  1851. if (Goal->search_time != 0 && Goal->goal_effects & TFGE_TIMER_CHECK_AP)
  1852. {
  1853. if (APMeetsCriteria(Goal, pPlayer))
  1854. {
  1855. Apply_Results(Goal, (CTFCPlayer*)pPlayer, AP, bAddBonuses);
  1856. bGotOne = TRUE;
  1857. }
  1858. }
  1859. else
  1860. {
  1861. Apply_Results(Goal, (CTFCPlayer*)pPlayer, AP, bAddBonuses);
  1862. bGotOne = TRUE;
  1863. }
  1864. }
  1865. }
  1866. #ifdef MAP_DEBUG
  1867. if (bGotOne == FALSE)
  1868. Warning("NO PLAYERS AFFECTED\n");
  1869. #endif
  1870. // Goal is now active
  1871. // Items are not set to active. They handle their modes.
  1872. if ( Goal->Classify() == CLASS_TFGOAL_TIMER || Goal->Classify() == CLASS_TFGOAL )
  1873. Goal->goal_state = TFGS_ACTIVE;
  1874. // EndGame checking
  1875. if (Goal->goal_result & TFGR_ENDGAME)
  1876. {
  1877. // Display Long TeamScores to everyone
  1878. TeamFortress_TeamShowScores(TRUE, NULL);
  1879. if ( g_pGameRules->IsMultiplayer() )
  1880. TFCGameRules()->TFCGoToIntermission();
  1881. return;
  1882. }
  1883. // EndRound checking
  1884. if (Goal->m_flEndRoundTime)
  1885. EndRound( Goal );
  1886. // Do Goal Group checking
  1887. DoGroupWork(Goal, AP);
  1888. // Do Goal checking
  1889. DoGoalWork(Goal, AP);
  1890. // Do Quake Trigger actions (Standard entities use SUB_UseTargets())
  1891. if ( Goal->Classify() == CLASS_TFGOAL_TIMER || Goal->Classify() == CLASS_TFGOAL_ITEM || Goal->Classify() == CLASS_TFGOAL || Goal->Classify() == CLASS_TFSPAWN || Goal->do_triggerwork )
  1892. DoTriggerWork(Goal, AP);
  1893. // Setup for Respawn
  1894. // Items, Triggers, and Spawnpoints do their own respawn work
  1895. if ( Goal->Classify() == CLASS_TFGOAL || Goal->Classify() == CLASS_TFGOAL_TIMER )
  1896. SetupRespawn(Goal);
  1897. }
  1898. //=========================================================================
  1899. // Check to see if the Goal should Activate. Handle Else Goals if not.
  1900. // If it does activate, Do the Results. Return true if the Goal activated.
  1901. bool ActivateDoResults(CTFGoal *Goal, CTFCPlayer *AP, CTFGoal *ActivatingGoal)
  1902. {
  1903. // Check Goal activation. This func handles Else Goals.
  1904. if ( !ActivationSucceeded(Goal, AP, ActivatingGoal) )
  1905. return false;
  1906. // Do the Results.
  1907. if (ActivatingGoal == Goal || Goal->m_bAddBonuses == true)
  1908. DoResults(Goal, AP, true);
  1909. else if (ActivatingGoal != NULL)
  1910. DoResults(Goal, AP, (ActivatingGoal->goal_result & TFGR_ADD_BONUSES));
  1911. else
  1912. DoResults(Goal, AP, 0);
  1913. return true;
  1914. }
  1915. //=========================================================================
  1916. // Return true if the Goal should activate, and handle Else Goals
  1917. bool ActivationSucceeded(CTFGoal *Goal, CTFCPlayer *AP, CTFGoal *ActivatingGoal)
  1918. {
  1919. // Can't activate during PreMatch time, except for timers
  1920. if ( (TFCGameRules()->IsInPreMatch()) && (Goal->Classify() != CLASS_TFGOAL_TIMER) )
  1921. return false;
  1922. // If activation fails, try and activate the Else Goal
  1923. if ( !ShouldActivate(Goal, AP) )
  1924. {
  1925. // If an else goal should be activated, activate it
  1926. if (Goal->else_goal != 0)
  1927. {
  1928. MDEBUG( Warning(" Else Goal.\n") );
  1929. CTFGoal *pElseGoal = Findgoal(Goal->else_goal);
  1930. if (pElseGoal)
  1931. ActivateDoResults(pElseGoal, AP, Goal);
  1932. }
  1933. return false;
  1934. }
  1935. return true;
  1936. }
  1937. // ---------------------------------------------------------------------------------------- //
  1938. // CTFBaseItem existence.
  1939. // ---------------------------------------------------------------------------------------- //
  1940. //===========================================
  1941. // Check whether this entity should exist at this skill
  1942. bool CTFBaseItem::CheckExistence()
  1943. {
  1944. if (ex_skill_min == -1 && g_iSkillLevel < 0)
  1945. return FALSE;
  1946. else if (ex_skill_max == -1 && g_iSkillLevel > 0)
  1947. return FALSE;
  1948. if ( (ex_skill_min != 0) && (ex_skill_min != -1) && (g_iSkillLevel < ex_skill_min) )
  1949. return FALSE;
  1950. else if ( (ex_skill_max != 0) && (ex_skill_max != -1) && (g_iSkillLevel > ex_skill_max) )
  1951. return FALSE;
  1952. return TRUE;
  1953. }
  1954. // ---------------------------------------------------------------------------------------- //
  1955. // CTFGoal implementation.
  1956. // ---------------------------------------------------------------------------------------- //
  1957. LINK_ENTITY_TO_CLASS(info_tfgoal, CTFGoal);
  1958. BEGIN_DATADESC( CTFGoal )
  1959. DEFINE_FUNCTION( PlaceGoal ),
  1960. DEFINE_FUNCTION( DelayedResult )
  1961. END_DATADESC()
  1962. //===========================================
  1963. // TF Goal spawn
  1964. void CTFGoal::Spawn( void )
  1965. {
  1966. if (CheckExistence() == false)
  1967. {
  1968. UTIL_Remove(this);
  1969. return;
  1970. }
  1971. // Graphic
  1972. string_t modelName = GetModelName();
  1973. if ( modelName != NULL_STRING )
  1974. {
  1975. // Brush Models need to be invisible
  1976. const char *pModel = STRING( modelName );
  1977. if (pModel[0] == '*')
  1978. AddEffects( EF_NODRAW );
  1979. }
  1980. #ifdef TFCTODO
  1981. // Activation sound
  1982. if (pev->noise)
  1983. PRECACHE_SOUND( (char*)STRING(pev->noise) );
  1984. // For the powerups
  1985. PRECACHE_SOUND("items/protect.wav");
  1986. PRECACHE_SOUND("items/protect2.wav");
  1987. PRECACHE_SOUND("items/protect3.wav");
  1988. PRECACHE_SOUND("FVox/HEV_logon.wav");
  1989. PRECACHE_SOUND("FVox/hev_shutdown.wav");
  1990. PRECACHE_SOUND("items/inv1.wav");
  1991. PRECACHE_SOUND("items/inv2.wav");
  1992. PRECACHE_SOUND("items/inv3.wav");
  1993. PRECACHE_SOUND("items/damage.wav");
  1994. PRECACHE_SOUND("items/damage2.wav");
  1995. PRECACHE_SOUND("items/damage3.wav");
  1996. #endif
  1997. // Set initial states
  1998. AddSolidFlags( FSOLID_TRIGGER );
  1999. if (goal_state == 0)
  2000. goal_state = TFGS_INACTIVE;
  2001. // Set Size
  2002. if (goal_min != vec3_origin && goal_max != vec3_origin)
  2003. UTIL_SetSize( this, goal_min, goal_max );
  2004. StartGoal();
  2005. }
  2006. //=========================================================================
  2007. // Respawn the goal
  2008. void CTFGoal::DoRespawn()
  2009. {
  2010. RestoreGoal(this);
  2011. InactivateGoal(this);
  2012. }
  2013. //=========================================================================
  2014. // Timer goal tick
  2015. void CTFGoal::tfgoal_timer_tick()
  2016. {
  2017. // Check criteria
  2018. if (goal_state != TFGS_REMOVED)
  2019. {
  2020. #ifdef MAP_DEBUG
  2021. Warning("==========================\n");
  2022. Warning("Timer Tick for: %s\nChecking Criteria...", GetEntityName().ToCStr());
  2023. #endif
  2024. // Timers don't fire during prematch.
  2025. // Instead, they setup to fire the correct amount of time past the prematch
  2026. if ( TFCGameRules()->IsInPreMatch() )
  2027. {
  2028. MDEBUG( Warning("\n PREMATCH IS ON. DELAYING UNTIL AFTER PREMATCH.\n") );
  2029. SetThink( &CTFGoal::tfgoal_timer_tick );
  2030. SetNextThink( TFCGameRules()->GetPreMatchEndTime() + search_time );
  2031. return;
  2032. }
  2033. if (APMeetsCriteria(this, NULL))
  2034. {
  2035. DoResults(this, NULL, TRUE);
  2036. }
  2037. else
  2038. {
  2039. MDEBUG( Warning("\n") );
  2040. SetThink( &CTFGoal::tfgoal_timer_tick );
  2041. SetNextThink( gpGlobals->curtime + search_time );
  2042. }
  2043. }
  2044. }
  2045. //=========================================================================
  2046. // Use (Triggered) function for Goals
  2047. void CTFGoal::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
  2048. {
  2049. // If the Activator isn't a player, pretend there isn't an activator
  2050. if (pActivator && !pActivator->IsPlayer())
  2051. {
  2052. pActivator = NULL;
  2053. }
  2054. CTFGoal *pCallerGoal = dynamic_cast<CTFGoal*>( pCaller );
  2055. if ( !pCallerGoal )
  2056. {
  2057. // Need to rethink some stuff if this can be called by entities that aren't CTFGoals.
  2058. Assert( false );
  2059. return;
  2060. }
  2061. // Goals are only activatable by players
  2062. if (!pActivator || pActivator->IsPlayer())
  2063. {
  2064. // Force it to add bonuses
  2065. m_bAddBonuses = true;
  2066. ActivateDoResults(this, (CTFCPlayer*)pActivator, pCallerGoal);
  2067. }
  2068. }
  2069. //===========================================
  2070. // Make Goal's more easy to touch
  2071. void CTFGoal::SetObjectCollisionBox( void )
  2072. {
  2073. const char *pModel = STRING( GetModelName() );
  2074. if (pModel[0] != '*')
  2075. {
  2076. Vector vMins = WorldAlignMins() + Vector(-24, -24, 0);
  2077. Vector vMaxs = WorldAlignMaxs() + Vector(24, 24, 16);
  2078. SetCollisionBounds( vMins, vMaxs );
  2079. }
  2080. else
  2081. {
  2082. // Do we even need to do this? The bmodel should be setup correctly at this point anyway.
  2083. #ifdef TFCTODO
  2084. // Ripped from ::SetObjectCollisionBox
  2085. float max, v;
  2086. int i;
  2087. max = 0;
  2088. for (i=0 ; i<3 ; i++)
  2089. {
  2090. v = fabs( (( float * )pev->mins )[i]);
  2091. if (v > max)
  2092. max = v;
  2093. v = fabs( (( float * )pev->maxs )[i]);
  2094. if (v > max)
  2095. max = v;
  2096. }
  2097. for (i=0 ; i<3 ; i++)
  2098. {
  2099. ((float *)pev->absmin)[i] = (( float * )GetAbsOrigin())[i] - max;
  2100. ((float *)pev->absmax)[i] = (( float * )GetAbsOrigin())[i] + max;
  2101. }
  2102. pev->absmin.x -= 1;
  2103. pev->absmin.y -= 1;
  2104. pev->absmin.z -= 1;
  2105. pev->absmax.x += 1;
  2106. pev->absmax.y += 1;
  2107. pev->absmax.z += 1;
  2108. #endif
  2109. }
  2110. }
  2111. //===========================================
  2112. // Start the Goal
  2113. void CTFGoal::StartGoal( void )
  2114. {
  2115. m_bAddBonuses = false;
  2116. SetThink( &CTFGoal::PlaceGoal );
  2117. SetNextThink( gpGlobals->curtime + 0.2 ); // goals start after other solids
  2118. if (goal_state == TFGS_REMOVED)
  2119. RemoveGoal(this);
  2120. };
  2121. //===========================================
  2122. // Sets up the Goal's first thoughts
  2123. void CTFGoal::PlaceGoal( void )
  2124. {
  2125. if ( FClassnameIs(this, "info_tfgoal_timer") )
  2126. {
  2127. // Set up the next Timer Tick
  2128. SetThink( &CTFGoal::tfgoal_timer_tick );
  2129. SetNextThink( gpGlobals->curtime + search_time );
  2130. }
  2131. else
  2132. {
  2133. // Only give touch functions to goals that can be activated by touch
  2134. if (goal_activation & TFGA_TOUCH)
  2135. SetTouch( &CTFGoal::tfgoal_touch );
  2136. }
  2137. // So searches for this goal work later on
  2138. Assert( stricmp( GetClassname(), "info_tfgoal" ) == 0 );
  2139. // Drop to ground
  2140. if (goal_activation & TFGA_DROPTOGROUND)
  2141. {
  2142. // Is this right?
  2143. #ifdef TFCTODO
  2144. SetMoveType( MOVETYPE_TOSS );
  2145. #else
  2146. SetMoveType( MOVETYPE_FLYGRAVITY );
  2147. #endif
  2148. SetAbsOrigin( GetAbsOrigin() + Vector( 0, 0, 6 ) );
  2149. if ( UTIL_DropToFloor(this, MASK_SOLID) == 0)
  2150. {
  2151. Error("TF Goal %s fell out of level at %f,%f,%f", GetEntityName(), GetAbsOrigin().x, GetAbsOrigin().y, GetAbsOrigin().z);
  2152. UTIL_Remove( this );
  2153. return;
  2154. }
  2155. }
  2156. SetMoveType( MOVETYPE_NONE );
  2157. SetAbsVelocity( Vector( 0, 0, 0 ) );
  2158. oldorigin = GetAbsOrigin(); // So we can return it later
  2159. }
  2160. // Touch function for Goals
  2161. void CTFGoal::tfgoal_touch( CBaseEntity *pOther )
  2162. {
  2163. // Can't touch during PreMatch time
  2164. if ( TFCGameRules()->IsInPreMatch() )
  2165. return;
  2166. // If it is not activated in by the player's touch, return
  2167. if (!(goal_activation & TFGA_TOUCH))
  2168. return;
  2169. // Only activatable by a player
  2170. if (!pOther->IsPlayer())
  2171. return;
  2172. if ( pOther->IsAlive() == FALSE )
  2173. return;
  2174. // If it's already active, don't bother
  2175. if (goal_state == TFGS_ACTIVE)
  2176. {
  2177. MDEBUG( Warning("Goal already active. aborting touch.\n") );
  2178. return;
  2179. }
  2180. // CTF Hack to make sure the key is in place. Like the rest of the CTF_Map stuff,
  2181. // it's not needed... the base scripting could handle it all.
  2182. if (TFCGameRules()->CTF_Map)
  2183. {
  2184. if ((goal_no == CTF_DROPOFF1) && (pOther->GetTeamNumber() == 1))
  2185. {
  2186. CTFGoalItem *pFlag = Finditem(CTF_FLAG1);
  2187. if ((pFlag->goal_state == TFGS_ACTIVE) || (pFlag->GetAbsOrigin() != pFlag->oldorigin))
  2188. return;
  2189. }
  2190. if ((goal_no == CTF_DROPOFF2) && (pOther->GetTeamNumber() == 2))
  2191. {
  2192. CTFGoalItem *pFlag = Finditem(CTF_FLAG2);
  2193. if ((pFlag->goal_state == TFGS_ACTIVE) || (pFlag->GetAbsOrigin() != pFlag->oldorigin))
  2194. return;
  2195. }
  2196. }
  2197. ActivateDoResults(this, ToTFCPlayer( pOther ), this);
  2198. }
  2199. //=========================================================================
  2200. // Handles Delayed Activation of Goals
  2201. void CTFGoal::DelayedResult()
  2202. {
  2203. CBaseEntity *pEnemy = enemy;
  2204. if (goal_state == TFGS_DELAYED)
  2205. DoResults(this, ToTFCPlayer( pEnemy ), weapon);
  2206. }
  2207. // ---------------------------------------------------------------------------------------- //
  2208. // CTFGoalItem implementation.
  2209. // ---------------------------------------------------------------------------------------- //
  2210. LINK_ENTITY_TO_CLASS(item_tfgoal, CTFGoalItem);
  2211. //=========================================================================
  2212. // Spawn a goalitem entity
  2213. void CTFGoalItem::Spawn( void )
  2214. {
  2215. if (CheckExistence() == false)
  2216. {
  2217. UTIL_Remove(this);
  2218. return;
  2219. }
  2220. // Set this in case they used abbreviations
  2221. Assert( stricmp( GetClassname(), "item_tfgoal" ) == 0 );
  2222. // Graphic
  2223. if ( GetModelName() != NULL_STRING )
  2224. {
  2225. // Setup animations
  2226. SetSequence( LookupSequence( "not_carried" ) );
  2227. if ( GetSequence() != -1 )
  2228. {
  2229. ResetSequenceInfo();
  2230. m_flCycle = 0;
  2231. }
  2232. }
  2233. #ifdef TFCTODO
  2234. // Respawn sound
  2235. PRECACHE_SOUND("items/itembk2.wav");
  2236. // Activation sound
  2237. if (pev->noise)
  2238. PRECACHE_SOUND( (char*)STRING(pev->noise) );
  2239. if (!(pev->netname))
  2240. pev->netname = MAKE_STRING("goalitem");
  2241. #endif
  2242. if (goal_state == 0)
  2243. goal_state = TFGS_INACTIVE;
  2244. // Set initial solidity
  2245. if (goal_activation & TFGI_SOLID)
  2246. {
  2247. SetSolid( SOLID_BBOX );
  2248. // Solid goalitems need a bbox
  2249. if (goal_min == vec3_origin)
  2250. goal_min = Vector(-16, -16, -24);
  2251. if (goal_max == vec3_origin)
  2252. goal_max = Vector(16, 16, 32);
  2253. }
  2254. else
  2255. {
  2256. SetSolidFlags( FSOLID_TRIGGER );
  2257. }
  2258. if (drop_time <= 0)
  2259. drop_time = 60;
  2260. // Set Size
  2261. UTIL_SetSize(this, goal_min, goal_max);
  2262. SetTouch( &CTFGoalItem::item_tfgoal_touch );
  2263. StartItem();
  2264. };
  2265. //=========================================================================
  2266. // Start the Goal Item
  2267. void CTFGoalItem::StartItem( void )
  2268. {
  2269. SetThink( &CTFGoalItem::PlaceItem );
  2270. SetNextThink( gpGlobals->curtime + 0.2 ); // items start after other solids
  2271. if (goal_state == TFGS_REMOVED)
  2272. RemoveGoal(this);
  2273. }
  2274. //===========================================
  2275. // Place the Goal Item
  2276. void CTFGoalItem::PlaceItem( void )
  2277. {
  2278. static int item_list_bit = 1; // used to determine what the bit of each new GoalItem will be.
  2279. SetAbsVelocity( vec3_origin );
  2280. // Drop to ground
  2281. if (goal_activation & TFGA_DROPTOGROUND)
  2282. {
  2283. #ifdef TFCTODO
  2284. pev->movetype = MOVETYPE_TOSS;
  2285. #else
  2286. SetMoveType( MOVETYPE_FLYGRAVITY );
  2287. #endif
  2288. SetAbsOrigin( GetAbsOrigin() + Vector( 0, 0, 6 ) );
  2289. if ( UTIL_DropToFloor( this, MASK_SOLID ) == 0)
  2290. {
  2291. Error("TF GoalItem %s fell out of level at %f,%f,%f", STRING( GetEntityName() ), GetAbsOrigin().x, GetAbsOrigin().y, GetAbsOrigin().z);
  2292. UTIL_Remove( this );
  2293. return;
  2294. }
  2295. }
  2296. SetMoveType( MOVETYPE_NONE );
  2297. oldorigin = GetAbsOrigin(); // So we can return it later
  2298. if (goal_activation & TFGI_ITEMGLOWS)
  2299. {
  2300. m_nRenderFX = kRenderFxGlowShell;
  2301. // If we have a teamcheck entity, use it instead
  2302. if ( owned_by_teamcheck != NULL_STRING )
  2303. owned_by = GetTeamCheckTeam( STRING(owned_by_teamcheck) );
  2304. if (owned_by > 0 && owned_by <= 4)
  2305. m_clrRender = Vector255ToRGBColor( rgbcolors[owned_by] );
  2306. else
  2307. m_clrRender = Vector255ToRGBColor( rgbcolors[0] );
  2308. SetRenderColorA( 100 ); // Shell size
  2309. }
  2310. // Set the item bit
  2311. item_list = item_list_bit;
  2312. item_list_bit *= 2;
  2313. }
  2314. // Touch function for the goalitem entity
  2315. void CTFGoalItem::item_tfgoal_touch( CBaseEntity *pOther )
  2316. {
  2317. if (!pOther->IsPlayer())
  2318. return;
  2319. if ( pOther->IsAlive() == FALSE )
  2320. return;
  2321. // Can't touch during PreMatch time
  2322. if ( TFCGameRules()->IsInPreMatch() )
  2323. return;
  2324. // Hack to prevent feigning spies from repicking up flags
  2325. CTFCPlayer *pPlayer = dynamic_cast<CTFCPlayer*>( pOther );
  2326. if (pPlayer->is_feigning)
  2327. return;
  2328. // only let players have one replacement_model goal item at a time
  2329. if ( replacement_model != NULL_STRING )
  2330. {
  2331. if ( pPlayer->replacement_model != NULL_STRING )
  2332. return;
  2333. }
  2334. // Prevent the dropping player from picking it up for longer
  2335. if (enemy.Get() && m_flDroppedAt != 0)
  2336. {
  2337. if ( (enemy == pOther) && m_flDroppedAt + 5 > gpGlobals->curtime )
  2338. return;
  2339. }
  2340. m_flDroppedAt = 0;
  2341. ASSERT( pOther != GetOwnerEntity() ); // There is no way in hell this should ever happen, and yet it still does.
  2342. // Prevent picking up flags through thin walls
  2343. trace_t tr;
  2344. UTIL_TraceLine ( WorldSpaceCenter(), pOther->WorldSpaceCenter(), MASK_SOLID_BRUSHONLY, this, COLLISION_GROUP_NONE, &tr );
  2345. if ( tr.fraction != 1.0 && tr.m_pEnt != pOther )
  2346. return;
  2347. // CTF Hack to return your key.
  2348. // Should use the builtin support now.
  2349. if (TFCGameRules()->CTF_Map == TRUE)
  2350. {
  2351. // Flag not at home?
  2352. if (GetAbsOrigin() != oldorigin)
  2353. {
  2354. if (GetTeamNumber() == 1)
  2355. {
  2356. if (goal_no == CTF_FLAG1)
  2357. {
  2358. UTIL_ClientPrintAll( HUD_PRINTNOTIFY, UTIL_VarArgs("%s RETURNED the BLUE flag!", pPlayer->GetPlayerName()) );
  2359. UTIL_LogPrintf("\"%s<%i><%s>\" triggered \"Returned_Blue_Flag\"\n",
  2360. pPlayer->GetPlayerName(),
  2361. pPlayer->GetUserID(),
  2362. GetTeamName( pOther->GetTeamNumber() ) );
  2363. }
  2364. else
  2365. {
  2366. UTIL_ClientPrintAll( HUD_PRINTNOTIFY, UTIL_VarArgs("%s RETURNED the RED flag!", pPlayer->GetPlayerName()) );
  2367. UTIL_LogPrintf("\"%s<%i><%s>\" triggered \"Returned_Red_Flag\"\n",
  2368. pPlayer->GetPlayerName(),
  2369. pPlayer->GetUserID(),
  2370. GetTeamName( pOther->GetTeamNumber() ) );
  2371. }
  2372. for ( int i = 1; i <= gpGlobals->maxClients; i++ )
  2373. {
  2374. CBasePlayer *pPlayer = UTIL_PlayerByIndex( i );
  2375. if ( !pPlayer )
  2376. continue;
  2377. if (pPlayer->GetTeamNumber() == 1 && goal_no == CTF_FLAG1)
  2378. ClientPrint( pPlayer, HUD_PRINTCENTER, "Your flag was RETURNED!!\n");
  2379. else if (pPlayer->GetTeamNumber() != 1 && goal_no == CTF_FLAG1)
  2380. ClientPrint( pPlayer, HUD_PRINTCENTER, "The ENEMY flag was RETURNED!!\n");
  2381. else if (pPlayer->GetTeamNumber() == 2 && goal_no == CTF_FLAG2)
  2382. ClientPrint( pPlayer, HUD_PRINTCENTER, "Your flag was RETURNED!!\n");
  2383. else if (pPlayer->GetTeamNumber() == 2 && goal_no == CTF_FLAG1)
  2384. ClientPrint( pPlayer, HUD_PRINTCENTER, "The ENEMY flag was RETURNED!!\n");
  2385. }
  2386. goal_state = TFGS_INACTIVE;
  2387. SetSolidFlags( FSOLID_TRIGGER );
  2388. SetTouch( &CTFGoalItem::item_tfgoal_touch );
  2389. SetAbsOrigin( oldorigin );
  2390. EmitSound( "GoalItem.Touch" );
  2391. //EMIT_SOUND_DYN( ENT(pev), CHAN_WEAPON, "items/itembk2.wav", 1, ATTN_NORM, 0, 150 );
  2392. return;
  2393. }
  2394. }
  2395. else
  2396. {
  2397. // Ignore touches to our own flag when it's at home
  2398. if (pOther->GetTeamNumber() == 1 && goal_no == CTF_FLAG1)
  2399. return;
  2400. if (pOther->GetTeamNumber() == 2 && goal_no == CTF_FLAG2)
  2401. return;
  2402. }
  2403. }
  2404. // Activate. Handles Else Goals if it fails.
  2405. if ( ActivationSucceeded( this, ToTFCPlayer( pOther ), NULL) )
  2406. {
  2407. // Give it to the player
  2408. tfgoalitem_GiveToPlayer(this, ToTFCPlayer( pOther ), this);
  2409. // It may have killed the player, so check:
  2410. if (pOther->GetHealth() > 0)
  2411. goal_state = TFGS_ACTIVE;
  2412. }
  2413. }
  2414. //=========================================================================
  2415. // Throw the item into the air at the specified position
  2416. void CTFGoalItem::DoDrop( Vector vecOrigin )
  2417. {
  2418. SetAbsOrigin( vecOrigin );
  2419. StopFollowingEntity();
  2420. SetMoveType( MOVETYPE_FLYGRAVITY );
  2421. // Just drop it vertically first time to prevent it falling through walls too often
  2422. Vector vVel = GetAbsVelocity();
  2423. vVel.z = 400;
  2424. if (redrop_count > 1)
  2425. {
  2426. // Second and third drops try pushing it in other directions
  2427. vVel.x = RandomFloat(-50, 50);
  2428. vVel.y = RandomFloat(-50, 50);
  2429. }
  2430. SetAbsVelocity( vVel );
  2431. goal_state = TFGS_INACTIVE;
  2432. SetAbsAngles( QAngle( 0, 0, 0 ) );
  2433. if (goal_activation & TFGI_SOLID)
  2434. {
  2435. SetSolid( SOLID_BBOX );
  2436. }
  2437. else
  2438. {
  2439. SetSolid( SOLID_BBOX );
  2440. SetSolidFlags( FSOLID_TRIGGER );
  2441. }
  2442. RemoveEffects( EF_NODRAW );
  2443. UTIL_SetSize(this, goal_min, goal_max);
  2444. redrop_count++;
  2445. SetThink( &CTFGoalItem::tfgoalitem_dropthink ); // give it five seconds
  2446. SetNextThink( gpGlobals->curtime + 5.0 ); // and then find where it ended up
  2447. }
  2448. //=========================================================================
  2449. // Set the GoalItems touch func
  2450. void CTFGoalItem::tfgoalitem_droptouch()
  2451. {
  2452. SetTouch( &CTFGoalItem::item_tfgoal_touch );
  2453. SetThink( &CTFGoalItem::tfgoalitem_dropthink ); // give it five seconds since it was dropped
  2454. SetNextThink( gpGlobals->curtime + 4.25 ); // and then find where it ended up
  2455. }
  2456. //=========================================================================
  2457. // A quick check to make sure the items is not in a wall
  2458. void CTFGoalItem::tfgoalitem_dropthink()
  2459. {
  2460. MDEBUG( Msg( "DropThink for %s\n", STRING(pev->netname)) );
  2461. StopFollowingEntity();
  2462. SetMoveType( MOVETYPE_FLYGRAVITY );
  2463. if (drop_time != 0)
  2464. {
  2465. int iEnviron = UTIL_PointContents( GetAbsOrigin() );
  2466. if (iEnviron == CONTENTS_SLIME)
  2467. {
  2468. SetNextThink( gpGlobals->curtime + (drop_time / 4) );
  2469. }
  2470. #ifdef TFCTODO // CONTENTS_LAVA and CONTENTS_SKY don't exist in src.
  2471. else if (iEnviron == CONTENTS_LAVA)
  2472. {
  2473. SetNextThink( gpGlobals->curtime + 5 );
  2474. }
  2475. else if (iEnviron == CONTENTS_SOLID || iEnviron == CONTENTS_SKY)
  2476. #else
  2477. else if (iEnviron == CONTENTS_SOLID)
  2478. #endif
  2479. {
  2480. // Its out of the world
  2481. // Retry a drop from the original position 3 times
  2482. if (redrop_count < 3)
  2483. {
  2484. // Retry the Drop
  2485. DoDrop( redrop_origin );
  2486. return;
  2487. }
  2488. else
  2489. {
  2490. // Fourth time round, just return it
  2491. SetNextThink( gpGlobals->curtime + 2 );
  2492. }
  2493. }
  2494. else
  2495. {
  2496. SetNextThink( gpGlobals->curtime + drop_time );
  2497. }
  2498. SetThink( &CTFGoalItem::tfgoalitem_remove );
  2499. }
  2500. }
  2501. //=========================================================================
  2502. // Remove the item, or Return it if needed
  2503. void CTFGoalItem::tfgoalitem_remove()
  2504. {
  2505. MDEBUG( Msg( "RemoveItem for %s...", STRING(pev->netname)) );
  2506. // Has someone picked it up?
  2507. if (goal_state == TFGS_ACTIVE)
  2508. {
  2509. MDEBUG( Msg( "Item picked up, exiting.\n") );
  2510. return;
  2511. }
  2512. // Should it be returned?
  2513. if (goal_activation & TFGI_RETURN_REMOVE)
  2514. {
  2515. MDEBUG( Msg( "Returned.\n") );
  2516. CTimer *pTimer = Timer_CreateTimer( this, TF_TIMER_RETURNITEM );
  2517. pTimer->weapon = GI_RET_TIME;
  2518. pTimer->m_flNextThink = gpGlobals->curtime + 0.1;
  2519. //pTimer->SetThink( &CBaseEntity::ReturnItem ); this is done by CreateTimer code now.
  2520. return;
  2521. }
  2522. MDEBUG( Msg( "Removed.\n") );
  2523. UTIL_Remove(this);
  2524. }
  2525. // ---------------------------------------------------------------------------------------------------- //
  2526. // CTFSpawn implementation.
  2527. // ---------------------------------------------------------------------------------------------------- //
  2528. LINK_ENTITY_TO_CLASS(info_player_teamspawn, CTFSpawn);
  2529. //===========================================
  2530. void CTFSpawn::Spawn( void )
  2531. {
  2532. if (CheckExistence() == FALSE)
  2533. {
  2534. UTIL_Remove(this);
  2535. return;
  2536. }
  2537. // Team spawnpoints must have a team associated with them
  2538. if ( (GetTeamNumber() <= 0 || GetTeamNumber() >= 5) && teamcheck == NULL_STRING)
  2539. {
  2540. Warning("Teamspawnpoint with an invalid GetTeamNumber() of %d\n", GetTeamNumber());
  2541. return;
  2542. }
  2543. // find the highest team number
  2544. if (number_of_teams < GetTeamNumber())
  2545. number_of_teams = GetTeamNumber();
  2546. // Save out the info_player_teamspawn
  2547. Assert( stricmp( GetClassname(), "info_player_teamspawn" ) == 0 );
  2548. #ifdef TFCTODO
  2549. pev->netname = pev->classname = MAKE_STRING( );
  2550. #endif
  2551. }
  2552. void CTFSpawn::Activate( void )
  2553. {
  2554. m_pTeamCheck = NULL;
  2555. // Find the team check entity
  2556. CBaseEntity *pTarget = gEntList.FindEntityByName( NULL, STRING(teamcheck) );
  2557. if ( pTarget )
  2558. {
  2559. if ( !strcmp( pTarget->GetClassname(), "info_tf_teamcheck" ) )
  2560. m_pTeamCheck = pTarget;
  2561. }
  2562. }
  2563. BOOL CTFSpawn::CheckTeam( int iTeamNo )
  2564. {
  2565. // First check team number
  2566. if ( GetTeamNumber() )
  2567. {
  2568. return ( iTeamNo == GetTeamNumber() );
  2569. }
  2570. // Then check the teamcheck
  2571. if ( m_pTeamCheck )
  2572. {
  2573. CTeamCheck *pTeamCheck = dynamic_cast<CTeamCheck*>( m_pTeamCheck.Get() );
  2574. Assert( pTeamCheck );
  2575. if ( pTeamCheck->TeamMatches( iTeamNo ) == FALSE )
  2576. return FALSE;
  2577. return TRUE;
  2578. }
  2579. return FALSE;
  2580. }
  2581. // ---------------------------------------------------------------------------------------------------- //
  2582. // CBaseDelay implementation.
  2583. // ---------------------------------------------------------------------------------------------------- //
  2584. LINK_ENTITY_TO_CLASS( DelayedUse, CBaseDelay );
  2585. void CBaseDelay::SUB_UseTargets( CBaseEntity *pActivator, USE_TYPE useType, float value )
  2586. {
  2587. // TeamFortress Goal Checking
  2588. if (!pActivator || pActivator->IsPlayer() )
  2589. DoResults(this, ToTFCPlayer( pActivator ), TRUE);
  2590. //
  2591. // exit immediatly if we don't have a target or kill target
  2592. //
  2593. if (target == NULL_STRING && !m_iszKillTarget)
  2594. return;
  2595. //
  2596. // check for a delay
  2597. //
  2598. if (m_flDelay != 0)
  2599. {
  2600. // create a temp object to fire at a later time
  2601. CBaseDelay *pTemp = (CBaseDelay*)CreateEntityByName( "DelayedUse" );
  2602. Assert( stricmp( pTemp->GetClassname(), "DelayedUse" ) == 0 );
  2603. pTemp->SetNextThink( gpGlobals->curtime + m_flDelay );
  2604. pTemp->SetThink( &CBaseDelay::DelayThink );
  2605. // Save the useType
  2606. pTemp->button = (int)useType;
  2607. pTemp->m_iszKillTarget = m_iszKillTarget;
  2608. pTemp->m_flDelay = 0; // prevent "recursion"
  2609. pTemp->target = target;
  2610. return;
  2611. }
  2612. //
  2613. // kill the killtargets
  2614. //
  2615. if ( m_iszKillTarget != NULL_STRING )
  2616. {
  2617. CBaseEntity *pentKillTarget = NULL;
  2618. Msg( "KillTarget: %s\n", STRING(m_iszKillTarget) );
  2619. pentKillTarget = gEntList.FindEntityByName( NULL, STRING(m_iszKillTarget) );
  2620. while ( pentKillTarget )
  2621. {
  2622. Msg( "killing %s\n", pentKillTarget->GetClassname() );
  2623. CBaseEntity *pNext = gEntList.FindEntityByName( pentKillTarget, STRING(m_iszKillTarget) );
  2624. UTIL_Remove( pentKillTarget );
  2625. pentKillTarget = pNext;
  2626. }
  2627. }
  2628. //
  2629. // fire targets
  2630. //
  2631. if ( target != NULL_STRING )
  2632. {
  2633. FireTargets( STRING(target), pActivator, this, useType, value );
  2634. }
  2635. }
  2636. bool CBaseDelay::KeyValue( const char *szKeyName, const char *szValue )
  2637. {
  2638. if (FStrEq(szKeyName, "delay"))
  2639. {
  2640. m_flDelay = atof( szValue );
  2641. return true;
  2642. }
  2643. else if (FStrEq(szKeyName, "killtarget"))
  2644. {
  2645. m_iszKillTarget = MAKE_STRING(szValue);
  2646. return true;
  2647. }
  2648. else
  2649. {
  2650. return BaseClass::KeyValue( szKeyName, szValue );
  2651. }
  2652. }
  2653. void CBaseDelay::DelayThink( void )
  2654. {
  2655. // The use type is cached (and stashed) in pev->button
  2656. SUB_UseTargets( NULL, (USE_TYPE)button, 0 );
  2657. UTIL_Remove( this );
  2658. }
  2659. // ---------------------------------------------------------------------------------------------------- //
  2660. // CTeamCheck implementation.
  2661. // ---------------------------------------------------------------------------------------------------- //
  2662. LINK_ENTITY_TO_CLASS(info_tf_teamcheck, CTeamCheck );
  2663. void CTeamCheck::Spawn( void )
  2664. {
  2665. }
  2666. void CTeamCheck::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
  2667. {
  2668. // Either Toggle or get set to a specific team number
  2669. if ( useType == USE_TOGGLE )
  2670. {
  2671. if ( GetTeamNumber() == 1 )
  2672. ChangeTeam( 2 );
  2673. else
  2674. ChangeTeam( 1 );
  2675. }
  2676. else if ( useType == USE_SET )
  2677. {
  2678. if ( value >= 1 && value <= 4 )
  2679. ChangeTeam( value );
  2680. }
  2681. }
  2682. BOOL CTeamCheck::TeamMatches( int iTeam )
  2683. {
  2684. return ( iTeam == GetTeamNumber() );
  2685. }