code:
//=============================================================================
// DevToolsManage.js
// ----------------------------------------------------------------------------
// (C)2015 Triacontane
// This software is released under the MIT License.
// http://opensource.org/licenses/mit-license.php
// ----------------------------------------------------------------------------
// Version
// 2.10.2 2021/04/10 タイトルカット設定時にCTRLキーを押し続けているとカットしなくなる機能が不完全だったので無効化
// 2.10.1 2019/05/26 高速化有効時にメッセージ強制スキップのみを無効化する設定を追加しました。
// 2.9.1 2019/05/19 DynamicDatabase.jsと併用したとき、データベースリロード機能を使うと動的データベースの内容が初期化される競合を解消
// 2.9.0 2019/04/01 テストプレー時のみ、特定の日付もしくは設定した誕生日になるとタイトル画面に専用メッセージが流れる機能を追加
// 2.8.1 2019/02/10 プラグイン等で画面サイズを変え、かつメニューバーを有効にしているとウィンドウサイズがおかしくなる問題を修正
// 2.8.0 2019/01/06 MakeScreenMovie.jsを有効にしていると録画用のツールバーが表示される機能を追加
// 2.7.0 2018/12/09 マップリロード機能で再読込したときに一時消去されたイベントが再表示されないよう仕様変更
// 2.6.0 2018/10/08 戦闘強制敗北、戦闘強制中断の機能を追加
// 2.5.1 2018/03/25 BGMが演奏されていないときに高速モードを切り替えるとエラーになる問題を修正
// 2.5.0 2018/03/17 最前面に表示しているとき、画面がフォーカスを失うと画面自動で右寄せになる機能を追加
//                  最新のNW.jsで使用できなくなる一部機能を削除
// 2.4.5 2018/03/06 各種ファンクションキーにCtrlおよびAltの同時押し要否の設定を追加しました。
// 2.4.4 2018/03/03 ブレークポイントから再開したときにキー入力が押しっぱなし扱いになってしまう場合があるMVの仕様を考慮。
// 2.4.3 2018/02/18 2.4.1の機能に加えて他のエディタから起動したとき全般で戦闘テストができるようにしました。
// 2.4.2 2018/02/18 ヘルプの記述を追加
// 2.4.1 2018/02/18 ブラウザ起動時に戦闘テストができる機能を追加しました。オプションのbtestは利用者が付与してください。
// 2.4.0 2018/02/15 ブラウザ起動時もテストプレーと判断した場合は一部の機能が使えるようにしました。
// 2.3.4 2017/12/02 リファクタリング
// 2.3.2 2017/11/23 Fix missing menu bar height at SceneManager.setWindowSizeForMenuBar
// 2.3.1 2017/11/11 画面キャプチャ管理プラグインとの連携による修正
// 2.3.0 2017/09/25 競合対策でマップとデータのリロード機能を無効にする設定を追加
//                  最新のNW.jsかつメニューバーを表示しない場合にエラーになる問題を修正
// 2.2.2 2017/09/25 ヘルプに注意事項を追記
// 2.2.1 2017/09/01 スクリプトエラー発生時に警告を出力する機能を追加
// 2.2.0 2017/08/09 パラメータ型指定機能に対応。一部パラメータは再設定が必要です。
//                  起動時に自動で最前面に表示するパラメータを追加。
//                  NW.jsを最新化したときに発生するエラーに対処（ただし一部機能は使用できません）
// 2.1.1 2017/03/10 コミュニティ版でロード時にエンジン名称を出力するよう修正。
// 2.1.0 2016/12/25 スローモーション機能を追加しました。一時的にゲーム速度を最低1/60倍速まで低下できます。
// 2.0.0 2016/12/16 ES2015向けにリファクタリングしました。
//                  JSON形式でのセーブ＆ロードに対応しました。
//                  ゲーム画面にフォーカスを戻した際に、マップとデータベースの再読込を自動で行うようにしました。
//                  「最前面に表示」機能をゲーム中に切り替えられるようにしました。
//                  一部、余分な機能を無効化しました。
// 1.5.1 2016/08/14 コアスクリプトのバージョンを出力するようにしました。
// 1.5.0 2016/06/25 スクリプトの常駐実行機能を追加
// 1.4.2 2016/06/14 SceneManager.initializeでエラーが発生した際にエラー内容を確認できない問題を修正
// 1.4.1 2016/06/14 YEP_CoreEngine.jsと併用したときにウィンドウ高さ補正が効かなくなる問題を修正
// 1.4.0 2016/06/03 メニューバーからデバッグ用のコマンドを実行できる機能を追加
//                  ゲーム画面の更新を停止し、一時的にフリーズする機能を追加
//                  セーブデータのエンコード・デコード機能を追加
// 1.3.0 2016/05/04 スクリプトのその場実行機能を追加
//                  モバイル偽装機能を追加
//                  コードのリファクタリング
// 1.2.2 2016/03/19 ゲームのスピード高速化を8倍速まで対応
// 1.2.1 2016/02/27 タイトルカットしたときにイベントテスト、戦闘テストが正しく開始されない不具合を修正
// 1.2.0 2016/02/24 ゲームのスピードを高速(2倍速)化する機能を追加
//                  戦闘を勝利扱いで即終了する機能を追加
// 1.1.0 2016/01/11 ゲーム開始時にFPS表示（FPS表示/MS表示に対応）を有効にする機能を追加
//                  タイトル画面を飛ばして最新のセーブファイルをロードする機能を追加
// 1.0.2 2016/01/02 繰り返しリセットすると警告が出る問題の解消
//                  ゲームウィンドウを端に寄せる機能(笑)を追加
// 1.0.1 2015/12/19 F12キーでリセットする機能を追加（F5と同様の動作）
// 1.0.0 2015/12/12 初版
// ----------------------------------------------------------------------------
// [Blog]   : https://triacontane.blogspot.jp/
// [Twitter]: https://twitter.com/triacontane/
// [GitHub] : https://github.com/triacontane/
//=============================================================================

/*:
 * @plugindesc Developer tools management plugin
 * @author triacontane
 *
 * @param StartupDevTool
 * @desc It will start the developer tools at the start of the game.
 * @default true
 * @type boolean
 *
 * @param FuncKeyReload
 * @desc 画面のリロードを行うキーです(F1～F12)。デフォルトF5キーと同様の役割を持ちます。
 * @default F12
 * @option none
 * @option F1
 * @option F2
 * @option F3
 * @option F4
 * @option F5
 * @option F6
 * @option F7
 * @option F8
 * @option F9
 * @option F10
 * @option F11
 * @option F12
 *
 * @param FuncKeyOnTop
 * @desc ゲーム画面を最前面に表示するキーです。(F1～F12)。
 * @default
 * @option none
 * @option F1
 * @option F2
 * @option F3
 * @option F4
 * @option F5
 * @option F6
 * @option F7
 * @option F8
 * @option F9
 * @option F10
 * @option F11
 * @option F12
 *
 * @param FuncKeyRapidGame
 * @desc ゲームを高速化するキーです。(F1～F12)。
 * @default F10
 * @option none
 * @option F1
 * @option F2
 * @option F3
 * @option F4
 * @option F5
 * @option F6
 * @option F7
 * @option F8
 * @option F9
 * @option F10
 * @option F11
 * @option F12
 *
 * @param FuncKeyForceVictory
 * @desc 戦闘を勝利扱いで強制終了するキーです。(F1～F12)。
 * @default
 * @type select
 * @option none
 * @option F1
 * @option F2
 * @option F3
 * @option F4
 * @option F5
 * @option F6
 * @option F7
 * @option F8
 * @option F9
 * @option F10
 * @option F11
 * @option F12
 *
 * @param FuncKeyForceDefeat
 * @desc 戦闘を敗北扱いで強制終了するキーです。(F1～F12)。
 * @default
 * @type select
 * @option none
 * @option F1
 * @option F2
 * @option F3
 * @option F4
 * @option F5
 * @option F6
 * @option F7
 * @option F8
 * @option F9
 * @option F10
 * @option F11
 * @option F12
 *
 * @param FuncKeyForceAbort
 * @desc 戦闘を中断扱いで強制終了するキーです。(F1～F12)。
 * @default
 * @type select
 * @option none
 * @option F1
 * @option F2
 * @option F3
 * @option F4
 * @option F5
 * @option F6
 * @option F7
 * @option F8
 * @option F9
 * @option F10
 * @option F11
 * @option F12
 *
 * @param FuncKeyScript
 * @desc スクリプト実行用のウィンドウをポップアップするキーです。(F1～F12)。
 * @default F6
 * @option none
 * @option F1
 * @option F2
 * @option F3
 * @option F4
 * @option F5
 * @option F6
 * @option F7
 * @option F8
 * @option F9
 * @option F10
 * @option F11
 * @option F12
 *
 * @param FuncKeyFreeze
 * @desc 画面の更新を一時停止するキーです。(F1～F12)。
 * @default
 * @option none
 * @option F1
 * @option F2
 * @option F3
 * @option F4
 * @option F5
 * @option F6
 * @option F7
 * @option F8
 * @option F9
 * @option F10
 * @option F11
 * @option F12
 *
 * @param SimultaneousCtrl
 * @desc 各機能を利用する際にCtrlキーの同時押しが必要かどうかです。他のプラグインと対象キーが競合する場合に利用します。
 * @default false
 * @type boolean
 *
 * @param SimultaneousAlt
 * @desc 各機能を利用する際にAltキーの同時押しが必要かどうかです。他のプラグインと対象キーが競合する場合に利用します。
 * @default false
 * @type boolean
 *
 * @param ShowFPS
 * @desc 初期状態で画面左上にFPSもしくはMSを表示します（FPS/MS/OFF）。
 * @default OFF
 * @type select
 * @option FPS
 * @option MS
 * @option OFF
 *
 * @param CutTitle
 * @desc タイトル画面をとばして最新のセーブファイルをロードします。
 * @default false
 * @type boolean
 *
 * @param RapidStart
 * @desc 高速化された状態でゲームを開始します。（ON/OFF）
 * @default false
 * @type boolean
 *
 * @param RapidSpeed
 * @desc 高速化を実行した際のスピード倍率です。
 * @default 2
 * @type number
 * @min -60
 * @max 16
 *
 * @param InvalidMessageSkip
 * @desc 高速化された状態でのメッセージ強制スキップを無効にします。
 * @default false
 * @type boolean
 *
 * @param FakeMobile
 * @desc モバイル実行を偽装します。(ON/OFF)
 * モバイル版で異なるUIを使用する場合の表示確認ができます。
 * @default false
 * @type boolean
 *
 * @param MenuBarVisible
 * @desc メニューバーを表示し各種デバッグコマンドを実行できます。(ON/OFF)
 * @default true
 * @type boolean
 *
 * @param ClickMenu
 * @desc クリックメニューから各種デバッグコマンドを実行できます。(-1:無効 0:左 1:ホイール 2:右)
 * @default 1
 * @type select
 * @option 無効
 * @value -1
 * @option 左
 * @value 0
 * @option ホイール
 * @value 1
 * @option 右
 * @value 2
 *
 * @param JsonSave
 * @desc JSON形式でセーブ＆ロードできます。テキストエディタ等でセーブファイルを自由に編集できるようになります。
 * @default false
 * @type boolean
 *
 * @param OutputStartupInfo
 * @desc 起動時に様々な情報をログ出力します。
 * @default true
 * @type boolean
 *
 * @param StartupOnTop
 * @desc 起動時にゲーム画面が最前面に固定されます。
 * @default false
 * @type boolean
 *
 * @param UseReloadData
 * @desc オンフォーカスでマップとデータを再読込します。競合等で動作に問題がある場合は無効にしてください。
 * @default true
 * @type boolean
 *
 * @param ShiftRightOnBlur
 * @desc ゲーム画面が最前面に表示されているときにフォーカスを失うと、指定した座標分画面を右寄せします。
 * @default 640
 * @type number
 *
 * @param GreetingHide
 * @desc タイトル画面の挨拶メッセージを非表示にします。
 * @default false
 * @type boolean
 *
 * @param BirthdayMonth
 * @desc 誕生日を入力しておくと当日にタイトル画面にメッセージが表示されます。
 * @default 0
 * @type number
 * @min 0
 * @max 12
 *
 * @param BirthdayDate
 * @desc 誕生日を入力しておくと当日にタイトル画面にメッセージが表示されます。
 * @default 0
 * @type number
 * @min 0
 * @max 31
 *
 * @help デベロッパツールの挙動を調整する制作支援プラグインです。
 * このプラグインはローカル環境でのテストプレー時のみ有効となります。
 * また、UserAgentやコアスクリプトのバージョン等役立つ情報をログに出力します。
 * 快適な開発支援のために以下の機能を提供します。
 *
 * 1. ゲーム開始時にデベロッパツールが自動で立ち上がります。(通常はF8で起動)
 *    OFFにしていた場合でもエラーが発生すると自動で立ち上がります。
 *
 * 2. ゲーム画面を常に最前面に表示してくれます。画面を見ながら作業をする場合に
 *    便利です。ゲーム中にメニューバーから切り替えできます。
 *
 * 3. マップやイベントを修正して再保存すると、ゲーム画面にフォーカスを戻した
 *    瞬間にマップとデータベースを自動でリロードしてくれます。
 *
 * 4. タイトル画面を飛ばして最新のセーブファイルをロードできます。
 *
 * 5. マップ上でのゲームのスピードを高速化(16倍速まで)できます。
 *    (マップ上で高速、フェードアウト、メッセージ表示の高速スキップ)
 *    逆に低速化(1/60倍速まで)することもできます。速度倍率に負の値を設定して
 *    ください。ゲームスピードが変化した場合は、BGMのピッチが変化します。
 *
 * 6. 強制的に敵を全滅させて勝利することができます。報酬も取得できます。
 *    強制敗北、強制中断も可能です。
 *
 * 7. 任意のスクリプトを毎フレーム実行させることができます。
 *    スクリプトの戻り値が変化したときのみ結果をコンソールに出力します。
 *
 * 8. ゲーム画面の更新を一時的に止めて画面をフリーズさせることができます。
 *
 * 9. セーブデータを保存する際にエンコーディングせずjson形式のまま
 *    セーブ・ロードできます。
 *
 * このプラグインにはプラグインコマンドはありません。
 *
 * 画面キャプチャ管理プラグインと連携すると画面キャプチャ用の
 * メニューバーが表示されます。
 * https://raw.githubusercontent.com/triacontane/RPGMakerMV/master/MakeScreenCapture.js
 *
 * ・高度な設定
 * ブラウザ起動時でも当プラグインのデバッグ機能を有効にしたい場合は、
 * 起動URLのオプションに「test」もしくは「best」を付与してください。
 * ただしNW.js由来のいくつかの機能は無効になります。
 *
 * 通常、ブラウザなど外部からゲーム起動の場合、戦闘テストは実行できませんが、
 * 当プラグインを有効にしていると戦闘テストが可能です。
 *
 * 外部エディタから起動する場合、以下の起動パラメータが指定可能です。
 * この指定はプラグインパラメータより優先されます。
 * devToolOff : デベロッパツールが起動しなくなります。
 * onTop : 最前面に画面を表示します。
 *
 * This plugin is released under the MIT License.
 */

