■スクリプト記述方法■

■スクリプトのフォーマット

スクリプトファイルのフォーマットは以下の形式を使用できます。
複数フォーマットが混在する状態で、#include を使用しファイル結合した場合は、
内部的には全てUnicodeに変換してファイルを結合します。
(不要な変換処理が入るため、フォーマットは1つに統一した方が速く動作します。)
種別 説明
Shift-JIS テキストエディタで、SJIS,Shift-JISを選択することで、保存することができる形式です。
(0.12mやph3 [.0]以前は、この形式のファイルのみ読み込むことができました)
日本語設定のWindowsでのみ正常に表示することができます。
Unicode (UTF16LE) テキストエディタで、Unicode,UTF16,UTF16LEを選択することで、保存することができる形式です。
ファイル先頭にBOM(Byte Order Mark)が必要です。
(Byte Order Markは、通常はテキストエディタが自動的に付加してくれます)



■スクリプトヘッダ

スクリプトヘッダとは、弾幕風本体のメニューへの登録や自機スクリプトとして認識させるために
スクリプトの先頭に記述するテキストのことです。
「#~~~」で記述し、以下の種類があります。
要素 説明
#東方弾幕風[xxx] 「#東方弾幕風」を記述することで東方弾幕風本体のメニューに登録することができます。
また「#TouhouDanmakufu」でも同様の意味があります。

以下の種類があります。
・#東方弾幕風[Single]:単発スクリプトとしてメニューに登録します。
・#東方弾幕風[Plural]:連続再生スクリプトとしてメニューに登録します。
・#東方弾幕風[Stage]:ステージスクリプトとしてメニューに登録します。
・#東方弾幕風[Package]:パッケージスクリプトとしてメニューに登録します。
・#東方弾幕風[Player]:自機スクリプトとして弾幕風に認識させます。
#ScriptVersion[3] スクリプトバージョン3であることを示します。
スクリプトバージョン3のみしか再生できないため必須です。
#ID["XXX"] スクリプトのIDです。
内部的にスクリプトを区別するのに使用します。
できるだけ他のスクリプトと一致しない名称にする方が良いです。
省略可能です。
省略した場合はファイル名になります。
#Title["XXX"] メニューのタイトルに使用される文字列です。
#Text["XXX"] メニューでの説明に使用される文字列です。
#Image["XXX"] メニューの画像に使用される画像ファイルへのパスです。
640×480の画像を指定します。
実行ファイル位置からの相対パスです。
ただし[./~]のようにパスの最初に「./」をかくと、スクリプトファイルのあるフォルダからの相対パスになります。

省略可能です。
#System["XXX"] システムスクリプトへのパスです。
システムスクリプトではスコアや残機、敵ライフの表示などを行います。

実行ファイル位置からの相対パスです。
ただし[./~]のようにパスの最初に「./」をかくと、スクリプトファイルのあるフォルダからの相対パスになります。

省略可能です。
省略した場合「/script/default_system/Default_System.txt」のシステムスクリプトが適応されます。
#Background["XXX"] 背景スクリプトへのパスです。
実行ファイル位置からの相対パスです。
ただし[./~]のようにパスの最初に「./」をかくと、スクリプトファイルのあるフォルダからの相対パスになります。

省略可能です。
省略した場合、背景は黒となります。

内部的には、このパスを使用して、LoadScript→StartScriptしているだけです。
省略した場合でも、独自に背景用のスクリプトをLoadScript→StartScriptすれば背景は描画されます。
#BGM["XXX"] BGMに使用されるファイルへのパスです。
実行ファイル位置からの相対パスです。
ただし[./~]のようにパスの最初に「./」をかくと、スクリプトファイルのあるフォルダからの相対パスになります。

