/*
**	Command & Conquer Renegade(tm)
**	Copyright 2025 Electronic Arts Inc.
**
**	This program is free software: you can redistribute it and/or modify
**	it under the terms of the GNU General Public License as published by
**	the Free Software Foundation, either version 3 of the License, or
**	(at your option) any later version.
**
**	This program is distributed in the hope that it will be useful,
**	but WITHOUT ANY WARRANTY; without even the implied warranty of
**	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
**	GNU General Public License for more details.
**
**	You should have received a copy of the GNU General Public License
**	along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

/***********************************************************************************************
 ***              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               ***
 ***********************************************************************************************
 *                                                                                             *
 *                 Project Name : Combat																		  *
 *                                                                                             *
 *                     $Archive:: /Commando/Code/Combat/basecontroller.cpp        $*
 *                                                                                             *
 *                       Author:: Patrick Smith                                                *
 *                                                                                             *
 *                     $Modtime:: 11/29/01 11:58a                                              $*
 *                                                                                             *
 *                    $Revision:: 31                                                          $*
 *                                                                                             *
 *---------------------------------------------------------------------------------------------*
 * Functions:                                                                                  *
 * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */

#include "basecontroller.h"
#include "gameobjmanager.h"
#include "scriptzone.h"
#include "radar.h"
#include "vehicle.h"
#include "rendobj.h"
#include "crandom.h"
#include "playerdata.h"
#include "soldier.h"
#include "playertype.h"
#include "combat.h"
#include "powerup.h"
#include "combatchunkid.h"
#include "refinerygameobj.h"
#include "vehiclefactorygameobj.h"
#include "beacongameobj.h"
#include "spawn.h"
#include "apppackettypes.h"
#include "TranslateObj.h"
#include "TranslateDB.h"
#include "WWAudio.h"
#include "MessageWindow.h"
#include "CNCModeSettings.h"

////////////////////////////////////////////////////////////////
//	Namespaces
////////////////////////////////////////////////////////////////
using namespace BuildingConstants;


////////////////////////////////////////////////////////////////
//	Static member initialization
////////////////////////////////////////////////////////////////
BaseControllerClass *	BaseControllerClass::CurrentBases[BuildingConstants::BASE_COUNT] = { 0 };


////////////////////////////////////////////////////////////////
//
//	BaseControllerClass
//
////////////////////////////////////////////////////////////////
BaseControllerClass::BaseControllerClass (void)	:
	BasePowered (true),
	PlayerType (PLAYERTYPE_NOD),
	OperationTimeFactor (1.0F),
	CanGenerateSoldiers (false),
	CanGenerateVehicles (false),
	IsRadarEnabled (true),
	IsBaseDestroyed (false),
	DidBeaconDestroyBase (false),
	BeaconZone (Vector3 (0, 0, 0), Vector3 (0, 0, 0)),
	AnnounceInterval(0),
	AnnouncedAlliedBldgDamageTime(0.0f),
	AnnouncedEnemyBldgDamageTime(0.0f),
	AnnouncedAlliedVehicleDamageTime(0.0f),
	AnnouncedEnemyVehicleDamageTime(0.0f)

{
	Initialize_Building_List ();

	Set_App_Packet_Type(APPPACKETTYPE_BASECONTROLLER);

	return ;
}


////////////////////////////////////////////////////////////////
//
//	~BaseControllerClass
//
////////////////////////////////////////////////////////////////
BaseControllerClass::~BaseControllerClass (void)
{
	WWASSERT ( PlayerType == PLAYERTYPE_GDI || PlayerType == PLAYERTYPE_NOD );
	if (CurrentBases[PlayerType] == this) {
		CurrentBases[PlayerType] = NULL;
	}

	Reset_Building_List ();
	return ;
}


////////////////////////////////////////////////////////////////
//
//	Shutdown
//
////////////////////////////////////////////////////////////////
void
BaseControllerClass::Shutdown (void)
{
	Reset_Building_List ();
	return ;
}


