//Header du moteur de depl

//Les defines
#define	TailleH	64
#define	TailleV	64

//Horizontalement (axe des X):
#define	DebutColH	6
#define	FinColH		57
//Verticalement (axe des Y):
#define	DebutColV	4
#define	FinColV		61

//Les vitesses :
#define	ACC_MARCHE_X	1.0
#define	ACC_MARCHE_Y	1.1

#define	FROX	0.9	//Coefficient des frottements horizontaux
#define	FROYM	0.0001	//Coefficient des frottements verticaux en montée
#define	FROYD	0.3	//Coefficient des frottements verticaux en descente

#define	CHAMP_PESANTEURD	1.0	//Coeff du champ de pesanteur (accélération du bonhomme vers le bas, quand c'est posible) 
#define	CHAMP_PESANTEURM	0.1	//Coeff du champ de pesanteur (accélération du bonhomme vers le bas, quand c'est posible) 
#define	MINI_VITESSE	0.1	//Vitesses minimum pour etre prise en compte
#define	ACC_SAUT	7.0	//Accélération au début du saut
#define	MINI_FROTTEMENT	1.0	//Minimum de vitesse pour la détection des frottements
#define	MINI_VIT_ETAT	1.0	//Minimum pour afficher l'�tat de depl a lieu de l'�tat immobile

//Defines pour l'accrochage :
#define	DIST_ACCROCH	30	//Distance entre le perso et la plaque sur laquelle on va s'accroch�e (horizontalement)
#define	HAUT_ACCROCH	60	//Distance entre le perso et le haut de la plaque libre

#define	PERTE_VIE_CARREAU	20 // Perte par carreau en chute libre au dessus d'un certain seuil


/* Valeurs initiales :
//Les defines
#define	TailleH	64
#define	TailleV	64

//Horizontalement (axe des X):
#define	DebutColH	6
#define	FinColH		57
//Verticalement (axe des Y):
#define	DebutColV	4
#define	FinColV		61

//Les vitesses :
#define	ACC_MARCHE_X	1.0
#define	ACC_MARCHE_Y	1.1

#define	FROX	0.9	//0	//0.9	//Coefficient des frottements horizontaux
#define	FROYM	0.01	//0.008	//0.01	//Coefficient des frottements verticaux en montée
#define	FROYD	0.25	//0.2	//0.025	//Coefficient des frottements verticaux en descente

#define	CHAMP_PESANTEURD	1.25	//0.9	//1.25	//Coeff du champ de pesanteur (accélération du bonhomme vers le bas, quand c'est posible) 
#define	CHAMP_PESANTEURM	0.1	//Coeff du champ de pesanteur (accélération du bonhomme vers le bas, quand c'est posible) 
#define	MINI_VITESSE	0.1	//Vitesses minimum pour etre prise en compte
#define	ACC_SAUT	7.5	//10.0	//7.5	//Accélération au début du saut
#define	MINI_FROTTEMENT	1.0	//Minimum de vitesse pour la détection des frottements
#define	MINI_VIT_ETAT	1.0	//Minimum pour afficher l'�tat de depl a lieu de l'�tat immobile

//Defines pour l'accrochage :
#define	DIST_ACCROCH	30	//Distance entre le perso et la plaque sur laquelle on va s'accroch�e (horizontalement)
#define	HAUT_ACCROCH	60	//Distance entre le perso et le haut de la plaque libre

#define	PERTE_VIE_CARREAU	20 // Perte par carreau en chute libre au dessus d'un certain seuil
*/

//Les fonctions inline
inline bool CPerso::DroitAcces(int px, int py) //La zone est-elle libre ? Peut-on accéder a cet endroit
{
	//Mise en place du procces de détection avec les quatres coins du carré
	return (Map.AutAcces(px + DebutColH, py + DebutColV) && Map.AutAcces(px + FinColH, py + DebutColV) && Map.AutAcces(px + DebutColH, py + FinColV) && Map.AutAcces(px + FinColH, py + FinColV));
}

