/*****************************/
/* Inside The Machine - MKS  */
/*****************************/

//Includes
#include "WorldManager.h"
#include "entities/Entity.h"
//GFXS

//MAPS
	#include "maps/Level_one_entrance.map.c"
	#include "maps/Level_one_entrance_layer.map.c"
	#include "maps/Level_one_entrance_coll.map.c"
	//-----
	#include "maps/Level_two_inside.map.c"
	#include "maps/Level_two_inside_layer.map.c"
	#include "maps/Level_two_inside_coll.map.c"
	//-----
	#include "maps/Level_three_canal.c"
	#include "maps/Level_three_canal_layer.c"
	#include "maps/Level_three_canal_coll.c"
	//-----
	#include "maps/Level_four_exit.map.c"
	#include "maps/Level_four_exit_layer.map.c"
	#include "maps/Level_four_exit_coll.map.c"
//LISTES
	#include "maps/Level_one_entrance_list.lst.c"
	#include "maps/Level_two_inside_list.lst.c"
	#include "maps/Level_three_canal_list.c"
	#include "maps/Level_four_exit.lst.c"
	
CWorldManager::CWorldManager()
{
   for(int k = 0; k < 8; k++)
   	bgscroll[k] = 0;
   cameraMode = CAMERA_FOLLOW;
   depthLevelSprites = depthBackgroundLevel = depthSpritesForeground = 0;
   
   resMan = CRessourceManager::getInstance();
   heroLoaded = false;
   toRestart = false;
   isFightingBoss = false;
   isBossKilled = false;
   waypoint = false;
   isScrollEnd = false;
   isGameFinished = false;
   isFirstLoad = true;
   lastLevel = false;

   //On charge quelques gfx'
   ulSetTransparentColor(RGB15(31, 0, 31));
   heroIcon.assign(ulEFSLoadPNG("efs:/Gui_HeroIcon.png", UL_IN_VRAM, UL_PF_PAL4));
   heroBarOver.assign(ulEFSLoadPNG("efs:/Gui_Bar_Over.png", UL_IN_VRAM, UL_PF_PAL2));
   heroLifeBar.assign(ulEFSLoadPNG("efs:/Gui_LifeBar.png", UL_IN_VRAM, UL_PF_PAL4));
   heroEnergyBar.assign(ulEFSLoadPNG("efs:/Gui_EnergyBar.png", UL_IN_VRAM, UL_PF_PAL4));
   ulDisableTransparentColor();
}

void CWorldManager::SetLevel(int lev)
{
   switch(lev)
   {
      case LEV_LEVEL1:
         curLevel = &itmLevel_1;
      break;
      
      case LEV_LEVEL2:
         curLevel = &itmLevel_2;
      break;
      
      case LEV_LEVEL3:
         curLevel = &itmLevel_3;
      break;
      
      case LEV_LEVEL4:
         curLevel = &itmLevel_4;
      break;
   };
}