////////////////////////////////////////////////////////////////
//
//	Initialize
//
////////////////////////////////////////////////////////////////
void
BaseControllerClass::Initialize (int player_type)
{
	WWASSERT ( player_type == PLAYERTYPE_GDI || player_type == PLAYERTYPE_NOD );

	//
	//	Remember which team this base belongs to
	//
	PlayerType					= player_type;
	CurrentBases[PlayerType]	= this;
	Set_Can_Generate_Soldiers( false );
	Set_Can_Generate_Vehicles( false );

	CNCModeSettingsDef* cncDef = CNCModeSettingsDef::Get_Instance();

	if (cncDef) {
		AnnounceInterval = cncDef->Get_Announcement_Interval();
	} else {
		AnnounceInterval = 0;
	}

	//
	//	Setup the network ID
	//
	if (PlayerType == PLAYERTYPE_GDI) {
		Set_Network_ID (NETID_GDI_BASE_CONTROLLER);
	} else {
		WWASSERT(PlayerType == PLAYERTYPE_NOD);
		Set_Network_ID (NETID_NOD_BASE_CONTROLLER);
	}

	Check_Base_Power ();

	Set_Base_Destroyed( false );
	Set_Beacon_Destroyed_Base( false );

	return ;
}


////////////////////////////////////////////////////////////////
//
//	Initialize_Building_List
//
////////////////////////////////////////////////////////////////
void
BaseControllerClass::Initialize_Building_List (void)
{
	Reset_Building_List ();
	return ;
}


////////////////////////////////////////////////////////////////
//
//	Reset_Building_List
//
////////////////////////////////////////////////////////////////
void
BaseControllerClass::Reset_Building_List (void)
{
	//
	//	Simply reset the list
	//
	BuildingList.Delete_All ();
	return ;
}


////////////////////////////////////////////////////////////////
//
//	On_Building_Damaged
//
////////////////////////////////////////////////////////////////
void BaseControllerClass::On_Building_Damaged(BuildingGameObj* building)
{
	const BuildingGameObjDef& def = building->Get_Definition();

	// Annouce the damage report if we haven't done so recently.
	if (AnnounceInterval > 0) {
		if (COMBAT_STAR) {
			int playersTeam = COMBAT_STAR->Get_Player_Type();
			bool isAllied = (playersTeam == PlayerType);
		
			float seconds = TimeManager::Get_Total_Seconds();
			int elapsed = 0;

			if (isAllied) {
				elapsed = (int)(seconds - AnnouncedAlliedBldgDamageTime);
			} else {
				elapsed = (int)(seconds - AnnouncedEnemyBldgDamageTime);
			}
		
			if (elapsed >= AnnounceInterval) {
				Play_Announcement(def.Get_Damage_Report(playersTeam));

				if (isAllied) {
					AnnouncedAlliedBldgDamageTime = seconds;
				} else {
					AnnouncedEnemyBldgDamageTime = seconds;
				}
			}
		}
	}

	//	Notify the team that the base is under attack
	Notify_Team(BASE_UNDER_ATTACK, def.Get_Type());
}


////////////////////////////////////////////////////////////////
//
//	On_Building_Destroyed
//
////////////////////////////////////////////////////////////////
void BaseControllerClass::On_Building_Destroyed(BuildingGameObj* building)
{	
	const BuildingGameObjDef& def = building->Get_Definition();

	if (COMBAT_STAR) {
		int playersTeam = COMBAT_STAR->Get_Player_Type();
		Play_Announcement(def.Get_Destroy_Report(playersTeam));
	}

	//	Let the team know that a building was destroyed
	Notify_Team(BUILDING_DESTROYED, def.Get_Type ());

	//	Check a victory condition
	if (Are_All_Buildings_Destroyed()) {
		Set_Base_Destroyed(true);
	}
}


