#include "commun.h"

/*
	Le tableau des sprites est divisé en deux sections. L'une d'entre-elle (la première)
	contient les sprites les plus importants, qui doivent obligatoirement être gérés avant
	les autres. On notera par exemple le contrôleur du balancier, qui doit bien entendu
	placer ses maillons avant que ceux-ci ne commencent à être affichés.
	La première section est composée de
*/
int num_sprite_actif = 0;
int nbrePersos = 0;
int gblJ, perso_signal = 0;
int super_vitesse;
int gblSonicComplexe = -1;

//DEBOGAGE SEULEMENT
int gblDebug_ID = 0;

//int gblChangeEnboule;
void Sonic_metEnBoule(SONIC *s, u32 etat)
{
	u32 pa;
	pa = calcPA(s);
	if (!etat && s->enboule)
	{
		s->hauteur = 32;
		if (pa != PA_HAUT)
			s->y -= 8;
	}

	if (etat && !s->enboule)
	{
		s->hauteur = 24;
		if (pa != PA_HAUT)
			s->y += 8;
	}

	s->enboule = etat;

	/*    if (etat && !s->enboulesauv)
	gblChangeEnboule=1;
	if (!etat && s->enboulesauv)
	gblChangeEnboule=-1;
	s->enboule=etat;*/
}

void GereSonicEnBoule(SONIC *s)
{

	/*   if (gblChangeEnboule==-1)
	s->hauteur=32, s->y-=8, s->enboule=0;
	if (gblChangeEnboule==1)
	s->hauteur=24, s->y+=8, s->enboule=1;
	gblChangeEnboule=0;
	s->enboulesauv=s->enboule;*/
}

//Crée un personnage (Comment? Vous l'auriez deviné?)
int CreePerso(
			  unsigned short x,
			  unsigned short y,
			  short direction,
			  unsigned short largeur,
			  unsigned short hauteur,
			  void (*fonction) (),
			  unsigned int instructions)
{
	int dejafait = 0;
	u16 zero = 0;
	PERSO *p;

pasbon:
	while (persos[num_sprite_actif].type && num_sprite_actif < LIMITE_PERSOS)
		num_sprite_actif++;
	if (num_sprite_actif >= LIMITE_PERSOS)
	{
		if (dejafait)
			return LIMITE_PERSOS - 1;
		num_sprite_actif = 0;
		dejafait = 1;
		goto pasbon;
	}

	p = &persos[num_sprite_actif];
	p->type = 1;
	p->x = x, p->y = y;
	p->cpt = 0;
	p->etat = 0;
	p->depX = x;
	p->depY = y;
	p->vx = direction;
	p->vy = 0;
	p->largeur = largeur;
	p->hauteur = hauteur;
	p->fHandler = (unsigned short (*) ()) fonction;
	p->instructions = instructions;
	_memset(p->donnees, &zero, sizeof(p->donnees));

	//    p->param1=p->param2=p->param3=p->param4=p->param5=p->param6=0;
	p->savX = x, p->savY = y;
	p->angle = 0;
	p->noObjet = gblNoObjet;
	p->dir = direction;
	p->mort = 0;

	gblNoObjet = 0x7fff;

	id_perso[nbrePersos++] = num_sprite_actif;
	return num_sprite_actif;
}

int CreePersoID(
				unsigned int id,
				unsigned short x,
				unsigned short y,
				short direction,
				unsigned short largeur,
				unsigned short hauteur,
				void (*fonction) (),
				unsigned int instructions)
{
	int dejafait = 0;
	u16 zero = 0;
	PERSO *p;

pasbon:
	while (persos[num_sprite_actif].type && num_sprite_actif < LIMITE_PERSOS)
		num_sprite_actif++;
	if (num_sprite_actif >= LIMITE_PERSOS)
	{
		if (dejafait)
			return LIMITE_PERSOS - 1;
		num_sprite_actif = 0;
		dejafait = 1;
		goto pasbon;
	}

	p = &persos[num_sprite_actif];
	p->type = 1;
	p->x = x, p->y = y;
	p->cpt = 0;
	p->etat = 0;
	p->depX = x;
	p->depY = y;
	p->vx = direction;
	p->vy = 0;
	p->largeur = largeur;
	p->hauteur = hauteur;
	p->fHandler = (unsigned short (*) ()) fonction;
	p->instructions = instructions;
	_memset(p->donnees, &zero, sizeof(p->donnees));

	//    p->param1=p->param2=p->param3=p->param4=0;
	p->savX = x, p->savY = y;
	p->angle = 0;
	if (gblNoObjet == 0x7fff && !(instructions & INSTR_HORS_MAP))
		Debug("Probleme #3 detecte!");

	p->dir = direction;
	p->mort = 0;

	p->noObjet = gblNoObjet;

	//    gblNoObjet=0x7fff;
	id_perso[id] = num_sprite_actif;
	return num_sprite_actif;
}

void CreeObjetStandardNormal(unsigned short tiles, unsigned short palette, unsigned short forme, unsigned short taille)
{
	if (objetsUtilises >= 127)
		return;
	objetsUtilises++;

	// Création de l'objet
	CreeObjet(objetsUtilises,        //Numéro d'objet
		tiles,                        //Numéro de mosaïque (3), <<2 car 16x16 (*4) et <<1 car mode 8 bits (*2)
		240,                        //Position X initiale
		160,                        //Position Y initiale
		0,                        //Mode (alpha-blend)
		forme,                //Forme (0=carrée)
		taille,                //Taille
		0,                        //Mode palette (1=256 couleurs, 0=16 couleurs)
		palette,                //Numéro de palette si 16 couleurs
		prioDefaut,        //Priorité
		0,                        //Retournement vertical
		0,                        //Retournement horizontal
		0,                        //Mode mosaïque (?)
		0,                        //Rotation
		0,                        //N° de rotation
		0);                        //Double-taille (pour rotation)
}

