/*
**	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/harvester.cpp         $*
 *                                                                                             *
 *                       Author:: Patrick Smith                                                *
 *                                                                                             *
 *                     $Modtime:: 1/18/02 11:16p                                              $*
 *                                                                                             *
 *                    $Revision:: 11                                                          $*
 *                                                                                             *
 *---------------------------------------------------------------------------------------------*
 * Functions:                                                                                  *
 * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */

#include "harvester.h"
#include "vehicle.h"
#include "refinerygameobj.h"
#include "animcontrol.h"
#include "vehiclephys.h"


////////////////////////////////////////////////////////////////
//	Local constants
////////////////////////////////////////////////////////////////
enum
{
	ACTIONID_GOTO_TIBERIUM	= 1000,
	ACTIONID_DOCK,
};


////////////////////////////////////////////////////////////////
//
//	HarvesterClass
//
////////////////////////////////////////////////////////////////
HarvesterClass::HarvesterClass (void) :
	Refinery (NULL),
	DockLocation (0, 0, 0),
	DockEntrance (0, 0, 0),
	StateTimer (0),
	State (STATE_UNINITIALIZED),
	Vehicle (NULL),
	IsHarvesting (false)
{
	Set_ID (GameObjObserverManager::Get_Next_Observer_ID ());
	return ;
}


////////////////////////////////////////////////////////////////
//
//	~HarvesterClass
//
////////////////////////////////////////////////////////////////
HarvesterClass::~HarvesterClass (void)
{
	return ;
}


////////////////////////////////////////////////////////////////
//
//	Initialize
//
////////////////////////////////////////////////////////////////
void
HarvesterClass::Initialize (void)
{
	Go_Harvest ();
	return ;
}


////////////////////////////////////////////////////////////////
//
//	Go_Harvest
//
////////////////////////////////////////////////////////////////
void
HarvesterClass::Go_Harvest (void)
{
	//
	//	Bail if the vehicle pointer is invalid, or if the vehicle
	// isn't on the ground...
	//
	if (Vehicle == NULL || Vehicle->Peek_Vehicle_Phys ()->Is_In_Contact () == false) {
		return ;
	}

	State = STATE_GOING_TO_HARVEST;

	//
	//	Choose a random offset into the tiberium box
	//
	Vector3 rand_offset;
	rand_offset.X = WWMath::Random_Float (0, TiberiumRegion.Extent.X - 5);
	rand_offset.Y = WWMath::Random_Float (0, TiberiumRegion.Extent.Y - 5);
	rand_offset.Z = 0;

	//
	//	Tranform this random offset into a world space position
	//
	Vector3 rand_pos = TiberiumRegion.Center + (TiberiumRegion.Basis * rand_offset);
	
	//
	//	Setup an action to instruct the vehicle to goto that location
	//
	ActionParamsStruct parameters;
	parameters.Priority		= 99;
	parameters.ActionID		= ACTIONID_GOTO_TIBERIUM;
	parameters.ObserverID	= Get_ID ();
	parameters.Set_Movement (rand_pos, 1.0F, 1.0F);
	Vehicle->Get_Action ()->Goto (parameters);
	return ;
}


////////////////////////////////////////////////////////////////
//
//	Go_Unload_Tiberium
//
////////////////////////////////////////////////////////////////
void
HarvesterClass::Go_Unload_Tiberium (void)
{
	Play_Harvest_Animation (false);

	//
	//	Switch states
	//
	IsHarvesting	= false;
	State				= STATE_GOING_TO_UNLOAD;

	//
	//	Setup an action to instruct the vehicle to dock in its refinery
	//
	ActionParamsStruct parameters;
	parameters.Priority		= 99;
	parameters.ActionID		= ACTIONID_DOCK;
	parameters.ObserverID	= Get_ID ();
	parameters.Dock_Vehicle (DockLocation, DockEntrance);
	parameters.MoveSpeed		= 1.0F;
	Vehicle->Get_Action ()->Dock_Vehicle (parameters);
	return ;
}


////////////////////////////////////////////////////////////////
//
//	Unload_Tiberium
//
////////////////////////////////////////////////////////////////
void
HarvesterClass::Unload_Tiberium (void)
{
	Refinery->On_Harvester_Docked ();
	State = STATE_UNLOADING;
	return ;
}


////////////////////////////////////////////////////////////////
//
//	Harvest_Tiberium
//
////////////////////////////////////////////////////////////////
void
HarvesterClass::Harvest_Tiberium (void)
{
	//
	//	Reset the harvesting timer (if necessary)
	//
	if (IsHarvesting == false) {
		HarvestTimer = 15.0F;
		IsHarvesting = true;
	}

	//
	//	Harvest the tiberium for a few seconds
	//
	State			= STATE_HARVESTING;
	StateTimer	= WWMath::Random_Float (3.0F, 7.0F);
	
	//
	//	Start playing the harvest animation
	//
	Play_Harvest_Animation (true);
	return ;
}


