/*********************************************************************//**
*	Game.
*	Tento modul je vstupnim bodem enginu, spousti vykreslovani,
*	aktualizaci entit, provadi skilly hrace, startuje vypocet pohybu,
*	nahravani levelu.
*
*	author: Michal Jirous
*	date: 07.04.2009
*	file: game.h
**********************************************************************/

#include "sys_controller.h"
#include "game.h"
#include "ctrl_gamecontrol.h"
#include "game_loadmap.h"
#include "game_loadingscreen.h"

#include "sys_config.h"
#include "game_mainmenu.h"
#include "game_musicplayer.h"
#include "HUD_messages.h"
#include <SDL/SDL_opengl.h>
#include "game_environment.h"

#include "ctrl_var_definition.h"


#include "HUD.h"
#include "HUD_crosshair.h"
#include "textureslib.h"
#include "spriteslib.h"
#include "modelslib.h"
#include "soundslib.h"

#include "bullet_tracks.h"
#include "level_loader.h"
#include "error_handler.h"

CGame game;
Sprite *g_pSprite = NULL;
unsigned int g_uiSprID = 0;







/* Funkce prida novy objekt sceny do seznamu */
//void CGame::addObject(CBaseObject *o)
//{
//
//	sceneObjectLibrary::addSceneObject( o );
//}

/* Vymaze vsechny objekty sceny ze seznamu */
void CGame::deleteObjects()
{
	//fanList.clear();
	//bObject *tmp = sceneObjectLibrary::getSceneObjectRoot();
	//while(tmp != NULL)
	//{
	//	//tmp = baseObject;
	//	//baseObject = baseObject->next;
	//	tmp->object->decompile();
	//	tmp = tmp->next;
	//}
	//baseObject = NULL;
	//sceneObjectLibrary::removeSceneObjects();
	
//	blendList.clear();	//vymazeme  objekty blendingu
	
	m_pPlayer = NULL;
	m_iNumTargets = 0;
	environment.decompile();
	//back = NULL;

}
#include "globaltime.h"
#include "game_highscore.h"
#include "textLibrary.h"
#include "parsing.h"
#include "ctrl_binding.h"
#include "ctrl_keydatabase.h"
#include "ctrl_com_definition.h"
void CGame::exitLevel()
{
	if( m_uiTotalGameTargets == m_uiTargetsDoneCount )
	{
		global_time::timeStop();
		m_bLevelFinnished = true;

		HUD::hud.setCrosshair( CROSSHAIR_NONE );

		highscore::HighScoreInfo * pHScore = highscore::getHighScore( m_sCurrentLevel );
		if( !pHScore )
			pHScore = highscore::getHighScore( m_sCurrentLevel + EXTENSION );
		
		ostringstream buf;
		buf << textLibrary::getText( TXT_LEVEL_REPORT_TITLE ) << endl;
		buf << textLibrary::getText( TXT_CURRENT_LEVEL ) << ": " << m_sCurrentLevel << endl;
		if( !pHScore || pHScore->m_uiTime > m_uiGameTime )	//neni zadne score
		{
			buf << textLibrary::getText( TXT_LEVEL_REPORT_NEW_HIGHSCORE ) << endl;
			buf << textLibrary::getText( TXT_LEVEL_REPORT_YOUR_TIME ) << ": " << parsing::formatTime( m_uiGameTime ) << endl;

			if( pHScore )
				buf << textLibrary::getText( TXT_LEVEL_REPORT_PREVIOUS_TIME ) << ": " << parsing::formatTime( pHScore->m_uiTime ) << endl;

			std::string levelName = m_sCurrentLevel;
			if( !parsing::stringEndsWith( m_sCurrentLevel, EXTENSION ) )
				levelName += EXTENSION;

			highscore::setHighScore( levelName, gamevarsLibrary::getsData( vardef::NAME_NAME ), m_uiGameTime );
			m_SoundBetterScore.play();
	
		}
		else
		{
			buf << textLibrary::getText( TXT_LEVEL_REPORT_NOT_BETTER ) << endl;
			buf << textLibrary::getText( TXT_LEVEL_REPORT_PREVIOUS_TIME ) << ": " << parsing::formatTime( pHScore->m_uiTime ) << endl;
			buf << textLibrary::getText( TXT_LEVEL_REPORT_YOUR_TIME ) << ": " << parsing::formatTime( m_uiGameTime ) << endl;
			m_SoundScoreWorse.play();
		}
		
		buf << endl << textLibrary::getText( TXT_LEVEL_REPORT_PRESS ) << " ";

		binding::Keys *pKey = binding::getKeyOfWatchedCommand( comdef::RESTART_NAME );
		if( pKey )
			buf << key_database::getKey( pKey->key_one );
		else
			buf << "L";

		buf << " " << textLibrary::getText( TXT_LEVEL_REPORT_RESTART ) << endl;

		if( !m_sNextLevel.empty() )
		{
			pKey = binding::getKeyOfWatchedCommand( comdef::ATTACK_NAME );
			buf << textLibrary::getText( TXT_LEVEL_REPORT_PRESS ) << " ";
			if( pKey )
				buf << key_database::getKey( pKey->key_one );
			else
				buf << "MOUSE1";
			buf	<< " " << textLibrary::getText( TXT_LEVEL_REPORT_NEXT_LEVEL ) << endl;
		}
		m_sLevelReportString = buf.str();			
	}
}

