function ShotDieAnim(x, y, v, a, g, d){
	let obj = ObjShot_Create(OBJ_SHOT);
	ObjShot_Regist(obj);
	ObjMove_SetPosition(obj, x, y);
	ObjMove_SetSpeed(obj, v);
	ObjMove_SetAngle(obj, a);
	ObjShot_SetGraphic(obj, g);
	ObjShot_SetDamage(obj, d);
	ObjShot_SetPenetration(obj, 1);

	let obj_Anim = ObjPrim_Create(OBJ_SPRITE_2D);
	ObjPrim_SetTexture(obj_Anim, GetCurrentScriptDirectory ~ "Image/Shot.png");
	Obj_SetRenderPriorityI(obj_Anim, 60);
	AnimateOnRemoval;
	return obj;

	task AnimateOnRemoval{
		let pos = [0, 0];
		let rect = GetShotDataInfoA1(g, TARGET_PLAYER, INFO_RECT);
		let shit = [rect[2] - rect[0], rect[3] - rect[1]];
		let z = a;

		while(!Obj_IsDeleted(obj)){
			pos = [ObjRender_GetX(obj), ObjRender_GetY(obj)];
			yield;
		}
		ObjRender_SetPosition(obj_Anim, pos[0], pos[1], 0);
		ObjRender_SetBlendType(obj_Anim, BLEND_ADD_ARGB);
		ObjSprite2D_SetSourceRect(obj_Anim, rect[0], rect[1], rect[2], rect[3]);
		ObjSprite2D_SetDestRect(obj_Anim, -shit[0]/2, -shit[1]/2, shit[0]/2, shit[1]/2);
		ObjRender_SetAngleZ(obj_Anim, z + 90 + rand(-8, 8));

		ascent(i in 0 .. 8){
			ObjSprite2D_SetSourceRect(obj_Anim, rect[0], rect[1] + 48 + trunc(i/2)*16, rect[2], rect[3] + 16 + trunc(i/2)*16);
			ObjSprite2D_SetDestCenter(obj_Anim);

			ObjRender_SetScaleXYZ(obj_Anim, 1 + i*0.15, 1 + i*0.15, 0);
			loop(3){yield;}
		}
		Obj_Delete(obj_Anim);
	}
}

function ShotNeedle(x, y, v, a, g, d){
	let obj = ObjShot_Create(OBJ_SHOT);
	ObjShot_Regist(obj);
	ObjMove_SetPosition(obj, x, y);
	ObjMove_SetSpeed(obj, v);
	ObjMove_SetAngle(obj, a);
	ObjShot_SetGraphic(obj, g);
	ObjShot_SetDamage(obj, d);
	ObjShot_SetPenetration(obj, 1);

	let obj_Anim = ObjPrim_Create(OBJ_SPRITE_2D);
	ObjPrim_SetTexture(obj_Anim, GetCurrentScriptDirectory ~ "Image/Shot.png");
	Obj_SetRenderPriorityI(obj_Anim, 60);
	AnimateOnRemoval;
	return obj;

	task AnimateOnRemoval{
		let pos = [0, 0];
		let rect = GetShotDataInfoA1(g, TARGET_PLAYER, INFO_RECT);
		let shit = [rect[2] - rect[0], rect[3] - rect[1]];
		let z = a;

		while(!Obj_IsDeleted(obj)){
			pos = [ObjRender_GetX(obj), ObjRender_GetY(obj)];
			yield;
		}
		ObjRender_SetPosition(obj_Anim, pos[0], pos[1], 0);
		ObjRender_SetBlendType(obj_Anim, BLEND_ADD_ARGB);
		ObjSprite2D_SetSourceRect(obj_Anim, rect[0], rect[1], rect[2], rect[3]);
		ObjSprite2D_SetDestRect(obj_Anim, -shit[0]/2, -shit[1]/2, shit[0]/2, shit[1]/2);
		ObjRender_SetAngleZ(obj_Anim, z + 90 + rand(-8, 8));

		let scaleX = 1;
		let scaleY = 1;
		loop(10){
			ObjRender_SetScaleX(obj_Anim, scaleX);
			ObjRender_SetScaleY(obj_Anim, scaleY);
			scaleX -= 1/10;
			scaleY += 1/10;
			loop(2){yield;}
		}
		Obj_Delete(obj_Anim);
	}
}