void CreeObjetStandardHUD(u32 x,
						  u32 y,
						  unsigned short tiles,
						  unsigned short palette,
						  unsigned short forme,
						  unsigned short taille)
{
	if (objetsUtilises >= 127)        //Pas nécessaire
		return;
	objetsUtilises++;

	// Création de l'objet
	CreeObjet(objetsUtilises,        //Numéro d'objet
		tiles,                        //Numéro de mosaïque (3), <<2 car 16x16 (*4) et <<1 car mode 8 bits (*2)
		x,                //Position X initiale
		y,                //Position Y initiale
		0,                //Mode (alpha-blend)
		forme,        //Forme (0=carrée)
		taille,        //Taille
		0,                //Mode palette (1=256 couleurs, 0=16 couleurs)
		palette,        //Numéro de palette si 16 couleurs
		0,                //Priorité
		0,                //Retournement vertical
		0,                //Retournement horizontal
		0,                //Mode mosaïque (?)
		0,                //Rotation
		0,                //N° de rotation
		0);                //Double-taille (pour rotation)
}

void CreeObjetStandardHUDAlphaRot(u32 x,
								  u32 y,
								  unsigned short tiles,
								  unsigned short palette,
								  int no_rotation,
								  unsigned short forme,
								  unsigned short taille)
{
	if (objetsUtilises >= 127)        //Pas nécessaire
		return;
	objetsUtilises++;

	// Création de l'objet
	CreeObjet(objetsUtilises,        //Numéro d'objet
		tiles,                        //Numéro de mosaïque (3), <<2 car 16x16 (*4) et <<1 car mode 8 bits (*2)
		x,                        //Position X initiale
		y,                        //Position Y initiale
		1,                        //Mode (alpha-blend)
		forme,                //Forme (0=carrée)
		taille,                //Taille
		0,                        //Mode palette (1=256 couleurs, 0=16 couleurs)
		palette,                //Numéro de palette si 16 couleurs
		0,                        //Priorité
		0,                        //Retournement vertical
		0,                        //Retournement horizontal
		0,                        //Mode mosaïque (?)
		1,                        //Rotation
		no_rotation,        //N° de rotation
		1);                        //Double-taille (pour rotation)
}

void CreeObjetStandardHUDRotation(u32 x,
								  u32 y,
								  unsigned short tiles,
								  unsigned short palette,
								  unsigned short no_rotation,
								  unsigned short forme,
								  unsigned short taille)
{
	if (objetsUtilises >= 127)        //Pas nécessaire
		return;
	objetsUtilises++;

	// Création de l'objet
	CreeObjet(objetsUtilises,        //Numéro d'objet
		tiles,                        //Numéro de mosaïque (3), <<2 car 16x16 (*4) et <<1 car mode 8 bits (*2)
		x,                        //Position X initiale
		y,                        //Position Y initiale
		0,                        //Mode (alpha-blend)
		forme,                //Forme (0=carrée)
		taille,                //Taille
		0,                        //Mode palette (1=256 couleurs, 0=16 couleurs)
		palette,                //Numéro de palette si 16 couleurs
		0,                        //Priorité
		0,                        //Retournement vertical
		0,                        //Retournement horizontal
		0,                        //Mode mosaïque (?)
		1,                        //Rotation
		no_rotation,        //N° de rotation
		1);                        //Double-taille (pour rotation)
}

void CreeObjetStandardEau(s32 x,
						  s32 y,
						  unsigned short tiles,
						  unsigned short palette,
						  unsigned short forme,
						  unsigned short taille)
{
	if (objetsUtilises >= 127)        //Pas nécessaire
		return;
	if (x >= 240 || y >= 160)
		return;
	objetsUtilises++;
	if (x < 0)
		x += 512;
	if (y < 0)
		y += 256;

	// Création de l'objet
	CreeObjet(objetsUtilises,        //Numéro d'objet
		tiles,                        //Numéro de mosaïque (3), <<2 car 16x16 (*4) et <<1 car mode 8 bits (*2)
		x,                //Position X initiale
		y,                //Position Y initiale
		0,                //Mode (alpha-blend)
		forme,        //Forme (0=carrée)
		taille,        //Taille
		0,                //Mode palette (1=256 couleurs, 0=16 couleurs)
		palette,        //Numéro de palette si 16 couleurs
		1,                //Priorité
		0,                //Retournement vertical
		0,                //Retournement horizontal
		0,                //Mode mosaïque (?)
		0,                //Rotation
		0,                //N° de rotation
		0);                //Double-taille (pour rotation)
}

