code:
/*:
 * @plugindesc Add Option to Message log
 * @author siguren
 *
 * @target MZ
 * @base ManoUZ_MessageLog
 *
 * @command OpenScene
 * @text Open Option Screen
 *
 * @param optionText
 * @desc Sets display name on Option Screen.
 * @default Message log Setting
 *
 * @param textON
 * @default ON
 *
 * @param textOFF
 * @default OFF
 *
 * @param logLimitBasicText
 * @text Basic number of logs saved:Item Name
 * @default Basic number of logs saved
 *
 * @param logLimitBasicHelp
 * @text Basic number of logs saved:Description
 * @default Affects the size of saved data.
 * @parent logLimitBasicText
 *
 * @param logLimitBasicItemList
 * @text Number of logs saved:List
 * @type struct<EnumItem>[]
 * @default ["{\"text\":\"Few\",\"value\":\"20\"}","{\"text\":\"Standard\",\"value\":\"40\"}","{\"text\":\"Many\",\"value\":\"60\"}","{\"text\":\"Extreme\",\"value\":\"100\"}"]
 * @parent logLimitBasicText
 *
 * @param logLimitExtendsText
 * @text Number of logs saved/added:Item Name
 * @default Number of logs saved(Add)
 *
 * @param logLimitExtendsHelp
 * @type multiline_string
 * @text Number of logs saved/added:Description
 * @default Affects memory consumption.
 * @parent logLimitExtendsText
 *
 * @param logLimitExtendsItemList
 * @text Number of logs saved/added:List
 * @desc This item is for changing settings.
 * @type struct<EnumItem>[]
 * @default ["{\"text\":\"Few\",\"value\":\"20\"}","{\"text\":\"Standard\",\"value\":\"50\"}","{\"text\":\"Many\",\"value\":\"80\"}"]
 * @parent logLimitExtendsText
 *
 * @param autoWaitTimeText
 * @text Auto Read:Item Name
 * @default Auto Read Wait Time
 *
 * @param autoWaitTimeHelp
 * @type multiline_string
 * @text Auto Read Wait Time:Description
 * @default Waiting time after sentence is displayed.
 * @parent autoWaitTimeText
 *
 * @param autoWaitTimeItemList
 * @text Auto Read Wait Time:Item List
 * @type struct<EnumItem>[]
 * @default ["{\"text\":\"Short\",\"value\":\"180\"}","{\"text\":\"Standard\",\"value\":\"360\"}","{\"text\":\"Long\",\"value\":\"480\"}","{\"text\":\"Very Long\",\"value\":\"600\"}"]
 * @parent autoWaitTimeText
 *
 * @param gaugeColorText
 * @text Gauge Color:Item Name
 * @type string
 * @default Gauge Color
 *
 * @param gaugeColorHelp
 * @type multiline_string
 * @text Gauge Color:Description
 * @default The color of the gauge
 * that appears during the Auto Read Wait Time.
 * @parent gaugeColorText
 *
 * @param gaugeColorItemListOld
 * @text Gauge Color List
 * @type number[]
 * @desc Numeric Value
 * Manually convert a hexadecimal number to a decimal number.
 * @default ["13181999","12674371","8104783","3050327","45797","20362","16628736"]
 * @parent gaugeColorText
 *
 * @param keepAutoMode
 * @text Keep Auto Read Mode:Item Name
 * @default Keep Auto Read Mode
 *
 * @param keepAutoModeHelp
 * @type multiline_string
 * @text Keep Auto Read Mode:Description
 * @default After the conversation has ended, keeps Auto Read Mode on.
 * @parent keepAutoMode
 *
 * @param machinakaMode
 * @text NPC convo Mode Line:Item Name
 * @default NPC convo Mode Line
 *
 * @param machinakaModeHelp
 * @text NPC convo Mode Line:Description
 * @type multiline_string
 * @default number for simultaneous displays in NPC convo Mode.
 * @parent machinakaMode
 *
 *
 *
 * @help
 * Attach optional features to ManoUZ_MessageLog.
 *
 * The main unit has Plugin Commands for changing values directly.
 *
 */
///////////////////////////////////////////////////////////////////////////////////////////////////////

