code:
//=============================================================================
// Mano_CoinShop.js
// ----------------------------------------------------------------------------
// Copyright (c) 2019-2019 Sigureya
// This software is released under the MIT License.
// http://opensource.org/licenses/mit-license.php
// ----------------------------------------------------------------------------
// Version
// 0.9.0 2019/05/26 初版
// ----------------------------------------------------------------------------
// [Twitter]: https://twitter.com/Sigureya/
//=============================================================================
/*:
 * @plugindesc 変数やアイテムを消費して購入できるショップが作れます。
 * 競合率・中ぐらい
 * @author しぐれん(https://github.com/Sigureya/RPGmakerMV)
 *
 * @help
 * お金の代わりに変数やアイテムを消費して購入できるショップを作成できます。
 *
 * 内部的には専用の財布を作って、そこに処理を流します。
 * 既存処理を再定義しているため、競合の可能性があります。
 * （ポイントカードのようなプラグインを使っている場合、これより後ろにおいてください）
 *
 * プラグインコマンドで以下の内容を入力してください。
 * 設定変更は１回のみ有効です。
 *
 * ShopMode モード 識別番号 単位
 * パラメータは上記の通りです。
 * この機能を使った場合、売却機能は強制的にロックされます。
 *
 * ShopMode Variable 8 枚
 * お金の代わりに変数8番の数値を見ます。
 * 単位として「枚」を使うようになります。
 *
 * ShopMode item 3 個
 * お金の代わりにitemID[3]のアイテムの所持数を見ます
 * 単位として「個」を使うようになります。
 *
 * 2019/05/26 公開
 *
 */

(function () {
  "use strict";

  class WalletBase {
    /**
     * @param {String} unit
     */
    constructor(unit) {
      this.setUnit(unit || TextManager.currencyUnit);
    }
    /**
     * @param {String} unit
     */
    setUnit(unit) {
      this._unit = unit;
    }

    value() {
      return 0;
    }
    pay(value) {}

    loseValue(value) {
      this.pay(value);
    }

    gainValue(value) {
      this.pay(-value);
    }
    unit() {
      return this._unit;
    }

    canSeil() {
      return false;
    }

    isGold() {
      return false;
    }
  }

  class WalletGold extends WalletBase {
    constructor() {
      super(TextManager.currencyUnit);
    }
    value() {
      return $gameParty.gold();
    }
    pay(value) {
      $gameParty.loseGold(value);
    }
    canSeil() {
      return true;
    }
    isGold() {
      return true;
    }
  }

  class WalletItem extends WalletBase {
    /**
     * @param {Number} itemId
     */
    constructor(itemId) {
      super();
      this._itemId = itemId;
    }

    item() {
      return $dataItems[this._itemId];
    }

    value() {
      return $gameParty.numItems(this.item());
    }

    pay(value) {
      $gameParty.loseItem(this.item(), value);
    }
  }
  window[WalletItem.name] = WalletItem;

  class WalletVariable extends WalletBase {
    /**
     * @param {Number} id
     */
    constructor(id) {
      super();
      this._variableId = id;
    }
    value() {
      return $gameVariables.value(this._variableId);
    }

    pay(value) {
      const lastValue = this.value();
      $gameVariables.setValue(this._variableId, lastValue - value);
    }
  }

  /**
   * @returns {WalletBase}
   * @param {String} mode
   * @param {Number} id
   */
  function makeWallet(mode, id) {
    if (mode === "item") {
      const wi = new WalletItem(id);
      return wi;
    }

    if (mode === "Variable" || mode === "variable") {
      const wv = new WalletVariable(id);
      return wv;
    }

    return new WalletGold();
  }

  let g_wallet = null;
  const Game_Interpreter_pluginCommand =
    Game_Interpreter.prototype.pluginCommand;
  Game_Interpreter.prototype.pluginCommand = function (cmd, args) {
    if (cmd === "ShopMode") {
      const mode = args[0];
      const id = Number(args[1]);
      const unit = args[2];
      const wallet = makeWallet(mode, id);
      wallet.setUnit(unit);
      g_wallet = wallet;
      return;
    }
    Game_Interpreter_pluginCommand.call(this, cmd, args);
  };

  const Scene_Load_onLoadSuccess = Scene_Load.prototype.onLoadSuccess;
  Scene_Load.prototype.onLoadSuccess = function () {
    g_wallet = null;
    Scene_Load_onLoadSuccess.call(this);
  };

  Window_Gold.prototype.setupWallet = function () {
    const w = g_wallet || new WalletGold();
    this._wallet = w;
    g_wallet = null;
  };
  Window_Gold.prototype.value = function () {
    return this._wallet.value();
  };

  Window_Gold.prototype.currencyUnit = function () {
    return this._wallet.unit();
  };
  Window_Gold.prototype.wallet = function () {
    return this._wallet;
  };

  const Window_Gold_initialize = Window_Gold.prototype.initialize;
  Window_Gold.prototype.initialize = function (x, y) {
    this.setupWallet();
    Window_Gold_initialize.call(this, x, y);
  };
  const Scene_Shop_createGoldWindow = Scene_Shop.prototype.createGoldWindow;
  Scene_Shop.prototype.createGoldWindow = function () {
    Scene_Shop_createGoldWindow.call(this);
    this._purchaseOnly =
      this._purchaseOnly || !this._goldWindow.wallet().canSeil();
  };

  Scene_Shop.prototype.doBuy = function (number) {
    this._goldWindow.wallet().loseValue(number * this.buyingPrice());
    $gameParty.gainItem(this._item, number);
  };

  Scene_Shop.prototype.doSell = function (number) {
    const p = number * this.sellingPrice();
    this._goldWindow.wallet().gainValue(p);
    $gameParty.loseItem(this._item, number);
  };
})();


code:
//=============================================================================
// MasterVolumeOption.js
// ----------------------------------------------------------------------------
// Copyright (c) 2015-2017 Triacontane
// This software is released under the MIT License.
// http://opensource.org/licenses/mit-license.php
// ----------------------------------------------------------------------------
// Version
// 1.1.2 2018/01/15 RPGアツマールのマスターボリューム調整機能と競合する旨をヘルプに追記
// 1.1.1 2017/06/29 マスターボリュームの増減値を変更したときに計算誤差が表示される場合がある問題を修正
// 1.1.0 2017/06/26 ボリュームの変化量を変更できる機能を追加（byツミオさん）
// 1.0.0 2017/06/24 初版
// ----------------------------------------------------------------------------
// [Blog]   : https://triacontane.blogspot.jp/
// [Twitter]: https://twitter.com/triacontane/
// [GitHub] : https://github.com/triacontane/
//=============================================================================

/*:
 * @plugindesc MasterVolumePlugin
 * @author triacontane      (Tsumio altered a portion.)
 *
 * @param ItemName
 * @type string
 * @desc It is a setting item name displayed on Options.
 * @default Master Volume
 *
 * @param DefaultValue
 * @type number
 * @desc Default value of the master volume.
 * @default 100
 *
 * @param OffsetValue
 * @type number
 * @desc Offset value of the all volume(including other volume).
 * @default 20
 *
 * @help Add the master volume to the option screen using the master volume API
 * added in RPG Maker version 1.5.0.
 * You can adjust the volume of all BGM / BGS / ME / SE at once.
 *
 * Of course, it can not be used on main body version 1.5.0 or earlier.
 *
 * This plugin is released under the MIT License.
 */
/*:ja
 * @plugindesc マスターボリューム設定プラグイン
 * @author トリアコンタン     （ツミオが一部改変）
 *
 * @param 項目名称
 * @type string
 * @desc オプション画面に表示される設定項目名称です。
 * @default 全体 音量
 *
 * @param 初期値
 * @type number
 * @desc マスターボリュームの初期値です。
 * @default 100
 *
 * @param 音量の増減量
 * @type number
 * @desc マスターボリュームと、その他全ての音量値を含めた音量の増減量です。
 * @default 20
 *
 * @help 注意！
 * 本プラグインは、RPGアツマールのサービス側で提供している
 * マスターボリューム調整機能と競合します。
 * よってRPGアツマールでは使用できません。
 *
 * 本体バージョン1.5.0で追加されたマスターボリュームAPIを利用して
 * オプション画面にマスターボリュームを追加します。
 * BGM/BGS/ME/SE全ての音量を一括調整できます。
 *
 * 本体バージョン1.5.0以前では使用できません。
 *
 * このプラグインにはプラグインコマンドはありません。
 *
 * 利用規約：
 *  作者に無断で改変、再配布が可能で、利用形態（商用、18禁利用等）
 *  についても制限はありません。
 *  このプラグインはもうあなたのものです。
 */

(function () {
  "use strict";
  var pluginName = "MasterVolumeOption";

  //=============================================================================
  // ローカル関数
  //  プラグインパラメータやプラグインコマンドパラメータの整形やチェックをします
  //=============================================================================
  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 getParamNumber = function (paramNames, min, max) {
    var value = getParamString(paramNames);
    if (arguments.length < 2) min = -Infinity;
    if (arguments.length < 3) max = Infinity;
    return (parseInt(value) || 0).clamp(min, max);
  };

  //=============================================================================
  // パラメータの取得と整形
  //=============================================================================
  var param = {};
  param.itemName = getParamString(["ItemName", "項目名称"]);
  param.defaultValue = getParamNumber(["DefaultValue", "初期値"]);
  param.offsetValue = getParamNumber(["OffsetValue", "音量の増減量"]); //ツミオ加筆

  //=============================================================================
  // ConfigManager
  //  マスターボリュームの設定機能を追加します。
  //=============================================================================
  Object.defineProperty(ConfigManager, "masterVolume", {
    get: function () {
      return Math.floor(AudioManager._masterVolume * 100);
    },
    set: function (value) {
      AudioManager.masterVolume = value.clamp(0, 100) / 100;
    },
  });

  var _ConfigManager_makeData = ConfigManager.makeData;
  ConfigManager.makeData = function () {
    var config = _ConfigManager_makeData.apply(this, arguments);
    config.masterVolume = this.masterVolume;
    return config;
  };

  var _ConfigManager_applyData = ConfigManager.applyData;
  ConfigManager.applyData = function (config) {
    _ConfigManager_applyData.apply(this, arguments);
    var symbol = "masterVolume";
    this.masterVolume = config.hasOwnProperty(symbol)
      ? this.readVolume(config, symbol)
      : param.defaultValue;
  };

  //=============================================================================
  // Window_Options
  //  マスターボリュームの設定項目を追加します。
  //=============================================================================
  var _Window_Options_addVolumeOptions =
    Window_Options.prototype.addVolumeOptions;
  Window_Options.prototype.addVolumeOptions = function () {
    this.addCommand(param.itemName, "masterVolume");
    _Window_Options_addVolumeOptions.apply(this, arguments);
  };

  //=============================================================================
  // Window_Options
  //  バーの移動量の設定を付け加えます（ツミオ加筆）
  //=============================================================================
  var _Window_Options_volumeOffset = Window_Options.prototype.volumeOffset;
  Window_Options.prototype.volumeOffset = function () {
    _Window_Options_volumeOffset.call(this);
    return param.offsetValue;
  };
})();

repo_name: dazed/translations

license: unknown


code:
//=============================================================================
// MenuCommonEvent.js
// ----------------------------------------------------------------------------
// (C)2017 Triacontane
// This software is released under the MIT License.
// http://opensource.org/licenses/mit-license.php
// ----------------------------------------------------------------------------
// Version
// 1.4.1 2023/08/20 クラス名取得関数の実装を変更
// 1.4.0 2021/02/06 ピクチャなどの画像をウィンドウの背後に表示できる設定を追加
// 1.3.7 2020/08/28 1.3.6の修正方法が間違っていた問題を修正
// 1.3.6 2020/08/27 DWindow.jsと組み合わせたときにコモンイベントが存在するメニューで動的ウィンドウが作成されてしまう競合を修正
// 1.3.5 2020/05/09 MOG_Weather_EX.jsと併用したときに発生するエラーを解消
// 1.3.4 2020/03/21 SceneCustomMenu.jsに合わせた微修正
// 1.3.3 2020/03/17 Canvasモード時、マップの色調変更がウィンドウに反映されていた問題を修正
// 1.3.2 2019/01/23 1.3.1の修正でGUI画面デザインプラグインと共存できなくなっていた問題を修正
// 1.3.1 2019/01/18 他のプラグインと連携しやすいように一部の実装を変更
// 1.3.0 2018/09/23 対象イベントの並列実行を停止するコマンドを追加
// 1.2.0 2017/12/24 公式ガチャプラグインと連携できるよう修正
// 1.1.3 2017/12/02 NobleMushroom.jsとの競合を解消
// 1.1.2 2017/11/18 コモンイベントを一切指定しない状態でメニューを開くとエラーになる現象を修正
// 1.1.1 2017/11/05 ヘルプとダウンロード先を追記
// 1.1.0 2017/11/05 タイマー有効化機能などいくつかの機能を追加
// 1.0.0 2017/11/04 初版
// ----------------------------------------------------------------------------
// [Blog]   : https://triacontane.blogspot.jp/
// [Twitter]: https://twitter.com/triacontane/
// [GitHub] : https://github.com/triacontane/
//=============================================================================

