basecontroller.cpp 28 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165
  1. /*
  2. ** Command & Conquer Renegade(tm)
  3. ** Copyright 2025 Electronic Arts Inc.
  4. **
  5. ** This program is free software: you can redistribute it and/or modify
  6. ** it under the terms of the GNU General Public License as published by
  7. ** the Free Software Foundation, either version 3 of the License, or
  8. ** (at your option) any later version.
  9. **
  10. ** This program is distributed in the hope that it will be useful,
  11. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ** GNU General Public License for more details.
  14. **
  15. ** You should have received a copy of the GNU General Public License
  16. ** along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. /***********************************************************************************************
  19. *** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
  20. ***********************************************************************************************
  21. * *
  22. * Project Name : Combat *
  23. * *
  24. * $Archive:: /Commando/Code/Combat/basecontroller.cpp $*
  25. * *
  26. * Author:: Patrick Smith *
  27. * *
  28. * $Modtime:: 11/29/01 11:58a $*
  29. * *
  30. * $Revision:: 31 $*
  31. * *
  32. *---------------------------------------------------------------------------------------------*
  33. * Functions: *
  34. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  35. #include "basecontroller.h"
  36. #include "gameobjmanager.h"
  37. #include "scriptzone.h"
  38. #include "radar.h"
  39. #include "vehicle.h"
  40. #include "rendobj.h"
  41. #include "crandom.h"
  42. #include "playerdata.h"
  43. #include "soldier.h"
  44. #include "playertype.h"
  45. #include "combat.h"
  46. #include "powerup.h"
  47. #include "combatchunkid.h"
  48. #include "refinerygameobj.h"
  49. #include "vehiclefactorygameobj.h"
  50. #include "beacongameobj.h"
  51. #include "spawn.h"
  52. #include "apppackettypes.h"
  53. #include "TranslateObj.h"
  54. #include "TranslateDB.h"
  55. #include "WWAudio.h"
  56. #include "MessageWindow.h"
  57. #include "CNCModeSettings.h"
  58. ////////////////////////////////////////////////////////////////
  59. // Namespaces
  60. ////////////////////////////////////////////////////////////////
  61. using namespace BuildingConstants;
  62. ////////////////////////////////////////////////////////////////
  63. // Static member initialization
  64. ////////////////////////////////////////////////////////////////
  65. BaseControllerClass * BaseControllerClass::CurrentBases[BuildingConstants::BASE_COUNT] = { 0 };
  66. ////////////////////////////////////////////////////////////////
  67. //
  68. // BaseControllerClass
  69. //
  70. ////////////////////////////////////////////////////////////////
  71. BaseControllerClass::BaseControllerClass (void) :
  72. BasePowered (true),
  73. PlayerType (PLAYERTYPE_NOD),
  74. OperationTimeFactor (1.0F),
  75. CanGenerateSoldiers (false),
  76. CanGenerateVehicles (false),
  77. IsRadarEnabled (true),
  78. IsBaseDestroyed (false),
  79. DidBeaconDestroyBase (false),
  80. BeaconZone (Vector3 (0, 0, 0), Vector3 (0, 0, 0)),
  81. AnnounceInterval(0),
  82. AnnouncedAlliedBldgDamageTime(0.0f),
  83. AnnouncedEnemyBldgDamageTime(0.0f),
  84. AnnouncedAlliedVehicleDamageTime(0.0f),
  85. AnnouncedEnemyVehicleDamageTime(0.0f)
  86. {
  87. Initialize_Building_List ();
  88. Set_App_Packet_Type(APPPACKETTYPE_BASECONTROLLER);
  89. return ;
  90. }
  91. ////////////////////////////////////////////////////////////////
  92. //
  93. // ~BaseControllerClass
  94. //
  95. ////////////////////////////////////////////////////////////////
  96. BaseControllerClass::~BaseControllerClass (void)
  97. {
  98. WWASSERT ( PlayerType == PLAYERTYPE_GDI || PlayerType == PLAYERTYPE_NOD );
  99. if (CurrentBases[PlayerType] == this) {
  100. CurrentBases[PlayerType] = NULL;
  101. }
  102. Reset_Building_List ();
  103. return ;
  104. }
  105. ////////////////////////////////////////////////////////////////
  106. //
  107. // Shutdown
  108. //
  109. ////////////////////////////////////////////////////////////////
  110. void
  111. BaseControllerClass::Shutdown (void)
  112. {
  113. Reset_Building_List ();
  114. return ;
  115. }
  116. ////////////////////////////////////////////////////////////////
  117. //
  118. // Initialize
  119. //
  120. ////////////////////////////////////////////////////////////////
  121. void
  122. BaseControllerClass::Initialize (int player_type)
  123. {
  124. WWASSERT ( player_type == PLAYERTYPE_GDI || player_type == PLAYERTYPE_NOD );
  125. //
  126. // Remember which team this base belongs to
  127. //
  128. PlayerType = player_type;
  129. CurrentBases[PlayerType] = this;
  130. Set_Can_Generate_Soldiers( false );
  131. Set_Can_Generate_Vehicles( false );
  132. CNCModeSettingsDef* cncDef = CNCModeSettingsDef::Get_Instance();
  133. if (cncDef) {
  134. AnnounceInterval = cncDef->Get_Announcement_Interval();
  135. } else {
  136. AnnounceInterval = 0;
  137. }
  138. //
  139. // Setup the network ID
  140. //
  141. if (PlayerType == PLAYERTYPE_GDI) {
  142. Set_Network_ID (NETID_GDI_BASE_CONTROLLER);
  143. } else {
  144. WWASSERT(PlayerType == PLAYERTYPE_NOD);
  145. Set_Network_ID (NETID_NOD_BASE_CONTROLLER);
  146. }
  147. Check_Base_Power ();
  148. Set_Base_Destroyed( false );
  149. Set_Beacon_Destroyed_Base( false );
  150. return ;
  151. }
  152. ////////////////////////////////////////////////////////////////
  153. //
  154. // Initialize_Building_List
  155. //
  156. ////////////////////////////////////////////////////////////////
  157. void
  158. BaseControllerClass::Initialize_Building_List (void)
  159. {
  160. Reset_Building_List ();
  161. return ;
  162. }
  163. ////////////////////////////////////////////////////////////////
  164. //
  165. // Reset_Building_List
  166. //
  167. ////////////////////////////////////////////////////////////////
  168. void
  169. BaseControllerClass::Reset_Building_List (void)
  170. {
  171. //
  172. // Simply reset the list
  173. //
  174. BuildingList.Delete_All ();
  175. return ;
  176. }
  177. ////////////////////////////////////////////////////////////////
  178. //
  179. // On_Building_Damaged
  180. //
  181. ////////////////////////////////////////////////////////////////
  182. void BaseControllerClass::On_Building_Damaged(BuildingGameObj* building)
  183. {
  184. const BuildingGameObjDef& def = building->Get_Definition();
  185. // Annouce the damage report if we haven't done so recently.
  186. if (AnnounceInterval > 0) {
  187. if (COMBAT_STAR) {
  188. int playersTeam = COMBAT_STAR->Get_Player_Type();
  189. bool isAllied = (playersTeam == PlayerType);
  190. float seconds = TimeManager::Get_Total_Seconds();
  191. int elapsed = 0;
  192. if (isAllied) {
  193. elapsed = (int)(seconds - AnnouncedAlliedBldgDamageTime);
  194. } else {
  195. elapsed = (int)(seconds - AnnouncedEnemyBldgDamageTime);
  196. }
  197. if (elapsed >= AnnounceInterval) {
  198. Play_Announcement(def.Get_Damage_Report(playersTeam));
  199. if (isAllied) {
  200. AnnouncedAlliedBldgDamageTime = seconds;
  201. } else {
  202. AnnouncedEnemyBldgDamageTime = seconds;
  203. }
  204. }
  205. }
  206. }
  207. // Notify the team that the base is under attack
  208. Notify_Team(BASE_UNDER_ATTACK, def.Get_Type());
  209. }
  210. ////////////////////////////////////////////////////////////////
  211. //
  212. // On_Building_Destroyed
  213. //
  214. ////////////////////////////////////////////////////////////////
  215. void BaseControllerClass::On_Building_Destroyed(BuildingGameObj* building)
  216. {
  217. const BuildingGameObjDef& def = building->Get_Definition();
  218. if (COMBAT_STAR) {
  219. int playersTeam = COMBAT_STAR->Get_Player_Type();
  220. Play_Announcement(def.Get_Destroy_Report(playersTeam));
  221. }
  222. // Let the team know that a building was destroyed
  223. Notify_Team(BUILDING_DESTROYED, def.Get_Type ());
  224. // Check a victory condition
  225. if (Are_All_Buildings_Destroyed()) {
  226. Set_Base_Destroyed(true);
  227. }
  228. }
  229. ////////////////////////////////////////////////////////////////
  230. //
  231. // On_Vehicle_Generated
  232. //
  233. ////////////////////////////////////////////////////////////////
  234. void
  235. BaseControllerClass::On_Vehicle_Generated (VehicleGameObj *vehicle)
  236. {
  237. //
  238. // Find our refinery (if we have one)
  239. //
  240. BuildingGameObj* building = Find_Building(TYPE_REFINERY);
  241. if (building) {
  242. RefineryGameObj* refinery = building->As_RefineryGameObj();
  243. //
  244. // Check to see if the refinery needs a harvester and if
  245. // the vehicle we just generated was a harvester.
  246. //
  247. int def_id = vehicle->Get_Definition().Get_ID();
  248. if (refinery->Needs_Harvester() && def_id == refinery->Get_Harvester_Def_ID()) {
  249. refinery->Set_Harvester_Vehicle(vehicle);
  250. }
  251. }
  252. return ;
  253. }
  254. void BaseControllerClass::On_Vehicle_Delivered(VehicleGameObj *vehicle)
  255. {
  256. SoldierGameObj* thePlayer = COMBAT_STAR;
  257. bool isAllied = (thePlayer && (thePlayer->Get_Player_Type() == PlayerType));
  258. // Only the allied player who purchased the vehicle should hear this.
  259. if (isAllied) {
  260. // Play unit ready report for the current player.
  261. CNCModeSettingsDef* cncDef = CNCModeSettingsDef::Get_Instance();
  262. if (cncDef) {
  263. Play_Announcement(cncDef->Get_Unit_Ready_Report(PlayerType));
  264. }
  265. }
  266. }
  267. void BaseControllerClass::On_Vehicle_Damaged(VehicleGameObj* vehicle)
  268. {
  269. // Annouce the damage report if we haven't done so recently.
  270. if (AnnounceInterval > 0) {
  271. if (COMBAT_STAR) {
  272. int playersTeam = COMBAT_STAR->Get_Player_Type();
  273. bool isAllied = (playersTeam == PlayerType);
  274. float seconds = TimeManager::Get_Total_Seconds();
  275. int elapsed = 0;
  276. if (isAllied) {
  277. elapsed = (int)(seconds - AnnouncedAlliedBldgDamageTime);
  278. } else {
  279. elapsed = (int)(seconds - AnnouncedEnemyBldgDamageTime);
  280. }
  281. if (elapsed >= AnnounceInterval) {
  282. const VehicleGameObjDef& def = vehicle->Get_Definition();
  283. Play_Announcement(def.Get_Damage_Report(playersTeam));
  284. if (isAllied) {
  285. AnnouncedAlliedBldgDamageTime = seconds;
  286. } else {
  287. AnnouncedEnemyBldgDamageTime = seconds;
  288. }
  289. }
  290. }
  291. }
  292. }
  293. void BaseControllerClass::On_Vehicle_Destroyed(VehicleGameObj* vehicle)
  294. {
  295. if (COMBAT_STAR) {
  296. const VehicleGameObjDef& def = vehicle->Get_Definition();
  297. int playersTeam = COMBAT_STAR->Get_Player_Type();
  298. Play_Announcement(def.Get_Destroy_Report(playersTeam));
  299. }
  300. }
  301. void BaseControllerClass::On_Beacon_Armed(BeaconGameObj* beacon)
  302. {
  303. CNCModeSettingsDef* cncDef = CNCModeSettingsDef::Get_Instance();
  304. if (cncDef) {
  305. bool isNuke = beacon->Get_Definition().Is_Nuke();
  306. if (COMBAT_STAR != NULL) {
  307. int team = COMBAT_STAR->Get_Player_Type();
  308. if (isNuke) {
  309. int report = cncDef->Get_Nuke_Beacon_Deployed_Report(team);
  310. Play_Announcement(report);
  311. } else {
  312. int report = cncDef->Get_Ion_Beacon_Deployed_Report(team);
  313. Play_Announcement(report);
  314. }
  315. }
  316. }
  317. }
  318. void BaseControllerClass::On_Beacon_Disarmed(BeaconGameObj* beacon)
  319. {
  320. CNCModeSettingsDef* cncDef = CNCModeSettingsDef::Get_Instance();
  321. if (cncDef) {
  322. bool isNuke = beacon->Get_Definition().Is_Nuke();
  323. if (COMBAT_STAR != NULL) {
  324. int team = COMBAT_STAR->Get_Player_Type();
  325. if (isNuke) {
  326. int report = cncDef->Get_Nuke_Beacon_Disarmed_Report(team);
  327. Play_Announcement(report);
  328. } else {
  329. int report = cncDef->Get_Ion_Beacon_Disarmed_Report(team);
  330. Play_Announcement(report);
  331. }
  332. }
  333. }
  334. }
  335. void BaseControllerClass::On_Beacon_Warning(BeaconGameObj* beacon)
  336. {
  337. CNCModeSettingsDef* cncDef = CNCModeSettingsDef::Get_Instance();
  338. if (cncDef) {
  339. bool isNuke = beacon->Get_Definition().Is_Nuke();
  340. if (COMBAT_STAR != NULL) {
  341. int team = COMBAT_STAR->Get_Player_Type();
  342. if (isNuke) {
  343. int report = cncDef->Get_Nuke_Beacon_Warning_Report(team);
  344. Play_Announcement(report);
  345. } else {
  346. int report = cncDef->Get_Ion_Beacon_Warning_Report(team);
  347. Play_Announcement(report);
  348. }
  349. }
  350. }
  351. }
  352. ////////////////////////////////////////////////////////////////
  353. //
  354. // Are_All_Buildings_Destroyed
  355. //
  356. ////////////////////////////////////////////////////////////////
  357. bool
  358. BaseControllerClass::Are_All_Buildings_Destroyed (void)
  359. {
  360. bool retval = true;
  361. //
  362. // Are all the buildings destroyed?
  363. //
  364. for (int index = 0; index < BuildingList.Count (); index ++) {
  365. BuildingGameObj *building = BuildingList[index];
  366. //
  367. // If this building has any health left, then the base is not
  368. // completely destroyed.
  369. //
  370. if (building->Is_Destroyed () == false) {
  371. retval = false;
  372. break;
  373. }
  374. }
  375. return retval;
  376. }
  377. ////////////////////////////////////////////////////////////////
  378. //
  379. // Notify_Team
  380. //
  381. ////////////////////////////////////////////////////////////////
  382. void
  383. BaseControllerClass::Notify_Team (Notification event, BuildingType type)
  384. {
  385. return ;
  386. }
  387. ////////////////////////////////////////////////////////////////
  388. //
  389. // Check_Base_Power
  390. //
  391. ////////////////////////////////////////////////////////////////
  392. void
  393. BaseControllerClass::Check_Base_Power (void)
  394. {
  395. bool is_powered = true;
  396. // Search through each building
  397. int count = BuildingList.Count();
  398. for (int index = 0; index < count; ++index) {
  399. BuildingGameObj* building = BuildingList[index];
  400. // Is this a power-plant?
  401. if (building->Get_Definition().Get_Type() == TYPE_POWER_PLANT) {
  402. // The base is NOT powered if all power-plants are destoryed.
  403. // However, the base IS powered if there are NO power plants
  404. if (BuildingList[index]->Is_Destroyed()) {
  405. is_powered = false;
  406. } else {
  407. is_powered = true;
  408. break;
  409. }
  410. }
  411. }
  412. // Change the powered state of the base
  413. Power_Base(is_powered);
  414. }
  415. ////////////////////////////////////////////////////////////////
  416. //
  417. // Power_Base
  418. //
  419. ////////////////////////////////////////////////////////////////
  420. void
  421. BaseControllerClass::Power_Base (bool onoff)
  422. {
  423. if (CombatManager::I_Am_Server () == false) {
  424. return ;
  425. }
  426. if (BasePowered != onoff) {
  427. Set_Base_Powered( onoff );
  428. Set_Operation_Time_Factor( BasePowered ? 1.0F : 2.0F );
  429. //
  430. // Switch the powered state of each building
  431. //
  432. for (int index = 0; index < BuildingList.Count (); index ++) {
  433. BuildingGameObj *building = BuildingList[index];
  434. //
  435. // Only change the power state of this building if it makes sense
  436. //
  437. if ((BasePowered == false) || (building->Is_Destroyed () == false)) {
  438. building->Enable_Power (BasePowered);
  439. }
  440. }
  441. // Notify that the base
  442. if (!BasePowered) {
  443. const CNCModeSettingsDef* def = CNCModeSettingsDef::Get_Instance();
  444. if (def) {
  445. Play_Announcement(def->Get_Power_Offline_Report(PlayerType));
  446. }
  447. }
  448. }
  449. return ;
  450. }
  451. ////////////////////////////////////////////////////////////////
  452. //
  453. // Set_Operation_Time_Factor
  454. //
  455. ////////////////////////////////////////////////////////////////
  456. void
  457. BaseControllerClass::Set_Operation_Time_Factor (float factor)
  458. {
  459. OperationTimeFactor = factor;
  460. Set_Object_Dirty_Bit( NetworkObjectClass::BIT_OCCASIONAL, true );
  461. }
  462. ////////////////////////////////////////////////////////////////
  463. //
  464. // Set_Base_Powered
  465. //
  466. ////////////////////////////////////////////////////////////////
  467. void
  468. BaseControllerClass::Set_Base_Powered (bool onoff)
  469. {
  470. BasePowered = onoff;
  471. Set_Object_Dirty_Bit( NetworkObjectClass::BIT_OCCASIONAL, true );
  472. }
  473. ////////////////////////////////////////////////////////////////
  474. //
  475. // Set_Can_Generate_Soldiers
  476. //
  477. ////////////////////////////////////////////////////////////////
  478. void
  479. BaseControllerClass::Set_Can_Generate_Soldiers (bool onoff)
  480. {
  481. CanGenerateSoldiers = onoff;
  482. Set_Object_Dirty_Bit( NetworkObjectClass::BIT_OCCASIONAL, true );
  483. }
  484. ////////////////////////////////////////////////////////////////
  485. //
  486. // Set_Can_Generate_Vehicles
  487. //
  488. ////////////////////////////////////////////////////////////////
  489. void
  490. BaseControllerClass::Set_Can_Generate_Vehicles (bool onoff)
  491. {
  492. CanGenerateVehicles = onoff;
  493. Set_Object_Dirty_Bit( NetworkObjectClass::BIT_OCCASIONAL, true );
  494. }
  495. ////////////////////////////////////////////////////////////////
  496. //
  497. // Request_Harvester
  498. //
  499. ////////////////////////////////////////////////////////////////
  500. void
  501. BaseControllerClass::Request_Harvester (int def_id)
  502. {
  503. if (CombatManager::I_Am_Server () == false) {
  504. return ;
  505. }
  506. //
  507. // Find our vehicle factory
  508. //
  509. BuildingGameObj *building = Find_Building (TYPE_VEHICLE_FACTORY);
  510. if (building != NULL) {
  511. VehicleFactoryGameObj *factory = building->As_VehicleFactoryGameObj ();
  512. //
  513. // If we have a vehicle factory that isn't busy, then start building a harvester
  514. //
  515. if (factory->Is_Available ()) {
  516. float time = 8.0F;
  517. factory->Request_Vehicle (def_id, time * OperationTimeFactor);
  518. }
  519. } else {
  520. // Find our refinery (if we have one)
  521. //
  522. BuildingGameObj *building = Find_Building (TYPE_REFINERY);
  523. if (building != NULL) {
  524. RefineryGameObj *refinery = building->As_RefineryGameObj ();
  525. //
  526. // If there is no vehicle factory in this level, then
  527. // try to find a spawner that will create this type of harvester
  528. // for us.
  529. //
  530. DynamicVectorClass<SpawnerClass *> spawner_list = SpawnManager::Get_Spawner_List ();
  531. for (int index = 0; index < spawner_list.Count (); index ++) {
  532. SpawnerClass *spawner = spawner_list[index];
  533. if (spawner != NULL && spawner->Can_Spawn_Object (def_id)) {
  534. //
  535. // Try to spawn the harvester
  536. //
  537. PhysicalGameObj *new_obj = spawner->Spawn_Object (def_id);
  538. if (new_obj != NULL && new_obj->As_VehicleGameObj () != NULL) {
  539. refinery->Set_Harvester_Vehicle (new_obj->As_VehicleGameObj ());
  540. break;
  541. }
  542. }
  543. }
  544. }
  545. }
  546. return ;
  547. }
  548. ////////////////////////////////////////////////////////////////
  549. //
  550. // Check_Radar
  551. //
  552. ////////////////////////////////////////////////////////////////
  553. void
  554. BaseControllerClass::Check_Radar (void)
  555. {
  556. bool enable_radar = false;
  557. //
  558. // Search through each building
  559. //
  560. for (int index = 0; index < BuildingList.Count (); index ++) {
  561. BuildingGameObj *building = BuildingList[index];
  562. //
  563. // Is this a com center?
  564. //
  565. if (building->Get_Definition ().Get_Type () == TYPE_COM_CENTER) {
  566. //
  567. // The base has radar if there is even one active com-center
  568. //
  569. if (BuildingList[index]->Is_Destroyed () == false) {
  570. enable_radar = true;
  571. break;
  572. }
  573. }
  574. }
  575. //
  576. // Update the radar
  577. //
  578. Enable_Radar (enable_radar);
  579. return ;
  580. }
  581. ////////////////////////////////////////////////////////////////
  582. //
  583. // Think
  584. //
  585. ////////////////////////////////////////////////////////////////
  586. void
  587. BaseControllerClass::Think (void)
  588. {
  589. return ;
  590. }
  591. ////////////////////////////////////////////////////////////////
  592. //
  593. // Find_Building
  594. //
  595. ////////////////////////////////////////////////////////////////
  596. BuildingGameObj *
  597. BaseControllerClass::Find_Building (BuildingConstants::BuildingType type)
  598. {
  599. BuildingGameObj *building = NULL;
  600. //
  601. // Search through each building
  602. //
  603. for (int index = 0; index < BuildingList.Count (); index ++) {
  604. //
  605. // Is this the type of building we are looking for?
  606. //
  607. if (BuildingList[index]->Get_Definition ().Get_Type () == type) {
  608. building = BuildingList[index];
  609. break;
  610. }
  611. }
  612. return building;
  613. }
  614. ////////////////////////////////////////////////////////////////
  615. //
  616. // Distribute_Funds_To_Each_Teammate
  617. //
  618. ////////////////////////////////////////////////////////////////
  619. void
  620. BaseControllerClass::Distribute_Funds_To_Each_Teammate (int funds)
  621. {
  622. //
  623. // Only let the server assign money
  624. //
  625. if (CombatManager::I_Am_Server () == false) {
  626. return ;
  627. }
  628. //
  629. // Loop over all the players in the game
  630. //
  631. SList<SoldierGameObj> *list = GameObjManager::Get_Star_Game_Obj_List ();
  632. SLNode<SoldierGameObj> *node = NULL;
  633. for (node = list->Head(); node != NULL; node = node->Next()) {
  634. SoldierGameObj *player = node->Data();
  635. //
  636. // Is this a player on our team?
  637. //
  638. if ( player != NULL &&
  639. (player->Get_Player_Type () == PlayerType) )
  640. {
  641. //
  642. // Get the data associated with this player
  643. //
  644. PlayerDataClass *player_data = player->Get_Player_Data ();
  645. if (player_data != NULL) {
  646. //
  647. // Add the money to this player's total
  648. //
  649. player_data->Increment_Money (funds);
  650. }
  651. }
  652. }
  653. return ;
  654. }
  655. /*
  656. ////////////////////////////////////////////////////////////////
  657. //
  658. // Deposit_Funds
  659. //
  660. ////////////////////////////////////////////////////////////////
  661. void
  662. BaseControllerClass::Deposit_Funds (int funds)
  663. {
  664. //
  665. // Only let the server assign money
  666. //
  667. if (CombatManager::I_Am_Server () == false) {
  668. return ;
  669. }
  670. DynamicVectorClass<SoldierGameObj *> team_players;
  671. //
  672. // Loop over all the players in the game
  673. //
  674. SList<SoldierGameObj> *list = GameObjManager::Get_Star_Game_Obj_List ();
  675. SLNode<SoldierGameObj> *node = NULL;
  676. for (node = list->Head(); node != NULL; node = node->Next()) {
  677. SoldierGameObj *player = node->Data();
  678. //
  679. // Is this a player on our team?
  680. //
  681. if ( player != NULL &&
  682. (player->Get_Player_Type () == PLAYERTYPE_GDI && Team == TEAM_GDI) ||
  683. (player->Get_Player_Type () == PLAYERTYPE_NOD && Team == TEAM_NOD))
  684. {
  685. //
  686. // Add the player to our list
  687. //
  688. team_players.Add (player);
  689. }
  690. }
  691. if (team_players.Count () > 0) {
  692. //
  693. // Now distribute the funds to each player
  694. //
  695. int funds_per_player = funds / team_players.Count ();
  696. for (int index = 0; index < team_players.Count (); index ++) {
  697. PlayerDataClass *player_data = team_players[index]->Get_Player_Data ();
  698. if (player_data != NULL) {
  699. //
  700. // Add the money to this player's total
  701. //
  702. player_data->Increment_Money (funds_per_player);
  703. funds -= funds_per_player;
  704. }
  705. }
  706. //
  707. // If there is any money left over, then give it to a random teammate
  708. //
  709. if (funds > 0) {
  710. index = FreeRandom.Get_Int ( team_players.Count () );
  711. PlayerDataClass *player_data = team_players[index]->Get_Player_Data ();
  712. if (player_data != NULL) {
  713. //
  714. // Add the money to this player's total
  715. //
  716. player_data->Increment_Money (funds);
  717. }
  718. }
  719. }
  720. return ;
  721. }
  722. */
  723. ////////////////////////////////////////////////////////////////
  724. //
  725. // Find_Base
  726. //
  727. ////////////////////////////////////////////////////////////////
  728. BaseControllerClass *
  729. BaseControllerClass::Find_Base ( int player_type )
  730. {
  731. BaseControllerClass *base = NULL;
  732. //
  733. // Try to find a base of the appropriate team in our list
  734. //
  735. for (int index = 0; index < BASE_COUNT; index ++) {
  736. if (CurrentBases[index] != NULL && CurrentBases[index]->Get_Player_Type () == player_type ) {
  737. base = CurrentBases[index];
  738. break;
  739. }
  740. }
  741. return base;
  742. }
  743. ////////////////////////////////////////////////////////////////
  744. //
  745. // Find_Base_For_Star
  746. //
  747. ////////////////////////////////////////////////////////////////
  748. BaseControllerClass *
  749. BaseControllerClass::Find_Base_For_Star (void)
  750. {
  751. int player_type = PLAYERTYPE_GDI;
  752. if ( COMBAT_STAR != NULL ) {
  753. player_type = COMBAT_STAR->Get_Player_Type ();
  754. }
  755. return Find_Base (player_type);
  756. }
  757. ////////////////////////////////////////////////////////////////
  758. //
  759. // Set_Base_Destroyed
  760. //
  761. ////////////////////////////////////////////////////////////////
  762. void
  763. BaseControllerClass::Set_Base_Destroyed ( bool onoff )
  764. {
  765. IsBaseDestroyed = onoff;
  766. Set_Object_Dirty_Bit( NetworkObjectClass::BIT_OCCASIONAL, true );
  767. }
  768. ////////////////////////////////////////////////////////////////
  769. //
  770. // Destroy_Base
  771. //
  772. ////////////////////////////////////////////////////////////////
  773. void
  774. BaseControllerClass::Destroy_Base (void)
  775. {
  776. for (int index = 0; index < BuildingList.Count (); index ++) {
  777. //
  778. // Destroy this building
  779. //
  780. BuildingGameObj *building = BuildingList[index];
  781. building->Set_Normalized_Health (0);
  782. }
  783. //
  784. // Disable everything
  785. //
  786. Set_Base_Powered( false );
  787. Set_Can_Generate_Soldiers( false );
  788. Set_Can_Generate_Vehicles( false );
  789. Set_Base_Destroyed( true );
  790. Set_Operation_Time_Factor( 2.0F );
  791. return ;
  792. }
  793. ////////////////////////////////////////////////////////////////
  794. //
  795. // Set_Beacon_Destroyed_Base
  796. //
  797. ////////////////////////////////////////////////////////////////
  798. void
  799. BaseControllerClass::Set_Beacon_Destroyed_Base ( bool onoff )
  800. {
  801. DidBeaconDestroyBase = onoff;
  802. Set_Object_Dirty_Bit( NetworkObjectClass::BIT_OCCASIONAL, true );
  803. }
  804. ////////////////////////////////////////////////////////////////
  805. //
  806. // Add_Building
  807. //
  808. ////////////////////////////////////////////////////////////////
  809. void
  810. BaseControllerClass::Add_Building (BuildingGameObj *building)
  811. {
  812. //
  813. // Add the building to our list (if its not already there)
  814. //
  815. if (building != NULL) {
  816. if (BuildingList.ID (building) == -1) {
  817. //
  818. // Add the building to our list
  819. //
  820. building->CnC_Initialize (this);
  821. BuildingList.Add (building);
  822. //
  823. // Find the beacon zone if this is the first building added...
  824. //
  825. if (BuildingList.Count () == 1) {
  826. //
  827. // Get the position of the first building in our list
  828. //
  829. Vector3 pos;
  830. BuildingList[0]->Get_Position (&pos);
  831. //
  832. // Find the closest beacon zone to the building
  833. //
  834. ScriptZoneGameObj *zone = NULL;
  835. zone = ScriptZoneGameObj::Find_Closest_Zone (pos, ZoneConstants::TYPE_BEACON);
  836. if (zone != NULL) {
  837. BeaconZone = zone->Get_Bounding_Box ();
  838. //
  839. // Get rid of the zone (if the game doesn't need it anymore)
  840. //
  841. if (zone->Get_Observers ().Count () == 0) {
  842. zone->Set_Delete_Pending();
  843. }
  844. }
  845. }
  846. //
  847. // Update the state of the base
  848. //
  849. Check_Base_Power ();
  850. Check_Radar ();
  851. }
  852. }
  853. return ;
  854. }
  855. ////////////////////////////////////////////////////////////////
  856. //
  857. // Import_Occasional
  858. //
  859. ////////////////////////////////////////////////////////////////
  860. void
  861. BaseControllerClass::Import_Occasional (BitStreamClass &packet)
  862. {
  863. //
  864. // Read the state variables from the server
  865. //
  866. packet.Get (OperationTimeFactor);
  867. bool wasBasePowered = BasePowered;
  868. packet.Get(BasePowered);
  869. packet.Get(CanGenerateSoldiers);
  870. packet.Get(CanGenerateVehicles);
  871. packet.Get(IsBaseDestroyed);
  872. packet.Get(DidBeaconDestroyBase);
  873. bool is_radar_enabled = packet.Get(is_radar_enabled);
  874. Enable_Radar(is_radar_enabled);
  875. // If the base was powered but now is not then report that
  876. // power is offline.
  877. if (wasBasePowered && !BasePowered) {
  878. const CNCModeSettingsDef* cncDef = CNCModeSettingsDef::Get_Instance();
  879. if (cncDef) {
  880. Play_Announcement(cncDef->Get_Power_Offline_Report(PlayerType));
  881. }
  882. }
  883. }
  884. ////////////////////////////////////////////////////////////////
  885. //
  886. // Export_Occasional
  887. //
  888. ////////////////////////////////////////////////////////////////
  889. void
  890. BaseControllerClass::Export_Occasional (BitStreamClass &packet)
  891. {
  892. //
  893. // Send the state variables to the client
  894. //
  895. packet.Add (OperationTimeFactor);
  896. packet.Add (BasePowered);
  897. packet.Add (CanGenerateSoldiers);
  898. packet.Add (CanGenerateVehicles);
  899. packet.Add (IsBaseDestroyed);
  900. packet.Add (DidBeaconDestroyBase);
  901. packet.Add (IsRadarEnabled);
  902. }
  903. ////////////////////////////////////////////////////////////////
  904. //
  905. // Enable_Radar
  906. //
  907. ////////////////////////////////////////////////////////////////
  908. void
  909. BaseControllerClass::Enable_Radar (bool onoff)
  910. {
  911. if (IsRadarEnabled != onoff) {
  912. IsRadarEnabled = onoff;
  913. //
  914. // Check to see if the current player belongs to this base
  915. //
  916. if ( COMBAT_STAR != NULL &&
  917. (COMBAT_STAR->Get_Player_Type () == PlayerType) )
  918. {
  919. //
  920. // Show or hide the radar
  921. //
  922. RadarManager::Set_Hidden (!IsRadarEnabled);
  923. }
  924. Set_Object_Dirty_Bit( NetworkObjectClass::BIT_OCCASIONAL, true );
  925. }
  926. return ;
  927. }
  928. ////////////////////////////////////////////////////////////////
  929. //
  930. // Get_Harvester_Vehicle
  931. //
  932. ////////////////////////////////////////////////////////////////
  933. VehicleGameObj *
  934. BaseControllerClass::Get_Harvester_Vehicle (void)
  935. {
  936. VehicleGameObj *retval = NULL;
  937. //
  938. // Find our refinery (if we have one)
  939. //
  940. BuildingGameObj *building = Find_Building (TYPE_REFINERY);
  941. if (building != NULL) {
  942. RefineryGameObj *refinery = building->As_RefineryGameObj ();
  943. //
  944. // Return the harvester to the caller
  945. //
  946. retval = refinery->Get_Harvester_Vehicle ();
  947. }
  948. return retval;
  949. }
  950. void BaseControllerClass::Play_Announcement(int text_id)
  951. {
  952. if (text_id == 0) {
  953. return;
  954. }
  955. // Lookup the translation object from the strings database
  956. TDBObjClass* translate_obj = TranslateDBClass::Find_Object(text_id);
  957. if (translate_obj) {
  958. // Display the text on the screen
  959. const WCHAR* string = translate_obj->Get_String();
  960. if (string) {
  961. CombatManager::Get_Message_Window()->Add_Message(string, Vector3(1, 1, 1));
  962. }
  963. // Play the sound effect
  964. int soundID = (int)translate_obj->Get_Sound_ID();
  965. if (soundID > 0) {
  966. WWAudioClass::Get_Instance()->Create_Instant_Sound(soundID, Matrix3D(1));
  967. }
  968. }
  969. }