/* MoleInvasion - Copyright (C) - Guillaume Chambraud (linuxprocess@free.fr)

  This program is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation; either version 2 of the License, or
  (at your option) any later version. */

# include "Sother.h"

# define STD_HORIZONTAL_SPEED		4  /* vitesse de déplacement standard */
# define STD_HORIZONTAL_ACCELERATION	1  /* accélération normale */
# define STD_HORIZONTAL_DECELERATION	1  /* décélération normale (frottements) */

# define MAX_VERTICAL_SPEED		21 /* vitesse de chute max */
# define STD_VERTICAL_ACCELERATION	21 /* force de saut */
# define STD_VERTICAL_DECELERATION	2  /* force de gravité */

int giveRandomBonus(void)
{	int id,rnd=rand() % 6;
	switch(rnd)
		{case 0:id=62;break;
		case 1:id=63;break;
		case 2:id=71;break;
		case 3:id=84;break;
		case 4:id=99;break;
		case 5:id=101;break;
		}
	return id;
}

int playerProche(mySprite *element,int dist)
{	return labs( (static_level_datas.global_player->posX + static_level_datas.global_player->imgW/2)
		   - (element->posX + element->imgW/2) ) < dist;
}

void pushMe(mySprite *player,myList * level_walls,myList * level_motionless_sprites,myList * level_sprites)
/* pour les sprites que l'on peut "actionner", test présence gauche/droite */
{	char d,g;

	g=testPositionAllowed(player , level_walls,level_motionless_sprites,level_sprites , -2 , 0);
	d=testPositionAllowed(player , level_walls,level_motionless_sprites,level_sprites , +2 , 0);

	if( !g && d )
	{	player->goright=1; player->goleft=0; player->direction=1;
		player->posX+=2;
	}
	else if( g && !d )
	{	player->goright=0; player->goleft=1; player->direction=-1;
		player->posX-=2;
	}
	else
	{	player->goright=0; player->goleft=0; player->direction=0;
	}
}

void pushMeTry(mySprite *player,myList * level_walls,myList * level_motionless_sprites,myList * level_sprites)
/* pour les sprites que l'on peut "actionner", test présence gauche/droite */
{	char d,g;

	if( ! testPositionAllowed(player, NULL, NULL, level_sprites , -1 , 0)
	   && player->stop_by->direction==+1)
	   	g=0;
	else
		g=1;
	
	if( ! testPositionAllowed(player, NULL, NULL, level_sprites , +1 , 0)
	   && player->stop_by->direction==-1)
	   	d=0;
	else
		d=1;

	if( !g && d )
/*	{	player->goright=1; player->goleft=0; player->direction=1;
*/		player->horizontal_speed=5;
/*	}
*/	else if( g && !d )
/*	{	player->goright=0; player->goleft=1; player->direction=-1;
*/		player->horizontal_speed=-5;
/*	}
	else
	{	player->goright=0; player->goleft=0; player->direction=0;
	}*/
}

char initOther(mySprite * player)
{
	player->vertical_speed=0;
	player->horizontal_speed=0;
	
	player->goright=0;
	player->acceleration=0;

	player->direction=0;
	if(player->sprite_management_type&SPRITE_MOVE)
	{	player->goleft=1;
		player->direction=-1;
	}
	else
	{	player->goleft=0;
		player->direction=0;
	}

	if(player->sprite_management_type&SPRITE_BOUNCY)
		player->gojump=1;
	else
		player->gojump=0;
	
	if(player->sprite_management_type & SPRITE_FLYING || player->id == 78)
		player->touchground=1;
	else
		player->touchground=0;
	player->draw_image_state = 0;
	player->etat=ETAT_VIVANT | ETAT_VISIBLE;

	return 0;
}