/*:ja
 * @plugindesc 総合開発支援プラグイン
 * @author トリアコンタン
 *
 * @param 開始時に起動
 * @desc ゲーム開始時に同時にデベロッパツールを起動します。
 * @default true
 * @type boolean
 *
 * @param リロードキー
 * @desc 画面のリロードを行うキーです(F1～F12)。デフォルトF5キーと同様の役割を持ちます。
 * 以前のツクールとの後方互換性を持たせるための機能です。
 * @default F12
 * @type select
 * @option none
 * @option F1
 * @option F2
 * @option F3
 * @option F4
 * @option F5
 * @option F6
 * @option F7
 * @option F8
 * @option F9
 * @option F10
 * @option F11
 * @option F12
 *
 * @param 最前面に表示キー
 * @desc ゲーム画面を最前面表示を切り替えるキーです。(F1～F12)。
 * @default F11
 * @type select
 * @option none
 * @option F1
 * @option F2
 * @option F3
 * @option F4
 * @option F5
 * @option F6
 * @option F7
 * @option F8
 * @option F9
 * @option F10
 * @option F11
 * @option F12
 *
 * @param 高速化切替キー
 * @desc ゲームの高速化を切り替えるキーです。(F1～F12)。
 * @default
 * @type select
 * @option none
 * @option F1
 * @option F2
 * @option F3
 * @option F4
 * @option F5
 * @option F6
 * @option F7
 * @option F8
 * @option F9
 * @option F10
 * @option F11
 * @option F12
 *
 * @param 強制戦闘勝利キー
 * @desc 戦闘を勝利扱いで強制終了するキーです。(F1～F12)。
 * @default
 * @type select
 * @option none
 * @option F1
 * @option F2
 * @option F3
 * @option F4
 * @option F5
 * @option F6
 * @option F7
 * @option F8
 * @option F9
 * @option F10
 * @option F11
 * @option F12
 *
 * @param 強制戦闘敗北キー
 * @desc 戦闘を敗北扱いで強制終了するキーです。(F1～F12)。
 * @default
 * @type select
 * @option none
 * @option F1
 * @option F2
 * @option F3
 * @option F4
 * @option F5
 * @option F6
 * @option F7
 * @option F8
 * @option F9
 * @option F10
 * @option F11
 * @option F12
 *
 * @param 強制戦闘中断キー
 * @desc 戦闘を中断扱いで強制終了するキーです。(F1～F12)。
 * @default
 * @type select
 * @option none
 * @option F1
 * @option F2
 * @option F3
 * @option F4
 * @option F5
 * @option F6
 * @option F7
 * @option F8
 * @option F9
 * @option F10
 * @option F11
 * @option F12
 *
 * @param スクリプト実行キー
 * @desc スクリプト常駐実行用のキーです。(F1～F12)。
 * @default
 * @type select
 * @option none
 * @option F1
 * @option F2
 * @option F3
 * @option F4
 * @option F5
 * @option F6
 * @option F7
 * @option F8
 * @option F9
 * @option F10
 * @option F11
 * @option F12
 *
 * @param フリーズキー
 * @desc 画面の更新を一時停止するキーです。(F1～F12)。
 * @default F10
 * @type select
 * @option none
 * @option F1
 * @option F2
 * @option F3
 * @option F4
 * @option F5
 * @option F6
 * @option F7
 * @option F8
 * @option F9
 * @option F10
 * @option F11
 * @option F12
 *
 * @param Ctrl同時押し
 * @desc 各機能を利用する際にCtrlキーの同時押しが必要かどうかです。他のプラグインと対象キーが競合する場合に利用します。
 * @default false
 * @type boolean
 *
 * @param Alt同時押し
 * @desc 各機能を利用する際にAltキーの同時押しが必要かどうかです。他のプラグインと対象キーが競合する場合に利用します。
 * @default false
 * @type boolean
 *
 * @param FPS表示
 * @desc 初期状態で画面左上にFPSを表示します。（FPS/MS/OFF）
 * @default OFF
 * @type select
 * @option FPS
 * @option MS
 * @option OFF
 *
 * @param タイトルカット
 * @desc タイトル画面をとばして最新のセーブファイルをロードします。
 * @default false
 * @type boolean
 *
 * @param 高速開始
 * @desc 高速化された状態でゲームを開始します。（ON/OFF）
 * @default false
 * @type boolean
 *
 * @param 高速スピード
 * @desc 高速化を実行した際のスピード倍率です。(-60...16)
 * 負の値を設定するとスローモーションになります。
 * @default 2
 * @type number
 * @min -60
 * @max 16
 *
 * @param メッセージスキップ無効
 * @desc 高速化された状態でのメッセージ強制スキップを無効にします。
 * @default false
 * @type boolean
 *
 * @param モバイル偽装
 * @desc モバイル実行を偽装します。(ON/OFF)
 * モバイル版で異なるUIを使用する場合の表示確認ができます。
 * @default false
 * @type boolean
 *
 * @param メニューバー表示
 * @desc メニューバーを表示し各種デバッグコマンドを実行できます。(ON/OFF)
 * @default true
 * @type boolean
 *
 * @param クリックメニュー
 * @desc クリックメニューから各種デバッグコマンドを実行できます。(-1:無効 0:左 1:ホイール 2:右)
 * @default 1
 * @type select
 * @option 無効
 * @value -1
 * @option 左
 * @value 0
 * @option ホイール
 * @value 1
 * @option 右
 * @value 2
 *
 * @param JSON形式セーブ
 * @desc JSON形式でセーブ＆ロードできます。テキストエディタ等でセーブファイルを自由に編集できるようになります。
 * @default false
 * @type boolean
 *
 * @param 起動時情報出力
 * @desc 起動時に様々な情報をログ出力します。
 * @default true
 * @type boolean
 *
 * @param 最前面で起動
 * @desc 起動時にゲーム画面が最前面に固定されます。
 * @default false
 * @type boolean
 *
 * @param リロード機能を使う
 * @desc オンフォーカスでマップとデータを再読込します。競合等で動作に問題がある場合は無効にしてください。
 * @default true
 * @type boolean
 *
 * @param 右寄せ座標
 * @desc ゲーム画面が最前面に表示されているときにフォーカスを失うと、指定した座標分画面を右寄せします。
 * @default 640
 * @type number
 *
 * @param 挨拶非表示
 * @desc タイトル画面の挨拶メッセージを非表示にします。
 * @default false
 * @type boolean
 *
 * @param 誕生月
 * @desc 誕生日を入力しておくと当日にタイトル画面にメッセージが表示されます。
 * @default 0
 * @type number
 * @min 0
 * @max 12
 *
 * @param 誕生日
 * @desc 誕生日を入力しておくと当日にタイトル画面にメッセージが表示されます。
 * @default 0
 * @type number
 * @min 0
 * @max 31
 *
 * @help デベロッパツールの挙動を調整する制作支援プラグインです。
 * このプラグインはローカル環境でのテストプレー時のみ有効となります。
 * また、UserAgentやコアスクリプトのバージョン等役立つ情報をログに出力します。
 * 快適な開発支援のために以下の機能を提供します。
 *
 * 1. ゲーム開始時にデベロッパツールが自動で立ち上がります。(通常はF8で起動)
 *    OFFにしていた場合でもエラーが発生すると自動で立ち上がります。
 *
 * 2. ゲーム画面を常に最前面に表示してくれます。画面を見ながら作業をする場合に
 *    便利です。ゲーム中にメニューバーから切り替えできます。
 *
 * 3. マップやイベントを修正して再保存すると、ゲーム画面にフォーカスを戻した
 *    瞬間にマップとデータベースを自動でリロードしてくれます。
 *
 * 4. タイトル画面を飛ばして最新のセーブファイルをロードできます。
 *
 * 5. マップ上でのゲームのスピードを高速化(16倍速まで)できます。
 *    (マップ上で高速、フェードアウト、メッセージ表示の高速スキップ)
 *    逆に低速化(1/60倍速まで)することもできます。速度倍率に負の値を設定して
 *    ください。ゲームスピードが変化した場合は、BGMのピッチが変化します。
 *
 * 6. 強制的に敵を全滅させて勝利することができます。報酬も取得できます。
 *    強制敗北、強制中断も可能です。
 *
 * 7. 任意のスクリプトを毎フレーム実行させることができます。
 *    スクリプトの戻り値が変化したときのみ結果をコンソールに出力します。
 *
 * 8. ゲーム画面の更新を一時的に止めて画面をフリーズさせることができます。
 *
 * 9. セーブデータを保存する際にエンコーディングせずjson形式のまま
 *    セーブ・ロードできます。
 *
 * このプラグインにはプラグインコマンドはありません。
 *
 * 画面キャプチャ管理プラグインと連携すると画面キャプチャ用の
 * メニューバーが表示されます。
 * https://raw.githubusercontent.com/triacontane/RPGMakerMV/master/MakeScreenCapture.js
 *
 * ・高度な設定
 * ブラウザ起動時でも当プラグインのデバッグ機能を有効にしたい場合は、
 * 起動URLのオプションに「test」もしくは「best」を付与してください。
 * ただしNW.js由来のいくつかの機能は無効になります。
 *
 * 通常、ブラウザなど外部からゲーム起動の場合、戦闘テストは実行できませんが、
 * 当プラグインを有効にしていると戦闘テストが可能です。
 *
 * 外部エディタから起動する場合、以下の起動パラメータが指定可能です。
 * この指定はプラグインパラメータより優先されます。
 * devToolOff : デベロッパツールが起動しなくなります。
 * onTop : 最前面に画面を表示します。
 *
 * 利用規約：
 *  作者に無断で改変、再配布が可能で、利用形態（商用、18禁利用等）
 *  についても制限はありません。
 *  このプラグインはもうあなたのものです。
 */

var p = null;

/**
 * Controller_NwJs
 * NW.jsのウィンドウを操作します。
 * @constructor
 */
function Controller_NwJs() {
    this.initialize.apply(this, arguments);
}