void CWorldManager::LoadLevel()
{
   //Chargemment du niveau
   switch(curLevel->id)
   {
   	//Niveau Entrance 1
   	case LEV_LEVEL1:
   	   	//Chargemment des chipsets/BGs
   	      ulSetTransparentColor(RGB15(31, 0, 31));
			   curLevel->chipset = ulEFSLoadPNG("efs:/Chipset_Entrance.png", UL_IN_VRAM, UL_PF_PAL8);
			   curLevel->background = ulEFSLoadPNG("efs:/BG_Entrance.png", UL_IN_VRAM, UL_PF_PAL4);
				curLevel->background->x = 0;
				ulDisableTransparentColor();
				curLevel->chipset_coll = ulEFSLoadPNG("efs:/Chipset_Entrance_coll.png", UL_IN_RAM, UL_PF_PAL8);
				//Chargemment des maps
				curLevel->map = ulCreateMap(curLevel->chipset, (void*)Level_one_entrance_map, 16, 16, curLevel->lx, curLevel->ly, UL_MF_U16);
				curLevel->map1 = ulCreateMap(curLevel->chipset, (void*)Level_one_entrance_layer_map, 16, 16, curLevel->lx, curLevel->ly, UL_MF_U16);
				curLevel->map_coll = ulCreateMap(curLevel->chipset_coll, (void*)Level_one_entrance_coll_map, 16, 16, curLevel->lx, curLevel->ly, UL_MF_U16);
				//Chargemment de la liste
				LoadEntities(Level_one_entrance_list_liste, &Level_one_entrance_list_liste_nbEle);
				MakePentes();
		break;
		
		//Niveau Inside 2
   	case LEV_LEVEL2:
   	   	//Chargemment des chipsets/BGs
   	      ulSetTransparentColor(RGB15(31, 0, 31));
			   curLevel->chipset = ulEFSLoadPNG("efs:/Chipset_Inside.png", UL_IN_VRAM, UL_PF_PAL8);
			   curLevel->background = ulEFSLoadPNG("efs:/BG_Inside.png", UL_IN_VRAM, UL_PF_PAL4); //ToFix
				curLevel->background->x = 0;
				ulDisableTransparentColor();
				curLevel->chipset_coll = ulEFSLoadPNG("efs:/Chipset_Inside_coll.png", UL_IN_RAM, UL_PF_PAL8);
				//Chargemment des maps
				curLevel->map = ulCreateMap(curLevel->chipset, (void*)Level_two_inside_map, 16, 16, curLevel->lx, curLevel->ly, UL_MF_U16);
				curLevel->map1 = ulCreateMap(curLevel->chipset, (void*)Level_two_inside_layer_map, 16, 16, curLevel->lx, curLevel->ly, UL_MF_U16);
				curLevel->map_coll = ulCreateMap(curLevel->chipset_coll, (void*)Level_two_inside_coll_map, 16, 16, curLevel->lx, curLevel->ly, UL_MF_U16);
				//Chargemment de la liste
				LoadEntities(Level_two_inside_list_liste, &Level_two_inside_list_liste_nbEle);
				MakePentes();
		break;
		
		//Niveau Canal 3
   	case LEV_LEVEL3:
   	   	//Chargemment des chipsets/BGs
   	      ulSetTransparentColor(RGB15(31, 0, 31));
			   curLevel->chipset = ulEFSLoadPNG("efs:/Chipset_Machine_Canal.png", UL_IN_VRAM, UL_PF_PAL8);
			   curLevel->background = ulEFSLoadPNG("efs:/BG_Inside2.png", UL_IN_VRAM, UL_PF_PAL4); //ToFix
				curLevel->background->x = 0;
				ulDisableTransparentColor();
				curLevel->chipset_coll = ulEFSLoadPNG("efs:/Chipset_Machine_Canal_coll.png", UL_IN_RAM, UL_PF_PAL8);
				//Chargemment des maps
				curLevel->map = ulCreateMap(curLevel->chipset, (void*)Level_three_canal_map, 16, 16, curLevel->lx, curLevel->ly, UL_MF_U16);
				curLevel->map1 = ulCreateMap(curLevel->chipset, (void*)Level_three_canal_layer_map, 16, 16, curLevel->lx, curLevel->ly, UL_MF_U16);
				curLevel->map_coll = ulCreateMap(curLevel->chipset_coll, (void*)Level_three_canal_coll_map, 16, 16, curLevel->lx, curLevel->ly, UL_MF_U16);
				//Chargemment de la liste
				LoadEntities(Level_three_canal_list_liste, &Level_three_canal_list_liste_nbEle);
				MakePentes();
		break;
		
		//Niveau Exit 4
   	case LEV_LEVEL4:
   	   	//Chargemment des chipsets/BGs
   	      ulSetTransparentColor(RGB15(31, 0, 31));
			   curLevel->chipset = ulEFSLoadPNG("efs:/Chipset_Exit.png", UL_IN_VRAM, UL_PF_PAL8);
			   curLevel->background = ulEFSLoadPNG("efs:/BG_Inside3.png", UL_IN_VRAM, UL_PF_PAL4); //ToFix
				curLevel->background->x = 0;
				ulDisableTransparentColor();
				curLevel->chipset_coll = ulEFSLoadPNG("efs:/Chipset_Inside_coll.png", UL_IN_RAM, UL_PF_PAL8);
				//Chargemment des maps
				curLevel->map = ulCreateMap(curLevel->chipset, (void*)Level_four_exit_map, 16, 16, curLevel->lx, curLevel->ly, UL_MF_U16);
				curLevel->map1 = ulCreateMap(curLevel->chipset, (void*)Level_four_exit_layer_map, 16, 16, curLevel->lx, curLevel->ly, UL_MF_U16);
				curLevel->map_coll = ulCreateMap(curLevel->chipset_coll, (void*)Level_four_exit_coll_map, 16, 16, curLevel->lx, curLevel->ly, UL_MF_U16);
				//Chargemment de la liste
				LoadEntities(Level_four_exit_liste, &Level_four_exit_liste_nbEle);
				MakePentes();
				lastLevel = true;
		break;
   };
	
	//Chargemment de la musique
	if(isFirstLoad == false)
		FreeMusic(music);
	music = LoadMusic(curLevel->music);
	AS_MP3DirectPlay(music.data, music.size);
	isFightingBoss = false;
	isFirstLoad = false;
}

void CWorldManager::RestartLevel(bool way)
{
   //Vidage de la liste d'entités
   bool first = false;
   for(eListItor = eList.begin(); eListItor != eList.end();)
	{
	   //On supprime toutes les entités après le héros
		delete (*eListItor);
		eList.erase(eListItor++);		  		
	}
	
	//Rechargemment des entités
	switch(curLevel->id)
	{
	 	case LEV_LEVEL1:
	 	   LoadEntities(Level_one_entrance_list_liste, &Level_one_entrance_list_liste_nbEle);
		break;
		
		case LEV_LEVEL2:
		   LoadEntities(Level_two_inside_list_liste, &Level_two_inside_list_liste_nbEle);
		break;
		
		case LEV_LEVEL3:
		   LoadEntities(Level_three_canal_list_liste, &Level_three_canal_list_liste_nbEle);
		break;
		
		case LEV_LEVEL4:
		   LoadEntities(Level_four_exit_liste, &Level_four_exit_liste_nbEle);
		break;
	}   	
	
	isFightingBoss = false;
	isScrollEnd = false;
	
	//Waypoint
	if(waypoint)
	{
	   hero->x = FIX(wayPointx);
	   hero->y = FIX(wayPointy);
	}  
}   

