//=============================================================================
// RPGツクールMZ - LL_EquipQuickChange.js v1.2.0
//-----------------------------------------------------------------------------
// ルルの教会 (Lulu's Church)
// https://nine-yusha.com/
//
// URL below for license details.
// https://nine-yusha.com/plugin/
//=============================================================================

/*:
 * @target MZ
 * @plugindesc 「今すぐ装備」コマンドを実装します。
 * @author ルルの教会
 * @url https://nine-yusha.com/plugin-quickequip/
 *
 * @help LL_EquipQuickChange.js
 *
 * 対象の装備品を誰に装備するか選択するウィンドウを表示します。
 * 装備品入手時に、いわゆる「今すぐ装備する」コマンドを実装できます。
 * プラグインコマンドで実行してください。
 *
 * プラグインコマンド:
 *   武器装備選択: 対象の武器を選択し、装備切替画面を表示します。
 *   防具装備選択: 対象の防具を選択し、装備切替画面を表示します。
 *   ※対象の装備品を所持していない場合、プラグインコマンドは無視されます。
 *
 * 利用規約:
 *   ・著作権表記は必要ございません。
 *   ・利用するにあたり報告の必要は特にございません。
 *   ・商用・非商用問いません。
 *   ・R18作品にも使用制限はありません。
 *   ・ゲームに合わせて自由に改変していただいて問題ございません。
 *   ・プラグイン素材としての再配布（改変後含む）は禁止させていただきます。
 *
 * 作者: ルルの教会
 * 作成日: 2022/8/18
 *
 * @param shopSettings
 * @text ショップ連動設定
 * @desc ※この項目は使用しません
 *
 * @param shopEnabled
 * @text 装備品購入時に自動表示
 * @desc ショップで装備品を購入した時に装備切替画面を表示します。
 * @default true
 * @type boolean
 * @parent shopSettings
 *
 * @param shopDisabledswitchId
 * @text 購入時無効化スイッチID
 * @desc ショップで装備品を購入した時、
 * このスイッチがONの時は装備切替画面を一時的に表示しません。
 * @type switch
 * @parent shopSettings
 *
 * @param shopMultipleEquip
 * @text 複数購入時に連続選択
 * @desc ショップで装備品を複数購入した場合に、
 * 購入数分選択画面を繰り返し表示します。
 * @default false
 * @type boolean
 * @parent shopSettings
 *
 * @param iniInfoText
 * @text 質問メッセージ
 * @desc 「質問メッセージ」の文言設定です。
 * @default 装備しますか？
 * @type string
 *
 * @param iniEquipNgText
 * @text 装備不可メッセージ
 * @desc 「装備不可」の文言設定です。
 * @default 装備できません。
 * @type string
 *
 * @param iniCancelText
 * @text キャンセルコマンド名
 * @desc 「キャンセル」コマンドの文言設定です。
 * @default 装備しない
 * @type string
 *
 * @command changeWeapon
 * @text 武器装備選択
 * @desc 対象の武器を選択し、装備切替画面を表示します。
 * 対象の装備品を所持していない場合、このコマンドは無視されます。
 *
 * @arg weaponId
 * @text 武器ID
 * @desc 変更対象の武器を選択します。
 * @type weapon
 *
 * @arg infoText
 * @text 質問メッセージ
 * @desc 「質問文」の文言設定です。
 * @default 装備しますか？
 * @type string
 *
 * @arg gainCount
 * @text 獲得数
 * @desc この回数分選択画面を繰り返し表示します。
 * パーティ人数を上回った場合、パーティ人数が上限となります。
 * @default 1
 * @min 1
 * @max 99
 * @type number
 *
 * @command changeArmor
 * @text 防具装備選択
 * @desc 対象の防具を選択し、装備切替画面を表示します。
 * 対象の装備品を所持していない場合、このコマンドは無視されます。
 *
 * @arg armorId
 * @text 防具ID
 * @desc 変更対象の防具を選択します。
 * @type armor
 *
 * @arg infoText
 * @text 質問メッセージ
 * @desc 「質問文」の文言設定です。
 * @default 装備しますか？
 * @type string
 *
 * @arg gainCount
 * @text 獲得数
 * @desc この回数分選択画面を繰り返し表示します。
 * パーティ人数を上回った場合、パーティ人数が上限となります。
 * @default 1
 * @min 1
 * @max 99
 * @type number
 */

