/*********************************************************************//**
*	Hrac.
*	Implementace objektu hrace.
*	
*	author: Michal Jirous
*	date: 23.04.2009
*	file: player.cpp
**********************************************************************/


#include "player.h"
#include "globaltime.h"
#include "ctrl_weapon_manager.h"
#include "soundslib.h"
#include "level_bspfile_def.h"
#include "sys_snd_reserv.h"
//promenne zvuku
//ALuint steps[4];
//ALuint stepIndex = 0;
//ALuint playerSource  = 0, gunSource = 0, itemSource = 0;
//ALuint fireSound[2];
//ALuint itemSound[2];

/* Inicializace */
CPlayer::CPlayer() : Creatures()
{
	m_sClassName = "player";

	m_Weight = PLAYER_WEIGHT;	//Kg

	m_iWaterDamage = 0;


	isJumping = false;
	m_iJumpTime = 5;
	m_iJumpStep = 0;
	m_iHealth = DEFAULT_HEALTH;
	m_iMaxHealth = DEFAULT_HEALTH;
	m_bIsDeath = false;


	//pTarget = NULL;

	stepTime = 0;
	m_fEnergy = DEFAULT_ENERGY;
	initSounds();
	isOnStairs = false;
	m_iDuckOffset = 0;
	m_iIsDucking = 0;
	m_iUpFromDuckOffset = 0;
	m_iDuckUpSpeed = 1;

	m_bJumpoutOfWater = false;
	m_iOxygen = DEFAULT_OXYGEN;
	
	m_uiUpdateTime = 0;
	m_bIsOnLadder = false;
	m_pLadder = NULL;
	m_bPosibleLadderDownMovement = false;
	AmmoAndWeapons.init();

	m_iHullType = HULL_PLAYER;
	
	m_uiStepSoundStartTime = 0;

	m_MovementSound.setSourceRelative( AL_TRUE );
	m_MovementSound.setPreference( AL_TRUE );
	m_MovementSound.setPreferedSourceId( RESERVED_SND_PLAYER_BODY );
	m_MovementSound.setLooping( AL_FALSE );

	m_iProperties = ENT_PARM_RUNNABLE | ENT_PARM_COLLIDING | ENT_PARM_SHOOTABLE | ENT_PARM_DYNAMIC_MODEL_USAGE | ENT_PARM_INTERACTIVE;

	m_StepDelayTime = 400;
}


void CPlayer::compile()
{
	origin.z += HULL_HEIGHTS[m_iHullType]/2.0f;	//nas origin musime posunou nahoru
	createModel( m_iHullType, true );
	m_Store_Position = origin;
	m_Store_Angles = angles;
}



BasicWeapon *CPlayer::getCurrentWeapon()
{
	return weapon_manager::weaponManager.getCurrentWeaponPointer();
}


/* Vymazani vsech zdroju */
CPlayer::~CPlayer()
{
	

	

	
}

/* vymazani zvukovych zdroju */
void CPlayer::unloadSource()
{
	
	

}

/* Inicializace zvuku */
void CPlayer::initSounds()
{
	
}
#include "game.h"
#include "level_collision.h"


void CPlayer::die()
{
	m_bIsDeath = true;
	weapon_manager::weaponManager.removeAllWeapons();
}
void CPlayer::processDuck()
{
	if( m_iIsDucking && m_iDuckOffset < PLAYER_HEIGHT_DUCKED )
	{
		int spd = (int)(PLAYER_HEIGHT/2);
		for( int i = 0; i < 4; i++)
			m_Model.m_Points[i].z += PLAYER_HEIGHT_DUCKED;
		
		m_Model.m_middleCenterPoint.z += PLAYER_HEIGHT_DUCKED / 2;
		m_Model.m_StaticBounds.m_fBounds[ MIN_Z ] += PLAYER_HEIGHT_DUCKED;
		m_Model.m_bottomCenterPoint.z = m_Model.m_StaticBounds.m_fBounds[ MIN_Z ];
//		m_ActiveBrush.bottomPlaneStatic->determineDistance();
		m_iDuckOffset = (int)PLAYER_HEIGHT_DUCKED;
		m_iHullType = HULL_PLAYER_DUCKED;


		m_BackTimeData.push_front( BackTimeData() );
		m_BackTimeData.front().event_time = game.getPlayerTime();
		m_BackTimeData.front().type = EVENT_DUCK;
	}

	if( !m_iIsDucking && m_iDuckOffset > 0 )
	{
		if( collisionSystem.clippingHullCollision( m_Model.m_topCenterPoint, HULL_PLAYER ) == CONTENTS_EMPTY )
		{
			m_iHullType = HULL_PLAYER;
			m_Model.m_middleCenterPoint.z += PLAYER_HEIGHT_DUCKED / 2;
			m_Model.m_StaticBounds.m_fBounds[ MAX_Z ] += PLAYER_HEIGHT_DUCKED;
			m_Model.m_topCenterPoint.z = m_Model.m_StaticBounds.m_fBounds[ MAX_Z ];
			m_iDuckOffset = 0;

			for( int i = TLN; i < POINT_COUNT; i++)
				m_Model.m_Points[i].z += PLAYER_HEIGHT_DUCKED;
			//m_fTransZ -= PLAYER_HEIGHT_DUCKED;
			origin = m_Model.m_topCenterPoint;
		}
	
		m_BackTimeData.push_front( BackTimeData() );
		m_BackTimeData.front().event_time = game.getPlayerTime();
		m_BackTimeData.front().type = EVENT_DUCK_UP;
	}
}


