//--------------------------------------------------------------------------------------
// 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.
//--------------------------------------------------------------------------------------
/// \file 3DObjVehicle.h
/// Para manejar los vehículos de la escena.
/// Este módulo ofrece un tratamiento específico a los objetos de tipo vehículo
//--------------------------------------------------------------------------------------
#pragma once
#ifndef __C3DOBJVEHICLE_H__
#define __C3DOBJVEHICLE_H__

//--------------------------------------------------------------------------------------
// Ficheros de cabecera
//--------------------------------------------------------------------------------------
#include "3DObject.h"
#include "3DPhyVehicle.h"
class C3DObjWeapon;
class CPlayer;

//--------------------------------------------------------------------------------------
// Constantes
//--------------------------------------------------------------------------------------
/// Directorio dónde se deben buscar los ficheros descriptivos de los vehículos del juego
#define     OBJVEHICLE_DIR                  L".\\models\\vehicles\\"

// Valores por defecto para las características del vehículo
#define     OBJVEHICLE_MAX_CAPACITY         20.0f
#define     OBJVEHICLE_MAX_HEALTH           50.0f
#define     OBJVEHICLE_MAX_SPEED            20.0f
#define     OBJVEHICLE_MAX_ACCELERATION     60.0f
#define     OBJVEHICLE_MAX_TURN_BODYZ       0.06f
#define     OBJVEHICLE_MAX_TURN_BODYX       0.1f
#define     OBJVEHICLE_TURN_BODYZ           2.0f
#define     OBJVEHICLE_TURN_BODYX           2.0f
#define     OBJVEHICLE_RECOV_BODYZ          2.0f
#define     OBJVEHICLE_RECOV_BODYX          2.0f
#define     OBJVEHICLE_TURN                 0.055f
#define     OBJVEHICLE_MAX_TURN_WHEELY      0.55f
#define     OBJVEHICLE_TURN_WHEELZ          3.6f
#define     OBJVEHICLE_HANDBRAKE_POWER      10.0f
#define     OBJVEHICLE_WHEEL_DISTANCE       2.0f
#define     OBJVEHICLE_CAMERAY				20.0f

// Máximo giro acumulado que se permite
#define     OBJVEHICLE_MAX_ACUM_TURN        1.5f

//--------------------------------------------------------------------------------------
/// Clase hija de C3DObject para para manejar los vehículos de la escena.
//--------------------------------------------------------------------------------------
class C3DObjVehicle : public C3DObject
{

private:  // Campos miembro

	CPlayer							*m_pPlayer;			  ///< Puntero al jugador asociado con el vehículo

    LPWSTR                          m_awName;             ///< Nombre del vehículo
    LPWSTR                          m_awDescription;      ///< Descripción textual del vehículo
    float                           m_iMaxCapacity;       ///< Capacidad máxima del vehículo
    float                           m_iMaxHealth;         ///< Vida máxima del vehículo
    float                           m_fMaxSpeed;          ///< Velocidad máxima del vehículo
    float                           m_fMaxAcceleration;   ///< Aceleración máxima del vehículo

	bool							m_bUpdate;            ///< Flag que indica si el objeto está actualizado (para forzar el primer update)
    C3DPhyVehicle                   *m_pPhyVehicle;       ///< Sistema físico asociado al vehículo

    float                           m_fMaxTurnBodyZ;      ///< Máxima rotación para la suspensión frontal
    float                           m_fMaxTurnBodyX;      ///< Máxima rotación para la suspensión lateral
    float                           m_fTurnBodyZ;         ///< Dureza para la suspensión frontal
    float                           m_fTurnBodyX;         ///< Dureza para la suspensión lateral
    float                           m_fRecvBodyZ;         ///< Recuperación para la suspensión frontal
    float                           m_fRecvBodyX;         ///< Recuperación para la suspensión frontal
    float                           m_fTurn;              ///< Giro del vehículo
    float                           m_fMaxTurnWheelY;     ///< Giro máximo de las ruedas en Y
    float                           m_fTurnWheelZ;        ///< Giro máximo de las ruedas en Z
    float                           m_fWheelDist;         ///< Longitud del centro del vehículo al tren trasero o delantero
	float                           m_fCameraY;           ///< Altura de la cámara en el modo de vista interior

