//===================================================================
// Boss Animation for Phantasmagoria, and other scripts.
//===================================================================

//-------------------------------------------------------------------
// Define Action Variables
//-------------------------------------------------------------------

/**
* 	Constant Action
*	Useful for animating in specific frames.
*	Be aware that the animation depends on the character type
*	( EXAMPLE: YUYUKO, MYSTIA, MEIRIN ). So it might be faster
* 	or slower.
*/
let ACT_STAND1 =	- 1; 	// Basic standing. No animation available.
let ACT_STAND3 =	0; 	// ( 3 piece animation ) 1 blink + standing.
let ACT_STAND4 =	1; 	// ( 4 piece animation ) 1 blink + standing.
let ACT_MOVE =		2; 	// Movement ( Left or right )
let ACT_MOVE_L =	3; 	// left movement
let ACT_MOVE_R =	4; 	// right movement
let ACT_SHOT_A3 =	5; 	// A barrage ( 3 pieces )
let ACT_SHOT_A3_B =	6; 	// A barrage ( 3 frames - B )
let ACT_SHOT_A3_C =	7; 	// A barrage ( 3 shots - C )
let ACT_SHOT_A4 =	8; 	// A barrage ( 4 pieces )
let ACT_SHOT_A5 =	9;	// A barrage ( 5 pieces )
let ACT_SHOT_B2 =	10;	// B Barrage ( 2 pieces )
let ACT_SHOT_B2_B =	11;	// B barrage ( 2 frames - B )
let ACT_SHOT_B3 =	12;	// B barrage ( 3 pieces )
let ACT_SHOT_B3_B =	13;	// B barrage ( 3 pieces - B )
let ACT_SHOT_B3_C =	14;	// B barrage ( 3 shots - C )
let ACT_SHOT_B4 =	15;	// B barrage ( 4 pieces )
let ACT_SHOT_B5 =	16;	// B barrage ( 5 pieces )
let ACT_SHOT_B5_B =	17;	// B barrage ( 5 frames - B )
let ACT_SHOT_C =	18;	// C barrage ( REIMU )
let ACT_SPELL3 =	19;	// Spell call ( 3 piece )
let ACT_SPELL4 =	20;	// Spell Call ( 4 piece )
let ACT_SPELL5 =	21;	// Spell Call ( 5 piece )
let ACT_SPELL5_B =	22;	// Spell Call ( 5 frames - B )
let ACT_ROLL =		23;	// Rolling


/**
* 	Draw a rectangle to cut the sprite.
*	the numbers determine the coordinates
*/
let RECT_BOSS_LENGTH =	128;		//	Length of one side of the square cut
let RECT_BOSS_STAND0 =	[ 0, 0 ];	//	 1
let RECT_BOSS_STAND1 =	[ 0, 1 ];	//	 2
let RECT_BOSS_STAND2 =	[ 0, 2 ];	//	 3
let RECT_BOSS_STAND3 =	[ 0, 3 ];	//	 4
let RECT_BOSS_BLINK0 =	[ 1, 0 ];	//	 5
let RECT_BOSS_BLINK1 =	[ 1, 1 ];	//	 6
let RECT_BOSS_MOVE_L0 =	[ 2, 0 ];	//	 9
let RECT_BOSS_MOVE_L1 =	[ 2, 1 ];	//	10
let RECT_BOSS_MOVE_R0 =	[ 2, 2 ];	//	11
let RECT_BOSS_MOVE_R1 =	[ 2, 3 ];	//	12
let RECT_BOSS_SPELL0 =	[ 3, 0 ];	//	13
let RECT_BOSS_SPELL1 =	[ 3, 1 ];	//	14
let RECT_BOSS_SPELL2 =	[ 3, 2 ];	//	15
let RECT_BOSS_SPELL3 =	[ 3, 3 ];	//	16
let RECT_BOSS_SHOT_A0 =	[ 4, 0 ];	//	17
let RECT_BOSS_SHOT_A1 =	[ 4, 1 ];	//	18
let RECT_BOSS_SHOT_A2 =	[ 4, 2 ];	//	19
let RECT_BOSS_SHOT_A3 =	[ 4, 3 ];	//	20
let RECT_BOSS_SHOT_B0 =	[ 5, 0 ];	//	21
let RECT_BOSS_SHOT_B1 =	[ 5, 1 ];	//	22
let RECT_BOSS_SHOT_B2 =	[ 5, 2 ];	//	23
let RECT_BOSS_SHOT_B3 =	[ 5, 3 ];	//	24
let RECT_BOSS_ETC_A0 =	[ 6, 0 ];	//	25
let RECT_BOSS_ETC_A1 =	[ 6, 1 ];	//	26
let RECT_BOSS_ETC_A2 =	[ 6, 2 ];	//	27
let RECT_BOSS_ETC_A3 =	[ 6, 3 ];	//	28
let RECT_BOSS_ETC_B0 =	[ 7, 0 ];	//	29
let RECT_BOSS_ETC_B1 =	[ 7, 1 ];	//	30
let RECT_BOSS_ETC_B2 =	[ 7, 2 ];	//	31
let RECT_BOSS_ETC_B3 =	[ 7, 3 ];	//	32