(() => {
    "use strict";
    const pluginName = "LL_EquipQuickChange";

    const parameters = PluginManager.parameters(pluginName);
    const shopEnabled = eval(parameters["shopEnabled"] || "true");
    const shopDisabledswitchId = Number(parameters["shopDisabledswitchId"] || 0);
    const shopMultipleEquip = eval(parameters["shopMultipleEquip"] || "false");
    const iniInfoText = String(parameters["iniInfoText"] || "装備しますか？");
    const iniEquipNgText = String(parameters["iniEquipNgText"] || "装備できません。");
    const iniCancelText = String(parameters["iniCancelText"] || "装備しない");


    // 独自変数定義
	let infoText = "";
    let exGoods = null;
    let exPurchaseOnly = null;
    let exBuyWindowLastIndex = 0;
    let exBuyCount = 1;

    PluginManager.registerCommand(pluginName, "changeWeapon", args => {
        const weaponId = Number(args.weaponId || null);
        if (weaponId) {
            // 対象装備品を所持しているか？
            if ($gameParty.hasItem($dataWeapons[weaponId], true)) {
                // 武器情報を取得
                ExEquipTargetItem.set($dataWeapons[weaponId]);
                // 文言をセット
                infoText = String(args.infoText || "");
                // ショップ判定オフ
                exGoods = null;
                exPurchaseOnly = null;
                exBuyWindowLastIndex = 0;
                exBuyCount = Number(args.gainCount || 1);
                // 装備選択画面へ
                SceneManager.push(Scene_EquipQuickChange);
            } else {
                console.log(pluginName + ": 対象の装備品を所持していなかったため、コマンドがスキップされました");
            }
        }
    });

    PluginManager.registerCommand(pluginName, "changeArmor", args => {
        const armorId = Number(args.armorId || null);
        if (armorId) {
            // 対象装備品を所持しているか？
            if ($gameParty.hasItem($dataArmors[armorId], true)) {
                // 防具情報を取得
                ExEquipTargetItem.set($dataArmors[armorId]);
                // 文言をセット
                infoText = String(args.infoText || "");
                // ショップ判定オフ
                exGoods = null;
                exPurchaseOnly = null;
                exBuyWindowLastIndex = 0;
                exBuyCount = Number(args.gainCount || 1);
                // 装備選択画面へ
                SceneManager.push(Scene_EquipQuickChange);
            } else {
                console.log(pluginName + ": 対象の装備品を所持していなかったため、コマンドがスキップされました");
            }
        }
    });


    //-----------------------------------------------------------------------------
	// ExEquipTargetItem
	//

    class ExEquipTargetItem {

        constructor() {
            this.item = null;
        }

        static get() {
            return this.item;
        }

        static set(item) {
            this.item = item;
        }

        static getSlotId() {
            return this.item.etypeId - 1;
        }

        static getEtypeId() {
            return this.item.etypeId;
        }

    }

    //-----------------------------------------------------------------------------
    // Scene_EquipQuickChange
    //
    // 対象の装備品と変更する独自のシーンを追加定義します。

    function Scene_EquipQuickChange() {
        this.initialize(...arguments);
    }

    Scene_EquipQuickChange.prototype = Object.create(Scene_MenuBase.prototype);
    Scene_EquipQuickChange.prototype.constructor = Scene_EquipQuickChange;

    Scene_EquipQuickChange.prototype.initialize = function() {
        Scene_MenuBase.prototype.initialize.call(this);
        this._equipCount = $gameParty.size() < exBuyCount ? $gameParty.size() : exBuyCount;
    };

    Scene_EquipQuickChange.prototype.start = function() {
        Scene_MenuBase.prototype.start.call(this);
        this._statusWindow.refresh();
    };

    Scene_EquipQuickChange.prototype.helpAreaHeight = function() {
        return this.calcWindowHeight(2, false);
    };

    Scene_EquipQuickChange.prototype.create = function() {
        Scene_MenuBase.prototype.create.call(this);
        this.createHelpWindow();
        this.createInfoWindow();
        this.createStatusWindow();
        this.createCommandWindow();
        this._helpWindow.setText(this.helpWindowText());
        this.infoWindowSetText();
    };

    Scene_EquipQuickChange.prototype.createInfoWindow = function() {
        const rect = this.infoWindowRect();
        this._infoWindow = new Window_Help(rect);
        this.addWindow(this._infoWindow);
    };

    Scene_EquipQuickChange.prototype.infoWindowRect = function() {
        const wx = this.isRightInputMode() ? this.statusWindowRect().width : 0;
        const wy = this.mainAreaTop();
        const ww = Graphics.boxWidth - this.statusWindowRect().width;
        const wh = this.calcWindowHeight(2, false);
        return new Rectangle(wx, wy, ww, wh);
    };

    Scene_EquipQuickChange.prototype.createStatusWindow = function() {
        const rect = this.statusWindowRect();
        this._statusWindow = new Window_EquipStatusQuickChange(rect);
        this.addWindow(this._statusWindow);
    };

    Scene_EquipQuickChange.prototype.statusWindowRect = function() {
        const ww = this.statusWidth();
        const wh = this.mainAreaHeight();
        const wx = this.isRightInputMode() ? 0 : Graphics.boxWidth - ww;
        const wy = this.mainAreaTop();
        return new Rectangle(wx, wy, ww, wh);
    };

    Scene_EquipQuickChange.prototype.createCommandWindow = function() {
        const rect = this.commandWindowRect();
        const commandWindow = new Window_EquipQuickActor(rect);
        commandWindow.setHandler("ok", this.checkPopScene.bind(this));
        commandWindow.setHandler("cancel", this.popScene.bind(this));
        commandWindow.setStatusWindow(this._statusWindow);
        this.addWindow(commandWindow);

        this._commandWindow = commandWindow;
    };

    Scene_EquipQuickChange.prototype.commandWindowRect = function() {
        const ww = Graphics.boxWidth - this.statusWindowRect().width;
        const wh = this.mainAreaHeight() - this._helpWindow.height;
        const wx = this.isRightInputMode() ? Graphics.boxWidth - ww : 0;
        const wy = this.mainAreaTop() + this._helpWindow.height;
        return new Rectangle(wx, wy, ww, wh);
    };

    Scene_EquipQuickChange.prototype.helpWindowText = function() {
        const targetItem = ExEquipTargetItem.get();
        return targetItem.description;
    };

    Scene_EquipQuickChange.prototype.infoWindowSetText = function() {
        const targetItem = ExEquipTargetItem.get();
        const width = this._infoWindow.innerWidth;
        const y2 = this._infoWindow.lineHeight();

        const numberWidth = this._infoWindow.textWidth(":00");
        const equipCount = this._equipCount;

        this._infoWindow.drawItemName(targetItem, 0, 0, width - numberWidth);
        this._infoWindow.drawText(":", width - numberWidth, 0, this._infoWindow.textWidth(":"), "right");
        this._infoWindow.drawText(equipCount, width - numberWidth + this._infoWindow.textWidth(":"), 0, this._infoWindow.textWidth("00"), "right");
        this._infoWindow.drawText(infoText, 0, y2, width);
    };

    Scene_EquipQuickChange.prototype.statusWidth = function() {
        return 312;
    };

    Scene_EquipQuickChange.prototype.popScene = function() {
        SceneManager.pop();
        // ショップ判定
        if (exGoods !== null) {
            SceneManager.prepareNextScene(exGoods, exPurchaseOnly);
            SceneManager._nextScene.buyWindowFocusOn();
        }
    };

    Scene_EquipQuickChange.prototype.checkPopScene = function() {
        // 装備回数が0になったら終了
        this._equipCount -= 1;
        if (this._equipCount > 0) {
            this._commandWindow.activate();
            this._commandWindow.refresh();
            this._statusWindow.refresh();
            this._infoWindow.refresh();
            this.infoWindowSetText();
        } else {
            this.popScene();
        }
    };


    //-----------------------------------------------------------------------------
    // Window_EquipStatusQuickChange
    //
    // The window for displaying parameter changes on the equipment screen.

    function Window_EquipStatusQuickChange() {
        this.initialize(...arguments);
    }

    Window_EquipStatusQuickChange.prototype = Object.create(Window_EquipStatus.prototype);
    Window_EquipStatusQuickChange.prototype.constructor = Window_EquipStatusQuickChange;

    Window_EquipStatusQuickChange.prototype.initialize = function(rect) {
        Window_EquipStatus.prototype.initialize.call(this, rect);
    };

    Window_EquipStatusQuickChange.prototype.refreshDisabled = function() {
        this.contents.clear();
        if (this._actor) {
            const nameRect = this.itemLineRect(0);
            this.drawActorName(this._actor, nameRect.x, 0, nameRect.width);
            this.drawActorFace(this._actor, nameRect.x, nameRect.height);
            this.drawAllParamsDisabled();
        }
    };

    Window_EquipStatusQuickChange.prototype.drawAllParamsDisabled = function() {
        const x = this.itemPadding();
        const y = this.paramY(0);
        const width = this.innerWidth - this.itemPadding() * 2;
        this.changeTextColor(ColorManager.powerDownColor());
        // 装備不可
        this.drawText(iniEquipNgText, x, y, width);
    };


    //-----------------------------------------------------------------------------
    // Window_EquipQuickActor
    //
    // 装備を変更する対象アクターを選択するウィンドウです。

    function Window_EquipQuickActor() {
        this.initialize(...arguments);
    }

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

    Window_EquipQuickActor.prototype.initialize = function(rect) {
        Window_Command.prototype.initialize.call(this, rect);
    };

    Window_EquipQuickActor.prototype.makeCommandList = function() {
        this.addPartyMembers();
    };

    Window_EquipQuickActor.prototype.addPartyMembers = function() {
        const _this = this;
        const targetItem = ExEquipTargetItem.get();
        const slotId = ExEquipTargetItem.getSlotId();
        this.addCommand(iniCancelText, "cancel");
        $gameParty.members().forEach(function(item) {
            if (item.canEquip(targetItem) && item.isEquipChangeOk(slotId)) {
                _this.addCommand(item._name, item._actorId, true);
            } else {
                _this.addCommand(item._name, item._actorId, false);
            }
        });
    };

    Window_EquipQuickActor.prototype.drawItem = function(index) {
        const actorName = this.commandName(index);
        const equippedName = this.equippedName(index);
        const rect = this.itemLineRect(index);
        const equippedWidth = this.equippedWidth();
        const actorNameWidth = rect.width - equippedWidth;
        this.resetTextColor();
        this.changePaintOpacity(this.isCommandEnabled(index));
        this.drawText(actorName, rect.x, rect.y, actorNameWidth, "left");
        this.drawItemName(equippedName, rect.x + actorNameWidth, rect.y, equippedWidth);
    };

    Window_EquipQuickActor.prototype.equippedWidth = function() {
        return 240;
    };

    Window_EquipQuickActor.prototype.equippedName = function(index) {
        const symbol = this.commandSymbol(index);
        const value = this.getEquippedItem(symbol);
        return value ? value : null;
    };

    Window_EquipQuickActor.prototype.getEquippedItem = function(symbol) {
        const actor = $gameActors.actor(symbol);
        const slotId = ExEquipTargetItem.getSlotId();
        return actor ? actor.equips()[slotId] : null;
    };

    Window_EquipQuickActor.prototype.setStatusWindow = function(statusWindow) {
        this._statusWindow = statusWindow;
        this.refreshActor();
    };

    Window_EquipQuickActor.prototype.cursorUp = function(wrap) {
        Window_Selectable.prototype.cursorUp.call(this, wrap);
        this.refreshActor();
    };

    Window_EquipQuickActor.prototype.cursorDown = function(wrap) {
        Window_Selectable.prototype.cursorDown.call(this, wrap);
        this.refreshActor();
    };

    Window_EquipQuickActor.prototype.onTouchSelect = function(trigger) {
        Window_Selectable.prototype.onTouchSelect.call(this, trigger);
        this.refreshActor();
    };

    Window_EquipQuickActor.prototype.refreshActor = function() {
        const index = this.index();
        const symbol = this.commandSymbol(index);
        if (this._statusWindow) {
            // キャンセルの場合
            if (symbol === "cancel") {
                this._statusWindow.contents.clear();
                return;
            }
            const actor = $gameActors.actor(symbol);
            const targetItem = ExEquipTargetItem.get();
            const slotId = ExEquipTargetItem.getSlotId();
            this._statusWindow.setActor(actor);
            // 装備後のパラメータを表示
            if (actor.canEquip(targetItem) && actor.isEquipChangeOk(slotId)) {
                const actorTmp = JsonEx.makeDeepCopy(actor);
                actorTmp.forceChangeEquip(slotId, targetItem);
                this._statusWindow.setTempActor(actorTmp);
            } else {
                this._statusWindow.refreshDisabled();
            }
        }
    };

    Window_EquipQuickActor.prototype.processOk = function() {
        if (this.isCurrentItemEnabled()) {
            this.playOkSound();
            this.equipChange();
            this.deactivate();
            this.callOkHandler();
        } else {
            this.playBuzzerSound();
        }
    };

    Window_EquipQuickActor.prototype.equipChange = function() {
        const index = this.index();
        const symbol = this.commandSymbol(index);
        // キャンセルの場合
        if (symbol === "cancel") return;
        const targetItem = ExEquipTargetItem.get();
        const etypeId = ExEquipTargetItem.getEtypeId();
        $gameActors.actor(symbol).changeEquipById(etypeId, targetItem.id);
    };

    Window_EquipQuickActor.prototype.playOkSound = function() {
        const index = this.index();
        const symbol = this.commandSymbol(index);
        // 決定音 or 装備音
        symbol === "cancel" ? SoundManager.playOk() : SoundManager.playEquip();
    };


    //-----------------------------------------------------------------------------
    // Scene_Shop を拡張
    //

    const _Scene_Shop_initialize = Scene_Shop.prototype.initialize;
    Scene_Shop.prototype.initialize = function() {
        _Scene_Shop_initialize.apply(this, arguments);
        this._buyWindowFocus = false;
    };

    const _Scene_Shop_create = Scene_Shop.prototype.create;
    Scene_Shop.prototype.create = function() {
        _Scene_Shop_create.apply(this, arguments);
        this.buyWindowFocus();
    };

    Scene_Shop.prototype.buyWindowFocusOn = function() {
        this._buyWindowFocus = true;
    };

    Scene_Shop.prototype.buyWindowFocus = function() {
        if (!this._buyWindowFocus) return;
        this._commandWindow.deactivate();
        this._buyWindow.setMoney(this.money());
        this._buyWindow.show();
        this._buyWindow.activate();
        this._statusWindow.show();
        // カーソルを合わせる
        if (exBuyWindowLastIndex > 0) {
            this._buyWindow.forceSelect(exBuyWindowLastIndex);
        }
    };

    const _Scene_Shop_onNumberOk = Scene_Shop.prototype.onNumberOk;
    Scene_Shop.prototype.onNumberOk = function() {
        // 購入かつ装備品の場合
        if (this._commandWindow.currentSymbol() === "buy" && this._item.etypeId) {
            // ショップ連動設定が有効の場合
            if (shopEnabled && !$gameSwitches.value(shopDisabledswitchId)) {
                this.gotoEquipQuickChange();
                return;
            }
        }
        _Scene_Shop_onNumberOk.apply(this, arguments);
    }

    Scene_Shop.prototype.gotoEquipQuickChange = function() {
        SoundManager.playShop();
        this.doBuy(this._numberWindow.number());
        // 装備情報を取得
        const targetItem = this._item;
        ExEquipTargetItem.set(targetItem);
        // 文言をセット
        infoText = iniInfoText;
        // ショップ情報を保持
        exGoods = this._goods;
        exPurchaseOnly = this._purchaseOnly;
        exBuyWindowLastIndex = this._buyWindow.index();
        exBuyCount = shopMultipleEquip ? this._numberWindow.number() : 1;
        // 装備選択画面へ
        SceneManager.push(Scene_EquipQuickChange);
    }
})();
