# Patche(パチェ) - 東方弾幕風 統合プレイヤースクリプトフレームワークモドキ version 0.4.1

お願い！＆お知らせ
手が空いている人は以下を手伝ってくれるととても助かります。

- Patcheに関して、ご意見ご要望等お待ちしております。
- また、妖々夢自機と比較して、性能や挙動が違う等ありましたらお知らせ下さい。
  観点はあくまで、妖々夢自機と可能な限り同じ振る舞いをするクローンです。

提供

蒼烏さん / 月の鍵さん
  低速時魔法陣画像

## 目次

1. 概要
2. 使い方(プレイヤー視点)
3. 使い方(開発者視点)
4. 注意点
5. リファレンス
6. ステージ側呼び出しライブラリ
7. サンプルステージ
8. FAQ
9. 二次使用に関して
10. 更新履歴

## コンテンツ

### 1. 概要 ▲

Patche(パチェ)は、東方弾幕風の統合プレイヤースクリプトフレームワークモドキです。
プレイヤースクリプトの開発を手助けできればと思って作りました。
以下のような特徴があります。

- パワーアップアイテムに対応
- ステージスクリプト中でのプレイヤータイプ選択に対応
- いくつかの基本的な処理をフレームワーク中で実装
- 妖々夢時点での自機のクローンをデフォルト機体として実装

フレームワークモドキなのは、ユーザの実装部分を完全にコンポーネント化できず、ユーザが実装時に
基盤部分のコードに手を加える必要があるからです。

### 2. 使い方(プレイヤー視点) ▲

東方弾幕風ディレクトリ\player\ にPatcheディレクトリをコピーしてください。
スクリプト開始時のプレイヤー選択画面でGame Start!(デフォルトの場合)を選ぶと、Patcheでゲームを開始します。
ただし、ステージスクリプト側がPatcheに対応している必要があります。
また、個別インターフェースを実装しているプレイヤースクリプトに関しては、そのプレイヤースクリプトを
単体で直接選択することができます。
この場合はステージ側がPatcheに対応していなくても、選択したプレイヤースクリプト単体でプレイすることができます。

### 3. 使い方(開発者視点) ▲

#### ステージスクリプト側での導入

Library ディレクトリの InitializePatcheSystemOnStage.dnh をお好みの場所に配置し、
ステージスクリプトでインクルードしてください。
Patcheを使用するスクリプトの@Initialize中で一度だけ、以下のコードを記述してください。
以下の初期化コードが組み込まれていない場合（Patcheの使用を想定していないステージの場合）、
ステージは動作しますが、プレイヤースクリプトは読み込まれません。
FLANの共通データを利用していますが、FLANの有無に関わらず動作します。

    initPatche( ステージ側がパワーアップに対応しているか否か: true / false,
    	 Patche側で低速時の効果を描写するか否か: true / false,
    	 EXステージか否か: true / false );

##### プレイヤータイプの選択について

ステージスクリプト中で共通データ"MZC_CD_PLAYERINDEX"に0以上の整数を代入することで
プレイヤータイプの選択とします。
プレイヤータイプが選択されるまで、Patcheは処理を待機しています。
ステージスクリプト開始後、ステージスクリプト中のメニュー画面等でプレイヤータイプを選択し、
プレイヤースクリプトが読み込まれた後にステージ開始というフローを想定しています。
なお、ザッピング対応プレイヤースクリプト以外はプレイヤータイプ選択後に変更はできません。
現時点ではインデックス 0(ルーミア), 5(咲夜幻符), 6(咲夜時符) が実装済みです。

    setPlayerIndex( 自機のインデックス: 0以上の整数 );

##### パワーアップについて

パワー値を操作するには共通データ FLAN_CD_PLAYER_POWER = "PLAYER_POWER" の値を操作します。

    SetCommonDataEx( FLAN_CDNS, FLAN_CD_PLAYER_POWER, パワー値: 0〜128の整数 );

ミス時には共通データ FLAN_CD_PLAYER_POWER = "PLAYER_POWER" の値は16減算されます。
共通データ FLAN_CD_PLAYER_POWER_ENABLE = "PLAYER_POWER_ENABLE" の値がfalseの場合は
パワーアップ処理は行われず、Patcheのパワー値は常にフルパワーモード(128)となります。 簡易版Pアイテム生成ライブラリを添付しています。

#### プレイヤースクリプトの追加

Patcheにプレイヤースクリプトを追加するには以下の処理を行います。

##### 固有処理の実装