省略可能です。
省略した場合は無音になります。
内部的には、このパスを使用して、音声再生をしているだけです。
省略した場合でも、独自に音声再生を行えばBGMは鳴ります。
#Player["XXX","YYY",...] このスクリプトで使用できる自機スクリプトへのパスです。
「,」で区切って複数の自機を登録します。
実行ファイル位置からの相対パスです。
ただし[./~]のようにパスの最初に「./」をかくと、スクリプトファイルのあるフォルダからの相対パスになります。

省略可能です。
省略した場合は「/script/player/」下のすべての自機スクリプトが使用可能になります。
#ReplayName["XXX"] リプレイ用の自機名称です。
8文字以内で指定します。



■組み込みルーチン

組み込みルーチンは「@XXX」で記述される特別なルーチンのことです。
特定のタイミングで弾幕風本体から自動的に呼び出されます。
以下の種類があります。
種類 説明
@Initialize スクリプト初期化時に一度だけ呼び出されます。
1回目の@MainLoopが呼び出される直前に呼ばれます。
@Finalize スクリプト終了時に一度だけ呼び出されます。
@MainLoop スクリプトがアクティブな場合に毎フレーム一度ずつ呼び出されます。
@Loading 主にLoadScriptInThreadでのスクリプト読み込み時に呼び出され、
別スレッドでの初期化を行います。

テクスチャや音声の読み込みにのみ使用でき、
オブジェクトの生成などを行うとエラーになります。
乱数も使用できません。
(実行タイミングが制御できないため、リプレイの再生に影響が出るため。)
@Event 特定のイベントが発生したときに呼び出されます。
イベントを参照願います。



■Singleスクリプト

単発再生用スクリプトです。
スクリプトに「#東方弾幕風[Single]」と記述することで認識されます。
通常は敵のスペルカード1枚分に相当します。
以下に記述例を示します。

	#東方弾幕風[Single]
	#ScriptVersion[3]
	#Title["星符「ミッドナイトレヴァリエ」"]
	#Text["Exルーミア最初のスペルカード:星符「ミッドナイトレヴァリエ」"]
	#Image["./img/ExRumia(星符「ミッドナイトレヴァリエ」).png"]
	#Background["script/default_system/Default_Background_IceMountain.txt"]

	#include"script/default_system/Default_ShotConst.txt"
	#include"script/default_system/Default_Effect.txt"

	let objEnemy;
	let bConcentrationMotion = false;
	@Initialize
	{
		objEnemy = ObjEnemy_Create(OBJ_ENEMY_BOSS);
		ObjEnemy_Regist(objEnemy);
		ObjEnemy_SetDamageRate(objEnemy, 10, 10);//披ダメージを10%に設定
		TWork;
		TRender;
		TEnd;

		DeleteShotAll(TYPE_ALL, TYPE_ITEM);//出現と同時に敵弾を全て削除	
	}

	@MainLoop
	{
		let ex = ObjMove_GetX(objEnemy);
		let ey = ObjMove_GetY(objEnemy);
		ObjEnemy_SetIntersectionCircleToShot(objEnemy, ex, ey, 32);//当たり判定(自弾)登録
		ObjEnemy_SetIntersectionCircleToPlayer(objEnemy, ex, ey, 24);//当たり判定(体当たり)登録

		yield;
	}

	@Event
	{
		alternative(GetEventType())
		case(EV_REQUEST_LIFE)
		{
			SetScriptResult(1500);//ライフを1500に設定
		}
		case(EV_REQUEST_TIMER)
		{
			SetScriptResult(60);//時間制限を60秒に設定
		}
		case(EV_REQUEST_SPELL_SCORE)
		{
			SetScriptResult(30000);//スペルカードボーナスを30000に設定
		}
	}


	//~~~敵の制御など

	//----------------------------------------------------
	//終了待機タスク
	//----------------------------------------------------
	task TEnd
	{
		while(ObjEnemy_GetInfo(objEnemy, INFO_LIFE) > 0)
		{
			yield;
		}

		let ex = ObjMove_GetX(objEnemy);
		let ey = ObjMove_GetY(objEnemy);
		TExplosionA(ex, ey, 10, 0.6);
		DeleteShotAll(TYPE_ALL, TYPE_ITEM);//敵弾を全て削除	

		//連続再生の場合は敵を削除することで、
		//次の段階に進みます。
		//必ず削除してください。
		Obj_Delete(objEnemy);

		loop(30){yield;}

		//最後はスクリプトをクローズしてください
		CloseScript(GetOwnScriptID());
	}