#define PLT_VERTICALE	0
#define PLT_HORIZONTALE	1
#define PLT_TOURNANTE	2
#define MAXDISTDIST 	10000 /* distance maximum d'éloignenment de posinit (au carré!) */
int performBonusPlateforme(mySprite *player,myList * level_walls,myList * level_motionless_sprites,myList * level_sprites,int type)
{	char tourne=0;
	long sposX,sposY;

/*printf("IN %ld %ld\n",player->posX,player->posY);*/
	if(!player->direction)
		player->direction=(type==PLT_HORIZONTALE?1:-1);

	if(type==PLT_HORIZONTALE)
	{	if(player->direction>0)
			player->horizontal_speed=STD_HORIZONTAL_SPEED;
		else
			player->horizontal_speed=-STD_HORIZONTAL_SPEED;
	}
	else if(type==PLT_VERTICALE)
	{	if(player->direction>0)
			player->vertical_speed=STD_HORIZONTAL_SPEED;
		else
			player->vertical_speed=-STD_HORIZONTAL_SPEED;
	}

	/* sauvegarde des positions d'arrivée */
	sposX=player->posX;
	sposY=player->posY;

	nearestPosTo(player,level_walls,level_motionless_sprites,level_sprites,
		player->posX+player->horizontal_speed,
		player->posY+player->vertical_speed,
		0);
		
	/* changement de direction ? */
	tourne=0;
	if(type==PLT_HORIZONTALE)
	{	if(player->direction>0)
			tourne=!testPositionAllowed(player, level_walls,level_motionless_sprites,level_sprites, 1, 0);
		else
			tourne=!testPositionAllowed(player, level_walls,level_motionless_sprites,level_sprites,-1, 0);
	}
	else if(type==PLT_VERTICALE)
	{	if(player->direction>0)
			tourne=!testPositionAllowed(player, level_walls,level_motionless_sprites,level_sprites, 0, 1);
		else
			tourne=!testPositionAllowed(player, level_walls,level_motionless_sprites,level_sprites, 0,-1);
	}
	if(tourne)
	{	player->direction=-player->direction;
		/*printf("tourne !\n");*/
	}
	/* trop éloigné de la position initiale ? */
	{	long distX=player->posX-player->posXinit;
		long distY=player->posY-player->posYinit;
		long distcc=distX*distX+distY*distY;
		
		if(distcc>=MAXDISTDIST)
		{	if(distX>0 || distY>0)
				player->direction=-1;
			if(distX<0 || distY<0)
				player->direction= 1;
			player->posX=sposX;
			player->posY=sposY;
			player->horizontal_speed=player->vertical_speed=0;
		}
	}
	
/*printf("OU %ld %ld\n",player->posX,player->posY);*/

	return 0;
}

int performFlyingMole(mySprite *player,myList * level_walls,myList * level_motionless_sprites,myList * level_sprites,int type)
{	char tourne=0;

	if( !player->must_die && player->etat == (ETAT_VISIBLE | ETAT_VIVANT) )
	{	if(!player->direction)
			player->direction=(type==PLT_HORIZONTALE?1:-1);

		if(type==PLT_HORIZONTALE)
		{	if(player->direction>0)
				player->horizontal_speed=STD_HORIZONTAL_SPEED;
			else
				player->horizontal_speed=-STD_HORIZONTAL_SPEED;
			player->vertical_speed=0;
		}
		else if(type==PLT_VERTICALE)
		{	if(player->direction>0)
				player->vertical_speed=STD_HORIZONTAL_SPEED;
			else
				player->vertical_speed=-STD_HORIZONTAL_SPEED;
			player->horizontal_speed=0;
		}
	
		nearestPosTo(player,level_walls,level_motionless_sprites,level_sprites,
			player->posX+player->horizontal_speed,
			player->posY+player->vertical_speed,
			0);
			
		/* changement de direction ? */
		tourne=0;
		if(type==PLT_HORIZONTALE)
		{	if(player->direction>0)
				tourne=!testPositionAllowed(player, level_walls,level_motionless_sprites,level_sprites, 1, 0);
			else
				tourne=!testPositionAllowed(player, level_walls,level_motionless_sprites,level_sprites,-1, 0);
		}
		else if(type==PLT_VERTICALE)
		{	if(player->direction>0)
				tourne=!testPositionAllowed(player, level_walls,level_motionless_sprites,level_sprites, 0, 1);
			else
				tourne=!testPositionAllowed(player, level_walls,level_motionless_sprites,level_sprites, 0,-1);
		}
		if(player->posX<=0 || player->posY>=600/* a ameliorer */ || player->posY<=MAX_VERTICAL_POSITION || tourne)
		{	player->direction=-player->direction;
			/*printf("tourne !\n");*/
		}
	}
	else	/* mourant */
	{	/* calcul des nouvelles vitesses */
		calculeNewVitesse(player,STD_HORIZONTAL_SPEED,STD_HORIZONTAL_ACCELERATION,STD_HORIZONTAL_DECELERATION
					,MAX_VERTICAL_SPEED,  STD_VERTICAL_ACCELERATION,  STD_VERTICAL_DECELERATION);

		if(player->must_die)
		{	startTheSound("snd/kill.ogg");
			player->must_die=0;
		}
		player->etat=ETAT_VISIBLE;
		player->touchground=0;
		if(player->vertical_speed>0)
			player->vertical_speed=0;
				
		player->posX+=player->horizontal_speed;
		player->posY+=player->vertical_speed;

		/* si le sprite est tombé dans un trou ! */
		if(player->posY <= MAX_VERTICAL_POSITION)
			player->etat=ETAT_NONE;
	}
	
	/* choix de l'image */
	performSpriteImage(player);
	
	/*printf("OU %ld %ld\n",player->posX,player->posY);*/

	return 0;
}