void CGame::onPlayerDeath()
{
	m_SoundPlayerDead.play();
	//global_time::timeStop();
	m_bLevelFinnished = true;
	HUD::hud.setCrosshair( CROSSHAIR_NONE );

	ostringstream buf;
	buf << endl << textLibrary::getText( TXT_LEVEL_REPORT_PRESS ) << " ";

	binding::Keys *pKey = binding::getKeyOfWatchedCommand( comdef::RESTART_NAME );
	if( pKey )
		buf << key_database::getKey( pKey->key_one );
	else
		buf << "L";

	buf << " " << textLibrary::getText( TXT_LEVEL_REPORT_RESTART ) << endl;

	if( !m_sNextLevel.empty() )
	{
		pKey = binding::getKeyOfWatchedCommand( comdef::ATTACK_NAME );
		buf << textLibrary::getText( TXT_LEVEL_REPORT_PRESS ) << " ";
		if( pKey )
			buf << key_database::getKey( pKey->key_one );
		else
			buf << "MOUSE1";
		buf	<< " " << textLibrary::getText( TXT_LEVEL_REPORT_NEXT_LEVEL ) << endl;
	}
	m_sLevelReportString = buf.str();			
}




#include "ctrl_weapon_manager.h"

void CGame::processNextLevel()
{
	if( !m_sNextLevel.empty() )
		loadMap( m_sNextLevel, systemController::GAME );

}
#include "gibs_system.h"
#include "snow_system.h"
/* Nacte novou mapu */
void CGame::loadMap( string file, int nextRunningLevel )
{

	//music_player::stop();
	systemController::setRunningLevel( systemController::LOADMAP );
	game.deleteObjects();

	snowSystem.reset();
	loadingScreen::loading_screen.setMyAlphaMultiplier( ALPHA_OPAQUE );
	loadingScreen::loading_screen.setProgress( 0 );
	loadingScreen::loading_screen.use_this_draw();
	
	hideCursor();
	hideCrosshair();
	weapon_manager::weaponManager.reset();
	global_time::resetTime();
	global_time::timeStop();

	m_sNextLevel.clear();
	
	m_uiTotalGameTargets = 0;
	m_uiTargetsDoneCount = 0;

	m_uiTotalFramesDone = 0;
	m_uiTotalTexturesAnimationsCount = 0;

	m_bLevelFinnished = false;
	m_uiTimeServed = 0;
	m_uiGameTime = 0;
	m_uiBackTimeMovesCount = 0;
	m_iuFrameStart = 0;
	m_uiTotalFramesDone = 0;
	m_uiSupposedFramesCount = 0;
	m_uiTotalTexturesAnimationsCount = 0;
	m_uiTimeNormalDelay = 0;
	m_uiTimeNormalDelayTotal = 0;

	m_uiTotalTimeUpdatesDone = 0;
	m_uiPlayerTimeDelayTotal = 0;
	m_uiPlayerTimeDelay = 0;
	m_uiBackTimeDelay = 0;
	m_bIsAudioEnabled = false;
	m_uiPlayerTime = 0;

	//===============================================================================
	//HERE
	//===============================================================================

	HUDMessages::HUD_messages.deleteAll();

	m_bDisplayLogo = false;
	m_bLevelFadeIn = false;
	fadeEffect.reset();

	if( levelLoader.loadLevel( file.c_str() ) )
	{
		m_bLevelStarted = true;
		m_sCurrentLevel = file;
	}
	else
	{
		m_bLevelStarted = false;
		m_sCurrentLevel = "";
	}
		
	environment.compile();

	modelLib::modelLibrary.checkModelsUsage();
	m_GlobalTexturesPool.Pool_checkTexturesUsage();
	textureLibrary.checkTexturesUsage();
	
	spritesLibrary.checkUsage();
	soundLibrary.checkSoundsUsage();

	mainMenu::main_menu.setMyAlphaMultiplier( ALPHA_TRANSPARENT );

	m_fTargetFOV = (float)gamevarsLibrary::getiData( vardef::DEFAULT_FOV_NAME );
	m_fDefaultFov = m_fTargetFOV;

	if( m_bLevelStarted )
		systemController::setRunningLevel( nextRunningLevel );
	else
	{
		systemController::setRunningLevel( systemController::MAINMENU );
		m_bDisplayLogo = true;

		//infinite fade
		fadeEffect.startFade( Color(0,0,0), 0, 3000, 3000, ALPHA_OPAQUE, ALPHA_OPAQUE, ALPHA_OPAQUE, true );
	}
	gibsSystem.restart();



	if( !m_sCurrentLevel.empty() )
	{
		levels::LevelInfo* pLevel = levels::getLevelInfo( m_sCurrentLevel );
		std::string levelText = textLibrary::getText( TXT_YOU_PLAY ) + " ";
		if( !pLevel )
			levelText += m_sCurrentLevel;
		else
			levelText += pLevel->m_sName;
		HUDMessages::HUD_messages.insertMessage( levelText, (float)(w*0.3), (float)(h*0.1), "SERIF16", FONT_ALIGN_CENTER, -1, HUDMessages::HUDMESSAGES_DEFAULT_DURATION, Color4I(151,240,177,255) );
	}
	global_time::timeStart();
}









