code:
//=============================================================================
// MessageWindowPopup.js
// ----------------------------------------------------------------------------
// Copyright (c) 2015 Triacontane
// This software is released under the MIT License.
// http://opensource.org/licenses/mit-license.php
// ----------------------------------------------------------------------------
// Version
// 2.0.1 2016/08/25 フォントサイズを\{で変更して\}で戻さなかった場合の文字サイズがおかしくなっていた現象を修正
// 2.0.0 2016/08/22 本体v1.3.0によりウィンドウ透過の実装が変更されたので対応
// 1.3.3 2016/07/02 ポップアップ有効時は選択肢の最大表示数が8になるよう修正
// 1.3.2 2016/06/02 YEP_MessageCore.jsとのウィンドウ位置に関する競合を解消
// 1.3.1 2016/05/25 フォロワーにフキダシを表示できる機能を追加
// 1.3.0 2016/03/21 ウィンドウの表示位置をキャラクターの高さに合わせて自動調整するよう修正
//                  ポップアップウィンドウ専用のウィンドウスキンを使用する機能を追加
//                  位置とサイズを微調整する機能を追加
//                  選択肢と数値入力ウィンドウの表示方法を2種類追加
// 1.2.3 2016/02/23 YEP_MessageCore.jsより上に配置した場合に発生するエラーを修正
//                  （正常に動作しない点はそのままです）
// 1.2.2 2016/02/20 YEP_MessageCore.js最新版に対応
// 1.2.1 2016/02/20 YEP_MessageCore.jsのネームポップをポップアップウィンドウと連動するよう対応
// 1.2.0 2016/02/13 並列処理のイベントが存在するときにポップアップ設定がクリアされてしまう
//                  問題の修正
//                  ウィンドウの表示位置を下に表示できる設定を追加
// 1.1.3 2016/02/04 イベント終了時にポップアップ設定をクリアするよう修正
// 1.1.2 2016/01/31 行間を調整できる機能を追加
// 1.1.1 2016/01/30 選択肢と数値入力ウィンドウをポップアップと連携するよう修正
//                  その他微調整と軽微な表示不良修正
// 1.1.0 2016/01/29 高確率で競合するバグを修正
//                  ポップアップウィンドウがキャラクターの移動に追従するよう修正
//                  顔グラフィックが見切れないよう修正
//                  実行中のイベントをポップアップ対象にできる機能を追加（0を指定）
//                  英語対応
// 1.0.0 2016/01/28 初版
// ----------------------------------------------------------------------------
// [Blog]   : http://triacontane.blogspot.jp/
// [Twitter]: https://twitter.com/triacontane/
// [GitHub] : https://github.com/triacontane/
//=============================================================================

/*:
 * @plugindesc Popup window plugin
 * @author triacontane
 *
 * @param FontSize
 * @desc Font size of popup window
 * @default 22
 *
 * @param Padding
 * @desc Padding of popup window
 * @default 10
 *
 * @param AutoPopup
 * @desc Popup set when event starting（ON/OFF）
 * @default ON
 *
 * @param FaceScale
 * @desc Scale of face graphic of popup window(1-100%)
 * @default 75
 *
 * @param WindowLinkage
 * @desc Select window and Number input window is linkage with popup window(ON/OFF)
 * @default ON
 *
 * @param BetweenLines
 * @desc Between the Lines
 * @default 4
 *
 * @param ThroughWindow
 * @desc Window through if overlap windows(ON/OFF)
 * @default OFF
 *
 * @help Change the message window from fixed to popup
 *
 * Plugin Command
 *
 * MWP_VALID [Character ID]
 *  Popup window valid
 *  Player:-1 Current event:0 Event:1...
 * ex:MWP_VALID 0
 *
 * MWP_INVALID
 *  Popup window invalid
 * ex:MWP_INVALID
 *
 * MWP_SETTING [parameter]
 *  Popup window setting. parameter are...
 *   POS_UPPER
 *     Window position fixed upper.
 *
 * 　POS_LOWER
 *     Window position fixed upper.
 *
 * 　POS_AUTO
 *     Window position auto.
 *
 *   SKIN [File name(/img/system/...)]
 *     Setting window skin for popup message.
 *
 *   SUB_POS_PLAYER
 *     Choice window or NumberInput displays player.
 *
 *   SUB_POS_INNER
 *     Choice window or NumberInput displays internal message window.
 *
 *   SUB_POS_NORMAL
 *     Choice window or NumberInput displays normal position.
 *
 * MWP_ADJUST [parameter]
 *   Popup window adjust. parameter are...
 *
 *   POS [X] [Y]
 *     Popup window adjust relative position.
 *
 * 　SIZE [Width] [Height]
 * 　　Popup window adjust relative size.
 *
 * This plugin is released under the MIT License.
 */
/*:ja
 * @plugindesc フキダシウィンドウプラグイン
 * @author トリアコンタン
 *
 * @param フォントサイズ
 * @desc フキダシウィンドウのデフォルトフォントサイズ
 * 通常ウィンドウのフォントサイズ：28
 * @default 22
 *
 * @param 余白
 * @desc フキダシウィンドウの余白サイズ
 * 通常ウィンドウの余白：18
 * @default 10
 *
 * @param 自動設定
 * @desc イベント起動時にフキダシの対象が、起動したイベントに自動設定されます。（ON/OFF）
 * OFFの場合は通常のメッセージウィンドウに設定されます。
 * @default ON
 *
 * @param フェイス倍率
 * @desc フキダシウィンドウの顔グラフィック表示倍率(1-100%)
 * @default 75
 *
 * @param ウィンドウ連携
 * @desc 選択肢ウィンドウと数値入力ウィンドウを
 * ポップアップウィンドウに連動させます。(ON/OFF)
 * @default ON
 *
 * @param 行間
 * @desc 行と行の間のスペースをピクセル単位で設定します。
 * @default 4
 *
 * @param ウィンドウ透過
 * @desc ウィンドウが重なったときに透過表示します。(ON/OFF)
 * 選択肢をフキダシ内に表示する場合はONにしてください。
 * @default OFF
 *
 * @help メッセージウィンドウを指定したキャラクターの頭上にフキダシで
 * 表示するよう変更します。
 *
 * YEP_MessageCore.jsのネームポップと併せて使用する場合は、
 * プラグイン管理画面で当プラグインをYEP_MessageCore.jsより
 * 下に配置してください。
 *
 * プラグインコマンド詳細
 *  イベントコマンド「プラグインコマンド」から実行。
 *  （パラメータの間は半角スペースで区切る）
 *
 * MWP_VALID [キャラクターID] or
 * フキダシウィンドウ有効化 [キャラクターID]
 * 　メッセージウィンドウを指定したキャラクターIDの頭上に表示するようにします。
 * 　プレイヤー : -1 このイベント : 0 指定したIDのイベント : 1 ～
 *   フォロワー : -2, -3, -4
 *
 * 例：MWP_VALID 0
 * 　　フキダシウィンドウ有効化 3
 *
 * MWP_INVALID or
 * フキダシウィンドウ無効化
 * 　ウィンドウの表示方法を通常に戻します。
 *
 * 例：MWP_INVALID
 * 　　フキダシウィンドウ無効化
 *
 * MWP_SETTING [設定内容] or
 * フキダシウィンドウ設定 [設定内容]
 * 　フキダシウィンドウの設定を行います。設定内容に以下を入力。
 *
 * 　POS_UPPER or 位置_上固定
 * 　　ウィンドウの位置をキャラクターの上で固定します。
 *
 * 　POS_LOWER or 位置_下固定
 * 　　ウィンドウの位置をキャラクターの下で固定します。
 *
 * 　POS_AUTO or 位置_自動
 * 　　通常はキャラクターの上に表示し、ウィンドウが上に見切れる場合のみ
 * 　　下に表示します。
 *
 *   SKIN or スキン [/img/system/以下に配置するスキンのファイル名]
 *     フキダシウィンドウ時専用のウィンドウスキンを設定します。
 *
 *   SUB_POS_PLAYER or サブ位置_プレイヤーの頭上
 *   　選択肢および数値入力のウィンドウをプレイヤーの頭上に表示します。
 *   　位置関係次第でウィンドウが被る場合があるので、必要に応じて
 *   　ウィンドウ透過のパラメータを有効にしてください。
 *
 *   SUB_POS_INNER or サブ位置_メッセージウィンドウ内部
 *     選択肢および数値入力のウィンドウをメッセージウィンドウに含めます。
 *     この設定を使用する場合は必ずウィンドウ透過のパラメータを
 *     有効にしてください。
 *
 *   SUB_POS_NORMAL or サブ位置_通常
 *   　選択肢および数値入力のウィンドウをフキダシウィンドウの下に表示します。
 *   　特に設定を変更しない場合はこの設定になります。
 *
 * 例：MWP_SETTING POS_UPPER
 * 　　フキダシウィンドウ設定 位置_自動
 * 　　MWP_SETTING SKIN window2
 * 　　フキダシウィンドウ設定 サブ位置_プレイヤーの頭上
 *
 * MWP_ADJUST [設定内容] or
 * フキダシウィンドウ調整 [設定内容]
 * 　フキダシウィンドウの表示位置やサイズを微調整します。設定内容に以下を入力。
 *
 * 　POS or 位置 [X座標] [Y座標]
 * 　　ウィンドウのX座標とY座標を調整します。指定するのは元の座標からの相対です。
 *
 * 　SIZE or サイズ [横幅] [高さ]
 * 　　ウィンドウの横幅と高さを調整します。指定するのは元のサイズからの相対です。
 *
 * 例：MWP_ADJUST POS 5 -3
 * 　　フキダシウィンドウ調整 サイズ 20 -40
 *
 * 利用規約：
 *  作者に無断で改変、再配布が可能で、利用形態（商用、18禁利用等）
 *  についても制限はありません。
 *  このプラグインはもうあなたのものです。
 */