Patche\players\プレイヤースクリプト名\ に追加するプレイヤースクリプトファイルを作成し、
各メソッドの固有処理を実装します。
実装すべきメソッドについては、 Patche\players\ひながた.dnh を参考にしてください。
なお、グローバル変数に関しては全プレイヤースクリプトから参照されますので、既存のものと
重複しないように注意してください。
ザッピング対応については、ザッピング対応の項にて述べます。

##### 各メソッドへの参照の実装

実装した固有処理をPatcheから呼び出せるようにします。
Patche\setting\function.dnh の各メソッドの alternative 文に、
追加するプレイヤースクリプトのインデックスに対応する case を追加してください。
例：インデックス7にプレイヤースクリプトを追加する。
onInitialize07() を実装した。

    function onInitialize() {
    	alternative ( m_nPlayerIndex )
    	...
    	case ( 7 ) {
    		onInitialize07();
    	}
    	...
    }

##### 追加するプレイヤースクリプトのインクルード

Patche\setting\playerInclude.dnh に追加するプレイヤースクリプトをインクルードします。

    #include_function ".\players\プレイヤースクリプト名\追加プレイヤー.dnh

##### 追加するスペルカードスクリプトのインクルード

Patche\setting\spellInclude.dnh に追加するプレイヤースクリプトのスペルカードスクリプトをインクルードします。

    #include_script ".\players\プレイヤースクリプト名\追加プレイヤースペルカード.dnh

##### パラメータの設定

Patche\setting\parameter.dnh に追加するプレイヤースクリプトの各パラメータを追加します。
全プレイヤースクリプトで用いられる共通変数のうち、ユーザが変更可能なものもここに記述されています。
記述に関しては parameter.dnh 内の既存の設定を参考にしてください。
基本的に、各配列の要素として追加プレイヤースクリプトの値を追加する形になります。

##### 単体稼働インターフェースの実装

単体稼働インターフェースを実装することで、Patche非対応ステージでも追加プレイヤースクリプトを単体動作させることができます。
この機能は付加的なものであり、必ずしも実装する必要はありません。
実装については、 Patche\XX_ひながたPlayer.dnh を参考にしてください。
なお、単体稼働インターフェースは必ずPatcheディレクトリ直下に配置してください。

##### ザッピング対応

パラメータの設定でザッピングの対応を宣言している場合、リアルタイムで何度でもプレイヤースクリプトを切り替えることができます。
リアルタイムといってもリソースの読み込み等がありますので、ステージ間の遷移時などに変更することをお勧めします。
また、ザッピング実行時にボム使用中であった場合は、ボム終了後にザッピングが実行されます。
ザッピング対応プレイヤースクリプトでは、固有処理の実装において、ザッピング時に全ての
実行中のループが終了するように制御を追加する必要があります。
ひながた.dnhを参考にし、以下のように、現在のプレイヤーインデックスが自分のインデックスと異なれば固有処理部の全ループを終了する
といった制御を行ってください。

    task myTask() {
    	loop {
    		if ( m_nPlayerIndex != 自分のインデックス ) {
    			return;
    		}
    		//自弾発射
    		yield;
    	}
    }

これを行わないと、プレイヤー変更後に変更前のプレイヤーの自弾発射タスクが実行しっぱなしになり、二重に弾を発射してしまう
といった不具合が生じます。

### 4. 注意点 ▲

- 各プレイヤースクリプト中に記述されたグローバル変数は、全プレイヤースクリプトから参照できます。
  当然既存のものと重複する変数名はエラーとなります。
  なるべくグローバル変数を用いないことをおすすめします。
- 言うまでもないことですが、 Patche\setting\ の各ファイルに記述されている変数名やメソッド名を
  変更したり削除したりしないでください。Patcheが正常に動作しなくなります。
- 画像、音ファイルの読み込みはPatche側で行います。プレイヤースクリプト側で読み込みを行う必要はありません。
  読み込ませたいファイルは Patche\setting\parameter.dnh に記述してください。

### 5. リファレンス ▲

Patcheに用意されているメソッドおよび変数のリファレンスです。

#### メソッド

updatePower( 引数: 1 )
  引数1: 各パワー値に対応した要素を持つ要素数9の配列
  返値: 引数の要素のうち現時点のパワー値に対応した値
  現時点でのパワー値に対応した値を返します。
  引数の最初の要素がパワー0の場合の値、最後の要素がフルパワー時の値となります。
  パワー値の段階は、0, 8, 16, 32, 48, 64, 80, 96, 128です。