/*:
 * @plugindesc MenuCommonEventPlugin
 * @author triacontane
 *
 * @param CommonEventInfo
 * @desc 各画面で実行するコモンイベントの情報です。
 * @default
 * @type struct<CommonEventInfo>[]
 *
 * @param MaxMenuPicture
 * @desc メニュー画面で表示するピクチャの最大数です。
 * @default 10
 * @type number
 * @min 1
 * @max 100
 *
 * @param SaveInterpreterIndex
 * @desc イベントの実行位置を記憶して別画面から戻ってきたときに記憶した位置から再開します。
 * @default false
 * @type boolean
 *
 * @param ActivateTimer
 * @desc メニュー画面中でもタイマーを表示し、かつタイマーを進めます。
 * @default false
 * @type boolean
 *
 * @param PictureUnderWindow
 * @desc ピクチャなどの画像要素をウィンドウの背後に表示します。
 * @default false
 * @type boolean
 *
 * @param CommandPrefix
 * @desc プラグインコマンドおよびメモ欄の接頭辞です。コマンドやメモ欄が他プラグインと被る場合に指定してください。
 * @default
 *
 * @help MenuCommonEvent.js
 *
 * メニュー画面やプラグインで追加した画面(※1)でコモンイベントを並列実行できます。
 * メッセージやピクチャ、変数の操作などが各イベントコマンド(※2)が実行可能です。
 * コモンイベントは各画面につきひとつ実行できます。
 *
 * ※1 メニュー系の画面であれば利用できます。
 * サウンドテストプラグインや用語辞典プラグインとの連携は確認済みです。
 *
 * ※2 移動ルートの設定などキャラクターを対象にする一部コマンドは動作しません。
 * また、プラグインによって追加されたスクリプトやコマンドは正しく動作しない
 * 可能性があります。
 *
 * プラグインコマンド詳細
 *  イベントコマンド「プラグインコマンド」から実行。
 *  （パラメータの間は半角スペースで区切る）
 *
 * ウィンドウ操作禁止      # メニュー画面のウィンドウ操作を禁止します。
 * DISABLE_WINDOW_CONTROL  # 同上
 * ウィンドウ操作許可      # 禁止したメニュー画面のウィンドウ操作を許可します。
 * ENABLE_WINDOW_CONTROL   # 同上
 *
 * プラグインコメント名が他のプラグインと被っている場合はパラメータの
 * 「コマンド接頭辞」に値を設定してください。
 *
 * スクリプト詳細
 *  イベントコマンド「スクリプト」「変数の操作」から実行。
 *
 * // ウィンドウオブジェクトを取得
 * this.getSceneWindow(windowName);
 * 指定した名前のウィンドウオブジェクトを返します。
 * プロパティの取得や設定が可能です。上級者向け機能です。
 * 主要画面のウィンドウ名は以下の通りです。
 *
 * ・メインメニュー
 * commandWindow   コマンドウィンドウ
 * statusWindow    ステータスウィンドウ
 * goldWindow      お金ウィンドウ
 *
 * ・アイテム画面
 * categoryWindow  アイテムカテゴリウィンドウ
 * itemWindow      アイテムウィンドウ
 * actorWindow     アクター選択ウィンドウ
 *
 * ・スキル画面
 * skillTypeWindow スキルタイプウィンドウ
 * statusWindow    ステータスウィンドウ
 * itemWindow      スキルウィンドウ
 * actorWindow     アクター選択ウィンドウ
 *
 * ・装備画面
 * helpWindow      ヘルプウィンドウ
 * commandWindow   コマンドウィンドウ
 * slotWindow      スロットウィンドウ
 * statusWindow    ステータスウィンドウ
 * itemWindow      装備品ウィンドウ
 *
 * ・ステータス画面
 * statusWindow    ステータスウィンドウ
 *
 * // ウィンドウアクティブ判定
 * this.isWindowActive(windowName);
 * 指定した名前のウィンドウがアクティブなときにtrueを返します。
 * ウィンドウの指定例は上と同じです。
 *
 * // ウィンドウインデックス取得
 * this.getSceneWindowIndex();
 * 現在アクティブなウィンドウのインデックスを取得します。先頭は0です。
 *
 * // 選択中のアクターオブジェクト取得
 * $gameParty.menuActor();
 * 装備画面やステータス画面で選択中のアクターの情報を取得します。
 * 上級者向けスクリプトです。(※1)
 *
 * // 選択中のアクターID取得
 * $gameParty.menuActor().actorId();
 * 装備画面やステータス画面で選択中のアクターIDを取得します。
 *
 * ※1 既存のコアスクリプトですが、有用に使えるため記載しています。
 *
 * // 用語辞典の表示内容更新
 * this.refreshGlossary();
 * 用語辞典プラグインにおいて用語の表示内容を最新にします。
 * 同プラグインと連携した場合に使用します。
 *
 * 〇他のプラグインとの連携
 * ピクチャのボタン化プラグイン（PictureCallCommon.js）と併用する場合
 * コマンドは「P_CALL_CE」ではなく「P_CALL_SWITCH」を使ってください。
 *
 * プラグインURL
 * https://raw.githubusercontent.com/triacontane/RPGMakerMV/master/MenuCommonEvent.js
 *
 * ヘルプURL
 * https://github.com/triacontane/RPGMakerMV/blob/master/ReadMe/MenuCommonEvent.md
 *
 * 利用規約：
 *  作者に無断で改変、再配布が可能で、利用形態（商用、18禁利用等）
 *  についても制限はありません。
 *  このプラグインはもうあなたのものです。
 */

/*~struct~CommonEventInfo:
 *
 * @param SceneName
 * @desc コモンイベント実行対象の画面です。独自に追加した画面を対象にする場合はクラス名を直接入力してください。
 * @type select
 * @default
 * @option メインメニュー
 * @value Scene_Menu
 * @option アイテム
 * @value Scene_Item
 * @option スキル
 * @value Scene_Skill
 * @option 装備
 * @value Scene_Equip
 * @option ステータス
 * @value Scene_Status
 * @option オプション
 * @value Scene_Options
 * @option セーブ
 * @value Scene_Save
 * @option ロード
 * @value Scene_Load
 * @option ゲーム終了
 * @value Scene_End
 * @option ショップ
 * @value Scene_Shop
 * @option 名前入力
 * @value Scene_Name
 * @option デバッグ
 * @value Scene_Debug
 * @option サウンドテスト
 * @value Scene_SoundTest
 * @option 用語辞典
 * @value Scene_Glossary
 *
 * @param CommonEventId
 * @desc 画面で並列実行するコモンイベントのIDです。トリガーを並列実行にする必要はなく、スイッチも参照されません。
 * @default 1
 * @type common_event
 *
 */
/*:ja
 * @plugindesc メニュー内コモンイベントプラグイン
 * @author トリアコンタン
 *
 * @param コモンイベント情報
 * @desc 各画面で実行するコモンイベントの情報です。
 * @default
 * @type struct<CommonEventInfo>[]
 *
 * @param ピクチャ表示最大数
 * @desc メニュー画面で表示するピクチャの最大数です。
 * @default 10
 * @type number
 * @min 1
 * @max 100
 *
 * @param 実行位置を記憶
 * @desc イベントの実行位置を記憶して別画面から戻ってきたときに記憶した位置から再開します。
 * @default false
 * @type boolean
 *
 * @param タイマー有効化
 * @desc メニュー画面中でもタイマーを表示し、かつタイマーを進めます。
 * @default false
 * @type boolean
 *
 * @param 画像をウィンドウ背後に配置
 * @desc ピクチャなどの画像要素をウィンドウの背後に表示します。
 * @default false
 * @type boolean
 *
 * @param コマンド接頭辞
 * @desc プラグインコマンドおよびメモ欄の接頭辞です。コマンドやメモ欄が他プラグインと被る場合に指定してください。
 * @default
 *
 * @help MenuCommonEvent.js
 *
 * メニュー画面やプラグインで追加した画面(※1)でコモンイベントを並列実行できます。
 * メッセージやピクチャ、変数の操作などが各イベントコマンド(※2)が実行可能です。
 * コモンイベントは各画面につきひとつ実行できます。
 *
 * ※1 メニュー系の画面であれば利用できます。
 * サウンドテストプラグインや用語辞典プラグインとの連携は確認済みです。
 *
 * ※2 移動ルートの設定などキャラクターを対象にする一部コマンドは動作しません。
 * また、プラグインによって追加されたスクリプトやコマンドは正しく動作しない
 * 可能性があります。
 *
 * プラグインコマンド詳細
 *  イベントコマンド「プラグインコマンド」から実行。
 *  （パラメータの間は半角スペースで区切る）
 *
 * ウィンドウ操作禁止      # メニュー画面のウィンドウ操作を禁止します。
 * DISABLE_WINDOW_CONTROL  # 同上
 * ウィンドウ操作許可      # 禁止したメニュー画面のウィンドウ操作を許可します。
 * ENABLE_WINDOW_CONTROL   # 同上
 * イベントの実行停止      # イベントの並列実行を停止します。画面遷移して戻ると再実行されます。
 * STOP_EVENT              # 同上
 *
 * プラグインコメント名が他のプラグインと被っている場合はパラメータの
 * 「コマンド接頭辞」に値を設定してください。
 *
 * スクリプト詳細
 *  イベントコマンド「スクリプト」「変数の操作」から実行。
 *
 * // ウィンドウオブジェクトを取得
 * this.getSceneWindow(windowName);
 * 指定した名前のウィンドウオブジェクトを返します。
 * プロパティの取得や設定が可能です。上級者向け機能です。
 * 主要画面のウィンドウ名は以下の通りです。
 *
 * ・メインメニュー
 * commandWindow   コマンドウィンドウ
 * statusWindow    ステータスウィンドウ
 * goldWindow      お金ウィンドウ
 *
 * ・アイテム画面
 * categoryWindow  アイテムカテゴリウィンドウ
 * itemWindow      アイテムウィンドウ
 * actorWindow     アクター選択ウィンドウ
 *
 * ・スキル画面
 * skillTypeWindow スキルタイプウィンドウ
 * statusWindow    ステータスウィンドウ
 * itemWindow      スキルウィンドウ
 * actorWindow     アクター選択ウィンドウ
 *
 * ・装備画面
 * helpWindow      ヘルプウィンドウ
 * commandWindow   コマンドウィンドウ
 * slotWindow      スロットウィンドウ
 * statusWindow    ステータスウィンドウ
 * itemWindow      装備品ウィンドウ
 *
 * ・ステータス画面
 * statusWindow    ステータスウィンドウ
 *
 * // ウィンドウアクティブ判定
 * this.isWindowActive(windowName);
 * 指定した名前のウィンドウがアクティブなときにtrueを返します。
 * ウィンドウの指定例は上と同じです。
 *
 * // ウィンドウインデックス取得
 * this.getSceneWindowIndex();
 * 現在アクティブなウィンドウのインデックスを取得します。先頭は0です。
 *
 * // 選択中のアクターオブジェクト取得
 * $gameParty.menuActor();
 * 装備画面やステータス画面で選択中のアクターの情報を取得します。
 * 上級者向けスクリプトです。(※1)
 *
 * // 選択中のアクターID取得
 * $gameParty.menuActor().actorId();
 * 装備画面やステータス画面で選択中のアクターIDを取得します。
 *
 * ※1 既存のコアスクリプトですが、有用に使えるため記載しています。
 *
 * // 用語辞典の表示内容更新
 * this.refreshGlossary();
 * 用語辞典プラグインにおいて用語の表示内容を最新にします。
 * 同プラグインと連携した場合に使用します。
 *
 * 〇他のプラグインとの連携
 * ピクチャのボタン化プラグイン（PictureCallCommon.js）と併用する場合
 * コマンドは「P_CALL_CE」ではなく「P_CALL_SWITCH」を使ってください。
 *
 * プラグインURL
 * https://raw.githubusercontent.com/triacontane/RPGMakerMV/master/MenuCommonEvent.js
 *
 * ヘルプURL
 * https://github.com/triacontane/RPGMakerMV/blob/master/ReadMe/MenuCommonEvent.md
 *
 * 利用規約：
 *  作者に無断で改変、再配布が可能で、利用形態（商用、18禁利用等）
 *  についても制限はありません。
 *  このプラグインはもうあなたのものです。
 */

/*~struct~CommonEventInfo:ja
 *
 * @param SceneName
 * @desc コモンイベント実行対象の画面です。独自に追加した画面を対象にする場合はクラス名を直接入力してください。
 * @type select
 * @default
 * @option メインメニュー
 * @value Scene_Menu
 * @option アイテム
 * @value Scene_Item
 * @option スキル
 * @value Scene_Skill
 * @option 装備
 * @value Scene_Equip
 * @option ステータス
 * @value Scene_Status
 * @option オプション
 * @value Scene_Options
 * @option セーブ
 * @value Scene_Save
 * @option ロード
 * @value Scene_Load
 * @option ゲーム終了
 * @value Scene_End
 * @option ショップ
 * @value Scene_Shop
 * @option 名前入力
 * @value Scene_Name
 * @option デバッグ
 * @value Scene_Debug
 * @option サウンドテスト
 * @value Scene_SoundTest
 * @option 用語辞典
 * @value Scene_Glossary
 * @option 公式ガチャ
 * @value Scene_Gacha
 *
 * @param CommonEventId
 * @desc 画面で並列実行するコモンイベントのIDです。トリガーを並列実行にする必要はなく、スイッチも参照されません。
 * @default 1
 * @type common_event
 *
 */