(function () {
    'use strict';
    var pluginName = 'MessageWindowPopup';

    var checkTypeFunction = function(value) {
        return checkType(value, 'Function');
    };

    var checkType = function(value, typeName) {
        return Object.prototype.toString.call(value).slice(8, -1) === typeName;
    };

    var getParamNumber = function(paramNames, min, max) {
        var value = getParamOther(paramNames);
        if (arguments.length < 2) min = -Infinity;
        if (arguments.length < 3) max = Infinity;
        return (parseInt(value, 10) || 0).clamp(min, max);
    };

    var getParamBoolean = function(paramNames) {
        var value = getParamOther(paramNames);
        return (value || '').toUpperCase() === 'ON';
    };

    var getParamOther = function(paramNames) {
        if (!Array.isArray(paramNames)) paramNames = [paramNames];
        for (var i = 0; i < paramNames.length; i++) {
            var name = PluginManager.parameters(pluginName)[paramNames[i]];
            if (name) return name;
        }
        return null;
    };

    var getArgNumber = function (arg, min, max) {
        if (arguments.length <= 2) min = -Infinity;
        if (arguments.length <= 3) max = Infinity;
        return (parseInt(convertEscapeCharacters(arg), 10) || 0).clamp(min, max);
    };

    var getArgString = function (arg, upperFlg) {
        arg = convertEscapeCharacters(arg);
        return upperFlg ? arg.toUpperCase() : arg;
    };

    var getCommandName = function (command) {
        return (command || '').toUpperCase();
    };

    var convertEscapeCharacters = function(text) {
        if (text == null) text = '';
        var window = SceneManager._scene._windowLayer.children[0];
        return window ? window.convertEscapeCharacters(text) : text;
    };

    //=============================================================================
    // パラメータのバリデーション
    //=============================================================================
    var paramThroughWindow = getParamBoolean(['ThroughWindow', 'ウィンドウ透過']);
    var paramFaceScale     = getParamNumber(['FaceScale', 'フェイス倍率'], 1, 100);
    var paramFontSize      = getParamNumber(['FontSize', 'フォントサイズ'], 1);
    var paramPadding       = getParamNumber(['Padding', '余白'], 1);
    var paramLinkage       = getParamBoolean(['WindowLinkage', 'ウィンドウ連携']);
    var paramBetweenLines  = getParamNumber(['BetweenLines', '行間'], 0);
    var paramAutoPopup     = getParamBoolean(['AutoPopup', '自動設定']);

    //=============================================================================
    // Game_Interpreter
    //  プラグインコマンドを追加定義します。
    //=============================================================================
    var _Game_Interpreter_pluginCommand      = Game_Interpreter.prototype.pluginCommand;
    Game_Interpreter.prototype.pluginCommand = function (command, args) {
        _Game_Interpreter_pluginCommand.apply(this, arguments);
        try {
            this.pluginCommandMessageWindowPopup(command, args);
        } catch (e) {
            if ($gameTemp.isPlaytest() && Utils.isNwjs()) {
                var window  = require('nw.gui').Window.get();
                var devTool = window.showDevTools();
                devTool.moveTo(0, 0);
                devTool.resizeTo(Graphics.width, Graphics.height);
                window.focus();
            }
            console.log('プラグインコマンドの実行中にエラーが発生しました。');
            console.log('- コマンド名 　: ' + command);
            console.log('- コマンド引数 : ' + args);
            console.log('- エラー原因   : ' + e.toString());
        }
    };

    Game_Interpreter.prototype.pluginCommandMessageWindowPopup = function (command, args) {
        switch (getCommandName(command)) {
            case 'MWP_VALID' :
            case 'フキダシウィンドウ有効化':
                var eventId = getArgNumber(args[0]);
                if (eventId === 0) eventId = this.eventId();
                $gameSystem.setMessagePopup(eventId);
                break;
            case 'MWP_INVALID':
            case 'フキダシウィンドウ無効化':
                $gameSystem.clearMessagePopup();
                break;
            case 'MWP_SETTING' :
            case 'フキダシウィンドウ設定':
                switch (getCommandName(args[0])) {
                    case 'POS_UPPER' :
                    case '位置_上固定':
                        $gameSystem.setPopupFixUpper();
                        break;
                    case 'POS_LOWER' :
                    case '位置_下固定':
                        $gameSystem.setPopupFixLower();
                        break;
                    case 'POS_AUTO' :
                    case '位置_自動':
                        $gameSystem.setPopupAuto();
                        break;
                    case 'SKIN' :
                    case 'スキン' :
                        $gameSystem.setPopupWindowSkin(getArgString(args[1]));
                        this.setWaitMode('image');
                        break;
                    case 'SUB_POS_NORMAL' :
                    case 'サブ位置_通常':
                        $gameSystem.setPopupSubWindowPosition(0);
                        break;
                    case 'SUB_POS_PLAYER' :
                    case 'サブ位置_プレイヤーの頭上':
                        $gameSystem.setPopupSubWindowPosition(1);
                        break;
                    case 'SUB_POS_INNER' :
                    case 'サブ位置_メッセージウィンドウ内部':
                        $gameSystem.setPopupSubWindowPosition(2);
                        break;
                }
                break;
            case 'MWP_ADJUST':
            case 'フキダシウィンドウ調整':
                switch (getCommandName(args[0])) {
                    case 'SIZE' :
                    case 'サイズ':
                        $gameSystem.setPopupAdjustSize(getArgNumber(args[1]), getArgNumber(args[2]));
                        break;
                    case 'POS' :
                    case '位置':
                        $gameSystem.setPopupAdjustPosition(getArgNumber(args[1]), getArgNumber(args[2]));
                        break;
                }
                break;
        }
    };

    var _Game_Interpreter_terminate = Game_Interpreter.prototype.terminate;
    Game_Interpreter.prototype.terminate = function() {
        _Game_Interpreter_terminate.apply(this, arguments);
        if (this._depth === 0 && this.isGameMapInterpreter()) $gameSystem.clearMessagePopup();
    };

    Game_Interpreter.prototype.setGameMapInterpreter = function() {
        this._gameMapInterpreter = true;
    };

    Game_Interpreter.prototype.isGameMapInterpreter = function() {
        return this._gameMapInterpreter;
    };

    //=============================================================================
    // Game_System
    //  ポップアップフラグを保持します。
    //=============================================================================
    var _Game_System_initialize = Game_System.prototype.initialize;
    Game_System.prototype.initialize = function() {
        _Game_System_initialize.apply(this, arguments);
        this._messagePopupCharacterId       = 0;
        this._messagePopupPosition          = null;
        this._messagePopupAdjustSize        = null;
        this._messagePopupAdjustPosition    = null;
        this._messagePopupWindowSkin        = null;
        this._messagePopupSubWindowPosition = 0;
    };

    Game_System.prototype.setPopupSubWindowPosition = function(position) {
        this._messagePopupSubWindowPosition = position.clamp(0, 2);
    };

    Game_System.prototype.getPopupSubWindowPosition = function() {
        return this._messagePopupSubWindowPosition;
    };

    Game_System.prototype.setPopupWindowSkin = function(fileName) {
        this._messagePopupWindowSkin = fileName;
        ImageManager.loadSystem(fileName);
    };

    Game_System.prototype.getPopupWindowSkin = function() {
        return this._messagePopupWindowSkin;
    };

    Game_System.prototype.setMessagePopup = function(id) {
        this._messagePopupCharacterId = id;
    };

    Game_System.prototype.clearMessagePopup = function() {
        this._messagePopupCharacterId = 0;
    };

    Game_System.prototype.getMessagePopupId = function() {
        return this._messagePopupCharacterId !== 0 ? this._messagePopupCharacterId : null;
    };

    Game_System.prototype.setPopupFixUpper = function() {
        this._messagePopupPosition = 1;
    };

    Game_System.prototype.setPopupFixLower = function() {
        this._messagePopupPosition = 2;
    };

    Game_System.prototype.setPopupAuto = function() {
        this._messagePopupPosition = 0;
    };

    Game_System.prototype.setPopupAdjustSize = function(w, h) {
        this._messagePopupAdjustSize = [w, h];
    };

    Game_System.prototype.getPopupAdjustSize = function() {
        return this._messagePopupAdjustSize;
    };

    Game_System.prototype.setPopupAdjustPosition = function(x, y) {
        this._messagePopupAdjustPosition = [x, y];
    };

    Game_System.prototype.getPopupAdjustPosition = function() {
        return this._messagePopupAdjustPosition;
    };

    Game_System.prototype.isPopupFixUpper = function() {
        return this._messagePopupPosition === 1;
    };

    Game_System.prototype.isPopupFixLower = function() {
        return this._messagePopupPosition === 2;
    };

    //=============================================================================
    // Game_Map
    //  イベント起動時に自動設定を適用します。
    //=============================================================================
    var _Game_Map_setupStartingMapEvent = Game_Map.prototype.setupStartingMapEvent;
    Game_Map.prototype.setupStartingMapEvent = function() {
        var result = _Game_Map_setupStartingMapEvent.apply(this, arguments);
        if (result) {
            if (paramAutoPopup) {
                $gameSystem.setMessagePopup(this._interpreter.eventId());
            } else {
                $gameSystem.clearMessagePopup();
            }
        }
        return result;
    };

    var _Game_Map_setup = Game_Map.prototype.setup;
    Game_Map.prototype.setup = function(mapId) {
        _Game_Map_setup.apply(this, arguments);
        this._interpreter.setGameMapInterpreter();
    };

    //=============================================================================
    // Game_Troop
    //  戦闘開始時にポップアップフラグを解除します。
    //=============================================================================
    var _Game_Troop_setup = Game_Troop.prototype.setup;
    Game_Troop.prototype.setup = function(troopId) {
        _Game_Troop_setup.apply(this, arguments);
        $gameSystem.clearMessagePopup();
    };

    //=============================================================================
    // Game_CharacterBase
    //  キャラクターの高さを設定します。
    //=============================================================================
    var _Game_CharacterBase_initMembers = Game_CharacterBase.prototype.initMembers;
    Game_CharacterBase.prototype.initMembers = function() {
        _Game_CharacterBase_initMembers.apply(this, arguments);
        this.setSizeForMessagePopup(0, 0);
    };

    Game_CharacterBase.prototype.setSizeForMessagePopup = function(width, height) {
        this._size = [width, height];
    };

    Game_CharacterBase.prototype.getHeightForPopup = function() {
        return this._size[1];
    };

    //=============================================================================
    // Sprite_Character
    //  キャラクターの高さを逆設定します。
    //=============================================================================
    var _Sprite_Character_updateBitmap = Sprite_Character.prototype.updateBitmap;
    Sprite_Character.prototype.updateBitmap = function() {
        if (this.isImageChanged()) this._imageChange = true;
        _Sprite_Character_updateBitmap.apply(this, arguments);
        if (this._imageChange) {
            this.bitmap.addLoadListener(function() {
                var width = this.bitmap.width === 1 ? $gameMap.tileWidth() : this.patternWidth();
                var height = this.bitmap.height === 1 ? $gameMap.tileHeight() : this.patternHeight();
                this._character.setSizeForMessagePopup(width, height);
            }.bind(this));
            this._imageChange = false;
        }
    };

    //=============================================================================
    // Window_Base
    //  共通処理を定義します。
    //=============================================================================
    var _Window_Base_loadWindowskin = Window_Base.prototype.loadWindowskin;
    Window_Base.prototype.loadWindowskin = function() {
        var popupSkin = $gameSystem.getPopupWindowSkin();
        if (this.isPopup() && popupSkin) {
            this.windowskin = ImageManager.loadSystem(popupSkin);
        } else {
            _Window_Base_loadWindowskin.apply(this, arguments);
        }
    };

    Window_Base.prototype.setPauseSignToTail = function(lowerFlg) {
        if (lowerFlg) {
            this._windowPauseSignSprite.rotation = 180 * Math.PI / 180;
            this._windowPauseSignSprite.y        = 12;
            this._windowPauseSignSprite.anchor.y = 0;
        } else {
            this._windowPauseSignSprite.rotation = 0;
            this._windowPauseSignSprite.y        = this.height + 12;
            this._windowPauseSignSprite.anchor.y = 1;
        }
        this._pauseSingToTail = true;
    };

    Window_Base.prototype.setPauseSignToNormal = function() {
        this._windowPauseSignSprite.rotation = 0;
        this._windowPauseSignSprite.anchor.y = 1.0;
        this._windowPauseSignSprite.move(this._width / 2, this._height);
        this._pauseSingToTail = false;
    };

    var _Window_Base_updatePauseSign = Window_Base.prototype._updatePauseSign;
    Window_Base.prototype._updatePauseSign = function() {
        _Window_Base_updatePauseSign.apply(this, arguments);
        if (this._pauseSingToTail) this._windowPauseSignSprite.alpha = 1.0;
    };

    Window_Base.prototype.isPopupLower = function() {
        return $gameSystem.isPopupFixLower() || (!$gameSystem.isPopupFixUpper() && this.y < 0);
    };

    Window_Base.prototype.setPopupPosition = function(character) {
        var pos = $gameSystem.getPopupAdjustPosition();
        this.x = character.screenX() - this.width / 2 + (pos ? pos[0] : 0);
        this.y = character.screenY() - this.height - (character.getHeightForPopup() + 8) + (pos ? pos[1] : 0);
        var lowerFlg = this.isPopupLower();
        if (lowerFlg) this.y = character.screenY() + 8;
        this.setPauseSignToTail(lowerFlg);
        var deltaX = 0;
        if (this.x < 0) {
            deltaX = this.x;
            this.x = 0;
        }
        if (this.x + this.width > Graphics.boxWidth) {
            deltaX = this.x + this.width - Graphics.boxWidth;
            this.x = Graphics.boxWidth - this.width;
        }
        this._windowPauseSignSprite.x = this._width / 2 + deltaX;
    };

    Window_Base.prototype.updatePlacementPopup = function() {
        if (!this._messageWindow) return;
        if (paramLinkage) {
            switch ($gameSystem.getPopupSubWindowPosition()) {
                case 0:
                    this.x = this._messageWindow.x;
                    this.y = this._messageWindow.y + this._messageWindow.height;
                    this.setPauseSignToNormal();
                    break;
                case 1:
                    this.setPopupPosition($gamePlayer);
                    break;
                case 2:
                    var pos = this._messageWindow.getSubWindowPosition();
                    this.x = pos.x;
                    this.y = pos.y;
                    this.setPauseSignToNormal();
                    this.opacity = 0;
                    break;
            }
        } else {
            this.y = Graphics.boxHeight - this.height - this._messageWindow.windowHeight() / 2;
        }
    };

    Window_Base.prototype.isPopup = function() {
        return false;
    };

    Window_Base.prototype.isPopupLinkage = function() {
        return this.isPopup() && paramLinkage;
    };

    Window_Base.prototype.resetLayout = function() {
        this.padding = this.standardPadding();
        this.width   = this.windowWidth();
        this.height  = this.windowHeight();
        this.loadWindowskin();
        this.setPauseSignToNormal();
    };

    //=============================================================================
    // Window_Message
    //  ポップアップする場合、表示内容により座標とサイズを自動設定します。
    //=============================================================================
    Window_Message._faceHeight = Math.floor(Window_Base._faceHeight * paramFaceScale / 100);
    Window_Message._faceWidth  = Math.floor(Window_Base._faceWidth  * paramFaceScale / 100);

    var _Window_Message_standardFontSize = Window_Message.prototype.standardFontSize;
    Window_Message.prototype.standardFontSize = function() {
        return this.isPopup() ? paramFontSize : _Window_Message_standardFontSize.apply(this, arguments);
    };

    var _Window_Message_standardPadding = Window_Message.prototype.standardPadding;
    Window_Message.prototype.standardPadding = function() {
        return this.isPopup() ? paramPadding : _Window_Message_standardPadding.apply(this, arguments);
    };

    var _Window_Message_calcTextHeight = Window_Message.prototype.calcTextHeight;
    Window_Message.prototype.calcTextHeight = function(textState, all) {
        var height = _Window_Message_calcTextHeight.apply(this, arguments);
        return this.isPopup() ? height - 8 + paramBetweenLines : height;
    };

    var _Window_Message_startMessage = Window_Message.prototype.startMessage;
    Window_Message.prototype.startMessage = function() {
        this.updateTargetCharacterId();
        _Window_Message_startMessage.apply(this, arguments);
        this.loadWindowskin();
        this.resetLayout();
    };

    Window_Message.prototype.updateTargetCharacterId = function() {
        this._targetCharacterId = $gameSystem.getMessagePopupId();
    };

    var _Window_Message_resetFontSettings = Window_Message.prototype.resetFontSettings;
    Window_Message.prototype.resetFontSettings = function() {
        _Window_Message_resetFontSettings.apply(this, arguments);
        if (this.isPopup()) this.contents.fontSize = paramFontSize;
    };

    Window_Message.prototype.getPopupTargetCharacter = function() {
        var id = this._targetCharacterId;
        if (id < -1) {
            return $gamePlayer.followers().follower((id * -1) - 2);
        } else if (id === -1) {
            return $gamePlayer;
        } else if (id > -1) {
            return $gameMap.event(id);
        } else {
            return null;
        }
    };

    Window_Message.prototype.isPopup = function() {
       return !!this.getPopupTargetCharacter();
    };

    var _Window_Message_update = Window_Message.prototype.update;
    Window_Message.prototype.update = function() {
        _Window_Message_update.apply(this, arguments);
        if (this.openness > 0 && this.isPopup()) this.updatePlacementPopup();
    };

    var _Window_Message_updatePlacement = Window_Message.prototype.updatePlacement;
    Window_Message.prototype.updatePlacement = function() {
        if (typeof Yanfly === 'undefined' || !Yanfly.Message) {
            this.x = 0;
        }
        _Window_Message_updatePlacement.apply(this, arguments);
        if (this.isPopup()) this.updatePlacementPopup();
    };

    Window_Message.prototype.isPopupLower = function() {
        return $gameSystem.isPopupFixLower() || (!$gameSystem.isPopupFixUpper() && this.y < 0);
    };

    Window_Message.prototype.updatePlacementPopup = function() {
        this.setPopupPosition(this.getPopupTargetCharacter());
        if (this._choiceWindow && $gameMessage.isChoice()) {
            this._choiceWindow.updatePlacementPopup();
        }
        this._numberWindow.updatePlacementPopup();
        if (this._nameWindow && checkTypeFunction(this._nameWindow.updatePlacementPopup)) {
            this._nameWindow.updatePlacementPopup();
        }
    };

    Window_Message.prototype.resetLayout = function() {
        this.padding = this.standardPadding();
        if (this.getPopupTargetCharacter()) {
            this.processVirtual();
        } else {
            this.width = this.windowWidth();
            this.height = this.windowHeight();
            this.setPauseSignToNormal();
        }
        this.updatePlacement();
        this.updateBackground();
    };

    Window_Message.prototype.processVirtual = function() {
        var virtual = {};
        virtual.index = 0;
        virtual.text = this.convertEscapeCharacters($gameMessage.allText());
        virtual.maxWidth = 0;
        this.newPage(virtual);
        while (!this.isEndOfText(virtual)) {
            this.processVirtualCharacter(virtual);
        }
        virtual.y += virtual.height;
        this._subWindowY = virtual.y;
        var choices = $gameMessage.choices();
        if (choices && $gameSystem.getPopupSubWindowPosition() === 2) {
            virtual.y += choices.length * this._choiceWindow.lineHeight();
            virtual.maxWidth = Math.max(virtual.maxWidth, this.newLineX() + this._choiceWindow.maxChoiceWidth());
        }
        var digit = $gameMessage.numInputMaxDigits();
        if (digit && $gameSystem.getPopupSubWindowPosition() === 2) {
            virtual.y += this._numberWindow.lineHeight();
        }
        var width = virtual.maxWidth + this.padding * 2;
        var height = Math.max(this.getFaceHeight(), virtual.y) + this.padding * 2;
        var adjust = $gameSystem.getPopupAdjustSize();
        if (adjust) {
            width += adjust[0];
            height += adjust[1];
        }
        this.width  = width;
        this.height = height;
        this.resetFontSettings();
    };

    Window_Message.prototype.getSubWindowPosition = function() {
        var pos = new Point();
        pos.x = this.x + this.newLineX();
        pos.y = this.y + this._subWindowY;
        return pos;
    };

    Window_Message.prototype.processVirtualCharacter = function(textState) {
        switch (textState.text[textState.index]) {
            case '\n':
                this.processNewLine(textState);
                break;
            case '\f':
                this.processNewPage(textState);
                break;
            case '\x1b':
                this.processVirtualEscapeCharacter(this.obtainEscapeCode(textState), textState);
                break;
            default:
                this.processVirtualNormalCharacter(textState);
                break;
        }
    };

    Window_Message.prototype.processVirtualEscapeCharacter = function(code, textState) {
        switch (code) {
            case 'C':
                this.changeTextColor(this.textColor(this.obtainEscapeParam(textState)));
                break;
            case 'I':
                this.processVirtualDrawIcon(this.obtainEscapeParam(textState), textState);
                break;
            case '{':
                this.makeFontBigger();
                break;
            case '}':
                this.makeFontSmaller();
                break;
        }
    };

    Window_Message.prototype.processVirtualNormalCharacter = function(textState) {
        var c = textState.text[textState.index++];
        textState.x += this.textWidth(c);
        textState.maxWidth = Math.max(textState.maxWidth, textState.x);
    };

    Window_Message.prototype.processVirtualDrawIcon = function(iconIndex, textState) {
        textState.x += Window_Base._iconWidth + 4;
        textState.maxWidth = Math.max(textState.maxWidth, textState.x);
    };

    var _Window_Message_newLineX = Window_Message.prototype.newLineX;
    Window_Message.prototype.newLineX = function() {
        if (this.isPopup()) {
            return $gameMessage.faceName() === '' ? 0 : Window_Message._faceWidth + 8;
        } else {
            return _Window_Message_newLineX.apply(this, arguments);
        }
    };

    Window_Message.prototype.getFaceHeight = function() {
        return $gameMessage.faceName() === '' ? 0 : Window_Message._faceHeight;
    };

    var _Window_Message_drawFace = Window_Message.prototype.drawFace;
    Window_Message.prototype.drawFace = function(faceName, faceIndex, x, y, width, height) {
        if (this.isPopup()) {
            width = width || Window_Base._faceWidth;
            height = height || Window_Base._faceHeight;
            var bitmap = ImageManager.loadFace(faceName);
            var pw = Window_Base._faceWidth;
            var ph = Window_Base._faceHeight;
            var sw = Math.min(width, pw);
            var sh = Math.min(height, ph);
            var dx = Math.floor(x + Math.max(width - pw, 0) / 2);
            var dy = Math.floor(y + Math.max(height - ph, 0) / 2);
            var sx = faceIndex % 4 * pw + (pw - sw) / 2;
            var sy = Math.floor(faceIndex / 4) * ph + (ph - sh) / 2;
            this.contents.blt(bitmap, sx, sy, sw, sh, dx, dy, Window_Message._faceWidth, Window_Message._faceHeight);
        } else {
            _Window_Message_drawFace.apply(this, arguments);
        }
    };

    //=============================================================================
    // Window_ChoiceList
    //  ポップアップする場合、メッセージウィンドウに連動して表示位置と余白を調整します。
    //=============================================================================
    var _Window_ChoiceList_standardFontSize = Window_ChoiceList.prototype.standardFontSize;
    Window_ChoiceList.prototype.standardFontSize = function() {
        return this.isPopupLinkage() ? paramFontSize : _Window_ChoiceList_standardFontSize.apply(this, arguments);
    };

    var _Window_ChoiceList_standardPadding = Window_ChoiceList.prototype.standardPadding;
    Window_ChoiceList.prototype.standardPadding = function() {
        return this.isPopupLinkage() ? paramPadding : _Window_ChoiceList_standardPadding.apply(this, arguments);
    };

    var _Window_ChoiceList_lineHeight = Window_ChoiceList.prototype.lineHeight;
    Window_ChoiceList.prototype.lineHeight = function() {
        return this.isPopupLinkage() ? paramFontSize + 8 : _Window_ChoiceList_lineHeight.apply(this, arguments);
    };

    var _Window_ChoiceList_updatePlacement = Window_ChoiceList.prototype.updatePlacement;
    Window_ChoiceList.prototype.updatePlacement = function() {
        this.resetLayout();
        _Window_ChoiceList_updatePlacement.apply(this, arguments);
        if (this.isPopup()) this.updatePlacementPopup();
    };

    var _Window_ChoiceList_refresh = Window_ChoiceList.prototype.refresh;
    Window_ChoiceList.prototype.refresh = function() {
        this.resetLayout();
        _Window_ChoiceList_refresh.apply(this, arguments);
    };

    Window_ChoiceList.prototype.isPopup = function() {
        return this._messageWindow.isPopup();
    };

    var _Window_ChoiceList_numVisibleRows = Window_ChoiceList.prototype.numVisibleRows;
    Window_ChoiceList.prototype.numVisibleRows = function() {
        var result = _Window_ChoiceList_numVisibleRows.apply(this, arguments);
        if (this.isPopupLinkage()) {
            result = Math.min($gameMessage.choices().length, 8);
        }
        return result;
    };

    //=============================================================================
    // Window_NumberInput
    //  ポップアップする場合、メッセージウィンドウに連動して表示位置と余白を調整します。
    //=============================================================================
    var _Window_NumberInput_standardFontSize = Window_NumberInput.prototype.standardFontSize;
    Window_NumberInput.prototype.standardFontSize = function() {
        return this.isPopupLinkage() ? paramFontSize : _Window_NumberInput_standardFontSize.apply(this, arguments);
    };

    var _Window_NumberInput_standardPadding = Window_NumberInput.prototype.standardPadding;
    Window_NumberInput.prototype.standardPadding = function() {
        return this.isPopupLinkage() ? paramPadding : _Window_NumberInput_standardPadding.apply(this, arguments);
    };

    var _Window_NumberInput_lineHeight = Window_NumberInput.prototype.lineHeight;
    Window_NumberInput.prototype.lineHeight = function() {
        return this.isPopupLinkage() ? paramFontSize + 8 : _Window_NumberInput_lineHeight.apply(this, arguments);
    };

    var _Window_NumberInput_updatePlacement = Window_NumberInput.prototype.updatePlacement;
    Window_NumberInput.prototype.updatePlacement = function() {
        this.resetLayout();
        this.opacity = 255;
        _Window_NumberInput_updatePlacement.apply(this, arguments);
        if (this.isPopup()) this.updatePlacementPopup();
    };

    Window_NumberInput.prototype.isPopup = function() {
        return this._messageWindow.isPopup();
    };

    //=============================================================================
    // Window_NameBox
    //  メッセージウィンドウに連動して表示位置と余白を調整します。
    //=============================================================================
    if (typeof Window_NameBox !== 'undefined') {
        var _Window_NameBox_standardFontSize = Window_NameBox.prototype.standardFontSize;
        Window_NameBox.prototype.standardFontSize = function() {
            return this.isPopupLinkage() ? paramFontSize : _Window_NameBox_standardFontSize.apply(this, arguments);
        };

        var _Window_NameBox_standardPadding = Window_NameBox.prototype.standardPadding;
        Window_NameBox.prototype.standardPadding = function() {
            return this.isPopupLinkage() ? paramPadding : _Window_NameBox_standardPadding.apply(this, arguments);
        };

        var _Window_NameBox_lineHeight = Window_NameBox.prototype.lineHeight;
        Window_NameBox.prototype.lineHeight = function() {
            return this.isPopupLinkage() ? paramFontSize + 8 : _Window_NameBox_lineHeight.apply(this, arguments);
        };

        var _Window_NameBox_updatePlacement = Window_NameBox.prototype.updatePlacement;
        Window_NameBox.prototype.updatePlacement = function() {
            this.resetLayout();
            _Window_NameBox_updatePlacement.apply(this, arguments);
            if (this.isPopup()) this.updatePlacementPopup();
        };

        var _Window_NameBox_refresh = Window_NameBox.prototype.refresh;
        Window_NameBox.prototype.refresh = function() {
            this.resetLayout();
            return _Window_NameBox_refresh.apply(this, arguments);
        };

        Window_NameBox.prototype.isPopup = function() {
            return this._parentWindow.isPopup();
        };

        Window_NameBox.prototype.updatePlacementPopup = function() {
            this.x = this._parentWindow.x;
            this.y = this._parentWindow.y - this.height;
        };
    }

    //=============================================================================
    // ウィンドウを透過して重なり合ったときの表示を自然にします。
    //=============================================================================
    if (paramThroughWindow && !WindowLayer.throughWindow) {
        WindowLayer.throughWindow = true;
        //=============================================================================
        //  WindowLayer
        //   ウィンドウのマスク処理を除去します。
        //=============================================================================
        WindowLayer.prototype._maskWindow = function(window) {};

        WindowLayer.prototype._canvasClearWindowRect = function(renderSession, window) {};
    }
})();