int performFallingPierro(mySprite *player,myList * level_walls,myList * level_motionless_sprites,myList * level_sprites)
{
	/* comportement spécial : si on est proche du joueur, alors on tombe */
	if( playerProche(player,55) )
	{	player->image=player->spImages->imgs[1];
		player->OGLtexture=player->spImages->OGLtexture[1];
		if( player->posY+player->imgH<=MAX_VERTICAL_POSITION ||
		   !testPositionAllowed(player, level_walls,level_motionless_sprites,level_sprites, 0,-1))
		  	player->vertical_speed=0;
		else
			calculeNewVitesse(player,0,0,0,MAX_VERTICAL_SPEED,STD_VERTICAL_ACCELERATION,STD_VERTICAL_DECELERATION);
	}
	else
	{	player->image=player->spImages->imgs[0];
		player->OGLtexture=player->spImages->OGLtexture[0];
		if(player->posY+player->imgH<600 /* a ameliorer */ && testPositionAllowed(player, level_walls,level_motionless_sprites,level_sprites, 0,1))
			player->vertical_speed=STD_HORIZONTAL_SPEED;
		else
			player->vertical_speed=0;
	}
	player->horizontal_speed=0;
	
	nearestPosTo(player,level_walls,level_motionless_sprites,level_sprites,
		player->posX,
		player->posY+player->vertical_speed,
		0);

	getCollisionList(player,level_walls,level_motionless_sprites,level_sprites);
	
	return 0;
}

int performSprite98(mySprite *player,myList * level_walls,myList * level_motionless_sprites,myList * level_sprites)
{	long sposX,sposY,tX[3],tY[3],ecart[3];
	long distX,distY,distcc;
	int step,i,j;

	if(!player->direction)
	{	/* init */
		player->direction=1;
		player->posY+=100; /*sqrt(MAXDISTDIST)*/
	}

	for(step=0;step<4;step++)
	{
		/* sauvegarde des positions d'arrivée */
		sposX=player->posX;
		sposY=player->posY;

		if(sposX < player->posXinit && sposY < player->posYinit)
			player->direction=2;
		if(sposX < player->posXinit && sposY > player->posYinit)
			player->direction=-1;
		if(sposX > player->posXinit && sposY > player->posYinit)
			player->direction=-2;
		if(sposX > player->posXinit && sposY < player->posYinit)
			player->direction=1;
		/* 3 positions possibles */
		switch(player->direction)
		{case -2 :	tX[0]=sposX-1;	tY[0]=sposY;
				tX[1]=sposX-1;	tY[1]=sposY+1;
				tX[2]=sposX;	tY[2]=sposY+1;
				break;
		case 1 :	tX[0]=sposX+1;	tY[0]=sposY;
				tX[1]=sposX;	tY[1]=sposY+1;
				tX[2]=sposX+1;	tY[2]=sposY+1;
				break;
		case 2 :	tX[0]=sposX;	tY[0]=sposY-1;
				tX[1]=sposX+1;	tY[1]=sposY-1;
				tX[2]=sposX+1;	tY[2]=sposY;
				break;
		case -1 :	tX[0]=sposX-1;	tY[0]=sposY-1;
				tX[1]=sposX-1;	tY[1]=sposY;
				tX[2]=sposX;	tY[2]=sposY-1;
				break;
		}
		/* on sélectionne la plus proche du rayon */
		for(i=0;i<3;i++)
		{	distX=player->posXinit-tX[i];
			distY=player->posYinit-tY[i];
			distcc=distX*distX+distY*distY;
			for(ecart[i]=0;ecart[i]<MAXDISTDIST;ecart[i]++)
			{	if(distcc+ecart[i] == MAXDISTDIST || distcc-ecart[i] == MAXDISTDIST)
					break;
				for(j=0;j<i-1;j++)
					if(ecart[i] > ecart[j])
						ecart[i]=MAXDISTDIST;
			}
		}
		
		if(ecart[0]<ecart[1])
		{	if(ecart[0]<ecart[2])
				i=0;
			else
				i=2;
		}
		else
		{	if(ecart[1]<ecart[2])
				i=1;
			else
				i=2;
		}
	
		player->posX=tX[i];
		player->posY=tY[i];
	}		
	return 0;
}

/* switch */
int performBonus87(mySprite *player,myList * level_walls,myList * level_motionless_sprites,myList * level_sprites)
{	
	if( player->must_die )
	{	/* on positionne le compte a rebours switch */
		static_level_datas.switchTime+=10;
		player->etat=ETAT_NONE;
	}
	return 0;
}