////////////////////////////////////////////////////////////////
//
//	Action_Complete
//
////////////////////////////////////////////////////////////////
void
HarvesterClass::Action_Complete
(
	GameObject *				game_obj,
	int							action_id,
	ActionCompleteReason		complete_reason
)
{
	//
	//	Check to ensure the harvester successfully completed
	// its action...
	//
	if (complete_reason == ACTION_COMPLETE_NORMAL) {

		//
		//	Which action was completed?
		//
		if (action_id == ACTIONID_GOTO_TIBERIUM) {
			
			//
			//	Check to ensure we were going to harvest the
			// tiberium before actually start harvesting
			//
			if (State == STATE_GOING_TO_HARVEST) {
				Harvest_Tiberium ();
			}
		} else if (action_id == ACTIONID_DOCK) {
			Unload_Tiberium ();
		}
	}

	return ;
}


////////////////////////////////////////////////////////////////
//
//	Animation_Complete
//
////////////////////////////////////////////////////////////////
void
HarvesterClass::Animation_Complete
(
	GameObject *	game_obj,
	const char *	animation_name
)
{
	return ;
}


////////////////////////////////////////////////////////////////
//
//	Attach
//
////////////////////////////////////////////////////////////////
void
HarvesterClass::Attach (GameObject *game_obj)
{
	WWASSERT (game_obj != NULL);
	if (game_obj != NULL) {

		//
		//	See if this game object is a vehicle (it better be)
		//
		PhysicalGameObj *physical_obj = game_obj->As_PhysicalGameObj ();
		if (physical_obj != NULL) {
			Vehicle = physical_obj->As_VehicleGameObj ();
		}
	}

	return ;
}


////////////////////////////////////////////////////////////////
//
//	Detach
//
////////////////////////////////////////////////////////////////
void
HarvesterClass::Detach (GameObject * /*game_obj*/)
{
	//
	//	Remove ourselves from the refinery
	//
	if (Refinery != NULL) {
		Refinery->Set_Harvester (NULL);
	}

	Vehicle = NULL;
	return ;
}


////////////////////////////////////////////////////////////////
//
//	Think
//
////////////////////////////////////////////////////////////////
void
HarvesterClass::Think (void)
{
	if (IsHarvesting) {

		//
		//	If we are harvesting, check to see if its time to go unload
		// the tiberium.
		//
		HarvestTimer -= TimeManager::Get_Frame_Seconds ();
		if (HarvestTimer <= 0) {
			Go_Unload_Tiberium ();
		}
	}

	switch (State)
	{		
		case STATE_HARVESTING:
			
			//
			//	Check to see if we should harvest in a new location
			//
			StateTimer -= TimeManager::Get_Frame_Seconds ();
			if (StateTimer	<= 0) {
				Go_Harvest ();
			}

			break;
		
		case STATE_UNINITIALIZED:
			if (Vehicle != NULL) {
				Go_Harvest ();
			}
			break;

		case STATE_GOING_TO_HARVEST:
		case STATE_GOING_TO_UNLOAD:
		case STATE_UNLOADING:
		default:
			break;
	}

	return ;
}


////////////////////////////////////////////////////////////////
//
//	Stop
//
////////////////////////////////////////////////////////////////
void
HarvesterClass::Stop (void)
{
	//
	//	Stopt the harvester from moving
	//
	if (Vehicle != NULL) {
		Vehicle->Get_Action ()->Reset (100);
		Vehicle->Enable_Engine (false);
	}

	return ;
}


////////////////////////////////////////////////////////////////
//
//	Play_Harvest_Animation
//
////////////////////////////////////////////////////////////////
void
HarvesterClass::Play_Harvest_Animation (bool onoff)
{
	if (onoff) {

		//
		//	Play the animation looped...
		//
		Vehicle->Set_Animation (HarvestAnimationName, true);		

	} else {
		
		//
		//	Stop the animation
		//
		AnimControlClass *anim_control = Vehicle->Get_Anim_Control ();
		if (anim_control != NULL) {
			anim_control->Set_Animation( (const char *)NULL );
		}
	}

	return ;
}


////////////////////////////////////////////////////////////////
//
//	Custom
//
////////////////////////////////////////////////////////////////
void
HarvesterClass::Custom
(
	GameObject *	game_obj,
	int				type,
	int				param,
	GameObject *	sender
)
{
	//
	//	Are we backing into the docking bay?
	//
	if (type == CUSTOM_EVENT_DOCK_BACKING_IN) {
		Refinery->Play_Unloading_Animation (true);
	}

	return ;
}


void HarvesterClass::Damaged(GameObject* damaged, GameObject* killer, float amount)
{
	// Only report damage not heal
	if (amount > 0.0f) {
		VehicleGameObj* vehicle = static_cast<VehicleGameObj*>(damaged);
		assert(Vehicle == vehicle);

		// If the unit has been damaged to the point of being destroyed
		// then do not report the damaged event. A killed event will be sent
		// later.
		DefenseObjectClass* defense = vehicle->Get_Defense_Object();

		if (defense && (defense->Get_Health() <= 0.0f)) {
			return;
		}

		DamageableGameObj* damager = NULL;

		if (killer) {
			damager = killer->As_DamageableGameObj();
		}

		bool friendlyFire = (damager && (damager->Get_Player_Type() == vehicle->Get_Player_Type()));

		//	Notify the building
		if (!friendlyFire) {
			assert(Refinery != NULL);
			Refinery->On_Harvester_Damaged(vehicle);
		}
	}
}


void HarvesterClass::Destroyed(GameObject* destroyed)
{
	VehicleGameObj* vehicle = static_cast<VehicleGameObj*>(destroyed);
	assert(Vehicle == vehicle);
	Refinery->On_Harvester_Destroyed(vehicle);
}