/*:ja
 * @plugindesc メッセージログにオプションを追加
 * @author しぐれん
 *
 * @target MZ
 * @base ManoUZ_MessageLog
 *
 * @command OpenScene
 * @text オプション画面を開く/OpenScene
 *
 * @param optionText
 * @text オプション画面での表示名
 * @default メッセージログ設定
 *
 * @param textON
 * @default ON
 *
 * @param textOFF
 * @default OFF
 *
 *
 * @param logLimitBasicText
 * @text ログ保存数(基本)：項目名
 * @default ログ保存数(基本)
 *
 * @param logLimitBasicHelp
 * @text ログの保存数(基本)：解説
 * @default セーブデータの大きさに影響します。
 * @parent logLimitBasicText
 *
 * @param logLimitBasicItemList
 * @text ログ保存数：候補リスト
 * @type struct<EnumItem>[]
 * @default ["{\"text\":\"少ない\",\"value\":\"20\"}","{\"text\":\"標準\",\"value\":\"40\"}","{\"text\":\"多い\",\"value\":\"60\"}","{\"text\":\"とても多い\",\"value\":\"100\"}"]
 * @parent logLimitBasicText
 *
 * @param logLimitExtendsText
 * @text ログ保存数・追加分：項目名
 * @default ログ保持数(追加)
 *
 * @param logLimitExtendsHelp
 * @text ログ保存数・追加分：説明文
 * @default メモリの消費量に影響します。
 * @parent logLimitExtendsText
 *
 * @param logLimitExtendsItemList
 * @text 追加のログ保存数：項目リスト
 * @desc 設定変更用の項目です。
 * @type struct<EnumItem>[]
 * @default ["{\"text\":\"少ない\",\"value\":\"20\"}","{\"text\":\"標準\",\"value\":\"50\"}","{\"text\":\"多い\",\"value\":\"80\"}"]
 * @parent logLimitExtendsText
 *
 * @param autoWaitTimeText
 * @text オート待ち時間：項目名
 * @default オート待ち時間
 *
 * @param autoWaitTimeHelp
 * @text オート待ち時間：説明文
 * @default 文章表示完了後の待機時間です。
 * @parent autoWaitTimeText
 *
 * @param autoWaitTimeItemList
 * @text オート待ち時間:項目リスト
 * @type struct<EnumItem>[]
 * @default ["{\"text\":\"短い\",\"value\":\"180\"}","{\"text\":\"標準\",\"value\":\"360\"}","{\"text\":\"長い\",\"value\":\"480\"}","{\"text\":\"とても長い\",\"value\":\"600\"}"]
 * @parent autoWaitTimeText
 *
 * @param gaugeColorText
 * @text ゲージ色：項目名
 * @type string
 * @default ゲージ色
 *
 * @param gaugeColorHelp
 * @text ゲージ色：説明文
 * @type string
 * @default オート待ち時間の間に表示するゲージの色。
 * @parent gaugeColorText
 *
 *
 * @param gaugeColorItemListOld
 * @text ゲージ色一覧
 * @type number[]
 * @desc 数値指定です。
 * 各自で16進数を10進数に変換して設定します。
 * @default ["13181999","12674371","8104783","3050327","45797","20362","16628736"]
 * @parent gaugeColorText
 *
 *
 * @param keepAutoMode
 * @text オートモード保持：項目名
 * @default オートモードを保持
 *
 * @param keepAutoModeHelp
 * @text オートモード保持：説明文
 * @default 会話終了後もオートモードを維持します。
 * @parent keepAutoMode
 *
 * @param machinakaMode
 * @text 街中モード行数：項目名
 * @default 街中モード行数
 *
 * @param machinakaModeHelp
 * @text 街中モード行数：説明文
 * @type string
 * @default 表示する数を増やすと、その分ログを表示する場所が減ります。
 * @parent machinakaMode
 *
 *
 *
 * @help
 * ManoUZ_MessageLogにオプション機能を取り付けます。
 *
 * 数値を直接変更するプラグインコマンドは本体側にあります。
 *
 */
/*~struct~EnumItem:
 * @param text
 * @type string
 *
 * @param value
 * @type number
 * @default 0
 */