(function() {
    'use strict';
    const pluginName = 'DevToolsManage';

    //=============================================================================
    // p
    //  ログ出力をより短い関数名で実現します。(RGSS互換)
    //=============================================================================
    p = function() {
        console.log.apply(console, arguments);
        SceneManager.getNwJs().showDevTools();
    };

    //=============================================================================
    // ローカル関数
    //  プラグインパラメータやプラグインコマンドパラメータの整形やチェックをします
    //=============================================================================
    const getParamString = function(paramNames, upperFlg) {
        const value = getParamOther(paramNames);
        return value === null ? '' : upperFlg ? value.toUpperCase() : value;
    };

    const getParamNumber = function(paramNames, min, max) {
        const value = getParamOther(paramNames);
        if (arguments.length < 2) min = -Infinity;
        if (arguments.length < 3) max = Infinity;
        return (parseInt(value, 10) || 0).clamp(min, max);
    };

    const getParamBoolean = function(paramNames) {
        const value = getParamOther(paramNames);
        return (value || '').toUpperCase() === 'ON' || (value || '').toUpperCase() === 'TRUE';
    };

    const getParamOther = function(paramNames) {
        if (!Array.isArray(paramNames)) paramNames = [paramNames];
        for (let i = 0; i < paramNames.length; i++) {
            const name = PluginManager.parameters(pluginName)[paramNames[i]];
            if (name) return name;
        }
        return null;
    };

    const paramStartupDevTool     = getParamBoolean(['StartupDevTool', '開始時に起動']);
    const paramFuncKeyReload      = getParamString(['FuncKeyReload', 'リロードキー']);
    const paramFuncKeyOnTop       = getParamString(['FuncKeyOnTop', '最前面に表示キー']);
    const paramFuncKeyRapidGame   = getParamString(['FuncKeyRapidGame', '高速化切替キー']);
    const paramFuncKeyVictory     = getParamString(['FuncKeyForceVictory', '強制戦闘勝利キー']);
    const paramFuncKeyDefeat      = getParamString(['FuncKeyForceDefeat', '強制戦闘敗北キー']);
    const paramFuncKeyAbort       = getParamString(['FuncKeyForceAbort', '強制戦闘中断キー']);
    const paramFuncKeyScript      = getParamString(['FuncKeyScript', 'スクリプト実行キー']);
    const paramFuncKeyFreeze      = getParamString(['FuncKeyFreeze', 'フリーズキー']);
    const paramShowFPS            = getParamString(['ShowFPS', 'FPS表示'], true);
    const paramCutTitle           = getParamBoolean(['CutTitle', 'タイトルカット']);
    const paramRapidStart         = getParamBoolean(['RapidStart', '高速開始']);
    const paramRapidSpeed         = getParamNumber(['RapidSpeed', '高速スピード'], -60, 16);
    const paramFakeMobile         = getParamBoolean(['FakeMobile', 'モバイル偽装']);
    const paramMenuBarVisible     = getParamBoolean(['MenuBarVisible', 'メニューバー表示']);
    const paramClickMenu          = getParamNumber(['ClickMenu', 'クリックメニュー'], -1);
    const paramJsonSave           = getParamBoolean(['JsonSave', 'JSON形式セーブ']);
    const paramOutputStartupInfo  = getParamBoolean(['OutputStartupInfo', '起動時情報出力']);
    const paramStartupOnTop       = getParamBoolean(['StartupOnTop', '最前面で起動']);
    const paramUseReloadData      = getParamBoolean(['UseReloadData', 'リロード機能を使う']);
    const paramSimultaneousCtrl   = getParamBoolean(['SimultaneousCtrl', 'Ctrl同時押し']);
    const paramSimultaneousAlt    = getParamBoolean(['SimultaneousAlt', 'Alt同時押し']);
    const paramShiftRightOnBlur   = getParamNumber(['ShiftRightOnBlur', '右寄せ座標'], -1000, 1000);
    const paramGreetingHide       = getParamBoolean(['GreetingHide', '挨拶非表示']);
    const paramBirthdayMonth      = getParamNumber(['BirthdayMonth', '誕生月'], 0, 12);
    const paramBirthdayDate       = getParamNumber(['BirthdayDate', '誕生日'], 0, 31);
    const paramInvalidMessageSkip = getParamBoolean(['InvalidMessageSkip', 'メッセージスキップ無効']);

    //=============================================================================
    // Graphics
    //  FPSの表示を設定します。
    //=============================================================================
    Graphics.setFPSMeter = function(type) {
        switch (type) {
            case 'FPS':
                this.hideFps();
                this._switchFPSMeter();
                break;
            case 'MS':
                this.hideFps();
                this._switchFPSMeter();
                this._switchFPSMeter();
                break;
        }
    };

    const _Graphics__createAllElements = Graphics._createAllElements;
    Graphics._createAllElements        = function() {
        _Graphics__createAllElements.apply(this, arguments);
        if (paramOutputStartupInfo) {
            this.outputStartUpLog();
        }
    };

    Graphics.outputStartUpLog = function() {
        console.log('********************************');
        console.log('***   User Agent             ***');
        console.log('********************************');
        console.log(navigator.userAgent);
        console.log('********************************');
        console.log('***   Core Version           ***');
        console.log('********************************');
        console.log('RPG Maker Name    : ' + Utils.RPGMAKER_NAME);
        console.log('RPG Maker Version : ' + Utils.RPGMAKER_VERSION);
        console.log('RPG Maker Engine  : ' + (Utils.RPGMAKER_ENGINE || 'Official Version'));
        console.log('********************************');
        console.log('***   Audio                  ***');
        console.log('********************************');
        console.log('Can Play OGG : ' + WebAudio.canPlayOgg());
        console.log('Can Play M4A : ' + WebAudio.canPlayM4a());

        if (Utils.isNwjs()) {
            console.log('********************************');
            console.log('***   Environment            ***');
            console.log('********************************');
            console.log('Platform : ' + process.platform);
            console.log(process.env);
            console.log('*********************************');
            console.log('***   document head           ***');
            console.log('*********************************');
            console.log(document.head);
            console.log('*********************************');
            console.log('***   document body           ***');
            console.log('*********************************');
            console.log(document.body);
        }
    };

    // テストプレー時以外は以降の機能を無効
    if (!Utils.isOptionValid('test') && !DataManager.isBattleTest()) {
        console.log(pluginName + ' is valid only test play!');
        return;
    }

    //=============================================================================
    // Utils
    //  モバイルモードを偽装します。
    //=============================================================================
    const _Utils_isMobileDevice = Utils.isMobileDevice;
    Utils.isMobileDevice        = function() {
        return _Utils_isMobileDevice.apply(this, arguments) || paramFakeMobile;
    };

    Utils.isNwjsNormal = function() {
        return this.isNwjs() && navigator.userAgent.match(/Chrome\/4/);
    };

    //=============================================================================
    // Input
    //  promptを再定義します。
    //=============================================================================
    const _Input_wrapNwjsAlert = Input._wrapNwjsAlert;
    Input._wrapNwjsAlert       = function() {
        _Input_wrapNwjsAlert.apply(this, arguments);
        const _window_prompt = window.prompt;
        window.prompt        = function(value, defaultValue) {
            return SceneManager.getNwJs().prompt(value, defaultValue, _window_prompt);
        };
    };

    Input.functionReverseMapper = {
        F1 : 112,
        F2 : 113,
        F3 : 114,
        F4 : 115,
        F5 : 116,
        F6 : 117,
        F7 : 118,
        F8 : 119,
        F9 : 120,
        F10: 121,
        F11: 122,
        F12: 123
    };

    var _Input__shouldPreventDefault = Input._shouldPreventDefault;
    Input._shouldPreventDefault      = function(keyCode) {
        return _Input__shouldPreventDefault.apply(this, arguments) || keyCode === 9; // Tab
    };

    //=============================================================================
    // SceneManager
    //  状況に応じてデベロッパツールを自動制御します。
    //=============================================================================
    SceneManager.originalTitle     = null;
    SceneManager._rapidGame        = false;
    SceneManager._lastScriptString = null;
    SceneManager._lastScriptResult = null;

    const _SceneManager_initialize = SceneManager.initialize;
    SceneManager.initialize        = function() {
        _SceneManager_initialize.apply(this, arguments);
        this.initDevCommand();
        Graphics.setFPSMeter(paramShowFPS);
        if (!Utils.isNwjs()) {
            return;
        }
        this._freeze  = false;
        this._nwJsGui = new Controller_NwJs();
        if (this.isAlwaysOnTop()) {
            this._nwJsGui.toggleAlwaysOnTop();
        }
    };

    SceneManager.initDevCommand = function() {
        this.devCommands = [
            {code: 102, use: true, name: '最前面に表示', key: paramFuncKeyOnTop, type: 'checkbox'},
            {code: 103, use: true, name: 'リロード', key: paramFuncKeyReload, type: 'normal'},
            {code: 104, use: true, name: '高速モード切替', key: paramFuncKeyRapidGame, type: 'checkbox'},
            {code: 105, use: true, name: '戦闘強制勝利', key: paramFuncKeyVictory, type: 'normal'},
            {code: 106, use: true, name: '常駐スクリプト実行', key: paramFuncKeyScript, type: 'normal'},
            {code: 107, use: true, name: '画面フリーズ', key: paramFuncKeyFreeze, type: 'checkbox'},
            {code: 108, use: !!SceneManager.takeCapture, name: '画面キャプチャ', key: true, type: 'normal'},
            {code: 109, use: true, name: '戦闘強制敗北', key: paramFuncKeyDefeat, type: 'normal'},
            {code: 110, use: true, name: '戦闘強制中断', key: paramFuncKeyAbort, type: 'normal'},
            {code: 111, use: !!SceneManager.onKeyDownForScreenMovie, name: '画面録画', key: true, type: 'normal'},
        ];
    };

    SceneManager.getNwJs = function() {
        return this._nwJsGui;
    };

    SceneManager.isAlwaysOnTop = function() {
        return paramStartupOnTop || Utils.isOptionValid('onTop');
    };

    SceneManager.toggleFreeze = function() {
        Input.clear();
        this._freeze = !this._freeze;
        this.updateDocumentTitle();
        return this._freeze;
    };

    const _SceneManager_catchException = SceneManager.catchException;
    SceneManager.catchException        = function(e) {
        if (this._nwJsGui) this._nwJsGui.showDevTools(false);
        _SceneManager_catchException.apply(this, arguments);
    };

    const _SceneManager_onError = SceneManager.onError;
    SceneManager.onError        = function(e) {
        if (this._nwJsGui) this._nwJsGui.showDevTools(false);
        _SceneManager_onError.apply(this, arguments);
    };

    const _SceneManager_onKeyDown = SceneManager.onKeyDown;
    SceneManager.onKeyDown        = function(event) {
        _SceneManager_onKeyDown.apply(this, arguments);
        if (paramSimultaneousCtrl === event.ctrlKey && paramSimultaneousAlt === event.altKey) {
            this.onKeyDownForDevToolManage(event);
        }
    };

    SceneManager.onKeyDownForDevToolManage = function(event) {
        let commandCode = null;
        this.devCommands.some(function(commandInfo) {
            if (Input.functionReverseMapper[commandInfo.key] === event.keyCode) {
                commandCode = commandInfo.code;
                return true;
            }
            return false;
        });
        if (commandCode && this._nwJsGui) this.executeDevCommand(commandCode, event);
    };

    SceneManager.executeDevCommand = function(code, event) {
        const command = this['executeDevCommand' + code];
        return command ? command.call(SceneManager, event) : null;
    };

    SceneManager.executeDevCommand102 = function() {
        return this._nwJsGui.toggleAlwaysOnTop();
    };

    SceneManager.executeDevCommand103 = function() {
        location.reload();
    };

    SceneManager.executeDevCommand104 = function() {
        return this.toggleRapid();
    };

    SceneManager.executeDevCommand105 = function() {
        BattleManager.forceVictory();
    };

    SceneManager.executeDevCommand106 = function() {
        this.showScriptDialog();
    };

    SceneManager.executeDevCommand107 = function() {
        return this.toggleFreeze();
    };

    SceneManager.executeDevCommand108 = function() {
        return this.takeCapture();
    };

    SceneManager.executeDevCommand109 = function() {
        BattleManager.forceDefect();
    };

    SceneManager.executeDevCommand110 = function() {
        BattleManager.forceAbort();
    };

    SceneManager.executeDevCommand111 = function() {
        this._screenRecorder.toggle();
    };

    SceneManager.isRapid = function() {
        return SceneManager._rapidGame && paramRapidSpeed > 1;
    };

    SceneManager.isSlow = function() {
        return SceneManager._rapidGame && paramRapidSpeed < -1;
    };

    SceneManager.toggleRapid = function() {
        this._rapidGame = !this._rapidGame;
        const bgm       = AudioManager.saveBgm();
        if (bgm.name) {
            AudioManager.playBgm(bgm, bgm.pos);
            AudioManager._bgmBuffer.play(true, bgm.pos);
        }
        this.updateDocumentTitle();
        return this.isRapid();
    };

    SceneManager.updateDocumentTitle = function() {
        if (!this.originalTitle) {
            this.originalTitle = document.title;
        }
        document.title = this.originalTitle + this.addDocumentTitleRapidOrSlow() +
            this.addDocumentTitleAlwaysOnTop() +
            this.addDocumentTitleFreeze();
    };

    SceneManager.addDocumentTitleRapidOrSlow = function() {
        if (this.isRapid()) {
            return ' [!!!Rapid!!!] * ' + paramRapidSpeed;
        } else if (this.isSlow()) {
            return ' [!!!Slow!!!] / ' + -paramRapidSpeed;
        } else {
            return '';
        }
    };

    SceneManager.addDocumentTitleAlwaysOnTop = function() {
        return this._nwJsGui.isOnTop() ? ' [!!!Always On Top!!!]' : '';
    };

    SceneManager.addDocumentTitleFreeze = function() {
        return this._freeze ? ' [!!!Freeze!!!]' : '';
    };

    SceneManager.isCurrentScene = function(sceneClass) {
        return this._scene && this._scene.constructor === sceneClass;
    };

    SceneManager.showScriptDialog = function() {
        const promptValue  = '常駐実行したいスクリプトを入力してください。';
        const scriptString = window.prompt(promptValue, this._nwJsGui.readClipboard());
        if (scriptString !== null && scriptString !== '') {
            this._nwJsGui.showDevTools();
            this._nwJsGui.writeClipboard(scriptString);
            this.executeScript(scriptString);
            this._lastScriptString = scriptString;
        }
    };

    SceneManager.executeScript = function(scriptString) {
        let result = null;
        try {
            result = eval(scriptString);
            if (!this._lastScriptString) {
                SoundManager.playOk();
                console.log('Execute Script : ' + scriptString);
                console.log('Execute Result : ');
            }
        } catch (e) {
            if (!this._lastScriptString) {
                SoundManager.playBuzzer();
                console.log('Error Script : ' + scriptString);
                console.error(e.stack);
            }
            result = e.toString();
        }
        if (!this._lastScriptString || result !== this._lastScriptResult) {
            console.log(result);
        }
        this._lastScriptResult = result;
    };

    const _SceneManager_initNwjs = SceneManager.initNwjs;
    SceneManager.initNwjs        = function() {
        _SceneManager_initNwjs.apply(this, arguments);
        if (Utils.isNwjs()) {
            this.addMenuBar();
        }
    };

    SceneManager.addMenuBar = function() {
        if (!paramMenuBarVisible) {
            this._needAdjustScreen = false;
            return;
        }
        const gui        = require('nw.gui');
        const gameWindow = gui.Window.get();
        if (!gameWindow.menu || gameWindow.menu.type !== 'menubar') {
            this._needAdjustScreen = true;
        }
        gameWindow.menu = new gui.Menu({type: 'menubar'});
    };

    const _SceneManager_run = SceneManager.run;
    SceneManager.run        = function(sceneClass) {
        _SceneManager_run.apply(this, arguments);
        this.setWindowSizeForMenuBar();
    };

    SceneManager.setWindowSizeForMenuBar = function() {
        if (!this._needAdjustScreen) {
            return;
        }
        const gui        = require('nw.gui');
        const gameWindow = gui.Window.get();
        setTimeout(function() { // Fix missing menu bar height
            var style_height = parseInt(Graphics._canvas.style.height, 10);
            var height_diff  = SceneManager._screenHeight - style_height;
            if (height_diff !== 0) {
                gameWindow.moveBy(0, -height_diff);
                gameWindow.resizeBy(0, height_diff);
            }
        }, 100);
    };

    SceneManager.getMenuBarHeight = function() {
        return Utils.isNwjsNormal() ? 20 : 25;
    };

    const _SceneManager_requestUpdate = SceneManager.requestUpdate;
    SceneManager._updateRateCount     = 0;
    SceneManager.requestUpdate        = function() {
        if (this.isSlow()) {
            this._updateRateCount++;
            if (this._updateRateCount >= -paramRapidSpeed) {
                this.updateInputData();
                _SceneManager_requestUpdate.apply(this, arguments);
                this._updateRateCount = 0;
            } else if (!this._stopped) {
                requestAnimationFrame(this.requestUpdate.bind(this));
            }
        } else {
            this._updateRateCount = 0;
            _SceneManager_requestUpdate.apply(this, arguments);
        }
    };

    const _SceneManager_updateMain = SceneManager.updateMain;
    SceneManager.updateMain        = function() {
        if (this.isSlow()) {
            this.changeScene();
            this.updateScene();
            this.renderScene();
            this.requestUpdate();
        } else {
            const newTime = this._getTimeInMsWithoutMobileSafari();
            // for break point
            if (newTime - this._currentTime > 1000) {
                Input.clear();
            }
            _SceneManager_updateMain.apply(this, arguments);
        }
    };

    const _SceneManager_updateScene = SceneManager.updateScene;
    SceneManager.updateScene        = function() {
        this.updateScript();
        if (this.isUsingReload()) {
            this.updateDataReload();
        }
        if (this._freeze || this.isReloading()) {
            return;
        }
        _SceneManager_updateScene.apply(this, arguments);
    };

    SceneManager.isUsingReload = function() {
        return paramUseReloadData && !DataManager.isBattleTest() && !DataManager.isEventTest() && Utils.isNwjs();
    };

    SceneManager.updateScript = function() {
        if (this._lastScriptString) {
            this.executeScript(this._lastScriptString);
        }
    };

    SceneManager.updateDataReload = function() {
        if (this.isOnFocusGameWindow() && !this._reloadGenerator) {
            this._reloadGenerator = this.reloadGenerator();
        }
        if (this._reloadGenerator && DataManager.isDatabaseLoaded()) {
            if (!this._reloadGenerator.next().value) {
                this._reloadGenerator = null;
                // Resolve conflict for DynamicDatabase.js
                if (typeof DynamicDatabaseManager !== 'undefined') {
                    DynamicDatabaseManager.makeDynamicDatabase();
                }
            }
        }
    };

    SceneManager.reloadGenerator = function* () {
        this._preVersionId = DataManager.reloadSystemData();
        yield true;
        if (this._preVersionId !== $dataSystem.versionId) {
            this.reloadMapData();
            DataManager.loadDatabase();
            console.log('Database Reload');
            yield true;
        }
        return false;
    };

    SceneManager.isOnFocusGameWindow = function() {
        if (this.getNwJs().isOnFocus()) {
            this.getNwJs().setOnFocus(false);
            return true;
        }
        return false;
    };

    SceneManager.reloadMapData = function() {
        if (this._scene instanceof Scene_Map && $gamePlayer.canMove()) {
            $gamePlayer.reserveTransfer(
                $gameMap.mapId(), $gamePlayer.x, $gamePlayer.y, $gamePlayer.direction(), 2);
            $gamePlayer.requestMapReload();
            console.log('Map Reload');
        }
    };

    SceneManager.isReloading = function() {
        return !!this._reloadGenerator;
    };

    //=============================================================================
    // BattleManager
    //  強制勝利を追加定義します。
    //=============================================================================
    BattleManager.forceVictory = function() {
        if (this.canExecuteBattleEndProcess()) {
            $gameTroop.members().forEach(function(enemy) {
                enemy.addNewState(enemy.deathStateId());
            });
            this.processVictory();
        }
    };

    BattleManager.forceDefect = function() {
        if (this.canExecuteBattleEndProcess()) {
            $gameParty.members().forEach(function(actor) {
                actor.addNewState(actor.deathStateId());
            });
            this.processDefeat();
        }
    };

    BattleManager.forceAbort = function() {
        if (this.canExecuteBattleEndProcess()) {
            $gameParty.performEscape();
            SoundManager.playEscape();
            this.displayEscapeSuccessMessage();
            this._escaped = true;
            this.processAbort();
        }
    };

    BattleManager.canExecuteBattleEndProcess = function() {
        return SceneManager.isCurrentScene(Scene_Battle) && this._phase !== 'battleEnd';
    };

    //=============================================================================
    // AudioManager
    //  高速化実行時にBGMのピッチを強制的に最大にします。
    //=============================================================================
    const _AudioManager_playBgm = AudioManager.playBgm;
    AudioManager.playBgm        = function(bgm, pos) {
        const originalPitch = bgm.pitch;
        if (SceneManager.isRapid()) {
            arguments[0].pitch = 150;
        }
        if (SceneManager.isSlow()) {
            arguments[0].pitch = 50;
        }
        _AudioManager_playBgm.apply(this, arguments);
        this._currentBgm.pitch = originalPitch;
    };

    //=============================================================================
    // DataManager
    //  セーブデータのエンコード・デコードを実施します。
    //=============================================================================
    DataManager.decodeSaveGame = function(savefileId) {
        if (this.isThisGameFile(savefileId)) {
            const json = StorageManager.load(savefileId);
            StorageManager.saveToLocalFileJson(savefileId, json);
        }
    };

    DataManager.encodeSaveGame = function(savefileId) {
        const json = StorageManager.loadFromLocalFileJson(savefileId);
        if (json) {
            StorageManager.save(savefileId, json);
        }
    };

    const _DataManager_saveGameWithoutRescue = DataManager.saveGameWithoutRescue;
    DataManager.saveGameWithoutRescue        = function(savefileId) {
        const result = _DataManager_saveGameWithoutRescue.apply(this, arguments);
        if (paramJsonSave) this.decodeSaveGame(savefileId);
        return result;
    };

    const _DataManager_loadGameWithoutRescue = DataManager.loadGameWithoutRescue;
    DataManager.loadGameWithoutRescue        = function(savefileId) {
        this.encodeSaveGame(savefileId);
        return _DataManager_loadGameWithoutRescue.apply(this, arguments);
    };

    const _DataManager_loadDatabase = DataManager.loadDatabase;
    DataManager.loadDatabase        = function() {
        if (this.isNeedSuppressBtest()) {
            this._suppressBattleTest = true;
        }
        _DataManager_loadDatabase.apply(this, arguments);
        this._suppressBattleTest = false;
    };

    const _DataManager_isBattleTest = DataManager.isBattleTest;
    DataManager.isBattleTest        = function() {
        return this._suppressBattleTest ? false : _DataManager_isBattleTest.apply(this, arguments);
    };

    DataManager.isNeedSuppressBtest = function() {
        if (!this.isBattleTest()) {
            return false;
        }
        if (Utils.isNwjs()) {
            return this._databaseFiles.some(function(databaseFile) {
                return !StorageManager.isExistTestData(databaseFile.src);
            });
        } else {
            return true;
        }
    };

    DataManager.reloadSystemData = function() {
        for (let i = 0; i < this._databaseFiles.length; i++) {
            const name = this._databaseFiles[i].name;
            if (name === '$dataSystem') {
                var preVersionId = $dataSystem.versionId;
                this.loadDataFile(name, this._databaseFiles[i].src);
                return preVersionId;
            }
        }
        return null;
    };

    //=============================================================================
    // StorageManager
    //  jsonセーブファイルの読み込みと書き込みを行います。
    //=============================================================================
    StorageManager.saveToLocalFileJson = function(savefileId, json) {
        const fs       = require('fs');
        const dirPath  = this.localFileDirectoryPath();
        const filePath = dirPath + 'file%1.json'.format(savefileId);
        if (!fs.existsSync(dirPath)) {
            fs.mkdirSync(dirPath);
        }
        fs.writeFileSync(filePath, json);
    };

    StorageManager.loadFromLocalFileJson = function(savefileId) {
        const fs       = require('fs');
        const filePath = this.localFileDirectoryPath() + 'file%1.json'.format(savefileId);
        if (fs.existsSync(filePath)) {
            return fs.readFileSync(filePath, {encoding: 'utf8'});
        }
        return null;
    };

    StorageManager.isExistTestData = function(fileName) {
        const fs       = require('fs');
        const path     = require('path');
        const filePath = path.join(path.dirname(process.mainModule.filename), 'data/Test_' + fileName);
        return fs.existsSync(filePath);
    };

    //=============================================================================
    // Scene_Base
    //  マップの高速化を提供します。
    //=============================================================================
    const _Scene_Base_fadeSpeed    = Scene_Base.prototype.fadeSpeed;
    Scene_Base.prototype.fadeSpeed = function() {
        return SceneManager.isRapid() ? 1 : _Scene_Base_fadeSpeed.apply(this, arguments);
    };

    const _Scene_Base_startFadeIn    = Scene_Base.prototype.startFadeIn;
    Scene_Base.prototype.startFadeIn = function(duration, white) {
        if (SceneManager.isRapid()) arguments[0] = 1;
        _Scene_Base_startFadeIn.apply(this, arguments);
    };

    const _Scene_Base_startFadeOut    = Scene_Base.prototype.startFadeOut;
    Scene_Base.prototype.startFadeOut = function(duration, white) {
        if (SceneManager.isRapid()) arguments[0] = 1;
        _Scene_Base_startFadeOut.apply(this, arguments);
    };

    //=============================================================================
    // Scene_Boot
    //  タイトル画面をとばしてマップ画面に遷移します。
    //=============================================================================
    const _Scene_Boot_start    = Scene_Boot.prototype.start;
    Scene_Boot.prototype.start = function() {
        _Scene_Boot_start.apply(this, arguments);
        if (paramRapidStart) SceneManager.toggleRapid();
        this.cutSceneTitle();
    };

    Scene_Boot.prototype.cutSceneTitle = function() {
        if (paramCutTitle && !DataManager.isBattleTest() && !DataManager.isEventTest()) {
            if (!this.goToLatestContinue()) {
                this.goToNewGame();
            }
        }
    };

    Scene_Boot.prototype.goToNewGame = function() {
        DataManager.setupNewGame();
        SceneManager.goto(Scene_Map);
    };

    Scene_Boot.prototype.goToLatestContinue = function() {
        if (DataManager.isAnySavefileExists()) {
            if (DataManager.loadGame(DataManager.latestSavefileId())) {
                this.reloadMapIfUpdated();
                SceneManager.goto(Scene_Map);
                $gameSystem.onAfterLoad();
                return true;
            } else {
                return false;
            }
        } else {
            return false;
        }
    };
    Scene_Boot.prototype.reloadMapIfUpdated = Scene_Load.prototype.reloadMapIfUpdated;

    //=============================================================================
    // Scene_Map
    //  高速モードを実装します。
    //=============================================================================
    const _Scene_Map_isFastForward    = Scene_Map.prototype.isFastForward;
    Scene_Map.prototype.isFastForward = function() {
        return _Scene_Map_isFastForward.apply(this, arguments) || SceneManager.isRapid();
    };

    const _Scene_Map_updateMainMultiply    = Scene_Map.prototype.updateMainMultiply;
    Scene_Map.prototype.updateMainMultiply = function() {
        _Scene_Map_updateMainMultiply.apply(this, arguments);
        if (this.isFastForward() && SceneManager.isRapid()) {
            for (let i = 2; i <= paramRapidSpeed; i++) {
                this.updateMain();
            }
        }
    };

    var _Scene_Title_createForeground      = Scene_Title.prototype.createForeground;
    Scene_Title.prototype.createForeground = function() {
        _Scene_Title_createForeground.apply(this, arguments);
        if (!paramGreetingHide) {
            this.createGreetingSprite();
        }
    };

    var greetingMessage = {
        '1_1'  : 'あけましておめでとうございます！　今年も制作がんばってください！',
        '2_14' : '今日はバレンタインデーです！　素敵な贈り物はもらえましたか？？？',
        '4_1'  : '今日はエイプリルフールです！',
        '8_31' : '夏休みも今日で終わりですね……　お仕事してる人には関係ないですが。',
        '12_24': '今日はクリスマスイブです！　こんな日まで制作するなんてえらいですね！！',
        '12_31': '今日は大晦日です。　来年も制作がんばりましょう！',
    };

    Scene_Title.prototype.createGreetingSprite = function() {
        var message = this.getGreetingMessage();
        if (message) {
            var fontSize         = 48;
            var bitmap           = new Bitmap(1000, fontSize);
            bitmap.fontSize      = fontSize;
            bitmap.fontFace      = '"ヒラギノ明朝 ProN W3","Hiragino Mincho ProN","ＭＳ Ｐ明朝","MS PMincho"';
            this._greetingSprite = new Sprite(bitmap);
            this._greetingSprite.bitmap.drawText(message, 0, 0, 1000, bitmap.height, 'left');
            this._greetingSprite.x = Graphics.width + 200;
            this._greetingSprite.y = Graphics.height / 2;
            this.addChild(this._greetingSprite);
        }
    };

    Scene_Title.prototype.getGreetingMessage = function() {
        var time  = new Date();
        var month = time.getMonth() + 1;
        var date  = time.getDate();
        var hour  = time.getHours();
        if (month === paramBirthdayMonth && date === paramBirthdayDate) {
            return 'お誕生日おめでとうございます！！！';
        }
        if (hour > 21 && Math.randomInt(100) < 2) {
            return '遅くまで制作お疲れさまです……！'
        }
        var key = `${month}_${date}`;
        return greetingMessage[key];
    };

    var _Scene_Title_update      = Scene_Title.prototype.update;
    Scene_Title.prototype.update = function() {
        _Scene_Title_update.apply(this, arguments);
        if (this._greetingSprite) {
            this._greetingSprite.x -= 2;
            this._greetingSprite.y = Graphics.height / 2 + Math.sin(Graphics.frameCount / 30) * 30;
            if (this._greetingSprite.x + this._greetingSprite.bitmap.width < 0) {
                this._greetingSprite.x = this._greetingSprite.bitmap.width;
            }
        }
    };

    //=============================================================================
    // Window_Base
    //  ウィンドウの高速開閉を提供します。
    //=============================================================================
    const _Window_Base_updateOpen    = Window_Base.prototype.updateOpen;
    Window_Base.prototype.updateOpen = function() {
        if (SceneManager.isRapid() && this._opening) this.openness = 255;
        _Window_Base_updateOpen.apply(this, arguments);
    };

    const _Window_Base_updateClose    = Window_Base.prototype.updateClose;
    Window_Base.prototype.updateClose = function() {
        if (SceneManager.isRapid() && this._closing) this.openness = 0;
        _Window_Base_updateClose.apply(this, arguments);
    };

    //=============================================================================
    // Window_Message
    //  メッセージの高速化を提供します。
    //=============================================================================
    if (!paramInvalidMessageSkip) {
        const _Window_Message_isTriggered    = Window_Message.prototype.isTriggered;
        Window_Message.prototype.isTriggered = function() {
            return _Window_Message_isTriggered.apply(this, arguments) || SceneManager.isRapid();
        };

        const _Window_Message_startPause    = Window_Message.prototype.startPause;
        Window_Message.prototype.startPause = function() {
            _Window_Message_startPause.apply(this, arguments);
            if (SceneManager.isRapid()) this.startWait(1);
        };
    }

    var _Game_Interpreter_command355      = Game_Interpreter.prototype.command355;
    Game_Interpreter.prototype.command355 = function() {
        try {
            return _Game_Interpreter_command355.apply(this, arguments);
        } catch (e) {
            console.warn(`Script Error!! Event ID:${this._eventId}`);
            throw e;
        }
    };

    var _Game_Interpreter_command111      = Game_Interpreter.prototype.command111;
    Game_Interpreter.prototype.command111 = function() {
        if (this._params[0] === 12) {
            try {
                return _Game_Interpreter_command111.apply(this, arguments);
            } catch (e) {
                if (this._params[0] === 12) {
                    console.warn(`Script Error!! Event ID:${this._eventId}`);
                }
                throw e;
            }
        } else {
            return _Game_Interpreter_command111.apply(this, arguments);
        }
    };

    var _Game_Character_processMoveCommand      = Game_Character.prototype.processMoveCommand;
    Game_Character.prototype.processMoveCommand = function(command) {
        try {
            _Game_Character_processMoveCommand.apply(this, arguments);
        } catch (e) {
            if (command.code === Game_Character.ROUTE_SCRIPT) {
                console.warn(`Script Error!! ${this.getInformation()}`);
            }
            throw e;
        }
    };

    Game_Character.prototype.getInformation = function() {
        return `X:${this._x} Y:${this._y}`;
    };

    Game_Event.prototype.getInformation = function() {
        return `ID:${this._eventId} Name:${this.event().name}` + Game_Character.prototype.getInformation.call(this);
    };

    Game_Player.prototype.getInformation = function() {
        return 'Player' + Game_Character.prototype.getInformation.call(this);
    };

    Game_Player.prototype.isNeedMapReload = function() {
        return this._needsMapReload;
    };

    const _Game_Map_eraseEvent    = Game_Map.prototype.eraseEvent;
    Game_Map.prototype.eraseEvent = function(eventId) {
        _Game_Map_eraseEvent.apply(this, arguments);
        this._eraseEvents.push(eventId);
    };

    const _Game_Map_setupEvents    = Game_Map.prototype.setupEvents;
    Game_Map.prototype.setupEvents = function() {
        _Game_Map_setupEvents.apply(this, arguments);
        if (this._eraseEvents && $gamePlayer.isNeedMapReload()) {
            this.restoreEventErase();
        } else {
            this._eraseEvents = [];
        }
    };

    Game_Map.prototype.restoreEventErase = function() {
        this._eraseEvents.forEach(eventId => {
            this._events[eventId].erase();
        });
    };

    //=============================================================================
    // Controller_NwJs
    //  Nw.jsのAPI呼び出しを管理します。
    //=============================================================================
    Controller_NwJs.prototype.constructor = Controller_NwJs;
    Controller_NwJs.prototype.initialize  = function() {
        this._nwGui     = require('nw.gui');
        this._onFocus   = false;
        this._menuBar   = this.getWindow().menu;
        this._menuClick = null;
        this._onTop     = false;
        this.setOnFocus(false);
        this.initSetting();
    };

    Controller_NwJs.prototype.initSetting = function() {
        this.addEventListener();
        if (paramMenuBarVisible) {
            this.makeMenu(this._menuBar);
            this.setMenuBar(this._menuBar);
        }
        this.initClickMenu();
        if (this.isStartUpDevTool()) {
            this.showDevTools();
        }
        setTimeout(function() {
            this.addOnFocusListener();
            SceneManager.updateDocumentTitle();
        }.bind(this), 1000);
    };

    Controller_NwJs.prototype.isStartUpDevTool = function() {
        return paramStartupDevTool && !Utils.isOptionValid('devToolOff');
    };

    Controller_NwJs.prototype.initClickMenu = function() {
        this._menuClick      = new this._nwGui.Menu();
        this._clickMenuItems = {};
        this.makeMenu(this._menuClick);
    };

    Controller_NwJs.prototype.setMenuBar = function(menu) {
        this.getWindow().menu = menu;
    };

    Controller_NwJs.prototype.makeMenu = function(menuObject) {
        this.getSortedDevCommands().forEach(function(commandInfo) {
            if (commandInfo.use) this.makeMenuItem(commandInfo, menuObject);
        }, this);
    };

    Controller_NwJs.prototype.makeMenuItem = function(commandInfo, menuObject) {
        const ctrl     = paramSimultaneousCtrl ? 'Ctrl+' : '';
        const alt      = paramSimultaneousAlt ? 'Alt+' : '';
        const key      = commandInfo.key && commandInfo.key[0] === 'F' ? commandInfo.key : '';
        const menuItem = new this._nwGui.MenuItem({
            label: commandInfo.name + (key ? `(${ctrl}${alt}${key})` : ''),
            type : commandInfo.type,
        });
        if (menuObject === this._menuClick) {
            this._clickMenuItems[commandInfo.name] = menuItem;
        }
        menuItem.click = function() {
            const result = SceneManager.executeDevCommand(commandInfo.code);
            if (commandInfo.type === 'checkbox') this._clickMenuItems[commandInfo.name].checked = result;
        }.bind(this);
        menuObject.append(menuItem);
    };

    Controller_NwJs.prototype.getSortedDevCommands = function() {
        return SceneManager.devCommands.filter(command => command.key && command.key !== 'none').sort(function(a, b) {
            if (a.key && b.key) {
                return Input.functionReverseMapper[a.key] - Input.functionReverseMapper[b.key];
            } else if (a.key || b.key) {
                return a.key ? -1 : 1;
            } else {
                return a.code - b.code;
            }
        });
    };

    Controller_NwJs.prototype.setOnFocus = function(value) {
        this._onFocus = value;
    };

    Controller_NwJs.prototype.isOnFocus = function() {
        return this._onFocus;
    };

    Controller_NwJs.prototype.addEventListener = function() {
        document.addEventListener('mousedown', function(event) {
            if (event.button === paramClickMenu) {
                this._menuClick.popup(event.pageX, event.pageY);
            }
        }.bind(this));
    };

    Controller_NwJs.prototype.addOnFocusListener = function() {
        const currentWin = this.getWindow();
        currentWin.removeAllListeners();
        currentWin.on('focus', this.onFocus.bind(this));
        currentWin.on('blur', this.onBlur.bind(this));
    };

    Controller_NwJs.prototype.onFocus = function() {
        if (this._disableScreenShift) {
            return;
        }
        this._onFocus = true;
        setTimeout(function() {
            if (this._moveOnBlur) {
                this.getWindow().moveBy(-paramShiftRightOnBlur, 0);
                this._moveOnBlur = false;
            }
        }.bind(this), 100);
    };

    Controller_NwJs.prototype.onBlur = function() {
        if (this._disableScreenShift) {
            return;
        }
        setTimeout(function() {
            if (!this._moveOnBlur && this._onTop) {
                this.getWindow().moveBy(paramShiftRightOnBlur, 0);
                this._moveOnBlur = true;
            }
        }.bind(this), 100);
    };

    Controller_NwJs.prototype.getWindow = function() {
        return this._nwGui.Window.get();
    };

    Controller_NwJs.prototype.getClipboard = function() {
        return this._nwGui.Clipboard.get();
    };

    Controller_NwJs.prototype.toggleAlwaysOnTop = function() {
        this._onTop = !this._onTop;
        this.getWindow().setAlwaysOnTop(this._onTop);
        SceneManager.updateDocumentTitle();
        return this._onTop;
    };

    Controller_NwJs.prototype.isOnTop = function() {
        return this._onTop;
    };

    Controller_NwJs.prototype.prompt = function(value, defaultValue, aliasPrompt) {
        const win    = this.getWindow();
        const result = aliasPrompt.call(window, value, defaultValue);
        win.focus();
        Input.clear();
        return result;
    };

    Controller_NwJs.prototype.showDevTools = function() {
        this._disableScreenShift = true;
        this.getWindow().showDevTools();
        setTimeout(function() {
            this.focus();
        }.bind(this), 1000);
    };

    Controller_NwJs.prototype.focus = function() {
        this._disableScreenShift = true;
        this.getWindow().focus();
        setTimeout(function() {
            this._disableScreenShift = false;
        }.bind(this), 500);
    };

    Controller_NwJs.prototype.readClipboard = function(mode) {
        if (!mode) mode = 'text';
        return this.getClipboard().get(mode);
    };

    Controller_NwJs.prototype.writeClipboard = function(copyValue, mode) {
        if (!mode) mode = 'text';
        if (mode === 'text') copyValue = copyValue.toString();
        this.getClipboard().set(copyValue, mode);
    };
})();