(function () {
  "use strict";
  var pluginName = "MenuCommonEvent";

  //=============================================================================
  // ローカル関数
  //  プラグインパラメータやプラグインコマンドパラメータの整形やチェックをします
  //=============================================================================
  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 !== undefined) return name;
    }
    return "";
  };

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

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

  var getParamArrayJson = function (paramNames, defaultValue) {
    var value = getParamString(paramNames) || null;
    try {
      value = JSON.parse(value);
      if (value === null) {
        value = defaultValue;
      } else {
        value = value.map(function (valueData) {
          return JSON.parse(valueData);
        });
      }
    } catch (e) {
      alert("!!!Plugin param is wrong.!!!\nPlugin:.js\nName:[]\nValue:");
      value = defaultValue;
    }
    return value;
  };

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

  var isNotAString = function (args) {
    return String(args) !== args;
  };

  var convertAllArguments = function (args) {
    return args.map(function (arg) {
      return convertEscapeCharacters(arg);
    });
  };

  var setPluginCommand = function (commandName, methodName) {
    pluginCommandMap.set(param.commandPrefix + commandName, methodName);
  };

  var getClassName = function (object) {
    var define = object.constructor.toString();
    if (define.match(/^class/)) {
      return define.replace(/class\s+(.*?)\s+[\s\S]*/m, "$1");
    }
    return define.replace(/function\s+(.*?)\s*\([\s\S]*/m, "$1");
  };

  //=============================================================================
  // パラメータの取得と整形
  //=============================================================================
  var param = {};
  param.commonEventInfo = getParamArrayJson(
    ["CommonEventInfo", "コモンイベント情報"],
    []
  );
  param.commandPrefix = getParamString(["CommandPrefix", "コマンド接頭辞"]);
  param.maxMenuPicture = getParamNumber(
    ["MaxMenuPicture", "ピクチャ表示最大数"],
    1
  );
  param.saveInterpreterIndex = getParamBoolean([
    "SaveInterpreterIndex",
    "実行位置を記憶",
  ]);
  param.activateTimer = getParamBoolean(["ActivateTimer", "タイマー有効化"]);
  param.pictureUnderWindow = getParamBoolean([
    "PictureUnderWindow",
    "画像をウィンドウ背後に配置",
  ]);

  var pluginCommandMap = new Map();
  setPluginCommand("ウィンドウ操作禁止", "execDisableWindowControl");
  setPluginCommand("DISABLE_WINDOW_CONTROL", "execDisableWindowControl");
  setPluginCommand("ウィンドウ操作許可", "execEnableWindowControl");
  setPluginCommand("ENABLE_WINDOW_CONTROL", "execEnableWindowControl");
  setPluginCommand("イベントの実行停止", "execStopEvent");
  setPluginCommand("STOP_EVENT", "execStopEvent");

  //=============================================================================
  // Game_Interpreter
  //  プラグインコマンドを追加定義します。
  //=============================================================================
  var _Game_Interpreter_pluginCommand =
    Game_Interpreter.prototype.pluginCommand;
  Game_Interpreter.prototype.pluginCommand = function (command, args) {
    _Game_Interpreter_pluginCommand.apply(this, arguments);
    var pluginCommandMethod = pluginCommandMap.get(command.toUpperCase());
    if (pluginCommandMethod) {
      this[pluginCommandMethod](convertAllArguments(args));
    }
  };

  Game_Interpreter.prototype.execDisableWindowControl = function () {
    $gameTemp.setDisableWindowControl(true);
  };

  Game_Interpreter.prototype.execEnableWindowControl = function () {
    $gameTemp.setDisableWindowControl(false);
  };

  Game_Interpreter.prototype.isWindowActive = function (windowName) {
    var sceneWindow = this.getSceneWindow(windowName);
    return sceneWindow ? sceneWindow.active : false;
  };

  Game_Interpreter.prototype.getSceneWindow = function (windowName) {
    return SceneManager.getSceneWindow("_" + windowName);
  };

  Game_Interpreter.prototype.getSceneWindowIndex = function () {
    var index = -1;
    SceneManager.getSceneWindowList().some(function (sceneWindow) {
      if (sceneWindow instanceof Window_Selectable && sceneWindow.active) {
        index = sceneWindow.index();
        return true;
      } else {
        return false;
      }
    });
    return index;
  };

  Game_Interpreter.prototype.refreshGlossary = function () {
    var glossaryWindow = this.getSceneWindow("glossaryWindow");
    if (glossaryWindow.visible) {
      var glossaryListWindow = this.getSceneWindow("glossaryListWindow");
      glossaryWindow.refresh(glossaryListWindow.item());
    }
  };

  Game_Interpreter.prototype.execStopEvent = function () {
    this._menuCommonStop = true;
  };

  Game_Interpreter.prototype.isMenuCommonStop = function () {
    return this._menuCommonStop;
  };

  //=============================================================================
  // Game_Temp
  //  メニューコモンイベントを作成、更新します。
  //=============================================================================
  var _Game_Temp_initialize = Game_Temp.prototype.initialize;
  Game_Temp.prototype.initialize = function () {
    _Game_Temp_initialize.apply(this, arguments);
    this._menuCommonEvent = {};
    this.clearSceneInformation();
  };

  Game_Temp.prototype.setupMenuCommonEvent = function (
    commonEventId,
    sceneName,
    sceneIndex
  ) {
    this._sceneName = sceneName;
    this._sceneIndex = sceneIndex;
    if (
      param.saveInterpreterIndex &&
      this.isExistSameCommonEvent(commonEventId)
    ) {
      return this._menuCommonEvent[sceneName];
    }
    return (this._menuCommonEvent[sceneName] =
      this.createMenuCommonEvent(commonEventId));
  };

  Game_Temp.prototype.createMenuCommonEvent = function (commonEventId) {
    if (commonEventId > 0) {
      var commonEvent = new Game_MenuCommonEvent(commonEventId);
      if (commonEvent.event()) {
        return commonEvent;
      }
    }
    return null;
  };

  Game_Temp.prototype.isExistSameCommonEvent = function (commonEventId) {
    var commonEvent = this._menuCommonEvent[this._sceneName];
    return commonEvent && commonEvent.isSameEvent(commonEventId);
  };

  Game_Temp.prototype.setDisableWindowControl = function (value) {
    this._disableWindowControl = value;
  };

  Game_Temp.prototype.isDisableWindowControl = function () {
    return !!this._disableWindowControl;
  };

  Game_Temp.prototype.getSceneIndex = function () {
    return this._sceneIndex;
  };

  Game_Temp.prototype.isInMenu = function () {
    return this.getSceneIndex() >= 0;
  };

  Game_Temp.prototype.clearSceneInformation = function () {
    this._sceneIndex = -1;
    this._sceneName = "";
  };

  //=============================================================================
  // Game_Screen
  //  シーンごとにピクチャを管理できるようにします。
  //=============================================================================
  if (param.maxMenuPicture > 0) {
    var _Game_Screen_realPictureId = Game_Screen.prototype.realPictureId;
    Game_Screen.prototype.realPictureId = function (pictureId) {
      var sceneIndex = $gameTemp.getSceneIndex();
      if (sceneIndex >= 0) {
        return (
          pictureId +
          this.maxMapPictures() * 2 +
          sceneIndex * this.maxPictures()
        );
      } else {
        return _Game_Screen_realPictureId.apply(this, arguments);
      }
    };

    var _Game_Screen_maxPictures = Game_Screen.prototype.maxPictures;
    Game_Screen.prototype.maxPictures = function () {
      return $gameTemp.isInMenu()
        ? param.maxMenuPicture
        : _Game_Screen_maxPictures.apply(this, arguments);
    };

    Game_Screen.prototype.maxMapPictures = function () {
      return _Game_Screen_maxPictures.apply(this, arguments);
    };
  }

  //=============================================================================
  // Game_MenuCommonEvent
  //  メニューコモンイベントを扱うクラスです。
  //=============================================================================
  function Game_MenuCommonEvent() {
    this.initialize.apply(this, arguments);
  }

  Game_MenuCommonEvent.prototype = Object.create(Game_CommonEvent.prototype);
  Game_MenuCommonEvent.prototype.constructor = Game_MenuCommonEvent;

  Game_MenuCommonEvent.prototype.isActive = function () {
    return true;
  };

  Game_MenuCommonEvent.prototype.isSameEvent = function (commonEventId) {
    return this._commonEventId === commonEventId;
  };

  var _Game_MenuCommonEvent_update = Game_MenuCommonEvent.prototype.update;
  Game_MenuCommonEvent.prototype.update = function () {
    if (this._interpreter) {
      if (!this._interpreter.isRunning()) {
        this._interpreter.execEnableWindowControl();
      }
      if (this._interpreter.isMenuCommonStop()) {
        return;
      }
    }
    _Game_MenuCommonEvent_update.apply(this, arguments);
  };

  //=============================================================================
  // Scene_MenuBase
  //  メニューコモンイベントを実行します。
  //=============================================================================
  var _Scene_MenuBase_create = Scene_MenuBase.prototype.create;
  Scene_MenuBase.prototype.create = function () {
    _Scene_MenuBase_create.apply(this, arguments);
    this.createCommonEvent();
  };

  Scene_MenuBase.prototype.createCommonEvent = function () {
    this.setupCommonEvent();
    if (!this.hasCommonEvent()) {
      return;
    }
    this.createSpriteset();
    if (param.pictureUnderWindow) {
      this.addChildAt(
        this._spriteset,
        this.children.indexOf(this._windowLayer)
      );
    }
    if (!this._messageWindow) {
      this.createMessageWindow();
    }
    if (!this._scrollTextWindow) {
      this.createScrollTextWindow();
    }
    this.changeParentMessageWindow();
  };

  var _Scene_MenuBase_start = Scene_MenuBase.prototype.start;
  Scene_MenuBase.prototype.start = function () {
    _Scene_MenuBase_start.apply(this, arguments);
    if (this.hasCommonEvent()) {
      this.addChild(this._messageWindow);
      this.addChild(this._scrollTextWindow);
      this._messageWindow.subWindows().forEach(function (win) {
        this.addChild(win);
      }, this);
    }
  };

  Scene_MenuBase.prototype.hasCommonEvent = function () {
    return !!this._commonEvent;
  };

  Scene_MenuBase.prototype.createMessageWindow = function () {
    Scene_Map.prototype.createMessageWindow.call(this);
  };

  Scene_MenuBase.prototype.createScrollTextWindow = function () {
    Scene_Map.prototype.createScrollTextWindow.call(this);
  };

  Scene_MenuBase.prototype.changeParentMessageWindow = function () {
    this.addChild(this._windowLayer.removeChild(this._messageWindow));
    this.addChild(this._windowLayer.removeChild(this._scrollTextWindow));
    this._messageWindow.subWindows().forEach(function (win) {
      this.addChild(this._windowLayer.removeChild(win));
    }, this);
  };

  // Resolve conflict for NobleMushroom.js
  Scene_MenuBase.prototype.changeImplementationWindowMessage =
    Scene_Map.prototype.changeImplementationWindowMessage;
  Scene_MenuBase.prototype.restoreImplementationWindowMessage =
    Scene_Map.prototype.restoreImplementationWindowMessage;
  Scene_MenuBase.prototype.onPause = Scene_Map.prototype.onPause;
  Scene_MenuBase.prototype.offPause = Scene_Map.prototype.offPause;
  Scene_MenuBase._stopWindow = false;

  Scene_MenuBase.prototype.createSpriteset = function () {
    this._spriteset = new Spriteset_Menu();
    this.addChild(this._spriteset);
  };

  Scene_MenuBase.prototype.setupCommonEvent = function () {
    var commonEventItem = this.getCommonEventData();
    var commonEventId = commonEventItem
      ? parseInt(commonEventItem["CommonEventId"])
      : 0;
    var sceneIndex = param.commonEventInfo.indexOf(commonEventItem);
    this._commonEvent = $gameTemp.setupMenuCommonEvent(
      commonEventId,
      this._sceneName,
      sceneIndex
    );
  };

  Scene_MenuBase.prototype.getCommonEventData = function () {
    this._sceneName = getClassName(this);
    return param.commonEventInfo.filter(function (data) {
      return data["SceneName"] === this._sceneName;
    }, this)[0];
  };

  var _Scene_MenuBase_updateChildren = Scene_MenuBase.prototype.updateChildren;
  Scene_MenuBase.prototype.updateChildren = function () {
    Scene_MenuBase._stopWindow =
      this.hasCommonEvent() && this.isNeedStopWindow();
    _Scene_MenuBase_updateChildren.apply(this, arguments);
  };

  Scene_MenuBase.prototype.isNeedStopWindow = function () {
    return $gameTemp.isDisableWindowControl() || $gameMessage.isBusy();
  };

  Scene_MenuBase.prototype.updateCommonEvent = function () {
    if (!this.hasCommonEvent()) {
      return;
    }
    this._commonEvent.update();
    $gameScreen.update();
    if (param.activateTimer) {
      $gameTimer.update(true);
    }
    this.checkGameover();
    this.updateTouchPicturesIfNeed();
  };

  /**
   * updateTouchPicturesIfNeed
   * for PictureCallCommon.js
   */
  Scene_MenuBase.prototype.updateTouchPicturesIfNeed = function () {
    if (this.updateTouchPictures && param.maxMenuPicture > 0) {
      this.updateTouchPictures();
    }
  };

  //=============================================================================
  // Scene_Base
  //  メニューコモンイベントを更新します。
  //=============================================================================
  var _Scene_Base_update = Scene_Base.prototype.update;
  Scene_Base.prototype.update = function () {
    this.updateCommonEvent();
    _Scene_Base_update.apply(this, arguments);
  };

  Scene_Base.prototype.updateCommonEvent = function () {
    // do nothing
  };

  var _Scene_Base_terminate = Scene_Base.prototype.terminate;
  Scene_Base.prototype.terminate = function () {
    _Scene_Base_terminate.apply(this, arguments);
    if ($gameTemp) {
      $gameTemp.clearSceneInformation();
    }
  };

  //=============================================================================
  // Spriteset_Menu
  //  メニュー画面用のスプライトセットです。
  //=============================================================================
  function Spriteset_Menu() {
    this.initialize.apply(this, arguments);
  }

  Spriteset_Menu.prototype = Object.create(Spriteset_Base.prototype);
  Spriteset_Menu.prototype.constructor = Spriteset_Menu;

  var _Spriteset_Menu_createBaseSprite =
    Spriteset_Menu.prototype.createBaseSprite;
  Spriteset_Menu.prototype.createBaseSprite = function () {
    _Spriteset_Menu_createBaseSprite.apply(this, arguments);
    this._blackScreen.opacity = 0;
  };

  var _Spriteset_Menu_createTimer = Spriteset_Menu.prototype.createTimer;
  Spriteset_Menu.prototype.createTimer = function () {
    if (param.activateTimer) {
      _Spriteset_Menu_createTimer.apply(this, arguments);
    }
  };

  Spriteset_Menu.prototype.createDynamicWindow = function () {};

  Spriteset_Menu.prototype.createToneChanger = function () {};

  Spriteset_Menu.prototype.updateToneChanger = function () {};

  Spriteset_Menu.prototype.reloadWeatherEX = function () {};

  //=============================================================================
  // SceneManager
  //  ウィンドウオブジェクトを取得します。
  //=============================================================================
  SceneManager.getSceneWindow = function (windowName) {
    var sceneWindow = this._scene[windowName];
    return sceneWindow instanceof Window ? sceneWindow : null;
  };

  SceneManager.getSceneWindowList = function () {
    var windowList = [];
    for (var sceneWindow in this._scene) {
      if (
        this._scene.hasOwnProperty(sceneWindow) &&
        this._scene[sceneWindow] instanceof Window
      ) {
        windowList.push(this._scene[sceneWindow]);
      }
    }
    return windowList;
  };

  //=============================================================================
  // Window_Selectable
  //  必要な場合にウィンドウの状態更新を停止します。
  //=============================================================================
  var _Window_Selectable_update = Window_Selectable.prototype.update;
  Window_Selectable.prototype.update = function () {
    if (Scene_MenuBase._stopWindow && this.isStopWindow()) {
      return;
    }
    _Window_Selectable_update.apply(this, arguments);
  };

  Window_Selectable.prototype.isStopWindow = function () {
    return !this._messageWindow;
  };
})();


