//Copyright (C) 2007 SiegeLord
//See ReadMe.txt and License.txt for copying information

#include "weapon.h"
#include "shipregistry.h"
#include "ship.h"

#include "rocket.h"
#include "plasma.h"
#include "ionbeam.h"

#include "sounds.h"

extern SObjectEx* g_obRootObject;

void SRocketLauncher::Engage(vector2d& target, int ship)
{
	target_loc = target;
	target_ship_id = ship;
}

void SRocketLauncher::DisEngage()
{
	target_ship_id = -2;
}

void SRocketLauncher::Draw()
{
	SetModelMatrix(net_transform);

	DrawModeMask();

	DrawBitmap(image, -image->w / 2, -image->h / 2, -10);

	SetModelMatrix(g_trIdentity);
	DrawModeSolid();
}

int SRocketLauncher::Handle()
{
	timer += g_fDelta;

	float angle = 0;
	if(target_ship_id == -2)
		angle = slot->rotation;
	else//we actually have a target!
	{
		if(target_ship_id > -1)
		{
			SShip* ship = GetShipByID(target_ship_id);
			if(ship)
				target_loc = ship->GetGlobalPosition();
			else//target was lost
				target_ship_id = -2;
		}
		if(target_ship_id > -2)
		{
			vector2d pos = GetGlobalPosition();
			vector2d dest = target_loc - pos;

			angle = atan2f(dest.y, dest.x);//find the angle to target
			angle = SubtractAngles(angle, parent->rotation);//make it local
			if((timer > reload_time) && (dest.GetLengthSQ() < range * range))//see if we can fire
			{
				vector2d dir = g_vecI;
				net_transform.RotateVector(&dir);

				pos = pos + dir * 5;//location of the exiting rocket

				dir *= 10.0f;

				SRocket* rocket = CreateRocket(g_obRootObject, pos, dir, target_loc, target_ship_id);
				rocket->min_damage = min_damage;
				rocket->max_damage = max_damage;
				timer = 0;
				CreateRocketFireSound(g_obRootObject, this);
			}
		}
	}

	float diff = SubtractAngles(angle, rotation);

	if(fabs(2 * rotation_acc * diff) < rotation_vel * rotation_vel)
	{
		ChangeVar(rotation_vel, 0.0f, rotation_acc * g_fDelta);
	}
	else
	{
		if(diff > 0)
		{
			ChangeVar(rotation_vel, max_rotation_vel, rotation_acc * g_fDelta);
		}
		else
		{
			ChangeVar(rotation_vel, -max_rotation_vel, rotation_acc * g_fDelta);
		}
	}

	SetRotation(rotation + g_fDelta * rotation_vel);
	return 0;
}

SRocketLauncher* CreateRocketLauncher(SObject* parent, SWeaponSlot* slot)
{
	SRocketLauncher* weapon = new SRocketLauncher();
	InitObject(weapon, parent);

	weapon->max_rotation_vel = 1.0f;
	weapon->rotation_vel = 0.0f;
	weapon->rotation_acc = 0.1f;
	weapon->slot = slot;
	weapon->range = 450;
	weapon->SetPosition(slot->position.x, slot->position.y);
	weapon->SetRotation(slot->rotation);

	weapon->image = FindBitmap("rocket_turret.tga");
	weapon->min_damage = 10.0f;
	weapon->max_damage = 10.0f;

	weapon->reload_time = 6.0f;
	weapon->timer = weapon->reload_time;

	slot->weapon = weapon;

	return weapon;
}

////////////////////Plasma

void SPlasmaLauncher::Engage(vector2d& target, int ship)
{
	target_loc = target;
	target_ship_id = ship;
}

void SPlasmaLauncher::DisEngage()
{
	target_ship_id = -2;
}

void SPlasmaLauncher::Draw()
{
	SetModelMatrix(net_transform);

	DrawModeMask();

	DrawBitmap(image, -image->w / 2, -image->h / 2, -10);

	SetModelMatrix(g_trIdentity);
	DrawModeSolid();
}

int SPlasmaLauncher::Handle()
{
	timer += g_fDelta;

	float angle = 0.0f;
	if(target_ship_id == -2)
		angle = slot->rotation;
	else//we actually have a target!
	{
		if(target_ship_id > -1)
		{
			SShip* ship = GetShipByID(target_ship_id);
			if(ship)
				target_loc = ship->GetGlobalPosition();
			else//target was lost
				target_ship_id = -2;
		}
		if(target_ship_id > -2)
		{
			vector2d pos = GetGlobalPosition();
			vector2d dest = target_loc - pos;

			angle = atan2f(dest.y, dest.x);//find the angle to target
			angle = SubtractAngles(angle, parent->rotation);//make it local
		}
	}

	float diff = SubtractAngles(angle, rotation);

	if(fabs(diff) > 0.01)
	{
		if(fabs(2 * rotation_acc * diff) < rotation_vel * rotation_vel)
		{
			ChangeVar(rotation_vel, 0.0f, rotation_acc * g_fDelta);
		}
		else
		{
			if(diff > 0)
			{
				ChangeVar(rotation_vel, max_rotation_vel, rotation_acc * g_fDelta);
			}
			else
			{
				ChangeVar(rotation_vel, -max_rotation_vel, rotation_acc * g_fDelta);
			}
		}
	}
	else if(target_ship_id > -2)//we fire
	{
		if(fabs(2 * rotation_acc * diff) < rotation_vel * rotation_vel)
		{
			ChangeVar(rotation_vel, 0.0f, rotation_acc * g_fDelta);
		}
		vector2d pos = GetGlobalPosition();
		vector2d dest = target_loc - pos;

		if((timer > reload_time) && (dest.GetLengthSQ() < range * range))//see if we can fire
		{
			vector2d dir = g_vecI;
			net_transform.RotateVector(&dir);

			pos = pos + dir * 5;//location of the exiting projectile

			dir *= 150.0f;

			SPlasma* plasma = CreatePlasma(g_obRootObject, pos, dir, target_loc, target_ship_id);
			plasma->min_damage = min_damage;
			plasma->max_damage = max_damage;
			timer = 0;
			CreatePlasmaFireSound(g_obRootObject, this);
		}
	}
	else
	{
		if(fabs(2 * rotation_acc * diff) < rotation_vel * rotation_vel)
		{
			ChangeVar(rotation_vel, 0.0f, rotation_acc * g_fDelta);
		}
	}

	SetRotation(rotation + g_fDelta * rotation_vel);
	return 0;
}