updatePowerEx( 引数: 2 )
  引数1: 各パワー値に対応した要素を持つ配列
  引数2: 各パワー値の要素を持つ配列
  返値: 引数1の要素のうち現時点のパワー値に対応した値
  現時点でのパワー値に対応した値を返します。
  引数1の最初の要素がパワー0の場合の値、最後の要素がフルパワー時の値となります。
  パワー値の段階は引数2で定義します。
  引数1と引数2の要素数は同じである必要があります。
GetGapLength( 引数: 4 )
  引数1: 点Aのx座標
  引数2: 点Aのy座標
  引数3: 点Bのx座標
  引数4: 点Bのy座標
  返値: 2点AB間の距離
  2つの点AB間の相対距離を取得します。
  END氏の汎用関数集を利用しています。
GetGapAngle( 引数: 4 )
  引数1: 点Aのx座標
  引数2: 点Aのy座標
  引数3: 点Bのx座標
  引数4: 点Bのy座標
  返値: 点Aから点B間への角度
  点Aから点B間への角度を取得します。
  END氏の汎用関数集を利用しています。
GetGapX( 引数: 3 )
  引数1: 点Aのx座標
  引数2: 点Bまでの距離
  引数3: 点Bへの角度
  返値: 点Aからある距離、角度にある点Bのx座標
  点Aからある距離、角度にある点Bのx座標を取得します。
  END氏の汎用関数集を利用しています。
GetGapY( 引数: 3 )
  引数1: 点Aのy座標
  引数2: 点Bまでの距離
  引数3: 点Bへの角度
  返値: 点Aからある距離、角度にある点Bのy座標
  点Aからある距離、角度にある点Bのy座標を取得します。
  END氏の汎用関数集を利用しています。
Min( 引数: 2 )
  引数1: 値1
  引数2: 値2
  返値: 値1と値2のうち小さい値
  値1と値2のうち小さい値を取得します。
Max( 引数: 2 )
  引数1: 値1
  引数2: 値2
  返値: 値1と値2のうち大きい値
  値1と値2のうち大きい値を取得します。
MinMax( 引数: 3 )
  引数1: 値
  引数2: 最小値
  引数3: 最大値
  返値: 補正された値
  値を最小値と最大値の範囲内に補正します。
__Wait( 引数: 1 )
  引数1: 値
  値の回数だけyieldを呼び出します。
Smooth( 引数: 4 )
  引数1: 内分カウンタの初期値
  引数2: 内分カウンタの最終値
  引数3: 現在時間
  引数4: 最終時間
  返値: 現在時間に対応する値
  初期値から最終値の間で等速変化する現在時間の時点での値を返します。
Accelerate( 引数: 4 )
  引数1: 内分カウンタの初期値
  引数2: 内分カウンタの最終値
  引数3: 現在時間
  引数4: 最終時間
  返値: 現在時間に対応する値
  初期値から最終値の間で加速変化する現在時間の時点での値を返します。
SlowDown( 引数: 4 )
  引数1: 内分カウンタの初期値
  引数2: 内分カウンタの最終値
  引数3: 現在時間
  引数4: 最終時間
  返値: 現在時間に対応する値
  初期値から最終値の間で減速変化する現在時間の時点での値を返します。

#### メンバ変数

m_sImgPlayerBorder
  低速時に描画する魔法陣のファイルパスを格納します。
  解像度は高さ64px、幅64pxです。
m_sImgPlayerDot
  低速時に描画するドットのファイルパスを格納します。
  解像度は高さ16px、幅16pxです。
m_sSePlayerPowerupSound
  パワーアップ時に再生する効果音のファイルパスを格納します。
m_sSePlayerShotSound
  ショット時に再生する効果音のファイルパスを格納します。

#### メンバ変数(読み取り専用)

csd
  GetCurrentScriptDirectory() の値が格納されます。
players
  GetCurrentScriptDirectory() ~ "players\" の値が格納されます。
  players\追加プレイヤースクリプトディレクトリ で各プレイヤースクリプトディレクトリにアクセスできます。
m_nPlayerIndex
  プレイヤースクリプトのインデックスが格納されます。
m_bIsPatche
  Patche本体からの起動か否かが格納されます。
m_nCount
  現在の経過フレーム(Patche起動時が0)が格納されます。
m_nPlayerCount
  プレイヤースクリプトを設定(変更)してからの経過フレーム(設定・変更時が0)が格納されます。
m_nMissedCount
  ミス中の経過フレーム(ミスした瞬間が0、復帰後は-1にリセット)が格納されます。
m_nBombCount
  ボム中の経過フレーム(ボムを使用した瞬間が0、ボム終了後は-1にリセット)が格納されます。
m_bIsSlowMove
  低速移動中か否かが格納されます。
m_nPower
  現在のパワーが格納されます。