void CreeObjetStandardHUDPlus(s32 x,
							  s32 y,
							  unsigned short tiles,
							  unsigned short palette,
							  unsigned short forme,
							  unsigned short taille)
{
	if (objetsUtilises >= 127)        //Pas nécessaire
		return;
	objetsUtilises++;
	if (y < 0)
		y += 256;

	// Création de l'objet
	CreeObjet(objetsUtilises,        //Numéro d'objet
		tiles,                        //Numéro de mosaïque (3), <<2 car 16x16 (*4) et <<1 car mode 8 bits (*2)
		x,                //Position X initiale
		y,                //Position Y initiale
		0,                //Mode (alpha-blend)
		forme,        //Forme (0=carrée)
		taille,        //Taille
		0,                //Mode palette (1=256 couleurs, 0=16 couleurs)
		palette,        //Numéro de palette si 16 couleurs
		0,                //Priorité
		0,                //Retournement vertical
		0,                //Retournement horizontal
		0,                //Mode mosaïque (?)
		0,                //Rotation
		0,                //N° de rotation
		0);                //Double-taille (pour rotation)
}

void CreeObjetStandardHUDHorsEcran(s32 x,
								   s32 y,
								   unsigned short tiles,
								   unsigned short palette,
								   unsigned short forme,
								   unsigned short taille)
{
	if (objetsUtilises >= 127)        //Pas nécessaire
		return;
	objetsUtilises++;
	if (x <= -64 || y <= -64 || x >= 240 || y >= 160)
		return;
	if (x < 0)
		x += 512;
	if (y < 0)
		y += 256;

	// Création de l'objet
	CreeObjet(objetsUtilises,        //Numéro d'objet
		tiles,                        //Numéro de mosaïque (3), <<2 car 16x16 (*4) et <<1 car mode 8 bits (*2)
		x,                //Position X initiale
		y,                //Position Y initiale
		0,                //Mode (alpha-blend)
		forme,        //Forme (0=carrée)
		taille,        //Taille
		0,                //Mode palette (1=256 couleurs, 0=16 couleurs)
		palette,        //Numéro de palette si 16 couleurs
		0,                //Priorité
		0,                //Retournement vertical
		0,                //Retournement horizontal
		0,                //Mode mosaïque (?)
		0,                //Rotation
		0,                //N° de rotation
		0);                //Double-taille (pour rotation)
}

void CreeObjetStandardSonicRotation(unsigned short prio,
									unsigned short tiles,
									unsigned short palette,
									unsigned short forme,
									unsigned short taille)
{
	if (objetsUtilises >= 127)
		return;
	objetsUtilises++;

	// Création de l'objet
	CreeObjet(objetsUtilises,        //Numéro d'objet
		tiles,                        //Numéro de mosaïque (3), <<2 car 16x16 (*4) et <<1 car mode 8 bits (*2)
		240,                //Position X initiale
		160,                //Position Y initiale
		0,                //Mode (alpha-blend)
		forme,        //Forme (0=carrée)
		taille,        //Taille
		0,                //Mode palette (1=256 couleurs, 0=16 couleurs)
		palette,        //Numéro de palette si 16 couleurs
		prio,                //Priorité
		0,                //Retournement vertical
		0,                //Retournement horizontal
		0,                //Mode mosaïque (?)
		1,                //Rotation
		10,                //N° de rotation
		0);                //Double-taille (pour rotation)
}

void CreeObjetStandardAlpha(u16 x,
							u16 y,
							unsigned short tiles,
							unsigned short palette,
							unsigned short forme,
							unsigned short taille)
{
	if (objetsUtilises >= 127 || skip)
		return;
	VerifieSIlYABesoinDePlacerUnSprite(x, y, EcrSprites);
	if (posX == 240 || posY == 160)
		return;
	objetsUtilises++;

	// Création de l'objet
	CreeObjet(objetsUtilises,        //Numéro d'objet
		tiles,                        //Numéro de mosaïque (3), <<2 car 16x16 (*4) et <<1 car mode 8 bits (*2)
		posX,                        //Position X initiale
		posY,                        //Position Y initiale
		1,                        //Mode (alpha-blend)
		forme,                //Forme (0=carrée)
		taille,                //Taille
		0,                        //Mode palette (1=256 couleurs, 0=16 couleurs)
		palette,                //Numéro de palette si 16 couleurs
		prioDefaut,        //Priorité
		0,                        //Retournement vertical
		0,                        //Retournement horizontal
		0,                        //Mode mosaïque (?)
		0,                        //Rotation
		0,                        //N° de rotation
		0);                        //Double-taille (pour rotation)
}

void CreeObjetStandardStage(s16 x,
							s16 y,
							unsigned short tiles,
							unsigned short palette,
							unsigned short forme,
							unsigned short taille)
{
	ECRAN ecr;
	if (objetsUtilises >= 127)
		return;
	ecr.scrlX = 0, ecr.scrlY = 0;
	VerifieSIlYABesoinDePlacerUnSprite(x, y, &ecr);
	if (posX == 240 || posY == 160)
		return;
	objetsUtilises++;

	// Création de l'objet
	CreeObjet(objetsUtilises,        //Numéro d'objet
		tiles,                        //Numéro de mosaïque (3), <<2 car 16x16 (*4) et <<1 car mode 8 bits (*2)
		posX,                        //Position X initiale
		posY,                        //Position Y initiale
		1,                        //Mode (alpha-blend)
		forme,                //Forme (0=carrée)
		taille,                //Taille
		0,                        //Mode palette (1=256 couleurs, 0=16 couleurs)
		palette,                //Numéro de palette si 16 couleurs
		prioDefaut,        //Priorité
		0,                        //Retournement vertical
		0,                        //Retournement horizontal
		0,                        //Mode mosaïque (?)
		1,                        //Rotation
		1,                        //N° de rotation
		1);                        //Double-taille (pour rotation)
}