code:
//=============================================================================
// MenuSubCommand.js
// ----------------------------------------------------------------------------
// (C) 2017 Triacontane
// This software is released under the MIT License.
// http://opensource.org/licenses/mit-license.php
// ----------------------------------------------------------------------------
// Version
// 2.8.0 2021/12/09 サブメニューで選択したアクターのIDをマップ遷移時以外でも設定するよう変更
// 2.7.4 2020/08/22 2.7.3の修正で復元が、動的イベント生成されたプラグインに対しても行われるよう修正
// 2.7.3 2020/08/18 イベントの一時消去後にサブコマンドマップに移動して戻ってきたときに消去状態が復元されるよう修正
// 2.7.2 2020/04/03 2.5.0で適用したMOG_SceneMenu.jsとの競合解消と、2.0.1で適用したMOG_MenuCursor.jsとの競合解消を両立できるよう修正
// 2.7.1 2020/03/13 Window_MenuCommandの初期化で引数を渡し忘れていたのを修正
// 2.7.0 2019/10/25 メニューマップと通常マップのピクチャの表示状態を別々に管理できる機能を追加
// 2.6.1 2019/10/12 2.6.0の修正で、メニューを開いたあと一度もサブコマンドを開かずにメニューを閉じるとエラーになる問題を修正
//                  その他軽微な不具合の修正
// 2.6.0 2019/09/16 サブコマンドのスクリプト実行後、マップに戻る機能を追加
//                  MOG_MenuBackground.jsとの競合を解消
//                  サブコマンドをキャンセル後、スキルや装備コマンドを選択して戻ると、再度サブコマンドにフォーカスする問題を修正
//                  サブコマンドの座標固定値設定で、XかYいずれかひとつの値を設定していると設定が有効になるよう仕様変更
// 2.5.2 2019/09/08 2.0.1で対策して、2.5.0で何らかの理由で元に戻した競合対策を再度有効化
// 2.5.1 2019/07/11 FixCursorSeByMouse.jsとの競合対策のためメソッド名を変更
// 2.5.0 2018/11/25 サブメニューの絶対座標と揃えを設定できる機能を追加
//                  MOG_SceneMenu.jsとの競合を解消
// 2.4.1 2018/11/24 用語辞典プラグインと連携する方法をヘルプに記載
// 2.4.0 2018/09/26 サブコマンドを逐次消去するオプションを追加
// 2.3.0 2018/09/26 サブコマンドを横並べにするオプションを追加
// 2.2.1 2018/01/28 サブコマンドを選択後メニューに戻って通常コマンドを選択し、さらにメニューに戻ったときに最初のサブコマンドが展開される問題を修正
// 2.2.0 2018/01/07 同名の親コマンドを指定できる機能を追加
// 2.1.0 2017/12/24 対象メンバーを選択するサブコマンド選択時にメニューコマンドをその名前に置き換える処理を追加
//                  メニューへ戻った際に対象メンバー選択やサブコマンド選択に戻るように変更
// 2.0.1 2017/11/19 MOG_MenuCursor.jsとの併用時、カーソルがサブコマンドの下に隠れてしまう競合の解消
// 2.0.0 2017/09/04 メニューコマンドやサブコマンドを好きなだけ追加できるようパラメータの仕様を変更
// 1.1.0 2017/05/14 デフォルトのオプションとゲーム終了コマンドを削除できる機能を追加
//                  カンマ(,)を含むスクリプトを正しく実行できない問題を修正
// 1.0.3 2017/04/09 サブコマンドマップから戻ってきたときにイベント位置を復元できるよう修正
// 1.0.2 2017/04/08 サブコマンドマップから戻ってきたときにフォロワー位置を復元できるよう修正
// 1.0.1 2017/04/08 サブコマンドマップから戻ってきたタイミングでセーブしたときにロード時の位置がサブコマンドマップに
//                  なってしまう問題を修正
//                  戦闘リトライプラグインと併用したときにリトライ中は、マップ移動するメニューを使用禁止に設定
// 1.0.0 2017/04/01 初版
// ----------------------------------------------------------------------------
// [Blog]   : https://triacontane.blogspot.jp/
// [Twitter]: https://twitter.com/triacontane/
// [GitHub] : https://github.com/triacontane/
//=============================================================================

/*:
 * @plugindesc MenuSubCommandPlugin
 * @author triacontane
 *
 * @param SubCommand
 * @desc サブコマンド情報です。
 * @default
 * @type struct<SubCommand>[]
 *
 * @param CommandPosition
 * @desc サブコマンド群を追加する位置です。
 * 0:並び替えの下 1:オプションの下 2:セーブの下 3:ゲーム終了の下
 * @default 0
 *
 * @param SubMenuWidth
 * @desc サブメニューを表示するウィンドウの横幅です。指定しない場合デフォルト値「240」が適用されます。
 * @default 0
 *
 * @param SelectActorIdVariable
 * @desc サブコマンドからアクターを選択したとき、そのアクターのIDを格納する変数番号です。
 * @default 0
 *
 * @param WindowSkin
 * @desc サブコマンド用のウィンドウに専用のスキンを設定します。
 * @default
 * @require 1
 * @dir img/system/
 * @type file
 *
 * @param HideOption
 * @desc メインメニューからオプションを消去します。
 * @default OFF
 *
 * @param HideGameEnd
 * @desc メインメニューからゲーム終了を消去します。
 * @default OFF
 *
 * @param HorizontalSubMenu
 * @desc サブメニューを横並べにします。
 * @default false
 * @type boolean
 *
 * @param ClearSubMenuOneByOne
 * @desc サブメニューを逐次消去します
 * @default true
 * @type boolean
 *
 * @param SubMenuX
 * @desc 指定するとサブコマンドのX座標が固定値になります。
 * @default 0
 * @type number
 *
 * @param SubMenuY
 * @desc 指定するとサブコマンドのY座標が固定値になります。
 * @default 0
 * @type number
 *
 * @param SubMenuAlign
 * @desc サブコマンドの揃えを設定します。
 * @default
 * @type select
 * @option Left(default)
 * @value
 * @option Center
 * @value center
 * @option Right
 * @value right
 *
 * @param AnotherPicturesInMenuMap
 * @desc メニューマップと通常マップのピクチャの表示状態を別々に管理します。
 * @default false
 * @type boolean
 *
 * @help MenuSubCommand.js
 *
 * メインメニュー画面に任意の名前のコマンドおよび
 * ツリー表示されるサブコマンドを好きなだけ追加できます。
 * サブコマンドを実行（決定）すると、任意のスクリプトが実行されるか、
 * もしくは指定したマップに移動します。（両方も可能）
 *
 * スクリプトは、主にスクリプトで組まれた別画面に遷移する場合に使用します。
 * もちろん他のプラグインで追加された画面にも遷移可能です。
 * マップ移動は主にイベントによる自作メニュー画面に遷移する場合に使用します。
 * 自作メニュー画面から戻る際は、再度メニューを開いてください。
 * 元々メニューを開いていた場所は、別途保存しているので意識する必要はありません。
 *
 * また、通常の縦レイアウトとメニュー画面はもちろん、
 * プラグインによる横レイアウトのメニュー画面にも対応しています。
 *
 * メンバー選択してマップ移動する際に選択したアクターIDを変数に保存できます。
 *
 * サブコマンドが全て非表示だった場合、親項目自体も非表示になります。
 * 同じく全て使用禁止だった場合、親項目自体も使用禁止になります。
 *
 * サブコマンドがひとつしかない場合、サブコマンドウィンドウは表示されず
 * 親コマンドを選択した時点でサブコマンドを実行します。
 *
 * サブコマンドウィンドウのフォントサイズ等、一部の高度な設定は
 * 「ユーザ設定領域」に直接記述されています。必要に応じて改変可能です。
 *
 * 〇用語辞典プラグインと組み合わせる場合
 * 「用語辞典プラグイン」を同時に使用する場合は
 * スクリプトで以下の通り実行すると用語辞典画面を呼び出せます。
 * this.commandGlossary(1); // 用語種別[1]の用語辞典を呼ぶ
 *
 * このプラグインにはプラグインコマンドはありません。
 *
 * This plugin is released under the MIT License.
 */
/*:ja
 * @plugindesc メニュー画面のサブコマンドプラグイン
 * @author トリアコンタン
 *
 * @param サブコマンド
 * @desc サブコマンド情報です。
 * @default
 * @type struct<SubCommand>[]
 *
 * @param コマンド追加位置
 * @desc サブコマンド群を追加する位置です。0:並び替えの下 1:オプションの下 2:セーブの下 3:ゲーム終了の下
 * @default 0
 * @type select
 * @option 並び替えの下
 * @value 0
 * @option オプションの下
 * @value 1
 * @option セーブの下
 * @value 2
 * @option ゲーム終了の下
 * @value 3
 *
 * @param サブメニュー横幅
 * @desc サブメニューを表示するウィンドウの横幅です。指定しない場合デフォルト値「240」が適用されます。
 * @default 0
 * @type number
 *
 * @param 選択アクターID変数
 * @desc サブコマンドからアクターを選択したとき、そのアクターのIDを格納する変数番号です。
 * @default 0
 * @type variable
 *
 * @param ウィンドウスキン
 * @desc サブコマンド用のウィンドウに専用のスキンを設定します。
 * @default
 * @require 1
 * @dir img/system/
 * @type file
 *
 * @param オプション消去
 * @desc メインメニューからオプションを消去します。
 * @default false
 * @type boolean
 *
 * @param ゲーム終了消去
 * @desc メインメニューからゲーム終了を消去します。
 * @default false
 * @type boolean
 *
 * @param 横並びサブメニュー
 * @desc サブメニューを横並べにします。
 * @default false
 * @type boolean
 *
 * @param サブメニュー逐次消去
 * @desc サブメニューを逐次消去します
 * @default true
 * @type boolean
 *
 * @param サブメニューX座標
 * @desc 指定するとサブコマンドのX座標が固定値になります。
 * @default 0
 * @type number
 *
 * @param サブメニューY座標
 * @desc 指定するとサブコマンドのY座標が固定値になります。
 * @default 0
 * @type number
 *
 * @param サブメニュー揃え
 * @desc サブコマンドの揃えを設定します。
 * @default
 * @type select
 * @option 左揃え(デフォルト)
 * @value
 * @option 中央揃え
 * @value center
 * @option 右揃え
 * @value right
 *
 * @param メニューピクチャ別管理
 * @desc メニューマップと通常マップのピクチャの表示状態を別々に管理します。
 * @default false
 * @type boolean
 *
 * @help MenuSubCommand.js
 *
 * メインメニュー画面に任意の名前のコマンドおよび
 * ツリー表示されるサブコマンドを好きなだけ追加できます。
 * サブコマンドを実行（決定）すると、任意のスクリプトが実行されるか、
 * もしくは指定したマップに移動します。（両方も可能）
 *
 * スクリプトは、主にスクリプトで組まれた別画面に遷移する場合に使用します。
 * もちろん他のプラグインで追加された画面にも遷移可能です。
 * マップ移動は主にイベントによる自作メニュー画面に遷移する場合に使用します。
 * 自作メニュー画面から戻る際は、再度メニューを開いてください。
 * 元々メニューを開いていた場所は、別途保存しているので意識する必要はありません。
 *
 * また、通常の縦レイアウトとメニュー画面はもちろん、
 * プラグインによる横レイアウトのメニュー画面にも対応しています。
 *
 * メンバー選択してマップ移動する際に選択したアクターIDを変数に保存できます。
 *
 * サブコマンドが全て非表示だった場合、親項目自体も非表示になります。
 * 同じく全て使用禁止だった場合、親項目自体も使用禁止になります。
 *
 * サブコマンドがひとつしかない場合、サブコマンドウィンドウは表示されず
 * 親コマンドを選択した時点でサブコマンドを実行します。
 *
 * サブコマンドウィンドウのフォントサイズ等、一部の高度な設定は
 * 「ユーザ設定領域」に直接記述されています。必要に応じて改変可能です。
 *
 * 〇用語辞典プラグインと組み合わせる場合
 * 「用語辞典プラグイン」を同時に使用する場合は
 * スクリプトで以下の通り実行すると用語辞典画面を呼び出せます。
 * this.commandGlossary(1); // 用語種別[1]の用語辞典を呼ぶ
 *
 * このプラグインにはプラグインコマンドはありません。
 *
 * 利用規約：
 *  作者に無断で改変、再配布が可能で、利用形態（商用、18禁利用等）
 *  についても制限はありません。
 *  このプラグインはもうあなたのものです。
 */

/*~struct~SubCommand:ja
 *
 * @param CommandId
 * @desc サブコマンドの識別番号。この番号と名称とでコマンドがまとめられます。通常は全て0で問題ありません。
 * @default 0
 *
 * @param Name
 * @desc サブコマンドに表示される任意のコマンド名称
 * @default アイテム
 *
 * @param ParentName
 * @desc メインコマンドに表示されるサブコマンドの親名称。同一の名称の親を持つサブコマンドは一つに纏められます。
 * @default 親コマンド1
 *
 * @param HiddenSwitchId
 * @desc ONのときコマンドが非表示になるスイッチID
 * @default 0
 * @type switch
 *
 * @param DisableSwitchId
 * @desc ONのときコマンドが使用禁止になるスイッチID
 * @default 0
 * @type switch
 *
 * @param Script
 * @desc コマンドを決定したときに実行されるスクリプト
 * @default this.commandItem();
 *
 * @param ReturnMap
 * @desc スクリプト実行後にマップに戻ります。
 * @default false
 * @type boolean
 *
 * @param MapId
 * @desc コマンドを決定したときに移動するマップID
 * @default 0
 * @type map_id
 *
 * @param SelectMember
 * @desc コマンド実行前に対象メンバーを選択するかどうか
 * @default false
 * @type boolean
 */

/*~struct~SubCommand:
 *
 * @param CommandId
 * @desc サブコマンドの識別番号。この番号と名称とでコマンドがまとめられます。通常は全て0で問題ありません。
 * @default 0
 *
 * @param Name
 * @desc サブコマンドに表示される任意のコマンド名称
 * @default アイテム
 *
 * @param ParentName
 * @desc メインコマンドに表示されるサブコマンドの親名称。同一の名称の親を持つサブコマンドは一つに纏められます。
 * @default 親コマンド1
 *
 * @param HiddenSwitchId
 * @desc ONのときコマンドが非表示になるスイッチID
 * @default 0
 * @type switch
 *
 * @param DisableSwitchId
 * @desc ONのときコマンドが使用禁止になるスイッチID
 * @default 0
 * @type switch
 *
 * @param Script
 * @desc コマンドを決定したときに実行されるスクリプト
 * @default this.commandItem();
 *
 * @param ReturnMap
 * @desc スクリプト実行後にマップに戻ります。
 * @default false
 * @type boolean
 *
 * @param MapId
 * @desc コマンドを決定したときに移動するマップID
 * @default 0
 *
 * @param SelectMember
 * @desc コマンド実行前に対象メンバーを選択するかどうか
 * @default false
 * @type boolean
 */