m_bIsFullPowerFrame
  フルパワーモードに達した瞬間か否かが格納されます。
m_bIsShooting
  ショットボタンが押されているか否かが格納されます。
m_bIsUserPushing
  ユーザーボタンが押されているか否かが格納されます。
m_bIsMoveRight
  右に移動中か否かが格納されます。
m_bIsMoveLeft
  左に移動中か否かが格納されます。
m_bIsMoveStraight
  まっすぐ移動中か否かが格納されます。
m_nSlowKeyTime
  最後に低速キーを押した / 放したフレームが格納されます。
m_nSlowKeyPassedTime
  最後に低速キーを押して / 放してからの経過フレームが格納されます。
m_nShotKeyTime
  最後にショットキーを押した / 放したフレームが格納されます。
m_nShotKeyPassedTime
  最後にショットキーを押して / 放してからの経過フレームが格納されます。
m_nUserKeyTime
  最後にユーザーキーを押した / 放したフレームが格納されます。
m_nUserKeyPassedTime
  最後にユーザーキーを押して / 放してからの経過フレームが格納されます。

#### 共通データ(ステージスクリプト側からのアクセスのみ想定)

##### 名前空間: FLAN_CDNS = "__FLAN_FRAMEWORK"

FLAN_CD_PLAYER_POWER = "PLAYER_POWER"
  入力値: 0〜128の整数
  現在のパワー値が格納されます。
FLAN_CD_PLAYER_POWER_ENABLE = "PLAYER_POWER_ENABLE"
  入力値: true / false
  ステージ側がパワーアップ処理に対応しているか否かが格納されます。

##### 名前空間: MZC_CDNS_PLAYER = "MZC_CDNS_PLAYER"

MZC_CD_PLAYERINDEX = "MZC_CD_PLAYERINDEX"
  入力値: 0以上の整数
  使用するプレイヤータイプのインデックスが格納されます。
MZC_CD_PLAYERSLOWEFFECT_ONSTAGE = "MZC_CD_PLAYERSLOWEFFECT_ONSTAGE"
  入力値: true / false
  低速時の魔法陣の描写をPatche側で行わずにステージ側で行うか否かが格納されます。
MZC_CD_PLAYER_ISEXMODE = "MZC_CD_PLAYER_ISEXMODE"
  入力値: true / false
  EXステージか否かが格納されます。
  EXステージの場合は非フルパワー時でもアイテムの回収が可能です。
MZC_CD_PLAYER_ISPATCHE = "MZC_CD_PLAYER_ISPATCHE"
  入力値: true / false
  Patche本体が呼び出されたか否かが格納されます。
MZC_CD_PLAYER_ISBOMBED_FRAME = "MZC_CD_PLAYER_ISBOMBED_FRAME"
  入力値: true / false
  ボムを使用した瞬間か否かが格納されます。
MZC_CD_PLAYER_ITEM_COLLECT_LINE = "MZC_CD_PLAYER_ITEM_COLLECT_LINE"
  入力値: -1以上の整数
  現在のアイテム回収ラインが格納されます。

### 6. ステージ側呼び出しライブラリ ▲

#### Patche初期化ライブラリ

Library\InitializePatcheSystemOnStage.dnh です。
必要に応じてステージスクリプトからインクルードしてください。

##### Patche初期化

共通データを用いずに平易にPatcheを初期化するためのラッパーメソッドを実装しました。
ステージスクリプト中で使用してください。

initPatche( 引数: 3 )
  引数1: ステージ側がパワーアップに対応しているか否か
  引数2: Patche側で低速時の効果を描写するか否か
  引数3: EXステージか否か
  Patcheを初期化します。
  initPatche() は@Initialize中で一度だけ呼び出してください。
setPlayerIndex( 引数: 1 )
  引数1: 自機のインデックス
  呼び出すプレイヤースクリプトを設定・変更します。
  変更できるのは現在のプレイヤースクリプトがザッピングに対応している場合のみです。

##### 簡易パワーアップシステム

Pアイテムを実装せずに手っ取り早くパワーアップ対応型自機を試すために、簡易パワーアップシステムを実装しました。
ステージスクリプト側での導入および
プレイヤータイプの選択についてで実装したコードの代わりに、以下のコードを@Initialize中に記述してください。

    callSimplePowerupSystem( 使用するプレイヤーのインデックス: 0以上の整数, 初期パワー値: -1(フルパワーに固定の場合)または0〜128の整数 );

これにより、点アイテムをPアイテムに見立ててパワーアップ処理を行います。
Pointは0〜128で変動し、128個を越える点アイテムを取得しても、自動的に128個に補正されます。