int performCanon(mySprite *player,myList * level_walls,myList * level_motionless_sprites,myList * level_sprites)
{	
	if(player->draw_image_state<100)
		player->draw_image_state++;
	else
	{	player->draw_image_state=0;
		
		player->direction=-1; /* gauche */
		if( testPositionAllowed(player , level_walls,level_motionless_sprites,level_sprites , -20 , 0))
			createNewSpriteNear(player,103,POS_SIDE,level_walls,level_motionless_sprites,level_sprites);

		player->direction=1; /* droite */
		if( testPositionAllowed(player , level_walls,level_motionless_sprites,level_sprites , 20 , 0))
			createNewSpriteNear(player,103,POS_SIDE,level_walls,level_motionless_sprites,level_sprites);
	}
	return 0;
}

/* [!] boxes */
int performBonusTile(mySprite *player,myList * level_walls,myList * level_motionless_sprites,myList * level_sprites, int bonus_id)
{	
	if( player->must_die )
	{	changeSpriteToId(player,66,level_walls,level_motionless_sprites,level_sprites,1);
		startTheSound("snd/openbox.ogg");
		/* on rajoute un bonus au dessus */
		if(bonus_id)
			createNewSpriteNear(player,bonus_id,POS_UP,level_walls,level_motionless_sprites,level_sprites);
		else
			createNewSpriteNear(player,giveRandomBonus(),POS_UP,level_walls,level_motionless_sprites,level_sprites);
	}
	/* choix de l'image */
	performSpriteImage(player);
	return 0;
}

int performBoulet(mySprite *player,myList * level_walls,myList * level_motionless_sprites,myList * level_sprites)
{	int code_retour=0; /* 0=on continue ; 1=sprite mort */

	/* calcul des nouvelles vitesses */
	calculeNewVitesse(player,STD_HORIZONTAL_SPEED,STD_HORIZONTAL_ACCELERATION,STD_HORIZONTAL_DECELERATION
					,MAX_VERTICAL_SPEED,  STD_VERTICAL_ACCELERATION,  STD_VERTICAL_DECELERATION);

	if(player->horizontal_speed>0)
		player->direction=1; /* droite */
	if(player->horizontal_speed<0)
		player->direction=-1; /* gauche */

	nearestPosTo(player,level_walls,level_motionless_sprites,level_sprites,
		player->posX+player->horizontal_speed,
		player->posY,
		0);

	if( !player->must_die && player->etat == (ETAT_VISIBLE | ETAT_VIVANT) )
	{	/* on teste si on touche quelque chose alors on explose */
		if( ! testPositionAllowed(player , level_walls,level_motionless_sprites,level_sprites , player->horizontal_speed<0?-1:+1 , 0))
			changeSpriteToId(player,102,level_walls,level_motionless_sprites,level_sprites,1);
	}
	else	/* mourant */
	{	if(player->must_die)
		{	startTheSound("snd/kill.ogg");
			player->must_die=0;
		}
		player->etat=ETAT_VISIBLE;
		player->touchground=0;
		if(player->vertical_speed>0)
			player->vertical_speed=0;
				
		player->posX+=player->horizontal_speed;
		player->posY+=player->vertical_speed;
	}

	/* si le sprite est tombe dans un trou ! */
	if(player->posY <= MAX_VERTICAL_POSITION)
	{	player->etat=ETAT_NONE;
		code_retour=1;
	}

	/* les boulets disparaissent si ils sont trop eloignés */
	if( player->posX + static_level_datas.decalX > 800 ||
	    player->posX + static_level_datas.decalX < -player->imgW )
	{	player->etat=ETAT_NONE;
		code_retour=1;
	}	
	
	/* choix de l'image */
	performSpriteImage(player);

	return code_retour;
}

int performExplosion(mySprite *player,myList * level_walls,myList * level_motionless_sprites,myList * level_sprites)
{	int code_retour=0; /* 0=on continue ; 1=sprite mort */

	if( !player->must_die )
	{	/* init */
		if(player->draw_image_state<100)
		{	player->draw_image_state=120;
			startTheSound("snd/explosion.ogg");
		}
		player->image=player->spImages->imgs[player->draw_image_state%2];
		player->OGLtexture=player->spImages->OGLtexture[player->draw_image_state%2];
		player->draw_image_state--;
		if(player->draw_image_state<100)
			player->must_die=1;

		/* y a t-il une incidence ? (typiquement sprite a tuer) */
		getCollisionList(player,level_walls,level_motionless_sprites,level_sprites);
	}
	else
	{	player->etat=ETAT_NONE;
		code_retour=1;
	}
	return code_retour;
}

