let ACTION_STRAIGHT = 0;
let ACTION_LEFT_TO = 1;
let ACTION_RIGHT_TO = 2;
let ACTION_LEFT = 3;
let ACTION_RIGHT = 4;
let ACTION_LEFT_FROM = 5;
let ACTION_RIGHT_FROM = 6;

let objPlayer = GetPlayerObjectID();
let objSlowShot = ID_INVALID;
let objPlayerAction = ACTION_STRAIGHT;
let objPlayerActionLast = ACTION_STRAIGHT;
let objPlayerActionChanged = false;
let objPlayerTurn = 0;
let objSpell;
let CSD = GetCurrentScriptDirectory();

let Animations = [];
let AnimSpeed = [];

let turnDuration = 16;
let shotPath = "";
let texturePath = CSD ~ "Textures/Player.png";
let hitboxRadius = 1;
let hitboxX = 0;
let hitboxY = 0;
let grazeRadius = 24;
let restockSpells = true;
let spellStock = 3;
let invincibleTime = 180;
let invincibleFlash = true; //Not ready

let EV_SHOT_DELETE = EV_USER + 291;


@Initialize
{
	LoadPlayerShotData(shotPath);

	ObjPlayer_AddIntersectionCircleA1(objPlayer, hitboxX, hitboxY, hitboxRadius, grazeRadius);

	SetObjectSprite(objPlayer, texturePath);

	Init();
	Animate(objPlayer);
	ControlPlayer();
}

@MainLoop
{
	yield;
}

@Finalize
{
}

@Event
{
	alternative(GetEventType())
	case(EV_REQUEST_SPELL)
	{
		let spell = GetPlayerSpell();
		if (spell > 0)
		{
			SetScriptResult(true);
			SetPlayerSpell(spell-1);
			Spell();
		}
		else
		{
			SetScriptResult(false);
		}
	}
	case(EV_HIT)
	{
		Death();
	}
	case(EV_PLAYER_REBIRTH)
	{
		if (restockSpells)
		{
			SetPlayerSpell(spellStock);
		}
		SetPlayerInvincibilityFrame(invincibleTime);
		if (invincibleFlash)
		{
			//InvincibleEffect();
		}
	}
	case(EV_GET_ITEM)
	{
		let itemType = GetEventArgument(0);
		alternative(itemType)
		case(ITEM_SPELL)
		{
			//WriteLog("ITEM_SPELL");
		}
		case(ITEM_SPELL_S)
		{
			//WriteLog("ITEM_SPELL_S");
		}
		case(ITEM_POWER)
		{
			//WriteLog("ITEM_POWER");
		}
		case(ITEM_POWER_S)
		{
			//WriteLog("ITEM_POWER_S");
		}
	}
	case(EV_GRAZE)
	{
		Graze();
	}
	others
	{
		OnEvent();
	}
}


//=========================================================================================================================================
//                                                                                                                   SETTINGS
//=========================================================================================================================================
function SetShotData(path)
{
	shotPath = path;
}
function SetPlayerTexture(path)
{
	texturePath = path;
}
function GetPlayerTexture()
{
	return texturePath;
}
function SetHitboxRadius(v)
{
	hitboxRadius = v;
}
function SetHitboxPosition(x, y)
{
	hitboxX = x;
	hitboxY = y;
}
function SetGrazeRadius(v)
{
	grazeRadius = v;
}
function SetTurnDuration(value)
{
	turnDuration = value;
}
function SetSpellRestock(v)
{
	restockSpells = v;
}
function SetSpellCount(v)
{
	spellStock = v;
}
function SetInvincibleTime(v)
{
	invincibleTime = v;
}
function SetInvincibleFlash(v)
{
	invincibleFlash = v;
}


