// DarkPlasma_Promise_StatusLayout 1.1.3
// Copyright (c) 2020 DarkPlasma

/**
 * 2021/08/28 1.1.3 耐性100％時の表示設定追加
 *            1.1.2 ステート無効化している場合、100％表示にする
 *            1.1.1 耐性表示を小数点第一位で四捨五入する
 *            1.1.0 耐性表示機能を追加
 * 2020/09/08 1.0.1 rollup構成へ移行
 * 2020/09/01 1.0.0 初回
 */

/*:ja
 * @plugindesc Promise用ステータス画面レイアウト
 * @author DarkPlasma
 * @license No License
 *
 * @target MZ
 *
 * @base DarkPlasma_ParameterText
 *
 * @param elements
 * @desc 耐性を表示する属性の一覧
 * @text 属性一覧
 * @type struct<Element>[]
 * @default ["{\"id\":\"2\",\"iconIndex\":\"64\"}","{\"id\":\"3\",\"iconIndex\":\"65\"}","{\"id\":\"4\",\"iconIndex\":\"66\"}","{\"id\":\"5\",\"iconIndex\":\"67\"}","{\"id\":\"6\",\"iconIndex\":\"68\"}","{\"id\":\"7\",\"iconIndex\":\"69\"}"]
 *
 * @param states
 * @desc 耐性を表示するステートの一覧
 * @text ステート一覧
 * @type state[]
 * @default ["4", "5", "6", "7", "8", "9", "10", "11", "12"]
 *
 * @param invalidText
 * @desc 耐性が100％の場合の表示。空の場合、100％表記
 * @text 無効化時の表示
 * @type string
 * @default 無効
 *
 * @help
 * version: 1.1.3
 * 入れるだけでステータス画面のレイアウトが変わります。
 *
 * 本プラグインの利用には下記プラグインを必要とします。
 * DarkPlasma_ParameterText
 */
/*~struct~Element:
 * @param id
 * @desc 属性のID
 * @text 属性ID
 * @type number
 *
 * @param iconIndex
 * @desc 属性を表すアイコン番号
 * @text アイコン番号
 * @type number
 */