code:
//=============================================================================
// MovieManager.js
// ----------------------------------------------------------------------------
// (C)2015 Triacontane
// This software is released under the MIT License.
// http://opensource.org/licenses/mit-license.php
// ----------------------------------------------------------------------------
// Version
// 1.0.4 2018/03/28 ムービー再生後、ロード完了前にムービーを停止するとムービーが停止されない問題を修正
// 1.0.3 2018/03/27 Saba_SimpleScenario.jsとの競合を解消（こちらの設定で上書き）
// 1.0.2 2018/01/30 ヘルプの記述を修正
// 1.0.1 2016/06/24 メニューを開いたときに最後に表示していたムービーが写り込む不具合を修正
// 1.0.0 2016/06/09 初版
// ----------------------------------------------------------------------------
// [Blog]   : https://triacontane.blogspot.jp/
// [Twitter]: https://twitter.com/triacontane/
// [GitHub] : https://github.com/triacontane/
//=============================================================================

/*:
 * @plugindesc 動画管理プラグイン
 * @author トリアコンタン
 *
 * @help イベントコマンド「ムービーの再生」で再生できる動画をピクチャのように
 * コントロールできるようになります。
 * 座標や拡大率はもちろん、ループ可否や再生速度を自由に調整可能です。
 * イベントコマンド「ムービーの再生」後に以下のプラグインコマンドを実行します。
 * （大抵のコマンドは「ムービーの再生」前でも機能しますが「MM_ウェイト」のみ
 * 　「ムービーの再生」前では機能しません）
 *
 * プラグインコマンド詳細
 *  イベントコマンド「プラグインコマンド」から実行。
 *  （パラメータの間は半角スペースで区切る）
 *
 * すべてのプラグインコマンドはムービーが再生中でなくても有効です。
 *
 * MM_移動_座標 [X座標] [Y座標] [移動時間(f)] [待ちフラグ(ON/OFF)]
 *  ムービーの表示座標を時間を掛けて変更します。
 *  下記の例は、座標[100:100]に[60]フレーム掛けて移動し、処理中はウェイトします。
 *  ex:MM_移動_座標 100 100 60 ON
 *
 * MM_移動_拡大率 [X拡大率(100%)] [Y拡大率(100%)] [時間(f)] [待ちフラグ(ON/OFF)]
 *  ムービーの拡大率を時間を掛けて変更します。
 *  下記の例は、縦横の拡大率を[50%]に60フレーム掛けて縮小し、
 *  処理中はウェイトしません。
 *  ex:MM_移動_拡大率 50 50 60
 *
 * MM_移動_不透明度 [不透明度(0-256)] [時間(f)] [ウェイトフラグ(ON/OFF)]
 *  ムービーの不透明度を時間を掛けて変更します。
 *  下記の例は、不透明度が変数[1]の値に即座に変更されます。
 *  ex:MM_移動_不透明度 \v[1] 0 ON
 *
 * MM_設定_再生速度 [再生速度(標準:1.0)]
 *  ムービーの再生速度倍率を変更します。
 *  下記の例は、再生速度が1.5倍になります。
 *  ex:MM_設定_再生速度 1.5
 *
 * MM_設定_再生位置 [再生位置(S)]
 *  ムービーの再生位置を変更します。
 *  ただしChromeの場合ロードしていない位置に移動すると再生が終了してしまうため
 *  使用には注意が必要です。(2016/06/12時点での最新版で確認)
 *  下記の例は、100秒目の再生位置にジャンプします。
 *  ex:MM_設定_再生位置 100
 *
 * MM_設定_画面に合わせる [設定値(ON/OFF)]
 *  ONにすると拡大率が100%の状態でムービーのサイズが画面にフィットするように
 *  調整されます。OFFにすると元の動画ファイルのサイズに合わせます。
 *  ex:MM_設定_画面に合わせる ON
 *
 * MM_設定_ループ [設定値(ON/OFF)]
 *  ONにすると、再生終了後に最初からループ再生します。
 *  ex:MM_設定_ループ ON
 *
 * MM_一時停止
 *  再生を一時停止します。
 *  ex:MM_一時停止
 *
 * MM_再生
 *  一時停止した状態から再生します。初回はイベントコマンドだけで再生されるので
 *  このコマンドの実行は不要です。
 *  ex:MM_再生
 *
 * MM_停止
 *  再生を終了してムービーを消去します。
 *  ex:MM_停止
 *
 * MM_ウェイト
 *  ムービーの再生が終了するまでイベント実行を待機します。
 *  ループ再生している場合はゲームの進行が停止するので注意してください。
 *  このコマンドはイベント「ムービーの再生」の直後に実行してください。
 *  ex:MM_ウェイト
 *
 * スクリプトコマンド詳細
 *
 * MovieManager.isPlaying();
 * ムービーが再生中の場合にtrueを返します。
 *
 * 制約事項
 * 現状、ムービーの表示状態はセーブできません。
 *
 * 利用規約：
 *  作者に無断で改変、再配布が可能で、利用形態（商用、18禁利用等）
 *  についても制限はありません。
 *  このプラグインはもうあなたのものです。
 */