int performExploBomb(mySprite *player,myList * level_walls,myList * level_motionless_sprites,myList * level_sprites)
{	int code_retour=0; /* 0=on continue ; 1=sprite mort */

	/* calcul des nouvelles vitesses */
	calculeNewVitesse(player,STD_HORIZONTAL_SPEED,STD_HORIZONTAL_ACCELERATION,STD_HORIZONTAL_DECELERATION
					,MAX_VERTICAL_SPEED,  STD_VERTICAL_ACCELERATION,  STD_VERTICAL_DECELERATION);

	if( !player->must_die )
	{	code_retour=commonMounvingSpriteBehaviour(player,level_walls,level_motionless_sprites,level_sprites);
		
		if(player->draw_image_count)
		{	player->draw_image_count--;
		}
		else	 /* init */
		{	if(player->draw_image_state<100)
			{	player->draw_image_state=110;
				startTheSound("snd/explobomb.ogg");
			}
			if(player->draw_image_state>105)
				player->draw_image_count=10;
			else
				player->draw_image_count=5;
			player->image=player->spImages->imgs[player->draw_image_state%2];
			player->OGLtexture=player->spImages->OGLtexture[player->draw_image_state%2];
			player->draw_image_state--;
			if(player->draw_image_state<100)
				player->must_die=1;
		}

		/* pour les sprites que l'on peut "actionner", test présence gauche/droite */
		pushMe(player,level_walls,level_motionless_sprites,level_sprites);
	}
	else	/* on explose */
	{	changeSpriteToId(player,102,level_walls,level_motionless_sprites,level_sprites,1);
		code_retour=1;
	}

	return code_retour;
}

/* under ground mole */
int performBonus72(mySprite *player,myList * level_walls,myList * level_motionless_sprites,myList * level_sprites)
{	
	int next,code_retour=0; /* 0=on continue ; 1=sprite mort */

	/* calcul des nouvelles vitesses */
	calculeNewVitesse(player,STD_HORIZONTAL_SPEED,STD_HORIZONTAL_ACCELERATION,STD_HORIZONTAL_DECELERATION
					,MAX_VERTICAL_SPEED,  STD_VERTICAL_ACCELERATION,  STD_VERTICAL_DECELERATION);

	if( !player->must_die )
	{	code_retour=commonMounvingSpriteBehaviour(player,level_walls,level_motionless_sprites,level_sprites);
			
		/* touche le sol ? */
		if(!testPositionAllowed(player, level_walls,level_motionless_sprites,level_sprites,0,-1))
		{	player->touchground=1;
			/* comportement spécial si on va vers le vide (demi-tour) */
			/* x4 pour ne pas trop déborder des bords */
			if(testPositionAllowed(player, level_walls,level_motionless_sprites,level_sprites,player->horizontal_speed<<2,-1))
				demi_tour(player);
		}
		else if(!(player->sprite_management_type & SPRITE_FLYING))
			player->touchground=0;
		
		/* comportement spécial : si on est proche du joueur,
		alors on meure pour se transformer et sortir de terre */
		if(playerProche(player,100))
			player->must_die=1;
	}
	else	/* mourant */
	{	if(player->draw_image_count)
		{	player->draw_image_count--;
		}
		else
		{	player->draw_image_count=5;
			next=player->draw_image_state+1;
			if(next>=player->spImages->imgs_cnt)
			{	/* en fait, on meure pour mieux revivre ;-) */
				player->posY += player->map->h;
				changeSpriteToId(player,60,level_walls,level_motionless_sprites,level_sprites,0);
			}
			else
			{	player->image=player->spImages->imgs[next];
				player->OGLtexture=player->spImages->OGLtexture[next];
				player->draw_image_state=next;
			}
		}
	}

	/* si le player est tombé dans un trou ! */
	if(player->posY <= MAX_VERTICAL_POSITION)
	{	player->etat=ETAT_NONE;
		code_retour=1;
	}

	return code_retour;
}