void CreeObjetStandardSansEcran(s16 x,
								s16 y,
								unsigned short tiles,
								unsigned short palette,
								unsigned short forme,
								unsigned short taille)
{
	ECRAN ecr;
	if (objetsUtilises >= 127)
		return;
	ecr.scrlX = 0, ecr.scrlY = 0;
	VerifieSIlYABesoinDePlacerUnSprite(x, y, &ecr);
	if (posX == 240 || posY == 160)
		return;
	objetsUtilises++;

	// Création de l'objet
	CreeObjet(objetsUtilises,        //Numéro d'objet
		tiles,                        //Numéro de mosaïque (3), <<2 car 16x16 (*4) et <<1 car mode 8 bits (*2)
		posX,                        //Position X initiale
		posY,                        //Position Y initiale
		1,                        //Mode (alpha-blend)
		forme,                //Forme (0=carrée)
		taille,                //Taille
		0,                        //Mode palette (1=256 couleurs, 0=16 couleurs)
		palette,                //Numéro de palette si 16 couleurs
		prioDefaut,        //Priorité
		0,                        //Retournement vertical
		0,                        //Retournement horizontal
		0,                        //Mode mosaïque (?)
		0,                        //Rotation
		0,                        //N° de rotation
		0);                        //Double-taille (pour rotation)
}

void CreeObjetStandardEx(u16 x,
						 u16 y,
						 u16 alpha,
						 u16 prio,
						 u16 mh,
						 u16 mv,
						 unsigned short tiles,
						 unsigned short palette,
						 unsigned short forme,
						 unsigned short taille)
{
	CodeBaseCreeObjet;

	// Création de l'objet
	CreeObjet(objetsUtilises,        //Numéro d'objet
		tiles,                        //Numéro de mosaïque (3), <<2 car 16x16 (*4) et <<1 car mode 8 bits (*2)
		posX,                        //Position X initiale
		posY,                        //Position Y initiale
		alpha,                //Mode (alpha-blend)
		forme,                //Forme (0=carrée)
		taille,                //Taille
		0,                        //Mode palette (1=256 couleurs, 0=16 couleurs)
		palette,                //Numéro de palette si 16 couleurs
		prio,                        //Priorité
		mv,                        //Retournement vertical
		mh,                        //Retournement horizontal
		0,                        //Mode mosaïque (?)
		0,                        //Rotation
		0,                        //N° de rotation
		0);                        //Double-taille (pour rotation)
}

//Pour la rotation, on lui réserve 64 tiles
#define SONIC_TILE_RESERVEE 960

void AfficheSonicComplexe()
{
	u32 i, j;
	j = 0;
	for (i = SONIC_TILE_RESERVEE + 24 + 1; i < SONIC_TILE_RESERVEE + 64 + 1; i += 8)
	{
		CopieDMA((void *) Sonic_tiles_tiles + 48 * 20 * gblSonicComplexe + 32 * j,
			OBJ_BASE_ADR + i * 32,
			16 * 6,
			DMA_16im);
		j += 6;
	}
}