////////////////////////////////////////////////////////////////
//
//	On_Vehicle_Generated
//
////////////////////////////////////////////////////////////////
void
BaseControllerClass::On_Vehicle_Generated (VehicleGameObj *vehicle)
{
	//
	//	Find our refinery (if we have one)
	//
	BuildingGameObj* building = Find_Building(TYPE_REFINERY);

	if (building) {
		RefineryGameObj* refinery = building->As_RefineryGameObj();

		//
		//	Check to see if the refinery needs a harvester and if
		// the vehicle we just generated was a harvester.
		//
		int def_id = vehicle->Get_Definition().Get_ID();

		if (refinery->Needs_Harvester() && def_id == refinery->Get_Harvester_Def_ID()) {
			refinery->Set_Harvester_Vehicle(vehicle);
		}
	}

	return ;
}


void BaseControllerClass::On_Vehicle_Delivered(VehicleGameObj *vehicle)
{
	SoldierGameObj* thePlayer = COMBAT_STAR;
	bool isAllied = (thePlayer && (thePlayer->Get_Player_Type() == PlayerType));

	// Only the allied player who purchased the vehicle should hear this.
	if (isAllied) {
		// Play unit ready report for the current player.
		CNCModeSettingsDef* cncDef = CNCModeSettingsDef::Get_Instance();
		
		if (cncDef) {
			Play_Announcement(cncDef->Get_Unit_Ready_Report(PlayerType));
		}
	}
}


void BaseControllerClass::On_Vehicle_Damaged(VehicleGameObj* vehicle)
{
	// Annouce the damage report if we haven't done so recently.
	if (AnnounceInterval > 0) {
		if (COMBAT_STAR) {
			int playersTeam = COMBAT_STAR->Get_Player_Type();
			bool isAllied = (playersTeam == PlayerType);
		
			float seconds = TimeManager::Get_Total_Seconds();
			int elapsed = 0;

			if (isAllied) {
				elapsed = (int)(seconds - AnnouncedAlliedBldgDamageTime);
			} else {
				elapsed = (int)(seconds - AnnouncedEnemyBldgDamageTime);
			}
		
			if (elapsed >= AnnounceInterval) {
				const VehicleGameObjDef& def = vehicle->Get_Definition();
				Play_Announcement(def.Get_Damage_Report(playersTeam));

				if (isAllied) {
					AnnouncedAlliedBldgDamageTime = seconds;
				} else {
					AnnouncedEnemyBldgDamageTime = seconds;
				}
			}
		}
	}
}


void BaseControllerClass::On_Vehicle_Destroyed(VehicleGameObj* vehicle)
{
	if (COMBAT_STAR) {
		const VehicleGameObjDef& def = vehicle->Get_Definition();
		int playersTeam = COMBAT_STAR->Get_Player_Type();
		Play_Announcement(def.Get_Destroy_Report(playersTeam));
	}
}


void BaseControllerClass::On_Beacon_Armed(BeaconGameObj* beacon)
{
	CNCModeSettingsDef* cncDef = CNCModeSettingsDef::Get_Instance();
		
	if (cncDef) {
		bool isNuke = beacon->Get_Definition().Is_Nuke();

		if (COMBAT_STAR != NULL) {
			int team = COMBAT_STAR->Get_Player_Type();

			if (isNuke) {
				int report = cncDef->Get_Nuke_Beacon_Deployed_Report(team);
				Play_Announcement(report);
			} else {
				int report = cncDef->Get_Ion_Beacon_Deployed_Report(team);
				Play_Announcement(report);
			}
		}
	}
}


