//====================================================================
//
//	東方夢終劇 〜 Concealed the Conclusion
//		専用魔理沙スクリプト
//
//====================================================================
//////////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////////////
//--------------------------------------------------------------------
//	ヘッダ
//--------------------------------------------------------------------
//////////////////////////////////////////////////////////////////////

#東方弾幕風[Player]
#ScriptVersion[2]
#ReplayName[THC_MA]
#Menu[魔理沙 星符]
#Image[.\IMAGE\Select.png]
#Text[ホーミングタイプ]


//////////////////////////////////////////////////////////////////////
//--------------------------------------------------------------------
//	メインスクリプト部
//--------------------------------------------------------------------
//////////////////////////////////////////////////////////////////////

script_player_main{


//////////////////////////////////////////////////////////////////////
//	ライブラリのインクルード
//////////////////////////////////////////////////////////////////////

#include_function ".\INCLUDE\player.dnh"


//////////////////////////////////////////////////////////////////////
//	設定定義
//////////////////////////////////////////////////////////////////////

	FLAN_PLAYER_SPEED_FAST = 3.9;
	FLAN_PLAYER_SPEED_SLOW = 1.7;
	FLAN_PLAYER_ITEM_AUTOCOLLECT_LINE = 128;
	FLAN_PLAYER_BORDERLIFE_DEFAULT = 16;
	PLAYER_INYAN_GAUGE_RATE = 1;
	PLAYER_SHOT_BASIC_WIDTH_FASTMOVE = 14;
	PLAYER_SHOT_BASIC_WIDTH_SLOWMOVE = 9;
	PLAYER_SPELL_NAME_FASTMOVE = "星符「スーパーノヴァ」";
	PLAYER_SPELL_NAME_SLOWMOVE = "星符「メテオライト」";
	PLAYER_SPELL_FUNCTION_FASTMOVE = "SpellMarisaA2";
	PLAYER_SPELL_FUNCTION_SLOWMOVE = "SpellMarisaA1";


//////////////////////////////////////////////////////////////////////
//	定数
//////////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////////////
//	メンバ変数
//////////////////////////////////////////////////////////////////////

	/**	ビット専用カウンタです。 */
	let m_nBitCount = 0;


//////////////////////////////////////////////////////////////////////
//	固有処理
//////////////////////////////////////////////////////////////////////

	/**
	*	サーチショット本体です。
	*
	*	@param nX 初期X座標
	*	@param nY 初期Y座標
	*	@param nAngle 初期角度
	*	@param bHoming 低速移動モードで発射されたかどうか
	*/
	task SearchShot( let nX, let nY, let nAngle, let bHoming ){
		let nObjCount = 0;
		let nStartSpeed = 10;
		let nMaxSpeed = 33;
		let nSpeedLimitTime = 100;
		let nLockID = -1;
		let obj = Obj_Create( OBJ_SHOT );
		Obj_SetPosition( obj, nX, nY );
		let nID = GetEnemyIDInScreenMoreNearX( nX );
		if( nID != -1 && !bHoming ){ Obj_SetAngle( obj, nAngle + atan2( m_nFlanInScreenEnemyY - Obj_GetY( obj ), m_nFlanInScreenEnemyX - Obj_GetX( obj ) ) ); }
		else{ Obj_SetAngle( obj, nAngle - 90 ); }
		ObjShot_SetGraphic( obj, US_SUBSHOT );
		Obj_SetAutoDelete( obj, true );
		ObjShot_SetDamage( obj, [ 2, 2.5 ][ bHoming ] );
		ObjShot_SetPenetration( obj, [ 2, 3 ][ bHoming ] );
		let nSpeedCache = nStartSpeed + ( nMaxSpeed - nStartSpeed );
		let nLimitCache = ( ( nSpeedLimitTime + 1 ) * nSpeedLimitTime ) * 2 ^ ( -1 );
		while( !Obj_BeDeleted( obj ) ){
			if( nObjCount % 3 == 0 ){
				Obj_SetAlpha( obj, Smooth( 0, 96, nObjCount, 20 ) );
				if( nLockID == -1 ){ nLockID = GetEnemyIDInScreenMoreNearX( Obj_GetX( obj ) ); }
				if( nLockID != -1 && bHoming ){
					let nX = GetEnemyInfoDefault( nID, ENEMY_X, 65536 );
					let nY = GetEnemyInfoDefault( nID, ENEMY_Y, 65536 );
					if( IsOutPos( nX, nY, 48 ) ){
						nLockID = -1;
						nX = GetCenterX();
						nY = 0;
					}
					let nAngle = Obj_GetAngle( obj );
					Obj_SetAngle( obj, nAngle + 2.5 * [ -1, 1 ][ MinMaxLoop( atan2( nY - Obj_GetY( obj ), nX - Obj_GetX( obj ) ) - nAngle, 0, 360 ) < 180 ] );
				}
				if( nObjCount < nSpeedLimitTime ){ Obj_SetSpeed( obj, nSpeedCache * ( ( ( nObjCount + 1 ) * nObjCount ) * 2 ^ ( -1 ) ) / nLimitCache ); }
				else if( !bHoming ){ return; }
			}
			yield;
			nObjCount++;
		}	// 大量生成されるのでなるべくライブラリのインライン展開に心がける
	}


//////////////////////////////////////////////////////////////////////
//	共通処理
//////////////////////////////////////////////////////////////////////

	/**
	*	固有動作のタスクです。onInitializeTHC()より1フレーム後に呼ばれます。
	*	ここに固有の動作を記述します。
	*/
	task MainTaskTHC(){
	}

	/**
	*	初期化時に呼ばれます。
	*/
	function onInitializeTHC(){
	}

	/**
	*	ショット発射時に呼ばれます。
	*
	*	@param nCount 現在のカウンタ値
	*	@param nPhase 現在のフェーズ
	*	@param nPhaseCount 現在のフェーズカウンタ値
	*	@param nPrevPhase 1つ前の状態のフェーズ
	*/
	function onShotTHC( let nCount, let nPhase, let nPhaseCount, let nPrevPhase ){
	}

	/**
	*	サブショット発射時に呼ばれます。
	*
	*	@param nParentBitObj 親ビットのオブジェクトハンドル
	*	@param nParentBitDir 親ビットの左右位置関係
	*	@param nCount 現在のカウンタ値
	*	@param nPhase 現在のフェーズ
	*	@param nPhaseCount 現在のフェーズカウンタ値
	*	@param nPrevPhase 1つ前の状態のフェーズ
	*/
	function onSubShotTHC( let nParentBitObj, let nParentBitDir, let nCount, let nPhase, let nPhaseCount, let nPrevPhase ){
		if( nCount % trunc( 50 / Max( nPhase * 2, 1 ) / [ 1.5, 1 ][ m_bFlanKeySlow ] ) != 0 ){ return; }
		let nX = Obj_GetX( nParentBitObj );
		let nY = Obj_GetY( nParentBitObj );
		if( nPhase == 0 ){
			SearchShot( nX, nY, 0, m_bFlanKeySlow );
			return;
		}
		SearchShot( nX, nY, m_nBitCount * ( 12 / [ 0.5, 1, 2, 2, 2.5 ][ nPhase - 1 ] ) %  24 - 12, m_bFlanKeySlow );
		m_nBitCount++;
	}

	/**
	*	毎フレームごとに呼ばれます。
	*
	*	@param nCount 現在のカウンタ値
	*	@param nPhase 現在のフェーズ
	*	@param nPhaseCount 現在のフェーズカウンタ値
	*	@param nPrevPhase 1つ前の状態のフェーズ
	*/
	function onMainLoopTHC( let nCount, let nPhase, let nPhaseCount, let nPrevPhase ){
	}

	/**
	*	ミス時に呼ばれます。
	*
	*	@param nCount 現在のカウンタ値
	*	@param nPhase 現在のフェーズ
	*	@param nPhaseCount 現在のフェーズカウンタ値
	*	@param nPrevPhase 1つ前の状態のフェーズ
	*/
	function onPlayerMissedTHC( let nCount, let nPhase, let nPhaseCount, let nPrevPhase ){
	}

	/**
	*	スペル発動時に呼ばれます。
	*
	*	@param nCount 現在のカウンタ値
	*	@param nPhase 現在のフェーズ
	*	@param nPhaseCount 現在のフェーズカウンタ値
	*	@param nPrevPhase 1つ前の状態のフェーズ
	*/
	function onStartSpellTHC( let nCount, let nPhase, let nPhaseCount, let nPrevPhase ){
	}

	/**
	*	終了時に呼ばれます。
	*
	*	@param nCount 現在のカウンタ値
	*	@param nPhase 現在のフェーズ
	*	@param nPhaseCount 現在のフェーズカウンタ値
	*	@param nPrevPhase 1つ前の状態のフェーズ
	*/
	function onFinalizeTHC( let nCount, let nPhase, let nPhaseCount, let nPrevPhase ){
	}

	/**
	*	絵画時に呼ばれます。
	*
	*	@param nCount 現在のカウンタ値
	*	@param nPhase 現在のフェーズ
	*	@param nPhaseCount 現在のフェーズカウンタ値
	*	@param nPrevPhase 1つ前の状態のフェーズ
	*/
	function onDrawLoopTHC( let nCount, let nPhase, let nPhaseCount, let nPrevPhase ){
	}


//////////////////////////////////////////////////////////////////////
//--------------------------------------------------------------------
//	メインスクリプト部ここまで
//--------------------------------------------------------------------
//////////////////////////////////////////////////////////////////////

}