void CPlayer::heal( int value )
{
	if( m_iHealth < m_iMaxHealth )
	{
		int diff = min(m_iMaxHealth - m_iHealth, value );
		m_iWaterDamage += diff;
		//m_iHealth += diff;
	}
}


void CPlayer::update( float seconds )
{
	soundLibrary.setListenerVelocity( -m_vecMove.x, -m_vecMove.y, -m_vecMove.z );
	soundLibrary.setListenerOrientation( game.vecDir.x, game.vecDir.y, game.vecDir.z, 0.0f,0.0f,1.0f );

	//prechod na skrceni
	processDuck();
	
	/*if( m_iUpFromDuckOffset > 0 )
	{
		m_fTransZ -= m_iUpFromDuckOffset;
		m_iUpFromDuckOffset = 0;
	}*/
	if( !m_bIsDeath )
	{
		if( m_uiUpdateTime + 200 < global_time::getGlobalTime() )
		{
			m_uiUpdateTime = global_time::getGlobalTime();
			if( m_iWaterLevel & HEAD_IN_WATER )
			{
				if( m_iOxygen == 0 )
				{
					m_iWaterDamage++;
					m_iHealth--;
				}

				m_iOxygen -= min( m_iOxygen, 1 );
			
			}
			else
			{
				if( m_iWaterDamage > 0 )
				{
					m_iWaterDamage--;
					if( m_iHealth < m_iMaxHealth )
						m_iHealth ++;
				}
				if( m_iOxygen < 100 )
					m_iOxygen++;
			
			}
		}
		
		//m_iHealth = m_iMyHealth - m_iWaterDamage;

		if( getHealth() <= 0 )
			die();
		

		if( m_fEnergy < DEFAULT_ENERGY )
		{
			m_fEnergy += min( DEFAULT_ENERGY - m_fEnergy, ENERGY_REGENERATION_RATIO);
		}
	}

	
	if( !m_bIsInAir || m_bIsOnLadder )
		m_StepSoundEnergy = std::min(m_StepSoundEnergy+30u,500u);
	else
		m_StepSoundEnergy -= std::min( m_StepSoundEnergy, 10u );

	if( (!m_bIsInAir || m_bIsOnLadder ) && m_StepSoundEnergy > m_StepDelayTime && m_Velocity.absolute() > 2.0f )
	{
		if( m_uiStepSoundStartTime + m_StepDelayTime < game.getPlayerTime() )
		{
			if( m_bIsOnLadder )
				generalSounds.playStepSound( SOUND_LADDER, m_MovementSound );
			else
				generalSounds.playStepSound( m_GroundMaterial, m_MovementSound );			
			m_uiStepSoundStartTime = game.getPlayerTime();
		}
	}
		
	

	Creatures::update( seconds );

	BasicWeapon *pWeapon = getCurrentWeapon();
	if( pWeapon )
		pWeapon->run();
	
}


void CPlayer::goBackInTime()
{

	Creatures::goBackInTime();
	m_uiStepSoundStartTime = 0;

	for( std::list<BackTimeData>::reverse_iterator riter = m_BackTimeData.rbegin(); riter != m_BackTimeData.rend(); ++riter  )
	{
		//jakmile nalezneme border, tak koncime pruchod
		if( (*riter).type == EVENT_BORDER )
			break;

		if( (*riter).type == EVENT_DUCK )
		{
			int backUp = m_iIsDucking;
			m_iIsDucking = 0;
			processDuck();
			m_iIsDucking = backUp;
			break;
		}
		else if(  (*riter).type == EVENT_DUCK_UP )
		{
			int backUp = m_iIsDucking;
			m_iIsDucking = 1;
			processDuck();
			m_iIsDucking = backUp;
			break;
		}
	}
}