void BaseControllerClass::On_Beacon_Disarmed(BeaconGameObj* beacon)
{
	CNCModeSettingsDef* cncDef = CNCModeSettingsDef::Get_Instance();
		
	if (cncDef) {
		bool isNuke = beacon->Get_Definition().Is_Nuke();
		if (COMBAT_STAR != NULL) {
			int team = COMBAT_STAR->Get_Player_Type();

			if (isNuke) {
				int report = cncDef->Get_Nuke_Beacon_Disarmed_Report(team);
				Play_Announcement(report);
			} else {
				int report = cncDef->Get_Ion_Beacon_Disarmed_Report(team);
				Play_Announcement(report);
			}
		}
	}
}


void BaseControllerClass::On_Beacon_Warning(BeaconGameObj* beacon)
{
	CNCModeSettingsDef* cncDef = CNCModeSettingsDef::Get_Instance();
		
	if (cncDef) {
		bool isNuke = beacon->Get_Definition().Is_Nuke();
		if (COMBAT_STAR != NULL) {
			int team = COMBAT_STAR->Get_Player_Type();

			if (isNuke) {
				int report = cncDef->Get_Nuke_Beacon_Warning_Report(team);
				Play_Announcement(report);
			} else {
				int report = cncDef->Get_Ion_Beacon_Warning_Report(team);
				Play_Announcement(report);
			}
		}
	}
}


////////////////////////////////////////////////////////////////
//
//	Are_All_Buildings_Destroyed
//
////////////////////////////////////////////////////////////////
bool
BaseControllerClass::Are_All_Buildings_Destroyed (void)
{
	bool retval = true;

	//
	//	Are all the buildings destroyed?
	//
	for (int index = 0; index < BuildingList.Count (); index ++) {
		BuildingGameObj *building = BuildingList[index];
		
		//
		//	If this building has any health left, then the base is not
		// completely destroyed.
		//
		if (building->Is_Destroyed () == false) {
			retval = false;
			break;
		}
	}

	return retval;
}


////////////////////////////////////////////////////////////////
//
//	Notify_Team
//
////////////////////////////////////////////////////////////////
void
BaseControllerClass::Notify_Team (Notification event, BuildingType type)
{	
	return ;
}


////////////////////////////////////////////////////////////////
//
//	Check_Base_Power
//
////////////////////////////////////////////////////////////////
void
BaseControllerClass::Check_Base_Power (void)
{
	bool is_powered = true;

	//	Search through each building
	int count = BuildingList.Count();

	for (int index = 0; index < count; ++index) {
		BuildingGameObj* building = BuildingList[index];

		//	Is this a power-plant?
		if (building->Get_Definition().Get_Type() == TYPE_POWER_PLANT) {
			//	The base is NOT powered if all power-plants are destoryed.
			//	However, the base IS powered if there are NO power plants
			if (BuildingList[index]->Is_Destroyed()) {
				is_powered = false;
			} else {
				is_powered = true;
				break;
			}
		}
	}

	//	Change the powered state of the base
	Power_Base(is_powered);	
}


////////////////////////////////////////////////////////////////
//
//	Power_Base
//
////////////////////////////////////////////////////////////////
void
BaseControllerClass::Power_Base (bool onoff)
{
	if (CombatManager::I_Am_Server () == false) {
		return ;
	}

	if (BasePowered != onoff) {
		Set_Base_Powered( onoff );
		Set_Operation_Time_Factor( BasePowered ? 1.0F : 2.0F );

		//
		//	Switch the powered state of each building
		//
		for (int index = 0; index < BuildingList.Count (); index ++) {
			BuildingGameObj *building = BuildingList[index];

			//
			//	Only change the power state of this building if it makes sense
			//
			if ((BasePowered == false) || (building->Is_Destroyed () == false)) {
				building->Enable_Power (BasePowered);
			}
		}
	
		// Notify that the base 
		if (!BasePowered) {
			const CNCModeSettingsDef* def = CNCModeSettingsDef::Get_Instance();

			if (def) {
				Play_Announcement(def->Get_Power_Offline_Report(PlayerType));
			}
		}
	}

	return ;
}