/**
 * 動画管理モジュールです。
 * @constructor
 */
function MovieManager() {
    throw new Error('This is a static class');
}

(function() {
    'use strict';
    var metaTagPrefix = 'MM_';

    var getCommandName = function(command) {
        return (command || '').toUpperCase();
    };

    var getArgFloat = function(arg, min, max) {
        if (arguments.length < 2) min = -Infinity;
        if (arguments.length < 3) max = Infinity;
        return (parseFloat(convertEscapeCharactersAndEval(arg, true)) || 0).clamp(min, max);
    };

    var getArgNumber = function(arg, min, max) {
        if (arguments.length < 2) min = -Infinity;
        if (arguments.length < 3) max = Infinity;
        return (parseInt(convertEscapeCharactersAndEval(arg, true), 10) || 0).clamp(min, max);
    };

    var getArgBoolean = function(arg) {
        return (arg || '').toUpperCase() === 'ON';
    };

    var convertEscapeCharactersAndEval = function(text, evalFlg) {
        if (text === null || text === undefined) {
            text = evalFlg ? '0' : '';
        }
        var windowLayer = SceneManager._scene._windowLayer;
        if (windowLayer) {
            var result = windowLayer.children[0].convertEscapeCharacters(text);
            return evalFlg ? eval(result) : result;
        } else {
            return text;
        }
    };

    //=============================================================================
    // Bitmap
    //  キャプチャに表示中のムービーを含めます。
    //=============================================================================
    var _Bitmap_snap = Bitmap.snap;
    Bitmap.snap      = function(stage) {
        var bitmap = _Bitmap_snap.apply(this, arguments);
        if (Graphics.isVideoPlaying()) {
            var video  = Graphics.getVideo();
            bitmap.context.drawImage(video, video.x, video.y, video.width, video.height);
        }
        return bitmap;
    };

    //=============================================================================
    // Graphics
    //  ムービー再生に必要なタグを動的に生成します。
    //=============================================================================
    Graphics._videoScaleFitScreen = false;

    Graphics._createVideo = function() {
        this._videoFrame    = document.createElement('div');
        this._videoFrame.id = 'GameVideoFrame';
        this._video         = document.createElement('video');
        this._video.id      = 'GameVideo';
        this._videoVisible  = false;
        document.body.appendChild(this._videoFrame);
        this._videoFrame.appendChild(this._video);
        this.setVideoContentsPosition(0, 0);
        this.setVideoContentsScale(1.0, 1.0);
        this._updateVideo();
        this._centerElement(this._video);
        this._video.style.margin = 0;
        this._videoLoading       = false;
    };

    Graphics.getVideo = function() {
        return this._video;
    };

    var _Graphics_playVideo = Graphics.playVideo;
    Graphics.playVideo      = function(src) {
        _Graphics_playVideo.apply(this, arguments);
        this._videoLoading = true;
    };

    Graphics.stopVideo = function() {
        if (!this._isVideoVisible() && this.isVideoLoading()) {
            this._needVideoStop = true;
        }
        this._video.pause();
        this._updateVisibility(false);
    };

    Graphics.setVisibleMovie = function(value) {
        this._videoFrame.style.visibility = (value ? 'visible' : 'hidden');
    };

    Graphics.setVideoScaleFitScreen = function(value) {
        this._videoScaleFitScreen = value;
        this.setVideoContentsScale(this._video.scaleX, this._video.scaleY);
    };

    var _Graphics_isVideoPlaying = Graphics.isVideoPlaying;
    Graphics.isVideoPlaying      = function() {
        return _Graphics_isVideoPlaying.apply(this, arguments) || this.isVideoLoading();
    };

    Graphics.isVideoLoading = function() {
        return this._videoLoading;
    };

    Graphics._updateVisibility = function(videoVisible) {
        this._videoVisible           = videoVisible;
        this._video.style.visibility = (videoVisible ? 'visible' : 'hidden');
        this._videoLoading           = false;
    };

    Graphics._isVideoVisible = function() {
        return this._videoVisible;
    };

    var _Graphics__onVideoLoad = Graphics._onVideoLoad;
    Graphics._onVideoLoad      = function() {
        _Graphics__onVideoLoad.apply(this, arguments);
        if (this._needVideoStop) {
            this._needVideoStop = false;
            this.stopVideo();
        } else {
            this.setVideoContentsScale(this._video.scaleX, this._video.scaleY);
        }
    };

    var _Graphics__updateVideo = Graphics._updateVideo;
    Graphics._updateVideo      = function() {
        var prevVideo = this._video;
        this._video   = this._videoFrame;
        _Graphics__updateVideo.apply(this, arguments);
        this._video = prevVideo;
        this._updateVideoContents();
    };

    Graphics.setVideoContentsPosition = function(x, y) {
        this._video.x = x;
        this._video.y = y;
        this._updateVideoContents();
    };

    Graphics.setVideoContentsScale = function(scaleX, scaleY) {
        this._video.scaleX = scaleX;
        this._video.scaleY = scaleY;
        this._video.width  = (this._videoScaleFitScreen ? this._width : this._video.videoWidth) * scaleX;
        this._video.height = (this._videoScaleFitScreen ? this._height : this._video.videoHeight) * scaleY;
        this._updateVideoContents();
    };

    Graphics._updateVideoContents = function() {
        var video          = this._video;
        video.style.width  = video.width * this._realScale + 'px';
        video.style.height = video.height * this._realScale + 'px';
        video.style.left   = video.x * this._realScale + 'px';
        video.style.top    = video.y * this._realScale + 'px';
    };

    //=============================================================================
    // Game_Interpreter
    //  プラグインコマンドを追加定義します。
    //=============================================================================
    var _Game_Interpreter_pluginCommand      = Game_Interpreter.prototype.pluginCommand;
    Game_Interpreter.prototype.pluginCommand = function(command, args) {
        _Game_Interpreter_pluginCommand.apply(this, arguments);
        if (!command.match(new RegExp('^' + metaTagPrefix))) return;
        this.pluginCommandMovieManager(command.replace(metaTagPrefix, ''), args);
    };

    Game_Interpreter.prototype.pluginCommandMovieManager = function(command, args) {
        var waitTime = 0;
        switch (getCommandName(command)) {
            case '設定_ループ':
            case 'SETTING_LOOP':
                MovieManager.setLoop(getArgBoolean(args[0]));
                break;
            case '設定_画面に合わせる':
            case 'SETTING_FIT_SCREEN':
                MovieManager.setScaleFitScreen(getArgBoolean(args[0]));
                break;
            case '設定_再生速度':
            case 'SETTING_PLAY_RATE':
                MovieManager.setPlaybackRate(getArgFloat(args[0], 0));
                break;
            case '設定_再生位置':
            case 'SETTING_CURRENT_TIME':
                MovieManager.setCurrentTime(getArgFloat(args[0], 0));
                break;
            case '移動_不透明度':
            case 'MOVE_OPACITY':
                waitTime = getArgNumber(args[1], 0);
                MovieManager.moveOpacity(getArgNumber(args[0], 0, 256), waitTime);
                if (getArgBoolean(args[2])) this.wait(waitTime);
                break;
            case '移動_座標':
            case 'MOVE_POSITION':
                waitTime = getArgNumber(args[2], 0);
                MovieManager.movePosition(getArgNumber(args[0]), getArgNumber(args[1]), waitTime);
                if (getArgBoolean(args[3])) this.wait(waitTime);
                break;
            case '移動_拡大率':
            case 'MOVE_SCALE':
                waitTime = getArgNumber(args[2], 0);
                MovieManager.moveScale(getArgNumber(args[0]), getArgNumber(args[1]), waitTime);
                if (getArgBoolean(args[3])) this.wait(waitTime);
                break;
            case '停止':
            case 'STOP':
                MovieManager.stop();
                break;
            case 'ウェイト':
            case 'WAIT':
                this.setWaitMode('video');
                break;
            case '一時停止':
            case 'PAUSE':
                MovieManager.pause();
                break;
            case '再生':
            case 'PLAY':
                MovieManager.play();
                break;
        }
    };

    var _Game_Interpreter_command261      = Game_Interpreter.prototype.command261;
    Game_Interpreter.prototype.command261 = function() {
        var result = _Game_Interpreter_command261.apply(this, arguments);
        this._waitMode = '';
        $gameTemp.sabaWaitForMovieMode = 0;
        return result;
    };

    var _Game_Interpreter_command354 = Game_Interpreter.prototype.command354;
    Game_Interpreter.prototype.command354 = function() {
        MovieManager.stop();
        return  _Game_Interpreter_command354.apply(this, arguments);
    };

    //=============================================================================
    // SceneManager
    //  動画管理モジュールを操作します。
    //=============================================================================
    var _SceneManager_initialize = SceneManager.initialize;
    SceneManager.initialize      = function() {
        _SceneManager_initialize.apply(this, arguments);
        MovieManager.initTarget();
    };

    var _SceneManager_updateScene = SceneManager.updateScene;
    SceneManager.updateScene      = function() {
        _SceneManager_updateScene.apply(this, arguments);
        MovieManager.update();
    };

    //=============================================================================
    // MovieManager
    //  動画管理モジュールです。
    //=============================================================================
    MovieManager.initTarget = function() {
        this._targetX          = this.getPositionX();
        this._targetY          = this.getPositionY();
        this._durationPosition = 0;
        this._targetScaleX     = this.getScaleX();
        this._targetScaleY     = this.getScaleY();
        this._durationScale    = 0;
        this._targetOpacity    = this.getOpacity();
        this._durationOpacity  = 0;
    };

    MovieManager.update = function() {
        this.updatePosition();
        this.updateScale();
        this.updateOpacity();
    };

    MovieManager.updatePosition = function() {
        if (this._durationPosition > 0) {
            var x = this.getPositionX();
            var y = this.getPositionY();
            var d = this._durationPosition;
            x     = (x * (d - 1) + this._targetX) / d;
            y     = (y * (d - 1) + this._targetY) / d;
            this.setPosition(x, y);
            this._durationPosition--;
        }
    };

    MovieManager.updateScale = function() {
        if (this._durationScale > 0) {
            var sx = this.getScaleX();
            var sy = this.getScaleY();
            var d  = this._durationScale;
            sx     = (sx * (d - 1) + this._targetScaleX) / d;
            sy     = (sy * (d - 1) + this._targetScaleY) / d;
            this.setScale(sx, sy);
            this._durationScale--;
        }
    };

    MovieManager.updateOpacity = function() {
        if (this._durationOpacity > 0) {
            var opacity = this.getOpacity();
            var d       = this._durationOpacity;
            opacity     = (opacity * (d - 1) + this._targetOpacity) / d;
            this.setOpacity(opacity);
            this._durationOpacity--;
        }
    };

    MovieManager.getVideo = function() {
        return Graphics.getVideo();
    };

    MovieManager.isPlaying = function() {
        return Graphics._isVideoVisible();
    };

    MovieManager.play = function() {
        if (!Graphics.isVideoLoading()) {
            this.getVideo().play();
        }
    };

    MovieManager.pause = function() {
        this.getVideo().pause();
    };

    MovieManager.stop = function() {
        Graphics.stopVideo();
        this.initTarget();
    };

    MovieManager.setLoop = function(value) {
        this.getVideo().loop = !!value;
    };

    MovieManager.getLoop = function() {
        return this.getVideo().loop;
    };

    MovieManager.setScaleFitScreen = function(value) {
        Graphics.setVideoScaleFitScreen(!!value);
    };

    MovieManager.setCurrentTime = function(value) {
        this.getVideo().currentTime = value;
    };

    MovieManager.getCurrentTime = function() {
        return this.getVideo().currentTime;
    };

    MovieManager.setPlaybackRate = function(value) {
        this.getVideo().playbackRate = value;
    };

    MovieManager.getPlaybackRate = function() {
        return this.getVideo().playbackRate;
    };

    MovieManager.moveOpacity = function(opacity, duration) {
        if (duration === 0) {
            this.setOpacity(opacity);
        } else {
            this._targetOpacity   = opacity;
            this._durationOpacity = duration;
        }
    };

    MovieManager.setOpacity = function(opacity) {
        var realOpacity = opacity / 256;
        if (realOpacity !== this.getOpacity()) {
            this.getVideo().style.opacity = String(realOpacity);
        }
    };

    MovieManager.getOpacity = function() {
        return this.getVideo().style.opacity * 256;
    };

    MovieManager.moveScale = function(scaleX, scaleY, duration) {
        if (duration === 0) {
            this.setScale(scaleX, scaleY);
        } else {
            this._targetScaleX  = scaleX;
            this._targetScaleY  = scaleY;
            this._durationScale = duration;
        }
    };

    MovieManager.setScale = function(scaleX, scaleY) {
        if (scaleX !== this.getScaleX() || scaleY !== this.getScaleY()) {
            Graphics.setVideoContentsScale(scaleX / 100, scaleY / 100);
        }
    };

    MovieManager.getScaleX = function() {
        return this.getVideo().scaleX * 100;
    };

    MovieManager.getScaleY = function() {
        return this.getVideo().scaleY * 100;
    };

    MovieManager.movePosition = function(x, y, duration) {
        if (duration === 0) {
            this.setPosition(x, y);
        } else {
            this._targetX          = x;
            this._targetY          = y;
            this._durationPosition = duration;
        }
    };

    MovieManager.setPosition = function(x, y) {
        if (this.getPositionX() !== x || this.getPositionY() !== y) {
            Graphics.setVideoContentsPosition(x, y);
        }
    };

    MovieManager.getPositionX = function() {
        return this.getVideo().x;
    };

    MovieManager.getPositionY = function() {
        return this.getVideo().y;
    };
})();