void CWorldManager::MakePentes()
{
   int ttX=0;
	int tX=0;
	int tY=0;
	for(int i=3;i<=9;i++)		
	{
		if(ttX == 0 && curLevel->map_coll->img->sysSizeX <= 1 << i)
			ttX = i;
		if(tX == 0 && curLevel->map_coll->tileX <= 1 << i)
			tX = i;
		if(tY == 0 && curLevel->map_coll->tileY <= 1 << i)
			tY = i;
	}
	//On analyse chaque tile a partir de chaque v envoyé
	for(int i = 0; i < curLevel->pentesNbr; i++)
	{
	   int v = curLevel->v_pentes[i];
	   PenteInfo pente;
	   pente.v = v;

	   int u0 = ((v << tX) & ((1 << ttX) - 1));
		int v0 = ((v << tX) >> ttX) << tY;
		
		//On parcours tout les pixels du tile donné
		//Pour chaque ligne...
		for(u8 x = 0; x < 16; x++)
		{
		   //Pour chaque colonne
		   for(u8 y = 0; y < 16; y++)
		   {
		   	//On récupère le pixel (on suppose tjrs une image 8 bits et des tiles de 16²)
		   	void *pPixel = ulGetImageLineAddr(curLevel->map_coll->img, v0+y);
		   	u8 pix = ((u8*)pPixel)[u0+x];
		   	//Si ce pixel est bleu on enregistre les positions
		   	if(pix == 3)
		   	{
		   		pente.hauteur[x] = y;
		   		//On arrête la recherche
		   		break;
		   	}  
		   }
		}
		//On ajoute la structure a la map
		//pentes.push_back(pente);		   
		pentes[v] = pente;
	}   	  
}   

void CWorldManager::FreeLevel()
{
   //Vidage de la liste d'entités
   for(eListItor = eList.begin(); eListItor != eList.end();)
	{
	   delete (*eListItor);
	   eList.erase(eListItor++);
	}
	
	//On vide les ressources du resman
	resMan->Free();
	
   //Libération des chipsets/BGs
	ulDeleteImage(curLevel->chipset);
	ulDeleteImage(curLevel->background);
	ulDeleteImage(curLevel->chipset_coll);
	
	//Libération des maps
	ulDeleteMap(curLevel->map);
	ulDeleteMap(curLevel->map1);
	ulDeleteMap(curLevel->map_coll);
	
	heroLoaded = false;
   toRestart = false;
   isFightingBoss = false;
   isBossKilled = false;
   waypoint = false;
   isScrollEnd = false;
   cameraMode = CAMERA_FOLLOW;
	toRestart = false;   
	
   //Libération de la musique
   AS_MP3Stop();
   FreeMusic(music);
}   
   
void CWorldManager::HandleWorld()
{
   //On change la vitesse de la musique
   if(isFightingBoss)
      AS_SetMP3Rate(27050);
   else
      AS_SetMP3Rate(22050);
   //**Mise a jour du monde**
   //Ajustement du scrolling en fonction du personnage
   SetCamera();

   //**Mise a jour des entités**
	for(eListItor = eList.begin(); eListItor != eList.end();)
	{
	   //On vérifie si il faut supprimer une entité
	   if((*eListItor)->toDelete == true)
	   {
	   	//ulDebug("Entity Deleted\n");
	   	//TODO : Corriger cette foutue fuite de mémoire... (Corrigé)
	      //eListItor = eList.erase(eListItor);
	      delete (*eListItor);
	      eList.erase(eListItor++);
	   }
		else
		{   
		   //On enregistre l'ancienne position des entités
		   (*eListItor)->oldx = (*eListItor)->x;
		   (*eListItor)->oldy = (*eListItor)->y;
		   
		   //Update perso des entités
			(*eListItor)->Update();
			
			//On vérifie les intéractions entre entités
			if((*eListItor)->actif && (*eListItor)->real)
				(*eListItor)->CheckInteractions();
			
			//Itération
			++eListItor;
		}			
	}
	
	//On vérifie si il faut recharger le niveau
	if(toRestart == true)
	{
		WorldState::Instance()->UnFadeWhite();
		RestartLevel(false);
		cameraMode = CAMERA_FOLLOW;
		toRestart = false;    
	}   
		
}