    C3DObject                       *m_pBody;             ///< Puntero al fuselaje del vehículo
    C3DObject                       *m_pFRWheel;          ///< Puntero a la 'Front Right Wheel' del vehículo
    C3DObject                       *m_pFLWheel;          ///< Puntero a la 'Front Left Wheel' del vehículo
    C3DObject                       *m_pRRWheel;          ///< Puntero a la 'Rear Right Wheel' del vehículo
    C3DObject                       *m_pRLWheel;          ///< Puntero a la 'Rear Left Wheel' del vehículo

    C3DObjWeapon                    *m_pRocket;           ///< Puntero al cohete del vehículo
    C3DObjWeapon                    *m_pMine;             ///< Puntero a la mina del vehículo

    float                           m_fLastSpeed;         ///< Última velocidad instantánea registrada en el vehículo
    float                           m_fLastYRotation;     ///< Última posición de rotación en Y del vehículo

    bool                            m_bHandBrake;         ///< Flag que indica si está activado el freno de mano
    bool                            m_bAccelerate;        ///< Flag que indica si está activado el acelerador
    float                           m_fAcumTurn;          ///< Giro acumulado del vehículo (debido a derrapes)

    C3DSound                        *m_pSndSkid;          ///< Sonido del derrape
    C3DSound                        *m_pSndCrash;         ///< Sonido del colisión

    /// Función para actualizar la última velocidad del vehículo, limitándola a la máxima,
    /// retorna la diferencia respecto la anterior
    float updateLastSpeed(void);
    /// Función para actualizar la última rotación del vehículo, retorna la diferencia respecto la anterior
    float updateLastYRotation(void);
    /// Función para actualizar la suspensión del fuselaje del vehículo (frontal y transversal)
    void updateBody(float DiffSpeed, float DiffRotation);
    /// Función para actualizar el rodaje de las ruedas del vehículo
    void updateWheels(void);
    /// Función para actualizar la dirección de la velocidad
    void updateDirection(float DiffRotation);
    /// Función para actualizar el sonido del vehículo
    void updateSound(float DiffSpeed);
    /// Refresca la transformación actual del objeto, sólo si es necesario
    void refreshTransformation(float DiffRotation);

public: // Métodos públicos

    /// Constructor
    C3DObjVehicle();
    /// Destructor
    ~C3DObjVehicle();

    /// Inicializa el vehículo
    bool initialize(C3DObject *dParent, LPCWSTR ObjectPath, CPlayer *dPlayer);
    /// Actualiza el vehículo
    void update();
    /// Renderiza el vehículo
    void render();

	/// Toma o calcula la inversa de la transformacion actual del vehículo
	D3DXMATRIX *calculateTransInv(D3DXMATRIX *result);

	/// Función observadora del jugador asociado con el vehículo
    CPlayer *getPlayer(void)					{return m_pPlayer;}

	/// Función observadora del nombre del vehículo
    LPWSTR getName(void)						{return m_awName;}
    /// Función observadora de la descripción del vehículo
    LPWSTR getDescription(void)					{return m_awDescription;}

    /// Función observadora de la capacidad máxima del vehículo
    float getMaxCapacity(void)					{return m_iMaxCapacity;}
    /// Función observadora de la vida máxima del vehículo
    float getMaxHealth(void)					{return m_iMaxHealth;}
    /// Función observadora de la velocidad máxima del vehículo
    float getMaxSpeed(void)						{return m_fMaxSpeed;}
    /// Función para indicar la velocidad máxima del vehículo
    void setMaxSpeed(float val)					{m_fMaxSpeed = val;}
    /// Función observadora de la aceleración máxima del vehículo
    float getMaxAcceleration(void)				{return m_fMaxAcceleration;}