inline bool CPerso::MortSiAcces(int px, int py) //La zone est-elle mortelle ? Peut-on mourrir a cet endroit
{
	//Mise en place du procces de détection avec les quatres coins du carré
	return (Map.DiedAcces(px + DebutColH, py + DebutColV) && Map.DiedAcces(px + FinColH, py + DebutColV) && Map.DiedAcces(px + DebutColH, py + FinColV) && Map.DiedAcces(px + FinColH, py + FinColV));
}


void CPerso::CalcDepl()
{
	//Calcul du Depl
	double AccX = 0.0, AccY = 0.0;
	int NewEtat = Etat;

	if(Etat == ACCROCHER && DebutAnim + 200 < SDL_GetTicks()) // traitement si accrocher
	{
		if(TouchesAppuyee[TOUCHE_BAS]) //si la touche du bas est activée, on le décroche
		{
			Etat = INDEFINI; //on ne sait pas dans quel état il est
		}
		if(TouchesAppuyee[TOUCHE_HAUT]) //si la touche du haut est activée, on saute
		{
			Etat = SAUT;
			AccY -= ACC_SAUT;
			VitY = 0.0;
			LastSaut = SDL_GetTicks();
			LastSaut += 1000;
		}
	}
	
	if(Etat == ATTAQUE)
	{
		if(DebutAnim + 500 < SDL_GetTicks())
		{
			Etat = INDEFINI;
		}
		else
		{
			CPerso* perso;
			for(int i = 0; i <= Personnages.size(); ++i)
			{
				perso = (i == Personnages.size()) ? PersoPrincipal : Personnages[i];
				
				int px = PosX;
				if(VersLaDroite)	px += 32;
				else	px -= 32;
				
				if(sqrt((((px-perso->ReturnPosX())*(px-perso->ReturnPosX())) + ((PosY-perso->ReturnPosY())*(PosY-perso->ReturnPosY())))) < 32)
				{
					if(perso->CampAllie() != CampAllie())
					{
						perso->AnimDegat();
						perso->PerteVie(1);
					}
				}
			}
		}
	}
	
	if(Etat == SORT_BOULE_FEU)
	{
		if(DebutAnim + 1000 < SDL_GetTicks())
		{
			Etat = INDEFINI;
			//CSortBouleFeu* sort = new CSortBouleFeu(VersLaDroite, PosX, PosY + 7, this);
			CSortSoin1* sort = new CSortSoin1(Personnages[0]);
			Sorts.push_back(sort);
		}
	}
	else if(Etat == TELEPORT)
	{
		
		if(SDL_GetTicks() - DebutAnim > 450 && SDL_GetTicks() - DebutAnim < 550)
		{
			PosX = PersoPrincipal->ReturnPosX();
			PosY = PersoPrincipal->ReturnPosY();
		}
		else if(DebutAnim + 1000 < SDL_GetTicks())
		{
			Etat = INDEFINI;
		}
	}
	
	if(Etat != ACCROCHER && Etat != ATTAQUE && Etat != SORT_BOULE_FEU) //traitement plus général si pas accroché
	{
		if(Etat != MORT && Etat != TELEPORT) // Bien entendu, il n'est pas mort!!!
		{
			if(TouchesAppuyee[TOUCHE_DROITE]) //A t-on appuyé sur la touche droite ?
			{
				//Gestion de l'accrochage ici!
				if(!DroitAcces(PosX + DIST_ACCROCH, PosY) && DroitAcces(PosX + DIST_ACCROCH, PosY - HAUT_ACCROCH) && !DroitAcces(PosX + DIST_ACCROCH, PosY - HAUT_ACCROCH + 3))
				{
					VitX = VitY = 0.0;
					div_t t = div(PosX + 32, 64);
					PosX = t.quot * 64;
					t = div(PosY, 64);
					PosY = t.quot * 64 + 64;
					Etat = ACCROCHER;
					DebutAnim = SDL_GetTicks();
					VersLaDroite = true;
					return;
				}
				
				if(DroitAcces(PosX + (int)(VitX + ACC_MARCHE_X), PosY + (int)(VitY + ACC_MARCHE_Y)) && (!DroitAcces(PosX, PosY + 3))) //Déplacement en bas à droite ?
				{
					AccX = ACC_MARCHE_X;
					AccY = ACC_MARCHE_Y;
				}
				else if(DroitAcces(PosX + (int)(VitX + ACC_MARCHE_X), PosY + (int)VitY)) //Déplacement à droite ?
				{
					AccX = ACC_MARCHE_X;
				}
				else if(DroitAcces(PosX + (int)(VitX + ACC_MARCHE_X), PosY - 2 + (int)(VitY - ACC_MARCHE_Y))) //Déplacement en haut à droite ?
				{
					AccX = ACC_MARCHE_X;
					AccY = -ACC_MARCHE_Y;// - .1;
				}
			}
			
			if(TouchesAppuyee[TOUCHE_GAUCHE]) //A t-on appuyé sur la touche gauche ?
			{
				//Gestion de l'accrochage ici!
				if(!DroitAcces(PosX - DIST_ACCROCH, PosY) && DroitAcces(PosX - DIST_ACCROCH, PosY - HAUT_ACCROCH) && !DroitAcces(PosX - DIST_ACCROCH, PosY - HAUT_ACCROCH + 3))
				{
					VitX = VitY = 0.0;
					div_t t = div(PosX + 32, 64);
					PosX = t.quot * 64;
					t = div(PosY, 64);
					PosY = t.quot * 64 + 64;
					Etat = ACCROCHER;
					DebutAnim = SDL_GetTicks();
					VersLaDroite = false;
					return;
				}
				
				if(DroitAcces(PosX + (int)(VitX - ACC_MARCHE_X), PosY + (int)(VitY + ACC_MARCHE_Y)) && (!DroitAcces(PosX, PosY + 3))) //Déplacement en bas à gauche ?
				{
					AccX = -ACC_MARCHE_X;
					AccY = ACC_MARCHE_Y;
				}
				else if(DroitAcces(PosX + (int)(VitX - ACC_MARCHE_X), PosY + (int)VitY)) //Déplacement à gauche ?
				{
					AccX = -ACC_MARCHE_X;
				}
				else if(DroitAcces(PosX + (int)(VitX - ACC_MARCHE_X), PosY - 2 + (int)(VitY - ACC_MARCHE_Y))) //Déplacement en haut à gauche ?
				{
					AccX = -ACC_MARCHE_X;
					AccY = -ACC_MARCHE_Y;
				}
			}
			
			//Le saut ...
			if(TouchesAppuyee[TOUCHE_HAUT])
			{
				if((!DroitAcces(PosX, PosY + 5) && Etat != SAUT)/* || (LastSaut < SDL_GetTicks())*/)
				{
					AccY -= ACC_SAUT;
					VitY = 0.0;
					LastSaut = SDL_GetTicks();
					LastSaut += 1000;
				}
			}
		}
		
		//Le poids (si pas de réaction du sol)...
		if(DroitAcces(PosX, PosY + 3 + (int)(VitY + AccY + CHAMP_PESANTEURD)))
		{
			if(VitY > 0.0)
			{			
				AccY += CHAMP_PESANTEURD;
			}
			else
			{
				AccY += CHAMP_PESANTEURM;
			}
		}
		
		//Traitements des frottements
		if(!((VitX < MINI_FROTTEMENT) && (VitX > -MINI_FROTTEMENT)))
		{		
			AccX -= (VitX * FROX);
		}		
	
		if(!((VitY < MINI_FROTTEMENT) && (VitY > -MINI_FROTTEMENT)))
		{
			if(VitY > 0.0)
			{
				AccY -= (VitY * FROYD);
			}
			else
			{
				AccY -= (VitY * FROYM);
			}
		}


		//Traitement des obstacle		
		if(!DroitAcces(PosX + (int)(VitX + AccX), PosY + (int)(VitY + AccY)))
		{	
			//Depl horizontaux
			if(!DroitAcces(PosX + (int)(VitX + AccX), PosY))
			{			
				VitX = AccX = 0.0;
			}

			//Depl verticaux
			if(!DroitAcces(PosX, PosY /*- 1*/ + (int)(VitY + AccY)))
			{
				VitY = AccY = 0.0;
			}
		} 
	}

	VitX += AccX;
	VitY += AccY;

	if((VitX < MINI_VITESSE) && (VitX > -MINI_VITESSE))
	{
		VitX = 0.0;
	}

	if((VitY < MINI_VITESSE) && (VitY > -MINI_VITESSE))
	{
		VitY = 0.0;
	}
	
	//Ne pas sortir de la map
	if(VitX + PosX < 0)
	{
		VitX = 0.0;
	}

	if(VitY + PosY < 0)
	{
		VitY = 0.0;
	}

	PosX += (int)VitX;
	PosY += (int)VitY;
	
	if(VitY <= 1.0)
	{
		if(PosY - HauteurMax > 384)
		{
			HauteurMax = PosY - HauteurMax - 384;
			if(HauteurMax > 0) Vie -= (HauteurMax/64 * PERTE_VIE_CARREAU);
			if(Vie <= 0)
			{
				Vie = 0;
		 		DebutAnim = SDL_GetTicks();
				DebutAnim += 2000;
			}
		}
		HauteurMax = PosY;
	}
	
	if(PosY < HauteurMax) HauteurMax = PosY;
	
	//Calcul de l'état actuel
	if((Etat != ACCROCHER) && (Etat != MORT) && (Etat != TELEPORT))
	{
		if((VitY*VitY) < 1.0 && Etat != ATTAQUE && Etat != SORT_BOULE_FEU && TouchesAppuyee[TOUCHE_ATTAQUE] && !DroitAcces(PosX, PosY + 20))
		{
			NewEtat = ATTAQUE;
			VitX = 0.0;
		}
		else if(Etat == ATTAQUE)
		{
			
		}
		else if((VitY*VitY) < 1.0 && Etat != SORT_BOULE_FEU && TouchesAppuyee[TOUCHE_SORT_BOULE_FEU] && !DroitAcces(PosX, PosY + 20) && Mana >= COUT_BOULE_FEU)
		{
			NewEtat = SORT_BOULE_FEU;
			VitX = 0.0;
			Mana -= COUT_BOULE_FEU;
		}
		else if(Etat == SORT_BOULE_FEU)
		{
			
		}
		else if(DroitAcces(PosX, PosY + 7))
		{
			NewEtat = SAUT;
			VersLaDroite = (VitX > 0.0);
		}
		else if(!((VitX < MINI_VIT_ETAT) && (VitX > -MINI_VIT_ETAT)))
		{
			NewEtat = MARCHE;
			VersLaDroite = (VitX > 0.0);
		}
		else if(MortSiAcces(PosX, PosY))
		{
			NewEtat = MORT;
			VersLaDroite = (VitX > 0.0);
		}
		else if(Etat != DEEQUILIBRE && Map.AutAcces(PosX + 31, PosY + 32) && Map.AutAcces(PosX + 50, PosY + 32) && !Map.AutAcces(PosX + DebutColH, PosY + 120)  && Map.AutAcces(PosX + 50, PosY + 120))
		{
			if(DroitAcces(PosX + 32 - PosX%64, PosY))PosX += 32 - PosX%64;
			VersLaDroite = true;
			
			NewEtat = DEEQUILIBRE;
		}
		else if(Etat != DEEQUILIBRE && Map.AutAcces(PosX - DebutColH, PosY + 32) && Map.AutAcces(PosX + FinColH, PosY + 32) && !(!Map.AutAcces(PosX - DebutColH, PosY + 120) || !Map.AutAcces(PosX - DebutColH, PosY + 130)) && (!Map.AutAcces(PosX + FinColH, PosY + 120) || !Map.AutAcces(PosX + FinColH, PosY + 130)))
		{
			div_t px = div(PosX, 64);
			if(px.rem < 15 && DroitAcces(PosX - 15, PosY)) PosX -= 15;
			if(DroitAcces(PosX + 32 - PosX%64, PosY)) PosX += 32 - PosX%64;
			VersLaDroite = false;
			
			NewEtat = DEEQUILIBRE;
		}
		else if(Etat != DEEQUILIBRE)
		{
			NewEtat = IMMOBILE;
		}
		
		if(Etat != NewEtat)
		{
			Etat = NewEtat;
			DebutAnim = SDL_GetTicks();
		}
	}
}