////////////////////////////////////////////////////////////////
//
//	Set_Operation_Time_Factor
//
////////////////////////////////////////////////////////////////
void
BaseControllerClass::Set_Operation_Time_Factor (float factor)	
{ 
	OperationTimeFactor = factor;

	Set_Object_Dirty_Bit( NetworkObjectClass::BIT_OCCASIONAL, true );
}


////////////////////////////////////////////////////////////////
//
//	Set_Base_Powered
//
////////////////////////////////////////////////////////////////
void
BaseControllerClass::Set_Base_Powered (bool onoff)	
{ 
	BasePowered = onoff;

	Set_Object_Dirty_Bit( NetworkObjectClass::BIT_OCCASIONAL, true );
}


////////////////////////////////////////////////////////////////
//
//	Set_Can_Generate_Soldiers
//
////////////////////////////////////////////////////////////////
void
BaseControllerClass::Set_Can_Generate_Soldiers (bool onoff)	
{ 
	CanGenerateSoldiers = onoff;

	Set_Object_Dirty_Bit( NetworkObjectClass::BIT_OCCASIONAL, true );
}


////////////////////////////////////////////////////////////////
//
//	Set_Can_Generate_Vehicles
//
////////////////////////////////////////////////////////////////
void
BaseControllerClass::Set_Can_Generate_Vehicles (bool onoff)	
{ 
	CanGenerateVehicles = onoff;

	Set_Object_Dirty_Bit( NetworkObjectClass::BIT_OCCASIONAL, true );
}


////////////////////////////////////////////////////////////////
//
//	Request_Harvester
//
////////////////////////////////////////////////////////////////
void
BaseControllerClass::Request_Harvester (int def_id)
{
	if (CombatManager::I_Am_Server () == false) {
		return ;
	}

	//
	//	Find our vehicle factory
	//
	BuildingGameObj *building = Find_Building (TYPE_VEHICLE_FACTORY);
	if (building != NULL) {
		VehicleFactoryGameObj *factory = building->As_VehicleFactoryGameObj ();

		//
		//	If we have a vehicle factory that isn't busy, then start building a harvester
		//
		if (factory->Is_Available ()) {			
			float time = 8.0F;
			factory->Request_Vehicle (def_id, time * OperationTimeFactor);
		}
	} else {

		//	Find our refinery (if we have one)
		//
		BuildingGameObj *building = Find_Building (TYPE_REFINERY);
		if (building != NULL) {
			RefineryGameObj *refinery = building->As_RefineryGameObj ();

			//
			//	If there is no vehicle factory in this level, then
			// try to find a spawner that will create this type of harvester
			// for us.
			//
			DynamicVectorClass<SpawnerClass *> spawner_list = SpawnManager::Get_Spawner_List ();
			for (int index = 0; index < spawner_list.Count (); index ++) {
				SpawnerClass *spawner = spawner_list[index];
				if (spawner != NULL && spawner->Can_Spawn_Object (def_id)) {

					//
					//	Try to spawn the harvester
					//
					PhysicalGameObj *new_obj = spawner->Spawn_Object (def_id);
					if (new_obj != NULL && new_obj->As_VehicleGameObj () != NULL) {
						refinery->Set_Harvester_Vehicle (new_obj->As_VehicleGameObj ());
						break;
					}
				}
			}
		}
	}

	return ;
}


////////////////////////////////////////////////////////////////
//
//	Check_Radar
//
////////////////////////////////////////////////////////////////
void
BaseControllerClass::Check_Radar (void)
{
	bool enable_radar = false;

	//
	//	Search through each building
	//
	for (int index = 0; index < BuildingList.Count (); index ++) {
		BuildingGameObj *building = BuildingList[index];

		//
		//	Is this a com center?
		//
		if (building->Get_Definition ().Get_Type () == TYPE_COM_CENTER) {

			//
			//	The base has radar if there is even one active com-center
			//
			if (BuildingList[index]->Is_Destroyed () == false) {
				enable_radar = true;
				break;
			}
		}
	}

	//
	//	Update the radar
	//
	Enable_Radar (enable_radar);
	return ;
}


