//--------------------------------------------------------------------------------------
// Copyright (C) 2008 http://shift.delblanco.es
//--------------------------------------------------------------------------------------
// SHIFT Videogame 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 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.
//--------------------------------------------------------------------------------------
// 3DObjWeapon.cpp
//--------------------------------------------------------------------------------------
#include "dxstdafx.h"
#include "3DObjWeapon.h"

#include "Player.h"
#include "3DSoundMng.h"

//--------------------------------------------------------------------------------------
// Variables Globales
//--------------------------------------------------------------------------------------
extern C3DSoundMng      *g_3DSoundMng;     // Instancia externa para manejar sonidos 3D (3DSoundMng.cpp)

//--------------------------------------------------------------------------------------
// Constructor
//--------------------------------------------------------------------------------------
C3DObjWeapon::C3DObjWeapon()
{
    m_pType = 0;
	m_pSndLaunch = NULL;
	m_pSndCrash = NULL;
	m_pSndEmpty = NULL;
	m_pDelay = 0.0f;
}

//--------------------------------------------------------------------------------------
// Destructor
//--------------------------------------------------------------------------------------
C3DObjWeapon::~C3DObjWeapon()
{
	// Liberamos sonidos
    if(m_pSndLaunch)	g_3DSoundMng->Destroy(m_pSndLaunch);
    if(m_pSndCrash)		g_3DSoundMng->Destroy(m_pSndCrash);
    if(m_pSndEmpty)		g_3DSoundMng->Destroy(m_pSndEmpty);
}

//--------------------------------------------------------------------------------------
// Inicializa el arma del vehículo
//--------------------------------------------------------------------------------------
bool C3DObjWeapon::initialize(C3DObjVehicle *Vehicle, LPCWSTR ObjectPath, int Type)
{
    // Almacenamos el objeto asociado
    m_pVehicle = Vehicle;
	m_pType = Type;

    // Función de la clase padre
	// Cuidado, aquí no le indicamos como padre el vehículo, ya que el arma será un objeto no dependiente en la jerarquía
    if(!C3DObject::initialize(NULL, ObjectPath))
        return false;

    // Se usará una nueva instancia de CXMLIO
    CXMLIO *myXMLIO = new CXMLIO;
    if(!myXMLIO) return false;

    // Tomamos los elementos específicos del arma
    if(myXMLIO->LoadFile(ObjectPath))
    {
        WCHAR value[MAX_STRING+1];

        // Sonidos adicionales del arma (nodo 'sound')
        if(myXMLIO->MoveSubElement(L"sound"))
        {
            // Lanzamiento (atributo 'launch')
            if(myXMLIO->GetAttribute(L"launch", value))
                m_pSndLaunch = g_3DSoundMng->Create(value, this);
            // Colisión (atributo 'crash')
            if(myXMLIO->GetAttribute(L"crash", value))
                m_pSndCrash = g_3DSoundMng->Create(value, this);
            // Vacío (atributo 'empty')
            if(myXMLIO->GetAttribute(L"empty", value))
                m_pSndEmpty = g_3DSoundMng->Create(value, this);

            myXMLIO->MoveParent();
        }
    }

    // Liberamos el parseador de XML
    SAFE_DELETE(myXMLIO);

	// Cambiamos el estado del arma
	m_pState = OBJWEAPON_FREE;

    return true;
}

//--------------------------------------------------------------------------------------
// Actualiza el arma del vehículo
//--------------------------------------------------------------------------------------
void C3DObjWeapon::update()
{
	// Si estamos en colisión
	if (m_pState == OBJWEAPON_COLLISION)
	{
		// Si no hemos llegado al límite
		if (m_pDelay < 1.0)
		{
			// Si es la primera vez, ajustamos los sistemas de partículas
			if (m_pDelay == 0.0f)
			{
				if (m_pParticles1) m_pParticles1->SetReleaseInterval(9999.0f);
				if (m_pParticles2) m_pParticles2->SetReleaseInterval(0.2f);
			}

			// Actualizamos los sistemas de partículas
			if (m_pParticles1) m_pParticles1->update();
			if (m_pParticles2) m_pParticles2->update();
		}

		// Si hemos llegado al límite, cambiamos el estado del arma
		else m_pState = OBJWEAPON_FREE;
	}

	// Acumulamos el tiempo desde la última actualización
	m_pDelay += DXUTGetElapsedTime();

	// Función de la clase padre
    C3DObject::update();
}

//--------------------------------------------------------------------------------------
// Para activar el sonido de lanzamiento del arma
//--------------------------------------------------------------------------------------
void C3DObjWeapon::playLaunch(bool loop, long volume, long frecuency)
{
	if(!m_pSndLaunch) return;

	m_pSndLaunch->Play(loop);
	if(volume)    m_pSndLaunch->setVolume(volume);
	if(frecuency) m_pSndLaunch->setFrecuency(frecuency);
}

//--------------------------------------------------------------------------------------
// Para activar el sonido de colisiones del arma
//--------------------------------------------------------------------------------------
void C3DObjWeapon::playCrash(bool loop, long volume, long frecuency)
{
	if(!m_pSndCrash) return;

	m_pSndCrash->Play(loop);
	if(volume)    m_pSndCrash->setVolume(volume);
	if(frecuency) m_pSndCrash->setFrecuency(frecuency);
}