/* Inicializace */
CGame::CGame()
{
	iteration = 0;
	m_iNumTargets = 0;
	m_pPlayer = NULL;
	m_iuFrameStart = 0;	
	m_bLevelStarted = false;
	cam_rot = 0.0f;
		m_uiTimeNormalDelay = 0;
	m_bGameStarted = m_bStartSequence = false;
	m_uiTimeServed = 0;
	
	m_bGameOver = false;
	m_bEnviromentAnimation = true;
	
	m_fSkyDistance = 5000.0f;
	


	m_bShowCursor = false;
	m_bShowCrosshair =false;
	m_bIsAudioEnabled = false;
}

/* Vymazani nekterych promennych */
CGame::~CGame()
{

	
}

void CGame::destroy()
{
	deleteObjects();
	m_GlobalTexturesPool.Pool_destroy();	//uvolnime pouzite textury
}



void CGame::calculateVecDir()
{
	
	if(m_pPlayer != NULL)
		vecDir.createFrom2Angles( m_pPlayer->angles[0],m_pPlayer->angles[2]  );
}



void CGame::checkInterAction()
{
//	collision.checkInteraction( vecDir, m_pPlayer );	//TODO ?

}


/* Provedeni strelby */
void CGame::attackExecution( CBaseEntity *object)
{
	
}

void CGame::setLevelEnvironment()
{
	if( m_bLevelFadeIn )
		fadeEffect.startFade( Color(0,0,0), 0, 3000, 3000, ALPHA_OPAQUE, ALPHA_OPAQUE, ALPHA_TRANSPARENT, false );
}

void CGame::setLevelParameters( parameters_t &parametersMap )
{
	string value = getParameterValue( parametersMap, "music" );
	music_player::openMusic( ("Sounds/Music/" + value).c_str() );
	music_player::fadein( -1, 3000 );

	value = getParameterValue( parametersMap, "startdark" );
	if( !value.empty() )
	{
		int v = atoi( value.c_str() );
		if( v )
			m_bLevelFadeIn = true;

	}

	value = getParameterValue( parametersMap, "gametitle" );
	if( !value.empty() )
		if( atoi( value.c_str() ) )
			m_bDisplayLogo = true;
	

	environment.setSkyName( getParameterValue( parametersMap, "skyname" ) );

	m_sNextLevel = getParameterValue( parametersMap, "nextlevel" );

	setLevelEnvironment();
}


#include "game_loadingscreen.h"

/* inicializace aplikace */
void CGame::init()
{
	CONSOLE_PRINT_LN( "Initializing game settings..." );
	m_bUpdateFrustum = true;
	
	//===============================================================================
	//HERE
	//===============================================================================
	//maploader.init();	//init komponenty pro nacitani map
	
	glClearColor(0.0f, 0.0f, 0.0f, 0.0f);       // barva pozadi
    glPolygonMode(GL_FRONT, GL_FILL);           // nastaveni rezimu vykresleni polygonalniho modelu
	glShadeModel(GL_SMOOTH);                        // nastaveni stinovaciho rezimu

	glClearStencil(0);
    glStencilMask(1);

	m_iNumFps = 0;
	m_iNumRuns = 0;
   
	glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);// nastaveni rezimu textury
	glHint(GL_PERSPECTIVE_CORRECTION_HINT,GL_NICEST);// vylepseni zobrazovani textur
	glHint(GL_FOG_HINT, GL_DONT_CARE);
	
	glDepthFunc(GL_LEQUAL);

	glDrawBuffer(GL_BACK);
	glClearDepth(1);
	
	glEnable(GL_DEPTH_TEST);


	m_fDefaultFov = 0.0f;
	m_fMaxDistance = 0.0f;
	
	initTime = clock();


	m_iCurrentActiveSkill = SK_NO_SKILL;
	m_uiPlayerTimeDelayTotal = 0;
	m_uiPlayerTimeDelay = 0;

	m_uiTimeNormalDelayTotal = 0;
	m_uiTimeNormalDelay = 0;