■連続再生スクリプト

連続再生用スクリプトです。
スクリプトに「#東方弾幕風[Plural]」と記述することで認識されます。
通常は敵のボス1体分に相当します。
以下に記述例を示します。

	#東方弾幕風[Plural]
	#ScriptVersion[3]
	#Title["Exルーミアスクリプト連続再生"]
	#Text["Exルーミアスペルカード"]
	#Image["./img/ExRumia(星符「ミッドナイトレヴァリエ」).png"]
	#Background["script/default_system/Default_Background_IceMountain.txt"]

	@Initialize
	{
		TPlural();
	}

	@MainLoop
	{
		yield;
	}

	@Finalize
	{
	}


	task TPlural
	{
		let dir = GetCurrentScriptDirectory();

		//ボスシーンを作成します。
		let obj = ObjEnemyBossScene_Create();
		ObjEnemyBossScene_Add(obj, 0, dir ~ "ExRumia01.txt");
		ObjEnemyBossScene_Add(obj, 0, dir ~ "ExRumiaSpell01.txt");
		ObjEnemyBossScene_LoadInThread(obj);
		ObjEnemyBossScene_Regist(obj);

		//敵ボスシーンが終了するまで待機
		while(!Obj_IsDeleted(obj))
		{
			yield;
		}

		//スクリプト終了
		CloseScript(GetOwnScriptID());
	}



■Stageスクリプト

ステージスクリプトです。
スクリプトに「#東方弾幕風[Stage]」と記述することで認識されます。
通常は1ステージ分に相当します。
以下に記述例を示します。

	#東方弾幕風[Stage]
	#ScriptVersion[3]
	#Title["EXルーミアテストステージ"]
	#Text["EXルーミアテストステージ"]
	#Image["./img/ExRumia(星符「ミッドナイトレヴァリエ」).png"]
	#Background["script/default_system/Default_Background_IceMountain.txt"]

	@Initialize
	{
		TStage();
	}

	@MainLoop
	{
		yield;
	}

	@Finalize
	{
	}


	task TStage
	{
		let dir = GetCurrentScriptDirectory();

		//ボス再生
		let path = dir ~ "ExRumia_Plural.txt";
		let idScript = LoadScriptInThread(path);
		loop(60){yield;}//1秒くらいあれば、コンパイル完了すると思われる。
		StartScript(idScript);

		//敵ボスシーンが終了するまで待機
		while(!IsCloseScript(idScript))
		{
			yield;
		}

		//~~~敵の出現やボスの出現を繰り返す。

		loop(240){yield;}

	    //ステージ終了
		CloseStgScene();
	}



■自機スクリプト

自機スクリプトです。
スクリプトに「#東方弾幕風[Player]」と記述することで自機用のスクリプトとして認識されます。
以下に記述例を示します。

	#Image["./ExRumiaImage.png"]


	let objPlayer = GetPlayerObjectID();
	let objSlowShot = ID_INVALID;
	let current = GetCurrentScriptDirectory();
	@Initialize
	{
		let path = current ~ "Default_Player_RumiaShotData.txt";
		LoadPlayerShotData(path); //自弾画像ロード

		ObjPlayer_AddIntersectionCircleA(objPlayer, 0, 0, 1, 20); //当たり判定登録

		TImage();//自機描画用タスク起動
		TShot();//弾発射用タスク起動
		TMagicCircle();//無敵時間魔法陣タスク起動
	}

	@MainLoop
	{
		yield;
	}

	@Finalize
	{
	}

	@Event
	{
		alternative(GetEventType())
		case(EV_REQUEST_SPELL)
		{
			//スペルカード要求
			let spell = GetPlayerSpell();//残りスペル数
			if(spell >= 1)
			{
				SetScriptResult(true);//スペル発動可能
				SetPlayerSpell(spell-1);//スペル数を1減らす
				TSpell();//スペルタスク起動
			}
			else
			{
				SetScriptResult(false);//スペル発動不可
			}
		}
		case(EV_HIT)
		{
			//被弾
			TExplosion();
		}
		case(EV_PLAYER_REBIRTH)
		{
			//復帰
			SetPlayerSpell(3);
			SetPlayerInvincibilityFrame(180);
		}
	}

	//~~~省略