int performBonusSprite(mySprite *player,myList * level_walls,myList * level_motionless_sprites,myList * level_sprites)
{
	int code_retour=0; /* 0=on continue ; 1=sprite mort */

	/* calcul des nouvelles vitesses */
	calculeNewVitesse(player,STD_HORIZONTAL_SPEED,STD_HORIZONTAL_ACCELERATION,STD_HORIZONTAL_DECELERATION
				,MAX_VERTICAL_SPEED,  STD_VERTICAL_ACCELERATION,  STD_VERTICAL_DECELERATION);

	if( !player->must_die && player->etat == (ETAT_VISIBLE | ETAT_VIVANT) )
	{
		code_retour=commonMounvingSpriteBehaviour(player,level_walls,level_motionless_sprites,level_sprites);

		/* on a trouvé le position finale du sprite */
		/* y a t-il une incidence ? (typiquement player à tuer) */
		getCollisionList(player,level_walls,level_motionless_sprites,level_sprites);

		/* touche le sol ? */
		if(!testPositionAllowed(player, level_walls,level_motionless_sprites,level_sprites,0,-1))
		{	player->touchground=1;
			if(player->sprite_management_type&SPRITE_BOUNCY)
				player->gojump=1;
			/* comportement spécial si on va vers le vide (saut ou demi-tour) */
			if(player->sprite_management_type&(SPRITE_TURNONEDGE|SPRITE_JUMPONEDGE))
			{	/* x4 pour ne pas trop déborder des bords */
				if(testPositionAllowed(player, level_walls,level_motionless_sprites,level_sprites,player->horizontal_speed<<2,-1))
				{	if(player->sprite_management_type&SPRITE_TURNONEDGE)
						demi_tour(player);
					else
						player->gojump=1;
				}
			}
		}
		else if(!(player->sprite_management_type & SPRITE_FLYING))
		{	player->touchground=0;
			player->gojump=0;
		}
	}
	else	/* mourant */
	{	if(player->must_die)
		{	/*startTheSound("snd/kill.ogg");*/
			player->must_die=0;
		}
		player->etat=ETAT_VISIBLE;
		player->touchground=0;
		if(player->vertical_speed>0)
			player->vertical_speed=0;
				
		player->posX+=player->horizontal_speed;
		player->posY+=player->vertical_speed;
	}

	/* si le sprite est tombé dans un trou ! */
	if(player->posY <= MAX_VERTICAL_POSITION)
	{	player->etat=ETAT_NONE;
		code_retour=1;
	}

	/* choix de l'image */
	performSpriteImage(player);

	return code_retour;
}

int performMovShell(mySprite *player,myList * level_walls,myList * level_motionless_sprites,myList * level_sprites)
{	
	unsigned int * liste_coll=NULL;
	int code_retour=0; /* 0=on continue ; 1=sprite mort */
	
	/* calcul des nouvelles vitesses */
	calculeNewVitesse(player,STD_HORIZONTAL_SPEED*3,STD_HORIZONTAL_SPEED*3,0
				,MAX_VERTICAL_SPEED,  0,  STD_VERTICAL_DECELERATION);

	if( !player->must_die && player->etat == (ETAT_VISIBLE | ETAT_VIVANT) )
	{
		if(player->horizontal_speed>0)
			player->direction=1; /* droite */
		if(player->horizontal_speed<0)
			player->direction=-1; /* gauche */

		/* si !jump && touch_ground => dépl horiontal seul */
		if(!testPositionAllowed(player, level_walls,level_motionless_sprites,level_sprites,0,-1))
			player->vertical_speed=0;
		else /* pour forcer la coquille a prendre les trous, gameplay++ ;-) */
			if(testPositionAllowed(player, level_walls,level_motionless_sprites,level_sprites,0,-1-STEP_SIZE))
				player->posY-=STEP_SIZE;

		/* on rentre latéralement dans un mur */
		if(player->horizontal_speed != 0 &&
		   !testPositionAllowed(player , level_walls,level_motionless_sprites,level_sprites , player->horizontal_speed<0?-1:+1 , 0) &&
		   !testPositionAllowed(player , level_walls,level_motionless_sprites,level_sprites , player->horizontal_speed<0?-1:+1 , STEP_SIZE))
		{	player->horizontal_speed=0;
			if(player->sprite_management_type&SPRITE_MOVE)
				demi_tour(player);
		}

		nearestPosTo(player,level_walls,level_motionless_sprites,level_sprites,
			player->posX + player->horizontal_speed,
			player->posY + player->vertical_speed,
			STEP_SIZE);

		/* on a trouvé la position finale du sprite */
		/* y a t-il une incidence ? (typiquement player à tuer) */
		liste_coll=getCollisionList(player,level_walls,level_motionless_sprites,level_sprites);
		
		/* si un sprite tue quelu'un, il fait demi-tour */
		if( player->sprite_management_type&SPRITE_MOVE &&
		    isElementIn(COLLISION_S1_KILL ,liste_coll) )
			demi_tour(player);

		/* touche le sol ? */
		if(!testPositionAllowed(player, level_walls,level_motionless_sprites,level_sprites,0,-1))
			player->touchground=1;
		else
			player->touchground=0;
	}
	else	/* mourant */
	{	if(player->must_die)
		{	
			startTheSound("snd/kill.ogg");
			player->must_die=0;
		}
		/* mov_shell devient imo_shell */
		changeSpriteToId(player,115,level_walls,level_motionless_sprites,level_sprites,1);
		player->horizontal_speed=0;
	}

	/* si le sprite est tombé dans un trou ! */
	if(player->posY <= MAX_VERTICAL_POSITION)
	{	player->etat=ETAT_NONE;
		code_retour=1;
	}
	
	/* choix de l'image */
	performSpriteImage(player);

	return code_retour;
}