////////////////////////////////////////////////////////////////
//
//	Think
//
////////////////////////////////////////////////////////////////
void
BaseControllerClass::Think (void)
{
	return ;
}


////////////////////////////////////////////////////////////////
//
//	Find_Building
//
////////////////////////////////////////////////////////////////
BuildingGameObj *
BaseControllerClass::Find_Building (BuildingConstants::BuildingType type)
{
	BuildingGameObj *building = NULL;

	//
	//	Search through each building
	//
	for (int index = 0; index < BuildingList.Count (); index ++) {
	
		//
		//	Is this the type of building we are looking for?
		//
		if (BuildingList[index]->Get_Definition ().Get_Type () == type) {
			building = BuildingList[index];
			break;
		}
	}
	
	return building;
}


////////////////////////////////////////////////////////////////
//
//	Distribute_Funds_To_Each_Teammate
//
////////////////////////////////////////////////////////////////
void
BaseControllerClass::Distribute_Funds_To_Each_Teammate (int funds)
{
	//
	//	Only let the server assign money
	//
	if (CombatManager::I_Am_Server () == false) {
		return ;
	}

	//
	//	Loop over all the players in the game
	//
	SList<SoldierGameObj> *list	= GameObjManager::Get_Star_Game_Obj_List ();
	SLNode<SoldierGameObj> *node	= NULL;
	for (node = list->Head(); node != NULL; node = node->Next()) {
		SoldierGameObj *player = node->Data();
		
		//
		//	Is this a player on our team?
		//
		if (	player != NULL && 
				(player->Get_Player_Type () == PlayerType) )
		{
			//
			//	Get the data associated with this player
			//
			PlayerDataClass *player_data = player->Get_Player_Data ();
			if (player_data != NULL) {

				//
				//	Add the money to this player's total
				//
				player_data->Increment_Money (funds);
			}
		}
	}

	return ;
}


/*
////////////////////////////////////////////////////////////////
//
//	Deposit_Funds
//
////////////////////////////////////////////////////////////////
void
BaseControllerClass::Deposit_Funds (int funds)
{
	//
	//	Only let the server assign money
	//
	if (CombatManager::I_Am_Server () == false) {
		return ;
	}

	DynamicVectorClass<SoldierGameObj *> team_players;
	
	//
	//	Loop over all the players in the game
	//
	SList<SoldierGameObj> *list	= GameObjManager::Get_Star_Game_Obj_List ();
	SLNode<SoldierGameObj> *node	= NULL;
	for (node = list->Head(); node != NULL; node = node->Next()) {
		SoldierGameObj *player = node->Data();
		
		//
		//	Is this a player on our team?
		//
		if (	player != NULL && 
				(player->Get_Player_Type () == PLAYERTYPE_GDI && Team == TEAM_GDI) ||
				(player->Get_Player_Type () == PLAYERTYPE_NOD && Team == TEAM_NOD))
		{
			//
			//	Add the player to our list
			//
			team_players.Add (player);
		}
	}

	if (team_players.Count () > 0) {

		//
		//	Now distribute the funds to each player
		//
		int funds_per_player = funds / team_players.Count ();
		for (int index = 0; index < team_players.Count (); index ++) {		
			PlayerDataClass *player_data = team_players[index]->Get_Player_Data ();
			if (player_data != NULL) {

				//
				//	Add the money to this player's total
				//
				player_data->Increment_Money (funds_per_player);
				funds -= funds_per_player;
			}
		}

		//
		//	If there is any money left over, then give it to a random teammate
		//
		if (funds > 0) {
			index = FreeRandom.Get_Int ( team_players.Count () );

			PlayerDataClass *player_data = team_players[index]->Get_Player_Data ();
			if (player_data != NULL) {

				//
				//	Add the money to this player's total
				//
				player_data->Increment_Money (funds);
			}
		}
	}

	return ;
}
*/