//	crossHairTexture = textureLibrary::applyTexture("CROSSHAIR");

	m_bInit = true;

	CONSOLE_PRINT( "\tLoading common game sounds..." );
	soundLibrary.pushAttrib();
	soundLibrary.setDefaultRelativity( AL_TRUE );

	soundLibrary.loadSound( m_SoundNoEnergy, "Skills/no_energy.wav" );
	soundLibrary.loadSound( m_SoundPlayerDead, "evilaf07.wav" );
	soundLibrary.loadSound( m_SoundBetterScore, "applause.wav" );
	soundLibrary.loadSound( m_SoundScoreWorse, "metal.wav" );

	soundLibrary.popAttrib();
	CONSOLE_PRINT_LN("done");

	CONSOLE_PRINT( "\tCreating game logo..." );
	m_pLogoTexture = textureLibrary.addEntry( loadingScreen::LOADING_SCREEN_LOGO_FILENAME );
	m_pLogoTexture->image.setFilename( loadingScreen::LOADING_SCREEN_LOGO_FILENAME );
	m_pLogoTexture = textureLibrary.applyTexture( loadingScreen::LOADING_SCREEN_LOGO_FILENAME );

	if( m_pLogoTexture )
	{
		m_LogoDList = glGenLists( 1 );
	
		glNewList( m_LogoDList, GL_COMPILE );
		
		float center_x = (float)(systemconf::getSystemInfo().m_iResolutionWidth >> 1);
		float center_y = (float)(systemconf::getSystemInfo().m_iResolutionHeight >> 1);
		float texture_halfWidth = (float)(m_pLogoTexture->image.width >> 1);
		float texture_halfHeight = (float)(m_pLogoTexture->image.height >> 1);

		glBegin( GL_QUADS );
		glTexCoord2i( 0,0); glVertex2f( center_x - texture_halfWidth, center_y - texture_halfHeight );
		glTexCoord2i( 1,0); glVertex2f( center_x + texture_halfWidth, center_y - texture_halfHeight );
		glTexCoord2i( 1,1); glVertex2f( center_x + texture_halfWidth, center_y + texture_halfHeight );
		glTexCoord2i( 0,1); glVertex2f( center_x - texture_halfWidth, center_y + texture_halfHeight );
		glEnd();
		glEndList();
	}

	w = (double)systemconf::getSystemInfo().m_iResolutionWidth;
	h = (double)systemconf::getSystemInfo().m_iResolutionHeight;

	CONSOLE_PRINT_LN("done");
}

/* Zmena velikosti zobrazovaciho okna */
void CGame::resizeScene(int width, int heigth)
{
	glViewport(0, 0, width, heigth);                     // viditelna oblast pres cele okno
    w=width;                              // zapamatovat si velikost okna
    h=heigth; 
	
}
/* Ukonceni aplikace */
void CGame::quit()
{
	soundLibrary.unloadSound( m_SoundNoEnergy );
	if(m_pPlayer != NULL)
		m_pPlayer->unloadSource();
	deleteObjects();

}

GLuint averageRunTime = 0;
GLuint totalRunTime = 0;
int numRuns = 0;
long int clockValue = 0;

#include "level_collision.h"

bool CGame::consumeEnergy( int skill, float multiplier )
{
	float fTotalEnergy = SKILLS_ENERGY_CONSUMING[ skill ] * multiplier;
	if( m_pPlayer->getEnergy() < fTotalEnergy )
		return false;

	m_pPlayer->consumeEnergy( fTotalEnergy );
	return true;
}

void CGame::proceedBackTime()
{
	if( m_iCurrentActiveSkill == SK_NO_SKILL )	//dosud nezacal
	{
		Uint32 lastEventTime = m_pPlayer->getTotalBackTimeSecondsAvaiable();
	
		if( consumeEnergy( SK_TIME_TRAVEL, (float)(m_uiPlayerTime - lastEventTime ) / 1000.0f  ) )
		{
			//skill muze zacit
			m_uiBackTimeDelay += m_uiPlayerTime - lastEventTime;
			m_uiTimeNormalDelayStarter = global_time::getGlobalTime();
			m_iCurrentActiveSkill = SK_TIME_TRAVEL;
		}
		else
			m_SoundNoEnergy.play();
		
	}
	
	if( m_iCurrentActiveSkill == SK_TIME_TRAVEL )
	{
		m_uiTimeNormalDelay = global_time::getGlobalTime() - m_uiTimeNormalDelayStarter;
		m_uiPlayerTimeDelay = global_time::getGlobalTime() - m_uiTimeNormalDelayStarter;	//zde zastavujeme i hrace
		if( m_uiTimeNormalDelayStarter + TIME_TRAVEL_ANIMATION_TIME < global_time::getGlobalTime() )	//end
		{
			m_uiPlayerTimeDelayTotal += m_uiPlayerTimeDelay;
			m_uiPlayerTimeDelay = 0;

			m_uiTimeNormalDelayTotal += m_uiTimeNormalDelay;
			m_uiTimeNormalDelay = 0;
			//activate backtime events

			for( list<CBaseEntity*>::iterator iter = levelLoader.m_Entities.m_RunnableEntities.begin(); iter != levelLoader.m_Entities.m_RunnableEntities.end(); ++iter )
				(*iter)->goBackInTime();

			m_iCurrentActiveSkill = SK_NO_SKILL;
		
		}
	
	}
}