//////////////////////////////////////////////////////////////////////
//--------------------------------------------------------------------
//	スペルカードスクリプト部
//--------------------------------------------------------------------
//////////////////////////////////////////////////////////////////////

script_spell SpellMarisaA1{


//////////////////////////////////////////////////////////////////////
//	ライブラリのインクルード
//////////////////////////////////////////////////////////////////////

#include_function ".\INCLUDE\spell.dnh"


//////////////////////////////////////////////////////////////////////
//	設定定義
//////////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////////////
//	定数
//////////////////////////////////////////////////////////////////////

/**	星の大きさを設定します。 */
let SPELL_STAR_SCALE		= 64;
/**	星の数を設定します。 */
let SPELL_STAR_NUMS			= 10;
/**	星がロックオンするまでの時間をフレーム単位で設定します。 */
let SPELL_STAR_FIRSTPHASE	= 100;


//////////////////////////////////////////////////////////////////////
//	メンバ変数
//////////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////////////
//	固有処理
//////////////////////////////////////////////////////////////////////

	/**
	*	星型のスペルカードエフェクトオブジェクトです。
	*
	*	@param nAngle 発射角度
	*	@param nColorR 赤輝度
	*	@param nColorR 緑輝度
	*	@param nColorB 青輝度
	*/
	task Star( let nAngle, let nColorR, let nColorG, let nColorB ){
		let nObjCount = 0;
		let nFirstPhase = 80;
		let obj = CreateStar( SPELL_STAR_SCALE, nColorR, nColorG, nColorB );
		Obj_SetAngle( obj, nAngle );
		Obj_SetPosition( obj, GetPlayerX(), GetPlayerY() );
		while( !Obj_BeDeleted( obj ) && nObjCount < nFirstPhase ){
			Obj_SetSpeed( obj, SlowDown( 3, 0, nObjCount, nFirstPhase ) );
			__StarLoop( obj, nObjCount, 3, SPELL_STAR_SCALE, 1.5 );
			yield;
			nObjCount++;
		}
		let nX = 65536;
		let nY = 65536;
		ascent( let i in EnumEnemyBegin()..EnumEnemyEnd() ){
			let nID = EnumEnemyGetID( i );
			nX = GetEnemyInfoDefault( nID, ENEMY_X, 65536 );
			nY = GetEnemyInfoDefault( nID, ENEMY_Y, 65536 );
			if( !IsOutPos( nX, nY, 48 ) ){ break; }
		}
		if( IsOutPos( nX, nY, 48 ) ){
			nX = GetCenterX();
			nY = 0;
		}
		let nAngle = Obj_GetAngle( obj );
		Obj_SetAngle( obj, GetGapAngle( Obj_GetX( obj ), Obj_GetY( obj ), nX, nY ) );
		while( !Obj_BeDeleted( obj ) && nObjCount < 300 ){
			Obj_SetSpeed( obj, 10 + ( nObjCount - nFirstPhase ) / 10 );
			__StarLoop( obj, nObjCount, 3, SPELL_STAR_SCALE, 5 );
			yield;
			nObjCount++;
		}
		Obj_Delete( obj );
	}


//////////////////////////////////////////////////////////////////////
//	共通処理
//////////////////////////////////////////////////////////////////////

	/**
	*	固有動作のタスクです。onInitializeTHC()より1フレーム後に呼ばれます。
	*	ここに固有の動作を記述します。
	*
	*	@param nArgv 任意の値
	*/
	task MainTask( let nArgv ){
		PlaySEEx( seKira1 );
		ascent( let i in 0..SPELL_STAR_NUMS ){
			ascent( let j in 0..2 ){
			let n = i % SPELL_STAR_COLORTABLE_LENGTH;
				Star( Smooth( 0, 180, i, SPELL_STAR_NUMS ) + j * 180, SPELL_STAR_COLORTABLE_RED[ n ], SPELL_STAR_COLORTABLE_GREEN[ n ], SPELL_STAR_COLORTABLE_BLUE[ n ] );
			}
			__Wait( 8 );
		}
		__Wait( 200 );
		End();
	}

	/**
	*	初期化時に呼ばれます。
	*
	*	@param nArgv 任意の値
	*/
	function onInitializeTHC( let nArgv ){
		LoadSE( seKira1 );
		SetPlayerInvincibility( 360 );
	}

	/**
	*	毎フレームごとに呼ばれます。
	*
	*	@param nArgv 任意の値
	*	@param nCount 現在のカウンタ値
	*	@param nPhase 現在のフェーズ
	*	@param nPhaseCount 現在のフェーズカウンタ値
	*	@param nPrevPhase 1つ前の状態のフェーズ
	*/
	function onMainLoopTHC( let nArgv, let nCount, let nPhase, let nPhaseCount, let nPrevPhase ){
	}

	/**
	*	終了時に呼ばれます。
	*
	*	@param nArgv 任意の値
	*	@param nCount 現在のカウンタ値
	*	@param nPhase 現在のフェーズ
	*	@param nPhaseCount 現在のフェーズカウンタ値
	*	@param nPrevPhase 1つ前の状態のフェーズ
	*/
	function onFinalizeTHC( let nArgv, let nCount, let nPhase, let nPhaseCount, let nPrevPhase ){
	}


//////////////////////////////////////////////////////////////////////
//--------------------------------------------------------------------
//	スペルカードスクリプト部ここまで
//--------------------------------------------------------------------
//////////////////////////////////////////////////////////////////////

}