(function () {
  "use strict";

  /**
   * @typedef {Object} OptionParametor
   * @property {number} logLimitBasic
   * @property {number} logLimitExtends
   * @property {number} autoWaitTime
   * @property {boolean} keepingAutoMode
   * @property {number} gaugeColor
   * @property {number} machinakaLines
   */

  /**
   * @type {String}
   */
  const PLUGIN_NAME = "ManoUZ_MessageLogOption";
  function getParam() {
    return PluginManager.parameters(PLUGIN_NAME);
  }

  /**
   * @returns {OptionParametor}
   */
  function getOption() {
    return ManoUZ_MessageLog.cloneOptionValue();
  }
  /**
   * @param {OptionParametor} option
   */
  function setOption(option) {
    ManoUZ_MessageLog.setOptionValue(option);
  }

  class Option_ItemBase {
    /**
     *
     * @param {string} key
     * @param {string} name
     * @param {string} help
     */
    constructor(key, name, help) {
      this._key = key;
      this._help = help;
      this._name = name;
    }
    helpText() {
      return this._help;
    }
    key() {
      return this._key;
    }

    name() {
      return this._name;
    }
    /**
     * @param {number} index
     * @returns
     */
    text(index) {
      return "";
    }
    /**
     *
     * @param {number} index
     * @returns
     */
    textColor(index) {
      return ColorManager.normalColor();
    }
    /**
     * @param {number} value
     * @returns
     */
    indexOf(value) {
      const maxItems = this.maxItems();
      for (let i = 0; i < maxItems; ++i) {
        const vv = this.value(i);
        if (vv === value) {
          return i;
        }
      }
      return 0;
    }
    maxItems() {
      return 1;
    }
    /**
     * @returns {number}
     * @param {number} _index
     */
    value(_index) {
      return 0;
    }
  }
  /**
   * @typedef {object} ValueTextPair
   * @property {number} value
   * @property {string} text
   */

  class OptionItemEnum extends Option_ItemBase {
    /**
     * @param {string} key
     * @param {string} name
     * @param {string} help
     * @param {ValueTextPair[]} list
     */
    constructor(key, name, help, list) {
      super(key, name, help);
      //this._defaultValue=defaultValue;

      this._list = list;
    }
    /**
     * @param {string} key
     * @param {string} name
     * @param {string} helpText
     * @param {string} listText
     */
    static create(key, name, helpText, listText) {
      /**
       * @type {string[]}
       */
      const listObj = JSON.parse(listText || "[]");

      return new OptionItemEnum(
        key,
        name,
        helpText,
        listObj.map((text) => {
          const obj = JSON.parse(text);
          return {
            text: obj.text,
            value: Number(obj.value),
          };
        })
      );
    }

    maxItems() {
      return this._list.length;
    }
    /**
     * @param {number} index
     * @returns
     */
    text(index) {
      const item = this._list[index];
      if (item) {
        return item.text;
      }
      return "";
    }
    /**
     *
     * @param {number} index
     */
    value(index) {
      const item = this._list[index];
      if (item) {
        return item.value;
      }
      return 0;
    }
  }
  /**
   * @param {string} key
   * @param {string} name
   * @param {string} helpText
   * @param {string} listText
   */
  function createEnumOption(key, name, helpText, listText) {
    return OptionItemEnum.create(key, String(name), String(helpText), listText);
  }

  class OptionItem_Boolean extends Option_ItemBase {
    /**
     * @param {number} index
     * @returns
     */
    value(index) {
      return index;
    }
    /**
     * @param {number} index
     * @returns
     */
    text(index) {
      return index === 0 ? "OFF" : "ON";
    }
    maxItems() {
      return 2;
    }
  }

  class OptionItem_Number extends Option_ItemBase {
    /**
     * @param {string} key
     * @param {string} name
     * @param {string} help
     *
     * @param {number} min
     * @param {number} max
     */
    constructor(key, name, help, min, max) {
      super(key, name, help);
      this._min = min;
      this._max = max;
      this._name = name;
    }
    /**
     * @param {number} index
     * @returns
     */
    text(index) {
      return this.value(index).toString();
    }
    maxItems() {
      return this._max - this._min;
    }
    /**
     *
     * @param {number} index
     * @returns
     */
    value(index) {
      return index + this._min;
    }
  }

  class OptionItemColorSelect extends Option_ItemBase {
    /**
     * @param {string} name
     * @param {string} help
     * @param {number[]} colorList
     */
    constructor(name, help, colorList) {
      super("color", name, help);

      this._colorList = colorList;
    }

    text() {
      return "????";
    }
    /**
     * @param {number} index
     * @returns
     */
    textColor(index) {
      const color = this.value(index);
      const _0x = color.toString(16);
      const zzz = _0x.padStart(6, "0");

      return `#${zzz}`;
    }
    maxItems() {
      return this._colorList.length;
    }
    /**
     *
     * @param {number} index
     * @returns
     */
    value(index) {
      return this._colorList[index];
    }
  }

  /**
   * @template {Option_ItemBase} OptionItemType
   */
  class OptionItemCase {
    /**
     *
     * @param {OptionItemType} obj
     * @param {(opt:OptionParametor)=>number} optionReadFunc
     *
     */
    constructor(obj, optionReadFunc) {
      this._index = 0;
      this._item = obj;
      this._readFunc = optionReadFunc;
    }
    /**
     * @param {OptionParametor} option
     */
    readIndex(option) {
      const value = this._readFunc(option);
      this._index = this._item.indexOf(value);
    }
    helpText() {
      return this._item.helpText();
    }
    name() {
      return this._item.name();
    }
    text() {
      return this._item.text(this._index);
    }
    textColor() {
      return this._item.textColor(this._index);
    }
    changePrev() {
      if (this._index > 0) {
        this._index -= 1;
        return true;
      }
      this._index = this._item.maxItems() - 1;
      return true;
    }
    changeNext() {
      if (this._index + 1 < this._item.maxItems()) {
        this._index += 1;
        return true;
      }
      this._index = 0;
      return true;
    }
    /**
     * @returns {OptionItemType | Option_ItemBase}
     */
    item() {
      return this._item;
    }
    maxItems() {
      return this._item.maxItems();
    }
    value() {
      return this._item.value(this._index);
    }
    /**
     * @param {number} value
     */
    selectValue(value) {
      const index = this._item.indexOf(value);
      this._index = index;
    }
  }

  class OptionClass {
    /**
     *
     * @param {Option_ItemBase[]} list
     */
    constructor(list) {
      /**
       * @type {Map<string,OptionItemCase< Option_ItemBase > >}
       */
      this._map = new Map();
      this.addItem(setting.logLimitBasic, (opt) => opt.logLimitBasic);
      this.addItem(setting.logLimitExtends, (opt) => opt.logLimitExtends);
      this.addItem(setting.autoSpeed, (opt) => opt.autoWaitTime);
      this.addItem(setting.keepAutoMode, (opt) =>
        opt.keepingAutoMode ? 1 : 0
      );
      this.addItem(setting.colorList, (opt) => opt.gaugeColor);
      this.addItem(setting.machinaka, (opt) => opt.machinakaLines);
    }
    /**
     *
     * @param {string} key
     */
    getValue(key) {
      const item = this._map.get(key);
      if (item) {
        return item.value();
      }
      return 0;
    }

    /**
     * @returns {OptionParametor}
     *
     */
    createOption() {
      const autokeep = this.getValue(setting.keepAutoMode.key()) !== 0;
      return {
        autoWaitTime: this.getValue(setting.autoSpeed.key()),
        logLimitBasic: this.getValue(setting.logLimitBasic.key()),
        logLimitExtends: this.getValue(setting.logLimitExtends.key()),
        keepingAutoMode: autokeep,
        gaugeColor: this.getValue(setting.colorList.key()),
        machinakaLines: this.getValue(setting.machinaka.key()),
      };
    }

    /**
     * @private
     * @param {Option_ItemBase} item
     * @param {(option:OptionParametor)=>number} func
     */
    addItem(item, func) {
      const key = item.key();
      this._map.set(key, new OptionItemCase(item, func));
    }
    /**
     *
     * @param {OptionParametor} option
     */
    setOption(option) {
      for (const iterator of this._map.values()) {
        iterator.readIndex(option);
      }
    }
    /**
     * @returns
     */
    createKeyList() {
      return Array.from(this._map.keys());
    }
    /**
     * @param {string} key
     * @returns {OptionItemCase<Option_ItemBase>}
     */
    getItem(key) {
      return this._map.get(key);
    }
  }

  const setting = (function () {
    const param = getParam();
    const logLimitBasic = createEnumOption(
      "logbasic",
      param.logLimitBasicText,
      param.logLimitBasicHelp || "",
      param.logLimitBasicItemList || "[]"
    );

    const logLimitExtends = createEnumOption(
      "logextends",
      param.logLimitExtendsText,
      param.logLimitExtendsHelp || "",
      param.logLimitExtendsItemList || "[]"
    );

    const autoSpeed = createEnumOption(
      "autospeed",
      param.autoWaitTimeText,
      param.autoWaitTimeHelp,
      param.autoWaitTimeItemList || "[]"
    );

    /**
     * @type {String[]}
     */
    const colorArray = JSON.parse(param.gaugeColorItemListOld);
    const colorList = new OptionItemColorSelect(
      String(param.gaugeColorText),
      String(param.gaugeColorHelp),
      colorArray.map((c) => Number(c))
    );
    const keepAutoMode = new OptionItem_Boolean(
      "autokeep",
      String(param.keepAutoMode),
      String(param.keepAutoModeHelp)
    );

    const machinaka = new OptionItem_Number(
      "machinaka",
      String(param.machinkaMode || param.machinakaMode),
      String(param.machinakaModeHelp || param.machinkaModeHelp),
      1,
      9
    );

    const optionText = String(param.optionText);

    const result = {
      optionText,
      logLimitBasic,
      logLimitExtends,
      colorList,
      autoSpeed,
      keepAutoMode,
      machinaka,
    };
    return result;
  })();

  class Window_LogOption extends Window_Selectable {
    /**
     * @param {Rectangle} rect
     */
    constructor(rect) {
      super(rect);
      this._optionClass = new OptionClass(setting.itemList);
      this._list = this._optionClass.createKeyList();
    }
    /**
     *
     * @param {OptionParametor} value
     */
    setOption(value) {
      this._optionClass.setOption(value);
      this.refresh();
    }
    /**
     *  @returns {OptionParametor}
     */
    createOption() {
      return this._optionClass.createOption();
    }
    maxItems() {
      if (this._list) {
        return this._list.length;
      }
      return 0;
    }
    changeNextValue() {
      const index = this.index();
      const key = this._list[index];
      const item = this._optionClass.getItem(key);
      if (item) {
        if (item.changeNext()) {
          this.playCursorSound();
          this.redrawItem(index);
        }
      }
    }
    changePrevValue() {
      const index = this.index();
      const key = this._list[index];
      const item = this._optionClass.getItem(key);
      if (item) {
        if (item.changePrev()) {
          this.playCursorSound();
          this.redrawItem(index);
        }
      }
    }
    cursorLeft() {
      this.changePrevValue();
    }
    playOkSound() {}
    cursorRight() {
      this.changeNextValue();
    }

    /**
     *
     * @param {OptionItemCase<Option_ItemBase>} item
     * @param {Rectangle} rect
     */
    drawItemText(item, rect) {
      const color = item.textColor();
      this.changeTextColor(color);
      this.drawText(item.text(), rect.x, rect.y, rect.width, "right");
    }
    /**
     * @param {number} index
     */
    itemAt(index) {
      const key = this._list[index];
      if (!key) {
        return null;
      }
      return this._optionClass.getItem(key);
    }
    /**
     * @param {number} index
     */
    drawItem(index) {
      const item = this.itemAt(index);
      if (item) {
        const rect = this.itemRectWithPadding(index);
        const nameWidth = Math.min(rect.width, 200);
        const name = item.name() || "";
        this.drawTextEx(name, rect.x, rect.y, nameWidth);
        if (item.item() !== setting.colorList) {
          this.drawItemText(item, rect);
        } else {
          const colorRect = new Rectangle(
            rect.x + 240,
            rect.y + 2,
            rect.width - 240,
            rect.height - 4
          );
          const color = item.textColor();
          this.drawColorBar(colorRect, color);
        }
      }
    }
    /**
     * @param {Rectangle} rect
     * @param {string} color
     */
    drawColorBar(rect, color) {
      this.contents.fillRect(rect.x, rect.y, rect.width, rect.height, color);
    }
    updateHelp() {
      const item = this.itemAt(this.index());
      if (item) {
        this._helpWindow.setText(item.helpText());
      }
    }
  }
  /**
   *
   * @param {string} symbol
   * @param {Sprite_Button} other
   * @param {number} buttonY
   * @param {number} spacing
   */
  function createButton(symbol, other, buttonY, spacing) {
    const button = new Sprite_Button(symbol);
    button.x = other.x - button.width - spacing;
    button.y = buttonY;
    return button;
  }

  class Scene_MessageLogOption extends Scene_MenuBase {
    constructor() {
      super();
      this._helpWindow = null;
      this._opitonWindow = null;
    }
    create() {
      super.create();
      this.createAllWindows();
    }
    createAllWindows() {
      this.createHelpWindow();
      this.createLogOpitonWindow();
    }
    logWindowRect() {
      const x = 0;
      const y = this.mainAreaTop();
      const w = Graphics.boxWidth;
      const h = this.mainAreaHeight();
      return new Rectangle(x, y, w, h);
    }
    createButtons() {
      super.createButtons();
      if (ConfigManager.touchUI) {
        this.createCursorButton();
      }
    }

    createCursorButton() {
      if (!this._cancelButton) {
        return;
      }
      const spacing = 4;
      const buttonY = this.buttonY();

      const right = createButton(
        "pagedown",
        this._cancelButton,
        buttonY,
        spacing
      );
      const left = createButton("pageup", right, buttonY, spacing);

      this.addWindow(right);
      this.addWindow(left);
    }
    createLogOpitonWindow() {
      const low = new Window_LogOption(this.logWindowRect());
      low.setOption(getOption());
      low.setHandler("ok", this.onOptionOk.bind(this));
      low.setHandler("cancel", this.saveOption.bind(this));
      low.setHandler("pageup", this.onOptionPageup.bind(this));
      low.setHandler("pagedown", this.onOptionPagedown.bind(this));

      this._opitonWindow = low;
      this.addWindow(low);
      low.select(0);
      low.setHelpWindow(this._helpWindow);
      low.activate();
    }
    onOptionOk() {
      this._opitonWindow.changeNextValue();
      this._opitonWindow.activate();
    }
    onOptionPageup() {
      this._opitonWindow.changePrevValue();
      this._opitonWindow.activate();
    }
    onOptionPagedown() {
      this._opitonWindow.changeNextValue();
      this._opitonWindow.activate();
    }

    saveOption() {
      const value = this._opitonWindow.createOption();
      setOption(value);
      this.popScene();
    }
  }

  const MESSAGELOG_OPTION = "MSGLOG_OPTION";

  const Window_Options_makeCommandList =
    Window_Options.prototype.makeCommandList;

  Window_Options.prototype.makeCommandList = function () {
    Window_Options_makeCommandList.call(this);
    this.addCommand(setting.optionText, MESSAGELOG_OPTION);
  };
  const Window_Options_drawItem = Window_Options.prototype.drawItem;
  Window_Options.prototype.drawItem = function (index) {
    const symbol = this.commandSymbol(index);
    if (symbol === MESSAGELOG_OPTION) {
      const rect = this.itemRectWithPadding(index);
      this.drawTextEx(setting.optionText, rect.x, rect.y, rect.width);
    } else {
      Window_Options_drawItem.call(this, index);
    }
  };
  const Window_Options_processOk = Window_Options.prototype.processOk;
  Window_Options.prototype.processOk = function () {
    Window_Options_processOk.call(this);
    if (SceneManager.isSceneChanging()) {
      return;
    }
    const symbol = this.currentSymbol();
    if (symbol === MESSAGELOG_OPTION) {
      SceneManager.push(Scene_MessageLogOption);
      return;
    }
  };

  PluginManager.registerCommand(PLUGIN_NAME, "OpenScene", () => {
    SceneManager.push(Scene_MessageLogOption);
  });
})();


