//=============================================================================
// MPP_ChoiceEX.js
//=============================================================================
// Copyright (c) 2015-2019 Mokusei Penguin
// Released under the MIT license
// http://opensource.org/licenses/mit-license.php
//=============================================================================

/*:
 * @plugindesc 【ver.3.11】選択肢の機能拡張
 * @author 木星ペンギン
 *
 * @help ※[]内は未設定でも動作します。
 * プラグインコマンド:
 *   ChoicePos x y[ row]    # 選択肢の位置(x,y)と行数(row)指定
 *   ChoiceVariableId n     # 選択肢のデフォルト位置を変数n番にする
 *   ChoiceRect x y width height
 *                          # 選択肢の座標とサイズを指定
 *   ChoiceUnderMessage     # 選択肢をメッセージの下に表示
 * 
 * ※ プラグインコマンドにて指定する値には変数が使用できます。
 *    v[n] と記述することでn番の変数の値を参照します。
 * 
 * 注釈:
 *   選択肢ヘルプ             # 各項目の下に設定することでヘルプを表示させる
 *
 * 選択肢テキスト:
 *   if(条件)                # 条件が偽になると項目が表示されなくなる
 *   en(条件)                # 条件が偽になると項目が選択不可
 *
 * ================================================================
 * ▼ 使い方
 * --------------------------------
 *  〇 選択肢を増やす
 *   イベントコマンド『選択肢の表示』を続けて配置すると
 *   一つの選択肢にまとめられます。
 *   まとめたくない場合は、間に注釈などを入れることで
 *   通常通り分けることができます。
 * 
 *   『デフォルト』の処理は、なし以外を設定したものが適用されます。
 *   『デフォルト』の処理が複数ある場合、
 *   後に設定された選択肢のものが適用されます。
 * 
 *   『キャンセル』の処理は、禁止以外を設定したものが適用されます。
 *   『キャンセル』の処理が複数ある場合、
 *   後に設定された選択肢のものが適用されます。
 * 
 *  『背景』と『ウィンドウ位置』は後の選択肢のものが適用されます。
 * 
 * 
 * ================================================================
 * ▼ プラグインコマンド 詳細
 * --------------------------------
 *  〇 ChoicePos x y[ row]
 *      x   : 選択肢ウィンドウのX座標
 *      y   : 選択肢ウィンドウのY座標
 *      row : 選択肢ウィンドウの行数。未設定の場合はすべて表示
 *   
 *   次に表示する選択肢の位置(x,y)と行数(row)指定します。
 *   
 * --------------------------------
 *  〇 ChoiceVariableId n
 *      n : 変数番号
 *   
 *   次に表示する選択肢のデフォルト位置を変数の値にします。
 *   さらに現在のカーソル位置を変数に入れます。
 *   
 *   カーソル位置は最初の選択肢が上から0～5、次の選択肢は10～15と、
 *   選択肢毎に+10されます。
 * 
 *   変数に入った値の項目が表示されない場合、なしと同じ処理をします。
 * 
 * --------------------------------
 *  〇 ChoiceRect x y width height
 *      x      : X座標
 *      y      : Y座標
 *      width  : 幅
 *      height : 高さ
 *   
 *   次に表示する選択肢の座標とサイズを指定します。
 *   
 *   各項目、未設定もしくは-1を指定した場合、通常の値が適用されます。
 *   
 * --------------------------------
 *  〇 ChoiceUnderMessage
 *  
 *   次に表示する選択肢をメッセージウィンドウ内に表示させます。
 *   
 *   この機能は[文章の表示]と併用しなければ機能しません。
 *   [文章の表示]の前に実行してください。
 *   
 *   選択肢ウィンドウの[背景]は設定したものが適用されます。
 * 
 * 
 * ================================================================
 * ▼ 選択肢テキスト 詳細
 * --------------------------------
 *  〇 項目が表示される条件の設定
 *   選択肢の文章中に
 *     if(条件)
 *   と入れ、その条件が偽になると項目が表示されなくなります。
 *   
 *   『デフォルト』の項目が表示されない場合の動作は、
 *   プラグインパラメータの[Disabled Index]にて設定できます。
 *   
 *   『キャンセル』の項目が表示されない場合、禁止と同じ処理をします。
 *   
 *   条件内では s でスイッチ、v で変数を参照できます。
 *   
 *     例：if(s[1]) とした場合
 *          => スイッチ１番がONで表示、OFFで非表示。
 *        if(!s[2]) とした場合
 *          => スイッチ２番がOFFで表示、ONで非表示。
 *        if(v[5]>0) とした場合
 *          => 変数５番が0より大きければ表示、0以下で非表示。
 *     
 *     変数で使える不等号
 *       === : 等しい
 *       !== : 等しくない
 *       <   : より小さい
 *       <=  : より小さいまたは等しい
 *       >   : より大きい
 *       >=  : より大きいまたは等しい
 *     
 *     条件式はeval関数で処理されているため、他演算子も使用できます。
 * 
 * --------------------------------
 *  〇 項目を半透明で表示する条件の設定
 *   選択肢の文章中に
 *     en(条件)
 *   と入れ、その条件が偽になると項目が半透明で表示されます。
 *   半透明となった項目は選択できなくなります。
 * 
 *   条件は上の『項目が表示される条件の設定』と同じです。
 * 
 *   『キャンセル』の項目が半透明の場合、ブザーが鳴ります。
 * 
 *
 * ================================================================
 * ▼ プラグインパラメータ 詳細
 * --------------------------------
 *  〇 Disabled Index
 *  
 *   [デフォルト]となる項目がif(条件)により非表示となった場合、
 *   デフォルト位置をどこにするかを設定します。
 *   
 *     none : [なし]と同じ
 *     top  : 先頭の項目
 *  
 * --------------------------------
 *  〇 Plugin Commands / Event Comment
 *  
 *   プラグインコマンドや注釈で使用するコマンドは、
 *   プラグインパラメータから変更できます。
 *  
 *   コマンドを短くしたり日本語にしたりなどして、
 *   自分が使いやすいようにしてください。
 *  
 *   プラグインコマンドのみ、変更後もデフォルトのコマンドでも動作します。
 * 
 * 
 * ================================================================
 * ▼ その他
 * --------------------------------
 *  〇 プラグインコマンドの実行タイミング
 *   プラグインコマンドを使用する場合、[選択肢の表示]の前に実行するのが
 *   好ましいです。
 *   ただし、メッセージウィンドウを表示したまま選択肢の処理を実行したい場合、
 *   [文章の表示]より前にプラグインコマンドを実行してください。
 * 
 * --------------------------------
 *  〇 ヘルプメッセージの表示
 *   各選択肢項目の下に注釈で以下の文字列を入れると、
 *   続きの文章をヘルプメッセージとしてカーソルを合わせたときに
 *   標示させることができます。
 *  
 *     選択肢ヘルプ
 * 
 *   ※注意点
 *    ヘルプメッセージは[文章の表示]と同じ機能を使っているため、
 *    制御文字が使用できます。
 *    ただし、\!と\^は使用できません。
 * 
 * ================================
 * 制作 : 木星ペンギン
 * URL : http://woodpenguin.blog.fc2.com/
 *
 * @param maxPageRow
 * @type number
 * @desc 1ページに表示される行数
 * @default 6
 *
 * @param Disabled Index
 * @type select
 * @option none
 * @option top
 * @desc [デフォルト]となる選択肢が表示されない場合のデフォルト位置
 * @default none
 *
 *
 * @param === Command ===
 * 
 * @param Plugin Commands
 * @type struct<Plugin>
 * @desc プラグインコマンド名
 * @default {"ChoicePos":"ChoicePos","ChoiceVariableId":"ChoiceVariableId","ChoiceRect":"ChoiceRect","ChoiceUnderMessage":"ChoiceUnderMessage"}
 * @parent === Command ===
 * 
 * @param Event Comment
 * @type struct<EventComment>
 * @desc イベントの注釈で使うコマンド名
 * @default {"ChoiceHelp":"選択肢ヘルプ"}
 * @parent === Command ===
 * 
 */