void CGame::proceedStopTime( bool stop )
{
	if( stop )
	{
		m_uiTimeNormalDelayTotal += m_uiTimeNormalDelay;
		m_uiTimeNormalDelay = 0;
		m_iCurrentActiveSkill = SK_NO_SKILL;
		m_AllowedEntities.clear();
	}
	else
	{
		if( m_iCurrentActiveSkill == SK_NO_SKILL )	//dosud nezacal
		{
			if( m_pPlayer->getEnergy() < SKILLS_ENERGY_CONSUMING[ SK_STOP_TIME ] )
				return;
			
			m_iCurrentActiveSkill = SK_STOP_TIME;
			m_uiTimeNormalDelayStarter = global_time::getGlobalTime();
			allowEntity( m_pPlayer );
		}

		if( consumeEnergy( SK_STOP_TIME )  )
		{
			//skill muze pouzivat
			m_uiTimeNormalDelay = global_time::getGlobalTime() - m_uiTimeNormalDelayStarter;
			m_iCurrentActiveSkill = SK_STOP_TIME;
		}
		else
		{
			m_SoundNoEnergy.play();
			proceedStopTime( true );
		}
	}
}

void CGame::proceedForwardTeleport( bool stop )
{
	if( stop )
	{
		m_uiTimeNormalDelayTotal += m_uiTimeNormalDelay;
		m_uiTimeNormalDelay = 0;
		m_uiPlayerTimeDelayTotal += m_uiPlayerTimeDelay;
		m_uiPlayerTimeDelay = 0;
		m_iCurrentActiveSkill = SK_NO_SKILL;
		m_AllowedEntities.clear();
	}
	else
	{
		if( m_iCurrentActiveSkill == SK_NO_SKILL )	//dosud nezacal
		{
			if( m_pPlayer->getEnergy() < SKILLS_ENERGY_CONSUMING[ SK_FORWARD_TELEPORT ] )
				return;
			
			m_iCurrentActiveSkill = SK_FORWARD_TELEPORT;
			m_uiTimeNormalDelayStarter = global_time::getGlobalTime();
			allowEntity( m_pPlayer );
			m_uiTeleportSpeed = max(m_pPlayer->getVelocity().absolute(), 3.0f );	//startovni rychlost
		}

		if( consumeEnergy( SK_FORWARD_TELEPORT )  )
		{
			//skill muze pouzivat
			m_uiTimeNormalDelay = global_time::getGlobalTime() - m_uiTimeNormalDelayStarter;
			m_uiPlayerTimeDelay = global_time::getGlobalTime() - m_uiTimeNormalDelayStarter;	//zde zastavujeme i hrace
			m_iCurrentActiveSkill = SK_FORWARD_TELEPORT;
		}
		else
		{
			m_SoundNoEnergy.play();
			proceedStopTime( true );
		}
	}




}


void CGame::startSkill( int sk )
{
	if( m_bLevelFinnished )
		return;

	if( !isInRange( sk, SK_TIME_TRAVEL, SK_FORWARD_TELEPORT ) )
		return;

	if( m_iCurrentActiveSkill == SK_NO_SKILL )
	{
		switch( sk )
		{
			case SK_TIME_TRAVEL:
				proceedBackTime();
				break;
			case SK_STOP_TIME:
				proceedStopTime();
				break;
			case SK_FORWARD_TELEPORT:
				proceedForwardTeleport();
				break;
		}
	}
}

void CGame::stopSkill( int sk )
{
	if( !isInRange( sk, SK_TIME_TRAVEL, SK_FORWARD_TELEPORT ) )
		return;

	if( m_iCurrentActiveSkill == sk )
	{
		switch( sk )
		{
			case SK_STOP_TIME:
				proceedStopTime(true);
				break;
			case SK_FORWARD_TELEPORT:
				proceedForwardTeleport(true);
				break;
		}
	
	}
}

void CGame::proceedSkills()
{
	switch( m_iCurrentActiveSkill )
	{
		case SK_TIME_TRAVEL:
			proceedBackTime();
			break;
		case SK_STOP_TIME:
				proceedStopTime();
				break;
		case SK_FORWARD_TELEPORT:
			proceedForwardTeleport();
			break;
	
	}
}

void CGame::restartGame()
{
	global_time::resetTime();
	global_time::timeStop();

	stopSkill( m_iCurrentActiveSkill );
	m_iCurrentActiveSkill = SK_NO_SKILL;

	

	m_uiTotalFramesDone = 0;
	m_uiTotalTexturesAnimationsCount = 0;

	m_uiPlayerTime = 0;
	m_uiTimeServed = 0;
	m_uiGameTime = 0;
	m_uiBackTimeMovesCount = 0;
	m_iuFrameStart = 0;
	m_uiTotalFramesDone = 0;
	m_uiSupposedFramesCount = 0;
	m_uiTotalTexturesAnimationsCount = 0;
	m_uiTimeNormalDelay = 0;
	m_uiPlayerTimeDelayTotal = 0;
	m_uiPlayerTimeDelay = 0;

	m_uiBackTimeDelay = 0;
	m_uiTimeNormalDelayTotal = 0;
	m_uiTimeNormalDelay = 0;
	m_uiTotalTimeUpdatesDone = 0;

	for( entityList_t::iterator iter = levelLoader.m_Entities.m_Entities.begin(); iter != levelLoader.m_Entities.m_Entities.end(); ++iter )
		(*iter)->restart();
	fadeEffect.reset();
	game.m_bLevelFinnished = false;
	setLevelEnvironment();
	gibsSystem.restart();
	global_time::timeStart();
	HUDMessages::HUD_messages.deleteAll();
}