function ShotSotoba(x, y, v, a, g, d){
	let obj = ObjShot_Create(OBJ_SHOT);
	ObjShot_Regist(obj);
	ObjMove_SetPosition(obj, x, y);
	ObjMove_SetSpeed(obj, v);
	ObjMove_SetAngle(obj, a);
	ObjShot_SetGraphic(obj, g);
	ObjShot_SetDamage(obj, d);
	ObjShot_SetPenetration(obj, 1);

	let obj_Anim = ObjPrim_Create(OBJ_SPRITE_2D);
	ObjPrim_SetTexture(obj_Anim, GetCurrentScriptDirectory ~ "Image/Shot.png");
	Obj_SetRenderPriorityI(obj_Anim, 60);
	AnimateOnRemoval;
	return obj;

	task AnimateOnRemoval{
		let pos = [0, 0];
		let rect = GetShotDataInfoA1(g, TARGET_PLAYER, INFO_RECT);
		let shit = [rect[2] - rect[0], rect[3] - rect[1]];
		let z = a;

		while(!Obj_IsDeleted(obj)){
			pos = [ObjRender_GetX(obj), ObjRender_GetY(obj)];
			z = ObjMove_GetAngle(obj);
			yield;
		}
		ObjRender_SetPosition(obj_Anim, pos[0], pos[1], 0);
		ObjRender_SetBlendType(obj_Anim, BLEND_ADD_ARGB);
		ObjSprite2D_SetSourceRect(obj_Anim, rect[0] + 16, rect[1], rect[2] + 16, rect[3]);
		ObjSprite2D_SetDestRect(obj_Anim, -shit[0]/2, -shit[1]/2, shit[0]/2, shit[1]/2);
		ObjRender_SetAngleZ(obj_Anim, z + 90 + rand(-8, 8));

		let scaleX = 1;
		z = z + 90 + rand(-8, 8);
		loop(10){
			ObjRender_SetAngleZ(obj_Anim, z);
			ObjRender_SetScaleX(obj_Anim, scaleX);
			z += 30/10;
			scaleX -= 1/10;
			loop(2){yield;}
		}
		Obj_Delete(obj_Anim);
	}
}

function Laser(parent, a, d, swing_angle, swing_speed){
	let obj = ObjShot_Create(OBJ_STRAIGHT_LASER);
	ObjShot_Regist(obj);
	ObjMove_SetPosition(obj, ObjRender_GetX(parent), ObjRender_GetY(parent));
	ObjMove_SetAngle(obj, a);
	ObjShot_SetGraphic(obj, 0);
	ObjShot_SetAutoDelete(obj, false);

	let obj_Anim = ObjPrim_Create(OBJ_SPRITE_2D);
	ObjPrim_SetTexture(obj_Anim, GetCurrentScriptDirectory ~ "Image/Shot.png");
	Obj_SetRenderPriorityI(obj_Anim, 40);
	ObjRender_SetAngleZ(obj_Anim, a);
	ObjRender_SetScaleY(obj_Anim, 0);
	ObjRender_SetAlpha(obj_Anim, 96);
	ObjRender_SetBlendType(obj_Anim, BLEND_ADD_ARGB);

	let obj_Anim_base = ObjPrim_Create(OBJ_SPRITE_2D);
	ObjPrim_SetTexture(obj_Anim_base, GetCurrentScriptDirectory ~ "Image/Shot.png");
	ObjSprite2D_SetSourceRect(obj_Anim_base, 224, 208, 256, 240);
	ObjSprite2D_SetDestCenter(obj_Anim_base);
	Obj_SetRenderPriorityI(obj_Anim_base, 40);
	ObjRender_SetAngleZ(obj_Anim_base, a);
	ObjRender_SetScaleXYZ(obj_Anim_base, 0, 0, 0);
	ObjRender_SetAlpha(obj_Anim_base, 96);
	ObjRender_SetBlendType(obj_Anim_base, BLEND_ADD_ARGB);
	HandleLaser;
	return obj;

	task HandleLaser{
		let pos = [0, 0];
		let endPos = [-1000, -1000];
		let c = 0;

		let laserLength = 0;
		let angle = a;
		while(!Obj_IsDeleted(obj)){
			if(Obj_IsDeleted(parent)){Obj_Delete(obj);}

			if(c < 10){
				ObjRender_SetScaleY(obj_Anim, deceleration(0, 1, c/10));
				ObjRender_SetScaleXYZ(obj_Anim_base, deceleration(0, 1, c/10), deceleration(0, 1, c/10), 0);
			}

			laserLength = GetDist(endPos[0], endPos[1], ObjRender_GetX(parent), ObjRender_GetY(parent));
			HitboxBullet;

			ObjMove_SetPosition(obj, ObjRender_GetX(parent), ObjRender_GetY(parent));
			ObjRender_SetPosition(obj_Anim, ObjMove_GetX(obj), ObjMove_GetY(obj), 0);
			ObjSprite2D_SetSourceRect(obj_Anim, 0 - c*10, 240, laserLength - c*10, 256);
			ObjSprite2D_SetDestRect(obj_Anim, 0, -8, laserLength, 8);
			ObjRender_SetAngleZ(obj_Anim, angle);

			ObjRender_SetPosition(obj_Anim_base, ObjMove_GetX(obj), ObjMove_GetY(obj), 0);
			ObjRender_SetAngleZ(obj_Anim_base, c*3);

			angle = swing_angle*sin(c * swing_speed) + a;
			c++;
			yield;
		}

		c = 0;
		loop(5){
			ObjRender_SetScaleY(obj_Anim, deceleration(1, 0, c/5));
			ObjRender_SetScaleXYZ(obj_Anim_base, deceleration(1, 0, c/5), deceleration(1, 0, c/5), 0);
			c++;
			yield;
		}
		Obj_Delete(obj_Anim);
		Obj_Delete(obj_Anim_base);

		task HitboxBullet{
			let shot = CreateShotA1(ObjRender_GetX(parent), ObjRender_GetY(parent), 0, angle, 1, 0);
			ObjShot_SetDamage(shot, d/2);
			ObjShot_SetPenetration(shot, 2);
			ObjShot_SetAutoDelete(shot, false);
			ObjShot_SetDeleteFrame(shot, 180);
			Obj_SetVisible(shot, false);

			let shot_Anim = ObjPrim_Create(OBJ_SPRITE_2D);
			ObjPrim_SetTexture(shot_Anim, GetCurrentScriptDirectory ~ "Image/Shot.png");
			ObjSprite2D_SetSourceRect(shot_Anim, 224, 208, 256, 240);
			ObjSprite2D_SetDestCenter(shot_Anim);
			ObjRender_SetBlendType(shot_Anim, BLEND_ADD_ARGB);
			ObjRender_SetAngleZ(shot_Anim, angle + 90);
			ObjRender_SetAlpha(shot_Anim, 255);
			Obj_SetVisible(shot_Anim, false);
			Obj_SetRenderPriorityI(shot_Anim, 60);

			let dis = 0;
			while(!Obj_IsDeleted(shot)){
				if(Obj_IsDeleted(obj)){Obj_Delete(shot); Obj_Delete(shot_Anim); return;}

				if(ObjShot_GetPenetration(shot) < 2){
					endPos = [ObjMove_GetX(shot), ObjMove_GetY(shot)];
				}
				if(!Obj_IsInArea(shot, -16, -16, GetStgFrameWidth + 16, GetStgFrameHeight + 48)){
					Obj_Delete(shot_Anim);
					endPos = [ObjMove_GetX(shot), ObjMove_GetY(shot)];
					Obj_Delete(shot);
					return;
				}

				ObjMove_SetPosition(shot, ObjRender_GetX(parent) + dis*cos(angle), ObjRender_GetY(parent) + dis*sin(angle));
				dis += 20;
				yield;
			}

			ObjRender_SetPosition(shot_Anim, endPos[0], endPos[1], 0);
			Obj_SetVisible(shot_Anim, true);

			ascent(i in 0 .. 11){
				ObjRender_SetScaleXYZ(shot_Anim, linear(1, 0, i/10), linear(1, 3, i/10), 0);
				ObjRender_SetPosition(shot_Anim, endPos[0] + linear(0, 64, i/10)*cos(angle + rand(-5, 5)), endPos[1] + linear(0, 64, i/10)*sin(angle + rand(-5, 5)), 0);
				yield;
			}
			Obj_Delete(shot_Anim);
		}
	}
}