code:
/*:
 * @plugindesc Auxiliary patch for ManoUZ_MessgiLog
 * @author しぐれん
 * @base ManoUZ_MessageLog
 * @orderAfter ManoUZ_MessageLog
 *
 * @base SimpleVoice
 * @orderAfter  SimpleVoice
 *
 * @target MZ
 * @help
 * This is a plugin for linking with SimpleVoice.js.
 * Log the played audio to the log
 */

/*:ja
 * @plugindesc ManoUZ_MessgiLogの補助用パッチです
 * @author しぐれん
 * @base ManoUZ_MessageLog
 * @orderAfter ManoUZ_MessageLog
 *
 * @base SimpleVoice
 * @orderAfter  SimpleVoice
 *
 * @target MZ
 * @help
 * トリアコンタンさんのSimpleVoiceと連携するためのプラグインです。
 * 再生した音声をログに記録します。
 */
(function () {
  "use stirct";
  if (!ManoUZ_MessageLog) {
    return;
  }
  function readExParam(exParam) {
    if (exParam) {
      return {
        /**
         * @type {Boolean}
         */
        loop: exParam.loop || false,
        /**
         * @type {Number}
         */
        chanel: exParam.chanel || 0,
      };
    }
    return {
      loop: false,
      chanel: 0,
    };
  }
  if (ManoUZ_MessageLog.setCannelVolumeFunction) {
    ManoUZ_MessageLog.setCannelVolumeFunction((se, exParam) => {
      const ex = readExParam(exParam);
      AudioManager.playVoice(se, ex.loop, ex.chanel);
    });
  }
  const AudioManager_playVoice = AudioManager.playVoice;
  if (AudioManager_playVoice) {
    AudioManager.playVoice = function (audio, loop, chanel) {
      if (audio) {
        const exParam = {
          loop: loop,
          chanel: chanel,
        };
        ManoUZ_MessageLog.setLastVoiceParam(audio, exParam);
      }
      AudioManager_playVoice.call(this, audio, loop, chanel);
    };
  }
})();

