#include <allegro.h>
#include "character.h"
#include "modules/tilemap.h"
#include "data.h"

int tilemap_gripl_check(TILEMAP * tmp, int layer, int flag, COLLISION_MAP * crp)
{
    int i;
    int r = 0;
    int c = 0;

    /* see if there's at least one point to check */
    if(crp->left.point_count > 0)
    {
		i = crp->left.point_count - 1;
	    if(tilemap_flag(tmp, layer, flag, crp->x + crp->rx + crp->left.point[i].x - 1, crp->y + crp->ry + crp->left.point[i].y) && tilemap_over_edge_h(tmp, crp->x + crp->rx + crp->left.point[i].x, crp->x + crp->rx + crp->left.point[i].x - 1))
	    {
		    if(tilemap_flag(tmp, layer, flag, crp->x + crp->rx + crp->left.point[0].x - 1, crp->y + crp->ry + crp->left.point[0].y))
		    {
		    	r = tilemap_flag(tmp, layer, flag, crp->x + crp->rx + crp->left.point[i].x - 1, crp->y + crp->ry + crp->left.point[i].y);
		    	return r;
	    	}
	    }
	}
	return r;
}

int tilemap_gripr_check(TILEMAP * tmp, int layer, int flag, COLLISION_MAP * crp)
{
    int i;
    int r = 0;
    int c = 0;

    /* see if there's at least one point to check */
    if(crp->right.point_count > 0)
    {
		i = crp->right.point_count - 1;
	    if(tilemap_flag(tmp, layer, flag, crp->x + crp->rx + crp->right.point[i].x + 1, crp->y + crp->ry + crp->right.point[i].y) && tilemap_over_edge_h(tmp, crp->x + crp->rx + crp->right.point[i].x, crp->x + crp->rx + crp->right.point[i].x + 1))
	    {
		    if(tilemap_flag(tmp, layer, flag, crp->x + crp->rx + crp->right.point[0].x + 1, crp->y + crp->ry + crp->right.point[0].y))
	    	{
			    r = tilemap_flag(tmp, layer, flag, crp->x + crp->rx + crp->right.point[i].x + 1, crp->y + crp->ry + crp->right.point[i].y);
		    	return r;
	    	}
	    }
	}
	return r;
}

void vg_character_apply_walk_friction(VG_CHARACTER * cp)
{
	if(cp->sprite.vx < itofix(0))
	{
		cp->sprite.vx += ftofix(VG_CHARACTER_WALK_FRICTION);
		if(cp->sprite.vx > itofix(0))
		{
			cp->sprite.vx = itofix(0);
		}
	}
	else
	{
		cp->sprite.vx -= ftofix(VG_CHARACTER_WALK_FRICTION);
		if(cp->sprite.vx < itofix(0))
		{
			cp->sprite.vx = itofix(0);
		}
	}
}

void vg_character_apply_walk_acceleration(VG_CHARACTER * cp, int dir)
{
	if(dir > 0)
	{
		if(vg_controller.button[CONTROLLER_FIRE].held)
		{
			cp->sprite.vx += ftofix(VG_CHARACTER_RUN_ACCELERATION);
			if(cp->sprite.vx > ftofix(VG_CHARACTER_MAX_RUN_SPEED))
			{
				cp->sprite.vx = ftofix(VG_CHARACTER_MAX_RUN_SPEED);
			}
		}
		else
		{
			if(cp->sprite.vx < ftofix(VG_CHARACTER_MAX_WALK_SPEED))
			{
				cp->sprite.vx += ftofix(VG_CHARACTER_WALK_ACCELERATION);
				if(cp->sprite.vx > ftofix(VG_CHARACTER_MAX_WALK_SPEED))
				{
					cp->sprite.vx = ftofix(VG_CHARACTER_MAX_WALK_SPEED);
				}
			}
			else if(cp->sprite.vx > ftofix(VG_CHARACTER_MAX_WALK_SPEED))
			{
				vg_character_apply_walk_friction(cp);
			}
		}
	}
	else if(dir < 0)
	{
		if(vg_controller.button[CONTROLLER_FIRE].held)
		{
			cp->sprite.vx -= ftofix(VG_CHARACTER_RUN_ACCELERATION);
			if(cp->sprite.vx < ftofix(-VG_CHARACTER_MAX_RUN_SPEED))
			{
				cp->sprite.vx = ftofix(-VG_CHARACTER_MAX_RUN_SPEED);
			}
		}
		else
		{
			if(cp->sprite.vx > ftofix(-VG_CHARACTER_MAX_WALK_SPEED))
			{
				cp->sprite.vx -= ftofix(VG_CHARACTER_WALK_ACCELERATION);
				if(cp->sprite.vx < ftofix(-VG_CHARACTER_MAX_WALK_SPEED))
				{
					cp->sprite.vx = ftofix(-VG_CHARACTER_MAX_WALK_SPEED);
				}
			}
			else if(cp->sprite.vx < ftofix(-VG_CHARACTER_MAX_WALK_SPEED))
			{
				vg_character_apply_walk_friction(cp);
			}
		}
	}
}