void CPlayer::onAttack( const AttackInfo &attackInfo )
{
	Creatures::onAttack( attackInfo );
	if( attackInfo.m_iDamageType == dmg::FALL )
		generalSounds.playStepSound( SOUND_FALLPAIN, m_MovementSound );			
}


void CPlayer::removeOldBackEvents()
{
	for( std::list<BackTimeData>::iterator iter = m_BackTimeData.begin(); iter != m_BackTimeData.end();  )
	{
		//jakmile nalezneme border, tak koncime pruchod
		if( (*iter).type == EVENT_BORDER )
			return;

		if( (*iter).event_time + BACK_TIME_MS_REAL < game.m_uiPlayerTime )
		{
			iter = m_BackTimeData.erase( iter );
		}
		else
			++iter;
	}
}



void CPlayer::restart()
{
	Creatures::restart();
	m_uiStepSoundStartTime = 0;
	m_bIsDeath = false;
	setHealth( DEFAULT_HEALTH );
	weapon_manager::weaponManager.removeAllWeapons();
	m_fEnergy = DEFAULT_ENERGY;
	m_uiUpdateTime = 0;
	m_iWaterDamage = 0;
}


/**************************************
*	Forces and collision data
***************************************/

//tuhle funkci vola CBasePhysics ve funkci update
//a nastavuji zakladni sily a treni
//hrac ma navic pohyb po zebriku, ktery je treba osetrit
void CPlayer::updateForces()
{
	if( !m_bIsOnLadder )
		addForce( Vector( 0.0f, 0.0f, -gamevarsLibrary::getfData( g_Gravity ) * m_Weight ) );

	if( !m_bIsInAir || m_bIsOnLadder )
		//a taky koeficient treni
		addFriction( gamevarsLibrary::getfData( g_FrictionNormalGround ) );
}

#include "sys_controller.h"
void CPlayer::prepareForCollision()
{
	m_Velocity += (m_TotalForce / m_Weight) * systemController::RUNTIME_PERIOD_S;	//rychlost v m/s
	if( !m_bIsInAir || m_bIsOnLadder )
		m_Velocity -= m_Velocity * m_TotalFriction;

	m_TotalForce.clear();	//reset rychlosti
	m_TotalFriction = 0.0f;

	//zde budeme mozna muset provest eulerovu metodu

	m_Model.m_vecMovement = m_Velocity * systemController::RUNTIME_PERIOD_S * POINTS_PER_METER;


}
//==========================================




void CPlayer::jump()
{
	if( !m_bIsInAir && m_iWaterLevel < BODY_IN_WATER )	//musim byt na zemi a nesmi byt telo ve vode
	{
		
		addForce( Vector( 0.0f, 0.0f, gamevarsLibrary::getfData( vardef::JUMPHEIGHT_NAME ) * m_Weight ) );
	}
}


void CPlayer::duck( int value )
{
	m_iIsDucking = value;
	if( value )
		m_iDuckUpSpeed = 4;
}




/* Funkce presune hrace podle zadaneho vektoru */
void CPlayer::teleport( const alg::Vector &v, bool interpolation )
{
	// - protoze trans sou opacny
	//je treba posunout stred hrace
	/*m_fTransX -= v[0];
	m_fTransY -= v[1];
	m_fTransZ -= v[2];*/
	Creatures::teleport( v,interpolation  );
	//m_Model.translateStatic( v );
	//origin = m_Model.m_topCenterPoint;
	soundLibrary.setListenerPosition( (float*)&origin );
	
}

/* Hrac utrpel zraneni */
void CPlayer::takeDamage( int dmg )
{
	if(m_iHealth-dmg < 1)
		m_bIsDeath = true;
	
	setHealth( m_iHealth - dmg);
}


void CPlayer::updateBackTime()
{
	//store position
	m_BackTimeData.push_front( BackTimeData() );
	m_BackTimeData.front().event_time = game.m_uiPlayerTime;
	m_BackTimeData.front().type = EVENT_POSITION;
	*((Vector*)(m_BackTimeData.front().values.position)) = origin;

	m_BackTimeData.push_front( BackTimeData() );
	m_BackTimeData.front().event_time = game.m_uiPlayerTime;
	m_BackTimeData.front().type = EVENT_ANGLES;
	*((Vector*)(m_BackTimeData.front().values.position)) = angles;
}

//musime projit zaznamy o minulosti a najit nestarsi zaznam
Uint32 CPlayer::getTotalBackTimeSecondsAvaiable()
{
	for( std::list<BackTimeData>::reverse_iterator riter = m_BackTimeData.rbegin(); riter != m_BackTimeData.rend(); ++riter )
	{
		//jakmile nalezneme border, tak koncime pruchod
		if( (*riter).type == EVENT_POSITION )
			return (*riter).event_time;

	}
	return 0;
}