void AfficheSonic(SONIC *perso, ECRAN *ecr)
{
	int posX, posY, i;
	static int workaround = 0;
	int curAngle, vx, curPrio;

	//Change la priorité par défaut des objets
	curPrio = prioDefaut;
	prioDefaut = perso->prio;

	gblSonicComplexe = -1;
	if (perso->clignote && nFrame & 1)
		return;

	if (perso->fctEtat)
		goto etat;
	if (perso->enboule)
	{

		/*        perso->cpt+=16+(ABS(perso->vx)>>8);
		if (aboule==0)      {
		perso->largeur=23;
		perso->hauteur=23;
		perso->y+=9;
		}
		CreeObjetStandard(0,0,AjSprite(Pal_0_32x32_tiles,32*32),0,TAILLE_32x32);
		if (perso->dir==1)
		perso->vangle=359-((perso->cpt)%360);
		else
		perso->vangle=(perso->cpt)%360;

		//        CreeObjetStandard(pAjSprite(Sonic_tiles+(32*32/2)*((perso->cpt>>4)&3),32*32),0,0,2);
		posX=perso->x-ecr->scrlX;
		posY=perso->y-ecr->scrlY;

		if (perso->enboule)     {
		posY-=4;
		posX-=4;
		}
		perso->vangle=perso->angle;

		if (perso->vangle<180)
		posY+=(4*sinus[(perso->vangle*2)%360])/256;
		else
		posY-=(4*sinus[(perso->vangle*2)%360])/256;
		//        Exec(ClipSpriteXY,objetsUtilises,posX,posY);*/

		/*        if (aboule==0)      {
		//            perso->largeur=26;
		perso->hauteur=24;
		//            perso->x-=perso->dir*2;
		perso->y+=8;
		if (perso->saut)
		perso->vangle=0;
		}*/
		i = ABS(perso->vx) >> 8;
		if (perso->sous_leau)
			i /= 2;
		if (i <= 2)
			perso->cpt += 1;
		else if (i <= 4)
			perso->cpt += 2;
		else
			perso->cpt += 3;

		/*         if (i<1)
		i=1;
		perso->cpt+=1;*/
		i = ((perso->cpt / 3) % 8);

		posX = perso->x - ecr->scrlX;
		posY = perso->y - ecr->scrlY;

		if (perso->angle < 180)
			posY += (4 * sinus[(perso->angle * 2) % 360]) / 256;
		else
			posY -= (4 * sinus[(perso->angle * 2) % 360]) / 256;

		CreeObjetStandardExRapide(perso->x - 2,
			perso->y,
			0,
			perso->prio,
			0,
			0,
			AjSprite(Pal_0_32x32_tiles + 16 * 32 * i, 32 * 32),
			AjPalette(Pal_0_palette),
			TAILLE_32x32);

		//        CreeObjetStandard(perso->x-2,perso->y,AjSprite(Pal_0_32x32_tiles+16*32*i,32*32),0,TAILLE_32x32);
		//        Exec(ClipSpriteXY,objetsUtilises,posX,posY);
	}
	else if (((perso->colSol != 0 && perso->colBasObj == 0) ||
			 ((perso->colBasObj == 8 || perso->colBasObj == 4) && perso->colSol == 0 && perso->col2D == 0)) &&
			  (perso->croche || perso->crochePF) && ABS(perso->vx) < VITESSE_MIN)
	{

		//Au bord d'un précipice

		/*        if (aboule!=perso->enboule)      {
		perso->hauteur=32;
		perso->y-=8;
		}*/
		perso->cpt++;
		i = (perso->cpt / 6) % 3;
		if ((signed) perso->colSol == 1 || perso->colBasObj == 4)
		{
			ExecSprScriptExPlus(perso->x - 7,
				perso->y,
				33,
				35,
				Obj_Spt_Pal_0_tiles,
				Obj_Spt_Pal_0_sprBlock + 2 + i,
				AjPalette(Pal_0_palette),
				0,
				perso->prio,
				1,
				0);
		}
		else
		{
			ExecSprScript(perso->x + 1,
				perso->y,
				Obj_Spt_Pal_0_tiles,
				Obj_Spt_Pal_0_sprBlock + 2 + i,
				AjPalette(Pal_0_palette));
		}
	}
	else if (perso->pousseMurDroite > 4)
	{
		perso->cpt++;
		i = (perso->cpt / 32) % 4;
		ExecSprScript(perso->x + 2,
			perso->y,
			Obj_Spt_Pal_0_tiles,
			Obj_Spt_Pal_0_sprBlock + 5 + i,
			AjPalette(Pal_0_palette));
	}
	else if (perso->pousseMurGauche > 4)
	{
		perso->cpt++;
		i = (perso->cpt / 32) % 4;
		ExecSprScriptExPlus(perso->x - 1,
			perso->y,
			24,
			32,
			Obj_Spt_Pal_0_tiles,
			Obj_Spt_Pal_0_sprBlock + 5 + i,
			AjPalette(Pal_0_palette),
			0,
			perso->prio,
			1,
			0);
	}
	else
	{
etat:
		if (perso->fctEtat != NULL)
			perso->fctEtat(perso, ETAT_ACTION_AFFICHE);
		else
		{
			i = Ext_AffSonicHook1(perso);

			//Le hook n'a pas géré? -> Gestion standard!
			if (i == 0)
			{
				vx = perso->vx;
				if (perso->sous_leau)
					vx /= 2;
				i = ABS(vx) >> 8;
				if (i < 1)
					i = 1;
				perso->cpt += i;

				if (ABS(vx) < VITESSE_MIN || perso->premAppui == 1)
				{
					if (perso->dir == 1)
					{
						CreeObjetStandardSonicRotation(perso->prio,
							SONIC_TILE_RESERVEE,
							AjPalette(Pal_0_palette),
							TAILLE_64x64);
						gblSonicComplexe = 0;
					}
					else
					{
						CreeObjetStandardSonicRotation(perso->prio,
							SONIC_TILE_RESERVEE,
							AjPalette(Pal_0_palette),
							TAILLE_64x64);
						gblSonicComplexe = 12;
					}
				}
				else
				{
					if (ABS(vx) < vMUL(5) + vMUL(1) / 2)
						i = ((perso->cpt / 12) % 7) + 1;

					//                       i=((perso->cpt>>3)&7)+1;
					//                   else if (ABS(perso->vx)<vMUL(7))
					//                       i=((perso->cpt>>4)&7)+10;
					else
						i = ((perso->cpt / 12) % 4) + 8;
					if (perso->dir == -1)
						i += 12;
					CreeObjetStandardSonicRotation(perso->prio,
						SONIC_TILE_RESERVEE,
						AjPalette(Pal_0_palette),
						TAILLE_64x64);
					gblSonicComplexe = i;
				}

				curAngle = perso->angle;

				if (curAngle == 0 && !perso->croche)
				{
					if (perso->vangle < curAngle)
					{
						if (ABS(perso->vangle - curAngle) < 180)
							perso->vangle += SKIP(4);
						else
							perso->vangle -= SKIP(4);
					}
					else if (perso->vangle > curAngle)
					{
						if (ABS(perso->vangle - curAngle) < 180)
							perso->vangle -= SKIP(4);
						else
							perso->vangle += SKIP(4);
					}

					if (perso->vangle >= 356 || perso->vangle < 4)
						perso->vangle = 0;
				}
				else
				{
					if (workaround >= 2 || curAngle != 0)
					{
						if (!perso->pas_angle)
							perso->vangle = curAngle;

						//                        perso->vangle=((perso->angle+15)/30)*30;
					}

					if (curAngle == 0)
						workaround++;
					else
						workaround = 0;
				}

				if (gblLI->ei.blocage_angle && perso->pas_angle)
					perso->vangle = 0;

				//               perso->vangle=270;
				if (perso->vangle >= 360)
					perso->vangle -= 360;
				if (perso->vangle < 0)
					perso->vangle += 360;

				rotData[10].pa = cosinus[perso->vangle];
				rotData[10].pb = -sinus[perso->vangle];
				rotData[10].pc = sinus[perso->vangle];
				rotData[10].pd = cosinus[perso->vangle];

				/*               if (perso->vangle<180)
				posX=perso->x-ecr->scrlX-16-((24*sinus[perso->vangle])>>8);
				else
				posX=perso->x-ecr->scrlX-16-((16*sinus[perso->vangle])>>8);*/
				posX = perso->x - ecr->scrlX - 20 - ((20 * sinus[perso->vangle]) >> 8);
				posY = perso->y - ecr->scrlY - 16 - ((15 * cosinus[perso->vangle]) >> 8);

				if (perso->vangle < 180)
					posY += (4 * sinus[(perso->vangle * 2) % 360]) / 256;
				else
					posY -= (4 * sinus[(perso->vangle * 2) % 360]) / 256;
				ClipSpriteXY(objetsUtilises, posX, posY);
			}
		}

		/*        if (adr_32x40)          {
		CreeObjetStandardNormal(AjSprite(adr_32x40,32*32),0,TAILLE_32x32);
		CreeObjetStandardNormal(AjSprite(adr_32x40+32*16,8*32),0,TAILLE_32x8);
		posX=perso->x-ecr->scrlX, posY=perso->y-ecr->scrlY;
		Exec(ClipSpriteXY,objetsUtilises-1,posX,posY);
		Exec(ClipSpriteXY,objetsUtilises,posX,posY+32);
		}*/
	}

	prioDefaut = curPrio;
#pragma attention_peut_etre_une_connerie

	//    if (perso->fctEtat!=NULL && perso->dir==-1)
	//        RetourneObjetH_Oui(objetsUtilises);
	//    aboule=perso->enboule;
}