code:
//=============================================================================
// DisableFastForward.js
// ----------------------------------------------------------------------------
// Copyright (c) 2015 Triacontane
// This software is released under the MIT License.
// http://opensource.org/licenses/mit-license.php
// ----------------------------------------------------------------------------
// Version
// 1.0.0 2016/02/22 初版
// ----------------------------------------------------------------------------
// [Blog]   : http://triacontane.blogspot.jp/
// [Twitter]: https://twitter.com/triacontane/
// [GitHub] : https://github.com/triacontane/
//=============================================================================

/*:
 * @plugindesc イベント高速化禁止プラグイン
 * @author トリアコンタン
 *
 * @help 決定ボタンやマウスをクリックし続けた場合のイベントの
 * 高速スキップを無効化できます。
 * プラグインコマンドから禁止/許可の設定ができます。
 * 設定値はセーブデータに保存されます。
 *
 * プラグインコマンド詳細
 *  イベントコマンド「プラグインコマンド」から実行。
 *  （パラメータの間は半角スペースで区切る）
 *
 *  イベント高速化禁止 or DISABLE_FAST_FORWARD
 *   イベントの高速スキップを禁止します。
 *
 *  イベント高速化許可 or ENABLE_FAST_FORWARD
 *   イベントの高速スキップを許可します。
 *
 * 利用規約：
 *  作者に無断で改変、再配布が可能で、利用形態（商用、18禁利用等）
 *  についても制限はありません。
 *  このプラグインはもうあなたのものです。
 */