/* Vykresleni hrace ( pouze ohraniceni  ) */
void CPlayer::drawPlayer(alg::LinkedPoint &p)
{
	/*if(p.m_iStatus == p.OPEN)
	{
		return;
	}

	p.m_iStatus = p.OPEN;

	for( BasicLinkedList<alg::LinkedPoint*>::BasicLink *tmpPoint = p.m_Neightbours.root; tmpPoint != NULL; tmpPoint = tmpPoint->next )
	{
		drawPlayer( *tmpPoint->pointer );
		if(tmpPoint->pointer->m_iStatus != p.CLOSED)
		{
			glVertex3i( p.x,  p.y,p.z);
			glVertex3i(tmpPoint->pointer->x,  tmpPoint->pointer->y, tmpPoint->pointer->z);
		}
	}
	
		
		
	
	p.m_iStatus = p.CLOSED;*/
}

/* Vykresleni hrace */
//void CPlayer::draw()
//{
//	//if(m_collModel == NULL)
//	//	return;
//	
//	glDisable(GL_LIGHTING);
//	glColor3f(0.0f, 1.0f, 0.0f);
//	
//	glBegin(GL_LINES);
//	//drawPlayer( m_ActiveBrush.m_points.root->pointer );
//		
//	glEnd();
//	/*glDisable(GL_CULL_FACE);
//	glBegin(GL_TRIANGLE_STRIP);
//	glVertex3i( m_collModel->first->x,  m_collModel->first->y+32, m_collModel->first->z);
//	glVertex3i( m_collModel->first->x,  m_collModel->first->y, m_collModel->first->z);
//	glVertex3i( m_collModel->first->x+32,  m_collModel->first->y+32, m_collModel->first->z);
//	glVertex3i( m_collModel->first->x+32,  m_collModel->first->y, m_collModel->first->z);
//	
//	
//	
//	glEnd();*/
//
//	glEnable(GL_LIGHTING);
//	
//	/*plPoint *tmp = m_collModel->first;
//	while(tmp != NULL)
//	{
//		tmp->status = UNUSED;	
//		tmp =  tmp->next;
//	}*/
//}
Uint32 g_uiJumpTime=0;
#include "ctrl_var_definition.h"
#include "sys_controller.h"
Uint32 g_uiNumJumps;
/* Vyskok (je to animace, kdy po urcitou dobu hrac ziskava vektor smerem vzhuru */
Vector CPlayer::jump( float fHeight, int move, float gravityDifference)
{	
	float fJumpHeight = gamevarsLibrary::getfData( vardef::JUMPHEIGHT_NAME );
	//fJumpHeight /= systemController::getTimeDelayMultiplicator();
	if( g_uiNumJumps == (int)fJumpHeight )
	{
		isJumping = false;
	}

	if(!isJumping && !m_bIsInAir  && move)	//pocatek skoku (posuneme hrace o 1 bod vzhuru a zacneme animaci)
	{
		//acceptVector(Vector(0.0f,0.0f,-1.0f) );
		g_uiNumJumps = 0;
		m_bIsInAir = true;
		isJumping = true;
	}
	if(isJumping)	//animace skoku
	{
		/*if( fHeight + m_fJumpPart > fJumpHeight )
		{
			fHeight = fJumpHeight - m_fJumpPart;
			isJumping = false;
		}
		else
			m_fJumpPart += fHeight;*/
		g_uiNumJumps++;

		return Vector(0.0f,0.0f,-fHeight );
	}
	return Vector();
}


/* Strelba hrace */
//bullet *CPlayer::attack()
//{
//
//
//	//vytvoreni kulky
//	bullet *pistolBullet = new bullet();
//	pistolBullet->damage = 10;
//	pistolBullet->movement = getAngle();
//	origin = getOrigin();
//	pistolBullet->start = Point(origin[0],origin[1],origin[2]);
//	return pistolBullet;
//}

/* Funkce posune hrace podle zadaneho vektoru */
void CPlayer::acceptVector(const Vector &v)
{

	if(!m_bIsInAir)	//pokud jde hrac po zemi, tak se prehraje zvuk pohybu
	{
		
	}
	teleport(v);
}



void CPlayer::setStairsMovement(alg::Vector &stairsMoveVector)
{
	isOnStairs = true;
	m_vecStairsMoveVector = stairsMoveVector;
	m_iStairsTimes = 3;
	m_vecStairsPart = m_vecStairsMoveVector / (float)m_iStairsTimes;
	m_iStarsAlreadyTimes = 0;

}