task Slash(x, y, a, al, size, damage, clearbullet, t_wait, reverse){
	let obj = ObjShot_Create(OBJ_SHOT);
	ObjShot_Regist(obj);
	ObjMove_SetPosition(obj, x, y);
	ObjShot_SetDamage(obj, damage);
	ObjShot_SetEraseShot(obj, clearbullet);
	ObjShot_SetIntersectionLine(obj, x - (128*size)*cos(a), y -(128*size)*sin(a), x + (128*size)*cos(a), y + (128*size)*sin(a), 40*size);
	Render;

	loop(8*t_wait){
		ObjShot_SetIntersectionLine(obj, x - (128*size)*cos(a), y -(128*size)*sin(a), x + (128*size)*cos(a), y + (128*size)*sin(a), 40*size);
		yield;
	}
	Obj_Delete(obj);

	task Render{
		let objRender = ObjPrim_Create(OBJ_SPRITE_2D);
		Obj_SetRenderPriorityI(objRender, 40);
		ObjPrim_SetTexture(objRender, GetCurrentScriptDirectory ~ "Image/claw.png");
		ObjSprite2D_SetSourceRect(objRender, 0, 0, 128, 256);
		ObjSprite2D_SetDestCenter(objRender);
		ObjRender_SetPosition(objRender, x, y, 0);
		ObjRender_SetAngleZ(objRender, a - 90);
		ObjRender_SetScaleXYZ(objRender, size, size, 0);
		ObjRender_SetAlpha(objRender, al);

		if(reverse){ObjRender_SetAngleX(objRender, 180);}

		ascent(i in 0 .. 2){
			ascent(j in 0 .. 4){
				ObjSprite2D_SetSourceRect(objRender, j*128, i*256, (j+1)*128, (i+1)*256);
				ObjSprite2D_SetDestCenter(objRender);
				loop(t_wait){yield;}
			}
		}
		Obj_Delete(objRender);
	}
}