repo_name: dazed/translations

license: unknown


code:
//=============================================================================
// Mano_BackupSave.js
// ----------------------------------------------------------------------------
// Copyright (c) 2021-2021 Sigureya
// This software is released under the MIT License.
// http://opensource.org/licenses/mit-license.php
// ----------------------------------------------------------------------------
// Version
// 1.0.0 2022/01/28 初版
// ----------------------------------------------------------------------------
// [Twitter]: https://twitter.com/Sigureya/
//=============================================================================
/*:
 * @plugindesc Make a backup of your save data as the game progresses.
 * @author siguren(https://github.com/Sigureya/RPGmakerMV)
 * @url https://raw.githubusercontent.com/Sigureya/RPGmakerMZ/master/Mano_BackupSave.js
 *
 * @target MZ
 *
 * @command BackupSave
 * @text createBackup
 * @arg id
 * @text BackupNumber
 * @desc Even if they are not serial numbers,
 * they are arranged in numerical order.
 * @type number
 * @min 1
 * @default 1
 *
 * @arg switchId
 * @text Multiple call prevention (blank OK)
 * @desc Use the switch to make a one-time backup.
 * @type switch
 * @default 0
 *
 * @arg text
 * @text helpText
 * @desc It is used for display on the reading screen.
 *
 * @command BackupScene
 * @text OpenBackup
 * @desc Open the backup load scene.
 *
 * @param titleWidth
 * @text titleWidth
 * @type number
 * @default 180
 *
 * @param titleFormat
 * @text titleFormat
 * @type string
 * @default backup %1
 *
 * @param commandName
 * @text CommandNamne
 * @desc Command name to display in the title scene
 * @default Backup Load
 *
 * @param commandHeight
 * @type number
 * @default 44
 *
 *
 * @help
 * Only one save data is created when advancing the game,
 * You may get stuck when you get caught in a bug.
 * This plugin forces data to be saved separately from regular save files.
 *
 * Save data is created with a plug-in command.
 *
 * ■ Timing of backup creation
 * Call "Create Backup" when the following conditions are met.
 * In theory, it is possible at any time, but for safety.
 * ・ Timing that is called only once (can be automated with a switch)
 * ・ Map with few events for production (affects the size of save data, etc.)
 * -The last line of the event command (Avoiding problems by updating game data-described later)
 * When you arrive in a new city, it is easy to meet these conditions.
 *
 * ■ When backing up with different save data
 * Different save data ・ When backing up in the same location
 * Overwrite the old one with a later backup.
 *
 * ■ About the effect of updating game data
 * If you have saved a chapter, please end the event as soon as possible.
 * It is recommended to place it as the last command of the map event.
 *
 * If there is a process immediately after the backup save,
 * The process will be executed after loading.
 * This will cause the old process to be executed when updating the game data.
 *
 */