void CWorldManager::DrawWorld()
{
   //**Affichage du monde**
   //Affichage du Background Color
   ulDrawGradientRect(0, 0, 256, 192, curLevel->topColor, curLevel->topColor, curLevel->botColor, curLevel->botColor);
	
	//Affichage du background : Scrolling Parallaxe
	DrawParallaxScrolling();
	
	//Affichage du paramètre de lumière
	/*ulMoveScreenView(UL_SCREEN_WIDTH / 2, UL_SCREEN_HEIGHT / 2);
	ulRotateScreenView(screenAngle);
	ulMoveScreenView(-UL_SCREEN_WIDTH / 2, -UL_SCREEN_HEIGHT / 2);*/
	if(curLevel->light == 2)
		DrawLight2();

	//Affichage du Layer 0 de la map 
	ulDrawMap(curLevel->map);
	for(eListItor = eList.begin(); eListItor != eList.end();++eListItor)
	{
		(*eListItor)->Draw(0);
		
		//On affichge les hitboxes
		//ulDrawRect((*eListItor)->x_screen + (*eListItor)->rect.x1, (*eListItor)->y_screen + (*eListItor)->rect.y1, (*eListItor)->x_screen + (*eListItor)->rect.x2, (*eListItor)->y_screen + (*eListItor)->rect.y2, RGB15(31, 0, 31) );
	}	
	
	//Affichage du Layer 1 de la map 
	for(eListItor = eList.begin(); eListItor != eList.end();++eListItor)  
	{
		(*eListItor)->Draw(1);
		
		//On affichge les hitboxes
		//ulDrawRect((*eListItor)->x_screen + (*eListItor)->rect.x1, (*eListItor)->y_screen + (*eListItor)->rect.y1, (*eListItor)->x_screen + (*eListItor)->rect.x2, (*eListItor)->y_screen + (*eListItor)->rect.y2, RGB15(31, 0, 31) );
	}
	ulDrawMap(curLevel->map1);
	ulResetScreenView();
	
	/*ulPrintf_xy(1, 40, "esize:%d", eList.size());
	ulSetTextColor(RGB15(31, 0, 0) );
	ulPrintf_xy(1, 50, "lx:%d ly:%d",curLevel->lx, curLevel->ly);*/
	//GetFramebuffer();
	
	//Affichage du GUI
		//Icone
	heroIcon.setXY(5, 5);
	heroIcon.draw();
		//Paramètrage de la vie du héros
	heroLifeBar.clip(0, 0, hero->life, 16);
	heroEnergyBar.clip(0, 0, UNFIX(hero->energy), 16);
		//Barres
	heroLifeBar.setXY(25, 5);
	heroEnergyBar.setXY(25, 5);
	heroLifeBar.draw();
	heroEnergyBar.draw();
		//Over
	heroBarOver.setXY(25, 5);
	heroBarOver.draw();
}

void CWorldManager::SetCamera()
{
   //Sauvegarde de l'ancienne position de la caméra
   oldScrollX = curLevel->map->scrollX;
   oldScrollY = curLevel->map->scrollY;
   
   //On vérifie si il faut changer de mode
   /*if(curLevel->map->scrollX >= fixPosx)
   	cameraMode = CAMERA_FIXED;*/
   //On met le bon scrolling en fonction du mode
   if(cameraMode == CAMERA_FOLLOW)
   {
      //On règle le scrolling au milieu de l'écran
   	curLevel->map->scrollX = curLevel->map1->scrollX = curLevel->map_coll->scrollX = UNFIX(hero->x) - 128;
   	curLevel->map->scrollY = curLevel->map1->scrollY = curLevel->map_coll->scrollY = UNFIX(hero->y) - 96;
   }
	else if(cameraMode == CAMERA_FIXED)
	{
		//On ne change plus le scrolling en X  et en Y
		//curLevel->map->scrollY = curLevel->map1->scrollY = curLevel->map_coll->scrollY = UNFIX(hero->y) - 96; 
		//ulDebug("plop2\n");
	}
	else if(cameraMode == CAMERA_FREE)
	{
	   //Test fin de scorlling
	   if(cameraDestx == curLevel->map->scrollX /*|| oldScrollX == curLevel->map->scrollX*/)
	   {
	    	cameraMode = CAMERA_FIXED;
	    	hero->isCanMove = true;
	    	//ulDebug("plop\n");
	   }
	   //Pendant un scroller
	   if(cameraDestx < curLevel->map->scrollX)
	   {
	    	curLevel->map->scrollX--;
			curLevel->map1->scrollX = curLevel->map_coll->scrollX = curLevel->map->scrollX;
			hero->isCanMove = false;
	   }
		if(cameraDestx > curLevel->map->scrollX)
	   {
	    	curLevel->map->scrollX++;
			curLevel->map1->scrollX = curLevel->map_coll->scrollX = curLevel->map->scrollX;
			hero->isCanMove = false;
	   }
		if(cameraDesty < curLevel->map->scrollY)
	   {
	    	curLevel->map->scrollY--;
			curLevel->map1->scrollY = curLevel->map_coll->scrollY = curLevel->map->scrollY;
			hero->isCanMove = false;
	   }
		if(cameraDesty > curLevel->map->scrollY)
	   {
	    	curLevel->map->scrollY++;
			curLevel->map1->scrollY = curLevel->map_coll->scrollY = curLevel->map->scrollY;
			hero->isCanMove = false;
	   }  	
	}   
    
   //Trop à gauche
	if(curLevel->map->scrollX < 0)
		curLevel->map->scrollX = curLevel->map1->scrollX = curLevel->map_coll->scrollX = 0;
	//Trop en haut
	if(curLevel->map->scrollY < 0)
		curLevel->map->scrollY = curLevel->map1->scrollY = curLevel->map_coll->scrollY = 0;
	//Trop à droite
	if(curLevel->map->scrollX + 256 > curLevel->lx<<4)
		curLevel->map->scrollX = curLevel->map1->scrollX = curLevel->map_coll->scrollX = (curLevel->lx<<4) - 256;
	//Trop en bas 
	if(curLevel->map->scrollY + 192 > curLevel->ly<<4)
		curLevel->map->scrollY = curLevel->map1->scrollY = curLevel->map_coll->scrollY = (curLevel->ly<<4) - 192;
}