//////////////////////////////////////////////////////////////////////
//--------------------------------------------------------------------
//	スペルカードスクリプト部
//--------------------------------------------------------------------
//////////////////////////////////////////////////////////////////////

script_spell SpellMarisaA2{


//////////////////////////////////////////////////////////////////////
//	ライブラリのインクルード
//////////////////////////////////////////////////////////////////////

#include_function ".\INCLUDE\spell.dnh"


//////////////////////////////////////////////////////////////////////
//	設定定義
//////////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////////////
//	定数
//////////////////////////////////////////////////////////////////////

/**	星の大きさを設定します。 */
let SPELL_STAR_SCALE		= 64;
/**	星の数を設定します。 */
let SPELL_STAR_NUMS			= 20;
/**	星がロックオンするまでの時間をフレーム単位で設定します。 */
let SPELL_STAR_FIRSTPHASE	= 80;


//////////////////////////////////////////////////////////////////////
//	メンバ変数
//////////////////////////////////////////////////////////////////////

/**	スペル発動時のプレイヤーのX座標を格納します。 */
let m_nFirstX = GetPlayerX();
/**	スペル発動時のプレイヤーのY座標を格納します。 */
let m_nFirstY = GetPlayerY();
/**	星リングの中心X座標を格納します。 */
let m_nCenterX;
/**	星リングの中心Y座標を格納します。 */
let m_nCenterY;


//////////////////////////////////////////////////////////////////////
//	固有処理
//////////////////////////////////////////////////////////////////////

	/**
	*	星型のスペルカードエフェクトオブジェクトです。
	*
	*	@param nGap 発射タイムラグ
	*	@param nAngle 発射角度
	*	@param nColorR 赤輝度
	*	@param nColorR 緑輝度
	*	@param nColorB 青輝度
	*/
	task Star( let nGap, let nAngle, let nColorR, let nColorG, let nColorB ){
		let nGapAngle = Smooth( 0, 360, nGap, SPELL_STAR_NUMS );
		let nObjCount = 0;
		let nFirstPhase = SPELL_STAR_FIRSTPHASE;
		let obj = CreateStar( SPELL_STAR_SCALE, nColorR, nColorG, nColorB );
		while( !Obj_BeDeleted( obj ) && nObjCount < nFirstPhase ){
			let nSpeed = SlowDown( 6, 0, nObjCount, nFirstPhase );
			let nDiam = sin( Smooth( 0, 180, nObjCount, nFirstPhase ) ) * 160;
			__StarLoop( obj, nObjCount, 3, SPELL_STAR_SCALE, 1 );
			Obj_SetPosition( obj, m_nCenterX - cos( nObjCount * nSpeed + nGapAngle ) * nDiam, m_nCenterY + sin( nObjCount * nSpeed + nGapAngle ) * nDiam );
			yield;
			nObjCount++;
		}
		__Wait( nGap * 2 );
		if( GetEnemyIDInScreen() != -1 ){
			let nID = EnumEnemyGetID( MinMaxLoop( nGap, EnumEnemyBegin(), EnumEnemyEnd() ) );
			Obj_SetAngle( obj, GetGapAngle( Obj_GetX( obj ), Obj_GetY( obj ), GetEnemyInfoDefault( nID, ENEMY_X, GetCenterX() ), GetEnemyInfoDefault( nID, ENEMY_Y, 0 ) ) );
		}
		else{ Obj_SetAngle( obj, GetGapAngle( Obj_GetX( obj ), Obj_GetY( obj ), GetCenterX(), 0 ) ); }
		let nObjPhaseTime = nObjCount;
		while( !Obj_BeDeleted( obj ) && nObjCount < 400 ){
			Obj_SetSpeed( obj, 10 + ( nObjCount - nObjPhaseTime ) / 10 );
			__StarLoop( obj, nObjCount, 3, SPELL_STAR_SCALE, 4 );
			yield;
			nObjCount++;
		}
		Obj_Delete( obj );
	}


//////////////////////////////////////////////////////////////////////
//	共通処理
//////////////////////////////////////////////////////////////////////

	/**
	*	固有動作のタスクです。onInitializeTHC()より1フレーム後に呼ばれます。
	*	ここに固有の動作を記述します。
	*
	*	@param nArgv 任意の値
	*/
	task MainTask( let nArgv ){
		PlaySEEx( seKira1 );
		ascent( let i in 0..SPELL_STAR_NUMS ){
			let n = i % SPELL_STAR_COLORTABLE_LENGTH;
			Star( i, Smooth( 0, 180, i, SPELL_STAR_NUMS ), SPELL_STAR_COLORTABLE_RED[ n ], SPELL_STAR_COLORTABLE_GREEN[ n ], SPELL_STAR_COLORTABLE_BLUE[ n ] );
		}
		__Wait( 200 );
		End();
	}

	/**
	*	初期化時に呼ばれます。
	*
	*	@param nArgv 任意の値
	*/
	function onInitializeTHC( let nArgv ){
		LoadSE( seKira1 );
		SetPlayerInvincibility( 300 );
	}

	/**
	*	毎フレームごとに呼ばれます。
	*
	*	@param nArgv 任意の値
	*	@param nCount 現在のカウンタ値
	*	@param nPhase 現在のフェーズ
	*	@param nPhaseCount 現在のフェーズカウンタ値
	*	@param nPrevPhase 1つ前の状態のフェーズ
	*/
	function onMainLoopTHC( let nArgv, let nCount, let nPhase, let nPhaseCount, let nPrevPhase ){
		m_nCenterX = SplineFakeSFS( m_nFirstX, GetCenterX(), nCount, SPELL_STAR_FIRSTPHASE );
		m_nCenterY = SplineFakeSFS( m_nFirstY, GetCenterY(), nCount, SPELL_STAR_FIRSTPHASE );
	}

	/**
	*	終了時に呼ばれます。
	*
	*	@param nArgv 任意の値
	*	@param nCount 現在のカウンタ値
	*	@param nPhase 現在のフェーズ
	*	@param nPhaseCount 現在のフェーズカウンタ値
	*	@param nPrevPhase 1つ前の状態のフェーズ
	*/
	function onFinalizeTHC( let nArgv, let nCount, let nPhase, let nPhaseCount, let nPrevPhase ){
	}


//////////////////////////////////////////////////////////////////////
//--------------------------------------------------------------------
//	スペルカードスクリプト部ここまで
//--------------------------------------------------------------------
//////////////////////////////////////////////////////////////////////

}