void CGame::renderEmptyScreen()
{
	fadeEffect.update( 0.00f );	//doesnt matter the number

	glPushAttrib( GL_CURRENT_BIT | GL_ENABLE_BIT );
	glPushMatrix();

	glClear( GL_DEPTH_BUFFER_BIT );
	glDisable(GL_DEPTH_TEST);
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	glOrtho(0, systemconf::getSystemInfo().m_iResolutionWidth, 0, systemconf::getSystemInfo().m_iResolutionHeight, -1, 1);
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();

	fadeEffect.render();

	renderLogo();
	
	glPopAttrib();
	glPopMatrix();
}


void CGame::renderLogo()
{
	if( m_pLogoTexture && m_bDisplayLogo && ( (m_uiGameTime < GAME_LOGO_LEVEL_IN_DURATION + GAME_LOGO_LEVEL_IN_FADE_OUT_DURATION) || !m_bLevelStarted ) )
	{
		float alpha = 1.0f;
		if( m_bLevelStarted )
		{
			if( m_uiGameTime > GAME_LOGO_LEVEL_IN_DURATION )
			{
				alpha = 1.0f - (float)(m_uiGameTime - GAME_LOGO_LEVEL_IN_DURATION) / (float)GAME_LOGO_LEVEL_IN_FADE_OUT_DURATION;
			}
		}

		glEnable( GL_BLEND );
		glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
		glPushAttrib( GL_CURRENT_BIT );
		glColor4f( 1,1,1, alpha );
		texBind( m_pLogoTexture->texture_id );
		glCallList( m_LogoDList );
		glPopAttrib();
	}
}

void CGame::gameLoop()
{
	if( !m_bLevelFinnished && m_pPlayer && m_pPlayer->isDeath() )
		onPlayerDeath();
	
	if( !levelLoader.isLevelLoaded() )
	{
		renderEmptyScreen();
		gameControl::game_control.futureCommandsProceed();
		return;
	}



	m_uiTimeNormal = global_time::getGlobalTime() - m_uiTimeNormalDelay - m_uiTimeNormalDelayTotal;
	m_uiPlayerTime = global_time::getGlobalTime() - m_uiPlayerTimeDelayTotal - m_uiPlayerTimeDelay - m_uiBackTimeDelay;	//hracuv cas
	m_uiGameTime = m_uiTimeNormal - m_uiBackTimeDelay;	//herni cas

	Uint32 g = global_time::getGlobalTime();
	if( m_uiTotalTimeUpdatesDone < (global_time::getGlobalTime()-m_uiBackTimeDelay) / TIME_TRAVEL_PERIOD_UPDATE )
	{
		m_uiTotalTimeUpdatesDone++;
		for( list<CBaseEntity*>::iterator iter = levelLoader.m_Entities.m_RunnableEntities.begin(); iter != levelLoader.m_Entities.m_RunnableEntities.end(); ++iter )
			(*iter)->updateBackTime();
	}


	m_uiSupposedFramesCount = global_time::getGlobalTime() / systemController::RUNTIME_PERIOD;
	if( m_uiSupposedFramesCount > m_uiTotalFramesDone )
	{
		m_uiTotalFramesDone++;	//pocet provedenych period
		m_iuFrameStart = global_time::getGlobalTime();	//cas pocatku periody
		//int timeDiff = (int)m_uiTotalFramesDone*systemController::RUNTIME_PERIOD - (int)m_uiTimeServed;	//rozdil celkoveho casu a poskytnuteho casu updatum
		//if( timeDiff > 0 )
		//m_uiTimeServed -= timeDiff;	//jejich rozdil se musi zde korigovat
		//basic run once per 30ms
		if( m_iCurrentActiveSkill != SK_NO_SKILL )
			proceedSkills();
		run();
	}



	

	Uint32 t = min( systemController::RUNTIME_PERIOD, global_time::getGlobalTime() - m_iuFrameStart) % systemController::RUNTIME_PERIOD;	//cas od zacatku periody
	float period_part = (float)t / (float)systemController::RUNTIME_PERIOD;	//procentuelni postup casu v periode
	FrameTime frame;
	frame.period_percentage = period_part;


	if( m_uiTimeServed < m_uiTimeNormal )
	{
		Uint32 uiAddTime = m_uiTimeNormal - m_uiTimeServed;	//ubehnuty cas
		if( uiAddTime > 1000 )
			uiAddTime = uiAddTime;
		m_uiTimeServed += uiAddTime;

		frame.elapsed_seconds = (float)(uiAddTime) / 1000.0f;
	}
	else
	{
		frame.elapsed_seconds = 0;
	}


	if( m_uiTotalTexturesAnimationsCount <  m_uiTimeNormal / 80 )	//tento cas vypada dobre
	{
		m_uiTotalTexturesAnimationsCount++;
		m_GlobalTexturesPool.Pool_animNextAll();
		frame.texturesAnim = true;
	}
	else
		frame.texturesAnim = false;



	if( m_bLevelStarted )
	{
		RenderData renderData;
		renderData.cameraPosition = &m_pPlayer->getRenderOrigin();
		renderData.frameTimes = frame;
		renderData.backfacecull = true;
		renderData.alpha = false;


		switch( m_iCurrentActiveSkill  )
		{
			case SK_TIME_TRAVEL:
				renderData.frameTimes.period_percentage = 1.0f;
				m_pPlayer->render( renderData );	//tady se ani hrac nema co pohybovat
				break;
			case SK_FORWARD_TELEPORT:
			case SK_STOP_TIME:
				m_pPlayer->render( renderData );	//tady se hrac muze normalne pohybovat
				renderData.frameTimes.period_percentage = 1.0f;
				break;
			default:
				m_pPlayer->render( renderData );
		}

		
		drawscene( frame );
	}


}