void CWorldManager::ScrollCamera(int xdest, int ydest)
{
   cameraDestx = xdest;
   cameraDesty = ydest;
   cameraMode = CAMERA_FREE;
   hero->isCanMove = false;
}   

void CWorldManager::DrawParallaxScrolling()
{ 
   //TODO : à optimiser sévèrement si il y a chutes de framerate
   //------ c'est vraiment codé comme un bourrin o:
	//Etage 1
	//On teste dans quel sens à bougé le scrolling (valeurs fixed point)
   scrollXSens = 0;
   if(oldScrollX > curLevel->map->scrollX)
   	scrollXSens = 256;
   if(oldScrollX == curLevel->map->scrollX)
   	scrollXSens = 0;
   if(oldScrollX < curLevel->map->scrollX)
   	scrollXSens = -256;
   	
   //On teste les limites
   if(bgscroll[0] < -(256<<8))
		bgscroll[0] = 0;
	if(bgscroll[0] > 0)
		bgscroll[0] = -(256<<8);
		
   bgscroll[0] += scrollXSens;
	ulSetImageTileSize(curLevel->background, 0, 0, 256, 32);
	ulDrawImageXY(curLevel->background, bgscroll[0]>>8, 0);
	ulDrawImageXY(curLevel->background, (bgscroll[0]>>8)+256, 0);

	//Etage 2
	//On teste dans quel sens à bougé le scrolling (valeurs fixed point)
   scrollXSens = 0;
   if(oldScrollX > curLevel->map->scrollX)
   	scrollXSens = 128;
   if(oldScrollX == curLevel->map->scrollX)
   	scrollXSens = 0;
   if(oldScrollX < curLevel->map->scrollX)
   	scrollXSens = -128;
   	
	//On teste les limites
   if(bgscroll[1] < -(256<<8))
		bgscroll[1] = 0;
	if(bgscroll[1] > 0)
		bgscroll[1] = -(256<<8);
	bgscroll[1] += scrollXSens;
	ulSetImageTileSize(curLevel->background, 0, 32, 256, 16);
	ulDrawImageXY(curLevel->background, bgscroll[1]>>8, 32);
	ulDrawImageXY(curLevel->background, (bgscroll[1]>>8)+256, 32);
	
	//Etage 3
	//On teste dans quel sens à bougé le scrolling (valeurs fixed point)
   scrollXSens = 0;
   if(oldScrollX > curLevel->map->scrollX)
   	scrollXSens = 64;
   if(oldScrollX == curLevel->map->scrollX)
   	scrollXSens = 0;
   if(oldScrollX < curLevel->map->scrollX)
   	scrollXSens = -64;
   	
	//On teste les limites
   if(bgscroll[2] < -(256<<8))
		bgscroll[2] = 0;
	if(bgscroll[2] > 0)
		bgscroll[2] = -(256<<8);
	bgscroll[2] += scrollXSens;
	ulSetImageTileSize(curLevel->background, 0, 48, 256, 16);
	ulDrawImageXY(curLevel->background, bgscroll[2]>>8, 48);
	ulDrawImageXY(curLevel->background, (bgscroll[2]>>8)+256, 48);
	
	//Etage 3bis
	/*ulSetImageTileSize(curLevel->background, 0, 64, 256, 32);
	ulDrawImageXY(curLevel->background, bgscroll[2]>>8, 64);
	ulDrawImageXY(curLevel->background, (bgscroll[2]>>8)+256, 64);*/
	
	//Etage 4
	//On teste dans quel sens à bougé le scrolling (valeurs fixed point)
   scrollXSens = 0;
   if(oldScrollX > curLevel->map->scrollX)
   	scrollXSens = 32;
   if(oldScrollX == curLevel->map->scrollX)
   	scrollXSens = 0;
   if(oldScrollX < curLevel->map->scrollX)
   	scrollXSens = -32;
   	
	//On teste les limites
   if(bgscroll[3] < -(256<<8))
		bgscroll[3] = 0;
	if(bgscroll[3] > 0)
		bgscroll[3] = -(256<<8);
	bgscroll[3] += scrollXSens;
	ulSetImageTileSize(curLevel->background, 0, 64, 256, 64);
	ulDrawImageXY(curLevel->background, bgscroll[3]>>8, 64);
	ulDrawImageXY(curLevel->background, (bgscroll[3]>>8)+256, 64);
	
	//Etage 5	
	ulSetImageTileSize(curLevel->background, 0, 128, 256, 16);
	ulDrawImageXY(curLevel->background, bgscroll[2]>>8, 128);
	ulDrawImageXY(curLevel->background, (bgscroll[2]>>8)+256, 128);
	
	//Etage 6	
	ulSetImageTileSize(curLevel->background, 0, 144, 256, 16);
	ulDrawImageXY(curLevel->background, bgscroll[1]>>8, 144);
	ulDrawImageXY(curLevel->background, (bgscroll[1]>>8)+256, 144);
	
	//Etage 7
	ulSetImageTileSize(curLevel->background, 0, 160, 256, 32);
	ulDrawImageXY(curLevel->background, bgscroll[0]>>8, 160);
	ulDrawImageXY(curLevel->background, (bgscroll[0]>>8)+256, 160);
}

