/* MoleInvasion 0.1 - Copyright (C) 2004 - 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é */

# define MAX_VERTICAL_POSITION		600

void demi_tour(mySprite * player)
{	player->horizontal_speed=0;
	if(player->goleft)
	{	player->goleft=0;
		player->goright=1;
		player->direction=1;
	}
	else
	{	player->goleft=1;
		player->goright=0;
		player->direction=-1;
	}
}

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->etat=ETAT_VIVANT | ETAT_VISIBLE;

	return 0;
}

/* switch */
int performBonus87(mySprite *player,myList * level_walls,myList * level_sprites,long decalX,long decalY)
{	
	if( (player->etat & ETAT_VISIBLE) && !(player->etat & ETAT_VIVANT) )
	{	/* on positionne le compte a rebours switch */
		static_level_datas.switchTime+=10;
		player->etat=ETAT_NONE;
	}
	return 0;
}

/* [!] box */
int performBonus55(mySprite *player,myList * level_walls,myList * level_sprites,long decalX,long decalY)
{	
	if( player->etat != (ETAT_VISIBLE | ETAT_VIVANT))
	{	int id,rnd=rand() % 4;
	
		changeSpriteToId(player,66);
		player->etat = (ETAT_VISIBLE | ETAT_VIVANT);
		
		/* on rajoute un bonus au dessus */
		switch(rnd)
		{case 0:id=62;break;
		case 1:id=63;break;
		case 2:id=71;break;
		case 3:id=84;break;
		}
		createNewSpriteNear(player,id,POS_UP,level_sprites);
	}
	return 0;
}