//=========================================================================================================================================
//                                                                                                                   CONTROl
//=========================================================================================================================================
task ControlPlayer()
{
	let frame = 0;
	objPlayerTurn = 0;

	loop
	{
		objPlayerActionLast = objPlayerAction;
		objPlayerActionChanged = false;
		let turning = 0;

		if (GetVirtualKeyState(VK_LEFT) == KEY_PUSH || GetVirtualKeyState(VK_LEFT) == KEY_HOLD)
		{
			turning -= 1;
			if (objPlayerTurn > -turnDuration)
			{
				objPlayerTurn -= 1;
			}
			else
			{
				objPlayerTurn = -turnDuration;
			}
		}
		if (GetVirtualKeyState(VK_RIGHT) == KEY_PUSH || GetVirtualKeyState(VK_RIGHT) == KEY_HOLD)
		{
			turning += 1;
			if (objPlayerTurn < turnDuration)
			{
				objPlayerTurn += 1;
			}
			else
			{
				objPlayerTurn = turnDuration;
			}
		}
		if (turning == 0)
		{
			if (objPlayerTurn > 0)
			{
				objPlayerTurn -= 1;
			}
			if (objPlayerTurn < 0)
			{
				objPlayerTurn += 1;
			}
		}

		if (objPlayerTurn < 0)
		{
			if (objPlayerTurn > -turnDuration)
			{
				if (turning == -1)
				{
					objPlayerAction = ACTION_LEFT_TO;
				}
			}
			else
			{
				objPlayerAction = ACTION_LEFT;
			}
			if (turning != -1)
			{
				objPlayerAction = ACTION_LEFT_FROM;
			}
		}
		else if (objPlayerTurn > 0)
		{
			if (objPlayerTurn < turnDuration)
			{
				if (turning == 1)
				{
					objPlayerAction = ACTION_RIGHT_TO;
				}
			}
			else
			{
				objPlayerAction = ACTION_RIGHT;
			}
			if (turning != 1)
			{
				objPlayerAction = ACTION_RIGHT_FROM;
			}
		}
		else
		{
			objPlayerAction = ACTION_STRAIGHT;
		}

		if (objPlayerAction != objPlayerActionLast)
		{
			objPlayerActionChanged = true;
		}
		else
		{
			objPlayerActionChanged = false;
		}

		yield;
	}
}
function GetAction()
{
	return objPlayerAction;
}
function GetActionChanged()
{
	return objPlayerActionChanged;
}
function GetTurn()
{
	return objPlayerTurn / turnDuration;
}
function GetTurnAbs()
{
	return (|objPlayerTurn|) / turnDuration;
}
function GetTurnFrame()
{
	return floor(GetTurnAbs() * (GetAnimationSize(GetPlayerAnimation()) - 1));
}
function SetPlayerAnimation(animation)
{
	SetAnimation(objPlayer, animation);
}
function GetPlayerAnimation()
{
	return GetAnimation(objPlayer);
}
function GetPlayerAnimationSize()
{
	return GetAnimationSize(GetPlayerAnimation());
}
function SetPlayerFrame(frame)
{
	SetFrame(objPlayer, floor(frame));
}
function GetShooting()
{
	if (GetVirtualKeyState(VK_SHOT) == KEY_PUSH || GetVirtualKeyState(VK_SHOT) == KEY_HOLD)
	{
		return true;
	}
	else
	{
		return false;
	}
}
function GetFocusing()
{
	if (GetVirtualKeyState(VK_SLOWMOVE) == KEY_PUSH || GetVirtualKeyState(VK_SLOWMOVE) == KEY_HOLD)
	{
		return true;
	}
	else
	{
		return false;
	}
}
function GetAlive()
{
	let state = GetPlayerState();
	if (state != STATE_DOWN && state != STATE_END)
	{
		return true;
	}
	else
	{
		return false;
	}
}
function EndSpell()
{
	Obj_Delete(GetSpellManageObject());
}
function GetSpellActive()
{
	return !Obj_IsDeleted(GetSpellManageObject());
}