repo_name: voidljb/karryn

license: unknown


code:
//=============================================================================
// NeMV - Tags
// NeMV_Tags.js
//=============================================================================

var Imported = Imported || {};
Imported.NeMV_Tags = true;

var NeMV = NeMV || {};
NeMV.Tags = NeMV.Tags || {};

//=============================================================================
 /*:
 * @plugindesc v1.3.1 Allows objects and events to be tagged and those tags to be easily retrieved and manipulated via script.
 * @author Nekoyoubi
 *
 * @help
 * ============================================================================
 * Introduction
 * ============================================================================
 *
 * This plugin allows actors, enemies, classes, skills, states, items, weapons,
 * armors, and events to be tagged and those tags to be easily retrieved via
 * script.
 *
 * ============================================================================
 * Usage
 * ============================================================================
 *
 * Add a tag to your actor, class, enemy, item, weapon, armor, or event as
 * below. Multiple tags per entry can be separated by whitespace or commas, and tags
 * are case insensitive. Add tags to events via the Comment event command.
 *
 * <Tags: Plant>
 *
 * ... or...
 *
 * <TAGS: root, red, alchemy>
 *
 * ... or...
 *
 * <tags: BOSS FIRERESIST EXTRAGOLD>
 *
 * ----------------------------------------------------------------------------
 *
 * Once your tags are added, they can be accessed in almost any location via:
 *
 * [Object].hasTag("plant")
 *
 * ... or wild-card the tag with an asterisk to get partial matches...
 *
 * [Object].hasTag("extra*")
 *
 * This will return a boolean result indicating whether your object contains
 * that tag (or any tag that matches your wild-card search) or not.
 *
 * Tags can also be added and removed programmatically by calling either:
 *
 * [Object].addTag("good")
 *
 * ... or...
 *
 * [Object].removeTag("bad")
 *
 * Removing a tag that does not exist will NOT throw an error.
 *
 * Tag addition and removal with these methods may be deprecated in the future.
 *
 * Events Note: Due to the volatile nature of events, adding and removing tags
 * dynamically is not currently possible. Tags on events do change between
 * the events pages; they simply cannot be addTag()/removeTag()'d.
 *
 * ----------------------------------------------------------------------------
 *
 * A couple of utility methods have also been added to allow you to quickly
 * scan the party for tags on items they either possess or have equipped, or
 * tags on states they may have active.
 *
 * NeMV.Tags.partyItemsWithTag("magical")
 *
 * ... will return true if the party possesses any items tagged as "magical".
 *
 * NeMV.Tags.partyStatesWithTag("weapon")
 *
 * ... will return true if a party actor has a state tagged as "weapon".
 *
 * NeMV.Tags.eventsWithTag("harvestable")
 *
 * ... will return a collection of Game_Event objects tagged as "harvestable".
 *
 * ============================================================================
 * Support
 * ============================================================================
 *
 * Compatibility with YEP - Item Core exists to a degree, but may require
 * additional effort when checking specific items. It's always advisable to
 * use...
 *
 * DataManager.getBaseItem(item)
 *
 * ... if you are using YEP - Item Core.
 *
 * Should this plugin not work for you for any reason, please notify me by
 * creating a Github issue, emailing me at lance-at-nekoyoubi.com, or message
 * me in any social convention you happen to see me in.
 *
 * Thanks, and happy tagging!
 *
 * ============================================================================
 * Changelog
 * ============================================================================
 *
 * Version 1.3.1:
 * - re-fixed the previously fixed bug that was ever so recently unfixed
 * - deprecated old utility methods
 *
 * Version 1.3.0:
 * - moved event tagging off of underlying event and put it on Game_Event
 * - corrected improper event page tagging issues
 *
 * Version 1.2.3:
 * - added better event loading after issues with some blank states
 *
 * Version 1.2.2:
 * - added EventsThatHaveTag() utility method
 *
 * Version 1.2.1:
 * - fixed up event tagging a bit
 *
 * Version 1.2.0:
 * - added event tagging!
 *
 * Version 1.1.1:
 * - added Game_Item protos
 * - reorderd object additions
 *
 * Version 1.1.0:
 * - added wild-card searches on .hasTag()
 *
 * Version 1.0.0:
 * - initial plugin
 *
 */
