/* This function performs all of the physics for a flinger
	A structure is defined to facilitate passing information between this function
 	and the collision checking function 
	This function assumes that there is a function called Is_Terrain(x,y) that returns whether or not there is terrain present on a specific pixel
	Note that there are some strange edge cases that the function handles */

struct collision_coordinates {
	int x_old;
	int y_old;
	int x_collision;
	int y_collision;
	int x_new;
	int y_new;
};

// Macro to replicate processor arithmetical shift right operation
#define SAR(x)		(( (x) >= 0 || ((x) & 1) == 0 ) ? (x) / 2 : ((x) / 2) - 1)

void Flinger_Physics(Lemming* lemming)
{
/* I have omitted the first part of the lemming flinger code which deals with the graphics frame counter */

collision_coordinates col_coords;
int collision_result;
	
// Call the air trajectory collision check function, passing it the lemming pointer,
// a pointer to the coordinate structure so the coordinates can be used when the function returns
// and the flinger lemming height constant
collision_result = Air_Collision_Check( lemming, &col_coords, 9 );
	
if( collision_result != 0 )
{
	if( col_coords->y_collision < col_coords->y_new )	// Lemming collided falling downwards?
	{
		lemming->distance_fallen -= col_coords->y_new - col_coords->y_collision;	// Correct distance fallen because it was set previously in air physics calculation
		if( lemming->distance_fallen < 0 )
		{
			lemming->distance_fallen = 0;
		}
	}
	
	lemming->x_pos = col_coords->x_collision;
	lemming->y_pos = col_coords->y_collision;	// First set lemming's new coordinates to the coordinates of the collision
	
	if( collision_result == -1 )	// Lemming hit head on ceiling?
	{
		if( col_coords->x_new == col_coords->x_old )	// Compares new coordinate to coordinate directly before the collision was detected
		{
			if( col_coords->y_new == col_coords->y_old + 1 )	// Did lemming collide 1 pixel above his new y coordinate?
			{
				col_coords->y_old += 1;		// Permanently modify y coordinate (to be stored)
				Change_Lemming_State(0x40);	// Set lemming state to faller
				// Note that this essentially means that if the lemming was travelling downwards and collided with the ceiling 
				// at his new x coordinate, but 1 pixel above his new y coordinate, he will become a faller
			}
			
			lemming->x_pos = col_coords->x_old;		// Store x coordinate prior to collision
			lemming->y_pos = col_coords->y_old;		// Store y coordinate prior to collision (or modified x coordinate)
		}
		
		lemming->dX = 0;
		lemming->dY = 0;	// Lemming falls straight down after ceiling collision
	}
	else	// Lemming collided with terrain normally
	{
		if( Is_Terrain( col_coords->x_collision, col_coords->y_collision - 1 ) )	// Check if there is terrain 1 pixel above collision coordinates
		{
			if( Is_Terrain( col_coords->x_collision, col_coords->y_collision - 2 ) )	// Check if there is terrain 2 pixels above
			{
				// There is terrain both 1 and 2 pixels above where the lemming collided
				if( Is_Terrain( col_coords->x_collision - lemming->direction, col_coords->y_collision - 1 ) )
				// Is there terrain 1 pixel behind and 1 pixel above the collision
				{
					// Lemming collided into one of the following:
					//	 X							X
					//  XX	moving right	OR     	XX 	moving left		where L is collision location, X is terrain
					//   L							L
					lemming->x_pos = col_coords->x_old;
					lemming->y_pos = col_coords->y_old;	// Set lemming coordinates to coordinates right before collision was detected
				}
				else if( Is_Terrain( col_coords->x_collision - lemming->direction, col_coords->y_collision ) )	// Is there terrain 1 pixel behind where lemming collided with wall
				{
					// Lemming collided into one of the following:
					//  X						X
					// OX	moving right	OR	XO	moving left		where L is collision location, X is terrain, O is confirmed air
					// XL						LX
					lemming->x_pos = col_coords->x_collision - lemming->direction;	// Move lemming back 1, into the pixel with open air above it
					lemming->y_pos = col_coords->y_collision;
				}
				else	// Lemming collided into an actual wall
				{
					lemming->x_pos = col_coords->x_collision - lemming->direction;	// Move lemming back 1, out of the wall
					lemming->y_pos = col_coords->y_collision;
					
					lemming->dY = SAR( lemming->dY );	// Nominally would perform a division by 2, but instead has different behavior for negative odd numbers
					
					lemming->direction = -lemming->direction;	// Flip lemming direction
					
					if( lemming->direction < 0 )	// New lemming direction is negative
					{
						lemming->dX = -lemming->dX;
						lemming->dX = SAR( lemming->dX );
						lemming->dX = SAR( lemming->dX );
					}
					else
					{
						lemming->dX = SAR( lemming->dX );
						lemming->dX = SAR( lemming->dX );
						lemming->dX = -lemming->dX;
					}
					return;
				}
			}
			else	// 2 pixels above where lemming collided with terrain there is air so move lemming up 1
			{
				lemming->x_pos = col_coords->x_collision;
				lemming->y_pos = col_coords->y_collision - 1;
			}
		}
		else
		{
			lemming->x_pos = col_coords->x_collision;
			lemming->y_pos = col_coords->y_collision;
		}
		
		if( lemming->distance_fallen > 99 )
		{
			Change_Lemming_State(0x5E); // Set lemming state to splatter
		}
		else
		{
			Change_Lemming_State(0x42); // Set lemming state to "ower"
		}
	}
}
else	// No collision
{
	lemming->x_pos = col_coords->x_collision;	
	lemming->y_pos = col_coords->y_collision;	// Reduntantly stores new lemming coordinates; the working coordinates should equal new coordinates since there was no collision
	
	if( lemming->dY >= 0 && abs(lemming->dX) < 2 ) // If lemming is falling downwards and moving less than 2 pixels per frame
	{
		if( lemming->is_floater )	// If the lemming has the floater permanent skill
		{
			Change_Lemming_State(0x16); // Set lemming state to floater
		}
		else if( lemming->is_parachuter )	// If the lemming has the floater permanent skill
		{
			Change_Lemming_State(0x28); // Set lemming state to parachuter
		}
	}
}
}