(function () {
    'use strict';

    var getCommandName = function (command) {
        return (command || '').toUpperCase();
    };

    //=============================================================================
    // Game_Interpreter
    //  プラグインコマンドを追加定義します。
    //=============================================================================
    var _Game_Interpreter_pluginCommand      = Game_Interpreter.prototype.pluginCommand;
    Game_Interpreter.prototype.pluginCommand = function (command, args) {
        _Game_Interpreter_pluginCommand.apply(this, arguments);
        try {
            this.pluginCommandDisableFastForward(command, args);
        } catch (e) {
            if ($gameTemp.isPlaytest() && Utils.isNwjs()) {
                var window = require('nw.gui').Window.get();
                if (!window.isDevToolsOpen()) {
                    var devTool = window.showDevTools();
                    devTool.moveTo(0, 0);
                    devTool.resizeTo(Graphics.width, Graphics.height);
                    window.focus();
                }
            }
            console.log('プラグインコマンドの実行中にエラーが発生しました。');
            console.log('- コマンド名 　: ' + command);
            console.log('- コマンド引数 : ' + args);
            console.log('- エラー原因   : ' + e.toString());
        }
    };

    Game_Interpreter.prototype.pluginCommandDisableFastForward = function (command, args) {
        switch (getCommandName(command)) {
            case 'イベント高速化禁止' :
            case 'DISABLE_FAST_FORWARD' :
                $gameSystem.disableFastForward = true;
                break;
            case 'イベント高速化許可' :
            case 'ENABLE_FAST_FORWARD' :
                $gameSystem.disableFastForward = false;
                break;
        }
    };

    var _Game_System_initialize = Game_System.prototype.initialize;
    Game_System.prototype.initialize = function() {
        _Game_System_initialize.apply(this, arguments);
        this.disableFastForward = false;
    };

    var _Scene_Map_isFastForward = Scene_Map.prototype.isFastForward;
    Scene_Map.prototype.isFastForward = function() {
        return !$gameSystem.disableFastForward && _Scene_Map_isFastForward.apply(this, arguments);
    };
})();

repo_name: dazed/translations

license: unknown