(function () {
  "use strict";
  //=============================================================================
  // ユーザ設定領域 開始
  //=============================================================================
  var userSetting = {
    /**
     * サブコマンドウィンドウに関する設定です
     */
    subCommandWindow: {
      adjustX: 0,
      adjustY: 0,
      fontSize: null,
      padding: null,
    },
    /**
     * サブマップ移動時に自働でプレイヤーを透明にします。
     */
    autoTransparent: true,
  };
  //=============================================================================
  // ユーザ設定領域 終了
  //=============================================================================
  var pluginName = "MenuSubCommand";

  //=============================================================================
  // ローカル関数
  //  プラグインパラメータやプラグインコマンドパラメータの整形やチェックをします
  //=============================================================================
  var getParamBoolean = function (paramNames) {
    var value = getParamString(paramNames);
    return value.toUpperCase() === "ON" || value.toUpperCase() === "TRUE";
  };

  var getParamString = 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 "";
  };

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

  var convertEscapeCharacters = function (text) {
    if (isNotAString(text)) text = "";
    text = text.replace(/\\/g, "\x1b");
    text = text.replace(/\x1b\x1b/g, "\\");
    text = text.replace(
      /\x1bV\[(\d+)\]/gi,
      function () {
        return $gameVariables.value(parseInt(arguments[1]));
      }.bind(this)
    );
    text = text.replace(
      /\x1bV\[(\d+)\]/gi,
      function () {
        return $gameVariables.value(parseInt(arguments[1]));
      }.bind(this)
    );
    text = text.replace(
      /\x1bN\[(\d+)\]/gi,
      function () {
        var actor =
          parseInt(arguments[1]) >= 1
            ? $gameActors.actor(parseInt(arguments[1]))
            : null;
        return actor ? actor.name() : "";
      }.bind(this)
    );
    text = text.replace(
      /\x1bP\[(\d+)\]/gi,
      function () {
        var actor =
          parseInt(arguments[1]) >= 1
            ? $gameParty.members()[parseInt(arguments[1]) - 1]
            : null;
        return actor ? actor.name() : "";
      }.bind(this)
    );
    text = text.replace(/\x1bG/gi, TextManager.currencyUnit);
    return text;
  };

  var isNotAString = function (args) {
    return String(args) !== args;
  };

  var getArgBoolean = function (arg) {
    return arg.toUpperCase() === "ON" || arg.toUpperCase() === "TRUE";
  };

  var getParamArrayJson = function (paramNames, defaultValue) {
    var value = getParamString(paramNames) || null;
    try {
      value = JSON.parse(value);
      if (value === null) {
        value = defaultValue;
      } else {
        value = value.map(function (valueData) {
          return JSON.parse(valueData);
        });
      }
    } catch (e) {
      alert(
        `!!!Plugin param is wrong.!!!\nPlugin:${pluginName}.js\nName:[${paramNames}]\nValue:${value}`
      );
      value = defaultValue;
    }
    return value;
  };

  //=============================================================================
  // パラメータの取得と整形
  //=============================================================================
  var param = {};
  param.subCommands = getParamArrayJson(["サブコマンド", "SubCommand"], []);
  param.commandPosition = getParamNumber([
    "CommandPosition",
    "コマンド追加位置",
  ]);
  param.subMenuWidth = getParamNumber(["SubMenuWidth", "サブメニュー横幅"]);
  param.selectActorIdVariable = getParamNumber([
    "SelectActorIdVariable",
    "選択アクターID変数",
  ]);
  param.windowSkin = getParamString(["WindowSkin", "ウィンドウスキン"]);
  param.hideOption = getParamBoolean(["HideOption", "オプション消去"]);
  param.hideGameEnd = getParamBoolean(["HideGameEnd", "ゲーム終了消去"]);
  param.horizontalSubMenu = getParamBoolean([
    "HorizontalSubMenu",
    "横並びサブメニュー",
  ]);
  param.clearSubMenuOneByObe = getParamBoolean([
    "ClearSubMenuOneByOne",
    "サブメニュー逐次消去",
  ]);
  param.subMenuX = getParamNumber(["SubMenuX", "サブメニューX座標"]);
  param.subMenuY = getParamNumber(["SubMenuY", "サブメニューY座標"]);
  param.subMenuAlign = getParamString(["SubMenuAlign", "サブメニュー揃え"]);
  param.anotherPicInMenuMap = getParamBoolean([
    "AnotherPicturesInMenuMap",
    "メニューピクチャ別管理",
  ]);

  //=============================================================================
  // Game_Temp
  //  メニューコマンド情報を構築して保持します。
  //=============================================================================
  var _Game_Temp_initialize = Game_Temp.prototype.initialize;
  Game_Temp.prototype.initialize = function () {
    _Game_Temp_initialize.apply(this, arguments);
    this.createMenuCommands();
  };

  Game_Temp.prototype.createMenuCommands = function () {
    this._menuParentCommands = new Map();
    param.subCommands.forEach(function (commands) {
      this.createMenuCommand(commands);
    }, this);
    /* 最後に選択したサブコマンド */
    this._lastSubCommand = {
      parent: null,
      index: 0,
    };
  };

  Game_Temp.prototype.createMenuCommand = function (commands) {
    var parentName = commands.ParentName + commands.CommandId;
    if (!this._menuParentCommands.has(parentName)) {
      this._menuParentCommands.set(parentName, []);
    }
    var parent = this._menuParentCommands.get(parentName);
    parent.push(new Game_MenuSubCommand(commands));
  };

  Game_Temp.prototype.iterateMenuParents = function (callBackFunc, thisArg) {
    this._menuParentCommands.forEach(callBackFunc, thisArg);
  };

  Game_Temp.prototype.getSubMenuCommands = function (parentName) {
    return this._menuParentCommands.get(parentName);
  };

  /**
   * 最後に選択したサブコマンドを取得する
   */
  Game_Temp.prototype.getLastSubCommand = function () {
    return this._lastSubCommand;
  };

  Game_Temp.prototype.setLastSubCommandParent = function (parentName) {
    this._lastSubCommand.parent = parentName;
  };

  Game_Temp.prototype.setLastSubCommandIndex = function (index) {
    this._lastSubCommand.index = index;
  };

  /**
   * 最後に選択したサブコマンドをリセットする
   */
  Game_Temp.prototype.resetLastSubCommand = function () {
    this._lastSubCommand = {
      parent: null,
      index: 0,
    };
  };

  //=============================================================================
  // Game_CharacterBase
  //  サブコマンドマップへ移動します。
  //=============================================================================
  Game_CharacterBase.prototype.savePosition = function () {
    this._originalX = this.x;
    this._originalY = this.y;
    this._originalDirection = this.direction();
  };

  Game_CharacterBase.prototype.restorePosition = function () {
    this.locate(this._originalX, this._originalY);
    this.setDirection(this._originalDirection);
  };

  //=============================================================================
  // Game_Player
  //  サブコマンドマップへ移動します。
  //=============================================================================
  Game_Player.prototype.reserveTransferToSubCommandMap = function (
    subCommandMapId
  ) {
    this.saveOriginalMap();
    this.reserveTransfer(subCommandMapId, 0, 0, 0, 2);
    if (userSetting.autoTransparent) {
      this.setTransparent(true);
    }
    if (param.anotherPicInMenuMap) {
      $gameScreen.setupMenuMapPictures();
    }
  };

  Game_Player.prototype.reserveTransferToOriginalMap = function () {
    DataManager.loadMapData(this._originalMapId);
    this.reserveTransfer(
      this._originalMapId,
      this._originalX,
      this._originalY,
      this._originalDirection,
      2
    );
    if (userSetting.autoTransparent) {
      this.setTransparent(this._originalTransparent);
    }
    this._originalMapId = 0;
    this._transferringToOriginalMap = true;
    if (param.anotherPicInMenuMap) {
      $gameScreen.restoreNormalMapPictures();
    }
  };

  Game_Player.prototype.isInSubCommandMap = function () {
    return this._originalMapId > 0;
  };

  Game_Player.prototype.isTransferringToOriginalMap = function () {
    return this._transferringToOriginalMap;
  };

  Game_Player.prototype.saveOriginalMap = function () {
    this._originalMapId = $gameMap.mapId();
    this._originalTransparent = this._transparent;
    this.savePosition();
  };

  var _Game_Player_performTransfer = Game_Player.prototype.performTransfer;
  Game_Player.prototype.performTransfer = function () {
    _Game_Player_performTransfer.apply(this, arguments);
    if (this.isTransferringToOriginalMap()) {
      this.restorePosition();
      this._transferringToOriginalMap = false;
    }
  };

  Game_Player.prototype.savePosition = function () {
    Game_CharacterBase.prototype.savePosition.call(this, arguments);
    this._followers.forEach(function (follower) {
      follower.savePosition();
    });
    $gameMap.saveOriginalMapEvent();
  };

  Game_Player.prototype.restorePosition = function () {
    Game_CharacterBase.prototype.restorePosition.call(this, arguments);
    this._followers.forEach(function (follower) {
      follower.restorePosition();
    });
    $gameMap.restoreOriginalMapEvent();
  };

  //=============================================================================
  // Game_Map
  //  すべてのイベントの状態を保存します。
  //=============================================================================
  Game_Map.prototype.saveOriginalMapEvent = function () {
    this._originalMapEvents = this._events;
  };

  Game_Map.prototype.restoreOriginalMapEvent = function () {
    if (this._originalMapEvents) {
      this._events = this._originalMapEvents;
    }
    this._originalMapEvents = null;
  };

  //=============================================================================
  // Game_Party
  //  無効なアクター設定時のエラーを回避します。
  //=============================================================================
  var _Game_Party_setMenuActor = Game_Party.prototype.setMenuActor;
  Game_Party.prototype.setMenuActor = function (actor) {
    if (!actor) return;
    _Game_Party_setMenuActor.apply(this, arguments);
  };

  Game_Screen.prototype.setupMenuMapPictures = function () {
    this._normalMapPictures = this._pictures;
    this.clearPictures();
  };

  Game_Screen.prototype.restoreNormalMapPictures = function () {
    if (this._normalMapPictures) {
      this._pictures = this._normalMapPictures;
    }
    this._normalMapPictures = null;
  };

  //=============================================================================
  // AudioManager
  //  システム効果音を消音します。
  //=============================================================================
  AudioManager.stopAllStaticSe = function () {
    this._staticBuffers.forEach(function (buffer) {
      buffer.stop();
    });
    this._staticBuffers = [];
  };

  //=============================================================================
  // SceneManager
  //  メニュー用マップではキャプチャを無効にします。
  //=============================================================================
  var _SceneManager_snapForBackground = SceneManager.snapForBackground;
  SceneManager.snapForBackground = function () {
    if ($gamePlayer.isInSubCommandMap()) return;
    _SceneManager_snapForBackground.apply(this, arguments);
  };

  //=============================================================================
  // Scene_Map
  //  自作ゲーム用マップ遷移の場合、一部演出を無効化します。
  //=============================================================================
  var _Scene_Map_callMenu = Scene_Map.prototype.callMenu;
  Scene_Map.prototype.callMenu = function () {
    _Scene_Map_callMenu.apply(this, arguments);
    if ($gamePlayer.isInSubCommandMap()) {
      AudioManager.stopAllStaticSe();
      SoundManager.playCancel();
    }
  };

  var _Scene_Map_onMapLoaded = Scene_Map.prototype.onMapLoaded;
  Scene_Map.prototype.onMapLoaded = function () {
    _Scene_Map_onMapLoaded.apply(this, arguments);
    if ($gamePlayer.isInSubCommandMap()) {
      this._transfer = false;
    }
  };

  //=============================================================================
  // Scene_Menu
  //  メインメニューにコマンドを追加します。
  //=============================================================================
  var _Scene_Menu_create = Scene_Menu.prototype.create;
  Scene_Menu.prototype.create = function () {
    _Scene_Menu_create.apply(this, arguments);
    this.loadSubCommandWindowSkin();
    if ($gamePlayer.isInSubCommandMap()) {
      $gamePlayer.reserveTransferToOriginalMap();
    }
    if (this._isSubCommandOkAfterCreate) {
      this.onSubCommandOk();
    }
  };

  Scene_Menu.prototype.loadSubCommandWindowSkin = function () {
    if (param.windowSkin) {
      ImageManager.loadSystem(param.windowSkin);
    }
  };

  var _Scene_Menu_isReady = Scene_Menu.prototype.isReady;
  Scene_Menu.prototype.isReady = function () {
    return (
      _Scene_Menu_isReady.apply(this, arguments) &&
      (!$gamePlayer.isTransferringToOriginalMap() || DataManager.isMapLoaded())
    );
  };

  var _Scene_Menu_start = Scene_Menu.prototype.start;
  Scene_Menu.prototype.start = function () {
    _Scene_Menu_start.apply(this, arguments);
    if ($gamePlayer.isTransferringToOriginalMap()) {
      $gamePlayer.performTransfer();
    }
  };

  var _Scene_Menu_createCommandWindow =
    Scene_Menu.prototype.createCommandWindow;
  Scene_Menu.prototype.createCommandWindow = function () {
    _Scene_Menu_createCommandWindow.apply(this, arguments);
    $gameTemp.iterateMenuParents(function (subCommands, parentName) {
      this._commandWindow.setHandler(
        "parent" + parentName,
        this.commandParent.bind(this)
      );
    }, this);

    /* 最後に選択していたメニューにカーソルを合わせる */
    this.selectLastCommand();
  };

  Scene_Menu.prototype.commandParent = function () {
    var parentName = this._commandWindow.currentExt();
    var subCommands = $gameTemp.getSubMenuCommands(parentName);
    $gameTemp.setLastSubCommandParent(parentName);
    if (subCommands.length === 1) {
      this.onSubCommandOk(subCommands[0]);
    } else {
      if (!param.clearSubMenuOneByObe && this._subMenuWindow) {
        this._subMenuWindow.activate();
      } else {
        this.createSubMenuCommandWindow(parentName);
      }
    }
  };

  Scene_Menu.prototype.createSubMenuCommandWindow = function (parentName) {
    this._subMenuWindow = new Window_MenuSubCommand(this.x, this.y, parentName);
    this._subMenuWindow.updatePlacement(this._commandWindow);
    this._subMenuWindow.setHandler("ok", this.onSubCommandOk.bind(this));
    this._subMenuWindow.setHandler(
      "cancel",
      this.onSubCommandCancel.bind(this)
    );
    // for MOG_MenuBackground.js
    if (typeof this._subMenuWindow.updateBackgroundOpacity === "function") {
      this._subMenuWindow.updateBackgroundOpacity();
    }
    // for MOG_MenuCursor.js and MOG_SceneMenu.js
    if (typeof Imported !== "undefined" && Imported.MMOG_SceneMenu) {
      this.addChild(this._subMenuWindow);
    } else {
      var index = this.getChildIndex(this._windowLayer) + 1;
      this.addChildAt(this._subMenuWindow, index);
    }
  };

  Scene_Menu.prototype.removeSubMenuCommandWindow = function () {
    if (this._subMenuWindow) {
      this.removeChild(this._subMenuWindow);
    }
    this._subMenuWindow = null;
  };

  Scene_Menu.prototype.onSubCommandOk = function (subCommand) {
    this._subCommand = this._subMenuWindow
      ? this._subMenuWindow.currentExt()
      : subCommand;
    $gameTemp.setLastSubCommandIndex(
      this._subMenuWindow ? this._subMenuWindow.index() : 0
    );
    if (this._subCommand.isNeedSelectMember()) {
      if (this._subMenuWindow) {
        this._commandWindow.maskCommand(this._subCommand.getName());
      }
      this._statusWindow.selectLast();
      this._statusWindow.activate();
      this._statusWindow.setHandler("ok", this.executeSubCommand.bind(this));
      this._statusWindow.setHandler("cancel", this.onPersonalCancel.bind(this));
      if (param.clearSubMenuOneByObe) {
        this.removeSubMenuCommandWindow();
      } else {
        this._subMenuWindow.deactivate();
      }
    } else {
      this.executeSubCommand();
    }
  };

  Scene_Menu.prototype.onSubCommandCancel = function () {
    this.removeSubMenuCommandWindow();
    $gameTemp.resetLastSubCommand();
    this._commandWindow.activate();
  };

  var _Scene_Menu_onPersonalCancel = Scene_Menu.prototype.onPersonalCancel;
  Scene_Menu.prototype.onPersonalCancel = function () {
    _Scene_Menu_onPersonalCancel.apply(this);
    this._commandWindow.maskOff();
    /* 最後に選択していたメニューにカーソルを合わせる */
    this.selectLastCommand();
  };

  /**
   * 最後に選択していたメニューにカーソルを合わせる
   */
  Scene_Menu.prototype.selectLastCommand = function () {
    var lastSubCommand = $gameTemp.getLastSubCommand();
    if (lastSubCommand.parent) {
      this._commandWindow.selectSymbol("parent" + lastSubCommand.parent);
      var subCommands = $gameTemp.getSubMenuCommands(lastSubCommand.parent);
      if (subCommands.length !== 1) {
        this.commandParent();
        this._commandWindow.deactivate();
        this._subMenuWindow.select(lastSubCommand.index);
        /* 別シーンからキャラ選択に戻った時 */
        var subCommand = subCommands[lastSubCommand.index];
        if (subCommand.isNeedSelectMember()) {
          this._isSubCommandOkAfterCreate = true;
        }
      }
    }
    $gameTemp.resetLastSubCommand();
  };

  Scene_Menu.prototype.executeSubCommand = function () {
    this.executeSubScript();
    this.moveSubCommandMap();
    if (param.selectActorIdVariable && this._subCommand.isNeedSelectMember()) {
      $gameVariables.setValue(
        param.selectActorIdVariable,
        this._statusWindow.getSelectedActorId()
      );
    }
    if (!SceneManager.isSceneChanging()) {
      this.onSubCommandCancel();
      this._statusWindow.deselect();
      this._commandWindow.maskOff();
    } else {
      this._subCommandSelected = true;
    }
  };

  Scene_Menu.prototype.executeSubScript = function () {
    var script = this._subCommand.getSelectionScript();
    if (!script) return;
    try {
      eval(script);
    } catch (e) {
      SoundManager.playBuzzer();
      console.error(`実行スクリプトエラー[${script}] メッセージ[${e.message}]`);
    }
    if (this._subCommand.isReturnMap()) {
      SceneManager.pop();
    }
  };

  Scene_Menu.prototype.moveSubCommandMap = function () {
    var mapId = this._subCommand.getMoveTargetMap();
    if (mapId <= 0) {
      return;
    }
    $gamePlayer.reserveTransferToSubCommandMap(mapId);
    SceneManager.pop();
  };

  /**
   * メニューから抜ける際に最後に選択したサブコマンドをリセットする
   */
  var _Scene_Menu_terminate = Scene_Menu.prototype.terminate;
  Scene_Menu.prototype.terminate = function () {
    _Scene_Menu_terminate.apply(this, arguments);
    if (this._subCommand && this._subCommand.getMoveTargetMap() <= 0) {
      $gameTemp.resetLastSubCommand();
    }
  };

  var _Scene_Menu_createField = Scene_Menu.prototype.createField;
  Scene_Menu.prototype.createField = function () {
    _Scene_Menu_createField.apply(this, arguments);
    if (this._subMenuWindow) {
      this.addChild(this._subMenuWindow);
    }
  };

  //=============================================================================
  // Window_MenuCommand
  //  サブコマンドを追加します。
  //=============================================================================
  var _Window_MenuCommand_initialize = Window_MenuCommand.prototype.initialize;
  Window_MenuCommand.prototype.initialize = function () {
    this._maskedName = {};
    _Window_MenuCommand_initialize.apply(this, arguments);
  };

  var _Window_MenuCommand_initCommandPosition =
    Window_MenuCommand.initCommandPosition;
  Window_MenuCommand.initCommandPosition = function () {
    if ($gamePlayer.isInSubCommandMap()) return;
    _Window_MenuCommand_initCommandPosition.apply(this, arguments);
  };

  var _Window_MenuCommand_addOriginalCommands =
    Window_MenuCommand.prototype.addOriginalCommands;
  Window_MenuCommand.prototype.addOriginalCommands = function () {
    _Window_MenuCommand_addOriginalCommands.apply(this, arguments);
    if (param.commandPosition === 0) this.makeSubCommandList();
  };

  var _Window_MenuCommand_addOptionsCommand =
    Window_MenuCommand.prototype.addOptionsCommand;
  Window_MenuCommand.prototype.addOptionsCommand = function () {
    _Window_MenuCommand_addOptionsCommand.apply(this, arguments);
    if (param.commandPosition === 1) this.makeSubCommandList();
  };

  var _Window_MenuCommand_addSaveCommand =
    Window_MenuCommand.prototype.addSaveCommand;
  Window_MenuCommand.prototype.addSaveCommand = function () {
    _Window_MenuCommand_addSaveCommand.apply(this, arguments);
    if (param.commandPosition === 2) this.makeSubCommandList();
  };

  var _Window_MenuCommand_addGameEndCommand =
    Window_MenuCommand.prototype.addGameEndCommand;
  Window_MenuCommand.prototype.addGameEndCommand = function () {
    if (this.needsCommand("gameEnd")) {
      _Window_MenuCommand_addGameEndCommand.apply(this, arguments);
    }
    if (param.commandPosition === 3) this.makeSubCommandList();
  };

  var _Window_MenuCommand_needsCommand =
    Window_MenuCommand.prototype.needsCommand;
  Window_MenuCommand.prototype.needsCommand = function (name) {
    var need = _Window_MenuCommand_needsCommand.apply(this, arguments);
    if (name === "options" && param.hideOption) {
      return false;
    }
    if (name === "gameEnd" && param.hideGameEnd) {
      return false;
    }
    return need;
  };

  Window_MenuCommand.prototype.makeSubCommandList = function () {
    $gameTemp.iterateMenuParents(function (subCommands, parentName) {
      this._subCommands = subCommands;
      if (this.checkSubCommands("isVisible")) {
        var commandName = this._maskedName[parentName]
          ? this._maskedName[parentName]
          : subCommands[0].getParentName();
        this.addCommand(
          commandName,
          "parent" + parentName,
          this.checkSubCommands("isEnable"),
          parentName
        );
      }
    }, this);
  };

  Window_MenuCommand.prototype.checkSubCommands = function (methodName) {
    return this._subCommands.some(function (subCommand) {
      return subCommand[methodName]();
    });
  };

  Window_MenuCommand.prototype.calculateSubCommandX = function (width) {
    var x = this.isHorizontalMenu() ? this._cursorRect.x : this.x + this.width;
    x += userSetting.subCommandWindow.adjustX;
    return x.clamp(0, Graphics.boxWidth - width);
  };

  Window_MenuCommand.prototype.calculateSubCommandY = function (height) {
    var y = this.isHorizontalMenu() ? this.y + this.height : this._cursorRect.y;
    y += userSetting.subCommandWindow.adjustY;
    return y.clamp(0, Graphics.boxHeight - height);
  };

  Window_MenuCommand.prototype.isHorizontalMenu = function () {
    return this.maxCols() >= this.maxPageRows();
  };

  Window_MenuCommand.prototype.maskCommand = function (maskName) {
    this._maskedName = {};
    this._maskedName[this.commandName(this.index())] = maskName;
    this.refresh();
  };

  Window_MenuCommand.prototype.maskOff = function () {
    this._maskedName = {};
    this.refresh();
  };

  //=============================================================================
  // Window_MenuStatus
  //  選択しているアクターのIDを取得します。
  //=============================================================================
  Window_MenuStatus.prototype.getSelectedActorId = function () {
    return $gameParty.members()[this._index].actorId();
  };

  //=============================================================================
  // Window_MenuSubCommand
  //  サブコマンドウィンドウのクラスです。
  //=============================================================================
  function Window_MenuSubCommand() {
    this.initialize.apply(this, arguments);
  }

  Window_MenuSubCommand.prototype = Object.create(Window_Command.prototype);
  Window_MenuSubCommand.prototype.constructor = Window_MenuSubCommand;

  Window_MenuSubCommand.prototype.initialize = function (x, y, parentName) {
    this._parentName = parentName;
    Window_Command.prototype.initialize.call(this, x, y);
  };

  Window_MenuSubCommand.prototype.makeCommandList = function () {
    var subMenus = $gameTemp.getSubMenuCommands(this._parentName);
    subMenus.forEach(function (subMenu) {
      if (subMenu.isVisible()) {
        this.addCommand(subMenu.getName(), "ok", subMenu.isEnable(), subMenu);
      }
    }, this);
  };

  Window_MenuSubCommand.prototype.numVisibleRows = function () {
    return param.horizontalSubMenu
      ? 1
      : Window_Command.prototype.numVisibleRows.call(this);
  };

  Window_MenuSubCommand.prototype.maxCols = function () {
    return param.horizontalSubMenu ? this.maxItems() : 1;
  };

  Window_MenuSubCommand.prototype.windowWidth = function () {
    return (
      param.subMenuWidth || Window_Command.prototype.windowWidth.call(this)
    );
  };

  Window_MenuSubCommand.prototype.lineHeight = function () {
    if (userSetting.subCommandWindow.fontSize) {
      return userSetting.subCommandWindow.fontSize + 8;
    } else {
      return Window_Command.prototype.lineHeight.call(this);
    }
  };

  Window_MenuSubCommand.prototype.updatePlacement = function (commandWindow) {
    if (param.subMenuX || param.subMenuY) {
      this.x = param.subMenuX;
      this.y = param.subMenuY;
    } else {
      this.x = commandWindow.calculateSubCommandX(this.width);
      this.y = commandWindow.calculateSubCommandY(this.height);
    }
  };

  Window_MenuSubCommand.prototype.standardFontSize = function () {
    return (
      userSetting.subCommandWindow.fontSize ||
      Window_Command.prototype.standardFontSize.call(this)
    );
  };

  Window_MenuSubCommand.prototype.standardPadding = function () {
    return (
      userSetting.subCommandWindow.padding ||
      Window_Command.prototype.standardPadding.call(this)
    );
  };

  Window_MenuSubCommand.prototype.loadWindowskin = function () {
    if (param.windowSkin) {
      this.windowskin = ImageManager.loadSystem(param.windowSkin);
    } else {
      Window_Command.prototype.loadWindowskin.call(this);
    }
  };

  var _Window_MenuSubCommand_itemTextAlign =
    Window_MenuSubCommand.prototype.itemTextAlign;
  Window_MenuSubCommand.prototype.itemTextAlign = function () {
    return (
      param.subMenuAlign ||
      _Window_MenuSubCommand_itemTextAlign.apply(this, arguments)
    );
  };

  //=============================================================================
  // Game_MenuSubCommand
  //  サブコマンドを扱うクラスです。
  //=============================================================================
  class Game_MenuSubCommand {
    constructor(subCommandData) {
      this._parentName = subCommandData.ParentName;
      this._name = subCommandData.Name;
      this._hiddenSwitchId = subCommandData.HiddenSwitchId;
      this._disableSwitchId = subCommandData.DisableSwitchId;
      this._targetScript = subCommandData.Script;
      this._targetMapId = subCommandData.MapId;
      this._returnMap = subCommandData.ReturnMap === "true";
      this._memberSelect = getArgBoolean(subCommandData.SelectMember);
    }

    getName() {
      return this._name;
    }

    getParentName() {
      return this._parentName;
    }

    isReturnMap() {
      return !this.getMoveTargetMap() && this._returnMap;
    }

    isVisible() {
      return !$gameSwitches.value(this.convert(this._hiddenSwitchId, true));
    }

    isEnable() {
      return (
        !$gameSwitches.value(this.convert(this._disableSwitchId, true)) &&
        !(
          SceneManager.isSceneRetry &&
          SceneManager.isSceneRetry() &&
          this.getMoveTargetMap() > 0
        )
      );
    }

    isNeedSelectMember() {
      return !!this._memberSelect;
    }

    getSelectionScript() {
      return this.convert(this._targetScript, false);
    }

    getMoveTargetMap() {
      return this.convert(this._targetMapId, true);
    }

    convert(text, isNumber) {
      var convertText = convertEscapeCharacters(text);
      return isNumber ? parseInt(convertText) : convertText;
    }
  }
})();