/*~struct~Plugin:
 * @param ChoicePos
 * @desc 選択肢の位置(x,y)と行数(row)指定
 * @default ChoicePos
 *
 * @param ChoiceVariableId
 * @desc 選択肢のデフォルト位置を変数n番にする
 * @default ChoiceVariableId
 *
 * @param ChoiceRect
 * @desc 選択肢の座標とサイズ(x,y,width,height)指定
 * @default ChoiceRect
 *
 * @param ChoiceUnderMessage
 * @desc 選択肢をメッセージの下に表示
 * @default ChoiceUnderMessage
 *
 */

/*~struct~EventComment:
 * @param ChoiceHelp
 * @desc 各項目の下に設定することでヘルプを表示させる
 * @default 選択肢ヘルプ
 */

(function() {

const MPPlugin = {};

{
    
    let parameters = PluginManager.parameters('MPP_ChoiceEX');
    
    MPPlugin.maxPageRow = Number(parameters['maxPageRow']);
    MPPlugin.DisabledIndex = parameters['Disabled Index'];
    
    MPPlugin.PluginCommands = JSON.parse(parameters['Plugin Commands']);
    MPPlugin.EventComment = JSON.parse(parameters['Event Comment']);

}

const Alias = {};

//-----------------------------------------------------------------------------
// Game_Message

//15
Alias.GaMe_clear = Game_Message.prototype.clear;
Game_Message.prototype.clear = function() {
    Alias.GaMe_clear.apply(this, arguments);
    this._choiceEnables = [];
    this._choiceResults = [];
    this._helpTexts = [];
    this._choiceX = -1;
    this._choiceY = -1;
    this._choiceWidth = -1;
    this._choiceHeight = -1;
    this._choiceMaxRow = MPPlugin.maxPageRow;
    this._choiceVariableId = 0;
    this.choiceUnderMes = false;
};

Game_Message.prototype.setChoiceEnables = function(enables) {
    this._choiceEnables = enables;
};

Game_Message.prototype.choiceEnables = function() {
    return this._choiceEnables;
};

Game_Message.prototype.setChoiceResults = function(results) {
    this._choiceResults = results;
};

Game_Message.prototype.setChoiceHelpTexts = function(texts) {
    this._helpTexts = texts;
};

Game_Message.prototype.isHelp = function() {
    return this._helpTexts.length > 0;
};

Game_Message.prototype.setChoicePos = function(x, y, row) {
    this._choiceX = x;
    this._choiceY = y;
    this._choiceWidth = -1;
    this._choiceHeight = -1;
    this._choiceMaxRow = row;
};

Game_Message.prototype.setChoiceRect = function(x, y, width, height) {
    this._choiceX = x;
    this._choiceY = y;
    this._choiceWidth = width;
    this._choiceHeight = height;
};

Game_Message.prototype.setChoiceVariableId = function(id) {
    this._choiceVariableId = id;
};

Game_Message.prototype.shiftLine = function(height) {
    this._choiceY += height;
    this._choiceHeight -= height;
};


//-----------------------------------------------------------------------------
// Game_Interpreter

//336
Game_Interpreter.prototype.setupChoices = function(params) {
    var data = {
        choices: [],
        enables: [],
        results: [],
        helpTexts: [],
        cancelType: -1,
        defaultType: -1,
        positionType: 0,
        background: 0
    };
    data = this.addChoices(params, this._index, data, 0);
    if (data.choices.length > 0) {
        var helpTexts = [];
        if (data.helpTexts.length > 0) {
            helpTexts = data.results.map( i => data.helpTexts[i] );
        }
        var cancelType = -1;
        if (data.cancelType.mod(10) === 8 || data.results.contains(data.cancelType)) {
            data.results.push(data.cancelType);
            cancelType = data.choices.length;
        }
        var index = data.defaultType;
        if ($gameMessage._choiceVariableId > 0) {
            index = $gameVariables.value($gameMessage._choiceVariableId);
        }
        var defaultType = data.results.indexOf(index);
        if (index >= 0 && defaultType < 0 && MPPlugin.DisabledIndex === "top")  {
            defaultType = 0;
        }
        $gameMessage.setChoices(data.choices, defaultType, cancelType);
        $gameMessage.setChoiceEnables(data.enables);
        $gameMessage.setChoiceResults(data.results);
        $gameMessage.setChoiceHelpTexts(helpTexts);
        $gameMessage.setChoiceBackground(data.background);
        $gameMessage.setChoicePositionType(data.positionType);
        $gameMessage.setChoiceCallback( n => this._branch[this._indent] = data.results[n] );
    } else {
        this._branch[this._indent] = -1;
    }
};

Game_Interpreter.prototype.addChoices = function(params, i, data, d) {
    var regIf = /\s*if\((.+?)\)/;
    var regEn = /\s*en\((.+?)\)/;
    for (var n = 0; n < params[0].length; n++) {
        var str = params[0][n];
        if (regIf.test(str)) {
            str = str.replace(regIf, '');
            if (RegExp.$1 && !this.evalChoice(RegExp.$1)) continue;
        }
        var enable = true;
        if (regEn.test(str)) {
            str = str.replace(regEn, '');
            enable = this.evalChoice(RegExp.$1);
        }
        data.choices.push(str);
        data.enables.push(enable);
        data.results.push(n + d);
    }
    var cancelType = params[1];
    if (cancelType !== -1) {
        data.cancelType = cancelType + d;
    }
    var defaultType = params.length > 2 ? params[2] : 0;
    if (defaultType >= 0) {
        data.defaultType = defaultType + d;
    }
    data.positionType = params.length > 3 ? params[3] : 2;
    data.background = params.length > 4 ? params[4] : 0;
    var command;
    for (;;) {
        i++;
        command = this._list[i];
        if (!command) break;
        if (command.indent === this._indent) {
            if (command.code === 402) {
                this.getHelpText(command.parameters[0] + d, i + 1, data);
            } else if (command.code === 404) {
                break;
            }
        }
    }
    command = this._list[i + 1];
    if (command && command.code === 102) {
        this.addChoices(command.parameters, i + 1, data, d + 10);
    }
    return data;
};

Game_Interpreter.prototype.getHelpText = function(c, i, data) {
    var command = MPPlugin.EventComment.ChoiceHelp || '選択肢ヘルプ';
    if (this._list[i].code === 108 && this._list[i].parameters[0] === command) {
        var texts = [];
        while (this._list[i + 1].code === 408) {
            i++;
            texts.push(this._list[i].parameters[0]);
        }
        data.helpTexts[c] = texts;
    }
};

Game_Interpreter.prototype.evalChoice = function(formula) {
    try {
        var s = $gameSwitches._data;
        var formula2 = formula.replace(/v\[(\d+)\]/g,
            (match, p1) => $gameVariables.value(parseInt(p1)) );
        return !!eval(formula2);
    } catch (e) {
        alert("条件エラー \n\n " + formula);
        return true;
    }
};

//362
Game_Interpreter.prototype.command403 = function() {
    if (this._branch[this._indent] !== -2) {
        this.skipBranch();
    }
    return true;
};

Game_Interpreter.prototype.command404 = function() {
    if (this.nextEventCode() === 102) {
        this._branch[this._indent] -= 10;
        this._index++;
    }
    return true;
};

//1739
Alias.GaIn_pluginCommand = Game_Interpreter.prototype.pluginCommand;
Game_Interpreter.prototype.pluginCommand = function(command, args) {
    Alias.GaIn_pluginCommand.apply(this, arguments);
    var args2 = this.mppPluginCommandArgs(args);
    switch (command) {
        case MPPlugin.PluginCommands.ChoicePos:
        case 'ChoicePos':
            var x = args2[0];
            var y = args2[1];
            var row = args2[2] || 99;
            $gameMessage.setChoicePos(x, y, row);
            break;
        case MPPlugin.PluginCommands.ChoiceVariableId:
        case 'ChoiceVariableId':
            $gameMessage.setChoiceVariableId(args2[0]);
            break;
        case MPPlugin.PluginCommands.ChoiceRect:
        case 'ChoiceRect':
            var x = (args2[0] === undefined ? -1 : args2[0]);
            var y = (args2[1] === undefined ? -1 : args2[1]);
            var width = (args2[2] === undefined ? -1 : args2[2]);
            var height = (args2[3] === undefined ? -1 : args2[3]);
            $gameMessage.setChoiceRect(x, y, width, height);
            break;
        case MPPlugin.PluginCommands.ChoiceUnderMessage:
        case 'ChoiceUnderMessage':
            $gameMessage.choiceUnderMes = true;
            break;
    }
    return true;
};

Game_Interpreter.prototype.mppPluginCommandArgs = function(args) {
    var v = $gameVariables._data;
    return args.map(function(arg) {
        try {
            return eval(arg) || 0;
        } catch (e) {
            return arg;
        }
    });
};

//-----------------------------------------------------------------------------
// Window

Window.prototype.isClearWindowRect = function() {
    return true;
};

//-----------------------------------------------------------------------------
// WindowLayer

//7100
Alias.WiLa__canvasClearWindowRect = WindowLayer.prototype._canvasClearWindowRect;
WindowLayer.prototype._canvasClearWindowRect = function(renderSession, window) {
    if (window.isClearWindowRect())
        Alias.WiLa__canvasClearWindowRect.apply(this, arguments);
};

//7162
Alias.WiLa__maskWindow = WindowLayer.prototype._maskWindow;
WindowLayer.prototype._maskWindow = function(window, shift) {
    Alias.WiLa__maskWindow.apply(this, arguments);
    if (!window.isClearWindowRect()) {
        var rect = this._windowRect;
        rect.x = 0;
        rect.y = 0;
        rect.width = 0;
        rect.height = 0;
    }
};

//-----------------------------------------------------------------------------
// Window_ChoiceList

Window_ChoiceList.prototype.isClearWindowRect = function() {
    return !this._underMessage;
};

if (Window_ChoiceList.prototype.hasOwnProperty('close')) {
    Alias.WiChLi_close = Window_ChoiceList.prototype.close
}
Window_ChoiceList.prototype.close = function() {
    if ($gameMessage.isHelp()) this._messageWindow.onShowFast();
    var _super = Alias.WiChLi_close || Window_Command.prototype.close;
    _super.apply(this, arguments);
};

if (Window_ChoiceList.prototype.hasOwnProperty('select')) {
    Alias.WiChli_select = Window_ChoiceList.prototype.select;
}
Window_ChoiceList.prototype.select = function(index) {
    var variableId = $gameMessage._choiceVariableId;
    if (index !== this.index() && variableId > 0) {
        var results = $gameMessage._choiceResults;
        $gameVariables.setValue(variableId, results[index]);
    }
    var _super = Alias.WiChli_select = Window_Command.prototype.select
    _super.apply(this, arguments);
};

//34
Alias.WiChLi_updatePlacement = Window_ChoiceList.prototype.updatePlacement;
Window_ChoiceList.prototype.updatePlacement = function() {
    Alias.WiChLi_updatePlacement.apply(this, arguments);
    if ($gameMessage._choiceWidth >= 0) {
        this.width = Math.min($gameMessage._choiceWidth, Graphics.boxWidth);
    }
    if ($gameMessage._choiceHeight >= 0) {
        this.height = Math.min($gameMessage._choiceHeight, Graphics.boxHeight);
    }
    if ($gameMessage._choiceX >= 0) {
        this.x = Math.min($gameMessage._choiceX, Graphics.boxWidth - this.width);
    }
    if ($gameMessage._choiceY >= 0) {
        this.y = Math.min($gameMessage._choiceY, Graphics.boxHeight - this.height);
    }
    this._underMessage = $gameMessage.choiceUnderMes;
};

//67
Window_ChoiceList.prototype.numVisibleRows = function() {
    return Math.min($gameMessage.choices().length, $gameMessage._choiceMaxRow);
};

//103
Window_ChoiceList.prototype.makeCommandList = function() {
    var choices = $gameMessage.choices();
    var enables = $gameMessage._choiceEnables;
    for (var i = 0; i < choices.length; i++) {
        this.addCommand(choices[i], 'choice', enables[i]);
    }
};

//110
Alias.WiChLi_drawItem = Window_ChoiceList.prototype.drawItem;
Window_ChoiceList.prototype.drawItem = function(index) {
    this.changePaintOpacity(this.isCommandEnabled(index));
    Alias.WiChLi_drawItem.apply(this, arguments);
};

//123
Alias.WiChLi_callOkHandler = Window_ChoiceList.prototype.callOkHandler;
Window_ChoiceList.prototype.callOkHandler = function() {
    Alias.WiChLi_callOkHandler.apply(this, arguments);
    this._messageWindow.forceClear();
};

//129
Alias.WiChLi_callCancelHandler = Window_ChoiceList.prototype.callCancelHandler;
Window_ChoiceList.prototype.callCancelHandler = function() {
    Alias.WiChLi_callCancelHandler.apply(this, arguments);
    this._messageWindow.forceClear();
};

if (Window_ChoiceList.prototype.hasOwnProperty('processCancel')) {
    Alias.WiChLi_processCancel = Window_ChoiceList.prototype.processCancel
}
Window_ChoiceList.prototype.processCancel = function() {
    var type = $gameMessage.choiceCancelType();
    var results = $gameMessage._choiceResults;
    var index = results.indexOf(results[type]);
    if (this.isCancelEnabled() && index !== type && !this.isCommandEnabled(index)) {
        this.playBuzzerSound();
    } else {
        var _super = Alias.WiChLi_processCancel || Window_Command.prototype.processCancel;
        _super.apply(this, arguments);
    }
};

Window_ChoiceList.prototype.callUpdateHelp = function() {
    if (this.active && this._messageWindow && $gameMessage.isHelp())
        this.updateHelp();
};

Window_ChoiceList.prototype.updateHelp = function() {
    this._messageWindow.forceClear();
    var texts = $gameMessage._helpTexts[this.index()];
    $gameMessage._texts = texts ? texts.clone() : [''];
    this._messageWindow.startMessage();
};


//-----------------------------------------------------------------------------
// Window_Message

//109
Alias.WiMe_updatePlacement = Window_Message.prototype.updatePlacement;
Window_Message.prototype.updatePlacement = function() {
    Alias.WiMe_updatePlacement.apply(this, arguments);
    this.clearUnderChoice();
};

Window_Message.prototype.clearUnderChoice = function() {
    if ($gameMessage.choiceUnderMes) {
        var x = this.x + this.standardPadding();
        x += this._textState.left || 0;
        var y = this.y + 4;
        var height = this.windowHeight();
        $gameMessage.setChoiceRect(x, y, -1, height);
    }
};

if (Window_Message.prototype.hasOwnProperty('processNewLine')) {
    Alias.WiMe_processNewLine = Window_Message.prototype.processNewLine;
}
Window_Message.prototype.processNewLine = function(textState) {
    if ($gameMessage.choiceUnderMes) $gameMessage.shiftLine(textState.height);
    var _super = Alias.WiMe_processNewLine || Window_Base.prototype.processNewLine;
    _super.apply(this, arguments);
};

//149
Alias.WiMe_updateInput = Window_Message.prototype.updateInput;
Window_Message.prototype.updateInput = function() {
    if ($gameMessage.isHelp() && this._textState) return false;
    return Alias.WiMe_updateInput.apply(this, arguments);
};

//196
Alias.WiMe_onEndOfText = Window_Message.prototype.onEndOfText;
Window_Message.prototype.onEndOfText = function() {
    if ($gameMessage.isHelp() && !this._choiceWindow.active) {
        this.startInput();
    } else {
        Alias.WiMe_onEndOfText.apply(this, arguments);
    }
};

//207
Alias.WiMe_startInput = Window_Message.prototype.startInput;
Window_Message.prototype.startInput = function() {
    if (this._choiceWindow.active) return true;
    if ($gameMessage.isChoice() && $gameMessage.choiceUnderMes &&
            this._textState.x !== this._textState.left) {
        $gameMessage.shiftLine(this._textState.height);
    }
    return Alias.WiMe_startInput.apply(this, arguments);
};

Window_Message.prototype.forceClear = function() {
    this._textState = null;
    this.close();
    this._goldWindow.close();
};

Window_Message.prototype.onShowFast = function() {
    this._showFast = true;
};

//243
Alias.WiMe_newPage = Window_Message.prototype.newPage;
Window_Message.prototype.newPage = function(textState) {
    Alias.WiMe_newPage.apply(this, arguments);
    this.clearUnderChoice();
};






})();