/*:ja
 * @plugindesc ゲームの進行に合わせて、セーブデータのバックアップを作成します。
 * @author しぐれん(https://github.com/Sigureya/RPGmakerMV)
 * @url https://raw.githubusercontent.com/Sigureya/RPGmakerMZ/master/Mano_BackupSave.js
 *
 * @target MZ
 *
 * @command BackupSave
 * @text バックアップ作成/createBackup
 * @arg id
 * @text バックアップ番号/BackupNumber
 * @desc 連番でなくても、番号順に並びます。
 * Even if they are not serial numbers, they are arranged in numerical order.
 * @type number
 * @min 1
 * @default 1
 *
 * @arg switchId
 * @text 多重呼び出し防止(空欄OK)
 * @desc スイッチを利用し、バックアップを1回だけ行うようにします。
 * @type switch
 * @default 0
 *
 * @arg text
 * @text 名称/helpText
 * @desc 読み込み画面での表示に使います。
 *
 * @command BackupScene
 * @text バックアップを開く/OpenBackup
 * @desc バックアップ読み込み画面を開きます。
 *
 * @param titleWidth
 * @text タイトルの幅/titleWidth
 * @type number
 * @default 180
 *
 * @param titleFormat
 * @text タイトル書式/titleFormat
 * @type string
 * @default バックアップ %1
 *
 * @param commandName
 * @text コマンド名/CommandNamne
 * @desc タイトル画面でのコマンド名
 * CommandName for SceneTitle
 * @default バックアップ読み込み
 *
 * @param commandHeight
 * @type number
 * @default 44
 *
 *
 * @help
 * ゲームを進める際に1つしかセーブデータを作っておらず、
 * バグに巻き込まれた際に詰みになってしまうことがあります。
 * このプラグインは、通常のセーブファイルと別にデータを強制的に保存させます。
 *
 * セーブデータの作成はプラグインコマンドで行います。
 *
 * ■バックアップ作成のタイミング
 * 以下の条件を満たすタイミングで「バックアップ作成」を呼び出してください。
 * 理論上どのタイミングでも可能ですが、安全のためです。
 * ・1回しか呼び出されないタイミング(スイッチで自動化可能)
 * ・演出用のイベントが少ないマップ(セーブデータの大きさなどに影響)
 * ・イベントコマンドの最後の行(ゲームデータ更新による不具合回避・後述)
 * 新しい街に到着したタイミングは、これらの条件を満たしやすいです。
 *
 * ■異なるセーブデータでバックアップを行った場合
 * 異なるセーブデータ・同じ場所でバックアップを行った場合、
 * 後で行ったバックアップで古い方を上書きします。
 *
 * ■ゲームデータ更新の影響について
 * チャプターセーブを行った場合、早めにイベントを終了してください。
 * マップイベントの一番最後のコマンドとして配置することを推奨します。
 *
 * バックアップセーブの直後に処理があると、
 * 読み込み後にその処理が実行されてしまいます。
 * これはゲームデータ更新の際に古い処理が実行される原因になります。
 *
 * ■更新履歴
 * 2022/01/29 ver 1.2
 * 非同期処理に関する問題を修正。
 *
 */

//TODO:ゲーム終了時に勝手にバックアップを作る機能
//最後のセーブから一定時間経過していたら行う