//-------------------------------------------------------------------
// Main Animation
//-------------------------------------------------------------------

//-------------------------------------------------------------------
// Define animation variables
//-------------------------------------------------------------------

/** If Dead equals to true, the boss and animation disappear */
let Dead = false;
/** The main bosses alpha */
let EnemyAlpha = 255;
/** Default Standing Action */
let ActionDefault = ACT_STAND3;
/** Main Action */
let nAction = 0;
/** Animation Count */
let ActionCount = 0;
/** Max Animation Count */
let ActionCountMax = 0;
/** Not a really important count. Just used for the floating */
let FloatCount = 0;

//-------------------------------------------------------------------
// Set boss animation type and stuff
//-------------------------------------------------------------------

/**
*	Summon this function of Initialize.
*	This will activate the animation.
*
*	@param Action	( Standing animation action used for the sprite )
*/
task BehaviorBoss( let Action ){
	ActionDefault = Action;
	loop{
		if( Dead ){ break; }
		SetAction( Action, 0 );
		while( ActionCount < ActionCountMax && !Dead ){
			ActionCount ++;
			yield;
		}
	}
}

/**
*	Set the desired action( example: ACT_SHOT_B, ACT_MOVE_L )
*	to do. Useful for bullet barrages, left and right movement,
*	and other stuff. It will automatically reset back into the standing
*	action used in BehaviorBoss.
*
*	@param Action	( Action to do )
*	@param Frame	( the amount of Frames it loops )
*/
function SetAction( let Action, let Frame ){
	alternative( Action )
	case( ACT_STAND1, ACT_STAND3, ACT_STAND4 ){ Frame = 36000; }
	case( ACT_SPELL3, ACT_SPELL4, ACT_SPELL5, ACT_SPELL5_B ){ Frame = 100; }
	case( ACT_ROLL ){ Frame = 42; }
	case( ACT_SHOT_A3_C ){ Frame = 18; }
	nAction = Action;
	ActionCount = 0;
	ActionCountMax = Frame;
}

//-------------------------------------------------------------------
// Draw the boss. Mandatory for the sprite
//-------------------------------------------------------------------

/**
*	Draw the sprite graphic. 
*	Note: This is only for ctc sprites. Or similiar sprites
*	in the same format...
*
*	@param ImageFile	( Sprite image )
*/
function DrawBoss( let ImageFile ){
	_DrawBoss( ImageFile, GetX(), GetY() );
}

/**
*	Draw the sprite graphic. Same as DrawBoss but
*	add some extra floating.
*
*	@param ImageFile	( Sprite image )
*/
function DrawBossFloat( let ImageFile ){
	_DrawBoss( ImageFile, GetX(), GetY() + 6 * sin( 3 * FloatCount ) );
	FloatCount ++;
}