/*void AfficheGrandSonic(SONIC *perso, ECRAN *ecr)        {
int posX, posY;
static int aboule=0;

if (perso->enboule)        {
perso->vangle=0;
if (aboule==0)      {
perso->largeur=29;
perso->hauteur=29;
perso->y+=10;
}
CreeObjetStandard(pAjSprite(Sonic_tiles,32*32),0,0,2);
if (perso->dir==1)      {
RetourneObjetH_Non(objetsUtilises);
}
else    {
RetourneObjetH_Oui(objetsUtilises);
}
posX=perso->x-ecr->scrlX;
posY=perso->y-ecr->scrlY;
if (perso->dir==-1)
posX-=8;
}
else    {
if (aboule==1)      {
//            perso->hauteur=32;
perso->hauteur=39;
perso->y-=10;
}
if (perso->dir==1)
CreeObjetStandardRotation(pAjSprite(Sonic_64x64_tiles,64*64),0,0,3);
else
CreeObjetStandardRotation(pAjSprite(Sonic_64x64_tiles+64*64/2,64*64),0,0,3);

if (perso->angle==0 && !perso->croche)        {
if (perso->vangle<perso->angle)        {
if (ABS(perso->vangle-perso->angle)<180)
perso->vangle+=SKIP(4);
else
perso->vangle-=SKIP(4);
}
else if (perso->vangle>perso->angle)    {
if (ABS(perso->vangle-perso->angle)<180)
perso->vangle-=SKIP(4);
else
perso->vangle+=SKIP(4);
}
if (perso->vangle>=356 || perso->vangle<4)
perso->vangle=0;
}
else
perso->vangle=perso->angle;

if (perso->vangle>=360)    perso->vangle-=360;
if (perso->vangle<0)       perso->vangle+=360;

rotData[0].pa=cosinus[perso->vangle];
rotData[0].pb=-sinus[perso->vangle];
rotData[0].pc=sinus[perso->vangle];
rotData[0].pd=cosinus[perso->vangle];

posX=perso->x-ecr->scrlX-18-((18*sinus[perso->vangle])>>8);
posY=perso->y-ecr->scrlY-13-((12*cosinus[perso->vangle])>>8);
}

if (perso->angle<180)
posY+=(6*sinus[(perso->vangle*2)%360])/256;
else
posY-=(6*sinus[(perso->vangle*2)%360])/256;
Exec(ClipSpriteXY,objetsUtilises,posX,posY);

aboule=perso->enboule;
perso->cpt++;
}*/
ECRAN *EcrSprites;

void InitSprites()
{
	int i;

	/*
	INITIALISATION DES SPRITES HARDWARE
	Ce procédé est réalisé à chaque nouvelle trame de manière à occuper l'espace
	des sprites de la manière la plus optimale qui soit.
	*/
	objetsUtilises = OBJ_SONIC;
	for (i = 0; i < 128; i++)
	{
		DetruitObjet(i);
	}

	nSprGba = n_tile = 0;        //Initialise le système de gestion de sprites VRAM.
}

//Prend 68 octets d'IWRAM
void IWRAM_CODE MoveRotData(u32 nbSprites)
{
	u32 i;
	const int maxRotData = 64;
	u16 *dst, *src;
	src = &MonOAM[nbSprites].dummy;
	dst = &MonOAM[0].dummy;
	i = 0;
	while (i < maxRotData)
	{
		if (i >= nbSpritesAvantObjets)
			*dst = *src;
		dst += 4, src += 4;
		i++;
	}
}