void CWorldManager::DrawLight2()
{
	//Affichage des vertex de lumière
	ulSetAlpha(UL_FX_ALPHA, 8, 1);
	//Rayon 1
	drawQuad(0, 15, 53, 192, 72, 192, 0, 0, RGB15(31, 31, 31));
	//Rayon 2
	drawQuad(0, 0, 100, 192, 156, 192, 15, 0, RGB15(31, 31, 31));
	//Rayon 3
	drawQuad(17, 0, 165, 192, 177, 192, 20, 0, RGB15(31, 31, 31));
	ulSetAlpha(UL_FX_DEFAULT, 8, 1);
	ulVertexHandleDepth();
}   

void CWorldManager::HBLFunc()
{ 
   //Update du VCount
   vcount = PA_GetVcount();
	vcount++;
	if(vcount >= 192) 
		vcount = 0;
		
   //Gestion des fausses lumières : Autour du héros
   /*if(curLevel->light == 0)
   {
	   u8 y;
	   int r = 50;
	   if(vcount < yCircle1) 
			y = yCircle1 - vcount;
		else 
			y = vcount - yCircle1;
			
		//Une equation de base du cercle est : x2 + y2 = r2
		//On cherche x, on en deduit que : x = SQRT(r*r-y*y)
		u16 x = getSQRT(r*r - y*y);
		
		//On calcule les coordonées de la "bande de fenetre"
		if(xCircle1 - x < 0) 
		   x1Fen1 = 0;
		else 
			x1Fen1 = xCircle1 - x;
	 
		if(xCircle1 + x > 255) 
			x2Fen1 = 255;
		else
			x2Fen1 = xCircle1 + x;
	 
		PA_SetWin0XY(0, x1Fen1, vcount, x2Fen1, vcount+1);
	}*/	
}

void CWorldManager::UpdateAlphaBuffer()
{
   //On récupère l'image en RAM
   //ulLockImage(alphaBuffer, UL_LOCK_PIXELS);
   //ulUnrealizeImage(alphaBuffer);
   
   //On mets a jour les pixels
   for(int x = 0; x < 256; x++)
	{
	   for(int y = 0; y < 192; y++)
	   {
	      //On remplit les pixies
	      void *pPixel = ulGetImageLineAddr(alphaBuffer, y);
	      ((u8*)pPixel)[x] = (1 & 7) | (128 & ~7);
	      //pixels[x + y * 256] = (u8)((1 & 7) | (128 & ~7));
	      /*u8* pix = ((u8*)(pixels) + ((((y)*(alphaBuffer)->sysSizeX + (x)) * ul_pixelWidth[(alphaBuffer)->format])>>3));
	      *pix = (u8)((0 & 7) | (128 & ~7));*/
	   }   
	}
	//pixels[10] = (1 & 7) | (0 & ~7);
	   
   //On ramène l'image en vram
   //ulUnlockImage(alphaBuffer, UL_LOCK_PIXELS);
   //ulRealizeImage(alphaBuffer);
}   

void CWorldManager::GetFramebuffer()
{
   /*u8 * buffer;
   u8 vram_cr_temp = VRAM_C_CR;
	VRAM_C_CR = VRAM_C_LCD;

	u8* vram_temp = (u8*)malloc(128*1024);
	dmaCopy(VRAM_C, vram_temp, 128*1024);

	REG_DISPCAPCNT = DCAP_BANK(0)|DCAP_ENABLE|DCAP_SIZE(3);
	while(REG_DISPCAPCNT & DCAP_ENABLE);

	dmaCopy(VRAM_C, buffer, 256*192*2);
	dmaCopy(vram_temp, VRAM_C, 128*1024);
	
	VRAM_C_CR = vram_cr_temp;
	
	free(vram_temp);*/
}
   
void CWorldManager::SetGravity(u8 x, u8 y)
{
	curLevel->vgx = x;
	curLevel->vgy = y;
}

/*void CWorldManager::HBLFunc()
{
}  */ 

void CWorldManager::LoadEntities(const SPRITE_LISTE* lst, const unsigned int* len)
{ 
   //Parcours de la liste d'entités
   for(int i = 0; i < *len; i++)
   {
   	AddEntity(lst[i].x, lst[i].y, lst[i].type, lst[i].genre, lst[i].p1, lst[i].p2, (char*)lst[i].raw);
   }  
}
   
void CWorldManager::AddEntity(int x, int y, int type, int genre, int p1, int p2, char* raw)
{
	//Ajout des entités au tableau
	switch(type)
	{	   
	   case ENT_TYPE_ENNEMY:
	      AddEntEnnemy(x, y, genre, p1, p2, raw);
	   break;
	   
	   case ENT_TYPE_BOSS:
	      AddEntBoss(x, y, genre, p1, p2, raw);
	   break;
	   
	   case ENT_TYPE_EVENT:
	      AddEntEvent(x, y, genre, p1, p2, raw);
	   break;
	   
	   case ENT_TYPE_LOGIC:
	      AddEntLogic(x, y, genre, p1, p2, raw);
	   break;
	   
	   case ENT_TYPE_STATIC:
	      AddEntStatic(x, y, genre, p1, p2, raw);
	   break;
	}; 
}

