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.

3127 lines
88 KiB

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