code:
//=============================================================================
// MessageSkip.js
// ----------------------------------------------------------------------------
// Copyright (c) 2015 Triacontane
// This software is released under the MIT License.
// http://opensource.org/licenses/mit-license.php
// ----------------------------------------------------------------------------
// Version
// 1.11.0 2018/06/16 オート及びスキップの機能を一時的に無効化するスイッチを追加
// 1.10.1 2018/05/07 オートモードで途中に「\!」が含まれる場合の待機フレームが正しく計算されない問題を修正
// 1.10.0 2018/05/01 スキップモードとオートモードをスイッチで自動制御できる機能を追加
// 1.9.0 2018/02/18 イベント終了時にオート、スキップを解除するかどうかを任意のスイッチで判定できるように仕様変更
// 1.8.0 2018/02/16 オート待機フレーム数の計算式にウィンドウに表示した文字数を組み込める機能を追加
// 1.7.0 2017/12/12 SkipAlreadyReadMessage.jsとの連携したときに当プラグインのスキップ機能が既読スキップになるよう修正
//                  スキップピクチャの条件スイッチが0(指定なし)のときに同ピクチャが表示されない問題を修正
// 1.6.1 2017/09/21 オートモード時 改ページを伴わない入力待ちの後のメッセージを一瞬でスキップする問題を修正(by DarkPlasmaさん)
// 1.6.0 2017/08/03 キーを押している間だけスキップが有効にできる機能を追加
// 1.5.0 2017/05/27 オートおよびスキップボタンの原点指定と表示可否を変更できるスイッチの機能を追加
// 1.4.0 2017/05/26 クリックでオートおよびスキップを切り替えるボタンを追加
// 1.3.1 2017/05/13 アイコンの量を増やしたときにオートとスキップのアイコンが正常に表示されない問題を修正
// 1.3.0 2017/05/05 スキップ中はメッセージのウェイトを無視するよう修正
// 1.2.0 2017/04/29 並列実行のイベントでも通常イベントが実行中でなければスキップを解除するよう修正
//                  キーコードの「右」と「上」が逆になっていた問題を修正
//                  オート待機フレームを制御文字を使って動的に変更できる機能を追加
// 1.1.0 2016/12/14 並列処理イベントが実行されている場合にスキップが効かなくなる問題を修正
// 1.0.1 2016/02/15 モバイル端末での動作が遅くなる不具合を修正
// 1.0.0 2016/01/15 初版
// ----------------------------------------------------------------------------
// [Blog]   : https://triacontane.blogspot.jp/
// [Twitter]: https://twitter.com/triacontane/
// [GitHub] : https://github.com/triacontane/
//=============================================================================