code:
//=============================================================================
// DispStatusWndOnMsg.js
//=============================================================================
/*:
 * @plugindesc Don't close status window when message window is opening in battle.
 * @author Sasuke KANNAZUKI
 *
 * @help
 * This plugin does not provide plugin commands.
 *
 * [License]
 * this plugin is released under MIT license.
 * http://opensource.org/licenses/mit-license.php
 */

/*:ja
 * @plugindesc 戦闘中メッセージウィンドウ表示中もステータスウィンドウを閉じません
 * @author 神無月サスケ
 *
 * @help
 * このプラグインには、プラグインコマンドはありません。
 *
 * ■概要
 * メッセージウィンドウの表示位置は上か中にしてください。
 * 下にすると、ステータスウィンドウとかぶって見えなくなります。
 *
 * ■ライセンス表記
 * このプラグインは MIT ライセンスで配布されます。
 * ご自由にお使いください。
 * http://opensource.org/licenses/mit-license.php
 */

(function() {
  // overwritten
  Scene_Battle.prototype.updateStatusWindow = function() {
    if ($gameMessage.isBusy()) {
      // this._statusWindow.close();
      this._partyCommandWindow.close();
      this._actorCommandWindow.close();
    } else if (this.isActive() && !this._messageWindow.isClosing()) {
      this._statusWindow.open();
    }
  };

})();


code:
//=============================================================================
// DrainExtend.js
// ----------------------------------------------------------------------------
// (C)2017 Triacontane
// This software is released under the MIT License.
// http://opensource.org/licenses/mit-license.php
// ----------------------------------------------------------------------------
// Version
// 1.2.0 2020/04/29 計算式中でローカル変数[a][b]を使えるよう修正
// 1.1.0 2020/04/29 吸収HPの有効率を設定できる機能を追加
//                  各種メモ欄にJavaScript計算式を使用できる機能を追加
// 1.0.2 2017/02/07 端末依存の記述を削除
// 1.0.0 2017/01/17 初版
// ----------------------------------------------------------------------------
// [Blog]   : https://triacontane.blogspot.jp/
// [Twitter]: https://twitter.com/triacontane/
// [GitHub] : https://github.com/triacontane/
//=============================================================================

/*:
 * @plugindesc DrainExtend
 * @author triacontane
 *
 * @param RecoverSe
 * @desc 吸収成功時に回復効果音を演奏します。
 * @default false
 * @type boolean
 *
 * @help ダメージタイプの「HP吸収」および「MP吸収」の仕様を拡張します。
 * 1. 吸収率を指定して、回復量を与えたダメージの割合で指定可能
 * 2. HPダメージに対してMPやTPを追加で回復することが可能
 * 3. MPダメージに対してHPやTPを追加で回復することが可能
 * 4. 通常ダメージ時のメッセージと効果音に変更可能
 * 5. HP吸収の上限が相手の残HPになる吸収の仕様を撤廃可能
 *
 * スキルもしくはアイテムのダメージタイプを「HP吸収」もしくは「MP吸収」
 * にしてからメモ欄に以下の通り記述してください。
 * <DE_HP吸収率:150>     # HPの吸収率が[150]%になります。
 * <DE_PercentageHP:150> # 同上
 * <DE_MP吸収率:50>      # MPの吸収率が[50]%になります。
 * <DE_PercentageMP:50>  # 同上
 * <DE_TP吸収率:50>      # TPの吸収率が[50]%になります。
 * <DE_PercentageTP:50>  # 同上
 * <DE_攻撃メッセージ>   # メッセージが攻撃時メッセージになります。
 * <DE_AttackMessage>    # 同上
 * <DE_上限突破>         # HP吸収が相手の残HPを超えるようになります。
 * <DE_LimitOver>        # 同上
 *
 * ※1 HP吸収に対してMPのみ回復させたい場合、HPの吸収率を0に指定してください。
 *
 * 吸収攻撃を受ける側に有効度を設定できます。与えるダメージには影響しません。
 * 特徴を有するデータベースのメモ欄に以下の通り指定してください。
 * <DE_有効率:50>        # 吸収率が[50%]になります。
 * <DE_EffectiveRate:50> # 同上
 *
 * このプラグインにはプラグインコマンドはありません。
 *
 * This plugin is released under the MIT License.
 */
/*:ja
 * @plugindesc 吸収拡張プラグイン
 * @author トリアコンタン
 *
 * @param 回復効果音
 * @desc 吸収成功時に回復効果音を演奏します。
 * @default false
 * @type boolean
 *
 * @help ダメージタイプの「HP吸収」および「MP吸収」の仕様を拡張します。
 * 1. 吸収率を指定して与えたダメージのN%回復をなどが可能
 * 2. HPダメージに対してMPやTPを追加で回復することが可能
 * 3. MPダメージに対してHPやTPを追加で回復することが可能
 * 4. 通常ダメージ時のメッセージと効果音に変更可能
 * 5. HP吸収の上限が相手の残HPになる吸収の仕様を撤廃可能
 *
 * スキルもしくはアイテムのダメージタイプを「HP吸収」もしくは「MP吸収」
 * にしてからメモ欄に以下の通り記述してください。
 * <DE_HP吸収率:150>     # HPの吸収率が[150]%になります。
 * <DE_PercentageHP:150> # 同上
 * <DE_MP吸収率:50>      # MPの吸収率が[50]%になります。
 * <DE_PercentageMP:50>  # 同上
 * <DE_TP吸収率:50>      # TPの吸収率が[50]%になります。
 * <DE_PercentageTP:50>  # 同上
 * <DE_攻撃メッセージ>   # メッセージが攻撃時メッセージになります。
 * <DE_AttackMessage>    # 同上
 * <DE_上限突破>         # HP吸収が相手の残HPを超えるようになります。
 * <DE_LimitOver>        # 同上
 *
 * メモ欄の値は制御文字に加えてJavaScript計算式が使用できます。
 * さらに計算式中では以下の変数が使えます。
 * a : 攻撃者
 * b : 対象者
 *
 * ※1 HP吸収に対してMPのみ回復させたい場合、HPの吸収率を0に指定してください。
 *
 * 吸収攻撃を受ける側に有効度を設定できます。与えるダメージには影響しません。
 * 特徴を有するデータベースのメモ欄に以下の通り指定してください。
 * <DE_有効率:50>        # 吸収率が[50%]になります。
 * <DE_EffectiveRate:50> # 同上
 *
 * このプラグインにはプラグインコマンドはありません。
 *
 * 利用規約：
 *  作者に無断で改変、再配布が可能で、利用形態（商用、18禁利用等）
 *  についても制限はありません。
 *  このプラグインはもうあなたのものです。
 */

(function() {
    'use strict';
    var pluginName    = 'DrainExtend';
    var metaTagPrefix = 'DE_';

    //=============================================================================
    // ローカル関数
    //  プラグインパラメータやプラグインコマンドパラメータの整形やチェックをします
    //=============================================================================
    var getParamString = function(paramNames) {
        if (!Array.isArray(paramNames)) paramNames = [paramNames];
        for (var i = 0; i < paramNames.length; i++) {
            var name = PluginManager.parameters(pluginName)[paramNames[i]];
            if (name) return name;
        }
        return '';
    };

    var getParamBoolean = function(paramNames) {
        var value = getParamString(paramNames).toUpperCase();
        return value === 'ON' || value === 'TRUE';
    };

    var getMetaValue = function(object, name) {
        var metaTagName = metaTagPrefix + (name ? name : '');
        return object.meta.hasOwnProperty(metaTagName) ? object.meta[metaTagName] : undefined;
    };

    var getMetaValues = function(object, names) {
        if (!Array.isArray(names)) return getMetaValue(object, names);
        for (var i = 0, n = names.length; i < n; i++) {
            var value = getMetaValue(object, names[i]);
            if (value !== undefined) return value;
        }
        return undefined;
    };

    var convertEscapeCharacters = function(text) {
        if (text == null) text = '';
        var windowLayer = SceneManager._scene._windowLayer;
        return windowLayer ? windowLayer.children[0].convertEscapeCharacters(text) : text;
    };

    //=============================================================================
    // パラメータの取得と整形
    //=============================================================================
    var param = {};
    param.recoverSe = getParamBoolean(['RecoverSe', '回復効果音']);

    //=============================================================================
    // Game_BattlerBase
    //  吸収の有効率を設定します。
    //=============================================================================
    Game_BattlerBase.prototype.getDrainEffectiveRate = function(subject) {
        var rate = null;
        var a = subject;
        var b = this;
        this.traitObjects().forEach(function(traitObj) {
            var meta = getMetaValues(traitObj, ['EffectiveRate', '有効率']);
            if (meta) {
                rate = Math.max(rate || 0, eval(convertEscapeCharacters(meta)) / 100);
            }
        });
        return rate !== null ?  rate : 1.0;
    };

    //=============================================================================
    // Game_Action
    //  吸収の仕様を拡張します。
    //=============================================================================
    var _Game_Action_isDrain = Game_Action.prototype.isDrain;
    Game_Action.prototype.isDrain = function() {
        if (this._temporaryDisableDrain) {
            this._temporaryDisableDrain = false;
            return false;
        }
        return _Game_Action_isDrain.apply(this, arguments);
    };

    Game_Action.prototype.getDrainExtendMeta = function(paramNames) {
        return getMetaValues(this.item(), paramNames);
    };

    Game_Action.prototype.getHpDrainRate = function(original) {
        var rate =  this.getDrainRate(['PercentageHP', 'HP吸収率']);
        return rate !== undefined ? rate / 100 : (original ? 1 : undefined);
    };

    Game_Action.prototype.getMpDrainRate = function(original) {
        var rate =  this.getDrainRate(['PercentageMP', 'MP吸収率']);
        return rate !== undefined ? rate / 100 : (original ? 1 : undefined);
    };

    Game_Action.prototype.getTpDrainRate = function() {
        var rate =  this.getDrainRate(['PercentageTP', 'TP吸収率']);
        return rate !== undefined ? rate / 100 : undefined;
    };

    Game_Action.prototype.getDrainRate = function(metaParams) {
        var rate = convertEscapeCharacters(this.getDrainExtendMeta(metaParams));
        var a = this.subject();
        var b = this._drainTarget;
        return rate ? eval(rate) : undefined;
    };

    Game_Action.prototype.isDrainMessageAttack = function() {
        return !!this.getDrainExtendMeta(['AttackMessage', '攻撃メッセージ']);
    };

    Game_Action.prototype.isDrainLimitOver = function() {
        return !!this.getDrainExtendMeta(['LimitOver', '上限突破']);
    };

    var _Game_Action_apply = Game_Action.prototype.apply;
    Game_Action.prototype.apply = function(target) {
        if (this.isDrainMessageAttack()) {
            this._temporaryDisableDrain = true;
        }
        this._drainTarget = target;
        return _Game_Action_apply.apply(this, arguments);
    };

    var _Game_Action_executeHpDamage = Game_Action.prototype.executeHpDamage;
    Game_Action.prototype.executeHpDamage = function(target, value) {
        if (this.isDrainLimitOver()) this._temporaryDisableDrain = true;
        _Game_Action_executeHpDamage.apply(this, arguments);
    };

    var _Game_Action_gainDrainedHp = Game_Action.prototype.gainDrainedHp;
    Game_Action.prototype.gainDrainedHp = function(value) {
        this.gainDrainedParam(value, 'hp');
    };

    var _Game_Action_gainDrainedMp = Game_Action.prototype.gainDrainedMp;
    Game_Action.prototype.gainDrainedMp = function(value) {
        this.gainDrainedParam(value, 'mp');
    };

    Game_Action.prototype.gainDrainedParam = function(value, originalType) {
        var effectiveRate = this._drainTarget.getDrainEffectiveRate(this.subject());
        var hpRate = this.getHpDrainRate(originalType === 'hp');
        if (hpRate !== undefined) {
            var hpValue = Math.floor(value * hpRate * effectiveRate);
            if (hpValue !== 0) {
                _Game_Action_gainDrainedHp.call(this, hpValue);
            }
        }
        var mpRate = this.getMpDrainRate(originalType === 'mp');
        if (mpRate !== undefined) {
            var mpValue = Math.floor(value * mpRate * effectiveRate);
            if (mpValue !== 0) {
                _Game_Action_gainDrainedMp.call(this, mpValue);
            }
        }
        var tpRate = this.getTpDrainRate();
        if (tpRate !== undefined) {
            var tpValue = Math.floor(value * tpRate * effectiveRate);
            if (tpValue !== 0) {
                this.gainDrainedTp(tpValue);
            }
        }
    };

    Game_Action.prototype.gainDrainedTp = function(value) {
        if (this.isDrain()) {
            var gainTarget = this.subject();
            if (this._reflectionTarget !== undefined) {
                gainTarget = this._reflectionTarget;
            }
            gainTarget.gainTp(value);
        }
    };

    //=============================================================================
    // Window_BattleLog
    //  吸収時に回復効果音を演奏します。
    //=============================================================================
    var _Window_BattleLog_displayDamage = Window_BattleLog.prototype.displayDamage;
    Window_BattleLog.prototype.displayDamage = function(target) {
        _Window_BattleLog_displayDamage.apply(this, arguments);
        if (this.isNeedDrainRecoverSe(target.result())) {
            this.push('performRecovery', target);
        }
    };

    Window_BattleLog.prototype.isNeedDrainRecoverSe = function(result) {
        return param.recoverSe && !result.missed && !result.evaded && result.drain;
    };
})();