//=========================================================================================================================================
//                                                                                                                   SHOT AND BOMB
//=========================================================================================================================================
function CreatePlayerShot(x, y, speed, angle, damage, penetration, graphic)
{
	task ShotTracker(obj)
	{
		let ex = false;
		let x = ObjMove_GetX(obj);
		let y = ObjMove_GetY(obj);
		let speed = ObjMove_GetSpeed(obj);
		let angle = ObjMove_GetAngle(obj);
		let id = ObjShot_GetImageID(obj);
		let xscale = ObjRender_GetScaleX(obj);
		let yscale = ObjRender_GetScaleY(obj);

		while (!ex)
		{
			if (!Obj_IsDeleted(obj))
			{
				x = ObjMove_GetX(obj);
				y = ObjMove_GetY(obj);
				speed = ObjMove_GetSpeed(obj);
				angle = ObjMove_GetAngle(obj);
			}
			else
			{
				NotifyEvent(GetOwnScriptID(), EV_SHOT_DELETE, [x + cos(angle) * speed, y + sin(angle) * speed, speed, angle, id, xscale, yscale]);
				ex = true;
			}
			yield;
		}
	}

	if (IsPermitPlayerShot())
	{
		let ret = CreatePlayerShotA1(x, y, speed, angle, damage, penetration, graphic);

		if (ObjShot_GetImageID(ret))
		{
			ShotTracker(ret);

			return ret;
		}
	}

}
function CreatePlayerShotCS(x, y, speed, angle, damage, penetration, graphic, r, g, b, xscale, yscale)
{
	if (IsPermitPlayerShot())
	{
		let ret = CreatePlayerShot(x, y, speed, angle, damage, penetration, graphic);

		if (ObjShot_GetImageID(ret))
		{
			ObjRender_SetColor(ret, r, g, b);
			ObjRender_SetScaleXYZ(ret, xscale, yscale, 1);
		}

		return ret;
	}
}
function GetShotRectangle(id)
{
	return GetShotDataInfoA1(id, TARGET_PLAYER, INFO_RECT);
}
function GetShotDelayColor(id)
{
	return GetShotDataInfoA1(id, TARGET_PLAYER, INFO_DELAY_COLOR);
}
function GetShotBlendType(id)
{
	return GetShotDataInfoA1(id, TARGET_PLAYER, INFO_BLEND);
}
function GetShotCollision(id)
{
	return GetShotDataInfoA1(id, TARGET_PLAYER, INFO_COLLISION);
}
function GetShotCollisionList(id)
{
	return GetShotDataInfoA1(id, TARGET_PLAYER, INFO_COLLISION_LIST);
}


//=========================================================================================================================================
//                                                                                                                   ANIMATION
//=========================================================================================================================================
function AddAnimation()
{
	let ret = length(Animations);
	Animations = Animations ~ [[]];
	AnimSpeed = AnimSpeed ~ [0.2];
	return ret;
}
function AddFrame(animation, left, top, right, bottom)
{
	Animations[animation] = Animations[animation] ~ [[left, top, right, bottom]];
}
function SetAnimationSpeed(animation, speed)
{
	AnimSpeed[animation] = speed;
}
function GetAnimationArray(animation)
{
	return Animations[animation];
}
function GetAnimationFrame(animation, frame)
{
	let arr = Animations[animation];
	return arr[floor(frame)];
}
function GetAnimationSize(animation)
{
	return length(Animations[animation]);
}
function GetAnimationSpeed(animation)
{
	return AnimSpeed[animation];
}
function SetFrame(obj, frame)
{
	Obj_SetValue(obj, "frame", frame);
}
function SetAnimation(obj, animation)
{
	Obj_SetValue(obj, "anim", animation);
	SetFrame(obj, 0);
}
function GetAnimation(obj)
{
	return Obj_GetValueD(obj, "anim", -1);
}
task Animate(obj)
{
	let frame = 0;
	let animation = -1;

	loop
	{
		animation = Obj_GetValueD(obj, "anim", -1);
		frame = Obj_GetValueD(obj, "frame", 0);

		if (animation != -1)
		{
			if (GetAnimationSize(animation) != 0)
			{
				let arr = GetAnimationFrame(animation, frame);
				ObjSprite2D_SetSourceRect(obj, arr[0], arr[1], arr[2], arr[3]);
				ObjSprite2D_SetDestCenter(obj);
			}

			frame += GetAnimationSpeed(animation);

			while (frame >= GetAnimationSize(animation))
			{
				frame -= GetAnimationSize(animation);
			}
			while (frame < 0)
			{
				frame += GetAnimationSize(animation);
			}
		}

		Obj_SetValue(obj, "frame", frame);
		yield;
	}
}