■メニュー系スクリプト

一時停止中などに呼び出されるスクリプトで、
メニュー系シーンのカスタマイズを行えます。
サンプルは各デフォルトスクリプトを参照お願いします。

いずれもSetScriptResultで特定の値を設定する必要があります。
これらのスクリプトでは自機や弾などの操作を行うことはできません。

種類 説明
一時停止 一時停止(ポーズ)中に呼び出されるスクリプトです。
システムスクリプト中で「SetPauseScriptPath」で使用スクリプトを設定します。
デフォルトでは「/script/default_system/Default_Pause.txt」が使用されます。

SetScriptResultに以下のいずれかを設定する必要があります。
・RESULT_CANCEL:再開
・RESULT_END:スクリプト:再生終了
・RESULT_RETRY:リトライ
STGシーン終了 ゲームオーバーやステージクリア時に呼び出されます。
デフォルトでは「/script/default_system/Default_EndScene.txt」が使用されます。

SetScriptResultに以下のいずれかを設定する必要があります。
・RESULT_SAVE_REPLAY:リプレイ保存
・RESULT_END:スクリプト:再生終了
・RESULT_RETRY:リトライ
リプレイ登録 リプレイ登録時に呼び出されます。
デフォルトでは「/script/default_system/Default_ReplaySaveScene.txt」が使用されます。

SetScriptResultに以下のいずれかを設定する必要があります。
・RESULT_CANCEL:キャンセル
・RESULT_END:リプレイ保存終了



■アイテムカスタムスクリプト
アイテムカスタムスクリプト内では、弾消しイベントやアイテム取得イベントを受けられます。
アイテム操作用のスクリプトはStartItemScript関数で起動します。
以下にアイテム動作カスタムスクリプトの記述例を示します。
	@Initialize
	{
		//弾削除時得点アイテム自動作成無効化
		SetDefaultBonusItemEnable(false);

		//ユーザ定義アイテムデータ読み込み
		let dir = GetCurrentScriptDirectory();
		LoadItemData(dir ~ "ItemData.txt")
	}

	@Event
	{
		alternative(GetEventType())
		case(EV_GET_ITEM)
		{
			//アイテム取得イベント
			let itemType = GetEventArgument(0); //アイテム種別取得
			let objItem = GetEventArgument(1); //アイテムオブジェクト取得

			//アイテム取得時処理
		}
		case(EV_DELETE_SHOT_TO_ITEM)
		{
			//弾削除時アイテム作成イベント
			let objShot = GetEventArgument(0); //オブジェクト取得
			let objPos = GetEventArgument(1); //弾オブジェクト座標取得([0]=x, [1]=y)

			//弾削除時アイテム作成処理
			TUserItem(objPos[0], objPos[1]);
		}
	}

	//ユーザ定義アイテム作成
	task TUserItem(let itemX, let itemY)
	{
		let obj = CreateItemU1(1, itemX, itemY, 10000);
		ObjItem_SetDefinedMovePatternA1(obj, ITEM_MOVE_TOPLAYER);
	}
	