/*:
 * @plugindesc MessageSkipPlugin
 * @author triacontane
 *
 * @param SkipKey
 * @desc メッセージスキップに該当するキー
 * (キーのアルファベット/shift/control/tab)
 * @default S
 * @type select
 * @option shift
 * @option control
 * @option tab
 * @option S
 *
 * @param AutoKey
 * @desc メッセージオートに該当するキー
 * (キーのアルファベット/shift/control/tab)
 * @default A
 * @type select
 * @option shift
 * @option control
 * @option tab
 * @option A
 *
 * @param SkipSwitchId
 * @desc 指定した番号のスイッチがONになっている場合は常にスキップします。
 * @default 0
 * @type switch
 *
 * @param AutoSwitchIId
 * @desc 指定した番号のスイッチがONになっている場合は常にオートします。スキップが優先されます。
 * @default 0
 * @type switch
 *
 * @param SkipIcon
 * @desc メッセージスキップ中にウィンドウ右下に表示されるアイコン
 * @default 140
 * @type number
 *
 * @param AutoIcon
 * @desc メッセージオート中にウィンドウ右下に表示されるアイコン
 * @default 75
 * @type number
 *
 * @param PressingSkip
 * @desc スキップの判定が指定のキーを押している間のみになります。
 * @default false
 * @type boolean
 *
 * @param AutoWaitFrame
 * @desc オートモードが有効の場合にメッセージを表示しておくフレーム数。制御文字\v[n]および計算式が指定できます。
 * @default 100 + textSize * 10
 *
 * @param ResetOnEndSwitch
 * @desc 指定した番号のスイッチがONのとき、イベント終了時にスキップ、オート状態を解除します。0の場合は常に解除します。
 * @default 0
 * @type switch
 *
 * @param SkipPicture
 * @desc ウィンドウ内に表示するスキップピクチャのファイル名です。クリックするとスキップモードになります。
 * @default
 * @require 1
 * @dir img/pictures/
 * @type file
 *
 * @param PictureAnchor
 * @desc スキップ、オートの各ピクチャボタン座標の原点です。（0:左上、1:右上、2:左下、3:右下）
 * @default 0
 * @type select
 * @option 0
 * @option 1
 * @option 2
 * @option 3
 *
 * @param PictureSwitchId
 * @desc 指定した番号のスイッチがONのときのみスキップ、オートの各ピクチャボタンを表示します。0の場合は無条件で表示します。
 * @default 0
 * @type switch
 *
 * @param SkipPictureX
 * @desc ウィンドウ内に表示するスキップピクチャのX座標です。
 * @default 500
 * @type number
 *
 * @param SkipPictureY
 * @desc ウィンドウ内に表示するスキップピクチャのY座標です。
 * @default 0
 * @type number
 *
 * @param AutoPicture
 * @desc ウィンドウ内に表示するオートピクチャのファイル名です。クリックするとオートモードになります。
 * @default
 * @require 1
 * @dir img/pictures/
 * @type file
 *
 * @param AutoPictureX
 * @desc ウィンドウ内に表示するオートピクチャのX座標です。
 * @default 750
 * @type number
 *
 * @param AutoPictureY
 * @desc ウィンドウ内に表示するオートピクチャのY座標です。
 * @default 0
 * @type number
 *
 * @param InvalidSwitchId
 * @desc 指定したスイッチがONのときプラグインの全機能が無効になります。
 * @default 0
 * @type switch
 *
 * @help メッセージウィンドウでメッセージのスキップやオートモードの切替ができます。
 * イベントが終了すると自働でスキップやオートモードは解除されます。
 * 並列実行イベントは、通常イベントが実行中でない場合のみ解除されます。
 * 明示的に解除したい場合は、以下のスクリプトを実行してください。
 *
 * $gameMessage.clearSkipInfo();
 *
 * ・SkipAlreadyReadMessage.jsとの連携
 * SkipAlreadyReadMessage.js（奏ねこま様作）と併用したときに
 * 当プラグインのスキップ機能は「既読スキップ」機能になります。
 * http://makonet.sakura.ne.jp/rpg_tkool/
 *
 * ・パラメータ「オート待機フレーム」を設定するとオートモード時の待機フレームを変更できます。
 * 制御文字\v[n]のほか、JavaScript計算式が使えます。
 * さらにtextSizeで表示文字数を計算式に組み込むことができます。
 *
 * 指定例：
 * 100 + textSize * 10
 *
 * このプラグインにはプラグインコマンドはありません。
 *
 * This plugin is released under the MIT License.
 */

/*:ja
 * @plugindesc メッセージスキッププラグイン
 * @author トリアコンタン
 *
 * @param スキップキー
 * @desc メッセージスキップに該当するキー
 * (キーのアルファベット/shift/control/tab)
 * @default S
 * @type select
 * @option shift
 * @option control
 * @option tab
 * @option S
 *
 * @param オートキー
 * @desc メッセージオートに該当するキー
 * (キーのアルファベット/shift/control/tab)
 * @default A
 * @type select
 * @option shift
 * @option control
 * @option tab
 * @option A
 *
 * @param スキップスイッチ
 * @desc 指定した番号のスイッチがONになっている場合は常にスキップします。
 * @default 0
 * @type switch
 *
 * @param オートスイッチ
 * @desc 指定した番号のスイッチがONになっている場合は常にオートします。スキップが優先されます。
 * @default 0
 * @type switch
 *
 * @param スキップアイコン
 * @desc メッセージスキップ中にウィンドウ右下に表示されるアイコン
 * @default 140
 * @type number
 *
 * @param オートアイコン
 * @desc メッセージオート中にウィンドウ右下に表示されるアイコン
 * @default 75
 * @type number
 *
 * @param 押し続けスキップ
 * @desc スキップの判定が指定のキーを押している間のみになります。
 * @default false
 * @type boolean
 *
 * @param オート待機フレーム
 * @desc オートモードが有効の場合にメッセージを表示しておくフレーム数。制御文字\v[n]および計算式が指定できます。
 * @default 100 + textSize * 10
 *
 * @param 終了解除スイッチID
 * @desc 指定した番号のスイッチがONのとき、イベント終了時にスキップ、オート状態を解除します。0の場合は常に解除します。
 * @default 0
 * @type switch
 *
 * @param スキップピクチャ
 * @desc ウィンドウ内に表示するスキップピクチャのファイル名です。クリックするとスキップモードになります。
 * @default
 * @require 1
 * @dir img/pictures/
 * @type file
 *
 * @param ボタン原点
 * @desc スキップ、オートの各ピクチャボタン座標の原点です。（0:左上、1:右上、2:左下、3:右下）
 * @default 0
 * @type select
 * @option 0
 * @option 1
 * @option 2
 * @option 3
 *
 * @param ボタン表示スイッチID
 * @desc 指定した番号のスイッチがONのときのみスキップ、オートの各ピクチャボタンを表示します。0の場合は無条件で表示します。
 * @default 0
 * @type switch
 *
 * @param スキップピクチャX
 * @desc ウィンドウ内に表示するスキップピクチャのX座標です。
 * @default 500
 * @type number
 *
 * @param スキップピクチャY
 * @desc ウィンドウ内に表示するスキップピクチャのY座標です。
 * @default 0
 * @type number
 *
 * @param オートピクチャ
 * @desc ウィンドウ内に表示するオートピクチャのファイル名です。クリックするとオートモードになります。
 * @default
 * @require 1
 * @dir img/pictures/
 * @type file
 *
 * @param オートピクチャX
 * @desc ウィンドウ内に表示するオートピクチャのX座標です。
 * @default 750
 * @type number
 *
 * @param オートピクチャY
 * @desc ウィンドウ内に表示するオートピクチャのY座標です。
 * @default 0
 * @type number
 *
 * @param 無効化スイッチ
 * @desc 指定したスイッチがONのときプラグインの全機能が無効になります。
 * @default 0
 * @type switch
 *
 * @help メッセージウィンドウでメッセージのスキップやオートモードの切替ができます。
 * イベントが終了すると自働でスキップやオートモードは解除されます。
 * 並列実行イベントは、通常イベントが実行中でない場合のみ解除されます。
 * 明示的に解除したい場合は、以下のスクリプトを実行してください。
 *
 * $gameMessage.clearSkipInfo();
 *
 * ・SkipAlreadyReadMessage.jsとの連携
 * SkipAlreadyReadMessage.js（奏ねこま様作）と併用したときに
 * 当プラグインのスキップ機能は「既読スキップ」機能になります。
 * http://makonet.sakura.ne.jp/rpg_tkool/
 *
 * ・パラメータ「オート待機フレーム」を設定するとオートモード時の待機フレームを変更できます。
 * 制御文字\v[n]のほか、JavaScript計算式が使えます。
 * さらにtextSizeで表示文字数を計算式に組み込むことができます。
 *
 * 指定例：
 * 100 + textSize * 10
 *
 * このプラグインにはプラグインコマンドはありません。
 *
 * 利用規約：
 *  作者に無断で改変、再配布が可能で、利用形態（商用、18禁利用等）
 *  についても制限はありません。
 *  このプラグインはもうあなたのものです。
 */

/**
 * メッセージボタンスプライト
 * @constructor
 */
function Sprite_MessageButton() {
  this.initialize.apply(this, arguments);
}

/**
 * アイコン描画用スプライト
 * @constructor
 */
function Sprite_Frame() {
  this.initialize.apply(this, arguments);
}