//Prend 68 octets d'IWRAM

/*void  MoveRotData(u32 nbSprites)        {
int i,j;
const int maxRotData;
u16 *dst, *src;
j=nbSpritesAvantObjets&~3;
maxRotData=64-j;
src=&MonOAM[nbSprites*4+j].attr3;
dst=&MonOAM[j].attr3;
Debug("%i %i %i",j,j+nbSprites*4,maxRotData);
i=maxRotData;
while(i-->0)       {
*dst=*src;
dst+=4, src+=4;
}
}*/
void CollisionGauche(SONIC *s)
{
	s->vx = 0;
	if (s->croche)
		Sonic_metEnBoule(s, 0);
	s->colGauche = 1;
}

void CollisionDroite(SONIC *s)
{
	s->vx = 0;
	if (s->croche)
		Sonic_metEnBoule(s, 0);
	s->colDroite = 1;
}

//Essaie de crocher le personnage. Cela donnera l'impression au moteur de collisions standard que Sonic s'est croché à une plate-forme standard (non-objet)
void EssaieDeCrocher(SONIC *s)
{
	s->colBas = 1;

	//    if (s->vy>GRAVITE_DEPART)
	if (s->decole >= MIN_DECOLE)
		Sonic_metEnBoule(s, 0);
	s->decole = 0;
	if (!(REG_KEYS & KEY_A))
		s->interdit_saut = 0;
	s->vy = GRAVITE_DEPART;
	s->croche = 1;
	s->crochePF = 3;
}

u32 MoteurCollisionObjets(PERSO *s, int vx, int vy)
{
	unsigned int L = s->largeur;
	unsigned int H = s->hauteur;
	unsigned int i, j, e;
	int dist;
	unsigned short LM = (L % P) ? (L - (L % P) + P) : L, HM = (H % P) ? (H - (H % P) + P) : H;        //Largeur et hauteur min. un pattern pour au moins une itération
	register unsigned int x, y;
	u32 col = 0;

	//        x=s->x-(depX<<4);
	//        y=s->y-(depY<<4);
	x = s->x, y = s->y;
	if (!zoneValide(x + (s->largeur >> 1), y + (s->hauteur >> 1), (s->largeur >> 1) + 16, (s->hauteur >> 1) + 16))
		return -1;

	y += vy;

	for (j = 0; j < LM / P + 1; j++)
	{
		if (j >= LM / P)
			i = L - 1;
		else
			i = j * P + 1;

		e = Element(x + i, y + H) &~MASQUE_ENNEMIS;

		//Détection normale
		if (e && e < TYPE_BAS)
		{
			col |= TC_BAS;
			y -= (y + H) & 15;
			s->angle = 0;
		}

		e = Element(x + i, y + H - 1) &~MASQUE_ENNEMIS;
		if (e >= TYPE_BAS && e < TYPE_HAUT)
		{
			col |= TC_BAS;
			dist = ((y + H - 1) % 16) - incline[e - TYPE_BAS][(x + i) % 16];
			if (dist > 0)
			{
				y -= dist;
				s->angle = anglesPF[e - TYPE_BAS];
			}
		}
	}

	x += vx;

	for (j = 0; j < HM / P + 1; j++)
	{
		if (j >= HM / P)
			i = H - 2;
		else
			i = j * P + 1;

		//Détection à gauche du personnage
		e = Element(x, y + i) &~MASQUE_ENNEMIS;
		if (e && e < TYPE_BAS)
		{
			col |= TC_GAUCHE;
			x += 16 - (x & 15);

			//            s->vx=-s->vx;
		}

		//Détection à droite du personnage
		e = Element(x + L, y + i) &~MASQUE_ENNEMIS;
		if (e && e < TYPE_BAS)
		{
			col |= TC_DROITE;
			x -= (x + L) & 15;

			//            s->vx=-s->vx;
		}
	}

	s->x = x, s->y = y;

	//        s->x=x+(depX<<4);
	//        s->y=y+(depY<<4);
	return col;
}

void EffacePerso(u32 j)
{
	int i;
	gblJ = j;
	i = id_perso[j];
	if (persos[i].type && !(persos[i].instructions & INSTR_PAS_EFFACER))
	{
		if (!(persos[i].instructions & INSTR_HORS_MAP))
		{
#ifdef DEBOGAGE
			if (persos[i].noObjet == 0x7fff)
				Debug("ERREUR GRAVE #3!!!");
			else
#endif
				sdUsed[persos[i].noObjet] = 0;

			//            CLR_TABLEAU(persos[i].depX>>4,persos[i].depY>>4);
		}

		DetruitPerso(&persos[i]);
	}
}

void LiberePerso(u32 j)
{
	int i;
	gblJ = j;
	i = id_perso[j];
	if (persos[i].type && !(persos[i].instructions & INSTR_HORS_MAP))
	{

		//Debogage seulement! Permet de me signaler lorsqu'il y a une erreur avec depX et depY.
		//        if (!LIT_TABLEAU(persos[i].depX>>4,persos[i].depY>>4))
		//            Debug("Perso %i (%x) pas libere",i,persos[i].Debug_ID);
		sdUsed[persos[i].noObjet] = 0;

		//        CLR_TABLEAU(persos[i].depX>>4,persos[i].depY>>4);
	}
}