//=============================================================================

// INITIALIZATION -------------------------------------------------------------

NeMV.Tags.init = function() {
	if ($dataActors !== null && $dataActors !== undefined) this.processNotetags($dataActors);
	if ($dataEnemies !== null && $dataEnemies !== undefined) this.processNotetags($dataEnemies);
	if ($dataClasses !== null && $dataClasses !== undefined) this.processNotetags($dataClasses);
	if ($dataSkills !== null && $dataSkills !== undefined) this.processNotetags($dataSkills);
	if ($dataStates !== null && $dataStates !== undefined) this.processNotetags($dataStates);
	if ($dataItems !== null && $dataItems !== undefined) this.processNotetags($dataItems);
	if ($dataWeapons !== null && $dataWeapons !== undefined) this.processNotetags($dataWeapons);
	if ($dataArmors !== null && $dataArmors !== undefined) this.processNotetags($dataArmors);
};

NeMV.Tags.processNotetags = function(data) {
	var tagsRegex = /<(?:TAGS):[ ](.*)>/i;
	for (var n = 1; n < data.length; n++) {
		var obj = data[n];
		if (obj === null || obj === undefined) continue;
		obj.tags = obj.tags || [];
		var notelines = obj.note.split(/[\r\n]+/);
		obj.hasTag = function(tag) {
			return NeMV.Tags.baseHasTag(tag, this.tags);
		};
		obj.removeTag = function(tag) {
			var index = this.tags.indexOf(tag.toUpperCase());
			if (index > -1) this.tags.splice(index, 1);
		};
		obj.addTag = function(tag) {
			this.removeTag(tag.toUpperCase());
			this.tags.push(tag.toUpperCase());
		};
		for (var i = 0; i < notelines.length; i++) {
			var line = notelines[i];
			lineMatch = line.match(tagsRegex);
			if (lineMatch) {
				var tagData = lineMatch[1].toUpperCase().match(/\w+/gi);
	    		obj.tags = obj.tags.concat(tagData);
			}
		}
	}
};

// BASE METHODS ---------------------------------------------------------------

NeMV.Tags.baseHasTag = function(tag, tags) {
	for (var t = 0; t < tags.length; t++) {
		tag = tag.toUpperCase();
		var regex = "^"+tag+"$";
		if (tag.indexOf("*") >= 0) {
			if (tag.charAt(0) == "*") {
				regex = tag.replace("*","")+"$";
			} else if (tag.charAt(tag.length-1) == "*") {
				regex = "^"+tag.replace("*","");
			} else {
				regex = "^"+tag.replace("*","\\w*")+"$";
			}
		}
		var currentTag = tags[t].toUpperCase();
		var exp = new RegExp(regex, "i");
		if (exp.exec(currentTag) !== null)
			return true;
	}
	return false;
};

NeMV.Tags.baseEventSetup = function(gameEvent) {
	if (gameEvent === null ||
		gameEvent === undefined ||
		gameEvent.event === undefined) return;
	var e = gameEvent.event();
	gameEvent.tags = [];
	gameEvent.hasTag = function(tag) {
		return NeMV.Tags.baseHasTag(tag, this.tags);
	};
	gameEvent.removeTag = function(tag) {
		var index = this.tags.indexOf(tag.toUpperCase());
		if (index > -1) this.tags.splice(index, 1);
	};
	gameEvent.addTag = function(tag) {
		this.removeTag(tag.toUpperCase());
		this.tags.push(tag.toUpperCase());
	};
	if (gameEvent.page() && gameEvent.list()) {
		for (var l = 0; l < gameEvent.list().length; l++) {
			if (gameEvent.list()[l].code == 108) {
				var tagLine = gameEvent.list()[l].parameters[0].toUpperCase().match(/<TAGS:[ ](.+)>/gi);
				if (tagLine !== null && tagLine !== undefined) {
					var tagData = tagLine[0].match(/<TAGS:[ ](.+)>/i)[1].match(/\w+/gi);
					gameEvent.tags = tagData;
				}
			}
		}
	}
};

// OVERRIDES ------------------------------------------------------------------

NeMV.Tags.Scene_Boot_terminate = Scene_Boot.prototype.terminate;
Scene_Boot.prototype.terminate = function() {
	NeMV.Tags.Scene_Boot_terminate.call(this);
	NeMV.Tags.init();
};

// UTILITIES ------------------------------------------------------------------