task SpellYukari(isTagTriggered){
	SetPlayerInvincibilityFrame(360);
	PlaySoundA1(4, 70, 0);

	let manage = GetSpellManageObject;
	CanShoot = false;

	if(!isTagTriggered){
		TagStandby;
	}

	ScreenShakeA1(120, 5);
	DarkenTintScreen(GetPlayerX, GetPlayerY, 32, [0, 64, 0], 240);

	PlaySoundA1(11, 70, 0);
	PlaySoundA1(12, 70, 0);
	let startPoint = [-64, GetStgFrameHeight/6];
	let an = 15;
	ascent(i in 0 .. 4){
		Train(startPoint[0] - i*(792*0.75)*cos(an), startPoint[1] - i*(792*0.75)*sin(an), 10, an, 120, 43 - i);
	}


	loop(300){yield;}
	CanShoot = true;
	Obj_Delete(manage);
	loop(90){yield;}

	
	task Train(x, y, v, a, t, pri){
		let pointAngle = a;
		let obj = ObjShot_Create(OBJ_SHOT);
		ObjShot_Regist(obj);
		ObjShot_SetDamage(obj, damage*5);
		ObjShot_SetPenetration(obj, 100);
		ObjShot_SetSpellFactor(obj, !isTagTriggered);
		ObjShot_SetEraseShot(obj, true);
		ObjShot_SetAutoDelete(obj, false);

		ObjMove_SetPosition(obj, x, y);
		ObjMove_SetSpeed(obj, v);
		ObjMove_SetAngle(obj, a);

		let objRender = ObjPrim_Create(OBJ_SPRITE_2D);
		Obj_SetRenderPriorityI(objRender, pri);
		ObjPrim_SetTexture(objRender, GetCurrentScriptDirectory ~ "Image/train.png");
		ObjSprite2D_SetSourceRect(objRender, 0, 0, 836, 282);
		ObjSprite2D_SetDestRect(objRender, -792, -141, 44, 141);
		//ObjRender_SetBlendType(objRender, BLEND_ADD_ARGB);
		ObjRender_SetScaleXYZ(objRender, 0.75, 0.75, 0);
		ObjRender_SetAngleZ(objRender, pointAngle);

		AndItExploded;
		Animate;
		Hitbox;

		task AndItExploded{
			loop(t){yield;}
			PlaySoundA1(14, 70, 0);
			ObjMove_SetSpeed(obj, 0);

			ObjPrim_SetTexture(objRender, GetCurrentScriptDirectory ~ "Image/train_ded.png");
			ObjSprite2D_SetSourceRect(objRender, 0, 0, 836, 282);
			ObjSprite2D_SetDestRect(objRender, -792, -141, 44, 141);
			
			ObjMove_AddPatternB2(obj, 0, 0, -3, -0.05, 0.05, -2, 4);
			ObjShot_SetDeleteFrame(obj, 450);

			while(!Obj_IsDeleted(obj)){
				ObjRender_SetAngleZ(objRender, pointAngle);
				pointAngle -= 0.25;
				yield;
			}
		}

		task Animate{
			while(!Obj_IsDeleted(obj)){
				ObjRender_SetPosition(objRender, ObjMove_GetX(obj), ObjMove_GetY(obj), 0);
				

				yield;
			}
			Obj_Delete(objRender);
		}

		task Hitbox{
			while(!Obj_IsDeleted(obj)){
				ObjShot_SetIntersectionLine(obj, ObjMove_GetX(obj), ObjMove_GetY(obj), ObjMove_GetX(obj) - 792*0.75*cos(pointAngle), ObjMove_GetY(obj) - 792*0.75*sin(pointAngle), 100);
				ObjShot_SetPenetration(obj, 100);

				yield;
			}
		}
	}

	task TagStandby{
		loop(15){yield;}
		while(!Obj_IsDeleted(manage)){
			if(GetVirtualKeyState(VK_TAG) == KEY_PUSH && CanSwap && GetPlayerSpell > 0){
				PlaySoundA1(16, 70, 0);
				
				if(enableRidiculousTag){ //Allows chaining spells infinitely. Will be disabled in the release version
					SpellReimu(false);
				}else{
					SetPlayerSpell(GetPlayerSpell-1);
					SpellReimu(true);
				}
				return;
			}
			yield;
		}
	}
}