int performOther(mySprite *player,myList * level_walls,myList * level_motionless_sprites,myList * level_sprites)
{	
	unsigned int * liste_coll=NULL;
	int code_retour=0; /* 0=on continue ; 1=sprite mort */
	
	/* gestions speciales */
	switch(player->id)
	{case 87: /* switch */
		return performBonus87(player,level_walls,level_motionless_sprites,level_sprites);
	case  55: /* [!] random */
	case  95:
		return performBonusTile(player,level_walls,level_motionless_sprites,level_sprites,0);
	case 105: /* donne chrono 71 */
		return performBonusTile(player,level_walls,level_motionless_sprites,level_sprites,71);
	case 106: /* donne sac 62 */
		return performBonusTile(player,level_walls,level_motionless_sprites,level_sprites,62);
	case 107: /* donne potion 63 */
		return performBonusTile(player,level_walls,level_motionless_sprites,level_sprites,63);
	case 108: /* donne coin 83 */
		return performBonusTile(player,level_walls,level_motionless_sprites,level_sprites,83);
	case 109: /* donne coin 84 */
		return performBonusTile(player,level_walls,level_motionless_sprites,level_sprites,84);
	case 110: /* donne gem 99 */
		return performBonusTile(player,level_walls,level_motionless_sprites,level_sprites,99);
	case  72: /* under ground mole */
		return performBonus72(player,level_walls,level_motionless_sprites,level_sprites);
	case  96: /* plateforme horizontale */
		return performBonusPlateforme(player,level_walls,level_motionless_sprites,level_sprites,PLT_HORIZONTALE);
	case  97: /* plateforme verticale */
		return performBonusPlateforme(player,level_walls,level_motionless_sprites,level_sprites,PLT_VERTICALE);
	case  98: /* rotating pics */
		return performSprite98(player,level_walls,level_motionless_sprites,level_sprites);
	case 101: /* explobomb */
		return performExploBomb(player,level_walls,level_motionless_sprites,level_sprites);
	case 102: /* explosion */
		return performExplosion(player,level_walls,level_motionless_sprites,level_sprites);
	case 103: /* boulet */
		return performBoulet(player,level_walls,level_motionless_sprites,level_sprites);
	case 104: /* canon */
		return performCanon(player,level_walls,level_motionless_sprites,level_sprites);
	case 71: /* bonuses */
	case 62: case 63: case 83: case 84: case 99:
		return performBonusSprite(player,level_walls,level_motionless_sprites,level_sprites);
	case 81: /* flyning mole h */
		return performFlyingMole(player,level_walls,level_motionless_sprites,level_sprites,PLT_HORIZONTALE);
	case 113:/* flyning mole v */
		return performFlyingMole(player,level_walls,level_motionless_sprites,level_sprites,PLT_VERTICALE);
	case 116:/* moving shell */
		return performMovShell(player,level_walls,level_motionless_sprites,level_sprites);
	case 117:/* falling pierro */
		return performFallingPierro(player,level_walls,level_motionless_sprites,level_sprites);
	}
	
	/* calcul des nouvelles vitesses */
	if(player->id == 76 || player->id == 89) /* shuriken , lpics */
		calculeNewVitesse(player,STD_HORIZONTAL_SPEED*4,STD_HORIZONTAL_SPEED*4,0,0,0,0);
	else if(player->id == 78 ) /* marteau */
		calculeNewVitesse(player,STD_HORIZONTAL_SPEED*2,STD_HORIZONTAL_SPEED*2,0
					,MAX_VERTICAL_SPEED,  STD_VERTICAL_ACCELERATION,  STD_VERTICAL_DECELERATION);
	else
		calculeNewVitesse(player,STD_HORIZONTAL_SPEED,STD_HORIZONTAL_ACCELERATION,STD_HORIZONTAL_DECELERATION
					,MAX_VERTICAL_SPEED,  STD_VERTICAL_ACCELERATION,  STD_VERTICAL_DECELERATION);

	if( !player->must_die && player->etat == (ETAT_VISIBLE | ETAT_VIVANT) )
	{
		code_retour=commonMounvingSpriteBehaviour(player,level_walls,level_motionless_sprites,level_sprites);

		/* on a trouvé la position finale du sprite */
		/* y a t-il une incidence ? (typiquement player à tuer) */
		liste_coll=getCollisionList(player,level_walls,level_motionless_sprites,level_sprites);
		
		/* si un sprite tue quelu'un, il fait demi-tour */
		if( player->sprite_management_type&SPRITE_MOVE &&
		    isElementIn(COLLISION_S1_KILL ,liste_coll) )
		{	demi_tour(player);
		}

		/* contact fatal ? */
		if(	(player->id == 78 || player->id == 76 || player->id == 89)
			&& isElementIn(COLLISION_S1_DIE,liste_coll))
		{	player->etat=ETAT_NONE;
			code_retour=1;
		}
		else
		{	/* touche le sol ? */
			if(!testPositionAllowed(player, level_walls,level_motionless_sprites,level_sprites,0,-1))
			{	player->touchground=1;
				if(player->sprite_management_type&SPRITE_BOUNCY)
					player->gojump=1;
				/* comportement spécial si on va vers le vide (saut ou demi-tour) */
				if(player->sprite_management_type&(SPRITE_TURNONEDGE|SPRITE_JUMPONEDGE))
				{	/* x4 pour ne pas trop déborder des bords */
					if(testPositionAllowed(player, level_walls,level_motionless_sprites,level_sprites,player->horizontal_speed<<2,-2*STEP_SIZE))
					{	if(player->sprite_management_type&SPRITE_TURNONEDGE)
							demi_tour(player);
						else
							player->gojump=1;
					}
				}
			}
			else if(!(player->sprite_management_type & SPRITE_FLYING))
			{	player->touchground=0;
				player->gojump=0;
			}

			/* armes lancées ! */	
			if(	(player->id == 57 || player->id == 82)
				&& rand()%100==0 ) /* lance une arme */
			{	
				if(player->id == 57) /* hammer */
					createNewSpriteNear(player,78,POS_SIDE,level_walls,level_motionless_sprites,level_sprites);
				else if(player->id == 82) /* lpic */
					createNewSpriteNear(player,89,POS_SIDE,level_walls,level_motionless_sprites,level_sprites);
			}
		}
	}
	else	/* mourant */
	{	if(player->must_die)
		{	
			startTheSound("snd/kill.ogg");
			player->must_die=0;
		}

		if(player->id == 53) /* caisse devient bonus  */
		{	changeSpriteToId(player,giveRandomBonus(),level_walls,level_motionless_sprites,level_sprites,1);
			player->vertical_speed=0;
		}
		else if(player->id == 100) /* bomby devient explobomb  */
		{	changeSpriteToId(player,101,level_walls,level_motionless_sprites,level_sprites,1);
			player->horizontal_speed=0;
		}
		else if(player->id == 76 || player->id == 78 || player->id == 89)
		{	/* les armes disparaissent de suite */
			player->etat=ETAT_NONE;
			code_retour=1;
		}
		else if(player->id == 73) /* giant mole devient multi mole */
		{	changeSpriteToId(player,60,level_walls,level_motionless_sprites,level_sprites,1);
			createNewSpriteNear(player,60,POS_SIDE,level_walls,level_motionless_sprites,level_sprites);
			createNewSpriteNear(player,60,POS_UP,level_walls,level_motionless_sprites,level_sprites);
		}
		else if(player->id == 114) /* tortoise devient imo_shell */
		{	changeSpriteToId(player,115,level_walls,level_motionless_sprites,level_sprites,1);
			player->horizontal_speed=0;
		}
		else if(player->id == 115) /* imo_shell devient mov_shell */
		{	changeSpriteToId(player,116,level_walls,level_motionless_sprites,level_sprites,1);
			if(static_level_datas.global_player->direction>0)
			{	player->direction=1;
				player->goleft=0;player->goright=1;
				player->horizontal_speed=STD_HORIZONTAL_SPEED*3;
				if(static_level_datas.global_player->horizontal_speed>STD_HORIZONTAL_SPEED)
					static_level_datas.global_player->horizontal_speed=STD_HORIZONTAL_SPEED;
			}
			else
			{	player->direction=-1;
				player->goleft=1;player->goright=0;
				player->horizontal_speed=-STD_HORIZONTAL_SPEED*3;
				if(static_level_datas.global_player->horizontal_speed<-STD_HORIZONTAL_SPEED)
					static_level_datas.global_player->horizontal_speed=-STD_HORIZONTAL_SPEED;
			}
		}
		else
		{	/* meure ... */
			player->etat=ETAT_VISIBLE;
			player->touchground=0;
			if(player->vertical_speed>0)
				player->vertical_speed=0;
				
			player->posX+=player->horizontal_speed;
			player->posY+=player->vertical_speed;
		}
	}

	/* si le sprite est tombé dans un trou ! */
	if(player->posY <= MAX_VERTICAL_POSITION)
	{	player->etat=ETAT_NONE;
		code_retour=1;
	}

	/* les armes disparaissent si elles sont trop eloignées */
	if( ( player->id == 76 || player->id == 78 || player->id == 89 ) &&
	    ( player->posX + static_level_datas.decalX > 800 ||
	      player->posX + static_level_datas.decalX < -player->imgW ) )
	{	player->etat=ETAT_NONE;
		code_retour=1;
	}
	
	/* pour les sprites que l'on peut "deplacer", test présence gauche/droite */
	if( player->id == 53 || player->id == 56 )
		pushMe(player,level_walls,level_motionless_sprites,level_sprites);
	
	/* choix de l'image */
	performSpriteImage(player);

	return code_retour;
}