#### Pアイテム生成ライブラリ

Patche以外からも利用できる簡易的なPアイテム生成ライブラリを実装しました。
Library\ItemLibrary\Item.dnh です。
必要に応じてステージスクリプトからインクルードしてください。
Pアイテムは取得時に名前空間: FLAN_CDNS = "__FLAN_FRAMEWORK"のFLAN_CD_PLAYER_POWER = "PLAYER_POWER"
を1増加します。プレイヤースクリプト側で値を取得し、対応してください。
プレイヤースクリプトのアイテム回収ラインは共通データを用いて取得しています。

DropPItem( 引数: 5 )
  引数1: アイテムをドロップするX座標
  引数2: アイテムをドロップするY座標
  引数3: アイテムをドロップする範囲
  引数4: アイテム数
  引数5: EXステージか否か
  Pアイテムをドロップします。
  アイテムの大小はアイテム数より自動的に判断されます。
DropPItemOnMissed( 引数: 1 )
  引数1: EXステージか否か
  プレイヤーの状態を監視し、ミス時にPアイテムを周囲にドロップするタスクです。
  @Initializeで一度だけ呼び出してください。
MZC_PITEM_IMAGE
  Pアイテムの画像が格納されます。
  同封のitem.pngを利用できます。

#### パワー値描写ライブラリ

簡易的にパワー値を描写するライブラリです。
ステージ側から呼び出します。
Library\ItemLibrary\DrawPower.dnh です。
必要に応じてステージスクリプトからインクルードしてください。

DrawPower( 引数: なし )
  パワー値を右下に描写します。
  描画ループ内で呼び出してください。

### 7. サンプルステージ ▲

簡易パワーアップシステムを用いてパワーアップに対応し、かつステージスクリプト中で自機選択可能な
ステージのサンプルを添付します。
デフォルトのEXルーミアステージなのですが、そのままでは難しすぎてサンプルどころではないので、
ざっと難易度調整してあります。
ExRumia_PatcheSample ディレクトリを 東方弾幕風ディレクトリ\script\ 以下にコピーしてください。
弾幕風メニューより、 【Patche対応サンプル】 ExRumiaステージ を選択してお試しください。

### 8. FAQ ▲

なんでパチェ？
  Player Airframe なんたらかんたらの略です。
  思いつきませんでした。
  親切なひとが名前を考えてくれました。
  Player Airframe Template with CHaracter Enumeratorの略ということになりました。
  ありがとうございました。
なんで作ったの？
  Pアイテム対応自機が欲しかったのと、ステージ側で自機選択がしたかったのが理由です。
  誰も使ってくれなかったら次作で自分で使うからいいです。
なんかややこしい気がする
  開発者向けですので…。
  一般プレイヤーの人が導入する場合は、単にplayerディレクトリに配置するだけなので簡単かと。

### 9. 二次使用ガイドライン ▲

無断使用、無断再配布、無断改変すべて自由です。
ただし改変して再配布したものにも全て上記と同じ条件が求められます。
ただし追加したプレイヤースクリプトは上記制限の適用外となります。
また、以下のリソースは再配布および改変不可とします。
再配布の際は、これらのリソースは削除してから配布してください。

- common\img\rental\以下
- common\se\rental\以下

### 10. 更新履歴 ▲

0.4.1
  霊符ボムの挙動を変更
  魔理沙Bレーザーのテクスチャを変更
  誘導弾の追尾処理を軽量化
0.4.0
  霊符、夢符追加
  幻符誘導弾のルーチン修正
  通常弾、ボムのダメージ調整
  ボム処理のタイミング修正（発動時の時間停止を考慮に）
  現在のアイテム回収ラインを格納する共通データ追加
  効果音修正
  アイテムライブラリ修正
  その他細部修正
0.3.2
  外部借用リソースの一部を削除、マニュアル修正
0.3.1
  攻撃力調整
  パワーアップ時に攻撃力固定に
  幻符軽量化
0.3.0
  ライブラリ追加
  汎用関数追加
  魔符、恋符実装
  時符の攻撃力を少しだけ強化
  名前がつきました
0.2.0
  単体稼働インターフェースに対応し、単体呼び出しを可能にした。
  スペルカード呼び出し処理はPatcheから切り離し、各プレイヤースクリプトでの呼び出しとした。（自由度を増すため）
  ザッピング対応
  各種ライブラリ、メソッド、変数追加
  各プレイヤースクリプト調整
0.1.0
  とりあえず形になった。
  ルーミア(0)と幻符咲夜さん(5)と時符咲夜さん(6)を実装。