void CPerso::CalcIA()
{
	if(PersoPrincipal->ReturnEtat() == MORT) return;
	
	switch(TypeIA)
	{
		case IA_SOIGNEUR:
			break;
		
		case IA_POLYVALENT:
			
			if(Etat != TELEPORT && (abs(PersoPrincipal->ReturnPosY() - PosY) > 400 || abs(PersoPrincipal->ReturnPosX() - PosX) > 400))
			{
				Etat = TELEPORT;
				DebutAnim = SDL_GetTicks();
			}
			else if(!IASuivrePerso())
			{
				if((Vie <= 0.1 * VieMax) && ((rand()/(double)RAND_MAX) < 0.75) && Mana >= COUT_SOIN3)
				{
					CSortSoin3* sort = new CSortSoin3(this);
					Sorts.push_back(sort);
				}
				else if((Vie <= 0.1 * VieMax) && ((rand()/(double)RAND_MAX) < 0.75) && Mana >= COUT_SOIN2)
				{
					CSortSoin2* sort = new CSortSoin2(this);
					Sorts.push_back(sort);
				}
				else if((Vie <= 0.2 * VieMax) && ((rand()/(double)RAND_MAX) < 0.75) && Mana >= COUT_SOIN2)
				{
					CSortSoin1* sort = new CSortSoin1(this);
					Sorts.push_back(sort);
				}
			}
			
			break;
	}
}