NeMV.Tags.partyItemsWithTag = function(tag) {
	if (Imported.YEP_ItemCore) {
		return $gameParty._actors.reduce(function(a,b) {
			return $gameActors.actor(b)._equips.reduce(function(c,d) {
				return c || ((d.object() !== null) ? DataManager.getBaseItem(d.object()).hasTag(tag) : false);
			},a);
		}, false) ||
		$gameParty.equipItems().reduce(function(e,f) {
			return e || DataManager.getBaseItem(f).hasTag(tag);
		}, false) ||
		$gameParty.items().reduce(function(g,h) {
			return g || DataManager.getBaseItem(h).hasTag(tag);
		}, false);
	} else {
		return $gameParty._actors.reduce(function(a,b) {
			return $gameActors.actor(b)._equips.reduce(function(c,d) {
				return c || ((d.object() !== null) ? d.object().hasTag(tag) : false);
			},a);
		}, false) ||
		$gameParty.equipItems().reduce(function(e,f) {
			return e || f.hasTag(tag);
		}, false) ||
		$gameParty.items().reduce(function(g,h) {
			return g || h.hasTag(tag);
		}, false);
	}
};

NeMV.Tags.partyStatesWithTag = function(tag) {
	return $gameParty._actors.reduce(function(a,b) {
		return $gameActors.actor(b).states().reduce(function(c,d) {
			return c||d.hasTag(tag);}, a);
	}, false);
};

NeMV.Tags.eventsWithTag = function(tag) {
	var events = [];
	$gameMap.events().forEach(function(e) {
		if (e.hasTag(tag))
			events.push(e);
	});
	if (events.length === 0) return null;
	else return events;
};

// deprecated; please use new methods
NeMV.Tags.AnyItemsHaveTag = NeMV.Tags.partyItemsWithTag;
NeMV.Tags.AnyPartyStatesHaveTag = NeMV.Tags.partyStatesWithTag;
NeMV.Tags.EventsThatHaveTag = NeMV.Tags.eventsWithTag;

// ENEMY PROTO ----------------------------------------------------------------

Game_Enemy.prototype.hasTag = function(tag) {
	return NeMV.Tags.baseHasTag(tag, this.enemy().tags);
};

Game_Enemy.prototype.removeTag = function(tag) {
	var index = this.enemy().tags.indexOf(tag.toUpperCase());
	if (index > -1) this.enemy().tags.splice(index, 1);
};

Game_Enemy.prototype.addTag = function(tag) {
	this.enemy().removeTag(tag.toUpperCase());
	this.enemy().tags.push(tag.toUpperCase());
};

// ACTOR PROTO ----------------------------------------------------------------

Game_Actor.prototype.hasTag = function(tag) {
	return NeMV.Tags.baseHasTag(tag, this.actor().tags);
};

Game_Actor.prototype.removeTag = function(tag) {
	var index = this.actor().tags.indexOf(tag.toUpperCase());
	if (index > -1) this.actor().tags.splice(index, 1);
};

Game_Actor.prototype.addTag = function(tag) {
	this.actor().removeTag(tag.toUpperCase());
	this.actor().tags.push(tag.toUpperCase());
};

// ITEM PROTO ----------------------------------------------------------------

Game_Item.prototype.hasTag = function(tag) {
	return NeMV.Tags.baseHasTag(tag, this.object().tags);
};

Game_Item.prototype.removeTag = function(tag) {
	var index = this.object().tags.indexOf(tag.toUpperCase());
	if (index > -1) this.object().tags.splice(index, 1);
};

Game_Item.prototype.addTag = function(tag) {
	this.object().removeTag(tag.toUpperCase());
	this.object().tags.push(tag.toUpperCase());
};

// EVENT PROTO ----------------------------------------------------------------

Game_Event.prototype.hasTag = function(tag) {
	return NeMV.Tags.baseHasTag(tag, this.event().tags);
};

// Game_Event.prototype.removeTag = function(tag) {
// 	var index = this.event().tags.indexOf(tag.toUpperCase());
// 	if (index > -1) this.event().tags.splice(index, 1);
// };
//
// Game_Event.prototype.addTag = function(tag) {
// 	this.event().removeTag(tag.toUpperCase());
// 	this.event().tags.push(tag.toUpperCase());
// };

NeMV.Tags.Game_Event_initialize = Game_Event.prototype.initialize;
Game_Event.prototype.initialize = function(mapId, eventId) {
	NeMV.Tags.Game_Event_initialize.call(this, mapId, eventId);
	NeMV.Tags.baseEventSetup(this);
};

NeMV.Tags.Game_Event_lock = Game_Event.prototype.lock;
Game_Event.prototype.lock = function() {
	NeMV.Tags.Game_Event_lock.call(this);
	NeMV.Tags.baseEventSetup(this);
};

NeMV.Tags.Game_Event_refresh = Game_Event.prototype.refresh;
Game_Event.prototype.refresh = function() {
	NeMV.Tags.Game_Event_refresh.call(this);
	NeMV.Tags.baseEventSetup(this);
};

// MAP PROTO ------------------------------------------------------------------

NeMV.Tags.Scene_Map_onMapLoaded = Scene_Map.prototype.onMapLoaded;
Scene_Map.prototype.onMapLoaded = function() {
	NeMV.Tags.Scene_Map_onMapLoaded.call(this);
	$gameMap.events().forEach(function(event) {
		NeMV.Tags.baseEventSetup(event);
	});
};


code:
//=============================================================================
// NeMV - Actor Equip Points
// NeMV_X_ActorEquipPoints.js
//=============================================================================

var Imported = Imported || {};
Imported.NeMV_ActorEquipPoints = true;

var NeMV = NeMV || {};
NeMV.Tags = NeMV.Tags || {};
NeMV.Tags.AEP = NeMV.Tags.AEP || {};

//=============================================================================
 /*:
 * @plugindesc v1.0.2 (Requires NeMV_Tags.js & YEP_X_EquipRequirements.js) Provides a point-based equipment system with the help of NeMV Tags and YEP - Equip Requirements.
 * @author Nekoyoubi
 *
 * @param --- Equipment Tags ---
 * @default
 *
 * @param Equipment Tag 1
 * @desc Define the type, tag to be counted, and its value.
 * Format: type tag variable (e.g. "gear chest 4")
 * @default gear chest 4
 *
 * @param Equipment Tag 2
 * @desc Define the type, tag to be counted, and its value.
 * Format: type tag variable (e.g. "gear helm 2")
 * @default gear helm 2
 *
 * @param Equipment Tag 3
 * @desc Define the type, tag to be counted, and its value.
 * Format: type tag variable (e.g. "bracers 2")
 * @default gear bracers 2
 *
 * @param Equipment Tag 4
 * @desc Define the type, tag to be counted, and its value.
 * Format: type tag variable (e.g. "gear twohand 4")
 * @default gear twohand 4
 *
 * @param Equipment Tag 5
 * @desc Define the type, tag to be counted, and its value.
 * Format: type tag variable (e.g. "gear onehand 2")
 * @default gear onehand 2
 *
 * @param Equipment Tag 6
 * @desc Define the type, tag to be counted, and its value.
 * Format: type tag variable (e.g. "gear bow 3")
 * @default gear bow 3
 *
 * @param Equipment Tag 7
 * @desc Define the type, tag to be counted, and its value.
 * Format: type tag variable (e.g. "gear boots 2")
 * @default gear boots 2
 *
 * @param Equipment Tag 8
 * @desc Define the type, tag to be counted, and its value.
 * Format: type tag variable (e.g. "gear shield 3")
 * @default gear shield 3
 *
 * @param Equipment Tag 9
 * @desc Define the type, tag to be counted, and its value.
 * Format: type tag variable (e.g. "gear dagger 1")
 * @default gear dagger 1
 *
 * @param Equipment Tag 10
 * @desc Define the type, tag to be counted, and its value.
 * Format: type tag variable (e.g. "gear quiver 1")
 * @default gear quiver 1
 *
 * @param Equipment Tags CSV
 * @desc CSV array of strings for more equipment tags counters.
 * Example: gear halberd 5, piety holysymbol 2, cursed voodoodoll 3
 * @default
 *
 * @param --- Misc. ---
 * @default
 *
 * @param Debug AEP
 * @desc Whether or not to output debug information for AEP.
 * Example: true (debug) or false (no debug)
 * @default false
 *
 * @help
 * ============================================================================
 * Introduction
 * ============================================================================
 *
 * This plugin provides a point-based equipment system with the help of
 * NeMV - Tags & YEP - Equip Requirements. It allows you to build an equipment
 * monitoring system, where when equipping and unequipping weapons and armor to
 * your actors, you can track that equipment based on tags. This can be used to
 * build a point-based equipment system, determine an encumbrance for your
 * actors, or even grant or deny skills, quests, event interactions, etc based
 * on the points associated to an actors tagged equipment.
 *
 * ============================================================================
 * Usage
 * ============================================================================
 *
 * First, configure the respective equipment entries in the plugin's parameters
 * as the default plugin parameters illustrate.
 *
 * Next, tag your equipment with the appropriate tags...
 *
 * Weapon  >  Notebox  >  <tags: twohand, sword, demonic>
 *
 * Armor  >  Notebox  >  <tags: shield, angelic, quest>
 *
 * Now add an equipment limiting tag to your actors. You will set the inital
 * maximum here, but this can be changed during the course of play via plugin
 * commands and scripts.
 *
 * Format:  <MAX TYPE POINTS: AMOUNT>
 *
 * Example:
 *
 * Actor  >  Notebox  >  <Max Gear Points: 10>
 *
 * Plugin Commands ------------------------------------------------------------
 *
 * AEP comes equipped with plugin commands for adding, removing, and manually
 * setting Equip Point tags. The format for these commands is as follows.
 *
 * AEP COMMAND TYPE TAG [ AMOUNT ]
 *
 * Examples:
 *
 * aep add gear buckler 2
 * aep remove gear buckler
 * aep set holy symbol 1
 * aep add gear necklace
 *
 * In the examples above, the first adds a new Gear-type entry with the tag
 * "buckler". The second removes the buckler from the Gear-type. This will not
 * remove buckler from any other types that may be watching for it though.
 * The third assumes that a Holy-type "symbol" tag is already setup, and sets
 * sets its point value to 1 going forward. The fourth example creates a new
 * Gear-type entry that defaults to a 0-point value.
 *
 * ============================================================================
 * Support
 * ============================================================================
 *
 * Should this plugin not work for you for any reason, please notify me by
 * creating a GitHub issue, emailing me at lance-at-nekoyoubi.com, or message
 * me in any social convention you happen to see me in.
 *
 * Thanks, and happy equipping!
 *
 * ============================================================================
 * Changelog
 * ============================================================================
 *
 * Version 1.0.2:
 * - fixed a bug where the available equip point threshold needed to be one below
 *
 * Version 1.0.1:
 * - removed unintentional YEP - Item Core requirement
 *
 * Version 1.0:
 * - initial plugin
 *
 */
//=============================================================================

// PARAMS ---------------------------------------------------------------------