////////////////////////////////////////////////////////////////
//
//	Find_Base
//
////////////////////////////////////////////////////////////////
BaseControllerClass *
BaseControllerClass::Find_Base ( int player_type )
{
	BaseControllerClass *base = NULL;

	//
	//	Try to find a base of the appropriate team in our list
	//
	for (int index = 0; index < BASE_COUNT; index ++) {
		if (CurrentBases[index] != NULL && CurrentBases[index]->Get_Player_Type () == player_type ) {
			base = CurrentBases[index];
			break;
		}
	}

	return base;
}


////////////////////////////////////////////////////////////////
//
//	Find_Base_For_Star
//
////////////////////////////////////////////////////////////////
BaseControllerClass *
BaseControllerClass::Find_Base_For_Star (void)
{
	int player_type = PLAYERTYPE_GDI;
	if ( COMBAT_STAR != NULL ) {
		player_type = COMBAT_STAR->Get_Player_Type ();
	}

	return Find_Base (player_type);
}


////////////////////////////////////////////////////////////////
//
//	Set_Base_Destroyed
//
////////////////////////////////////////////////////////////////
void
BaseControllerClass::Set_Base_Destroyed ( bool onoff )
{
	IsBaseDestroyed = onoff;

	Set_Object_Dirty_Bit( NetworkObjectClass::BIT_OCCASIONAL, true );
}


////////////////////////////////////////////////////////////////
//
//	Destroy_Base
//
////////////////////////////////////////////////////////////////
void
BaseControllerClass::Destroy_Base (void)
{
	for (int index = 0; index < BuildingList.Count (); index ++) {
		
		//
		//	Destroy this building
		//
		BuildingGameObj *building = BuildingList[index];
		building->Set_Normalized_Health (0);
	}

	//
	//	Disable everything
	//
	Set_Base_Powered( false );
	Set_Can_Generate_Soldiers( false );
	Set_Can_Generate_Vehicles( false );
	Set_Base_Destroyed( true );
	Set_Operation_Time_Factor( 2.0F );
	return ;
}


////////////////////////////////////////////////////////////////
//
//	Set_Beacon_Destroyed_Base
//
////////////////////////////////////////////////////////////////
void
BaseControllerClass::Set_Beacon_Destroyed_Base ( bool onoff )
{
	DidBeaconDestroyBase = onoff;

	Set_Object_Dirty_Bit( NetworkObjectClass::BIT_OCCASIONAL, true );
}


////////////////////////////////////////////////////////////////
//
//	Add_Building
//
////////////////////////////////////////////////////////////////
void
BaseControllerClass::Add_Building (BuildingGameObj *building)
{
	//
	//	Add the building to our list (if its not already there)
	//
	if (building != NULL) {
		if (BuildingList.ID (building) == -1) {

			//
			//	Add the building to our list
			//			
			building->CnC_Initialize (this);
			BuildingList.Add (building);

			//
			//	Find the beacon zone if this is the first building added...
			//
			if (BuildingList.Count () == 1) {
				
				//
				//	Get the position of the first building in our list
				//
				Vector3 pos;
				BuildingList[0]->Get_Position (&pos);

				//
				//	Find the closest beacon zone to the building
				//
				ScriptZoneGameObj *zone = NULL;
				zone = ScriptZoneGameObj::Find_Closest_Zone (pos, ZoneConstants::TYPE_BEACON);
				if (zone != NULL) {
					BeaconZone = zone->Get_Bounding_Box ();

					//
					//	Get rid of the zone (if the game doesn't need it anymore)
					//
					if (zone->Get_Observers ().Count () == 0) {
						zone->Set_Delete_Pending();
					}
				}
			}

			//
			//	Update the state of the base
			//
			Check_Base_Power ();
			Check_Radar ();
		}
	}

	return ;
}