code:
//=============================================================================
// DynamicDatabase.js
// ----------------------------------------------------------------------------
// (C)2015-2018 Triacontane
// This software is released under the MIT License.
// http://opensource.org/licenses/mit-license.php
// ----------------------------------------------------------------------------
// Version
// 1.3.2 2019/08/25 1.3.1の修正方法に誤りがあったため再度修正
// 1.3.1 2019/06/02 後方互換性を考慮しデータベースの元の値を参照する際「元の値」という変数名を使えるようになりました。
// 1.3.0 2019/02/10 計算式中に不等号を使えるようエスケープ処理を追加
// 1.2.9 2018/08/04 1.2.8の修正により、レベルアップメッセージなどでアクター名が正常に取得できなくなっていた問題を修正
// 1.2.8 2018/04/29 アクターの名前、二つ名、プロフィールについて一部の制御文字が正常に動作していなかった問題を修正
// 1.2.7 2017/10/07 リファクタリング
// 1.2.6 2017/06/09 全設定一覧のスプレッドシートへのリンクを説明に追加
// 1.2.5 2017/06/02 1.2.4の修正により動作しなくなっていた問題を修正
// 1.2.4 2017/05/27 競合の可能性のある記述（Objectクラスへのプロパティ追加）をリファクタリング
// 1.2.3 2017/02/16 1.2.2で数値を0に設定すると動的設定が効かなくなる問題を修正
// 1.2.2 2017/02/16 データベースに項目を追加するプラグインで発生する可能性のある競合対策
// 1.2.1 2017/02/12 汎用的な競合対策
// 1.2.0 2017/02/10 アクターと職業のデータベースについて「特徴」のみ動的データベースに対応
// 1.1.1 2017/01/19 設定値に入れた小数点以下の値が切り捨てられていた問題を修正
// 1.1.0 2016/08/15 コード整形、ドロップアイテムにドロップアイテムIDの定義が抜けていたのを修正
// 1.0.2 2016/05/16 特徴と効果にデータIDの定義を追加
// 1.0.1 2016/01/03 iterateとisEmptyが重複定義されないよう対応
// 1.0.0 2015/12/28 初版
// ----------------------------------------------------------------------------
// [Blog]   : https://triacontane.blogspot.jp/
// [Twitter]: https://twitter.com/triacontane/
// [GitHub] : https://github.com/triacontane/
//=============================================================================

/*:
 * @plugindesc 動的データベース構築プラグイン
 * @author トリアコンタン
 *
 * @help データベースの各項目を動的な値に変更するプラグインです。
 * 変数やJavaScriptの関数を使ってより高度なデータベースを構築できます。
 *
 * 注意！　データベースファイルを保存、更新するプラグインと併用しないでください。
 *
 * 文字列項目：各項目に直接入力した制御文字が利用できます。
 * 数値項目：メモ欄に入力した制御文字＋JavaScript計算式が利用できます。
 * 選択項目：メモ欄に入力した制御文字＋JavaScript計算式が利用できます。
 * 　　　　　※一番上の選択肢が 0 になります。
 *
 * 数値、選択項目の場合、メモ欄に以下の通り指定してください。
 * 　<DD（項目名）:（計算式）>
 *
 * 設定例１（アイテムの価格に10番の変数の2倍の値を設定したい場合）
 * 　<DD価格:\V[10] * 2>
 *
 * 設定例２（武器の攻撃力に、元の値と10番の変数の値との乗算値を設定したい場合）
 * 　<DD攻撃力:prev * \V[10]>
 *
 * 計算式中で不等号を使いたい場合、以下のように記述してください。
 * < → <
 * > → >
 *
 * 対象データベースは以下の全項目になります。
 * 　アクター（特徴のみ）
 * 　職業（特徴のみ）
 * 　スキル
 * 　アイテム
 * 　武器
 * 　防具
 * 　敵キャラ
 * 　ステート
 *
 * 設定可能な項目の詳細は以下のリンクを参照ください。
 * https://docs.google.com/spreadsheets/d/1BnTyJr3Z1WoW4FMKtvKaICl4SQ5ehL5RxTDSV81oVQc/edit#gid=894678948
 *
 * このプラグインにはプラグインコマンドはありません。
 *
 * 利用規約：
 *  作者に無断で改変、再配布が可能で、利用形態（商用、18禁利用等）
 *  についても制限はありません。
 *  このプラグインはもうあなたのものです。
 */

(function() {
    'use strict';

    Number.prototype.times = function(handler) {
        var i = 0;
        while (i < this) handler.call(this, i++);
    };

    //=============================================================================
    // Scene_Boot
    //  ダイナミックデータベースの構築開始
    //=============================================================================
    var _Scene_Boot_start      = Scene_Boot.prototype.start;
    Scene_Boot.prototype.start = function() {
        _Scene_Boot_start.call(this);
        DynamicDatabaseManager.makeDynamicDatabase();
    };

    //=============================================================================
    // Game_Actor
    //  アクター名、二つ名、プロフィールについて変更されるまではDBから再取得するよう修正
    //=============================================================================
    var _Game_Actor_setup = Game_Actor.prototype.setup;
    Game_Actor.prototype.setup = function(actorId) {
        _Game_Actor_setup.apply(this, arguments);
        this.__nickname = null;
        this.__profile = null;
        this.__name = null;
    };

    Object.defineProperty(Game_Actor.prototype, '_profile', {
        get: function() {
            return this.__profile !== null ? this.__profile : this.actor().profile;
        },
        set: function(name) {
            this.__profile = name;
        },
    });

    Object.defineProperty(Game_Actor.prototype, '_nickname', {
        get: function() {
            return this.__nickname !== null ? this.__nickname : this.actor().nickname;
        },
        set: function(name) {
            this.__nickname = name;
        },
    });

    Object.defineProperty(Game_Actor.prototype, '_name', {
        get: function() {
            return this.__name !== null ? this.__name : this.actor().name;
        },
        set: function(name) {
            this.__name = name;
        },
    });
})();

/**
 * DynamicDatabaseManager
 *  ダイナミックデータベースの構築処理を定義します。
 * @constructor
 */
function DynamicDatabaseManager() {
    throw new Error('This is a static class');
}

DynamicDatabaseManager._columnMapper = null;
DynamicDatabaseManager._targetData   = null;

DynamicDatabaseManager._columnMapperCoomon = {
    animationId     : 'アニメーション',
    hitType         : '命中タイプ',
    iconIndex       : 'アイコン',
    occasion        : '使用可能時',
    repeats         : '連続回数',
    scope           : '範囲',
    speed           : '速度補正',
    successRate     : '成功率',
    tpCost          : '消費TP',
    tpGain          : '得TP',
    mpCost          : '消費MP',
    damage_elementId: '属性',
    damage_type     : 'タイプ',
    damage_variance : '分散度',
    price           : '価格',
    params_0        : '最大HP',
    params_1        : '最大MP',
    params_2        : '攻撃力',
    params_3        : '防御力',
    params_4        : '魔法力',
    params_5        : '魔法防御',
    params_6        : '敏捷性',
    params_7        : '運'
};

DynamicDatabaseManager._columnMapperSkills = {
    stypeId         : 'スキルタイプ',
    requiredWtypeId1: '武器タイプ1',
    requiredWtypeId2: '武器タイプ2'
};

DynamicDatabaseManager._columnMapperItems = {
    itypeId   : 'アイテムタイプ',
    consumable: '消耗'
};

DynamicDatabaseManager._columnMapperWeapons = {
    wtypeId: '武器タイプ'
};

DynamicDatabaseManager._columnMapperArmors = {
    atypeId: '防具タイプ',
    etypeId: '装備タイプ'
};

DynamicDatabaseManager._columnMapperEnemies = {
    battlerHue: '色相',
    exp       : '経験値',
    gold      : '所持金'
};

DynamicDatabaseManager._columnMapperStates = {
    autoRemovalTiming  : '自動解除のタイミング',
    chanceByDamage     : 'ダメージで解除_ダメージ',
    maxTurns           : '継続ターン数_最大',
    minTurns           : '継続ターン数_最小',
    motion             : '[SV] モーション',
    overlay            : '[SV] 重ね合わせ',
    priority           : '優先度',
    removeAtBattleEnd  : '戦闘終了時に解除',
    removeByDamage     : 'ダメージで解除',
    removeByRestriction: '行動制約で解除',
    removeByWalking    : '歩数で解除',
    restriction        : '行動制約',
    stepsToRemove      : '歩数で解除_歩数'
};

DynamicDatabaseManager._targetDynamicDatabase = {
    $dataActors : DynamicDatabaseManager._columnMapperCoomon,
    $dataClasses: DynamicDatabaseManager._columnMapperCoomon,
    $dataSkills : DynamicDatabaseManager._columnMapperSkills,
    $dataItems  : DynamicDatabaseManager._columnMapperItems,
    $dataWeapons: DynamicDatabaseManager._columnMapperWeapons,
    $dataArmors : DynamicDatabaseManager._columnMapperArmors,
    $dataEnemies: DynamicDatabaseManager._columnMapperEnemies,
    $dataStates : DynamicDatabaseManager._columnMapperStates
};

DynamicDatabaseManager._isEmpty = function(that) {
    return Object.keys(that).length <= 0;
};

DynamicDatabaseManager._iterate = function(that, handler) {
    Object.keys(that).forEach(function(key, index) {
        handler.call(that, key, that[key], index);
    });
};

DynamicDatabaseManager.makeDynamicDatabase = function() {
    this._setColumnMapperDynamic();
    this._iterate(this._targetDynamicDatabase, function(dataKey, columnMap) {
        this._makeDynamicData(window[dataKey], columnMap);
    }.bind(this));
};

DynamicDatabaseManager._setColumnMapperDynamic = function() {
    this._getMaxLength('effects').times(function(i) {
        this._columnMapperCoomon['effects_%1_code'.format(i)]   = '使用効果%1_タイプ'.format(i + 1);
        this._columnMapperCoomon['effects_%1_dataId'.format(i)] = '使用効果%1_データID'.format(i + 1);
        this._columnMapperCoomon['effects_%1_value1'.format(i)] = '使用効果%1_内容1'.format(i + 1);
        this._columnMapperCoomon['effects_%1_value2'.format(i)] = '使用効果%1_内容2'.format(i + 1);

    }.bind(this));
    this._getMaxLength('traits').times(function(i) {
        this._columnMapperCoomon['traits_%1_code'.format(i)]   = '特徴%1_タイプ'.format(i + 1);
        this._columnMapperCoomon['traits_%1_dataId'.format(i)] = '特徴%1_データID'.format(i + 1);
        this._columnMapperCoomon['traits_%1_value'.format(i)]  = '特徴%1_内容'.format(i + 1);
    }.bind(this));
    this._getMaxLength('actions').times(function(i) {
        this._columnMapperEnemies['actions_%1_conditionParam1'.format(i)] = '行動%1_条件1'.format(i + 1);
        this._columnMapperEnemies['actions_%1_conditionParam2'.format(i)] = '行動%1_条件2'.format(i + 1);
        this._columnMapperEnemies['actions_%1_conditionType'.format(i)]   = '行動%1_条件タイプ'.format(i + 1);
        this._columnMapperEnemies['actions_%1_rating'.format(i)]          = '行動%1_R'.format(i + 1);
        this._columnMapperEnemies['actions_%1_skillId'.format(i)]         = '行動%1_スキル'.format(i + 1);
    }.bind(this));
    Number(3).times(function(i) {
        this._columnMapperEnemies['dropItems_%1_denominator'.format(i)] = 'ドロップアイテム%1_ドロップアイテム'.format(i + 1);
        this._columnMapperEnemies['dropItems_%1_dataId'.format(i)]      = 'ドロップアイテム%1_ドロップアイテムID'.format(i + 1);
        this._columnMapperEnemies['dropItems_%1_kind'.format(i)]        = 'ドロップアイテム%1_出現率'.format(i + 1);
    }.bind(this));
};

DynamicDatabaseManager._getMaxLength = function(keyName) {
    var length = 0;
    this._iterate(this._targetDynamicDatabase, function(dataKey) {
        var dataArray = window[dataKey];
        dataArray.forEach(function(data) {
            if (data && data.hasOwnProperty(keyName)) {
                length = Math.max(data[keyName].length, length);
            }
        });
    });
    return length;
};

DynamicDatabaseManager._makeDynamicData = function(dataArray, columnMap) {
    this._columnMapper = columnMap;
    dataArray.forEach(function(data) {
        if (data) {
            this._targetData = data;
            this._iterate(data, function(key, value) {
                this._makeProperty(data, key, key, value);
            }.bind(this));
        }
    }.bind(this));
};

DynamicDatabaseManager._makeProperty = function(parent, keyPath, key, child) {
    if (key === 'meta') {
        return;
    }
    switch (typeof child) {
        case 'string':
            if (child.match(/\\/g)) {
                this._makePropertyString(parent, key, child);
            }
            break;
        case 'boolean':
        case 'number':
            if (this._isEmpty(parent.meta)) {
                return;
            }
            var propName = this._columnMapper[keyPath] || this._columnMapperCoomon[keyPath];
            var metaTag  = 'DD' + propName;
            if (propName != null && parent.meta[metaTag] != null)  {
                this._makePropertyFormula(parent, key, child, metaTag);
            }
            parent[propName] = child;
            break;
        case 'object':
            if (!child || this._isEmpty(parent.meta)) {
                return;
            }
            child.meta = parent.meta;
            this._iterate(child, function(valuesKey, valuesItem) {
                this._makeProperty(child, keyPath + '_' + valuesKey, valuesKey, valuesItem);
            }.bind(this));
            break;
    }
};

DynamicDatabaseManager._makePropertyFormula = function(parent, key, child, metaTag) {
    var data = this._targetData;
    Object.defineProperty(parent, key, {
        get: function() {
            var prev = child, 元の値 = child;
            var result = eval(DynamicDatabaseManager._convertEscapeCharacters(this.meta[metaTag]));
            return typeof child === 'number' ? result : !!result;
        }
    });
};

DynamicDatabaseManager._makePropertyString = function(parent, key, child) {
    Object.defineProperty(parent, key, {
        get: function() {
            return DynamicDatabaseManager._convertEscapeCharacters(child);
        }
    });
};