(() => {
  'use strict';

  const pluginName = document.currentScript.src.replace(/^.*\/(.*).js$/, function () {
    return arguments[1];
  });

  const pluginParameters = PluginManager.parameters(pluginName);

  const settings = {
    elements: JSON.parse(
      pluginParameters.elements ||
        '[{"id":"2","iconIndex":"64"},{"id":"3","iconIndex":"65"},{"id":"4","iconIndex":"66"},{"id":"5","iconIndex":"67"},{"id":"6","iconIndex":"68"},{"id":"7","iconIndex":"69"}]'
    ).map((e) => {
      return ((parameter) => {
        const parsed = JSON.parse(parameter);
        return {
          id: Number(parsed.id || 0),
          iconIndex: Number(parsed.iconIndex || 0),
        };
      })(e || '{}');
    }),
    states: JSON.parse(pluginParameters.states || '["4", "5", "6", "7", "8", "9", "10", "11", "12"]').map((e) => {
      return Number(e || 0);
    }),
    invalidText: String(pluginParameters.invalidText || '無効'),
  };

  /**
   * 命中率、回避率、会心率、魔法回避率、魔法反射率
   */
  const XPARAM_IDS = [0, 1, 2, 4, 5];

  Scene_Status.prototype.statusParamsWidth = function () {
    return 450;
  };

  const _Scene_Status_create = Scene_Status.prototype.create;
  Scene_Status.prototype.create = function () {
    _Scene_Status_create.call(this);
    this.createRateWindow();
  };

  const _Scene_Status_createStatusWindow = Scene_Status.prototype.createStatusWindow;
  Scene_Status.prototype.createStatusWindow = function () {
    _Scene_Status_createStatusWindow.call(this);
    this._statusWindow.setHandler('shift', this.toggleParamWindow.bind(this));
  };

  Scene_Status.prototype.createRateWindow = function () {
    this._rateWindowLayer = new WindowLayer();
    this._rateWindowLayer.x = (Graphics.width - Graphics.boxWidth) / 2;
    this._rateWindowLayer.y = (Graphics.height - Graphics.boxHeight) / 2;
    this.addChild(this._rateWindowLayer);

    this._rateWindow = new Window_StatusRate(this.rateWindowRect());
    this._rateWindow.hide();
    this._rateWindowLayer.addChild(this._rateWindow);
  };

  Scene_Status.prototype.rateWindowRect = function () {
    return new Rectangle(
      this._statusParamsWindow.x,
      this._statusParamsWindow.y,
      Graphics.boxWidth,
      this._statusParamsWindow.height
    );
  };

  Scene_Status.prototype.toggleParamWindow = function () {
    if (this._statusParamsWindow.visible) {
      this._statusParamsWindow.hide();
      this._statusEquipWindow.hide();
      this._rateWindow.show();
    } else {
      this._rateWindow.hide();
      this._statusParamsWindow.show();
      this._statusEquipWindow.show();
    }
  };

  const _Scene_Status_refreshActor = Scene_Status.prototype.refreshActor;
  Scene_Status.prototype.refreshActor = function () {
    _Scene_Status_refreshActor.call(this);
    this._rateWindow.setActor(this.actor());
  };

  const _Window_StatusParams_drawAllItems = Window_StatusParams.prototype.drawAllItems;
  Window_StatusParams.prototype.drawAllItems = function () {
    _Window_StatusParams_drawAllItems.call(this);
    XPARAM_IDS.forEach((_, index) => this.drawExtraParams(index));
  };

  Window_StatusParams.prototype.drawItem = function (index) {
    const rect = this.itemLineRect(index);
    const paramId = index + 2;
    const name = TextManager.param(paramId);
    const value = this._actor.param(paramId);
    const nameWidth = this.textWidth('魔法防御 ');
    this.changeTextColor(ColorManager.systemColor());
    this.drawText(name, rect.x, rect.y, nameWidth);
    this.resetTextColor();
    this.drawText(value, rect.x + nameWidth, rect.y, this.textWidth('000'), 'right');
  };

  Window_StatusParams.prototype.drawExtraParams = function (index) {
    const x = this.width / 2;
    const y = this.lineHeight() * index;
    const nameWidth = this.textWidth('魔法回避率 ');
    this.changeTextColor(ColorManager.systemColor());
    this.drawText(TextManager.xparam(XPARAM_IDS[index]), x, y, nameWidth);
    this.resetTextColor();
    this.drawText(
      Math.round(this._actor.xparam(XPARAM_IDS[index]) * 100),
      x + nameWidth,
      y,
      this.textWidth('000'),
      'right'
    );
  };

  Window_StatusEquip.prototype.drawItem = function (index) {
    const rect = this.itemLineRect(index);
    const equips = this._actor.equips();
    const item = equips[index];
    this.changeTextColor(ColorManager.systemColor());
    this.drawItemName(item, rect.x, rect.y, rect.width);
  };

  /**
   * シフトキーハンドラを追加するmixin
   * @param {Window_Selectable} windowClass ウィンドウクラスのプロトタイプ
   */
  function Window_ShiftMixIn(windowClass) {
    const _processHandling = windowClass.processHandling;
    windowClass.processHandling = function () {
      _processHandling.call(this);
      if (this.isOpenAndActive()) {
        if (this.isShiftTriggered()) {
          return this.processShift();
        }
      }
    };

    windowClass.isShiftTriggered = function () {
      return Input.isTriggered('shift');
    };

    windowClass.processShift = function () {
      this.playCursorSound();
      this.updateInputData();
      this.callShiftHandler();
    };

    windowClass.callShiftHandler = function () {
      this.callHandler('shift');
    };
  }

  Window_ShiftMixIn(Window_Status.prototype);

  const _Window_Status_refresh = Window_Status.prototype.refresh;
  Window_Status.prototype.refresh = function () {
    _Window_Status_refresh.call(this);
    this.drawManual();
  };

  Window_Status.prototype.drawManual = function () {
    this.contents.fontSize = 20;
    this.changeTextColor(ColorManager.textColor(6));
    this.drawText(
      'Shift: 표시 전환',
      this.innerWidth - this.textWidth('Shift: 표시 전환'),
      this.innerHeight - this.lineHeight()
    );
    this.resetFontSettings();
  };

  class Window_StatusRate extends Window_Selectable {
    initialize(rect) {
      super.initialize(rect);
      this._actor = null;
    }

    /**
     * @param {Game_Actor} actor アクター
     */
    setActor(actor) {
      if (this._actor !== actor) {
        this._actor = actor;
        this.refresh();
      }
    }

    /**
     * 属性6, ステート9, 能力低下5
     * @return {number}
     */
    maxItems() {
      return settings.elements.length + settings.states.length + 5;
    }

    maxRows() {
      return 6;
    }

    maxCols() {
      return Math.ceil(this.maxItems() / this.maxRows());
    }

    itemHeight() {
      return this.lineHeight();
    }

    itemRect(index) {
      const maxRows = this.maxRows();
      const itemWidth = this.itemWidth();
      const itemHeight = this.itemHeight();
      const colSpacing = this.colSpacing();
      const rowSpacing = this.rowSpacing();
      const col = Math.floor(index / maxRows);
      const row = index % maxRows;
      const x = col * itemWidth + colSpacing / 2;
      const y = row * itemHeight + rowSpacing / 2;
      const width = itemWidth - colSpacing;
      const height = itemHeight - rowSpacing;
      return new Rectangle(x, y, width, height);
    }

    drawItem(index) {
      if (this.isElement(index)) {
        this.drawElement(index);
      } else if (this.isState(index)) {
        this.drawState(index);
      } else {
        this.drawDebuff(index);
      }
    }

    isElement(index) {
      return settings.elements.length > index;
    }

    isState(index) {
      return settings.elements.length <= index && settings.elements.length + settings.states.length > index;
    }

    isDebuff(index) {
      return settings.elements.length + settings.states.length <= index;
    }

    elementId(index) {
      return settings.elements[index].id;
    }

    stateId(index) {
      return settings.states[index - settings.elements.length];
    }

    paramId(index) {
      return index - settings.elements.length - settings.states.length + 2;
    }

    drawElement(index) {
      const elementId = this.elementId(index);
      const rate = Math.round((1 - this._actor.elementRate(elementId)) * 100);
      const iconIndex = settings.elements[index].iconIndex;
      this.drawRate(index, iconIndex, rate);
    }

    drawState(index) {
      const stateId = this.stateId(index);
      const rate = this._actor.isStateResist(stateId) ? 100 : Math.round((1 - this._actor.stateRate(stateId)) * 100);
      const iconIndex = $dataStates[stateId].iconIndex;
      this.drawRate(index, iconIndex, rate);
    }

    drawDebuff(index) {
      const paramId = this.paramId(index);
      const rate = Math.round((1 - this._actor.debuffRate(paramId)) * 100);
      const iconIndex = this._actor.buffIconIndex(-2, paramId);
      this.drawRate(index, iconIndex, rate);
    }

    drawRate(index, iconIndex, rate) {
      const rect = this.itemLineRect(index);
      this.drawIcon(iconIndex, rect.x, rect.y + 2);
      this.drawText(
        `${rate === 100 && settings.invalidText ? settings.invalidText : rate}%`,
        rect.x,
        rect.y,
        rect.width,
        'right'
      );
    }
  }
})();