////////////////////////////////////////////////////////////////
//
//	Import_Occasional
//
////////////////////////////////////////////////////////////////
void
BaseControllerClass::Import_Occasional (BitStreamClass &packet)
{
	//
	//	Read the state variables from the server
	//
	packet.Get (OperationTimeFactor);

	bool wasBasePowered = BasePowered;
	packet.Get(BasePowered);

	packet.Get(CanGenerateSoldiers);
	packet.Get(CanGenerateVehicles);	
	packet.Get(IsBaseDestroyed);
	packet.Get(DidBeaconDestroyBase);

	bool is_radar_enabled = packet.Get(is_radar_enabled);
	Enable_Radar(is_radar_enabled);

	// If the base was powered but now is not then report that
	// power is offline.
	if (wasBasePowered && !BasePowered) {
		const CNCModeSettingsDef* cncDef = CNCModeSettingsDef::Get_Instance();

		if (cncDef) {
			Play_Announcement(cncDef->Get_Power_Offline_Report(PlayerType));
		}
	}
}


////////////////////////////////////////////////////////////////
//
//	Export_Occasional
//
////////////////////////////////////////////////////////////////
void
BaseControllerClass::Export_Occasional (BitStreamClass &packet)
{
	//
	//	Send the state variables to the client
	//
	packet.Add (OperationTimeFactor);
	packet.Add (BasePowered);
	packet.Add (CanGenerateSoldiers);
	packet.Add (CanGenerateVehicles);	
	packet.Add (IsBaseDestroyed);
	packet.Add (DidBeaconDestroyBase);
	packet.Add (IsRadarEnabled);
}


////////////////////////////////////////////////////////////////
//
//	Enable_Radar
//
////////////////////////////////////////////////////////////////
void
BaseControllerClass::Enable_Radar (bool onoff)
{
	if (IsRadarEnabled != onoff) {
		IsRadarEnabled = onoff;
		
		//
		//	Check to see if the current player belongs to this base
		//
		if (	COMBAT_STAR != NULL && 
				(COMBAT_STAR->Get_Player_Type () == PlayerType) )
		{
			//
			//	Show or hide the radar
			//
			RadarManager::Set_Hidden (!IsRadarEnabled);
		}

		Set_Object_Dirty_Bit( NetworkObjectClass::BIT_OCCASIONAL, true );
	}

	return ;
}


////////////////////////////////////////////////////////////////
//
//	Get_Harvester_Vehicle
//
////////////////////////////////////////////////////////////////
VehicleGameObj *
BaseControllerClass::Get_Harvester_Vehicle (void)
{
	VehicleGameObj *retval = NULL;
	
	//
	//	Find our refinery (if we have one)
	//
	BuildingGameObj *building = Find_Building (TYPE_REFINERY);
	if (building != NULL) {
		RefineryGameObj *refinery = building->As_RefineryGameObj ();

		//
		//	Return the harvester to the caller
		//
		retval = refinery->Get_Harvester_Vehicle ();
	}

	return retval;
}


void BaseControllerClass::Play_Announcement(int text_id)
{
	if (text_id == 0) {
		return;
	}

	// Lookup the translation object from the strings database
	TDBObjClass* translate_obj = TranslateDBClass::Find_Object(text_id);

	if (translate_obj) {
		// Display the text on the screen
		const WCHAR* string = translate_obj->Get_String();

		if (string) {
			CombatManager::Get_Message_Window()->Add_Message(string, Vector3(1, 1, 1));
		}		

		// Play the sound effect
		int soundID = (int)translate_obj->Get_Sound_ID();

		if (soundID > 0) {
			WWAudioClass::Get_Instance()->Create_Instant_Sound(soundID, Matrix3D(1));
		}
	}
}