bool CPerso::IASuivrePerso()
{
	//GEstion du déplacement du l'IA
	
	//On met les touches a zéro
	TouchesAppuyee[0] = false;
	TouchesAppuyee[1] = false;
	TouchesAppuyee[2] = false;
	TouchesAppuyee[3] = false;
	
	//On récupère la direction actuelle
	bool Gauche = !VersLaDroite;
	bool Droite = VersLaDroite;
	
	//Si le perso est en dééquilibre, le perso principal dot être plus loin pour faire bouger le perso (l'etat dééquilibre fais bouger le perso tt seul)
	if(Etat == DEEQUILIBRE)
	{
		Gauche = (PosX > PersoPrincipal->ReturnPosX() + 150);
		Droite = (PosX + 150 < PersoPrincipal->ReturnPosX());		
	}
	else if(abs(PersoPrincipal->ReturnPosY() - PosY) > 75)
	{
		Gauche = (PosX > PersoPrincipal->ReturnPosX());
		Droite = (PosX < PersoPrincipal->ReturnPosX());
	}
	else if(Etat != SAUT) //Sinon si le perso saute pas on le déplace vers le erso principal avec une distance de sécu ... ( si il saute on ne l'arrête pas en plein saut ...)
	{
		Gauche = (PosX > PersoPrincipal->ReturnPosX() + 100);
		Droite = (PosX + 100 < PersoPrincipal->ReturnPosX());
	}	
	else // SI on saute on se dirige vers la position horizontale exacte du perso principal
	{
		Gauche = (!VersLaDroite && (PosX + 5 > PersoPrincipal->ReturnPosX()));
		Droite = (VersLaDroite && (PosX < PersoPrincipal->ReturnPosX() + 5));
	}
	
	if(!Gauche && !Droite) return false; // Si on se déplace pas on le dis et on s'en va ...
	
	TouchesAppuyee[TOUCHE_DROITE] = Droite;
	TouchesAppuyee[TOUCHE_GAUCHE] = Gauche;
	
	//on donne les ordes aux tuches ...
	
	//On trouve le carreau sur lequel est le perso
	div_t ty = div(PosY, 64);
	div_t tx = div(PosX, 64);
	
	unsigned int CX = tx.quot;
	unsigned int CY = ty.quot;
	
	//Détermination du coefficient directeur entre le perso et le perso principal
	float CoefDir = 0;
	if(PersoPrincipal->ReturnPosX() != PosX)
	{
		CoefDir = (PersoPrincipal->ReturnPosY() > PosY) ? -fabs((float)(PersoPrincipal->ReturnPosY() - PosY)/(float)(PersoPrincipal->ReturnPosX() - PosX)) : fabs((float)(PersoPrincipal->ReturnPosY() - PosY)/(float)(PersoPrincipal->ReturnPosX() - PosX));
	}
	
	//Si on va a droite
	if(Droite)
	{
		//Si on est au brod d'un précipice
		if(Map.AutAcces(PosX + 20, PosY + 60) && Map.AutAcces(PosX + 28, PosY + 60) && !Map.AutAcces(PosX + 20, PosY + 68) && Map.AutAcces(PosX + 28, PosY + 68))
		{
			//Si on est pas ds la pente alors on saute
			if(PersoPrincipal->ReturnPosY() <= PosY + 10 && Map.ReturnTypeCarreau(CX + 1, CY + 1) != PENTE_DROITE && Map.ReturnTypeCarreau(CX + 1, CY + 1) != SOMMET_COTE_DROITE) TouchesAppuyee[TOUCHE_HAUT] = true;
		}
	}
	
	//idem au gauche
	if(Gauche)
	{
		if(Map.AutAcces(PosX + 50, PosY + 60) && Map.AutAcces(PosX + 42, PosY + 60) && !Map.AutAcces(PosX + 50, PosY + 68) && Map.AutAcces(PosX + 42, PosY + 68))
		{
			if(PersoPrincipal->ReturnPosY() <= PosY + 10 && Map.ReturnTypeCarreau(CX, CY + 1) != PENTE_GAUCHE && Map.ReturnTypeCarreau(CX, CY + 1) != SOMMET_COTE_GAUCHE) TouchesAppuyee[TOUCHE_HAUT] = true;
		}
	}
	
	//Si on est accrocher et que le perso principal n'est pas à la meme hauteur, on se décroche en conséquence ...
	if(Etat == ACCROCHER)
	{
		TouchesAppuyee[TOUCHE_HAUT] = (PosY > PersoPrincipal->ReturnPosY() + 10);
		TouchesAppuyee[TOUCHE_BAS] = (PosY + 10 < PersoPrincipal->ReturnPosY());
	}
	//Si il y a un mur a droite, on saute ...
	else if(Droite)
	{
		if(!Map.AutAcces(CX * 64 + 70, CY * 64 + 10))
		{
			TouchesAppuyee[TOUCHE_HAUT] = true;
		}
	}
	//Idem a gauche ...
	else
	{
		if(!Map.AutAcces(CX * 64 + 60, CY * 64 + 10))
		{
			TouchesAppuyee[TOUCHE_HAUT] = true;
		}
	}
	
	if(PersoPrincipal->ReturnEtat() != SAUT && CoefDir >= 1.8f)
	{
		TouchesAppuyee[TOUCHE_HAUT] = true;
	}
	
	//On return la valeur pour savoir si on se déplace ou pas ...
	return (!TouchesAppuyee[0] && !TouchesAppuyee[1] && !TouchesAppuyee[2] && !TouchesAppuyee[3]);
}