/**
*	This is the most mandatory part of 
*	drawing the sprite. Simple call it at DrawLoop with the
*	following parameters:
*
*	@param ImageFile	( Sprite image )
*	@param X		( X Coordinate )
*	@param Y		( Y Coordinate )
*/
function _DrawBoss( let ImageFile, let X, let Y ){
	let anRect = [];
	alternative( nAction )
	/** Standing animations */
	case( ACT_STAND3 ){
		let _ACount = 12;
		let ACount = ActionCount % ( _ACount * 12 );
		let Anime = 2;
		let AnimeNum = [ 0, 1, 2, 0, 1, 2, 0, 3, 4, 0, 1, 2 ];
		let AnimeCount = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 ];
		ascent( let i in 0 .. 12 ){
			if( ACount < _ACount * AnimeCount[ i ] ){
				Anime = AnimeNum[ i ];
				break;
			}
		}
		alternative( Anime )
		case( 0 ){ anRect = RECT_BOSS_STAND0; }
		case( 1 ){ anRect = RECT_BOSS_STAND1; }
		case( 2 ){ anRect = RECT_BOSS_STAND2; }
		case( 3 ){ anRect = RECT_BOSS_BLINK0; }
		case( 4 ){ anRect = RECT_BOSS_BLINK1; }
	}
	case( ACT_STAND4 ){
		let _ACount = 12;
		let ACount = ActionCount % ( _ACount * 12 );
		let Anime = 2;
		let AnimeNum = [ 0, 1, 2, 3, 0, 1, 2, 3, 0, 4, 5, 3 ];
		let AnimeCount = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 ];
		ascent( let i in 0 .. 12 ){
			if( ACount < _ACount * AnimeCount[ i ] ){
				Anime = AnimeNum[ i ];
				break;
			}
		}
		alternative( Anime )
		case( 0 ){ anRect = RECT_BOSS_STAND0; }
		case( 1 ){ anRect = RECT_BOSS_STAND1; }
		case( 2 ){ anRect = RECT_BOSS_STAND2; }
		case( 3 ){ anRect = RECT_BOSS_STAND3; }
		case( 4 ){ anRect = RECT_BOSS_BLINK0; }
		case( 5 ){ anRect = RECT_BOSS_BLINK1; }
	}
	/** Movement */
	case( ACT_MOVE, ACT_MOVE_L, ACT_MOVE_R ){
		if( nAction == ACT_MOVE && GetSpeed() < 0.1 ){ anRect = RECT_BOSS_STAND0; }
		else{
			let Count0 = 10;
			if( ActionCountMax < 40 ){ Count0 = trunc( ActionCountMax / 4 ); }
			let Count1 = ActionCountMax - Count0;
			let Anime = 0;
			let AnimeNum = [ 0, 1, 0 ];
			let AnimeCount = [ Count0, Count1, ActionCountMax ];
			ascent( let i in 0 .. 3 ){
				if( ActionCount < AnimeCount[ i ] ){
					Anime = AnimeNum[ i ];
					break;
				}
			}
			let MoveL = true;
			alternative( nAction )
			case( ACT_MOVE_R ){ MoveL = false; }
			case( ACT_MOVE ){
				if( cos( GetAngle() ) > 0 ){ MoveL = false; }
			}
			alternative( Anime )
			case( 0 ){
				if( MoveL ){ anRect = RECT_BOSS_MOVE_L0; }
				else{ anRect = RECT_BOSS_MOVE_R0; }
			}
			case( 1 ){	
				if( MoveL ){ anRect = RECT_BOSS_MOVE_L1; }
				else{ anRect = RECT_BOSS_MOVE_R1; }
			}
		}
	}
	/** A B barrage series( B ) */
	case( ACT_SHOT_B2, ACT_SHOT_B2_B ){
		let Count0 = 6;
		if( ActionCountMax < 18 ){ Count0 = trunc( ActionCountMax / 3 ); }
		let Anime = 1;
		let AnimeNum = [ 0, 1 ];
		let AnimeCount = [ Count0, ActionCountMax ];
		ascent( let i in 0 .. 2 ){
			if( ActionCount < AnimeCount[ i ] ){
				Anime = AnimeNum[ i ];
				break;
			}
		}
		alternative( Anime )
		case( 0 ){
			alternative( nAction )
			case( ACT_SHOT_B2 ){ anRect = RECT_BOSS_SHOT_B0; }
			case( ACT_SHOT_B2_B ){ anRect = RECT_BOSS_SHOT_B2; }
		}
		case( 1 ){
			alternative( nAction )
			case( ACT_SHOT_B2 ){ anRect = RECT_BOSS_SHOT_B1; }
			case( ACT_SHOT_B2_B ){ anRect = RECT_BOSS_SHOT_B3; }
		}
	}
	/** A and B barrage series( 3 ) */
	case( ACT_SHOT_A3, ACT_SHOT_B3, ACT_SHOT_B3_C ){
		let Count0 = 6;
		if( ActionCountMax < 24 ){ Count0 = trunc( ActionCountMax / 4 ); }
		let Count1 = ActionCountMax - Count0;
		let Anime = 0;
		let AnimeNum = [ 0, 1, 0 ];
		let AnimeCount = [ Count0, Count1, ActionCountMax ];
		ascent( let i in 0 .. 3 ){
			if( ActionCount < AnimeCount[ i ] ){
				Anime = AnimeNum[ i ];
				break;
			}
		}
		alternative( Anime )
		case( 0 ){
			alternative( nAction )
			case( ACT_SHOT_A3 ){ anRect = RECT_BOSS_SHOT_A0; }
			case( ACT_SHOT_B3 ){ anRect = RECT_BOSS_SHOT_B0; }
			case( ACT_SHOT_B3_C ){ anRect = RECT_BOSS_SHOT_B2; }
		}
		case( 1 ){
			alternative( nAction )
			case( ACT_SHOT_A3 ){ anRect = RECT_BOSS_SHOT_A1; }
			case( ACT_SHOT_B3 ){ anRect = RECT_BOSS_SHOT_B1; }
			case( ACT_SHOT_B3_C ){ anRect = RECT_BOSS_SHOT_B3; }
		}
	}
	case( ACT_SHOT_A3_B ){
		let Count0 = 6;
		if( ActionCountMax < 24 ){ Count0 = trunc( ActionCountMax / 4 ); }
		let Anime = 0;
		let AnimeNum = [ 0, 1, 2 ];
		let AnimeCount = [ Count0, Count0 * 2, ActionCountMax ];
		ascent( let i in 0 .. 3 ){
			if( ActionCount < AnimeCount[ i ] ){
				Anime = AnimeNum[ i ];
				break;
			}
		}
		alternative( Anime )
		case( 0 ){ anRect = RECT_BOSS_SHOT_A0; }
		case( 1 ){ anRect = RECT_BOSS_SHOT_A1; }
		case( 2 ){ anRect = RECT_BOSS_SHOT_A2; }
	}
	case( ACT_SHOT_A3_C ){
		let Count0 = 6;
		let Anime = 0;
		let AnimeNum = [ 0, 1, 2 ];
		let AnimeCount = [ 1, 2, 3 ];
		ascent( let i in 0 .. 3 ){
			if( ActionCount < Count0 * AnimeCount[ i ] ){
				Anime = AnimeNum[ i ];
				break;
			}
		}
		alternative( Anime )
		case( 0 ){ anRect = RECT_BOSS_SHOT_A3; }
		case( 1 ){ anRect = RECT_BOSS_SHOT_A1; }
		case( 2 ){ anRect = RECT_BOSS_SHOT_A0; }
	}
	case( ACT_SHOT_B3_B ){
		let Count0 = 6;
		if( ActionCountMax < 24 ){ Count0 = trunc( ActionCountMax / 4 ); }
		let Anime = 0;
		let AnimeNum = [ 0, 1, 2 ];
		let AnimeCount = [ Count0, Count0 * 2, ActionCountMax ];
		ascent( let i in 0 .. 3 ){
			if( ActionCount < AnimeCount[ i ] ){
				Anime = AnimeNum[ i ];
				break;
			}
		}
		alternative( Anime )
		case( 0 ){ anRect = RECT_BOSS_SHOT_B0; }
		case( 1 ){ anRect = RECT_BOSS_SHOT_B2; }
		case( 2 ){ anRect = RECT_BOSS_SHOT_B3; }
	}
	/** AA and B barrage ( 4 series )
	case( ACT_SHOT_A4, ACT_SHOT_B4 ){
		let Count0 = 6;
		if( ActionCountMax < 30 ){ Count0 = trunc( ActionCountMax / 5 ); }
		let Count1 = ActionCountMax - Count0;
		let Anime = 0;
		let AnimeNum = [ 0, 1, 2, 1 ];
		let AnimeCount = [ Count0, Count0 * 2, Count1, ActionCountMax ];
		ascent( let i in 0 .. 4 ){
			if( ActionCount < AnimeCount[ i ] ){
				Anime = AnimeNum[ i ];
				break;
			}
		}
		alternative( Anime )
		case( 0 ){
			alternative( nAction )
			case( ACT_SHOT_A4 ){ anRect = RECT_BOSS_SHOT_A0; }
			case( ACT_SHOT_B4 ){ anRect = RECT_BOSS_SHOT_B0; }
		}
		case( 1 ){
			alternative( nAction )
			case( ACT_SHOT_A4 ){ anRect = RECT_BOSS_SHOT_A1; }
			case( ACT_SHOT_B4 ){ anRect = RECT_BOSS_SHOT_B1; }
		}
		case( 2 ){
			alternative( nAction )
			case( ACT_SHOT_A4 ){ anRect = RECT_BOSS_SHOT_A2; }
			case( ACT_SHOT_B4 ){ anRect = RECT_BOSS_SHOT_B2; }
		}
	}
	/** A and B barrage ( 5 series ) */
	case( ACT_SHOT_A5, ACT_SHOT_B5, ACT_SHOT_B5_B ){
		let Count0 = 6;
		if( ActionCountMax < 36 ){ Count0 = trunc( ActionCountMax / 6 ); }
		let Count1 = ActionCountMax - Count0;
		let Anime = 0;
		let AnimeNum = [ 0, 1, 2, 1, 0 ];
		let AnimeCount = [ Count0, Count0 * 2, Count1 - Count0, Count1, ActionCountMax ];
		ascent( let i in 0 .. 5 ){
			if( ActionCount < AnimeCount[ i ] ){
				Anime = AnimeNum[ i ];
				break;
			}
		}
		alternative( Anime )
		case( 0 ){
			alternative( nAction )
			case( ACT_SHOT_A5 ){ anRect = RECT_BOSS_SHOT_A0; }
			others{ anRect = RECT_BOSS_SHOT_B0; }
		}
		case( 1 ){
			alternative( nAction )
			case( ACT_SHOT_A5 ){ anRect = RECT_BOSS_SHOT_A1; }
			others{ anRect = RECT_BOSS_SHOT_B1; }
		}
		case( 2 ){
			alternative( nAction )
			case( ACT_SHOT_A5 ){ anRect = RECT_BOSS_SHOT_A2; }
			case( ACT_SHOT_B5 ){ anRect = RECT_BOSS_SHOT_B2; }
			case( ACT_SHOT_B5_B ){ anRect = RECT_BOSS_SHOT_B3; }
		}
	}
	/** Barrage C */
	case( ACT_SHOT_C ){
		let Count00 = 6;
		let Anime = 7;
		if( ActionCountMax < 12 ){ Count00 = trunc( ( ActionCountMax + 1 ) / 2 ); }
		if( ActionCount < Count00 ){ Anime = 0; }
		else if( ActionCount < ActionCountMax - Count00 ){ Anime = trunc( ( ActionCount - Count00 ) / Count00 ) % 6 + 1; }
		alternative( Anime )
		case( 0 ){ anRect = RECT_BOSS_ETC_A0; }
		case( 1 ){ anRect = RECT_BOSS_ETC_A1; }
		case( 2 ){ anRect = RECT_BOSS_ETC_A2; }
		case( 3 ){ anRect = RECT_BOSS_ETC_A3; }
		case( 4 ){ anRect = RECT_BOSS_ETC_B0; }
		case( 5 ){ anRect = RECT_BOSS_ETC_B1; }
		case( 6 ){ anRect = RECT_BOSS_ETC_B2; }
		case( 7 ){ anRect = RECT_BOSS_ETC_B3; }
	}
	/** The spell summon series */
	case( ACT_SPELL3 ){
		let Anime = 0;
		let AnimeNum = [ 0, 1, 0 ];
		let AnimeCount = [ 6, 94, 100 ];
		ascent( let i in 0 .. 3 ){
			if( ActionCount < AnimeCount[ i ] ){
				Anime = AnimeNum[ i ];
				break;
			}
		}
		alternative( Anime )
		case( 0 ){ anRect = RECT_BOSS_SPELL0; }
		case( 1 ){ anRect = RECT_BOSS_SPELL1; }
	}
	case( ACT_SPELL4 ){
		let Anime = 0;
		let AnimeNum = [ 0, 1, 2, 1 ];
		let AnimeCount = [ 6, 12, 94, 100 ];
		ascent( let i in 0 .. 4 ){
			if( ActionCount < AnimeCount[ i ] ){
				Anime = AnimeNum[ i ];
				break;
			}
		}
		alternative( Anime )
		case( 0 ){ anRect = RECT_BOSS_SPELL0; }
		case( 1 ){ anRect = RECT_BOSS_SPELL1; }
		case( 2 ){ anRect = RECT_BOSS_SPELL2; }
	}
	case( ACT_SPELL5 ){
		let Anime = 0;
		let AnimeNum = [ 0, 1, 2, 1, 0 ];
		let AnimeCount = [ 6, 12, 88, 94, 100 ];
		ascent( let i in 0 .. 5 ){
			if( ActionCount < AnimeCount[ i ] ){
				Anime = AnimeNum[ i ];
				break;
			}
		}
		alternative( Anime )
		case( 0 ){ anRect = RECT_BOSS_SPELL0; }
		case( 1 ){ anRect = RECT_BOSS_SPELL1; }
		case( 2 ){ anRect = RECT_BOSS_SPELL2; }
	}
	case( ACT_SPELL5_B ){
		let Anime = 0;
		let AnimeNum = [ 0, 1, 2, 3, 2 ];
		let AnimeCount = [ 6, 12, 18, 94, 100 ];
		ascent( let i in 0 .. 5 ){
			if( ActionCount < AnimeCount[ i ] ){
				Anime = AnimeNum[ i ];
				break;
			}
		}
		alternative( Anime )
		case( 0 ){ anRect = RECT_BOSS_SPELL0; }
		case( 1 ){ anRect = RECT_BOSS_SPELL1; }
		case( 2 ){ anRect = RECT_BOSS_SPELL2; }
		case( 3 ){ anRect = RECT_BOSS_SPELL3; }
	}
	/** Rolling */
	case( ACT_ROLL ){
		let _Count = 7;
		let Anime = 0;
		let AnimeNum = [ 0, 1, 2, 3, 4, 0 ];
		let AnimeCount = [ 1, 2, 3, 4, 5, 6 ];
		ascent( let i in 0 .. 6 ){
			if( ActionCount < _Count * AnimeCount[ i ] ){
				Anime = AnimeNum[ i ];
				break;
			}
		}
		alternative( Anime )
		case( 0 ){ anRect = RECT_BOSS_ETC_A0; }
		case( 1 ){ anRect = RECT_BOSS_ETC_B0; }
		case( 2 ){ anRect = RECT_BOSS_ETC_B1; }
		case( 3 ){ anRect = RECT_BOSS_ETC_B2; }
		case( 4 ){ anRect = RECT_BOSS_ETC_B3; }
	}
	/** Drawing the sprite */
	others{ anRect = RECT_BOSS_STAND0; }
	let nRectX = RECT_BOSS_LENGTH * anRect[ 0 ];
	let nRectY = RECT_BOSS_LENGTH * anRect[ 1 ];
	SetAlpha( EnemyAlpha );
	DrawCharRect( ImageFile, X, Y, nRectX, nRectY, RECT_BOSS_LENGTH, RECT_BOSS_LENGTH );
	SetGraphicScale( 1, 1 );
}

/**
*	Draw the Boss Rect
*	@param ImageFile	( ImageFile )
*	@param X	( X Coordinate )
*	@param Y	( Y Coordinate )
*	@param RectX	( Rect X )
* 	@param RectY	( Rect Y )
*	@param Width	( Width of image )
*	@param Height	( Height of image )
*/
function DrawCharRect( let ImageFile, let X, let Y, let RectX, let RectY, let Width, let Height ){
	SetGraphicRect( RectX, RectY, RectX + Width, RectY + Height );
	SetTexture( ImageFile );
	DrawGraphic( X, Y );
}