/* under ground mole */
int performBonus72(mySprite *player,myList * level_walls,myList * level_sprites,long decalX,long decalY)
{	
	long sposX,sposY;
	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->etat == (ETAT_VISIBLE | ETAT_VIVANT))
	{	/* sauvegarde des positions d'arrivée */
		sposX=player->posX;
		sposY=player->posY;
		
		/* si touch_ground && ! jump => dépl horiontal seul */
		if ( player->gojump == 0 )
		{	player->posY++;
			if(!isPositionAllowed(player, level_walls,level_sprites))
				player->vertical_speed=0;
			player->posY=sposY;
		}
		/* on est collé à un mur */
		if ( player->horizontal_speed != 0 )
		{	if(player->horizontal_speed<0)
				player->posX--;
			else
				player->posX++;
			if(!isPositionAllowed(player, level_walls,level_sprites))
				player->horizontal_speed=0;
			player->posX=sposX;
		}
		
		nearestPosTo(player,level_walls,level_sprites,
			player->posX+player->horizontal_speed,
			player->posY+player->vertical_speed,
			0); /* à modifier pour essayer de monter les cotes */
	
		/* reset des accélérations ? */
		if(sposX==player->posX)
			demi_tour(player);
		if(sposY==player->posY)
			player->vertical_speed=0;
		
		/* touche le sol ? */
		sposY=player->posY;
		sposX=player->posX;
		player->posY++;
		if(!isPositionAllowed(player, level_walls,level_sprites))
		{	player->touchground=1;
			/* comportement spécial si on va vers le vide (saut ou demi-tour) */
			player->posX+=(player->horizontal_speed<<2); /* x4 pour ne pas trop déborder des bords */
			if(isPositionAllowed(player, level_walls,level_sprites))
				demi_tour(player);
		}
		else if(!(player->sprite_management_type & SPRITE_FLYING))
			player->touchground=0;
		player->posY=sposY;
		player->posX=sposX;
		
		/* comportement spécial : si on est proche du joueur, alors on meure pour se transformer et sortir de terre */
//		printf("DEBUG -> %ld %ld\n",static_level_datas.global_player->posX , player->posX);
		if(labs(static_level_datas.global_player->posX-player->posX) < 100)
			player->etat=ETAT_VISIBLE;
	}
	else	/* mourant */
	{	if(player->draw_image_count)
		{	player->draw_image_count--;
		}
		else
		{	player->draw_image_count=5;
			if(player->draw_image_state == IMAGESTOPDRTE)
			{	player->image=player->imageAv1Drte;
				player->draw_image_state=IMAGEAV1DRTE;
			}
			else if(player->draw_image_state == IMAGEAV1DRTE)
			{	player->image=player->imageAv2Drte;
				player->draw_image_state=IMAGEAV2DRTE;
			}
			else if(player->draw_image_state == IMAGEAV2DRTE)
			{	player->image=player->imageAv3Drte;
				player->draw_image_state=IMAGEAV3DRTE;
			}
			else if(player->draw_image_state == IMAGEAV3DRTE)
			{	player->image=player->imageAv4Drte;
				player->draw_image_state=IMAGEAV4DRTE;
			}
			else if(player->draw_image_state == IMAGEAV4DRTE)
			{	/* en fait, on meure pour mieux revivre ;-) */
				changeSpriteToId(player,60);
				player->etat = (ETAT_VISIBLE | ETAT_VIVANT);
				player->posY -= player->map->h;
			}
		}
	}

	/* 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 performOther(mySprite *player,myList * level_walls,myList * level_sprites,long decalX,long decalY)
{	
	long sposX,sposY;
	char * liste_coll=NULL;
	int code_retour=0; /* 0=on continue ; 1=sprite mort */
	
	if(player->id == 87) /* switch */
		return performBonus87(player,level_walls,level_sprites,decalX,decalY);
	if(player->id == 55) /* [!] */
		return performBonus55(player,level_walls,level_sprites,decalX,decalY);
	if(player->id == 72) /* deep mole */
		return performBonus72(player,level_walls,level_sprites,decalX,decalY);
	
	/* vérification de l'état du sprite : un SPRITE_MUR a pu venir se chevaucher */
	if(!isPositionAllowed(player, level_walls,level_sprites))
	{	// sprite doit se pousser
		int pouss=0;
		sposX=player->posX;
		sposY=player->posY;
		// tests haut, bas, gauche, droite 
		while(1)
		{	pouss++;
			// haut 
			player->posX=sposX;
			player->posY=sposY-pouss;
			if(isPositionAllowed(player, level_walls,level_sprites))
				break;
			// bas 
			player->posX=sposX;
			player->posY=sposY+pouss;
			if(isPositionAllowed(player, level_walls,level_sprites))
				break;
			// gauche 
			player->posX=sposX-pouss;
			player->posY=sposY;
			if(isPositionAllowed(player, level_walls,level_sprites))
				break;
			// droite 
			player->posX=sposX+pouss;
			player->posY=sposY;
			if(isPositionAllowed(player, level_walls,level_sprites))
				break;
		}
	}

	/* 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 if(player->sprite_management_type & SPRITE_FLYING && player->etat == (ETAT_VISIBLE | ETAT_VIVANT))
		calculeNewVitesse(player,STD_HORIZONTAL_SPEED,STD_HORIZONTAL_ACCELERATION,STD_HORIZONTAL_DECELERATION
					,0,  0,  0);
	else
		calculeNewVitesse(player,STD_HORIZONTAL_SPEED,STD_HORIZONTAL_ACCELERATION,STD_HORIZONTAL_DECELERATION
					,MAX_VERTICAL_SPEED,  STD_VERTICAL_ACCELERATION,  STD_VERTICAL_DECELERATION);

	if( player->etat == (ETAT_VISIBLE | ETAT_VIVANT))
	{		
		/* sauvegarde des positions d'arrivée */
		sposX=player->posX;
		sposY=player->posY;
		
		/* si touch_ground && ! jump => dépl horiontal seul */
		if ( player->gojump == 0 )
		{	player->posY++;
			if(!isPositionAllowed(player, level_walls,level_sprites))
				player->vertical_speed=0;
			player->posY=sposY;
		}
		/* on est collé à un mur ? */
		if ( player->horizontal_speed != 0 )
		{	if(player->horizontal_speed<0)
				player->posX--;
			else
				player->posX++;
			if(!isPositionAllowed(player, level_walls,level_sprites))
			{	player->horizontal_speed=0;
				if(player->sprite_management_type&SPRITE_MOVE)
					demi_tour(player);
			}
			player->posX=sposX;
		}
		
		nearestPosTo(player,level_walls,level_sprites,
			player->posX+player->horizontal_speed,
			player->posY+player->vertical_speed,
			0); /* à modifier pour essayer de monter les cotes */
	
		/* reset des accélérations ? */
		if(sposY==player->posY)
			player->vertical_speed=0;
		else
			player->gojump=0;
		
		if(sposX==player->posX)
		{	player->horizontal_speed=0;
		}
		
		/* on a trouvé le position finale du sprite */
		/* y a t-il une incidence ? (typiquement player à tuer) */
		liste_coll=getCollisionList(player,level_walls,level_sprites);

		/* 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 ? */
		sposY=player->posY;
		sposX=player->posX;
		player->posY++;
		if(!isPositionAllowed(player, level_walls,level_sprites))
		{	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))
			{	player->posX+=(player->horizontal_speed<<2); /* x4 pour ne pas trop déborder des bords */
	
				if(isPositionAllowed(player, level_walls,level_sprites))
				{	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->posY=sposY;
		player->posX=sposX;

		/* 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_sprites);
			else if(player->id == 82) /* lpic */
				createNewSpriteNear(player,89,POS_SIDE,level_sprites);
		}
		
		}
	}
	else	/* mourant */
	{	player->posX+=player->horizontal_speed;
		player->posY+=player->vertical_speed;
		if(player->id == 53)
		{	int id,rnd=rand() % 4;
			switch(rnd)
			{case 0:id=62;break;
			case 1:id=63;break;
			case 2:id=71;break;
			case 3:id=84;break;
			}
			changeSpriteToId(player,id);
			player->etat = (ETAT_VISIBLE | ETAT_VIVANT);
			player->vertical_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;
		}
	}

	/* 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 + decalX > 800 || player->posX + decalX < -player->image->w ) )
	{	player->etat=ETAT_NONE;
		code_retour=1;
	}
	
	/* pour les sprites que l'on peut "actionner", test présence gauche/droite */
	if( player->id == 53 || player->id == 52 || player->id == 56 )
	{	char d,g;
		sposX=player->posX;
		/* a gauche */
		player->posX--;
		liste_coll=getCollisionList(player,level_walls,level_sprites);
		g=liste_coll[0];
		/* a droite */
		player->posX+=2;
		liste_coll=getCollisionList(player,level_walls,level_sprites);
		d=liste_coll[0];
		player->posX=sposX;
		
		/* pousse ? */
		if(player->goright || player->goleft)
		{	if(g != 0 && d == 0)
			{	player->goright=1;
				player->goleft=0;
				player->direction=1;
			}
			if(g == 0 && d != 0)
			{	player->goright=0;
				player->goleft=1;
				player->direction=-1;
			}
		}
		else
		{	if(g != 0 && d == 0)
				player->posX++;
			if(g == 0 && d != 0)
				player->posX--;
		}
	}
	
	/* choix de l'image */
	performSpriteImage(player);

	return code_retour;
}