void RemetPerso(u32 j)
{
	int i;
	gblJ = j;
	i = id_perso[j];
	if (persos[i].type && !(persos[i].instructions & INSTR_HORS_MAP))
		sdUsed[persos[i].noObjet] = 1;

	//        SET_TABLEAU(persos[i].depX>>4,persos[i].depY>>4);
}

int wrap(int angle)
{
	if (angle < 0)
		angle -= ((angle - 360) / 360) * 360;
	if (angle > 360)
		angle -= (angle / 360) * 360;
	return angle;
}

void Sonic_perdBagues(SONIC *s)
{
	u32 i, k, add, nombre, mult;

	if (s->invincible)
		return;
	if (s->bagues == 0)
	{
		s->type = 0;
		return;
	}

	if (s->bagues > 32)
		s->bagues = 32;

	while (1)
	{
		nombre = s->bagues;
		if (nombre > 16)
		{
			mult = 1;
			nombre = 16;
		}
		else
			mult = 2;

		if (nombre <= 5)
			add = 90 / nombre;
		else
			add = 180 / nombre;
		if (add < 22)
			add = 22;
		for (i = 0; i < nombre; i++)
		{
			k = CreePerso(s->x, s->y, 1, 16, 16, hBaguePerdue, INSTR_HORS_MAP);
			persos[k].vx = mult * ((3 * cosinus[wrap(110 + (i - nombre / 2) * add)]) >> 1);
			persos[k].vy = mult * ((-sinus[wrap(110 + (i - nombre / 2) * add)] >> 3));
		}

		if (s->bagues > 16)
			s->bagues -= 16;
		else
			break;
	}

	JoueSon(2, SFX_PERDBAGUES); //Perd ses bagues
	s->invincible = 120;
	s->croche = 0;
	ChangeEtat(s, heTouche);
	s->vy = -vMUL(6);
	s->vx = -s->dir * vMUL(2);
	s->angle = 0;
	s->bagues = 0;
	Sonic_metEnBoule(s, 0);
}

void InitSonic(SONIC *s, short x, short y, short l, short h, short vitesse)
{
	s->type = 1;
	s->x = x;
	s->y = y;
	if (vitesse < 0)
		s->dir = -1;
	else
		s->dir = 1;
	s->cpt = 0;
	s->fctEtat = NULL;
	s->vx = vitesse;
	s->saut = 0;
	s->vy = 2;
	s->hauteur = h;
	s->largeur = l;
	s->vangle = 0;
	s->premAppui = s->decole = s->crochePF = 0;
	s->clignote = 0;
	s->croche = 0;
	s->bagues = s->score = 0;
	s->interdit_saut = 1;
	s->sous_leau = 0;
	s->controle = CNT_TOUS;
	s->enbouleobligatoire = 0;
	s->enboule = 0;
	s->virgule_x = s->virgule_y = 0;
	s->prio = 2;
	plan = 0;
}

//Retourne 1 si l'objet existe, 0 sinon
u32 CreeObjetStandard(u16 x,
					  u16 y,
					  unsigned short tiles,
					  unsigned short palette,
					  unsigned short forme,
					  unsigned short taille)
{
	CodeBaseCreeObjet;

	// Création de l'objet
	CreeObjet(objetsUtilises,        //Numéro d'objet
		tiles,                        //Numéro de mosaïque (3), <<2 car 16x16 (*4) et <<1 car mode 8 bits (*2)
		posX,                        //Position X initiale
		posY,                        //Position Y initiale
		0,                        //Mode (alpha-blend)
		forme,                //Forme (0=carrée)
		taille,                //Taille
		0,                        //Mode palette (1=256 couleurs, 0=16 couleurs)
		palette,                //Numéro de palette si 16 couleurs
		prioDefaut,        //Priorité
		0,                        //Retournement vertical
		0,                        //Retournement horizontal
		0,                        //Mode mosaïque (?)
		0,                        //Rotation
		0,                        //N° de rotation
		0);                        //Double-taille (pour rotation)
	return 1;
}

u32 CreeObjetStandardP(
					   PERSO *p,
					   unsigned short tiles,
					   unsigned short palette,
					   unsigned short forme,
					   unsigned short taille)
{
	if (objetsUtilises >= 127 || nSpritesSup >= SPRITES_SUP_MAX || skip)
		return 0;
	VerifieSIlYABesoinDePlacerUnSprite(p->x, p->y, EcrSprites);
	if (posX == 240 && posY == 160)
		return 0;
	objetsUtilises++;

	// Création de l'objet
	CreeObjet(objetsUtilises,        //Numéro d'objet
		tiles,                        //Numéro de mosaïque (3), <<2 car 16x16 (*4) et <<1 car mode 8 bits (*2)
		posX,                        //Position X initiale
		posY,                        //Position Y initiale
		0,                        //Mode (alpha-blend)
		forme,                //Forme (0=carrée)
		taille,                //Taille
		0,                        //Mode palette (1=256 couleurs, 0=16 couleurs)
		palette,                //Numéro de palette si 16 couleurs
		prioDefaut,        //Priorité
		0,                        //Retournement vertical
		0,                        //Retournement horizontal
		0,                        //Mode mosaïque (?)
		0,                        //Rotation
		0,                        //N° de rotation
		0);                        //Double-taille (pour rotation)
	return 1;
}