if (true) { //PARAMS COLLAPSE
	NeMV.Tags.AEP.Parameters = PluginManager.parameters('NeMV_X_ActorEquipPoints');
	NeMV.Tags.AEP.Param = NeMV.Tags.AEP.Param || {};

	NeMV.Tags.AEP.Param.EquipPoints = [];
	NeMV.Tags.AEP.Param.EquipPoints.push(String(NeMV.Tags.AEP.Parameters['Equipment Tag 1']));
	NeMV.Tags.AEP.Param.EquipPoints.push(String(NeMV.Tags.AEP.Parameters['Equipment Tag 2']));
	NeMV.Tags.AEP.Param.EquipPoints.push(String(NeMV.Tags.AEP.Parameters['Equipment Tag 3']));
	NeMV.Tags.AEP.Param.EquipPoints.push(String(NeMV.Tags.AEP.Parameters['Equipment Tag 4']));
	NeMV.Tags.AEP.Param.EquipPoints.push(String(NeMV.Tags.AEP.Parameters['Equipment Tag 5']));
	NeMV.Tags.AEP.Param.EquipPoints.push(String(NeMV.Tags.AEP.Parameters['Equipment Tag 6']));
	NeMV.Tags.AEP.Param.EquipPoints.push(String(NeMV.Tags.AEP.Parameters['Equipment Tag 7']));
	NeMV.Tags.AEP.Param.EquipPoints.push(String(NeMV.Tags.AEP.Parameters['Equipment Tag 8']));
	NeMV.Tags.AEP.Param.EquipPoints.push(String(NeMV.Tags.AEP.Parameters['Equipment Tag 9']));
	NeMV.Tags.AEP.Param.EquipPoints.push(String(NeMV.Tags.AEP.Parameters['Equipment Tag 10']));
	NeMV.Tags.AEP.Param.EquipPoints = NeMV.Tags.AEP.Param.EquipPoints.concat(
		String(NeMV.Tags.AEP.Parameters['Equipment Tag CSV']).split(/\s*,\s*/)||[]);

	NeMV.Tags.AEP.Debug = eval(NeMV.Tags.AEP.Parameters['Debug AEP']);
}

// INITIALIZATION -------------------------------------------------------------

NeMV.Tags.AEP.EquipPoints = NeMV.Tags.AEP.EquipPoints || [];

NeMV.Tags.AEP.init = function() {
	for (var i = 0; i < this.Param.EquipPoints.length; i++) {
		var points = this.Param.EquipPoints[i].trim();
		if (points === null || points == 'undefined' || points === "") {
			this.Param.EquipPoints.splice(i, 1);
		} else {
			this.addEquipPoints(points);
		}
	}
	if ($dataActors !== null && $dataActors !== undefined) this.processNotetags($dataActors);
	if ($dataWeapons !== null && $dataWeapons !== undefined) this.processEquipment($dataWeapons);
	if ($dataArmors !== null && $dataArmors !== undefined) this.processEquipment($dataArmors);
};

NeMV.Tags.AEP.processEquipment = function(data) {
	for (var n = 1; n < data.length; n++) {
		var obj = data[n];
		if (obj !== null && obj !== undefined) {
			obj.getEquipPointsValue = function(type) {
				return NeMV.Tags.AEP.baseGetEquipPointsValue(type, this);
			};
		}
	}
};

NeMV.Tags.AEP.processNotetags = function(data) {
	var tagRegex = /<(?:MAX[ ](\w+)[ ]POINTS):\s*(\d+)>/i;
	for (var n = 1; n < data.length; n++) {
		var obj = data[n];
		if (obj === null || obj == 'undefined') continue;
		obj.maxEquipPoints = obj.maxEquipPoints || [];
		obj.getEquipPointsMax = function(type) {
			return NeMV.Tags.AEP.baseGetEquipPointsMax(type, this.maxEquipPoints);
		};
		obj.setEquipPointsMax = function(type, max) {
			return NeMV.Tags.AEP.baseSetEquipPointsMax(type, max, this.maxEquipPoints);
		};
		obj.getEquipPoints = function(type) {
			return NeMV.Tags.AEP.baseGetEquipPoints(type, this.id);
		};
		var notelines = obj.note.split(/[\r\n]+/);
		for (var i = 0; i < notelines.length; i++) {
			var line = notelines[i];
			lineMatch = line.match(tagRegex);
			if (lineMatch) {
				var type = lineMatch[1].toUpperCase();
				var max = Number(lineMatch[2]);
	    		obj.maxEquipPoints.push({ 'type' : type, 'max' : max });
			}
		}
	}
};

NeMV.Tags.AEP.Scene_Boot_terminate = Scene_Boot.prototype.terminate;
Scene_Boot.prototype.terminate = function() {
	NeMV.Tags.AEP.Scene_Boot_terminate.call(this);
	NeMV.Tags.AEP.init();
};

// BASE METHODS ---------------------------------------------------------------

NeMV.Tags.AEP.baseGetEquipPointsMax = function(type, array) {
	for (var i = 0; i < array.length; i++)
		if (array[i].type.toUpperCase() == type.toUpperCase())
			return array[i].max;
	return -1;
};

NeMV.Tags.AEP.baseSetEquipPointsMax = function(type, max, array) {
	for (var i = 0; i < array.length; i++) {
		if (array[i].type.toUpperCase() == type.toUpperCase()) {
			array[i].max = max;
			return;
		}
	}
};

NeMV.Tags.AEP.baseGetEquipPoints = function(type, actorId) {
	var actor = $gameActors.actor(actorId);
	var equips = actor._equips;
	var points = 0;
	for (var ep = 0; ep < this.EquipPoints.length; ep++) {
		for (var e = 0; e < equips.length; e++) {
			if (equips[e]._dataClass !== "" &&
				this.EquipPoints[ep].type.toUpperCase() == type.toUpperCase() &&
				equips[e].hasTag(this.EquipPoints[ep].tag)) {
				points += this.EquipPoints[ep].points;
			}
		}
	}
	return points;
};

NeMV.Tags.AEP.baseGetEquipPointsValue = function(type, item) {
	for (var ep = 0; ep < this.EquipPoints.length; ep++) {
		if (this.EquipPoints[ep].type.toUpperCase() == type.toUpperCase() &&
			item.hasTag(this.EquipPoints[ep].tag)) {
			return this.EquipPoints[ep].points;
		}
	}
	return 0;
};

// EQUIP POINT METHODS ------------------------------------------------------------

NeMV.Tags.AEP.addEquipPoints = function(points) {
	var split = points.split(/\s+/);
	this.EquipPoints.push({
		'type' : split[0].toUpperCase(),
		'tag' : split[1].toUpperCase(),
		'points' : (split.length > 2 && !isNaN(parseInt(split[2]))) ? Number(split[2]) : 0
	});
	if (this.Debug) console.log("AEP - Tag added: "+points);
};

NeMV.Tags.AEP.removeEquipPoints = function(tag) {
	var index = -1;
	for (var i = 0; i < this.EquipPoints.length; i++)
		if (this.EquipPoints[i].tag.toUpperCase() == tag.toUpperCase())
			index = i;
	if (index > -1) {
		this.EquipPoints.splice(index, 1);
		if (this.Debug) console.log("AEP - "+tag+" removed");
	} else {
		if (this.Debug) console.log("AEP - "+tag+" not found");
	}
};

NeMV.Tags.AEP.setEquipPoints = function(points) {
	var split = points.split(/\s+/);
	for (var i = 0; i < this.EquipPoints.length; i++) {
		if (this.EquipPoints[i].type.toUpperCase() == split[0].toUpperCase() &&
			this.EquipPoints[i].tag.toUpperCase() == split[1].toUpperCase()) {
			this.EquipPoints[i].points = (split.length > 2 && !isNaN(parseInt(split[2]))) ? Number(split[2]) : 0;
			if (this.Debug) console.log("AEP - Tag set: "+this.EquipPoints[i].type.toUpperCase()+":"+this.EquipPoints[i].tag.toUpperCase()+" to "+this.EquipPoints[i].points);
		}
	}
};

// PLUGIN COMMANDS ------------------------------------------------------------

NeMV.Tags.AEP.Game_Interpreter_pluginCommand = Game_Interpreter.prototype.pluginCommand;
Game_Interpreter.prototype.pluginCommand = function(command, args) {
	NeMV.Tags.AEP.Game_Interpreter_pluginCommand.call(this, command, args);
	if (command.toUpperCase() == "AEP") {
		var regex = /(?:AEP)\s(ADD|REMOVE|SET)\s(([a-z_-]+)\s([a-z_-]+)((?:\s)(\d+))?)/i;
		var data = (command+" "+args.join(" ")).toUpperCase().match(regex);
		if (data !== null) {
			var comm = data[1];
			var tagdata = data[2];
			var tag = data[3];
			var points = (data[5].length > 0) ? Number(data[5]) : 0;
			switch (comm.toUpperCase()) {
				case 'ADD':
					NeMV.Tags.AEP.addEquipPoints(tagdata);
					break;
				case 'REMOVE':
					NeMV.Tags.AEP.removeEquipPoints(tag);
					break;
				case 'SET':
					NeMV.Tags.AEP.setEquipPoints(tagdata);
					break;
			}
		}
	}
};

// EQUIP REQUIREMENTS INTEGRATION ---------------------------------------------

NeMV.Tags.AEP.getBaseItem = function(item) {
	return (Imported.YEP_ItemCore) ? DataManager.getBaseItem(item) : item;
};

if (Imported.YEP_X_EquipRequirements) {
	Game_BattlerBase.prototype.meetEquipPointsRequirements = function(item, currentItem) {
		var actor = this.actor();
		var baseItem = (item.hasTag === undefined) ? NeMV.Tags.AEP.getBaseItem(item) : item;

		var epa = NeMV.Tags.AEP.EquipPoints;
		var safe = true;
		for (var ep = 0; ep < epa.length; ep++) {
			if (baseItem.hasTag(epa[ep].tag) && actor.getEquipPointsMax(epa[ep].type) > -1) {
				var max = actor.getEquipPointsMax(epa[ep].type);
				var current = actor.getEquipPoints(epa[ep].type);
				var ipoints = baseItem.getEquipPointsValue(epa[ep].type);
				var cpoints = 0;
				if(currentItem != false) {
					cpoints = currentItem.getEquipPointsValue(epa[ep].type);
				}
				safe &= (max >= (current + ipoints - cpoints));
			}
		}
		return safe;
	};

	Game_BattlerBase.prototype.meetAllEquipRequirements = function(item, currentItem) {
		if (!item.equipRequirements) {
			if (item.baseItemId) {
				item.equipRequirements = NeMV.Tags.AEP.getBaseItem(item).equipRequirements;
			} else {
	    		return true;
	    	}
		}
		if (!this.meetEquipPointsRequirements(item, currentItem)) return false; // the only change in the override
		if (!this.meetEquipParamRequirements(item)) return false;
		if (!this.meetEquipClassRequirements(item)) return false;
		if (!this.meetEquipSkillRequirements(item)) return false;
		if (!this.meetEquipSwitchRequirements(item)) return false;
		if (!this.meetEquipUniqueRequirements(item)) return false;
		if (!this.meetEquipEvalRequirements(item)) return false;
		return true;
	};
}

// ACTOR PROTO ----------------------------------------------------------------

Game_Actor.prototype.getEquipPoints = function(type) {
	return NeMV.Tags.AEP.baseGetEquipPoints(type, this.actor().id);
};

Game_Actor.prototype.getEquipPointsMax = function(type) {
	return NeMV.Tags.AEP.baseGetEquipPointsMax(type, this.actor().maxEquipPoints);
};

// ITEM PROTO ----------------------------------------------------------------

Game_Item.prototype.getEquipPointsValue = function(type) {
	return NeMV.Tags.AEP.baseGetEquipPointsValue(type, this.object());
};