■弾カスタムスクリプト
弾カスタムスクリプト内では、弾消しイベントなどを受けられます。
スクリプトはStartShotScript関数で起動します。
以下に弾動作カスタムスクリプトの記述例を示します。
	@Initialize
	{
		//弾消し(即消時)イベント有効
		SetShotDeleteEventEnable(EV_DELETE_SHOT_IMMEDIATE, true);
	}

	@Event
	{
		alternative(GetEventType())
		case(EV_DELETE_SHOT_IMMEDIATE)
		{
			//弾消し時イベント有効
			let objShot = GetEventArgument(0); //オブジェクト取得
			let objPos = GetEventArgument(1); //弾オブジェクト座標取得([0]=x, [1]=y)

			//弾消し時動作記載
		}
	}
	


■パッケージスクリプト

タイトル画面、リプレイ一覧画面、ステージの連続再生など、
すべての機能を作成するためのスクリプトです。

パッケージスクリプト専用の関数は パッケージスクリプト専用関数 を参照お願いします。

記述方法は以下のサンプルスクリプトを参照お願いします。
/script/ExRumia/ExRumia_Package_Main.txt

実行ファイルをパッケージスクリプト再生専用にするには、「定義ファイル(th_dnh.def)」を参照お願いします。



■イベント(@Event)

@Eventは特定のタイミングで呼び出されます。
イベントの種類は、「GetEventType」で取得できます。
引数のあるイベントの場合は「GetEventArgument」で取得でき、
返値が必要なイベントの場合は「SetScriptResult」で返値を設定します。

組み込みのイベントには、以下の種類があります。
イベント種類 説明
EV_REQUEST_LIFE 敵ボスのライフの要求です。
敵ボススクリプトのみで呼び出されます。

real値を「SetScriptResult」で返す必要があります。
要求された場合に無視するとエラーになります。
EV_REQUEST_TIMER 敵ボスのタイマー要求です。
敵ボススクリプトのみで呼び出されます。

real値を「SetScriptResult」で返す必要があります。
無視すると、無制限になります。
EV_REQUEST_IS_LAST_SPELL ラストスペル要求です。
敵ボススクリプトのみで呼び出されます。

boolean値を「SetScriptResult」で返す必要があります。
無視すると、ラストスペルではなくなります。
EV_REQUEST_IS_DURABLE_SPELL 耐久スペル要求です。
敵ボススクリプトのみで呼び出されます。

boolean値を「SetScriptResult」で返す必要があります。
無視すると、耐久スペルではなくなります。
EV_REQUEST_SPELL_SCORE スペルカードスコア要求です。
敵ボススクリプトのみで呼び出されます。

boolean値を「SetScriptResult」で返す必要があります。
無視すると、0点になります。
EV_TIMEOUT 敵スペルのタイムアウト通知です。
アクティブな全スクリプトに通知されます。
EV_START_BOSS_SPELL 敵スペルカード開始通知です。
アクティブな全スクリプトに通知されます。
EV_GAIN_SPELL スペルカード取得通知です。
アクティブな全スクリプトに通知されます。
EV_START_BOSS_STEP ボスの1ステップ開始通知です。(Singleの1スクリプト相当開始通知です。)
アクティブな全スクリプトに通知されます。
EV_END_BOSS_STEP ボスの1ステップ終了通知です。(Singleの1スクリプト相当終了通知です。)
アクティブな全スクリプトに通知されます。
EV_PLAYER_SHOOTDOWN 自機撃墜通知です。
アクティブな全スクリプトに通知されます。
EV_PLAYER_SPELL 自機スペル発動通知です。
アクティブな全スクリプトに通知されます。
EV_PLAYER_REBIRTH 自機復帰通知です。
アクティブな全スクリプトに通知されます。
EV_PAUSE_ENTER 一時停止開始通知です。
アクティブな全スクリプトに通知されます。

音声の停止操作などを想定しています。
このイベント内では、乱数の使用、敵/弾オブジェクトの生成などSTGシーンに影響を与える処理は行わないでください。
リプレイがずれます。
EV_PAUSE_LEAVE 一時停止解除通知です。
アクティブな全スクリプトに通知されます。