void CWorldManager::AddEntHero(int x, int y, int genre, int p1, int p2, char* raw)
{
	//On ajoute l'entité Heros standard
	eHeroCat * cat = new eHeroCat();   //On crée l'entité héro
	cat->x = FIX(x), cat->y = FIX(y);  //On set la position de départ du héros
	cat->SetManager(this);             //On ajoute l'instance du Worldmanager au héros
	cat->Load();                       //On charge les gfx
	eList.push_back(cat);              //On ajoute le héros a la liste des entités
	hero = cat;                        //On ajoute l'adresse du héros a l'instance du héros du worldmanager
	heroLoaded = true;	
}
   
void CWorldManager::AddEntEnnemy(int x, int y, int genre, int p1, int p2, char* raw)
{
   //Création de tout les types d'entités possibles
   eEnnemyChuck * tmpEnnChuck;
   eFish * tmpEnnFish;
   eVSlime * tmpEnnSlime;
   eBall * tmpBall;
   
   //Sélecteur d'entités ennemies
   switch(genre)
   {
      case ENT_ENNEMY_CHUCK:
         //Création de l'ennemi
         tmpEnnChuck = NULL;
         tmpEnnChuck = new eEnnemyChuck();
         tmpEnnChuck->x = FIX(x), tmpEnnChuck->y = FIX(y);
         tmpEnnChuck->vitesse = p2, tmpEnnChuck->distx = FIX(p1);
         tmpEnnChuck->SetManager(this);
         tmpEnnChuck->Load();
         eList.push_back(tmpEnnChuck);
      break;
      
      case ENT_ENNEMY_FISH:
         //Création de l'ennemi
         tmpEnnFish = NULL;
         tmpEnnFish = new eFish();
         tmpEnnFish->x = FIX(x), tmpEnnFish->y = FIX(y);
         tmpEnnFish->vitesse = p2, tmpEnnFish->distx = FIX(p1);
         tmpEnnFish->SetManager(this);
         tmpEnnFish->Load();
         eList.push_back(tmpEnnFish);
      break;
      
      case ENT_ENNEMY_VSLIME:
         //Création de l'ennemi
         tmpEnnSlime = NULL;
         tmpEnnSlime = new eVSlime();
         tmpEnnSlime->x = FIX(x), tmpEnnFish->y = FIX(y);
         tmpEnnSlime->vitesse = p2, tmpEnnSlime->hy = FIX(p1);
         tmpEnnSlime->SetManager(this);
         tmpEnnSlime->Load();
         eList.push_back(tmpEnnSlime);
      break;
      
      case ENT_ENNEMY_BALL:
         //Création de l'ennemi
         tmpBall = NULL;
         tmpBall = new eBall();
         tmpBall->x = FIX(x), tmpBall->y = FIX(y);
         tmpBall->SetManager(this);
         tmpBall->Load();
         eList.push_back(tmpBall);
      break;
   }   
}
   
void CWorldManager::AddEntBoss(int x, int y, int genre, int p1, int p2, char* raw)
{
   //Création de tout les types d'entités possibles
   eBoss1 * tmpBoss1;
   eBoss2 * tmpBoss2;
   eBoss3 * tmpBoss3;
   //Sélecteur d'entités Boss
   switch(genre)
   {
      case ENT_BOSS_ONE:
         //Création de l'ennemi
         tmpBoss1 = NULL;
         tmpBoss1 = new eBoss1();
         tmpBoss1->x = x, tmpBoss1->y = y;
         tmpBoss1->SetManager(this);
         tmpBoss1->Load();
         eList.push_back(tmpBoss1);
      break;
      
      case ENT_BOSS_TWO:
         //Création de l'ennemi
         tmpBoss2 = NULL;
         tmpBoss2 = new eBoss2();
         tmpBoss2->x = x, tmpBoss2->y = y;
         tmpBoss2->SetManager(this);
         tmpBoss2->Load();
         eList.push_back(tmpBoss2);
      break;
      
      case ENT_BOSS_THREE:
         //Création de l'ennemi
         tmpBoss3 = NULL;
         tmpBoss3 = new eBoss3();
         tmpBoss3->x = x, tmpBoss3->y = y;
         tmpBoss3->SetManager(this);
         tmpBoss3->Load();
         eList.push_back(tmpBoss3);
      break;
   }  
}
   
void CWorldManager::AddEntEvent(int x, int y, int genre, int p1, int p2, char* raw)
{
   
}
   