(function () {
  "use strict";
  var pluginName = "MessageSkip";

  var getParamString = function (paramNames, upperFlg) {
    var value = getParamOther(paramNames);
    return value === null ? "" : upperFlg ? value.toUpperCase() : value;
  };

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

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

  var getParamOther = 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 null;
  };

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

  var isNotAString = function (args) {
    return String(args) !== args;
  };

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

  Input.keyCodeReverseMapper = {
    a: 65,
    b: 66,
    c: 67,
    d: 68,
    e: 69,
    f: 70,
    g: 71,
    h: 72,
    i: 73,
    j: 74,
    k: 75,
    l: 76,
    m: 77,
    n: 78,
    o: 79,
    p: 80,
    q: 81,
    r: 82,
    s: 83,
    t: 84,
    u: 85,
    v: 86,
    w: 87,
    x: 88,
    y: 89,
    z: 90,
    backspace: 8,
    tab: 9,
    enter: 13,
    shift: 16,
    ctrl: 17,
    alt: 18,
    pause: 19,
    esc: 27,
    space: 32,
    page_up: 33,
    page_down: 34,
    end: 35,
    home: 36,
    left: 37,
    right: 39,
    up: 38,
    down: 40,
    insert: 45,
    delete: 46,
  };
  (9).times(function (i) {
    Input.keyCodeReverseMapper[i] = i + 48;
  });
  (12).times(function (i) {
    Input.keyCodeReverseMapper["f" + (i + 1)] = i + 112;
  });

  //=============================================================================
  // パラメータの取得と整形
  //=============================================================================
  var skipKeyName = getParamString(["SkipKey", "スキップキー"]).toLowerCase();
  var skipKeyCode = Input.keyCodeReverseMapper[skipKeyName];
  var autoKeyName = getParamString(["AutoKey", "オートキー"]).toLowerCase();
  var autoKeyCode = Input.keyCodeReverseMapper[autoKeyName];
  if (skipKeyCode) {
    if (!Input.keyMapper[skipKeyCode]) {
      Input.keyMapper[skipKeyCode] = "messageSkip";
    } else {
      skipKeyName = Input.keyMapper[skipKeyCode];
    }
  }
  if (autoKeyCode) {
    if (!Input.keyMapper[autoKeyCode]) {
      Input.keyMapper[autoKeyCode] = "messageAuto";
    } else {
      autoKeyName = Input.keyMapper[autoKeyCode];
    }
  }
  var paramSkipPicture = getParamString(["SkipPicture", "スキップピクチャ"]);
  var paramSkipPictureX = getParamNumber(["SkipPictureX", "スキップピクチャX"]);
  var paramSkipPictureY = getParamNumber(["SkipPictureY", "スキップピクチャY"]);
  var paramAutoPicture = getParamString(["AutoPicture", "オートピクチャ"]);
  var paramAutoPictureX = getParamNumber(["AutoPictureX", "オートピクチャX"]);
  var paramAutoPictureY = getParamNumber(["AutoPictureY", "オートピクチャY"]);
  var paramPictureAnchor = getParamNumber(["PictureAnchor", "ボタン原点"]);
  var paramPictureSwitchId = getParamNumber(
    ["PictureSwitchId", "ボタン表示スイッチID"],
    0
  );
  var paramPressingSkip = getParamBoolean(["PressingSkip", "押し続けスキップ"]);
  var paramSkipSwitchId = getParamNumber(
    ["SkipSwitchId", "スキップスイッチ"],
    0
  );
  var paramAutoSwitchIId = getParamNumber(
    ["AutoSwitchIId", "オートスイッチ"],
    0
  );
  var paramInvalidSwitchId = getParamNumber(
    ["InvalidSwitchId", "無効化スイッチ"],
    0
  );

  //=============================================================================
  // Game_Message
  //  メッセージスキップ情報を保持します。
  //=============================================================================
  var _Game_Message_initialize = Game_Message.prototype.initialize;
  Game_Message.prototype.initialize = function () {
    _Game_Message_initialize.apply(this, arguments);
    this.clearSkipInfo();
    this._autoClearSkipSwitch = getParamNumber([
      "ResetOnEndSwitch",
      "終了解除スイッチID",
    ]);
  };

  Game_Message.prototype.toggleSkip = function () {
    this.setSkipFlg(!this._skipFlg);
  };

  Game_Message.prototype.toggleAuto = function () {
    this.setAutoFlg(!this._autoFlg);
  };

  Game_Message.prototype.skipFlg = function () {
    return this._skipFlg;
  };

  Game_Message.prototype.autoFlg = function () {
    return this._autoFlg;
  };

  Game_Message.prototype.setSkipFlg = function (value) {
    this._skipFlg = value;
    if (this._skipFlg) this._autoFlg = false;
  };

  Game_Message.prototype.setAutoFlg = function (value) {
    if (!this._skipFlg) {
      this._autoFlg = value;
    }
  };

  Game_Message.prototype.clearSkipInfo = function () {
    this._skipFlg = false;
    this._autoFlg = false;
  };

  Game_Message.prototype.terminateEvent = function () {
    if (
      !this._autoClearSkipSwitch ||
      $gameSwitches.value(this._autoClearSkipSwitch)
    ) {
      this.clearSkipInfo();
    }
  };

  //=============================================================================
  // Game_Interpreter
  //  マップイベント終了時にメッセージスキップフラグを初期化します。
  //=============================================================================
  var _Game_Interpreter_terminate = Game_Interpreter.prototype.terminate;
  Game_Interpreter.prototype.terminate = function () {
    _Game_Interpreter_terminate.apply(this, arguments);
    if (this.isNeedClearSkip()) {
      $gameMessage.terminateEvent();
    }
  };

  Game_Interpreter.prototype.isNeedClearSkip = function () {
    return (
      ($gameMap.isMapInterpreterOf(this) || !$gameMap.isEventRunning()) &&
      this._depth === 0
    );
  };

  //=============================================================================
  // Game_Map
  //  指定されたインタプリタがマップイベントかどうかを返します。
  //=============================================================================
  Game_Map.prototype.isMapInterpreterOf = function (interpreter) {
    return this._interpreter === interpreter;
  };

  //=============================================================================
  // Window_Message
  //  メッセージスキップ状態を描画します。
  //=============================================================================
  var _Window_Message_initialize = Window_Message.prototype.initialize;
  Window_Message.prototype.initialize = function () {
    _Window_Message_initialize.apply(this, arguments);
    this.createSpriteFrame();
    this.createSpriteSkipButton();
    this.createSpriteAutoButton();
  };

  Window_Message.prototype.createSpriteFrame = function () {
    this._icon = new Sprite_Frame(ImageManager.loadSystem("IconSet"), -1);
    this._icon.x = this.width - this._icon.width;
    this._icon.y = this.height - this._icon.height;
    this.addChild(this._icon);
  };

  Window_Message.prototype.createSpriteSkipButton = function () {
    if (!paramSkipPicture) return;
    this._skipButton = new Sprite_MessageButton(paramSkipPicture);
    this.addChild(this._skipButton);
  };

  Window_Message.prototype.createSpriteAutoButton = function () {
    if (!paramAutoPicture) return;
    this._autoButton = new Sprite_MessageButton(paramAutoPicture);
    this.addChild(this._autoButton);
  };

  Window_Message.prototype.getRelativeButtonX = function (originalX) {
    if (paramPictureAnchor === 1 || paramPictureAnchor === 3) {
      originalX += this.width;
    }
    return originalX;
  };

  Window_Message.prototype.getRelativeButtonY = function (originalY) {
    if (paramPictureAnchor === 2 || paramPictureAnchor === 3) {
      originalY += this.height;
    }
    return originalY;
  };

  var _Window_Message_startMessage = Window_Message.prototype.startMessage;
  Window_Message.prototype.startMessage = function () {
    _Window_Message_startMessage.apply(this, arguments);
    this.initializeMessageAutoCount();
  };

  Window_Message.prototype.initializeMessageAutoCount = function () {
    var textSize = 0;
    if (this._textState) {
      var index = this._textState.index;
      var text = this._textState.text;
      while (
        text[index] &&
        !(text[index] === "\x1b" && text[index + 1] === "!")
      ) {
        index++;
      }
      // use in eval
      textSize = index - this._textState.index;
    }
    var paramValue =
      convertEscapeCharacters(
        getParamString(["AutoWaitFrame", "オート待機フレーム"])
      ) || 1;
    this._messageAutoCount = eval(paramValue);
  };

  var _Window_Message_update = Window_Message.prototype.update;
  Window_Message.prototype.update = function () {
    this.updateAutoIcon();
    return _Window_Message_update.apply(this, arguments);
  };

  var _Window_Message_updatePlacement =
    Window_Message.prototype.updatePlacement;
  Window_Message.prototype.updatePlacement = function () {
    _Window_Message_updatePlacement.apply(this, arguments);
    if (this._skipButton) {
      this.updateSkipButtonPlacement();
    }
    if (this._autoButton) {
      this.updateAutoButtonPlacement();
    }
  };

  Window_Message.prototype.updateSkipButtonPlacement = function () {
    var x = this.getRelativeButtonX(paramSkipPictureX);
    var y = this.getRelativeButtonY(paramSkipPictureY);
    this._skipButton.move(x, y);
  };

  Window_Message.prototype.updateAutoButtonPlacement = function () {
    var x = this.getRelativeButtonX(paramAutoPictureX);
    var y = this.getRelativeButtonY(paramAutoPictureY);
    this._autoButton.move(x, y);
  };

  Window_Message.prototype.updateAutoIcon = function () {
    if (this.messageSkip() && this.openness === 255) {
      this._icon.refresh(getParamNumber(["SkipIcon", "スキップアイコン"]));
      this._icon.flashSpeed = 16;
      this._icon.flash = true;
    } else if (this.messageAuto() && this.openness === 255) {
      this._icon.refresh(getParamNumber(["AutoIcon", "オートアイコン"]));
      this._icon.flashSpeed = 2;
      this._icon.flash = true;
    } else {
      this._icon.refresh(0);
      this._icon.flash = false;
    }
  };

  var _Window_Message_updateWait = Window_Message.prototype.updateWait;
  Window_Message.prototype.updateWait = function () {
    this.updateSkipAuto();
    if (this.messageSkip()) {
      this._waitCount = 0;
    }
    return _Window_Message_updateWait.apply(this, arguments);
  };

  Window_Message.prototype.updateSkipAuto = function () {
    if (this.isClosed()) return;
    if (this.isAnySubWindowActive()) {
      $gameMessage.clearSkipInfo();
    } else {
      this.setSkipAutoFlagByTrigger();
      this.setSkipAutoFlagBySwitch();
    }
    this.updateSkipForSkipAlreadyReadMessage();
  };

  Window_Message.prototype.setSkipAutoFlagByTrigger = function () {
    if (!paramPressingSkip && this.isTriggeredMessageSkip()) {
      $gameMessage.toggleSkip();
    } else if (this.isTriggeredMessageAuto()) {
      $gameMessage.toggleAuto();
    } else if (paramPressingSkip) {
      $gameMessage.setSkipFlg(this.isPressedMessageSkip());
    }
  };

  Window_Message.prototype.setSkipAutoFlagBySwitch = function () {
    if (paramInvalidSwitchId > 0 && $gameSwitches.value(paramInvalidSwitchId)) {
      $gameMessage.setSkipFlg(false);
      $gameMessage.setAutoFlg(false);
      return;
    }
    if (paramSkipSwitchId > 0) {
      $gameMessage.setSkipFlg($gameSwitches.value(paramSkipSwitchId));
    }
    if (paramAutoSwitchIId > 0) {
      $gameMessage.setAutoFlg($gameSwitches.value(paramAutoSwitchIId));
    }
  };

  // for SkipAlreadyReadMessage.js
  Window_Message.prototype.updateSkipForSkipAlreadyReadMessage = function () {
    var pluginName = "SkipAlreadyReadMessage";
    if ($gameMessage[pluginName] && !$gameMessage[pluginName].already_read) {
      $gameMessage.setSkipFlg(false);
    }
  };

  Window_Message.prototype.messageAuto = function () {
    return $gameMessage.autoFlg();
  };

  Window_Message.prototype.messageSkip = function () {
    return $gameMessage.skipFlg();
  };

  var _Window_Message_updateInput = Window_Message.prototype.updateInput;
  Window_Message.prototype.updateInput = function () {
    if (this.messageAuto() && this._messageAutoCount > 0 && this.visible)
      this._messageAutoCount--;
    return _Window_Message_updateInput.apply(this, arguments);
  };

  Window_Message.prototype.isTriggeredMessageSkip = function () {
    return (
      Input.isTriggered("messageSkip") ||
      Input.isTriggered(skipKeyName) ||
      this.isTriggeredMessageSkipButton(false)
    );
  };

  Window_Message.prototype.isPressedMessageSkip = function () {
    return (
      Input.isPressed("messageSkip") ||
      Input.isPressed(skipKeyName) ||
      this.isTriggeredMessageSkipButton(true)
    );
  };

  Window_Message.prototype.isTriggeredMessageSkipButton = function (pressed) {
    return (
      this._skipButton &&
      this._skipButton.isTriggered(
        this.canvasToLocalX(TouchInput.x),
        this.canvasToLocalY(TouchInput.y),
        pressed
      )
    );
  };

  Window_Message.prototype.isTriggeredMessageAuto = function () {
    return (
      Input.isTriggered("messageAuto") ||
      Input.isTriggered(autoKeyName) ||
      this.isTriggeredMessageAutoButton()
    );
  };

  Window_Message.prototype.isTriggeredMessageAutoButton = function () {
    return (
      this._autoButton &&
      this._autoButton.isTriggered(
        this.canvasToLocalX(TouchInput.x),
        this.canvasToLocalY(TouchInput.y)
      )
    );
  };

  var _Window_Message_isTriggered = Window_Message.prototype.isTriggered;
  Window_Message.prototype.isTriggered = function () {
    if (
      this.isTriggeredMessageSkipButton() ||
      this.isTriggeredMessageAutoButton()
    ) {
      return false;
    }
    if (this.messageAuto() && this._messageAutoCount <= 0) {
      this.initializeMessageAutoCount();
      return true;
    }
    return (
      _Window_Message_isTriggered.apply(this, arguments) || this.messageSkip()
    );
  };

  var _Window_Message_startPause = Window_Message.prototype.startPause;
  Window_Message.prototype.startPause = function () {
    _Window_Message_startPause.apply(this, arguments);
    if (this.messageSkip()) this.startWait(2);
  };

  //=============================================================================
  // Sprite_MessageButton
  //  メッセージボタン描画用スプライトです。
  //=============================================================================
  Sprite_MessageButton.prototype = Object.create(Sprite.prototype);
  Sprite_MessageButton.prototype.constructor = Sprite_MessageButton;

  Sprite_MessageButton.prototype.initialize = function (fileName) {
    Sprite.prototype.initialize.call(this);
    this.bitmap = ImageManager.loadPicture(fileName);
    this.anchor.x = 0.5;
    this.anchor.y = 0.5;
    this.visible = false;
  };

  Sprite_MessageButton.prototype.update = function () {
    Sprite.prototype.update.call(this);
    this.updateOpacity();
    this.updateVisibility();
  };

  Sprite_MessageButton.prototype.updateOpacity = function () {
    this.opacity = this.parent.openness;
  };

  Sprite_MessageButton.prototype.updateVisibility = function () {
    if (paramInvalidSwitchId > 0 && $gameSwitches.value(paramInvalidSwitchId)) {
      this.visible = false;
      return;
    }
    this.visible =
      !paramPictureSwitchId || $gameSwitches.value(paramPictureSwitchId);
  };

  Sprite_MessageButton.prototype.isTriggered = function (
    targetX,
    targetY,
    pressed
  ) {
    var realX = targetX + this._frame.width * this.anchor.x;
    var realY = targetY + this._frame.height * this.anchor.y;
    var triggeredOk = pressed
      ? TouchInput.isPressed()
      : TouchInput.isTriggered();
    return triggeredOk && this.isInSprite(realX, realY);
  };

  Sprite_MessageButton.prototype.isInSprite = function (targetX, targetY) {
    return (
      this.x <= targetX &&
      this.x + this._frame.width >= targetX &&
      this.y <= targetY &&
      this.y + this._frame.height >= targetY
    );
  };

  //=============================================================================
  // Sprite_Frame
  //  アイコン描画用スプライトです。
  //=============================================================================
  Sprite_Frame.prototype = Object.create(Sprite.prototype);
  Sprite_Frame.prototype.constructor = Sprite_Frame;

  Sprite_Frame.prototype.initialize = function (bitmap, index) {
    Sprite.prototype.initialize.call(this);
    bitmap.addLoadListener(
      function () {
        this._column = Math.floor(bitmap.width / Window_Base._iconWidth);
        this._row = Math.floor(bitmap.height / Window_Base._iconHeight);
      }.bind(this)
    );
    this.bitmap = bitmap;
    this.anchor.x = 0.5;
    this.anchor.y = 0.5;
    this.flash = false;
    this.flashSpeed = 2;
    this._flashAlpha = 0;
    this.refresh(index ? index : 0);
  };

  Sprite_Frame.prototype.refresh = function (index) {
    if (!this.bitmap.isReady()) return;
    var w = Window_Base._iconWidth;
    var h = Window_Base._iconHeight;
    this.setFrame(
      (index % this._column) * w,
      Math.floor(index / this._column) * h,
      w,
      h
    );
  };

  Sprite_Frame.prototype.update = function () {
    if (this.flash) {
      if (this._flashAlpha <= -64) this._flashAlpha = 192;
      this.setBlendColor([255, 255, 255, this._flashAlpha]);
      this._flashAlpha -= this.flashSpeed;
    }
  };
})();