task SpellReimu(isTagTriggered){
	SetPlayerInvincibilityFrame(390);
	PlaySoundA1(4, 70, 0);

	let manage = GetSpellManageObject;
	CanShoot = false;

	if(!isTagTriggered){
		TagStandby;
	}

	DarkenTintScreen(GetPlayerX, GetPlayerY, 40, [0, 32, 32], 300);

	let dir = 0;
	loop(3){
		SpellShot(GetPlayerX, GetPlayerY, 4, dir, [255, 0, 0]);
		SpellShot(GetPlayerX, GetPlayerY, 4, dir + (360/9), [0, 255, 0]);
		SpellShot(GetPlayerX, GetPlayerY, 4, dir + 2*(360/9), [0, 0, 255]);

		dir += 360/3;
	}

	loop(300){yield;}
	CanShoot = true;
	Obj_Delete(manage);
	loop(90){yield;}

	
	task SpellShot(x, y, v, a, color){
		//let v = rand(3, 6);
		//let a = rand(0, 360);

		let obj = ObjShot_Create(OBJ_SHOT);
		ObjShot_Regist(obj);
		ObjShot_SetIntersectionCircleA1(obj, 80);
		ObjShot_SetDamage(obj, damage*1);
		ObjShot_SetPenetration(obj, 10000000000);
		ObjShot_SetSpellFactor(obj, !isTagTriggered);
		ObjShot_SetAutoDelete(obj, false);
		ObjShot_SetEraseShot(obj, true);

		ObjMove_SetPosition(obj, x, y);
		ObjMove_SetSpeed(obj, v);
		ObjMove_SetAngle(obj, a);
		ObjMove_SetAngularVelocity(obj, 2);

		let objRender = ObjPrim_Create(OBJ_SPRITE_2D);
		ObjPrim_SetTexture(objRender, GetCurrentScriptDirectory ~ "Image/ball.png");
		ObjSprite2D_SetSourceRect(objRender, 0, 0, 128, 128);
		ObjSprite2D_SetDestCenter(objRender);
		ObjRender_SetBlendType(objRender, BLEND_ADD_ARGB);
		ObjRender_SetScaleXYZ(objRender, 1.25, 1.25, 0);

		let objRender2 = ObjPrim_Create(OBJ_SPRITE_2D);
		ObjPrim_SetTexture(objRender2, GetCurrentScriptDirectory ~ "Image/ball.png");
		ObjSprite2D_SetSourceRect(objRender2, 0, 0, 128, 128);
		ObjSprite2D_SetDestCenter(objRender2);
		ObjRender_SetBlendType(objRender2, BLEND_ADD_ARGB);
		ObjRender_SetColor(objRender, color[0], color[1], color[2]);
		ObjRender_SetScaleXYZ(objRender2, 1.25, 1.25, 0);

		let c = 0;
		let av = v;
		let av_temp;
		loop(120){
			ObjShot_SetPenetration(obj, 10000000000);
			ObjShot_SetIntersectionCircleA1(obj, 80);

			ObjRender_SetPosition(objRender, ObjMove_GetX(obj), ObjMove_GetY(obj), 0);
			ObjRender_SetPosition(objRender2, ObjMove_GetX(obj), ObjMove_GetY(obj), 0);

			ObjRender_SetAngleZ(objRender, c*8);
			ObjRender_SetAngleZ(objRender2, -c*8);

			c++;
			yield;
		}
		ObjMove_SetAngularVelocity(obj, 0);
		ObjMove_SetSpeed(obj, 0);

		let pos = [];
		let enem = GetEnemyDestination(obj);
		

		if(length(enem) > 0){moveDeceleration(obj, enem[0], enem[1], 60);}
		else{
			ObjMove_SetSpeed(obj, v);
			ObjMove_SetAcceleration(obj, -0.1);
			ObjMove_SetMaxSpeed(obj, 0);
		}

		ObjShot_SetDamage(obj, damage*3);
		c = 0;
		loop(120){

			ObjShot_SetPenetration(obj, 10000000000);
			ObjShot_SetIntersectionCircleA1(obj, 80);

			if(length(enem) > 0){
				if(!Obj_IsDeleted(enem[2])){
					if(c > 30){
						moveDeceleration(obj, ObjMove_GetX(enem[2]) + rand(-15, 15), ObjMove_GetY(enem[2]) + rand(-15, 15), 10);
						enem[0] = ObjMove_GetX(enem[2]);
						enem[1] = ObjMove_GetY(enem[2]);
					}
				}else{
					if(c > 30){
						moveDeceleration(obj, enem[0] + rand(-15, 15), enem[1] + rand(-15, 15), 10);
					}
				}
			}

			ObjRender_SetPosition(objRender, ObjMove_GetX(obj), ObjMove_GetY(obj), 0);
			ObjRender_SetPosition(objRender2, ObjMove_GetX(obj), ObjMove_GetY(obj), 0);

			ObjRender_SetAngleZ(objRender, c*8);
			ObjRender_SetAngleZ(objRender2, -c*8);

			c++;
			yield;
		}

		PlaySoundA1(15, 50, 0);
		loop(24){
			SplashObject(GetCurrentScriptDirectory ~ "Image/ball.png", ObjMove_GetX(obj), ObjMove_GetY(obj), rand(3, 8), rand(0, 360), color);
			SplashObject(GetCurrentScriptDirectory ~ "Image/ball.png", ObjMove_GetX(obj), ObjMove_GetY(obj), rand(3, 8), rand(0, 360), color);
			SplashObject(GetCurrentScriptDirectory ~ "Image/ball.png", ObjMove_GetX(obj), ObjMove_GetY(obj), rand(3, 8), rand(0, 360), [255, 255, 255]);
		}

		let scale = 1.25;
		loop(15){
			ObjShot_SetPenetration(obj, 10000000000);
			ObjShot_SetDamage(obj, damage*3);
			ObjShot_SetIntersectionCircleA1(obj, 160);

			ObjRender_SetScaleXYZ(objRender, scale, scale, 0);
			ObjRender_SetScaleXYZ(objRender2, scale, scale, 0);

			ObjRender_SetAngleZ(objRender, c*8);
			ObjRender_SetAngleZ(objRender2, -c*8);

			scale -= 1.25/15;
			c++;
			yield;
		}

		Obj_Delete(obj);
		Obj_Delete(objRender);
		Obj_Delete(objRender2);
	}

	task TagStandby{
		loop(15){yield;}
		while(!Obj_IsDeleted(manage)){
			if(GetVirtualKeyState(VK_TAG) == KEY_PUSH && CanSwap && GetPlayerSpell > 0){
				PlaySoundA1(16, 70, 0);
				
				if(enableRidiculousTag){ //Allows chaining spells infinitely. Will be disabled in the release version
					SpellYukari(false);
				}else{
					SetPlayerSpell(GetPlayerSpell-1);
					SpellYukari(true);
				}
				return;
			}
			yield;
		}
	}

	function GetEnemyDestination(obj){
		let enem = [];
		let dist = 100000000;
		let ar = GetIntersectionRegistedEnemyID;

		ascent(i in 0 .. length(ar)){
			if(GetDist(ObjMove_GetX(ar[i]), ObjMove_GetY(ar[i]), ObjMove_GetX(obj), ObjMove_GetY(obj)) < dist){
				dist = GetDist(ObjMove_GetX(ar[i]), ObjMove_GetY(ar[i]), ObjMove_GetX(obj), ObjMove_GetY(obj));
				enem = [ObjMove_GetX(ar[i]), ObjMove_GetY(ar[i]), ar[i]];
			}
		}

		return enem;
	}
}