void CWorldManager::AddEntLogic(int x, int y, int genre, int p1, int p2, char* raw)
{
   //Création des pointeurs d'entités
	eCamScroller * tmpCamScroll;
	eJumper * tmpJumper;
	eLife * tmpLife;
	eBlocker * tmpBlocker;
	eWaypoint * tmpWay;
	eEnd * tmpEnd;
	
	//Sélécteur d'entités logiques
	switch(genre)
	{
	   case ENT_LOGIC_STARTPOS:  //Position de départ
	      startPosx = x;
			startPosy = y;
			//Si il y a position de départ alors il y a un héros a ajouter a la liste
			AddEntHero(startPosx, startPosy, 0, 0, 0,  NULL);
	   break;
	   
	   case ENT_LOGIC_ENDPOS:  //Crée une zone de collisions
	   	tmpEnd = new eEnd;
	   	tmpEnd->SetManager(this);
	   	tmpEnd->x = x, tmpEnd->y = y;
	   	tmpEnd->Load();
	   	eList.push_back(tmpEnd);
	   	endPosx = x;
	      endPosy = y;
		break;	   
	   
	   case ENT_LOGIC_CAMERA:  //Fixeur de camera
	   	fixPosx = x;
		break;
		
		case ENT_LOGIC_CAMSCROLLER:  //Déplaceur de camera de camera
	   	tmpCamScroll = new eCamScroller;
	   	tmpCamScroll->SetManager(this);
	   	tmpCamScroll->x = x, tmpCamScroll->y = y;
	   	tmpCamScroll->camxDest = p1, tmpCamScroll->camyDest = p2;
	   	eList.push_back(tmpCamScroll);
		break;
		
		case ENT_LOGIC_JUMPER:  //Augmente la pussance de saut
	   	tmpJumper = new eJumper;
	   	tmpJumper->SetManager(this);
	   	tmpJumper->x = x, tmpJumper->y = y;
	   	tmpJumper->w = p1, tmpJumper->h = p2;
	   	tmpJumper->Load();
	   	eList.push_back(tmpJumper);
		break;
		
		case ENT_LOGIC_LIFE:  //Augmente la vie
	   	tmpLife = new eLife;
	   	tmpLife->SetManager(this);
	   	tmpLife->x = x, tmpLife->y = y;
	   	tmpLife->Load();
	   	eList.push_back(tmpLife);
		break;
		
		case ENT_LOGIC_BLOCKER:  //Crée une zone de collisions
	   	tmpBlocker = new eBlocker;
	   	tmpBlocker->SetManager(this);
	   	tmpBlocker->x = x, tmpBlocker->y = y;
	   	tmpBlocker->w = p1, tmpBlocker->h = p2;
	   	sscanf(raw, "%d", &tmpBlocker->event);
	   	tmpBlocker->Load();
	   	eList.push_back(tmpBlocker);
		break;
		
		case ENT_LOGIC_WAYPOINT:  //Crée un waypoint
	   	tmpWay = new eWaypoint;
	   	tmpWay->SetManager(this);
	   	tmpWay->x = x, tmpWay->y = y;
	   	tmpWay->Load();
	   	eList.push_back(tmpWay);
		break;
	}; 
}
   
void CWorldManager::AddEntStatic(int x, int y, int genre, int p1, int p2, char* raw)
{
   //Création de tout les types possibls d'entités
   eWater * tmpWat;
   eGenerator * tmpGen;
   eJaunty * tmpJaunty;
   //Sélécteur d'entités statiques
	switch(genre)
	{
	   case ENT_STATIC_WATER: //Zone de fluide
	   	//Création de l'entité
	   	tmpWat = new eWater();
	   	tmpWat->SetManager(this);
	   	//Assignation des paramètres
	   	tmpWat->x = x, tmpWat->y = y;
	   	tmpWat->w = p1, tmpWat->h = p2;
	   	sscanf(raw, "%d%d%d%d%d%d", &tmpWat->def, &tmpWat->tint, &tmpWat->tint2, &tmpWat->movh, &tmpWat->speed, &tmpWat->dangerous);
	   	//Loading
	   	tmpWat->Load();
	   	eList.push_back(tmpWat);
	   	//ulDebug("Water Area = w:%d h:%d def:%d tint:%d mov:%d speed:%d danger:%d\n",tmpWat->w, tmpWat->h, tmpWat->def, tmpWat->tint, tmpWat->movh, tmpWat->speed, tmpWat->dangerous);
	   break;
	   
	   case ENT_STATIC_GENERATOR:  //Générateur de particules
	   	//Création de l'entité
	   	tmpGen = new eGenerator();
	      tmpGen->SetManager(this);
	      //Assignation des apramètres
	      tmpGen->x = x, tmpGen->y = y;
	      tmpGen->vx = p1, tmpGen->vy = p2;
	      sscanf(raw, "%d%d%d%d%d%d%d%d%d%d%d%d", &tmpGen->texture, &tmpGen->number, &tmpGen->color, &tmpGen->color2, &tmpGen->taille, &tmpGen->fade, &tmpGen->rangex, &tmpGen->rangey, &tmpGen->bootFreq, &tmpGen->impFreq, &tmpGen->endMethod, &tmpGen->g);
			//Loading
			tmpGen->Load();
			eList.push_back(tmpGen);
	   	//ulDebug("PGen = vx:%d vy:%d tex:%d num:%d c1:%d c2:%d t:%d fade:%d rx:%d ry:%d bf:%d if:%d end:%d g:%d\n", tmpGen->vx, tmpGen->vy, tmpGen->texture, tmpGen->number, tmpGen->color, tmpGen->color2, tmpGen->taille, tmpGen->fade, tmpGen->rangex, tmpGen->rangey, tmpGen->bootFreq, tmpGen->impFreq, tmpGen->endMethod, tmpGen->g);
		break;
		
		case ENT_STATIC_JAUNTY: //Informateur
			//Création de l'entité
			tmpJaunty = new eJaunty();
			tmpJaunty->SetManager(this);
			//Params
			tmpJaunty->Load();
			tmpJaunty->x = x, tmpJaunty->y = y;
			strcpy(tmpJaunty->text, raw);
			eList.push_back(tmpJaunty);
		break;
	}; 
}

void CWorldManager::DeleteMe(CEntity* ent)
{
   eList.remove(ent);
   /*delete ent;
   ent = NULL;*/
}