SPlasmaLauncher* CreatePlasmaLauncher(SObject* parent, SWeaponSlot* slot)
{
	SPlasmaLauncher* weapon = new SPlasmaLauncher();
	InitObject(weapon, parent);

	weapon->max_rotation_vel = 1.0f;
	weapon->rotation_vel = 0.0f;
	weapon->rotation_acc = 0.5f;
	weapon->slot = slot;
	weapon->range = 300;
	weapon->min_damage = 10.0f;
	weapon->max_damage = 10.0f;
	weapon->SetPosition(slot->position.x, slot->position.y);
	weapon->SetRotation(slot->rotation);
	weapon->image = FindBitmap("plasma_turret.tga");

	weapon->reload_time = 4.0f;
	weapon->timer = weapon->reload_time;

	slot->weapon = weapon;

	return weapon;
}

//Ion Beam

void SIonBeamCannon::Engage(vector2d& target, int ship)
{
	target_loc = target;
	target_ship_id = ship;
}

void SIonBeamCannon::DisEngage()
{
	target_ship_id = -2;
}

void SIonBeamCannon::Draw()
{
	SetModelMatrix(net_transform);

	DrawModeMask();

	DrawBitmap(image, -image->w / 2, -image->h / 2, -10);

	SetModelMatrix(g_trIdentity);
	DrawModeSolid();
}

int SIonBeamCannon::Handle()
{
	for(list<SObject*>::iterator it = children.begin(); it != children.end(); it++)//we need to do this since the ion beams are parented to this... yet they can die
	{
		if((*it)->type >= objectex_type)
		{
			if(((SObjectEx*)(*it))->dead)
			{
				DestroyObject((*it));
				it = children.erase(it);
			}
		}
	}
	
	timer += g_fDelta;

	float angle = 0.0f;
	if(target_ship_id == -2)
		angle = slot->rotation;
	else//we actually have a target!
	{
		if(target_ship_id > -1)
		{
			SShip* ship = GetShipByID(target_ship_id);
			if(ship)
				target_loc = ship->GetGlobalPosition();
			else//target was lost
				target_ship_id = -2;
		}
		if(target_ship_id > -2)
		{
			vector2d pos = GetGlobalPosition();
			vector2d dest = target_loc - pos;

			angle = atan2f(dest.y, dest.x);//find the angle to target
			angle = SubtractAngles(angle, parent->rotation);//make it local
		}
	}

	float diff = SubtractAngles(angle, rotation);

	if(fabs(diff) > 0.01)
	{
		if(fabs(2 * rotation_acc * diff) < rotation_vel * rotation_vel)
		{
			ChangeVar(rotation_vel, 0.0f, rotation_acc * g_fDelta);
		}
		else
		{
			if(diff > 0)
			{
				ChangeVar(rotation_vel, max_rotation_vel, rotation_acc * g_fDelta);
			}
			else
			{
				ChangeVar(rotation_vel, -max_rotation_vel, rotation_acc * g_fDelta);
			}
		}
	}
	else if(target_ship_id > -2)//we can fire
	{
		if(fabs(2 * rotation_acc * diff) < rotation_vel * rotation_vel)
		{
			ChangeVar(rotation_vel, 0.0f, rotation_acc * g_fDelta);
		}
		vector2d pos = GetGlobalPosition();
		vector2d dest = target_loc - pos;

		if((timer > reload_time) && (dest.GetLengthSQ() < range * range))//see if we can fire
		{
			SIonBeam* beam = CreateIonBeam(this, this, dest.GetLength(), target_ship_id);
			beam->min_damage = min_damage;
			beam->max_damage = max_damage;
			timer = 0;
			CreateBeamFireSound(g_obRootObject, this);
		}
	}
	else
	{
		if(fabs(2 * rotation_acc * diff) < rotation_vel * rotation_vel)
		{
			ChangeVar(rotation_vel, 0.0f, rotation_acc * g_fDelta);
		}
	}


	SetRotation(rotation + g_fDelta * rotation_vel);
	return 0;
}

SIonBeamCannon* CreateIonBeamCannon(SObject* parent, SWeaponSlot* slot)
{
	SIonBeamCannon* weapon = new SIonBeamCannon();
	InitObject(weapon, parent);

	weapon->max_rotation_vel = 1.0f;
	weapon->rotation_vel = 0.0f;
	weapon->rotation_acc = 0.5f;
	weapon->slot = slot;
	weapon->range = 300;
	weapon->min_damage = 10.0f;
	weapon->max_damage = 10.0f;
	weapon->SetPosition(slot->position.x, slot->position.y);
	weapon->SetRotation(slot->rotation);
	weapon->image = FindBitmap("ion_turret.tga");

	weapon->reload_time = 4.0f;
	weapon->timer = weapon->reload_time;

	slot->weapon = weapon;

	return weapon;
}