void CGame::updateEntities( float seconds )
{
	for( list<CBaseEntity*>::iterator iter = levelLoader.m_Entities.m_RunnableEntities.begin(); iter != levelLoader.m_Entities.m_RunnableEntities.end(); ++iter )
		(*iter)->update( seconds );
}

void CGame::allowEntity( CBasePhysics *entity )
{
	for( std::list<CBasePhysics*>::iterator iter = m_AllowedEntities.begin(); iter != m_AllowedEntities.end(); ++iter )
	{
		if( (*iter) == entity )
			return;
	}
	m_AllowedEntities.push_back( entity );
}


/* Funkce volana za urcity cas, funkce spousti podobne funkce pro ostatni objekty aplikace */
void CGame::run()
{
		if( !m_bLevelFinnished )
			m_iCurrentCrosshair = CROSSHAIR_DEFAULT;

		m_bUpdateFrustum = true;
		HUDMessages::HUD_messages.run();

		calculateVecDir();	//vypocet vektoru pohledu
		
		switch( m_iCurrentActiveSkill  )
		{
			case SK_FORWARD_TELEPORT:
				{
					Vector teleport_movement( vecDir, m_uiTeleportSpeed );
					m_pPlayer->setVelocity( teleport_movement );	//reset pohybu
					m_pPlayer->setFriction( 0.0f );
					m_uiTeleportSpeed += SK_FRWRD_TEL_SPEED_STEP;
					collisionSystem.processMoving( m_AllowedEntities );
					m_pPlayer->update( 0.03f );
					gameControl::game_control.futureCommandsProceed();
				}
				break;
			case SK_STOP_TIME:
				gameControl::game_control.run();	//moving + future commands
				collisionSystem.processMoving( m_AllowedEntities );
				m_pPlayer->update( 0.03f );
				break;
			case SK_TIME_TRAVEL:
				gameControl::game_control.futureCommandsProceed();
				break;
			default:
				gameControl::game_control.run();	//moving + future commands
				{
					Point origin = m_pPlayer->origin;
					
					collisionSystem.processMoving( levelLoader.m_Entities.m_PhysicModels );
				
					if( m_pPlayer->origin.x > 1535.9999f )
					{
  						bool x = true;
						/*while( x )
						{
							m_pPlayer->teleport( origin - m_pPlayer->origin );
							m_pPlayer->setMoveVector( movement );

							collisionSystem.processMoving( levelLoader.m_Entities.m_PhysicModels );
						
						}*/
					
					
					}
					



				}
				updateEntities( 0.03f );
		}

		
		weapon_manager::weaponManager.run();
			

		bullet_tracks::run();
		fadeEffect.update( 0.03f );
		

		snowSystem.update( 0.03f );
			
		environment.run();
		
		m_fWFov = m_Frustum.m_fHalfWFov;
		m_fTargetFOV = (float)gamevarsLibrary::getiData( vardef::DEFAULT_FOV_NAME );
		if( m_iCurrentActiveSkill == SK_FORWARD_TELEPORT )
		{
			m_fTargetFOV = getFromRange((1.0f -  m_uiTeleportSpeed / SK_FRWRD_TEL_MAX_SPEED) * 60.0f + 30.0f, 30.0f, 130.0f);
		}

		if( m_fDefaultFov < m_fTargetFOV )
		{
			m_fDefaultFov += min( m_fTargetFOV-m_fDefaultFov,1.0f);
		}
		else if( m_fDefaultFov > m_fTargetFOV )
		{
			m_fDefaultFov -= min( m_fDefaultFov-m_fTargetFOV,1.0f);
		}

			
		m_fMaxDistance = gamevarsLibrary::getfData( vardef::MAX_DISTANCE_NAME );
		
		if( m_pPlayer )
			collisionSystem.processPlayerPointing();


		soundLibrary.run();

		/*Uint32 startTime = SDL_GetTicks();

		for( int i = 0; i < iteration; i++ )
		{

			RayTraceData rayData;
			rayData.ray = Line( -m_ViewInterpolation.current, Vector( 1.0f,1.2f,0) );
			rayData.vzdaleny = rayData.ray + Vector( rayData.ray.m_vecDirection, 4092 );
			rayData.distance = 4092;
			rayData.determineDistance();
			collisionSystem.rayTraceVIS( rayData );
		}

		cout << iteration << " " << SDL_GetTicks() - startTime << endl;*/
		
}