task OccultYukari{
	let yukariButtCoords = [];

	CanOccult = false;
	CanSwap = false;
	IsYukariSplit = true;

	GapCut;
	RenderYukariButt;
	RenderYukariTop;

	SetPlayerSpeed(6, 3);
	ObjPlayer_ClearIntersection(GetPlayerObjectID);
	ObjPlayer_AddIntersectionCircleA1(objPlayer, 0, 0, 0.25, 15);
	loop(30){yield;}

	while(GetVirtualKeyState(VK_OCCULT) != KEY_PUSH){
		yield;
	}

	IsYukariSplit = false;
	SetPlayerSpeed(speeds[player][0], speeds[player][1]);
	ObjPlayer_ClearIntersection(GetPlayerObjectID);
	ObjPlayer_AddIntersectionCircleA1(objPlayer, 0, 0, 0.5, 30);
	loop(30){yield;}

	CanOccult = true;
	CanSwap = true;

	task GapCut{
		let gap = ObjPrim_Create(OBJ_SPRITE_2D);
		Obj_SetRenderPriorityI(gap, 50);
		ObjPrim_SetTexture(gap, GetCurrentScriptDirectory ~ "Image/gap_00.png");
		ObjSprite2D_SetSourceRect(gap, 0, 0, 64, 128);
		ObjSprite2D_SetDestCenter(gap);
		ObjRender_SetPosition(gap, GetPlayerX - 32, GetPlayerY, 0);
		ObjRender_SetScaleXYZ(gap, 0, 0, 0);
		ObjRender_SetAngleZ(gap, 90);

		ascent(i in 0 .. 10){
			ObjRender_SetPosition(gap, GetPlayerX - linear(32, 0, i/9), GetPlayerY, 0);
			ObjRender_SetScaleXYZ(gap, linear(0, 0.2, i/9), linear(0, 1, i/9), 0);
			yield;
		}
		ascent(i in 0 .. 10){
			ObjRender_SetPosition(gap, GetPlayerX + linear(32, 0, i/9), GetPlayerY, 0);
			ObjRender_SetScaleXYZ(gap, linear(0.2, 0, i/9), linear(1, 0, i/9), 0);
			yield;
		}
	}

	task RenderYukariTop{
		let gap = ObjPrim_Create(OBJ_SPRITE_2D);
		Obj_SetRenderPriorityI(gap, 31);
		ObjRender_SetBlendType(gap, BLEND_ALPHA);
		ObjPrim_SetTexture(gap, GetCurrentScriptDirectory ~ "Image/optionYukari2_00.png");
		ObjSprite2D_SetSourceRect(gap, 0, 0, 64, 16);
		ObjSprite2D_SetDestCenter(gap);
		ObjRender_SetPosition(gap, GetPlayerX, GetPlayerY, 0);

		let ribbon = ObjPrim_Create(OBJ_SPRITE_2D);
		Obj_SetRenderPriorityI(ribbon, 31);
		ObjRender_SetBlendType(ribbon, BLEND_ALPHA);
		ObjPrim_SetTexture(ribbon, GetCurrentScriptDirectory ~ "Image/optionYukari2_01.png");
		ObjSprite2D_SetSourceRect(ribbon, 0, 0, 64, 16);
		ObjSprite2D_SetDestCenter(ribbon);
		ObjRender_SetPosition(ribbon, GetPlayerX, GetPlayerY, 0);

		ObjShader_SetShaderF(GetPlayerObjectID, GetCurrentScriptDirectory ~ "HLSL_Mask.txt");
		ObjShader_SetTechnique(GetPlayerObjectID,"TecMask");

		ObjShader_SetTexture(GetPlayerObjectID, "textureMask_", GetCurrentScriptDirectory ~ "Image/yukariMask_top.png");

		ObjShader_SetFloat(GetPlayerObjectID, "iw", 32);
		ObjShader_SetFloat(GetPlayerObjectID, "ih", 144);

		ObjShader_SetFloat(GetPlayerObjectID, "iscale_x", 1);
		ObjShader_SetFloat(GetPlayerObjectID, "iscale_y", 1);

		loop(30){
			ObjRender_SetPosition(gap, GetPlayerX, GetPlayerY, 0);
			ObjRender_SetPosition(ribbon, GetPlayerX, GetPlayerY, 0);

			ObjShader_SetFloat(GetPlayerObjectID, "offset_x", -GetStgFrameLeft - GetPlayerX - 16);
			ObjShader_SetFloat(GetPlayerObjectID, "offset_y", -GetStgFrameTop - GetPlayerY - 72);
			yield;
		}
		loop{
			if(GetVirtualKeyState(VK_OCCULT) == KEY_PUSH){break;}
			ObjRender_SetPosition(gap, GetPlayerX, GetPlayerY, 0);
			ObjRender_SetPosition(ribbon, GetPlayerX, GetPlayerY, 0);

			ObjShader_SetFloat(GetPlayerObjectID, "offset_x", -GetStgFrameLeft - GetPlayerX - 16);
			ObjShader_SetFloat(GetPlayerObjectID, "offset_y", -GetStgFrameTop - GetPlayerY - 72);
			yield;
		}
		ascent(i in 0 .. 24){
			if(GetVirtualKeyState(VK_OCCULT) != KEY_FREE && GetVirtualKeyState(VK_SLOWMOVE) != KEY_FREE){
				SwapYukari;
				return;
			}
			ObjRender_SetPosition(gap, GetPlayerX, GetPlayerY + i*2, 0);
			ObjRender_SetPosition(ribbon, GetPlayerX, GetPlayerY + i*2, 0);

			ObjShader_SetFloat(GetPlayerObjectID, "offset_x", -GetStgFrameLeft - GetPlayerX - 16);
			ObjShader_SetFloat(GetPlayerObjectID, "offset_y", -GetStgFrameTop - GetPlayerY - 72 - i*2);
			yield;
		}

		ObjShader_ResetShader(GetPlayerObjectID);
		ascent(i in 0 .. 11){
			ObjRender_SetScaleY(gap, linear(1, 0, i/10));
			ObjRender_SetScaleY(ribbon, linear(1, 0, i/10));
			yield;
		}
		Obj_Delete(gap);
		Obj_Delete(ribbon);

		task SwapYukari{
			ObjMove_SetPosition(GetPlayerObjectID, yukariButtCoords[0], yukariButtCoords[1]);
			ObjShader_SetTexture(GetPlayerObjectID, "textureMask_", GetCurrentScriptDirectory ~ "Image/yukariMask_bottom.png");

			ascent(i in 0 .. 24){
				ObjRender_SetPosition(gap, yukariButtCoords[0], yukariButtCoords[1] - i*2, 0);
				ObjRender_SetPosition(ribbon, yukariButtCoords[0], yukariButtCoords[1] - i*2, 0);

				ObjShader_SetFloat(GetPlayerObjectID, "offset_x", -GetStgFrameLeft - yukariButtCoords[0] - 16);
				ObjShader_SetFloat(GetPlayerObjectID, "offset_y", -GetStgFrameTop - yukariButtCoords[1] - 72 + i*2);
				yield;
			}

			ObjShader_ResetShader(GetPlayerObjectID);
			ascent(i in 0 .. 11){
				ObjRender_SetScaleY(gap, linear(1, 0, i/10));
				ObjRender_SetScaleY(ribbon, linear(1, 0, i/10));
				yield;
			}
			Obj_Delete(gap);
			Obj_Delete(ribbon);
		}
	}

	task RenderYukariButt{
		let x = GetPlayerX;
		let y = GetPlayerY;
		yukariButtCoords = [x, y];

		let bottom = ObjPrim_Create(OBJ_SPRITE_2D);
		RenderPlayerImage(bottom, 0, true);
		ObjRender_SetPosition(bottom, x, y, 0);

		/*let bottom = ObjPrim_Create(OBJ_SPRITE_2D); //mask test
		Obj_SetRenderPriorityI(bottom, 31);
		ObjRender_SetBlendType(bottom, BLEND_ALPHA);
		ObjPrim_SetTexture(bottom, GetCurrentScriptDirectory ~ "Image/gapBack.png");
		ObjSprite2D_SetSourceRect(bottom, 0, 0, 512, 512);
		ObjSprite2D_SetDestCenter(bottom);
		ObjRender_SetPosition(bottom, GetPlayerX, GetPlayerY, 0);*/

		let gap = ObjPrim_Create(OBJ_SPRITE_2D);
		Obj_SetRenderPriorityI(gap, 31);
		ObjRender_SetBlendType(gap, BLEND_ALPHA);
		ObjPrim_SetTexture(gap, GetCurrentScriptDirectory ~ "Image/optionYukari2_00.png");
		ObjSprite2D_SetSourceRect(gap, 0, 0, 64, 16);
		ObjSprite2D_SetDestCenter(gap);
		ObjRender_SetPosition(gap, x, y, 0);

		let ribbon = ObjPrim_Create(OBJ_SPRITE_2D);
		Obj_SetRenderPriorityI(ribbon, 31);
		ObjRender_SetBlendType(ribbon, BLEND_ALPHA);
		ObjPrim_SetTexture(ribbon, GetCurrentScriptDirectory ~ "Image/optionYukari2_01.png");
		ObjSprite2D_SetSourceRect(ribbon, 0, 0, 64, 16);
		ObjSprite2D_SetDestCenter(ribbon);
		ObjRender_SetPosition(ribbon, x, y, 0);

		ObjShader_SetShaderF(bottom, GetCurrentScriptDirectory ~ "HLSL_Mask.txt");
		ObjShader_SetTechnique(bottom,"TecMask");

		ObjShader_SetTexture(bottom, "textureMask_", GetCurrentScriptDirectory ~ "Image/yukariMask_bottom.png");

		ObjShader_SetFloat(bottom, "iw", 32);
		ObjShader_SetFloat(bottom, "ih", 144);

		ObjShader_SetFloat(bottom, "iscale_x", 1);
		ObjShader_SetFloat(bottom, "iscale_y", 1);

		ObjShader_SetFloat(bottom, "offset_x", -GetStgFrameLeft - x - 16);
		ObjShader_SetFloat(bottom, "offset_y", -GetStgFrameTop - y - 72);

		loop(30){yield;}

		while(GetVirtualKeyState(VK_OCCULT) != KEY_PUSH){
			yield;
		}

		ascent(i in 0 .. 24){
			if(GetVirtualKeyState(VK_OCCULT) != KEY_FREE && GetVirtualKeyState(VK_SLOWMOVE) != KEY_FREE){
				SwapYukari;
				return;
			}
			ObjRender_SetPosition(gap, x, y + i*2, 0);
			ObjRender_SetPosition(ribbon, x, y + i*2, 0);

			ObjShader_SetFloat(bottom, "offset_x", -GetStgFrameLeft - x - 16);
			ObjShader_SetFloat(bottom, "offset_y", -GetStgFrameTop - y - 72 -  i*2);
			yield;
		}

		Obj_Delete(bottom);
		ascent(i in 0 .. 11){
			ObjRender_SetScaleY(gap, linear(1, 0, i/10));
			ObjRender_SetScaleY(ribbon, linear(1, 0, i/10));
			yield;
		}
		Obj_Delete(gap);
		Obj_Delete(ribbon);

		task SwapYukari{
			x = GetPlayerX;
			y = GetPlayerY;
			ObjRender_SetPosition(bottom, x, y, 0);
			ObjShader_SetTexture(bottom, "textureMask_", GetCurrentScriptDirectory ~ "Image/yukariMask_top.png");

			ascent(i in 0 .. 24){
				ObjRender_SetPosition(gap, x, y - i*2, 0);
				ObjRender_SetPosition(ribbon, x, y - i*2, 0);

				ObjShader_SetFloat(bottom, "offset_x", -GetStgFrameLeft - x - 16);
				ObjShader_SetFloat(bottom, "offset_y", -GetStgFrameTop - y - 72 +  i*2);
				yield;
			}

			Obj_Delete(bottom);
			ascent(i in 0 .. 11){
				ObjRender_SetScaleY(gap, linear(1, 0, i/10));
				ObjRender_SetScaleY(ribbon, linear(1, 0, i/10));
				yield;
			}
			Obj_Delete(gap);
			Obj_Delete(ribbon);

		}
	}
}