//--------------------------------------------------------------------------------------
// Para activar el sonido de colisiones del arma
//--------------------------------------------------------------------------------------
void C3DObjWeapon::playEmpty(bool loop, long volume, long frecuency)
{
	if(!m_pSndEmpty) return;

	m_pSndEmpty->Play(loop);
	if(volume)    m_pSndEmpty->setVolume(volume);
	if(frecuency) m_pSndEmpty->setFrecuency(frecuency);
}

//--------------------------------------------------------------------------------------
// Manejador de colisión básica
//--------------------------------------------------------------------------------------
bool C3DObjWeapon::onQuickCollision(C3DObject *object)
{
	// Damos OBJWEAPON_TIME_ACTIVATE segundos antes de que afecte al propio vehículo
	if (object == m_pVehicle && m_pDelay < OBJWEAPON_TIME_ACTIVATE)
		return false;
	return true;
}

//--------------------------------------------------------------------------------------
// Manejador de colisión completa
//--------------------------------------------------------------------------------------
bool C3DObjWeapon::onFullCollision(C3DObject *object)
{
	// Reiniciamos el contador de tiempo
	m_pDelay = 0.0f;

	// Desactivamos el arma
	setEnabled(false);

	// Si choca contra un vehículo, tomamos el jugador asociado
	CPlayer *player = NULL;
	if (object->getCollision()->getIsVehicle())
		player = static_cast<C3DObjVehicle*>(object)->getPlayer();

	// Dependiendo del tipo de arma
	switch(m_pType)
	{
	case OBJWEAPON_ROCKET:
		// Restamos la vida al jugador
		if (player)
		{
			player->setHealth(max(player->getHealth()-OBJWEAPON_ROCKET_HEALTH, 0.0f));
			player->setHealthSecond(-OBJWEAPON_ROCKET_HEALTH);
		}
		break;
	case OBJWEAPON_MINE:
		// Restamos la vida al jugador
		if (player)
		{
			player->setHealth(max(player->getHealth()-OBJWEAPON_MINE_HEALTH, 0.0f));
			player->setHealthSecond(-OBJWEAPON_MINE_HEALTH);
		}
		// Incrementamos la fuerza de la colisión
		if (object->getPhysics()->getLSpeed() >= 0.0f)
			m_pPhysics->setLDirection(-*(object->getPhysics()->getLDirection()));
		else
			m_pPhysics->setLDirection(*(object->getPhysics()->getLDirection()));
		m_pPhysics->setLSpeed(50.0f);
		break;
	}

	// Activamos el sonido de colisión
	stopCrash();
	playCrash(false);

	// Cambiamos el estado del arma
	m_pState = OBJWEAPON_COLLISION;

	return true;
}

//--------------------------------------------------------------------------------------
// Función para cambiar el estado de procesamiento del arma, activado/desactivado
//--------------------------------------------------------------------------------------
void C3DObjWeapon::setEnabled(bool enabled)
{
	// Si estamos activando el arma
	if (enabled)
	{
		// Salimos si el arma está bloqueado
		if (m_pState != OBJWEAPON_FREE) return;

		// Según el tipo de arma
		switch(m_pType)
		{
			case OBJWEAPON_ROCKET:
			{
				// Ajustamos dirección y velocidad
				D3DXVECTOR3 *vp_aux = m_pVehicle->getPhysics()->getLDirection(); D3DXVECTOR3 v_aux = *vp_aux;
				m_pPhysics->setLDirection(v_aux);
				m_pPhysics->setLSpeed(max(m_pVehicle->getPhysics()->getLSpeed()/1.5f, 0.0f) + 40.0f);
				m_pPhysics->setASpeed(D3DXVECTOR3(0.0f, 0.0f, 0.0f));

				// Ajustamos posición
				m_pVehicle->getPosition(v_aux); v_aux.y = 2.0f;
				setPosition(v_aux);

				// Ajustamos rotación
				m_pVehicle->getRotation(v_aux); v_aux.y -= 1.5708f;
				setRotation(v_aux);

				// Restamos velocidad al vehículo
				m_pVehicle->getPhysics()->setLSpeed(m_pVehicle->getPhysics()->getLSpeed() - 10.0f);
				break;
			}
			case OBJWEAPON_MINE:
			{
				// Ajustamos velocidad
				m_pPhysics->setLSpeed(0.0f);
				m_pPhysics->setASpeed(D3DXVECTOR3(0.0f, 0.0f, 0.0f));

				// Ajustamos posición
				D3DXVECTOR3 v_aux;
				m_pVehicle->getPosition(v_aux); v_aux.y = 0.5f;
				setPosition(v_aux);

				// Ajustamos rotación
				m_pVehicle->getRotation(v_aux); v_aux.y -= 1.5708f;
				setRotation(v_aux);
				break;
			}
		}

		// Ajustamos los sistemas de partículas
		if (m_pParticles1) m_pParticles1->SetReleaseInterval(0.02f);
		if (m_pParticles2) m_pParticles2->SetReleaseInterval(9999.0f);

		// Activamos el sonido de lanzamiento
		stopLaunch();
		playLaunch(false);

		// Reseteamos el temporizador y cambiamos el estado del arma
		m_pDelay = 0.0f;
		m_pState = OBJWEAPON_LAUNCH;
	}

	// Función de la clase padre
    C3DObject::setEnabled(enabled);
}