void CGame::onPointingFinnished( RayTraceData &rayData )
{
	if( rayData.target != NULL )
	{
		if( ((CBaseEntity*)rayData.target)->getProperties() & ENT_PARM_INTERACTIVE )
			m_iCurrentCrosshair = CROSSHAIR_HAND;
	}
}


void CGame::setBasicDrawSettings()
{
	w = (float)systemconf::getSystemInfo().m_iResolutionWidth;
	h = (float)systemconf::getSystemInfo().m_iResolutionHeight;

    glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	gluPerspective( m_fDefaultFov, w/h, 0.1, m_fMaxDistance );
	glMatrixMode(GL_MODELVIEW); 
	glLoadIdentity();

}

void CGame::setBasicDrawMatrixes()
{
	if( m_pPlayer != NULL)
	{
		glRotatef(m_pPlayer->angles.x, 1.0f, 0.0f, 0.0f);
		if( m_pPlayer->isDeath())
			glRotatef(45, 0.0f, 0.0f, 1.0f);
		glRotatef(((m_pPlayer->angles.z*-1 + 90.0f)), 0.0f, 1.0f, 0.0f);
		

	}
	glRotatef(-90.0f, 1.0f, 0.0f, 0.0f);	//zmena os..zamena Y za Z

}



void CGame::setCurrentTranslateMatrix()
{
	Point origin = m_pPlayer->getRenderOrigin();
	glTranslatef( -origin.x, -origin.y, -origin.z );
}


#include "level_render.h"

void CGame::drawscene(  FrameTime &frame )
{
	glPushAttrib( GL_ENABLE_BIT );
	//glClear( GL_COLOR_BUFFER_BIT );
	glClear(GL_DEPTH_BUFFER_BIT );               // vymazani vsech bitovych rovin barvoveho bufferu
	glEnable( GL_DEPTH_TEST );   
	/*	Basic settings	*/
	glEnable(GL_CULL_FACE);
	glFrontFace(GL_CW);
	glCullFace(GL_BACK);
	
	glDisable(GL_ALPHA_TEST);
	glAlphaFunc(GL_GREATER, 0.5f);
	glEnable(GL_TEXTURE_2D);
	glDisable(GL_LIGHTING);
	glDisable(GL_BLEND);
	glDisable(GL_STENCIL_TEST);
	glShadeModel(GL_SMOOTH); 
	glColor3f(1.0f,1.0f,1.0f);
	/*		*/
	

	
	/* Console */
	
		
	/*if(m_iRunningLevel == RUN_MAINMENU && m_bEnviromentAnimation)
		m_fSkyDistance += 758;*/

	setBasicDrawSettings();
	glPushMatrix();
	setBasicDrawMatrixes();
	

	RenderData renderData;
	renderData.cameraPosition = &m_pPlayer->getRenderOrigin();
	renderData.frustum = &m_Frustum;
	renderData.frameTimes = frame;


	environment.drawSkyBox();
	
	setCurrentTranslateMatrix();

	m_Frustum.updateFrustumPlanes( vecDir, m_pPlayer->getRenderOrigin()/*m_ViewInterpolation.current*/, 0.1f,  m_fMaxDistance, m_fDefaultFov, (float)w, (float)h );

	renderer.draw( renderData );
	
	
	//environment.drawHighmap();

	

	//end of 3D projection
	
	bullet_tracks::draw();
	

	glPopMatrix();
	
	drawWeapon();

	glDisable( GL_CULL_FACE );
	glDisable(GL_DEPTH_TEST);
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	glOrtho(0, systemconf::getSystemInfo().m_iResolutionWidth, 0, systemconf::getSystemInfo().m_iResolutionHeight, -1, 1);
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();

	HUDMessages::HUD_messages.draw();

	fadeEffect.render();


	if( m_pLogoTexture && m_bDisplayLogo && m_uiGameTime < GAME_LOGO_LEVEL_IN_DURATION + GAME_LOGO_LEVEL_IN_FADE_OUT_DURATION )
	{
		float alpha = 1.0f;
		if( m_uiGameTime > GAME_LOGO_LEVEL_IN_DURATION )
		{
			alpha = 1.0f - (float)(m_uiGameTime - GAME_LOGO_LEVEL_IN_DURATION) / (float)GAME_LOGO_LEVEL_IN_FADE_OUT_DURATION;
		}
		
		glEnable( GL_BLEND );
		glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
		glPushAttrib( GL_CURRENT_BIT );
		glColor4f( 1,1,1, alpha );
		texBind( m_pLogoTexture->texture_id );
		glCallList( m_LogoDList );
		glPopAttrib();
	
	
	
	}





	glPopAttrib();

}




void CGame::drawWeapon()
{
	glPushAttrib( GL_ENABLE_BIT | GL_CURRENT_BIT );
	glEnable( GL_BLEND );
	glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
	if( m_pPlayer )
	glColor4f( m_pPlayer->rendercolor.x,m_pPlayer->rendercolor.y,m_pPlayer->rendercolor.z, ( (m_fDefaultFov-30.0f) ) / 60.0f );
	weapon_manager::weaponManager.draw();
	glPopAttrib();
}