    /// Función observadora de la máxima rotación para la suspensión frontal
    float getMaxTurnBodyZ(void)					{return m_fMaxTurnBodyZ;}
    /// Función observadora de la máxima rotación para la suspensión lateral
    float getMaxTurnBodyX(void)					{return m_fMaxTurnBodyX;}
    /// Función observadora de la dureza para la suspensión frontal
    float getTurnBodyZ(void)					{return m_fTurnBodyZ;}
    /// Función observadora de la dureza para la suspensión frontal
    float getTurnBodyX(void)					{return m_fTurnBodyX;}
    /// Función observadora de la recuperación para la suspensión frontal
    float getRecvBodyZ(void)					{return m_fRecvBodyZ;}
    /// Función observadora de la recuperación para la suspensión frontal
    float getRecvBodyX(void)					{return m_fRecvBodyX;}
    /// Función observadora del giro del vehículo
    float getTurn(void)							{return m_fTurn;}
    /// Función observadora del máximo de las ruedas en Y
    float getMaxTurnWheelY(void)				{return m_fMaxTurnWheelY;}
    /// Función observadora del máximo de las ruedas en Z
    float getTurnWheelZ(void)					{return m_fTurnWheelZ;}
    /// Función observadora de la longitud del centro del vehículo al tren trasero o delantero
    float getWheelDist(void)					{return m_fWheelDist;}
    /// Para cambiar la longitud del centro del vehículo al tren trasero o delantero
    void setWheelDist(float val)				{m_fWheelDist = val;}
    /// Función observadora de la altura de la cámara en el modo de vista interior
    float getCameraY(void)						{return m_fCameraY;}

    /// Función observadora de la última velocidad registrada
    float getLastSpeed(void)					{return m_fLastSpeed;}

	/// Función observadora del fuselaje del vehículo
    C3DObject *getBody(void)					{return m_pBody;}
    /// Función observadora de la 'Front Right Wheel' del vehículo
    C3DObject *getFRWheel(void)					{return m_pFRWheel;}
    /// Función observadora de la 'Front Left Wheel' del vehículo
    C3DObject *getFLWheel(void)					{return m_pFLWheel;}
    /// Función observadora de la 'Rear Right Wheel' del vehículo
    C3DObject *getRRWheel(void)					{return m_pRRWheel;}
    /// Función observadora de la 'Rear Left Wheel' del vehículo
    C3DObject *getRLWheel(void)					{return m_pRLWheel;}

    /// Función observadora del cohete asociado del vehículo
    C3DObjWeapon *getRocket(void)				{return m_pRocket;}
    /// Función observadora de la mina asociada del vehículo
    C3DObjWeapon *getMine(void)                 {return m_pMine;}

    /// Función observadora del estado del freno de mano
    bool getHandBrake(void)						{return m_bHandBrake;}
    /// Función para activar o desactivar el freno de mano
    void setHandBrake(bool Value)				{m_bHandBrake = Value;}
	/// Función que determina si el vehículo está o no derrapando
	bool isSkidding(void)						{return ((m_bHandBrake && m_fLastSpeed != 0.0f) || (fabsf(m_fAcumTurn) > 0.3f));}

	/// Función observadora del ángulo de giro acumulado
    float getAcumTurn(void)						{return m_fAcumTurn;}
    /// Función para fijar un ángulo de giro acumulado determinado
    void setAcumTurn(float Value)				{m_fAcumTurn = Value;}

    /// Función observadora del estado del acelerador
    bool getAccelerate(void)					{return m_bAccelerate;}
    /// Función para activar o desactivar el acelerador
    void setAccelerate(bool Value)				{m_bAccelerate = Value;}

	/// Para realizar las consecuencias de una colisión del vehículo
	void doCrash(float impulse);

    /// Para activar el sonido de derrape del coche
    void playSkid(bool loop, long volume = 0, long frecuency = 0);
    /// Para saber si está activo el sonido de derrape del coche
	bool isPlaySkid(void)						{return (m_pSndSkid && m_pSndSkid->isPlaying());}
    /// Para desactivar el sonido de derrape del coche
	void stopSkid(void)							{if(m_pSndSkid) m_pSndSkid->Stop();}
    /// Para activar el sonido de colisiones del coche
    void playCrash(bool loop, long volume = 0, long frecuency = 0);
    /// Para saber si está activo el sonido de colisiones del coche
	bool isPlayCrash(void)						{return (m_pSndCrash && m_pSndCrash->isPlaying());}
    /// Para desactivar el sonido de colisiones del coche
	void stopCrash(void)						{if(m_pSndCrash) m_pSndCrash->Stop();}
};

#endif