音声の再開操作などを想定しています。
このイベント内では、乱数の使用、オブジェクトの生成などSTGシーンに影響を与える処理は行わないでください。
リプレイがずれます。
EV_REQUEST_SPELL 自機スペル開始要求です。
自機スクリプトのみで呼び出されます。

boolean値を「SetScriptResult」で返す必要があります。
スペルカードを呼び出せる場合にtrueを返します。
要求された場合に無視するとエラーになります。
EV_GRAZE かすり通知です。
自機スクリプトのみで呼び出されます。

かすりのエフェクトや効果音を再生するのに使用します。
GetEventArgument(0):前フレームのかすり回数(real)
GetEventArgument(1):前フレームのかすった弾IDのリスト(real配列)
GetEventArgument(2):前フレームのかすった弾座標のリスト(real配列[index][x, y])
EV_HIT 撃墜通知です。
自機スクリプトのみで呼び出されます。

自機の撃墜エフェクトや効果音を再生するのに使用します。
GetEventArgument(0):自機に当たった敵/弾ID(real)
EV_GET_ITEM アイテム取得通知です。
自機スクリプト、アイテムスクリプトのみで呼び出されます。

GetEventArgument(0)でどのアイテムを取得したかを確認できます。
・ITEM_POWER:パワーアップアイテム
・ITEM_POWER_S:パワーアップアイテム(小)
・ITEM_SPELL:スペル(ボム)アイテム
・ITEM_SPELL_S:スペル(ボム)アイテム(小)
・ITEM_POINT:点アイテム
・ITEM_POINT_S:点アイテム(小)

GetEventArgument(1)でアイテムオブジェクトのIDを取得できます。
EV_DELETE_SHOT_IMMEDIATE 敵弾の削除通知です。
弾動作カスタムスクリプトで呼び出されます。
弾動作カスタムスクリプトでのイベント通知は、
 SetShotDeleteEventEnable(EV_DELETE_SHOT_IMMEDIATE, true);
を呼び出すと有効になります。

GetEventArgument(0)で弾オブジェクトのIDを取得できます。
GetEventArgument(1)で弾座標を取得できます。(real配列 [x, y])
EV_DELETE_SHOT_TO_ITEM 敵弾のアイテム化通知です。
アイテム動作カスタムスクリプトで呼び出されます。

GetEventArgument(0)で弾オブジェクトのIDを取得できます。
GetEventArgument(1)で弾座標を取得できます。(real配列 [x, y])
EV_DELETE_SHOT_FADE 敵弾のフェード削除通知です。
弾動作カスタムスクリプトで呼び出されます。
弾動作カスタムスクリプトでのイベント通知は、
 SetShotDeleteEventEnable(EV_DELETE_SHOT_FADE, true);
を呼び出すと有効になります。

GetEventArgument(0)で弾オブジェクトのIDを取得できます。
GetEventArgument(1)で弾座標を取得できます。(real配列 [x, y])

独自にイベントを通知したい場合は「NotifyEvent」もしくは「NotifyEventAll」関数を呼び出します。
その場合のイベント種別は、以下の値を使用してください。
イベント種類 説明
EV_USER_SYSTEM システムスクリプト用のユーザ定義イベント値です。
EV_USER_SYSTEM~EV_USER_SYSTEM + EV_USER_COUNT までの値を指定できます。
EV_USER_STAGE ステージ(敵)スクリプト用のユーザ定義イベント値です。
EV_USER_STAGE~EV_USER_STAGE + EV_USER_COUNT までの値を指定できます。
EV_USER_PLAYER 自機スクリプト用のユーザ定義イベント値です。
EV_USER_PLAYER~EV_USER_PLAYER + EV_USER_COUNT までの値を指定できます。
EV_USER_PACKAGE パッケージスクリプト用のユーザ定義イベント値です。
EV_USER_PACKAGE~EV_USER_PACKAGE + EV_USER_COUNT までの値を指定できます。
EV_USER ユーザ定義イベント値です。
EV_USER~EV_USER + EV_USER_COUNT までの値を指定できます。