(function () {
  "use strict";
  /**
   * @type {String}
   */
  const PLUGIN_NAME = "Mano_BackupSave";
  function getCurrentScriptName() {
    const pluginName = decodeURIComponent(document.currentScript.src).match(
      /([^/]+)\.js$/
    );
    if (pluginName) {
      return pluginName[1];
    }
    return "";
  }
  /**
   * @param {String} officialFileName
   */
  function TestFileNameValid(officialFileName) {
    const currentFileName = getCurrentScriptName();
    if (officialFileName === currentFileName) {
      return;
    }
    const message =
      `Do not rename the plugin file.<br>` +
      `Current file name: ${currentFileName}<br>` +
      `Original file name: ${officialFileName}<br>` +
      `プラグインファイルの名前を変更してはいけません<br>` +
      `現在のファイル名:` +
      currentFileName +
      `<br>` +
      `本来のファイル名:${officialFileName}`;
    throw new Error(message);
  }
  TestFileNameValid(PLUGIN_NAME);

  function getParam() {
    return PluginManager.parameters("Mano_BackupSave");
  }
  const setting = (function () {
    const param = getParam();
    const result = {
      commandHeight: Number(param.commandHeight || 44),
      commandName: String(param.commandName),
      titleFormat: String(param.titleFormat),
      titleWidth: Number(param.titleWidth),
    };
    return result;
  })();
  const BACKUP_SYMBOL = "BACKUP";
  /**
   *
   * @param {String} filename
   * @param {*} obj
   * @returns {Promise}
   */
  function saveObject(filename, obj) {
    return StorageManager.saveObject(filename, obj);
  }
  /**
   * @param {String} filename
   * @returns {Promise}
   */
  function loadObject(filename) {
    return StorageManager.loadObject(filename);
  }
  /**
   *
   * @returns {Number}
   */
  function chapterId(c) {
    if (c) {
      return c.chapterId;
    }
    return 0;
  }
  class BackupInfo {
    constructor() {
      this.clear();
    }
    clear() {
      /**
       * @type {{helpText:String, chapterId:Number, info:rm.types.SaveFileInfo,}[]}
       */
      this._globalInfo = [];
    }
    sort() {
      this._globalInfo.sort((a, b) => {
        return chapterId(a) - chapterId(b);
      });
    }
    removeInvalidGlobalInfo() {
      this._globalInfo = this._globalInfo.filter((info) => {
        if (info) {
          const filename = this.makeFileName(info.chapterId);
          if (StorageManager.exists(filename)) {
            return true;
          }
        }
      });
    }
    isEmpty() {
      return this._globalInfo.length <= 0;
    }

    refresh() {
      this.removeInvalidGlobalInfo();
      this.sort();
    }
    /**
     *
     * @param {Number} chapterId
     * @returns
     */
    indexOf(chapterId) {
      for (let i = 0; i < this._globalInfo.length; ++i) {
        const info = this._globalInfo[i];
        if (info.chapterId === chapterId) {
          return i;
        }
      }
      return -1;
    }
    separateChar() {
      if (StorageManager.isLocalMode()) {
        return "\\";
      }
      return ".";
    }

    /**
     * @param {Number} chapterId
     * @param {String} helpText
     * @param {rm.types.SaveFileInfo} info
     */
    push(chapterId, helpText, info) {
      const backupItem = {
        chapterId: chapterId,
        helpText: helpText,
        info: info,
      };
      const index = this.indexOf(chapterId);
      if (index >= 0) {
        this._globalInfo[index] = backupItem;
      } else {
        this._globalInfo.push(backupItem);
      }
    }
    /**
     * @param {Number} index
     * @returns
     */
    itemAt(index) {
      return this._globalInfo[index];
    }
    /**
     * @param {Number} index
     * @returns {Promise}
     */
    loadBackup(index) {
      const item = this.itemAt(index);
      const filename = this.makeFileName(item.chapterId);

      return StorageManager.loadObject(filename);
    }
    /**
     * @param {Number} index
     * @returns
     */
    helpText(index) {
      const item = this.itemAt(index);
      if (item) {
        return item.helpText;
      }
      return "";
    }
    numItems() {
      return this._globalInfo.length;
    }
    infoFileName() {
      return this.backupFolderName() + "backupInfo";
    }
    executeSaveFileInfoList() {
      //this.makeDirectory();
      saveObject(this.infoFileName(), this._globalInfo);
    }
    executeLoadFileInfoList() {
      //起動時に1回だけ呼び出される
      const fileName = this.infoFileName();
      loadObject(fileName)
        .then((info) => {
          this._globalInfo = info;
          this.refresh();
        })
        .catch(() => {
          this.clear();
        });
    }
    /**
     * @param {Number} chapterId
     * @returns
     */
    makeFileName(chapterId) {
      return `${this.backupFolderName()}backup${chapterId}`;
    }
    backupFolderName() {
      return `backup` + this.separateChar();
    }
    makeDirectory() {
      if (StorageManager.isLocalMode()) {
        const folderName = this.backupFolderName();
        const parentPath = StorageManager.fileDirectoryPath();
        StorageManager.fsMkdir(parentPath + folderName);
      }
    }

    loadGloablInfo() {
      this.executeLoadFileInfoList();
      this.refresh();
    }
    /**
     *
     * @param {Number} index
     * @returns
     */
    backupFileName(index) {
      const item = this.itemAt(index);
      if (item) {
        return `${this.backupFolderName()}chapter${item.chapterId}`;
      }
      return "";
    }
    /**
     * @param {Number} chapterId
     * @param {String} chapterText
     */
    async saveChappter(chapterId, chapterText) {
      $gameSystem.onBeforeSave();
      const contents = DataManager.makeSaveContents();
      const fileName = this.makeFileName(chapterId);
      this.makeDirectory();
      await saveObject(fileName, contents);
      const info = DataManager.makeSavefileInfo();
      this.push(chapterId, chapterText, info);
      this.executeSaveFileInfoList();
    }
  }

  class ChapterSaveManager_T {
    constructor() {
      this._fileWriting = false;
      this._globalInfoV2 = new BackupInfo();
    }
    isFileWriting() {
      return this._fileWriting;
    }
    loadGloablInfo() {
      return this._globalInfoV2.loadGloablInfo();
    }
    /**
     * @param {Number} index
     * @returns
     */
    getSaveFileInfo(index) {
      return this._globalInfoV2.itemAt(index);
    }
    /**
     * @param {Number} index
     * @returns
     */
    chapterText(index) {
      return this._globalInfoV2.helpText(index);
    }

    /**
     * @param {Number} chapterId
     * @param {String} chapterText
     */
    saveChappter(chapterId, chapterText) {
      this._fileWriting = true;
      return this._globalInfoV2
        .saveChappter(chapterId, chapterText)
        .finally(() => {
          this._fileWriting = false;
        });
    }
    /**
     * @param {Number} index
     */
    executeLoad(index) {
      return this._globalInfoV2.loadBackup(index).then((contents) => {
        DataManager.createGameObjects();
        DataManager.extractSaveContents(contents);
        DataManager.correctDataErrors();
      });
    }
    numItems() {
      return this._globalInfoV2.numItems();
    }
  }

  const backupManager = new ChapterSaveManager_T();
  class Window_BackupFileLoad extends Window_SavefileList {
    helpText() {
      return backupManager.chapterText(this.index());
    }
    updateHelp() {
      const helpText = this.helpText();
      this._helpWindow.setText(helpText);
    }
    /**
     *
     * @param {Number} chapterId
     * @param {Number} x
     * @param {Number} y
     */
    drawFileTitle(chapterId, x, y) {
      const text = setting.titleFormat.format(chapterId);
      this.drawText(text, x, y, setting.titleWidth);
    }
    drawItem(index) {
      const rect = this.itemRectWithPadding(index);
      const info = backupManager.getSaveFileInfo(index);
      this.resetTextColor();
      this.changePaintOpacity(!!info);

      if (info) {
        this.drawFileTitle(info.chapterId, rect.x, rect.y);
        this.drawContents(info.info, rect);
      }
    }
    maxItems() {
      return backupManager.numItems();
    }
  }
  class Scene_BackupLoad extends Scene_Load {
    /**
     * @returns {String}
     */
    helpWindowText() {
      return this._listWindow.helpText();
    }
    createListWindow() {
      //Windowと関連するセーブデータが専用なので、独自のクラスを作る
      const rect = this.listWindowRect();
      const wsf = new Window_BackupFileLoad(rect);
      wsf.select(0);
      wsf.setHelpWindow(this._helpWindow);
      wsf.setHandler("ok", this.onSavefileOk.bind(this));
      wsf.setHandler("cancel", this.popScene.bind(this));
      wsf.refresh();
      this.addWindow(wsf);
      this._listWindow = wsf;
    }
    backupFileName() {
      return "test";
    }
    onLoadSuccess() {
      super.onLoadSuccess();
      DataManager.selectSavefileForNewGame();
    }
    /**
     * @param {Number} index
     */
    executeLoad(index) {
      backupManager
        .executeLoad(index)
        .then(() => {
          this.onLoadSuccess();
        })
        .catch(() => {
          this.onLoadFailure();
        });
    }
    onSavefileOk() {
      if (this._listWindow.isCurrentItemEnabled()) {
        const savefileIndex = this._listWindow.index();
        this.executeLoad(savefileIndex);
      } else {
        this.onLoadFailure();
      }
    }
  }
  const Scene_Boot_loadPlayerData = Scene_Boot.prototype.loadPlayerData;
  Scene_Boot.prototype.loadPlayerData = function () {
    Scene_Boot_loadPlayerData.call(this);
    backupManager.loadGloablInfo();
  };
  const Window_TitleCommand_addCommand =
    Window_TitleCommand.prototype.addCommand;
  Window_TitleCommand.prototype.addCommand = function (name, symbol, enabled) {
    Window_TitleCommand_addCommand.apply(this, arguments);
    if (symbol === "continue") {
      this.addCommand(setting.commandName, BACKUP_SYMBOL);
      this.setHandler(BACKUP_SYMBOL, () => {
        SceneManager.push(Scene_BackupLoad);
      });
    }
  };
  const Scene_Title_commandWindowRect = Scene_Title.prototype.commandWindowRect;
  Scene_Title.prototype.commandWindowRect = function () {
    const rect = Scene_Title_commandWindowRect.call(this);
    rect.height += setting.commandHeight;
    return rect;
  };
  const WAIT_FOR_WRITE = "WaitForFileWrite";
  function createAwaitEventCode() {
    return [
      {
        code: 357,
        indent: 0,
        parameters: [PLUGIN_NAME, WAIT_FOR_WRITE],
      },
    ];
  }

  PluginManager.registerCommand(PLUGIN_NAME, WAIT_FOR_WRITE, function () {
    /**
     * @type {Game_Interpreter}
     */
    const inter = this;
    if (backupManager.isFileWriting()) {
      inter.wait(10);
      inter.jumpTo(0);
    }
  });
  PluginManager.registerCommand(PLUGIN_NAME, "BackupSave", function (arg) {
    if (backupManager.isFileWriting()) {
      return;
    }
    const switchId = Number(arg.switchId);
    if ($gameSwitches.value(switchId)) {
      return;
    }
    /**
     * @type {Game_Interpreter}
     */
    const inter = this;
    const code = createAwaitEventCode();
    //実行完了までの待機用イベントをセットする
    inter.setupChild(code, 0);
    $gameSwitches.setValue(switchId, true);
    const chapterId = Number(arg.id);
    backupManager.saveChappter(chapterId, arg.text);
  });

  PluginManager.registerCommand(PLUGIN_NAME, "BackupScene", () => {
    SceneManager.push(Scene_BackupLoad);
  });
})();