void vg_character_apply_jump_acceleration(VG_CHARACTER * cp, int dir)
{
	fixed max;
	
	if(cp->jump_speed > ftofix(VG_CHARACTER_MAX_WALK_SPEED))
	{
		max = cp->jump_speed;
	}
	else if(cp->jump_speed < -ftofix(VG_CHARACTER_MAX_WALK_SPEED))
	{
		max = -cp->jump_speed;
	}
	else
	{
		max = ftofix(VG_CHARACTER_MAX_WALK_SPEED);
	}
	
	if(dir > 0)
	{
		cp->sprite.vx += ftofix(VG_CHARACTER_JUMP_ACCELERATION);
		if(cp->sprite.vx > max)
		{
			cp->sprite.vx = max;
		}
	}
	else if(dir < 0)
	{
		cp->sprite.vx -= ftofix(VG_CHARACTER_JUMP_ACCELERATION);
		if(cp->sprite.vx < -max)
		{
			cp->sprite.vx = -max;
		}
	}
}

int vg_character_take_hit(VG_CHARACTER * cp, int points)
{
	cp->life -= points;
	if(cp->life <= 0)
	{
		cp->lives--;
		cp->life = 0;
		return 1;
	}
	return 0;
}

void vg_character_logic(VG_CHARACTER * cp)
{
	if(cp->sprite.d1 > 0)
	{
		cp->sprite.d1--;
	}
	switch(cp->warp_type)
	{
		case VG_CHARACTER_WARP_TYPE_LEFT:
		case VG_CHARACTER_WARP_TYPE_RIGHT:
		{
			cp->warp_time++;
			if(cp->warp_time > cp->sprite.sp->ap[0]->w)
			{
				cp->warp_type = VG_CHARACTER_WARP_TYPE_NONE;
				warp_execute(cp->warp);
				cp->warp = NULL;
				cp->sprite.active = 0;
			}
			return;
			break;
		}
		case VG_CHARACTER_WARP_TYPE_UP:
		case VG_CHARACTER_WARP_TYPE_DOWN:
		{
			cp->warp_time++;
			if(cp->warp_time > cp->sprite.sp->ap[0]->h)
			{
				cp->warp_type = VG_CHARACTER_WARP_TYPE_NONE;
				warp_execute(cp->warp);
				cp->warp = NULL;
				cp->sprite.active = 0;
			}
			return;
			break;
		}
		case VG_CHARACTER_WARP_TYPE_UP_OUT:
		case VG_CHARACTER_WARP_TYPE_DOWN_OUT:
		{
			cp->warp_time--;
			if(cp->warp_time <= 0)
			{
				cp->warp_type = VG_CHARACTER_WARP_TYPE_NONE;
			}
			return;
			break;
		}
		case VG_CHARACTER_WARP_TYPE_LEFT_OUT:
		case VG_CHARACTER_WARP_TYPE_RIGHT_OUT:
		{
			cp->warp_time--;
			if(cp->warp_time <= 0)
			{
				cp->warp_type = VG_CHARACTER_WARP_TYPE_NONE;
			}
			return;
			break;
		}
		case VG_CHARACTER_WARP_TYPE_DOOR_IN:
		{
			cp->warp_time++;
			if(cp->warp_time > 15)
			{
				cp->warp_type = VG_CHARACTER_WARP_TYPE_NONE;
				warp_execute(cp->warp);
				cp->warp = NULL;
				cp->sprite.active = 0;
			}
			return;
			break;
		}
	}
	switch(cp->sprite.state)
	{
		case VG_CHARACTER_HIT_RIGHT:
		{
			vg_character_apply_walk_friction(cp);
			cp->sprite.vy += ftofix(VG_CHARACTER_GRAVITY);
			if(cp->sprite.vy > itofix(VG_CHARACTER_MAX_FALL_VELOCITY))
			{
				cp->sprite.vy = itofix(VG_CHARACTER_MAX_FALL_VELOCITY);
			}
			cp->sprite.timer++;
			if(cp->sprite.timer >= 15)
			{
				cp->sprite.state = VG_CHARACTER_STAND_RIGHT;
				cp->sprite.d1 = 30;
			}
			break;
		}
		case VG_CHARACTER_HIT_LEFT:
		{
			vg_character_apply_walk_friction(cp);
			cp->sprite.vy += ftofix(VG_CHARACTER_GRAVITY);
			if(cp->sprite.vy > itofix(VG_CHARACTER_MAX_FALL_VELOCITY))
			{
				cp->sprite.vy = itofix(VG_CHARACTER_MAX_FALL_VELOCITY);
			}
			cp->sprite.timer++;
			if(cp->sprite.timer >= 15)
			{
				cp->sprite.state = VG_CHARACTER_STAND_LEFT;
				cp->sprite.d1 = 30;
			}
			break;
		}
		case VG_CHARACTER_STAND_RIGHT:
		{
			if(vg_controller.button[CONTROLLER_JUMP].pressed && tilemap_rubb_check(vg_level->tilemap, vg_level->tilemap->il, TILEMAP_FLAG_SOLIDT, &cp->sprite.cmap[cp->sprite.state]))
			{
				ncds_play_sample(vg_sound[VG_SOUND_PLAYER_JUMP], 127, -1, -1);
				vg_player_set_state(VG_CHARACTER_JUMP_RIGHT);
				cp->sprite.frame = 0;
				cp->sprite.vy = itofix(VG_CHARACTER_JUMP_VELOCITY);
				cp->jump_speed = cp->sprite.vx;
			}
			else if(vg_controller.button[CONTROLLER_RIGHT].held)
			{
				vg_player_set_state(VG_CHARACTER_WALK_RIGHT);
				cp->sprite.frame = 0;
			}
			else if(vg_controller.button[CONTROLLER_LEFT].held)
			{
				vg_player_set_state(VG_CHARACTER_WALK_LEFT);
				cp->sprite.frame = 0;
			}
			else if(vg_controller.button[CONTROLLER_DOWN].held)
			{
				vg_player_set_state(VG_CHARACTER_DUCK_RIGHT);
				cp->sprite.frame = 0;
			}
			vg_character_apply_walk_friction(cp);
			break;
		}
		case VG_CHARACTER_STAND_LEFT:
		{
			if(vg_controller.button[CONTROLLER_JUMP].pressed && tilemap_rubb_check(vg_level->tilemap, vg_level->tilemap->il, TILEMAP_FLAG_SOLIDT, &cp->sprite.cmap[cp->sprite.state]))
			{
				ncds_play_sample(vg_sound[VG_SOUND_PLAYER_JUMP], 127, -1, -1);
				vg_player_set_state(VG_CHARACTER_JUMP_LEFT);
				cp->sprite.frame = 0;
				cp->sprite.vy = itofix(VG_CHARACTER_JUMP_VELOCITY);
				cp->jump_speed = cp->sprite.vx;
			}
			else if(vg_controller.button[CONTROLLER_RIGHT].held)
			{
				vg_player_set_state(VG_CHARACTER_WALK_RIGHT);
				cp->sprite.frame = 0;
			}
			else if(vg_controller.button[CONTROLLER_LEFT].held)
			{
				vg_player_set_state(VG_CHARACTER_WALK_LEFT);
				cp->sprite.frame = 0;
			}
			else if(vg_controller.button[CONTROLLER_DOWN].held)
			{
				vg_player_set_state(VG_CHARACTER_DUCK_LEFT);
				cp->sprite.frame = 0;
			}
			vg_character_apply_walk_friction(cp);
			break;
		}
		case VG_CHARACTER_WALK_RIGHT:
		{
			if(!vg_controller.button[CONTROLLER_RIGHT].held)
			{
				vg_player_set_state(VG_CHARACTER_STAND_RIGHT);
			}
			else
			{
				vg_character_apply_walk_acceleration(cp, 1);
			}
			if(vg_controller.button[CONTROLLER_LEFT].held)
			{
				vg_player_set_state(VG_CHARACTER_WALK_LEFT);
			}
			else if(vg_controller.button[CONTROLLER_DOWN].held)
			{
				vg_player_set_state(VG_CHARACTER_DUCK_RIGHT);
				cp->sprite.frame = 0;
			}
			else if(vg_controller.button[CONTROLLER_JUMP].pressed && tilemap_rubb_check(vg_level->tilemap, vg_level->tilemap->il, TILEMAP_FLAG_SOLIDT, &cp->sprite.cmap[cp->sprite.state]))
			{
				ncds_play_sample(vg_sound[VG_SOUND_PLAYER_JUMP], 127, -1, -1);
				vg_player_set_state(VG_CHARACTER_JUMP_RIGHT);
				cp->sprite.frame = 0;
				cp->sprite.vy = itofix(VG_CHARACTER_JUMP_VELOCITY);
				cp->jump_speed = cp->sprite.vx;
			}
			break;
		}
		case VG_CHARACTER_WALK_LEFT:
		{
			if(!vg_controller.button[CONTROLLER_LEFT].held)
			{
				vg_player_set_state(VG_CHARACTER_STAND_LEFT);
			}
			else
			{
				vg_character_apply_walk_acceleration(cp, -1);
			}
			if(vg_controller.button[CONTROLLER_RIGHT].held)
			{
				vg_player_set_state(VG_CHARACTER_WALK_RIGHT);
				cp->sprite.frame = 0;
			}
			else if(vg_controller.button[CONTROLLER_DOWN].held)
			{
				vg_player_set_state(VG_CHARACTER_DUCK_LEFT);
				cp->sprite.frame = 0;
			}
			else if(vg_controller.button[CONTROLLER_JUMP].pressed && tilemap_rubb_check(vg_level->tilemap, vg_level->tilemap->il, TILEMAP_FLAG_SOLIDT, &cp->sprite.cmap[cp->sprite.state]))
			{
				ncds_play_sample(vg_sound[VG_SOUND_PLAYER_JUMP], 127, -1, -1);
				vg_player_set_state(VG_CHARACTER_JUMP_LEFT);
				cp->sprite.frame = 0;
				cp->sprite.vy = itofix(VG_CHARACTER_JUMP_VELOCITY);
				cp->jump_speed = cp->sprite.vx;
			}
			break;
		}
		case VG_CHARACTER_DUCK_RIGHT:
		{
			if(!vg_controller.button[CONTROLLER_DOWN].held && !tilemap_rubt_check(vg_level->tilemap, vg_level->tilemap->il, TILEMAP_FLAG_SOLIDB, &cp->sprite.cmap[cp->sprite.state]))
			{
				vg_player_set_state(VG_CHARACTER_STAND_RIGHT);
				break;
			}
			if(vg_controller.button[CONTROLLER_LEFT].held)
			{
				vg_player_set_state(VG_CHARACTER_DUCK_LEFT);
			}
			if(vg_controller.button[CONTROLLER_JUMP].pressed && vg_controller.button[CONTROLLER_RIGHT].held)
			{
				cp->sprite.vx = itofix(7);
				vg_player_set_state(VG_CHARACTER_SLIDE_RIGHT);
				
			}
			else if(vg_controller.button[CONTROLLER_JUMP].pressed && !tilemap_rubb_check(vg_level->tilemap, vg_level->tilemap->il, TILEMAP_FLAG_SOLIDB, &cp->sprite.cmap[cp->sprite.state]))
			{
				cp->sprite.y += itofix(1);
				cp->sprite.vy = itofix(0);
				vg_player_set_state(VG_CHARACTER_FALL_RIGHT);
				cp->jump_speed = cp->sprite.vx;
			}
			vg_character_apply_walk_friction(cp);
			break;
		}
		case VG_CHARACTER_DUCK_LEFT:
		{
			if(!vg_controller.button[CONTROLLER_DOWN].held && !tilemap_rubt_check(vg_level->tilemap, vg_level->tilemap->il, TILEMAP_FLAG_SOLIDB, &cp->sprite.cmap[cp->sprite.state]))
			{
				vg_player_set_state(VG_CHARACTER_STAND_LEFT);
				break;
			}
			if(vg_controller.button[CONTROLLER_RIGHT].held)
			{
				vg_player_set_state(VG_CHARACTER_DUCK_RIGHT);
			}
			if(vg_controller.button[CONTROLLER_JUMP].pressed && vg_controller.button[CONTROLLER_LEFT].held)
			{
				cp->sprite.vx = itofix(-7);
				vg_player_set_state(VG_CHARACTER_SLIDE_LEFT);
				
			}
			else if(vg_controller.button[CONTROLLER_JUMP].pressed && !tilemap_rubb_check(vg_level->tilemap, vg_level->tilemap->il, TILEMAP_FLAG_SOLIDB, &cp->sprite.cmap[cp->sprite.state]))
			{
				ncds_play_sample(vg_sound[VG_SOUND_PLAYER_JUMP], 127, -1, -1);
				cp->sprite.y += itofix(1);
				cp->sprite.vy = itofix(0);
				vg_player_set_state(VG_CHARACTER_FALL_LEFT);
				cp->jump_speed = cp->sprite.vx;
			}
			vg_character_apply_walk_friction(cp);
			break;
		}
		case VG_CHARACTER_JUMP_RIGHT:
		{
			if(cp->sprite.vy > itofix(0))
			{
				vg_player_set_state(VG_CHARACTER_FALL_RIGHT);
				break;
			}
			if(vg_controller.button[CONTROLLER_RIGHT].held)
			{
				vg_character_apply_jump_acceleration(cp, 1);
			}
			if(vg_controller.button[CONTROLLER_LEFT].held)
			{
				if(cp->sprite.vx < ftofix(VG_CHARACTER_MAX_WALK_SPEED))
				{
					vg_player_set_state(VG_CHARACTER_JUMP_LEFT);
				}
				cp->sprite.frame = 0;
			}
			
			if(vg_controller.button[CONTROLLER_JUMP].held)
			{
				cp->sprite.vy += ftofix(VG_CHARACTER_GRAVITY);
			}
			else
			{
				if(cp->sprite.vy < itofix(-1))
				{
					cp->sprite.vy = fdiv(cp->sprite.vy, itofix(2));
				}
				else
				{
					cp->sprite.vy += ftofix(VG_CHARACTER_GRAVITY);
				}
			}
			if(cp->sprite.vy > itofix(5))
			{
				cp->sprite.vy = itofix(5);
			}
			break;
		}
		case VG_CHARACTER_JUMP_LEFT:
		{
			if(cp->sprite.vy > itofix(0))
			{
				vg_player_set_state(VG_CHARACTER_FALL_LEFT);
				break;
			}
			if(vg_controller.button[CONTROLLER_LEFT].held)
			{
				vg_character_apply_jump_acceleration(cp, -1);
			}
			if(vg_controller.button[CONTROLLER_RIGHT].held)
			{
				if(cp->sprite.vx > -ftofix(VG_CHARACTER_MAX_WALK_SPEED))
				{
					vg_player_set_state(VG_CHARACTER_JUMP_RIGHT);
				}
				cp->sprite.frame = 0;
			}
			if(vg_controller.button[CONTROLLER_JUMP].held)
			{
				cp->sprite.vy += ftofix(VG_CHARACTER_GRAVITY);
			}
			else
			{
				if(cp->sprite.vy < itofix(-1))
				{
					cp->sprite.vy = fdiv(cp->sprite.vy, itofix(2));
				}
				else
				{
					cp->sprite.vy += ftofix(VG_CHARACTER_GRAVITY);
				}
			}
			if(cp->sprite.vy > itofix(5))
			{
				cp->sprite.vy = itofix(5);
			}
			break;
		}
		case VG_CHARACTER_FALL_RIGHT:
		{
			if(vg_controller.button[CONTROLLER_RIGHT].held && tilemap_gripr_check(vg_level->tilemap, vg_level->tilemap->il, TILEMAP_FLAG_SOLIDL, &cp->sprite.cmap[cp->sprite.state]))
			{
				vg_player_set_state(VG_CHARACTER_GRIP_RIGHT);
				break;
			}
			else if(vg_controller.button[CONTROLLER_RIGHT].held)
			{
				vg_character_apply_jump_acceleration(cp, 1);
			}
			if(vg_controller.button[CONTROLLER_LEFT].held)
			{
				vg_player_set_state(VG_CHARACTER_FALL_LEFT);
				cp->sprite.frame = 0;
			}
			if(vg_controller.button[CONTROLLER_JUMP].held)
			{
				cp->sprite.vy += ftofix(VG_CHARACTER_GRAVITY);
			}
			else
			{
				if(cp->sprite.vy < itofix(-1))
				{
					cp->sprite.vy = fdiv(cp->sprite.vy, itofix(2));
				}
				else
				{
					cp->sprite.vy += ftofix(VG_CHARACTER_GRAVITY);
				}
			}
			if(cp->sprite.vy > itofix(VG_CHARACTER_MAX_FALL_VELOCITY))
			{
				cp->sprite.vy = itofix(VG_CHARACTER_MAX_FALL_VELOCITY);
			}
			break;
		}
		case VG_CHARACTER_FALL_LEFT:
		{
			if(vg_controller.button[CONTROLLER_LEFT].held && tilemap_gripl_check(vg_level->tilemap, vg_level->tilemap->il, TILEMAP_FLAG_SOLIDR, &cp->sprite.cmap[cp->sprite.state]))
			{
				vg_player_set_state(VG_CHARACTER_GRIP_LEFT);
				break;
			}
			else if(vg_controller.button[CONTROLLER_LEFT].held)
			{
				vg_character_apply_jump_acceleration(cp, -1);
			}
			if(vg_controller.button[CONTROLLER_RIGHT].held)
			{
				vg_player_set_state(VG_CHARACTER_FALL_RIGHT);
				cp->sprite.frame = 0;
			}
			if(vg_controller.button[CONTROLLER_JUMP].held)
			{
				cp->sprite.vy += ftofix(VG_CHARACTER_GRAVITY);
			}
			else
			{
				if(cp->sprite.vy < itofix(-1))
				{
					cp->sprite.vy = fdiv(cp->sprite.vy, itofix(2));
				}
				else
				{
					cp->sprite.vy += ftofix(VG_CHARACTER_GRAVITY);
				}
			}
			if(cp->sprite.vy > itofix(VG_CHARACTER_MAX_FALL_VELOCITY))
			{
				cp->sprite.vy = itofix(VG_CHARACTER_MAX_FALL_VELOCITY);
			}
			break;
		}
		case VG_CHARACTER_GRIP_RIGHT:
		{
			if(!tilemap_gripr_check(vg_level->tilemap, vg_level->tilemap->il, TILEMAP_FLAG_SOLIDL, &cp->sprite.cmap[cp->sprite.state]))
			{
				vg_player_set_state(VG_CHARACTER_FALL_LEFT);
				break;
			}
			else if(vg_controller.button[CONTROLLER_RIGHT].held)
			{
				cp->sprite.vy = itofix(1);
			}
			else
			{
				vg_player_set_state(VG_CHARACTER_FALL_LEFT);
				cp->sprite.frame = 0;
			}
			if(vg_controller.button[CONTROLLER_LEFT].held)
			{
				vg_player_set_state(VG_CHARACTER_FALL_LEFT);
				cp->sprite.frame = 0;
			}
			if(vg_controller.button[CONTROLLER_JUMP].pressed)
			{
				ncds_play_sample(vg_sound[VG_SOUND_PLAYER_JUMP], 127, -1, -1);
				cp->sprite.vx = ftofix(-VG_CHARACTER_MAX_RUN_SPEED);
				cp->sprite.vy = itofix(VG_CHARACTER_JUMP_VELOCITY);
				vg_player_set_state(VG_CHARACTER_JUMP_LEFT);
				cp->sprite.frame = 0;
				cp->jump_speed = cp->sprite.vx;
			}
			break;
		}
		case VG_CHARACTER_GRIP_LEFT:
		{
			if(!tilemap_gripl_check(vg_level->tilemap, vg_level->tilemap->il, TILEMAP_FLAG_SOLIDR, &cp->sprite.cmap[cp->sprite.state]))
			{
				vg_player_set_state(VG_CHARACTER_FALL_RIGHT);
				break;
			}
			else if(vg_controller.button[CONTROLLER_LEFT].held)
			{
				cp->sprite.vy = itofix(1);
			}
			else
			{
				vg_player_set_state(VG_CHARACTER_FALL_RIGHT);
				cp->sprite.frame = 0;
			}
			if(vg_controller.button[CONTROLLER_RIGHT].held)
			{
				vg_player_set_state(VG_CHARACTER_FALL_RIGHT);
				cp->sprite.frame = 0;
			}
			if(vg_controller.button[CONTROLLER_JUMP].pressed)
			{
				ncds_play_sample(vg_sound[VG_SOUND_PLAYER_JUMP], 127, -1, -1);
				cp->sprite.vx = ftofix(VG_CHARACTER_MAX_RUN_SPEED);
				cp->sprite.vy = itofix(VG_CHARACTER_JUMP_VELOCITY);
				vg_player_set_state(VG_CHARACTER_JUMP_RIGHT);
				cp->sprite.frame = 0;
				cp->jump_speed = cp->sprite.vx;
			}
			break;
		}
		case VG_CHARACTER_SLIDE_RIGHT:
		{
			vg_character_apply_walk_friction(cp);
			if(cp->sprite.vx == itofix(0))
			{
				vg_player_set_state(VG_CHARACTER_DUCK_RIGHT);
			}
			break;
		}
		case VG_CHARACTER_SLIDE_LEFT:
		{
			vg_character_apply_walk_friction(cp);
			if(cp->sprite.vx == itofix(0))
			{
				vg_player_set_state(VG_CHARACTER_DUCK_LEFT);
			}
			break;
		}
	}
	
	/* move player */
	cp->sprite.x += cp->sprite.vx;
	update_collision_map(&cp->sprite.cmap[cp->sprite.state], fixtoi(cp->sprite.x), fixtoi(cp->sprite.y));
	if(tilemap_collide(vg_level->tilemap, &cp->sprite.cmap[cp->sprite.state]))
	{
		cp->sprite.x = itofix(get_sprite_x(&cp->sprite.cmap[cp->sprite.state], 16));
		update_collision_map(&cp->sprite.cmap[cp->sprite.state], fixtoi(cp->sprite.x), fixtoi(cp->sprite.y));
		cp->sprite.vx = itofix(0);
	}
	
	/* move player */
	cp->sprite.y += cp->sprite.vy;
	update_collision_map(&cp->sprite.cmap[cp->sprite.state], fixtoi(cp->sprite.x), fixtoi(cp->sprite.y));
	if(tilemap_collide(vg_level->tilemap, &cp->sprite.cmap[cp->sprite.state]))
	{
		cp->sprite.y = itofix(get_sprite_y(&cp->sprite.cmap[cp->sprite.state], 16));
		if(cp->sprite.vy > 0)
		{
			cp->sprite.vy = itofix(0);
		}
		else
		{
			cp->sprite.vy = itofix(0);
		}
		update_collision_map(&cp->sprite.cmap[cp->sprite.state], fixtoi(cp->sprite.x), fixtoi(cp->sprite.y));
	}
	if(tilemap_rubb_check(vg_level->tilemap, vg_level->tilemap->il, TILEMAP_FLAG_SOLIDT, &cp->sprite.cmap[cp->sprite.state]))
	{
		if(cp->sprite.state == VG_CHARACTER_FALL_RIGHT || cp->sprite.state == VG_CHARACTER_GRIP_RIGHT)
		{
			vg_player_set_state(VG_CHARACTER_STAND_RIGHT);
			cp->sprite.vy = itofix(0);
		}
		else if(cp->sprite.state == VG_CHARACTER_FALL_LEFT || cp->sprite.state == VG_CHARACTER_GRIP_LEFT)
		{
			vg_player_set_state(VG_CHARACTER_STAND_LEFT);
			cp->sprite.vy = itofix(0);
		}
		else if(cp->sprite.state == VG_CHARACTER_HIT_RIGHT || cp->sprite.state == VG_CHARACTER_HIT_LEFT)
		{
			cp->sprite.vy = itofix(0);
		}
	}
	else
	{
		if(cp->sprite.state == VG_CHARACTER_WALK_RIGHT || cp->sprite.state == VG_CHARACTER_STAND_RIGHT || cp->sprite.state == VG_CHARACTER_DUCK_RIGHT || cp->sprite.state == VG_CHARACTER_SLIDE_RIGHT)
		{
			cp->sprite.vy = itofix(0);
			vg_player_set_state(VG_CHARACTER_FALL_RIGHT);
			cp->jump_speed = cp->sprite.vx;
		}
		else if(cp->sprite.state == VG_CHARACTER_WALK_LEFT || cp->sprite.state == VG_CHARACTER_STAND_LEFT || cp->sprite.state == VG_CHARACTER_DUCK_LEFT || cp->sprite.state == VG_CHARACTER_SLIDE_LEFT)
		{
			cp->sprite.vy = itofix(0);
			vg_player_set_state(VG_CHARACTER_FALL_LEFT);
			cp->jump_speed = cp->sprite.vx;
		}
	}
	if(vg_controller.button[CONTROLLER_FIRE].pressed)
	{
		switch(cp->sprite.state)
		{
			case VG_CHARACTER_STAND_RIGHT:
			case VG_CHARACTER_WALK_RIGHT:
			case VG_CHARACTER_JUMP_RIGHT:
			case VG_CHARACTER_FALL_RIGHT:
			case VG_CHARACTER_GRIP_LEFT:
			{
				vg_create_projectile(vg_animation[VG_ANIMATION_PSHOT], VG_PROJECTILE_PLAYER_SHOT, cp->sprite.x + itofix(10), cp->sprite.y + itofix(12), itofix(8), itofix(0));
				ncds_play_sample(vg_sound[VG_SOUND_PLAYER_SHOOT], 127, -1, -1);
				break;
			}
			case VG_CHARACTER_DUCK_RIGHT:
			case VG_CHARACTER_SLIDE_RIGHT:
			{
				vg_create_projectile(vg_animation[VG_ANIMATION_PSHOT], VG_PROJECTILE_PLAYER_SHOT, cp->sprite.x + itofix(10), cp->sprite.y + itofix(17), itofix(8), itofix(0));
				ncds_play_sample(vg_sound[VG_SOUND_PLAYER_SHOOT], 127, -1, -1);
				break;
			}
			case VG_CHARACTER_STAND_LEFT:
			case VG_CHARACTER_WALK_LEFT:
			case VG_CHARACTER_JUMP_LEFT:
			case VG_CHARACTER_FALL_LEFT:
			case VG_CHARACTER_GRIP_RIGHT:
			{
				vg_create_projectile(vg_animation[VG_ANIMATION_PSHOT], VG_PROJECTILE_PLAYER_SHOT, cp->sprite.x + itofix(10), cp->sprite.y + itofix(12), itofix(-8), itofix(0));
				ncds_play_sample(vg_sound[VG_SOUND_PLAYER_SHOOT], 127, -1, -1);
				break;
			}
			case VG_CHARACTER_DUCK_LEFT:
			case VG_CHARACTER_SLIDE_LEFT:
			{
				vg_create_projectile(vg_animation[VG_ANIMATION_PSHOT], VG_PROJECTILE_PLAYER_SHOT, cp->sprite.x + itofix(10), cp->sprite.y + itofix(17), itofix(-8), itofix(0));
				ncds_play_sample(vg_sound[VG_SOUND_PLAYER_SHOOT], 127, -1, -1);
				break;
			}
		}
	}
	if((cp->sprite.state == VG_CHARACTER_WALK_LEFT || cp->sprite.state == VG_CHARACTER_WALK_RIGHT) && (cp->sprite.vx < ftofix(-VG_CHARACTER_MAX_WALK_SPEED) || cp->sprite.vx > ftofix(VG_CHARACTER_MAX_WALK_SPEED)))
	{
		cp->sprite.frame += 2;
	}
	else
	{
		cp->sprite.frame++;
	}
}