DynamicDatabaseManager._convertEscapeCharacters = function(text) {
    text = text.replace(/>?/gi, '>');
    text = text.replace(/<?/gi, '<');
    text = text.replace(/\\/g, '\x1b');
    text = text.replace(/\x1b\x1b/g, '\\');
    text = text.replace(/\x1bV\[(\d+)\]/gi, function() {
        return $gameVariables ? $gameVariables.value(parseInt(arguments[1], 10)) : 0;
    });
    text = text.replace(/\x1bV\[(\d+)\]/gi, function() {
        return $gameVariables ? $gameVariables.value(parseInt(arguments[1], 10)) : 0;
    });
    text = text.replace(/\x1bS\[(\d+)\]/gi, function() {
        return $gameSwitches ? ($gameSwitches.value(parseInt(arguments[1], 10)) ? '1' : '0') : '0';
    });
    text = text.replace(/\x1bN\[(\d+)\]/gi, function() {
        var n     = parseInt(arguments[1]);
        var actor = (n >= 1 && $gameActors ? $gameActors.actor(n) : null);
        return actor ? actor.name() : '';
    });
    text = text.replace(/\x1bP\[(\d+)\]/gi, function() {
        var n     = parseInt(arguments[1]);
        var actor = (n >= 1 && $gameParty ? $gameParty.members()[n - 1] : null);
        return actor ? actor.name() : '';
    });
    text = text.replace(/\x1bG/gi, TextManager.currencyUnit);
    return text;
};


code:
//=============================================================================
// DynamicVariables.js
// ----------------------------------------------------------------------------
// (C)2016 Triacontane
// This software is released under the MIT License.
// http://opensource.org/licenses/mit-license.php
// ----------------------------------------------------------------------------
// Version
// 1.2.0 2020/10/18 リファクタリングとヘルプの整理
// 1.1.1 2018/09/27 テストプレー時はパラメータ「例外処理」の値に関係なくスクリプトエラーで異常終了しないよう修正
// 1.1.0 2018/08/19 イベントページの出現条件および敵キャラの行動パターンで各オブジェクトおよびデータを参照できる機能を追加
// 1.0.5 2018/01/27 1.0.4の更新でもともと入っていた値の取得方法をvalueに変更
// 1.0.4 2018/01/15 実行時に対象スイッチIDおよび代入されているもとの値を参照できる機能を追加
// 1.0.3 2017/08/12 パラメータの型指定機能に対応
// 1.0.2 2016/11/04 指定範囲外のスイッチの値を正しく返していなかった問題を修正
// 1.0.1 2016/11/01 結果が空文字の場合に0が設定されないよう修正
// 1.0.0 2016/10/27 初版
// ----------------------------------------------------------------------------
// [Blog]   : https://triacontane.blogspot.jp/
// [Twitter]: https://twitter.com/triacontane/
// [GitHub] : https://github.com/triacontane/
//=============================================================================

/*:
 * @plugindesc DynamicVariablesPlugin
 * @author triacontane
 *
 * @param DynamicSwitchStart
 * @desc The start position number of the dynamic switch.
 * @default 0
 * @type switch
 *
 * @param DynamicSwitchEnd
 * @desc The end position number of the dynamic switch.
 * @default 0
 * @type switch
 *
 * @param DynamicVariableStart
 * @desc The start position number of the dynamic variable.
 * @default 0
 * @type variable
 *
 * @param DynamicVariableEnd
 * @desc The end position number of the dynamic variable.
 * @default 0
 * @type variable
 *
 * @param ValidException
 * @desc Handles exceptions during script execution.
 * @default false
 * @type boolean
 *
 * @help When a variable or switch in the specified range is referenced
 * Returns the result of evaluating "variable name" and "switch name" as a script.
 * The following local variables can be used in the script
 *
 * id # ID of the switch or variable to be processed
 * value # the value that was originally in the switch or variable ID to be processed
 *
 * Dynamic variables are valid in all places (*) that refer to variables and switches.
 *
 * Examples of referring to variables and switches
 * 1. decision processing of the event page
 * 2. enemy character action decision processing
 * 3. conditional branching
 * 4. various operands of event commands.
 * 5. Other plug-in references
 *
 * You can also reference additional dynamic variables and switches in your scripts, but you can also use the
 * If you try to reference the variable (switch) with the same number, a circular reference occurs and an error occurs.
 *
 * If you try to refer to a variable (switch) with the same number, it will be a circular reference and an error will occur.
 * Normally, the process of determining the page of events is done when one of the switches or variables is
 * It only runs when it is changed.
 * The plugin retains that specification for performance reasons.
 * If you enter the following in the event memo field, only that event will be executed when
 * You can change it to always check the page conditions.
 *
 * <DVAlwaysRefresh>
 *
 * There are no plug-in commands in this plugin.
 *
 * This plugin is released under the MIT License.
 */
/*:ja
 * @plugindesc 動的変数プラグイン
 * @author トリアコンタン
 *
 * @param DynamicSwitchStart
 * @text 動的スイッチ開始位置
 * @desc 動的スイッチの開始位置番号です。
 * @default 0
 * @type switch
 *
 * @param DynamicSwitchEnd
 * @text 動的スイッチ終了位置
 * @desc 動的スイッチの終了位置番号です。
 * @default 0
 * @type switch
 *
 * @param DynamicVariableStart
 * @text 動的変数開始位置
 * @desc 動的変数の開始位置番号です。
 * @default 0
 * @type variable
 *
 * @param DynamicVariableEnd
 * @text 動的変数終了位置
 * @desc 動的変数の終了位置番号です。
 * @default 0
 * @type variable
 *
 * @param ValidException
 * @text 例外処理
 * @desc スクリプト実行時に例外処理を行います。不正なスクリプトで強制終了しなくなる代わりに実行速度が僅かに低下します。
 * @default false
 * @type boolean
 *
 * @help 指定範囲内の変数、スイッチを参照したとき
 * 「変数名称」及び「スイッチ名称」をスクリプトとして評価した結果を返します。
 * スクリプト中では以下のローカル変数が利用できます。
 *
 * id    # 処理対象のスイッチ、変数ID
 * value # 処理対象のスイッチ、変数IDにもともと入っていた値
 *
 * イベントページの出現条件でスイッチを参照する場合、追加で以下の変数が使えます。
 * e     # イベントオブジェクトへの参照
 * d     # イベントデータへの参照
 *
 * 敵キャラの行動パターンでスイッチを参照する場合、追加で以下の変数が使えます。
 * e     # 敵キャラオブジェクトへの参照
 * d     # 敵キャラデータへの参照
 *
 * 動的変数は、変数およびスイッチを参照するすべての箇所(※)で有効です。
 *
 * ※ 変数・スイッチを参照する例
 * 1. イベントページの決定処理
 * 2. 敵キャラの行動決定処理
 * 3. 条件分岐
 * 4. イベントコマンドの各種オペランド
 * 5. その他プラグインによる参照
 *
 * スクリプト中でさらに動的変数およびスイッチを参照することもできますが
 * 同じ番号の変数(スイッチ)を参照しようとすると循環参照となりエラーが発生します。
 *
 * ・使用上の注意
 * 通常、イベントのページを決定する処理は、いずれかのスイッチもしくは変数が
 * 変更されたときにのみ実行されます。
 * 本プラグインでは、パフォーマンス上の理由からその仕様を維持します。
 * イベントのメモ欄に以下の通り入力すると、そのイベントのみ
 * 常にページの条件チェックを行うように変更できます。
 *
 * <DV常時リフレッシュ>
 * <DVAlwaysRefresh>
 *
 * このプラグインにはプラグインコマンドはありません。
 *
 * 利用規約：
 *  作者に無断で改変、再配布が可能で、利用形態（商用、18禁利用等）
 *  についても制限はありません。
 *  このプラグインはもうあなたのものです。
 */

(function() {
    'use strict';
    var metaTagPrefix = 'DV';

    var getMetaValue = function(object, name) {
        var metaTagName = metaTagPrefix + (name ? name : '');
        return object.meta.hasOwnProperty(metaTagName) ? object.meta[metaTagName] : undefined;
    };

    var getMetaValues = function(object, names) {
        if (!Array.isArray(names)) return getMetaValue(object, names);
        for (var i = 0, n = names.length; i < n; i++) {
            var value = getMetaValue(object, names[i]);
            if (value !== undefined) return value;
        }
        return undefined;
    };

    var createPluginParameter = function(pluginName) {
        var paramReplacer = function(key, value) {
            if (value === 'null') {
                return value;
            }
            if (value[0] === '"' && value[value.length - 1] === '"') {
                return value;
            }
            try {
                return JSON.parse(value);
            } catch (e) {
                return value;
            }
        };
        var parameter     = JSON.parse(JSON.stringify(PluginManager.parameters(pluginName), paramReplacer));
        PluginManager.setParameters(pluginName, parameter);
        return parameter;
    };

    var param = createPluginParameter('DynamicVariables');

    // eval参照用
    var e = null;
    var d = null;
    var max = Math.max, min = Math.min, abs = Math.abs, floor = Math.floor, pow = Math.pow, random = Math.random;
    var dActors       = $dataActors;
    var dClasses      = $dataClasses;
    var dSkills       = $dataSkills;
    var dItems        = $dataItems;
    var dWeapons      = $dataWeapons;
    var dArmors       = $dataArmors;
    var dEnemies      = $dataEnemies;
    var dTroops       = $dataTroops;
    var dStates       = $dataStates;
    var dAnimations   = $dataAnimations;
    var dTilesets     = $dataTilesets;
    var dCommonEvents = $dataCommonEvents;
    var dSystem       = $dataSystem;
    var dMapInfos     = $dataMapInfos;
    var dMap          = $dataMap;
    var gTemp         = $gameTemp;
    var gSystem       = $gameSystem;
    var gScreen       = $gameScreen;
    var gTimer        = $gameTimer;
    var gMessage      = $gameMessage;
    var gSwitches     = $gameSwitches;
    var gActors       = $gameActors;
    var gParty        = $gameParty;
    var gTroop        = $gameTroop;
    var gMap          = $gameMap;
    var gPlayer       = $gamePlayer;

    //=============================================================================
    // Game_Variables
    //  動的変数の取得処理を追加定義します。
    //=============================================================================
    var _Game_Variables_value      = Game_Variables.prototype.value;
    Game_Variables.prototype.value = function(variableId) {
        var value = _Game_Variables_value.apply(this, arguments);
        if (variableId >= param.DynamicVariableStart && variableId <= param.DynamicVariableEnd) {
            return this.getDynamicValue($dataSystem.variables[variableId], variableId, value);
        } else {
            return value;
        }
    };

    Game_Variables.prototype.getOriginalValue = function(variableId) {
        return _Game_Variables_value.apply(this, arguments);
    };

    Game_Variables.prototype.getDynamicValue = function(dynamicScript, id, value) {
        if (!dynamicScript) {
            return value;
        }
        var v = $gameVariables.value.bind($gameVariables);
        var s = $gameSwitches.value.bind($gameSwitches);
        if (param.ValidException || $gameTemp.isPlaytest()) {
            try {
                return eval(dynamicScript);
            } catch (e) {
                console.error(e.message);
                return 0;
            }
        } else {
            return eval(dynamicScript);
        }
    };

    //=============================================================================
    // Game_Switches
    //  動的スイッチの取得処理を追加定義します。
    //=============================================================================
    var _Game_Switches_value      = Game_Switches.prototype.value;
    Game_Switches.prototype.value = function(switchId) {
        var value = _Game_Switches_value.apply(this, arguments);
        if (switchId >= param.DynamicSwitchStart && switchId <= param.DynamicSwitchEnd) {
            return !!this.getDynamicValue($dataSystem.switches[switchId], switchId, value);
        } else {
            return value;
        }
    };

    Game_Switches.prototype.getOriginalValue = function(switchId) {
        return _Game_Switches_value.apply(this, arguments);
    };

    Game_Switches.prototype.getDynamicValue = Game_Variables.prototype.getDynamicValue;

    //=============================================================================
    // Game_Event
    //  必要な場合、イベントページを毎フレームリフレッシュします。
    //=============================================================================
    var _Game_Event_initialize      = Game_Event.prototype.initialize;
    Game_Event.prototype.initialize = function(mapId, eventId) {
        _Game_Event_initialize.apply(this, arguments);
        this._needsAlwaysRefresh = this.isNeedAlwaysRefresh();
    };

    Game_Event.prototype.isNeedAlwaysRefresh = function() {
        return getMetaValues(this.event(), ['AlwaysRefresh', '常時リフレッシュ']);
    };

    var _Game_Event_update      = Game_Event.prototype.update;
    Game_Event.prototype.update = function() {
        if (this._needsAlwaysRefresh) {
            this.refresh();
        }
        if(($gameSwitches.value(11))&&($gameVariables.value(66)!=$gameParty.steps())){
        	$gameTemp.reserveCommonEvent(204);
        	$gameVariables._data[66]=$gameParty.steps();
        }
        _Game_Event_update.apply(this, arguments);
    };

    var _Game_Event_meetsConditions      = Game_Event.prototype.meetsConditions;
    Game_Event.prototype.meetsConditions = function(page) {
        e          = this;
        d          = this.event();
        var result = _Game_Event_meetsConditions.apply(this, arguments);
        e          = null;
        d          = null;
        return result;
    };

    /**
     * Game_Enemy
     * 敵キャラ情報をスクリプト実行用に記憶します。
     */
    var _Game_Enemy_meetsSwitchCondition      = Game_Enemy.prototype.meetsSwitchCondition;
    Game_Enemy.prototype.meetsSwitchCondition = function(param) {
        e          = this;
        d          = this.enemy();
        var result = _Game_Enemy_meetsSwitchCondition.apply(this, arguments);
        e          = null;
        d          = null;
        return result;
    };
})();