task OccultReimu{
	CanOccult = false;

	let minDis = 10000;
	let enem = [0, 0, minDis];
	let ar = GetIntersectionRegistedEnemyID;
	let angle = 270;
	if(length(ar) > 0){
		ascent(i in 0..(length(ar))){
			let dis = GetDist(GetPlayerX, ObjMove_GetX(ar[i]), GetPlayerX, ObjMove_GetY(ar[i]));
			if(dis<enem[2]){
				enem[2] = dis;
				enem[0] = ObjMove_GetX(ar[i]);
				enem[1] = ObjMove_GetY(ar[i]);
			}
		}

		angle = NormalizeAngle(atan2(enem[1] - GetPlayerY, enem[0] - GetPlayerX));
	}

	let gap = ObjPrim_Create(OBJ_SPRITE_2D);
	Obj_SetRenderPriorityI(gap, 30);
	ObjPrim_SetTexture(gap, GetCurrentScriptDirectory ~ "Image/gap_00.png");
	ObjSprite2D_SetSourceRect(gap, 0, 0, 64, 128);
	ObjSprite2D_SetDestCenter(gap);
	ObjRender_SetPosition(gap, GetPlayerX + 48*cos(angle), GetPlayerY + 48*sin(angle), 0);
	ObjRender_SetAngleZ(gap, angle);
	ObjRender_SetScaleXYZ(gap, 0, 0.75, 0);

	ascent(i in 0 .. 11){
		ObjRender_SetScaleX(gap, linear(0, 0.5, i/10));
		yield;
	}

	let sideAn = angle + 90;
	let x = ObjRender_GetX(gap);
	let y = ObjRender_GetY(gap);
	loop(15){
		PlaySoundA1(9, 50, 0);
		ShotSotoba(x, y, 20, angle, 4, damage*5);
		loop(5){yield;}
		ascent(i in 1 .. 6){
			PlaySoundA1(9, 50, 0);
			ShotSotoba(x + (i/5)*32*cos(sideAn), y + (i/5)*32*sin(sideAn), 20, angle, 4, damage*5);
			ShotSotoba(x - (i/5)*32*cos(sideAn), y - (i/5)*32*sin(sideAn), 20, angle, 4, damage*5);
			loop(5){yield;}
		}
	}

	descent(i in 0 .. 11){
		ObjRender_SetScaleX(gap, linear(0, 0.5, i/10));
		yield;
	}

	Obj_Delete(gap);
	CanOccult = true;
}