//=============================================================================
// Keke_BattleEventPlusEx - バトルイベントプラスEX
// バージョン: 1.2.0
//=============================================================================
// Copyright (c) 2023 ケケー
// Released under the MIT license
// http://opensource.org/licenses/mit-license.php
//=============================================================================

/*:
 * @target MZ
 * @plugindesc バトルイベント起動タイミングを増築（ダメージ受けた時を追加）
 * @author えむうん
 * 
 * 
 * @help
 * 【ver.1.2.0】
 * Keke_BattleEventPlusの機能に加えて、
 * 敵キャラがダメージを受けた時にバトルイベントを起動できるようにする
 * 
 * ● 使い方 ●
 * バトルイベントのページの"一番上"に「注釈」を置き、その中に
 * 
 * <条件: 敵ダメージ: (対象キャラ)>
 * 
 * と記述してください。
 * 
 * ★例)
 * <条件: 敵ダメージ: 1>
 * 　インデックス 1 の敵キャラがダメージを受けた時にイベント起動する
 * 
 * ※対象キャラは敵キャラの「インデックス」で指定する
 * ※一度のダメージで一度だけイベントが起動します
 * ※イベントはダメージの数値表示とSEが鳴る前に起動します
 * 
 * ● 利用規約 ●
 * MITライセンスのもと、自由に使ってくれて大丈夫です
 */

(() => {
    //- プラグイン名
    const pluginName = document.currentScript.src.match(/^.*\/(.*).js$/)[1];

    //==================================================
    //--  バトルイベントの条件を追加
    //==================================================

    //- バトルイベントの条件判定の増築(コア追加)
    const _Game_Troop_meetsConditions = Game_Troop.prototype.meetsConditions;
    Game_Troop.prototype.meetsConditions = function(page) {
        const result = _Game_Troop_meetsConditions.apply(this, arguments);
        if (result) return true;
        
        // 追加条件の取得
        const addConditions = getAddConditions(page);
        if (!addConditions.length) return false;
        
        // 追加の条件判定
        return meetsConditionAdd(addConditions);
    };

    //- 追加条件の取得
    function getAddConditions(page) {
        const addConditions = [];
        // 最初の注釈を取得
        const comment = getFirstComment(page);
        if (!comment) return [];
        
        // 『敵ダメージ』の取得
        const enemyDamage = getCondition(comment, "敵ダメージ");
        if (enemyDamage) {
            addConditions.push({ type: "enemyDamage", enemyIndex: enemyDamage.id - 1 });
        }
        
        return addConditions;
    };

    //- 追加の条件判定
    function meetsConditionAdd(conditions) {
        if (!conditions || !conditions.length) return false;
        
        // 全ての条件を判定
        for (const condition of conditions) {
            const type = condition.type;
            
            // 敵ダメージ
            if (type == "enemyDamage") {
                const enemy = $gameTroop.members()[condition.enemyIndex];
                if (!enemy || !enemy._lastDamageKeBevpEx) return false;
            }
        }
        return true;
    };

    //- 条件の取得
    function getCondition(note, tag) {
        const metas = metaAll(note, ["条件", "condition"]);
        if (!metas || !metas.length) return null;
        
        for (const str of metas.reverse()) {
            if (!str) continue;
            
            // 敵ダメージ
            if (tag == "敵ダメージ") {
                const match = str.match(/(^|[,\s\n])(enemyDamage|敵ダメージ|敵キャラダメージ):\s*(\-*\d+\.*\d*)/i);
                if (match && match[3]) {
                    return { id: Number(match[3]) };
                }
            }
        }
        return null;
    };

    //==================================================
    //--  敵キャラのダメージ処理
    //==================================================

    //- 敵キャラのダメージ処理の拡張
    const _Game_Enemy_performDamage = Game_Enemy.prototype.performDamage;
    Game_Enemy.prototype.performDamage = function() {
        if (!this._lastDamageKeBevpEx) {
            this._lastDamageKeBevpEx = true;
            this.requestBattleEventKeBevpEx();
            BattleManager.updateEventMain();
        }
        _Game_Enemy_performDamage.apply(this, arguments);
    };

    //- バトルイベントのリクエスト
    Game_Enemy.prototype.requestBattleEventKeBevpEx = function() {
        BattleManager._needsEvent = true;
    };

    //- ダメージポップアップの処理を拡張
    const _Sprite_Battler_updateDamagePopup = Sprite_Battler.prototype.updateDamagePopup;
    Sprite_Battler.prototype.updateDamagePopup = function() {
        if (this._battler && this._battler.isEnemy()) {
            if (this._battler._lastDamageKeBevpEx) {
                this._battler._lastDamageKeBevpEx = false;
                BattleManager.updateEventMain();
            }
        }
        _Sprite_Battler_updateDamagePopup.apply(this, arguments);
    };

    //- ターン終了時にダメージフラグをリセット
    const _BattleManager_endTurn = BattleManager.endTurn;
    BattleManager.endTurn = function() {
        _BattleManager_endTurn.apply(this, arguments);
        $gameTroop.members().forEach(enemy => {
            enemy._lastDamageKeBevpEx = false;
        });
    };

    //- 行動終了時にもダメージフラグをリセット
    const _BattleManager_endAction = BattleManager.endAction;
    BattleManager.endAction = function() {
        _BattleManager_endAction.apply(this, arguments);
        $gameTroop.members().forEach(enemy => {
            enemy._lastDamageKeBevpEx = false;
        });
    };

    //==================================================
    //--  メタ取得 /ベーシック
    //==================================================
    
    //- 全取得メタ
    function metaAll(note, words, ratioIndex) {
        var result = [];
        words.forEach(word => {
            var regText = '\<\\s*' + word + '\\s*:([^\>]*)\>';
            var regExp_g = new RegExp(regText, 'g');
            var regExp = new RegExp(regText);
            var matches = note.match(regExp_g);
            if (matches) {
                matches.forEach(function(line) {
                    const match = line.match(regExp);
                    const vals = match[1].replace(/\s/g, "").split(",");
                    ratioIndexEx = ratioIndex - 1;
                    if (ratioIndex && vals[ratioIndexEx] && Math.randomInt(100) >= Number(vals[ratioIndexEx])) {
                        return;
                    }
                    result.push(match[1]);
                });
            }
        });
        return result;
    };

    //==================================================
    //-  注釈 /ベーシック
    //==================================================

    //- 最初の注釈を取得
    function getFirstComment(page) {
        let list = page ? page.list : [];
        if (!list.length) return "";
        // 注釈を全て読み込み
        let comment = "";
        let i = 0;
        while (true) {
            const command = list[i];
            if (!command || !(command.code == 108 || command.code == 408)) break;
            comment += command.parameters[0] + "\n";
            i++;
        }
        return comment;
    };

})();