//=========================================================================================================================================
//                                                                                                                   BUILT IN EFFECTS
//=========================================================================================================================================
/*task InvincibleEffect()
{
	let frame = 0;
	let flash = false;

	loop (GetPlayerInvincibilityFrame() / 8)
	{
		if (frame % 8 == 0)
		{
			flash = !flash;

			if (flash)
			{
				ObjRender_SetBlendType
			}
		}

		frame++;

		yield;
	}
}*/


//=========================================================================================================================================
//                                                                                                                   EASY STUFF
//=========================================================================================================================================
function wait(time) {
	loop (time) {
		yield;
	}
}
function CreateObject() {
	return ObjPrim_Create(OBJ_SPRITE_2D);
}
function CreateSprite(x, y, path, angle, alpha, r, g, b, xscale, yscale, priorityI, blendtype)
{
	let ret = CreateObject();

	SetObjectSprite(ret, path);
	ObjRender_SetPosition(ret, x, y, 0);
	ObjRender_SetAngleZ(ret, angle);
	ObjRender_SetAlpha(ret, alpha);
	ObjRender_SetColor(ret, r, g, b);
	ObjRender_SetScaleXYZ(ret, xscale, yscale, 1);
	Obj_SetRenderPriorityI(ret, priorityI);
	ObjRender_SetBlendType(ret, blendtype);

	return ret;
}
task RotateObject(obj, amount, time)
{
	while (Obj_GetValueD(obj, "rotating", false))
	{
		yield;
	}

	let angle = ObjRender_GetAngleZ(obj);

	Obj_SetValue(obj, "rotating", true);

	loop (time)
	{
		angle += amount / time;
		ObjRender_SetAngleZ(obj, angle);

		yield;
	}

	Obj_SetValue(obj, "rotating", false);
}
task ScaleObject(obj, scale, time)
{
	while (Obj_GetValueD(obj, "scaling", false))
	{
		yield;
	}

	let xscale = ObjRender_GetScaleX(obj);
	let yscale = ObjRender_GetScaleY(obj);
	let xsc = (scale - xscale) / time;
	let ysc = (scale - yscale) / time;

	Obj_SetValue(obj, "scaling", true);

	loop (time)
	{
		xscale += xsc;
		yscale += ysc;
		ObjRender_SetScaleX(obj, xscale);
		ObjRender_SetScaleY(obj, yscale);

		yield;
	}

	Obj_SetValue(obj, "scaling", false);
}
task FadeObject(obj, startalpha, endalpha, time)
{
	while (Obj_GetValueD(obj, "fading", false))
	{
		yield;
	}

	let alpha = startalpha;
	let range = endalpha - startalpha;

	Obj_SetValue(obj, "fading", true);

	loop (time)
	{
		alpha += range / time;
		ObjRender_SetAlpha(obj, alpha);

		yield;
	}

	Obj_SetValue(obj, "fading", false);
	ObjRender_SetAlpha(obj, endalpha);
}
task FadeObjectToDelete(obj, startalpha, time)
{
	while (Obj_GetValueD(obj, "fading", false))
	{
		yield;
	}

	let alpha = startalpha;
	let range = -startalpha;

	Obj_SetValue(obj, "fading", true);

	loop (time)
	{
		alpha += range / time;
		ObjRender_SetAlpha(obj, alpha);

		yield;
	}

	Obj_Delete(obj);
}
task PauseFade(obj, time)
{
	while (Obj_GetValueD(obj, "fading", false))
	{
		yield;
	}

	Obj_SetValue(obj, "fading", true);

	wait(time);

	Obj_SetValue(obj, "fading", false);
}
task MoveObject(obj, x, y, time)
{
	while (Obj_GetValueD(obj, "moving", false))
	{
		yield;
	}

	Obj_SetValue(obj, "moving", true);

	let objx = ObjRender_GetX(obj);
	let objy = ObjRender_GetY(obj);
	let xc = (x - objx) / time;
	let yc = (y - objy) / time;

	loop (time)
	{
		objx += xc;
		objy += yc;

		ObjRender_SetX(obj, objx);
		ObjRender_SetY(obj, objy);

		yield;
	}

	ObjRender_SetX(obj, x);
	ObjRender_SetY(obj, y);

	Obj_SetValue(obj, "moving", false);
}
task AttachObject(obj, parent, x, y)
{
	while (Obj_GetValueD(obj, "moving", false))
	{
		yield;
	}

	Obj_SetValue(obj, "moving", true);

	while (!Obj_IsDeleted(obj) && !Obj_IsDeleted(parent))
	{
		ObjRender_SetPosition(obj, x + ObjRender_GetX(parent), y +ObjRender_GetY(parent), 0);

		yield;
	}
}
function SetObjectSprite(obj,sprite) {
	Obj_SetValue(obj,"Sprite",sprite);
	let spritepath = sprite;
	ObjPrim_SetTexture(obj, spritepath);
	let width = GetTextureWidth(spritepath);
	let height = GetTextureHeight(spritepath);
	ObjSprite2D_SetSourceRect(obj,0,0,width,height);
	ObjSprite2D_SetDestRect(obj,-width / 2,-height / 2,width / 2,height / 2);
	Obj_SetValue(obj,"Dest",[-width / 2,-height / 2,width / 2,height / 2]);
	Obj_SetValue(obj,"Offset",[0,0]);

	return obj;
}
function GetObjectSprite(obj) {
	return Obj_GetValueD(obj,"Sprite","");
}
function SetObjectSource(obj,left,top,right,bottom) {
	ObjSprite2D_SetSourceRect(obj,left,top,right,bottom);

	return obj;
}
function SetObjectSpriteOffset(obj,offx,offy) {
	let dest = Obj_GetValueD(obj,"Dest",[0,0,0,0]);

	Obj_SetValue(obj,"Offset",[offx,offy]);
	ObjSprite2D_SetSourceRect(obj,dest[0] + offx,dest[1] + offy,dest[2] + offx,dest[3] + offy);

	return obj;
}
function GetObjectSpriteOffset(obj,offx,offy) {
	return Obj_GetValueD(obj,"Offset",[0,0]);
}
function SetObjectAlpha(obj,alpha) {
	ObjRender_SetAlpha(obj,alpha);
	Obj_SetValue(obj,"Alpha",alpha);

	return obj;
}
function GetObjectAlpha(obj) {
	return Obj_GetValueD(obj,"Alpha",255);
}
function SetObjectScale(obj,xscale,yscale) {
	ObjRender_SetScaleXYZ(obj,xscale,yscale,1);

	return obj;
}
function SetObjectScaleX(obj,xscale) {
	ObjRender_SetScaleX(obj,xscale);

	return obj;
}
function SetObjectScaleY(obj,yscale) {
	ObjRender_SetScaleY(obj,yscale);

	return obj;
}
function GetObjectScale(obj) {
	return [ObjRender_GetScaleX(obj),ObjRender_GetScaleY(obj)];
}
function GetObjectScaleX(obj) {
	return ObjRender_GetScaleX(obj);
}
function GetObjectScaleY(obj) {
	return ObjRender_GetScaleY(obj);
}
function SetObjectValue(obj,key,value) {
	Obj_SetValue(obj,key,value);

	return obj;
}
function GetObjectValue(obj,key) {
	return Obj_GetValue(obj,key);
}
function GetObjectValueD(obj,key,default) {
	return Obj_GetValueD(obj,key,default);
}
function DeleteObject(obj) {
	return Obj_Delete(obj);
}
function CreateSound(path, volume)
{
	let ret = ObjSound_Create();

	ObjSound_Load(ret, path);
	ObjSound_SetVolumeRate(ret, volume);

	return ret;
}
function PlaySound(sound)
{
	ObjSound_Play(sound);
}