code:
//=============================================================================
// FastForwardCustomize.js
// ----------------------------------------------------------------------------
// Copyright (c) 2015-2017 Triacontane
// This software is released under the MIT License.
// http://opensource.org/licenses/mit-license.php
// ----------------------------------------------------------------------------
// Version
// 1.0.0 2017/07/01 初版
// ----------------------------------------------------------------------------
// [Blog]   : https://triacontane.blogspot.jp/
// [Twitter]: https://twitter.com/triacontane/
// [GitHub] : https://github.com/triacontane/
//=============================================================================

/*:
 * @plugindesc FastForwardCustomizePlugin
 * @author triacontane
 *
 * @param EventSpeedVariableId
 * @desc イベント高速化時の速度を取得する変数番号です。変数値が0なら高速化禁止、数値が大きくなると速度も速くなります。
 * @default 0
 * @type variable
 *
 * @help イベント高速化時の速度を調整できます。
 * 指定した変数の値によって高速化時の速度が変化します。
 * 変数値によって以下の通り変化します。
 * 0  : 高速化が禁止されます。
 * 1  : デフォルトの速度です。
 * 2- : 数値が高いほど高速になります。異常に高い値を設定すると処理落ちします。
 *
 * このプラグインにはプラグインコマンドはありません。
 *
 * This plugin is released under the MIT License.
 */
/*:ja
 * @plugindesc イベント高速化調整プラグイン
 * @author トリアコンタン
 *
 * @param イベント速度変数
 * @desc イベント高速化時の速度を取得する変数番号です。変数値が0なら高速化禁止、数値が大きくなると速度も速くなります。
 * @default 0
 * @type variable
 *
 * @help イベント高速化時の速度を調整できます。
 * 指定した変数の値によって高速化時の速度が変化します。
 * 変数値によって以下の通り変化します。
 * 0  : 高速化が禁止されます。
 * 1  : デフォルトの速度です。
 * 2- : 数値が高いほど高速になります。異常に高い値を設定すると処理落ちします。
 *
 * このプラグインにはプラグインコマンドはありません。
 *
 * 利用規約：
 *  作者に無断で改変、再配布が可能で、利用形態（商用、18禁利用等）
 *  についても制限はありません。
 *  このプラグインはもうあなたのものです。
 */

(function() {
    'use strict';
    var pluginName    = 'FastForwardCustomize';

    //=============================================================================
    // ローカル関数
    //  プラグインパラメータやプラグインコマンドパラメータの整形やチェックをします
    //=============================================================================
    var getParamString = 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 '';
    };

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

    //=============================================================================
    // パラメータの取得と整形
    //=============================================================================
    var param       = {};
    param.eventSpeedVariableId = getParamNumber(['EventSpeedVariableId', 'イベント速度変数']);

    var _Scene_Map_updateMainMultiply = Scene_Map.prototype.updateMainMultiply;
    Scene_Map.prototype.updateMainMultiply = function() {
        _Scene_Map_updateMainMultiply.apply(this, arguments);
        if (this.isFastForward()) {
            this.updateMainForMoreFast();
        }
    };

    Scene_Map.prototype.updateMainForMoreFast = function() {
        var updateCount = this.getFastSpeed() - 1;
        for (var i = 0; i < updateCount; i++) {
            this.updateMain();
        }
    };

    var _Scene_Map_isFastForward = Scene_Map.prototype.isFastForward;
    Scene_Map.prototype.isFastForward = function() {
        return _Scene_Map_isFastForward.apply(this, arguments) && this.getFastSpeed() > 0;
    };

    Scene_Map.prototype.getFastSpeed = function() {
        return param.eventSpeedVariableId > 0 ? $gameVariables.value(param.eventSpeedVariableId) : 1;
    };
})();


code:
//=============================================================================
// FileDownloader.js
// ----------------------------------------------------------------------------
// Copyright (c) 2016 Triacontane
// This software is released under the MIT License.
// http://opensource.org/licenses/mit-license.php
// ----------------------------------------------------------------------------
// Version
// 1.0.1 2016/12/04 少しコードをリファクタリング
// 1.0.0 2016/11/25 初版
// ----------------------------------------------------------------------------
// [Blog]   : http://triacontane.blogspot.jp/
// [Twitter]: https://twitter.com/triacontane/
// [GitHub] : https://github.com/triacontane/
//=============================================================================

/*:
 * @plugindesc FileDownloaderPlugin
 * @author triacontane
 *
 * @param NormalEndSwitch
 * @desc コマンドが正常終了した際にONになるスイッチIDです。
 * @default 0
 *
 * @param AbnormalEndSwitch
 * @desc コマンドが異常終了した際にONになるスイッチIDです。
 * @default 0
 *
 * @param ResourceUrl
 * @desc リソースの配布元URLです。特定の配布元からのダウンロードを簡略化できます。
 * @default https://raw.githubusercontent.com/triacontane/RPGMakerMV/master/
 *
 * @help ゲーム中にインターネット上からファイルをダウンロードして
 * プロジェクト配下の任意の場所に配置できます。同名ファイルは上書きされます。
 * 配置したファイルはゲーム中で動的に参照することができます。
 *
 * 主に以下のような用途に使用できます。
 *
 * 1. 開発時のプラグインの自動アップデート
 * ゲーム起動時に自動で配布元の最新版を適用できます。わざわざ確認しなくても
 * 機能追加やバグ修正が行われた最新のファイルを利用できます。
 *
 * ただし、すでに適用済みのプラグインを更新した場合、
 * 変更を反映させるにはゲームをリロードする必要があります。
 *
 * ※パラメータ「配布サイトURL」をデフォルトのままで
 * 以下のプラグインコマンドを実行すると、本プラグインを最新化できます。
 *
 * FD_MY_PLUGIN FileDownloader.js
 *
 * 2. 小規模なアップデートファイル配信
 * あらかじめ準備しておけば、プレイヤーにゲーム全体を再ダウンロードさせずに
 * 一部ファイルのみ差し替えさせることができます。
 *
 * 3. インターネット上の画像をピクチャ表示
 * ネット上の画像ファイルなどを取り込んでゲーム内で使用することができます。
 * 著作権等には十分ご注意ください。
 *
 * 注意！
 * 1. ダウンロードには非常に時間が掛かります。（特にWindowsの場合）
 *
 * 2. ファイルは確認なしに上書きされます。復元はできませんのでご注意ください。
 *
 * 3. サーバによっては拒否される場合もあります。
 *
 * 4. ローカル実行（テストプレー含む）以外では利用できません。
 *
 * また、おまけ機能で「指定したURLを既定のブラウザで開く」機能もあります。
 *
 * プラグインコマンド詳細
 *  イベントコマンド「プラグインコマンド」から実行。
 *  （パラメータの間は半角スペースで区切る）
 *
 * FD_FILE http://～.png test/     # 指定したURLのファイルをtest/に配置
 * FD_ファイル http://～.png test/ # 同上
 * FD_MY_FILE ～.json data/        # 指定したパスのファイルをdata/に配置
 * FD_マイファイル ～.json data/   # 同上
 * FD_PLUGIN http://～.js          # 指定したURLのjsをjs/plugins/に配置
 * FD_プラグイン http://～.js      # 同上
 * FD_MY_PLUGIN ～.js              # 指定したパスのjsをjs/plugins/に配置
 * FD_マイプラグイン ～.js         # 同上
 * FD_PICTURE http://～.png        # 指定したURLのpngをimg/pictures/に配置
 * FD_ピクチャ http://～.png       # 同上
 * FD_MY_PICTURE ～.png            # 指定したパスのpngをimg/pictures/に配置
 * FD_マイピクチャ ～.png          # 同上
 * FD_START_SITE http://～.jp      # 規定のブラウザで指定したURLを開く
 * FD_サイト起動 http://～.jp      # 同上
 *
 * 「マイ～」と言うコマンドは「配布サイトURL」パラメータ配下の
 * ファイルを取得できます。URLの記述を簡略化できます。
 *
 * また追加パラメータを後ろに付与すると、処理の正常終了時と異常終了時に
 * 任意のスイッチをONにできます。
 * 以下の例では処理終了後に正常終了なら[10]を異常終了なら[11]をONにします。
 *
 * FD_FILE http://～.png test/ 10 11
 *
 * 省略すると、もともとのプラグインパラメータで指定したスイッチがONになります。
 *
 * This plugin is released under the MIT License.
 */
/*:ja
 * @plugindesc ファイルダウンロードプラグイン
 * @author トリアコンタン
 *
 * @param 正常終了スイッチID
 * @desc コマンドが正常終了した際にONになるスイッチIDです。
 * @default 0
 *
 * @param 異常終了スイッチID
 * @desc コマンドが異常終了した際にONになるスイッチIDです。
 * @default 0
 *
 * @param 配布サイトURL
 * @desc リソースの配布元URLです。特定の配布元からのダウンロードを簡略化できます。
 * @default https://raw.githubusercontent.com/triacontane/RPGMakerMV/master/
 *
 * @help ゲーム中にインターネット上からファイルをダウンロードして
 * プロジェクト配下の任意の場所に配置できます。同名ファイルは上書きされます。
 * 配置したファイルはゲーム中で動的に参照することができます。
 *
 * 主に以下のような用途に使用できます。
 *
 * 1. 開発時のプラグインの自動アップデート
 * ゲーム起動時に自動で配布元の最新版を適用できます。わざわざ確認しなくても
 * 機能追加やバグ修正が行われた最新のファイルを利用できます。
 *
 * ただし、すでに適用済みのプラグインを更新した場合、
 * 変更を反映させるにはゲームをリロードする必要があります。
 *
 * ※パラメータ「配布サイトURL」をデフォルトのままで
 * 以下のプラグインコマンドを実行すると、本プラグインを最新化できます。
 *
 * FD_MY_PLUGIN FileDownloader.js
 *
 * 2. 小規模なアップデートファイル配信
 * あらかじめ準備しておけば、プレイヤーにゲーム全体を再ダウンロードさせずに
 * 一部ファイルのみ差し替えさせることができます。
 *
 * 3. インターネット上の画像をピクチャ表示
 * ネット上の画像ファイルなどを取り込んでゲーム内で使用することができます。
 * 著作権等には十分ご注意ください。
 *
 * 注意！
 * 1. ダウンロードには非常に時間が掛かります。（特にWindowsの場合）
 *
 * 2. ファイルは確認なしに上書きされます。復元はできませんのでご注意ください。
 *
 * 3. サーバによっては拒否される場合もあります。
 *
 * 4. ローカル実行（テストプレー含む）以外では利用できません。
 *
 * また、おまけ機能で「指定したURLを既定のブラウザで開く」機能もあります。
 *
 * プラグインコマンド詳細
 *  イベントコマンド「プラグインコマンド」から実行。
 *  （パラメータの間は半角スペースで区切る）
 *
 * FD_FILE http://～.png test/     # 指定したURLのファイルをtest/に配置
 * FD_ファイル http://～.png test/ # 同上
 * FD_MY_FILE ～.json data/        # 指定したパスのファイルをdata/に配置
 * FD_マイファイル ～.json data/   # 同上
 * FD_PLUGIN http://～.js          # 指定したURLのjsをjs/plugins/に配置
 * FD_プラグイン http://～.js      # 同上
 * FD_MY_PLUGIN ～.js              # 指定したパスのjsをjs/plugins/に配置
 * FD_マイプラグイン ～.js         # 同上
 * FD_PICTURE http://～.png        # 指定したURLのpngをimg/pictures/に配置
 * FD_ピクチャ http://～.png       # 同上
 * FD_MY_PICTURE ～.png            # 指定したパスのpngをimg/pictures/に配置
 * FD_マイピクチャ ～.png          # 同上
 * FD_START_SITE http://～.jp      # 規定のブラウザで指定したURLを開く
 * FD_サイト起動 http://～.jp      # 同上
 *
 * 「マイ～」と言うコマンドは「配布サイトURL」パラメータ配下の
 * ファイルを取得できます。URLの記述を簡略化できます。
 *
 * また追加パラメータを後ろに付与すると、処理の正常終了時と異常終了時に
 * 任意のスイッチをONにできます。
 * 以下の例では処理終了後に正常終了なら[10]を異常終了なら[11]をONにします。
 *
 * FD_FILE http://～.png test/ 10 11
 *
 * 省略すると、もともとのプラグインパラメータで指定したスイッチがONになります。
 *
 * 利用規約：
 *  作者に無断で改変、再配布が可能で、利用形態（商用、18禁利用等）
 *  についても制限はありません。
 *  このプラグインはもうあなたのものです。
 */

(function() {
    'use strict';
    const pluginName = 'FileDownloader';

    const getParamOther = function(paramNames) {
        for (let name of paramNames) {
            const paramName = PluginManager.parameters(pluginName)[name];
            if (paramName) return paramName;
        }
        return null;
    };

    const getParamString = function(paramNames) {
        const value = getParamOther(paramNames);
        return value === null ? '' : value;
    };

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

    const convertAllArguments = function(args) {
        for (let i = 0; i < args.length; i++) {
            args[i] = convertEscapeCharacters(args[i]);
        }
        return args;
    };

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

    const addSlashOfEnd = function(text) {
        if (text[text.length - 1] !== '/') text += '/';
        return text;
    };

    //=============================================================================
    // パラメータの取得と整形
    //=============================================================================
    const paramNormalEndSwitch   = getParamNumber(['NormalEndSwitch', '正常終了スイッチID'], 0);
    const paramAbnormalEndSwitch = getParamNumber(['AbnormalEndSwitch', '異常終了スイッチID'], 0);
    const paramResourceUrl       = addSlashOfEnd(getParamString(['ResourceUrl', '配布サイトURL']));

    const pluginCommandMap = new Map([
        ['FD_FILE' ,'downloadFile'],
        ['FD_ファイル' , 'downloadFile'],
        ['FD_MY_FILE' , 'downloadMyFile'],
        ['FD_マイファイル' ,'downloadMyFile'],
        ['FD_PLUGIN' , 'downloadPlugin'],
        ['FD_プラグイン' , 'downloadPlugin'],
        ['FD_MY_PLUGIN', 'downloadMyPlugin'],
        ['FD_マイプラグイン', 'downloadMyPlugin'],
        ['FD_PICTURE', 'downloadPicture'],
        ['FD_ピクチャ', 'downloadPicture'],
        ['FD_MY_PICTURE', 'downloadMyPicture'],
        ['FD_マイピクチャ', 'downloadMyPicture'],
        ['FD_START_SITE', 'startupWebSite'],
        ['FD_サイト起動', 'startupWebSite']
    ]);

    //=============================================================================
    // Game_Interpreter
    //  プラグインコマンドを追加定義します。
    //=============================================================================
    const _Game_Interpreter_clear    = Game_Interpreter.prototype.clear;
    Game_Interpreter.prototype.clear = function() {
        _Game_Interpreter_clear.apply(this, arguments);
        this._downloader = null;
    };

    const _Game_Interpreter_pluginCommand    = Game_Interpreter.prototype.pluginCommand;
    Game_Interpreter.prototype.pluginCommand = function(command, args) {
        _Game_Interpreter_pluginCommand.apply(this, arguments);
        this.pluginCommandFileDownloader.apply(this, arguments);
    };

    Game_Interpreter.prototype.pluginCommandFileDownloader = function(command, args) {
        const pluginCommand = pluginCommandMap.get(command.toUpperCase());
        if (pluginCommand) {
            args = convertAllArguments(args);
            this.makeDownloader(args);
            this[pluginCommand](args);
            this._downloader = null;
        }
    };

    Game_Interpreter.prototype.downloadFile = function(args) {
        args[1] = addSlashOfEnd(args[1]);
        this._downloader.execute(args[0], args[1]);
    };

    Game_Interpreter.prototype.downloadMyFile = function(args) {
        args[0] = paramResourceUrl + args[0];
        this.downloadFile(args);
    };

    Game_Interpreter.prototype.downloadPlugin = function(args) {
        args[1] = 'js/plugins/';
        this.downloadFile(args);
    };

    Game_Interpreter.prototype.downloadMyPlugin = function(args) {
        args[0] = paramResourceUrl + args[0];
        this.downloadPlugin(args);
    };

    Game_Interpreter.prototype.downloadPicture = function(args) {
        args[1] = 'img/pictures/';
        this.downloadFile(args);
    };

    Game_Interpreter.prototype.downloadMyPicture = function(args) {
        args[0] = paramResourceUrl + args[0];
        this.downloadPicture(args);
    };

    Game_Interpreter.prototype.startupWebSite = function(args) {
        const commander = GameStartUpWebSite.getInstance();
        commander.execute(args[0]);
    };

    Game_Interpreter.prototype.makeDownloader = function(args) {
        this._downloader = this._downloader || GameFileDownload.getInstance();
        this._downloader.setResultSwitchId(Number(args[args.length - 2]), Number(args[args.length - 1]));
    };

    //=============================================================================
    // GameChildProcess
    //  node.jsのchild_processを用いてコマンド実行を実現する基底クラスです。
    //=============================================================================
    class GameChildProcess {
        constructor() {
            this._normalSwitchId   = paramNormalEndSwitch;
            this._abnormalSwitchId = paramAbnormalEndSwitch;
        }

        setResultSwitchId(normalSwitchId, abnormalSwitchId) {
            this.setNormalSwitchId(normalSwitchId || paramNormalEndSwitch);
            this.setAbnormalSwitchId(abnormalSwitchId || paramAbnormalEndSwitch);
        }

        setNormalSwitchId(switchId) {
            this._normalSwitchId = switchId;
        }

        setAbnormalSwitchId(switchId) {
            this._abnormalSwitchId = switchId;
        }

        execute() {
            this.executeChildProcess(this.getCommand.apply(this, arguments));
        }

        executeChildProcess(command) {
            this.outputDebugLog('*** Execute Command : ' + command);
            this.setResultSwitch(this._normalSwitchId, false);
            this.setResultSwitch(this._abnormalSwitchId, false);
            const childProcess = require('child_process');
            const promise = new Promise(function(resolve, reject) {
                childProcess.exec(command, function(error, stdout, stderr) {
                    if (stdout) this.outputDebugLog(stdout);
                    if (stderr) this.outputDebugLog(stderr);
                    return error ? reject(error) : resolve();
                }.bind(this));
            }.bind(this));
            promise.then(this.onNormalEnd.bind(this), this.onAbnormalEnd.bind(this));
        }

        onNormalEnd() {
            this.setResultSwitch(this._normalSwitchId, true);
            this.outputDebugLog('*** Command Normal End ***');
        }

        onAbnormalEnd(error) {
            this.setResultSwitch(this._abnormalSwitchId, true);
            this.outputErrorLog(error);
            this.outputDebugLog('*** Command Abnormal End ***');
        };

        setResultSwitch(switchId, value) {
            if (switchId > 0) {
                $gameSwitches.setValue(switchId, value);
            }
        }

        outputDebugLog() {
            this.outputLog(false, arguments);
        };

        outputErrorLog() {
            this.outputLog(true, arguments);
        };

        outputLog(errorFlg, args) {
            if (!$gameTemp.isPlaytest() && !errorFlg) return;
            //this.showDevTool();
            //console[errorFlg ? 'error' : 'log'].apply(console, args);

        }

        showDevTool() {
            const gameWindow = require('nw.gui').Window.get();
            if (gameWindow.isDevToolsOpen()) return;
            const devTool = gameWindow.showDevTools();
            devTool.moveTo(0, 0);
            devTool.resizeTo(gameWindow.screenX + gameWindow.outerWidth, gameWindow.screenY + gameWindow.outerHeight);
            gameWindow.focus();
        };

        getCommand() {
            return '';
        }

        static getInstance() {
            return this.isNwjs() ? (this.isWindows() ? this.getWindowsInstance() : this.getMacInstance()) :
                this.getNoNwjsInstance();
        }

        static getDefaultInstance() {
            return new GameEmptyProcess();
        }

        static getWindowsInstance() {
            return this.getDefaultInstance();
        }

        static getMacInstance() {
            return this.getDefaultInstance();
        }

        static getNoNwjsInstance() {
            return this.getDefaultInstance();
        }

        static isWindows() {
            return process.platform === 'win32';
        }

        static isNwjs() {
            return Utils.isNwjs();
        }
    }

    //=============================================================================
    // GameEmptyProcess
    //  実行不可能な環境では何も実行しません。
    //=============================================================================
    class GameEmptyProcess extends GameChildProcess {
        execute() {
            console.log('指定した動作はこの環境では実行できません。');
        }
    }

    //=============================================================================
    // GameFileDownload
    //  ファイルダウンロードを実現します。
    //=============================================================================
    class GameFileDownload extends GameChildProcess {
        execute(url, localDir) {
            const path        = require('path');
            const projectBase = path.dirname(process.mainModule.filename);
            const localPath   = path.join(projectBase, localDir) + path.basename(url, true);
            super.execute(url, localPath);
        }

        static getWindowsInstance() {
            return new GameFileDownloadWindows();
        }

        static getMacInstance() {
            return new GameFileDownloadMac();
        }
    }

    //=============================================================================
    // GameFileDownloadWindows
    //  Windowsでファイルダウンロードを実現します。
    //=============================================================================
    class GameFileDownloadWindows extends GameFileDownload {
        getCommand(url, localPath) {
            return `bitsadmin.exe /TRANSFER FILE_DOWNLOAD ${url} ${localPath}`;
        }
    }

    //=============================================================================
    // GameFileDownloadMac
    //  Macでファイルダウンロードを実現します。
    //=============================================================================
    class GameFileDownloadMac extends GameFileDownload {
        getCommand(url, localPath) {
            return `curl ${url} -o ${localPath}`;
        }
    }

    //=============================================================================
    // GameStartUpWebSite
    //  ウェブサイトを開きます。
    //=============================================================================
    class GameStartUpWebSite extends GameChildProcess {
        static getWindowsInstance() {
            return new GameStartUpWebSiteWindows();
        }

        static getMacInstance() {
            return new GameStartUpWebSiteMac();
        }

        static getNoNwjsInstance() {
            return new GameStartUpWebSiteNoNwjs();
        }
    }

    //=============================================================================
    // GameStartUpWebSiteWindows
    //  Windowsでウェブサイトを開きます。
    //=============================================================================
    class GameStartUpWebSiteWindows extends GameStartUpWebSite {
        getCommand(url) {
            return `rundll32.exe url.dll,FileProtocolHandler "${url}"`;
        }
    }

    //=============================================================================
    // GameStartUpWebSiteMac
    //  Macでファイルダウンロードを実現します。
    //=============================================================================
    class GameStartUpWebSiteMac extends GameStartUpWebSite {
        getCommand(url) {
            return `open "${url}"`
        }
    }

    //=============================================================================
    // GameStartUpWebSiteNoNwjs
    //  ブラウザでウェブサイトを開きます。
    //=============================================================================
    class GameStartUpWebSiteNoNwjs extends GameStartUpWebSite {
        execute(url) {
            window.open(url);
        }
    }
})();

license: unknown


code:
var Remtairy = Remtairy || {};
Remtairy.EditedForeground = Remtairy.EditedForeground || {};

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

//=============================================================================
// Foreground.js
//=============================================================================

/*:
 * @plugindesc display foreground tiling sprite
 * @author Sasuke KANNAZUKI (thanks to Yoji Ojima)
 *
 * @noteParam fgName
 * @noteRequire 1
 * @noteDir img/parallaxes/
 * @noteType file
 * @noteData maps
 *
 * @help  This plugin does not provide plugin commands.
 *
 * 'foreground' is like a parallax that displays over the map.
 * put bitmap file at img/parallaxes.
 *
 * Map Note:
 *  write down following 5 settings at map's note.
 *  <fgName:name>     name is the string, file name of tiling sprite.
 *    if the name starts '!', it is regarded as "foreground zero".
 *    the filename is searched from img/parallaxes.
 *  <fgLoopX:number>  number is the flag of loop x. 0:no 1:yes
 *    if this is not written on the note, it'll be 0(=no).
 *  <fgLoopY:number>  number is the flag of loop y. 0:no 1:yes
 *    if this is not written on the note, it'll be 0(=no).
 *  <fgSx:number>     number is x scroll speed.
 *    when it doesn't loop x, this is ignored.
 *    if this is not written on the note, it'll be 0.
 *  <fgSy:number>     number is y scroll speed.
 *    when it doesn't loop y, this is ignored.
 *    if this is not written on the note, it'll be 0.
 *
 * Ex.
 * <fgName:sample1><fgLoopX:1><fgLoopY:1>
 *
 * <fgName:!sample1>
 */

/*:ja
 * @plugindesc マップに合わせてスクロールする近景の設定
 * @author 神無月サスケ (thanks to Yoji Ojima)
 *
 * @noteParam fgName
 * @noteRequire 1
 * @noteDir img/parallaxes/
 * @noteType file
 * @noteData maps
 *
 * @help このプラグインにプラグインコマンドはありません。
 * 近景(foreground)は、マップの上に表示される遠景のようなものです。
 * 使用する画像ファイルは、img/parallaxes に置いてください。
 *
 * マップのメモ:
 *  以下の5項目を書いてください(設定項目は、遠景と似ています)。
 *  <fgName:ファイル名> 前景として使うファイル名です（拡張子なし）
 *    名前が '!'で始まる場合、遠景同様視差ゼロとなります。
 *    ファイルは img/parallaxes に置いてください
 *  <fgLoopX:数字> X座標にループするかどうか  (0:no 1:yes)。
 *    省略時は0(=no)になります。
 *  <fgLoopY:number> Y座標にループするかどうか  (0:no 1:yes)。
 *    省略時は0(=no)になります。
 *  <fgSx:数字>    X座標のスクロール速度です
 *    X座標にループしない場合は無視されます。
 *    省略時は0になります。
 *  <fgSy:数字>    Y座標のスクロール速度です
 *    Y座標にループしない場合は無視されます。
 *    省略時は0になります。
 *
 * 例：
 * <fgName:sample1><fgLoopX:1><fgLoopY:1>
 * sample1.png が前景になり、斜め上にループします。
 *
 * <fgName:!sample1>
 * 視差ゼロで!sample1.png が表示されます。
 */

(function() {
  //
  // check zero foreground or not.
  //
  ImageManager.isZeroForeground = function(filename) {
    return filename.charAt(0) === '!';
  };

  //
  // map initialization
  //
  var _Game_Map_initialize = Game_Map.prototype.initialize;
  Game_Map.prototype.initialize = function() {
    _Game_Map_initialize.call(this);
    this.initForeground();
  };

  Game_Map.prototype.initForeground = function(){
    this._foregroundDefined = true;
    this._foregroundName = '';
    this._foregroundZero = false;
    this._foregroundLoopX = false;
    this._foregroundLoopY = false;
    this._foregroundSx = 0;
    this._foregroundSy = 0;

	this._foregroundNameB = '';
    this._foregroundZeroB = false;
    this._foregroundLoopXB = false;
    this._foregroundLoopYB = false;
    this._foregroundSxB = 0;
    this._foregroundSyB = 0;

    this._foregroundX = 0;
    this._foregroundY = 0;
  };

  //
  // if foreground is undefined, initialize it.
  //
  Game_Map.prototype.guardForeground = function(){
    if(!this._foregroundDefined){
      this.initForeground();
    }
  };

  //
  // an accessor
  //
  Game_Map.prototype.foregroundName = function() {
    this.guardForeground();
    return this._foregroundName;
};
Game_Map.prototype.foregroundNameB = function() {
    this.guardForeground();
    return this._foregroundNameB;
};

Game_Map.prototype.foregroundSwitch = function() {
    return this._foregroundSwitch;
};
Game_Map.prototype.foregroundSwitchB = function() {
    return this._foregroundSwitchB;
};
Game_Map.prototype.foregroundNotSwitchB = function() {
    return this._foregroundNotSwitchB;
};
Game_Map.prototype.foregroundNotSwitchB2 = function() {
    return this._foregroundNotSwitchB2;
};

  //
  // set foreground by reading map's note.
  //
  //var _Game_Map_setup = Game_Map.prototype.setup;
  Remtairy.EditedForeground.Game_Map_setup = Game_Map.prototype.setup;
  Game_Map.prototype.setup = function(mapId) {
    //_Game_Map_setup.call(this, mapId);
	Remtairy.EditedForeground.Game_Map_setup.call(this, mapId);
    this.setupForeground();
  };

  Game_Map.prototype.setupForeground = function() {
	if(!$dataMap || !$dataMap.meta) return;
    this._foregroundName = $dataMap.meta.fgName || '';
	this._foregroundSwitch = $dataMap.meta.fgSwitch || 0;
    this._foregroundZero = ImageManager.isZeroForeground(this._foregroundName);
    this._foregroundLoopX = !!$dataMap.meta.fgLoopX;
    this._foregroundLoopY = !!$dataMap.meta.fgLoopY;
    this._foregroundSx = Number($dataMap.meta.fgSx) || 0;
    this._foregroundSy = Number($dataMap.meta.fgSy) || 0;

	this._foregroundNameB = $dataMap.meta.fgName_b || '';
	this._foregroundSwitchB = $dataMap.meta.fgSwitch_b || 0;
	this._foregroundNotSwitchB = $dataMap.meta.fgNotSwitch_b || 0;
	this._foregroundNotSwitchB2 = $dataMap.meta.fgNotSwitch_b2 || 0;
    this._foregroundZeroB = ImageManager.isZeroForeground(this._foregroundNameB);
    this._foregroundLoopXB = !!$dataMap.meta.fgLoopX_b;
    this._foregroundLoopYB = !!$dataMap.meta.fgLoopY_b;
    this._foregroundSxB = Number($dataMap.meta.fgSx_b) || 0;
    this._foregroundSyB = Number($dataMap.meta.fgSy_b) || 0;

    this._foregroundX = 0;
    this._foregroundY = 0;
  };

  //
  // to display foreground
  //
  var _Game_Map_setDisplayPos = Game_Map.prototype.setDisplayPos;
  Game_Map.prototype.setDisplayPos = function(x, y) {
    _Game_Map_setDisplayPos.call(this, x, y);
    this.guardForeground();
    if (this.isLoopHorizontal()) {
      this._foregroundX = x;
    } else {
       this._foregroundX = this._displayX;
    }
    if (this.isLoopVertical()) {
      this._foregroundY = y;
    } else {
      this._foregroundY = this._displayY;
    }
  };

  Game_Map.prototype.foregroundOx = function() {
    this.guardForeground();
    if (this._foregroundZero) {
      return this._foregroundX * this.tileWidth();
    } else if (this._foregroundLoopX) {
      return this._foregroundX * this.tileWidth() / 2;
    } else {
      return 0;
    }
  };

  Game_Map.prototype.foregroundOy = function() {
    this.guardForeground();
    if (this._foregroundZero) {
      return this._foregroundY * this.tileHeight();
    } else if (this._foregroundLoopY) {
      return this._foregroundY * this.tileHeight() / 2;
    } else {
      return 0;
    }
  };

  Game_Map.prototype.foregroundOxB = function() {
    this.guardForeground();
    if (this._foregroundZeroB) {
      return this._foregroundX * this.tileWidth();
    } else if (this._foregroundLoopX) {
      return this._foregroundX * this.tileWidth() / 2;
    } else {
      return 0;
    }
  };

  Game_Map.prototype.foregroundOyB = function() {
    this.guardForeground();
    if (this._foregroundZeroB) {
      return this._foregroundY * this.tileHeight();
    } else if (this._foregroundLoopY) {
      return this._foregroundY * this.tileHeight() / 2;
    } else {
      return 0;
    }
  };

  //
  // to scroll foreground
  //
  var _Game_Map_scrollDown = Game_Map.prototype.scrollDown;
  Game_Map.prototype.scrollDown = function(distance) {
    var lastY = this._displayY;
    _Game_Map_scrollDown.call(this, distance);
    this.guardForeground();
    if (this.isLoopVertical()) {
      if (this._foregroundLoopY) {
        this._foregroundY += distance;
      }
    } else if (this.height() >= this.screenTileY()) {
      var displayY = Math.min(lastY + distance,
        this.height() - this.screenTileY());
      this._foregroundY += displayY - lastY;
    }
  };

  var _Game_Map_scrollLeft = Game_Map.prototype.scrollLeft;
  Game_Map.prototype.scrollLeft = function(distance) {
    var lastX = this._displayX;
    _Game_Map_scrollLeft.call(this, distance);
    this.guardForeground();
    if (this.isLoopHorizontal()) {
      if (this._foregroundLoopX) {
        this._foregroundX -= distance;
      }
    } else if (this.width() >= this.screenTileX()) {
      var displayX = Math.max(lastX - distance, 0);
      this._foregroundX += displayX - lastX;
    }
  };

  var _Game_Map_scrollRight = Game_Map.prototype.scrollRight;
  Game_Map.prototype.scrollRight = function(distance) {
    var lastX = this._displayX;
    _Game_Map_scrollRight.call(this, distance);
    this.guardForeground();
    if (this.isLoopHorizontal()) {
      if (this._foregroundLoopX) {
        this._foregroundX += distance;
      }
    } else if (this.width() >= this.screenTileX()) {
      var displayX = Math.min(lastX + distance,
       this.width() - this.screenTileX());
      this._foregroundX += displayX - lastX;
    }
  };

  var _Game_Map_scrollUp = Game_Map.prototype.scrollUp;
  Game_Map.prototype.scrollUp = function(distance) {
    var lastY = this._displayY;
    _Game_Map_scrollUp.call(this, distance);
    this.guardForeground();
    if (this.isLoopVertical()) {
      if (this._foregroundLoopY) {
        this._foregroundY -= distance;
      }
    } else if (this.height() >= this.screenTileY() && !this.ignoreForegroundScrollUp()) {
      var displayY = Math.max(lastY - distance, 0);
      this._foregroundY += displayY - lastY;
    }
  };

  //
  // update foreground
  //
  var _Game_Map_update = Game_Map.prototype.update;
  Game_Map.prototype.update = function(sceneActive) {
    _Game_Map_update.call(this, sceneActive);
    this.updateForeground();
  };

  Game_Map.prototype.updateForeground = function() {
    this.guardForeground();
    if (this._foregroundLoopX) {
      this._foregroundX += this._foregroundSx / this.tileWidth() / 2;
    }
    if (this._foregroundLoopY) {
      this._foregroundY += this._foregroundSy / this.tileHeight() / 2;
    }
  };

  //
  // sprites
  //
  var _Spriteset_Map_createLowerLayer =
   Spriteset_Map.prototype.createLowerLayer;
  Spriteset_Map.prototype.createLowerLayer = function() {
    _Spriteset_Map_createLowerLayer.call(this);
   this.createForeground();
  };

  var _Spriteset_Map_update = Spriteset_Map.prototype.update;
  Spriteset_Map.prototype.update = function() {
    _Spriteset_Map_update.call(this);
    this.updateForeground();
  };

  Spriteset_Map.prototype.createForeground = function() {
    this._foreground = new TilingSprite();
    this._foreground.move(0, 0, Graphics.width, Graphics.height);
    // in order to display under the weather sprites:
    this._baseSprite.removeChild(this._weather);
    this._baseSprite.addChild(this._foreground);
    this._baseSprite.addChild(this._weather);
  };

  Spriteset_Map.prototype.updateForeground = function() {
	if(!ConfigManager.remMapEffect) return;
	if($gameMap.foregroundSwitch() !== 0 && $gameMap.foregroundSwitchB() !== 0 && !$gameSwitches.value($gameMap.foregroundSwitch()) && !$gameSwitches.value($gameMap.foregroundSwitchB())) return;
	if($gameMap.foregroundSwitch() !== 0 && $gameMap.foregroundSwitchB() === 0 && !$gameSwitches.value($gameMap.foregroundSwitch())) return;
	if($gameMap.foregroundSwitchB() !== 0 && $gameMap.foregroundSwitch() === 0 && !$gameSwitches.value($gameMap.foregroundSwitchB()) && !$gameMap.foregroundName()) return;

	let foregroundNotSwitchBNotTriggered = true;
	if($gameMap.foregroundNotSwitchB() !== 0) {
		if($gameSwitches.value($gameMap.foregroundNotSwitchB())) foregroundNotSwitchBNotTriggered = false;
	}
	if($gameMap.foregroundNotSwitchB2() !== 0) {
		if($gameSwitches.value($gameMap.foregroundNotSwitchB2())) foregroundNotSwitchBNotTriggered = false;
	}

	if($gameSwitches.value($gameMap.foregroundSwitch())) {
		if(this._foregroundName !== $gameMap.foregroundName()) {
		  this._foregroundName = $gameMap.foregroundName();
		  this._foreground.bitmap = ImageManager.loadParallax(this._foregroundName);
		}
		if(this._foreground.bitmap) {
		  this._foreground.origin.x = $gameMap.foregroundOx();
		  this._foreground.origin.y = $gameMap.foregroundOy();
		}
	}
	else if($gameSwitches.value($gameMap.foregroundSwitchB()) && foregroundNotSwitchBNotTriggered) {

		if(this._foregroundNameB !== $gameMap.foregroundNameB()) {
		  this._foregroundNameB = $gameMap.foregroundNameB();
		  this._foreground.bitmap = ImageManager.loadParallax(this._foregroundNameB);
		}
		if(this._foreground.bitmap) {
		  this._foreground.origin.x = $gameMap.foregroundOxB();
		  this._foreground.origin.y = $gameMap.foregroundOyB();
		}
	}
	else {
		if(this._foregroundName !== $gameMap.foregroundName()) {
		  this._foregroundName = $gameMap.foregroundName();
		  this._foreground.bitmap = ImageManager.loadParallax(this._foregroundName);
		}
		if(this._foreground.bitmap) {
		  this._foreground.origin.x = $gameMap.foregroundOx();
		  this._foreground.origin.y = $gameMap.foregroundOy();
		}
	}
  };

})();


code:
//-----------------------------------------------------------------------------
//  Galv's Animated Menu Cursor
//-----------------------------------------------------------------------------
//  For: RPGMAKER MV
//  GALV_CursorImage.js
//-----------------------------------------------------------------------------
//  2019-03-13 - Version 1.8 - fixed issue with battle actor window no cursor
//  2017-04-02 - Version 1.7 - added ability to hide/unhide cursor
//  2016-08-10 - Version 1.6 - updated to work with MV version 1.3
//  2016-07-10 - Version 1.5 - hid cursor in yanfly battle status window
//  2016-06-13 - Version 1.4 - removed cursor in shop plugins item number box
//  2016-06-11 - Version 1.3 - fixed indent for default battle actor name
//                           - removed cursor from number input
//  2016-05-12 - Version 1.2 - cursor image added to 'dont exclude' file list
//  2016-04-11 - Version 1.1 - fixed display bug for initially inactive windows
//  2016-04-02 - Version 1.0 - release
//-----------------------------------------------------------------------------
// Terms can be found at:
// galvs-scripts.com
//-----------------------------------------------------------------------------

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

var Galv = Galv || {};          // Galv's main object
Galv.pCmd = Galv.pCmd || {};    // Plugin Command manager
Galv.CI = Galv.CI || {};        // Galv's stuff

//-----------------------------------------------------------------------------
/*:
 * @plugindesc (v.1.8) Display an animated image next to the selected menu command.
 *
 * @author Galv - galvs-scripts.com
 *
 * @param Cursor Image
 * @desc Image filename located in /img/system/ folder.
 * @default WindowCursor
 * @require 1
 * @dir img/system/
 * @type file
 *
 * @param Image Frames
 * @desc How many frames are in your cursor animation
 * @default 4
 *
 * @param Position Centered
 * @desc true or false if Image cursor is centered vertically to the command or not.
 * @default true
 *
 * @param Position Offset
 * @desc x,y - to reposition the cursor next to the active command in your menus
 * @default 0,0
 *
 * @param Animation Speed
 * @desc Speed that the animation plays each frame. Lower numbers mean faster animation speed.
 * @default 6
 *
 * @param Command Indent
 * @desc Indent commands in menus to make room for the cursor if required
 * @default 0
 *
 * @param Item Indent
 * @desc Indent items and skills in menus to make room for the cursor if required
 * @default 0
 *
 * @param Start Hidden
 * @desc Start the cursor hidden (invisible) on game load
 * true or false
 * @default false
 *
 * @help
 *   Galv's Animated Menu Cursor
 * ----------------------------------------------------------------------------
 * Make sure the cursor image is located in /img/system/ folder in your
 * project and the plugin settings are setup as required.
 *
 * Any size image can be used as long as the width is divisible by the number
 * of frames set in the "Image Frames" plugin setting.
 *
 * ----------------------------------------------------------------------------
 *    SCRIPT CALLS
 * ----------------------------------------------------------------------------
 *
 *     $gameSystem._cursorHidden = true;      // hide cursor
 *     $gameSystem._cursorHidden = false;     // show cursor
 */

//-----------------------------------------------------------------------------
//  CODE STUFFS
//-----------------------------------------------------------------------------

(function() {

Galv.CI.initHidden = PluginManager.parameters('Galv_CursorImage')["Start Hidden"].toLowerCase() === 'true' ? true : false;

Galv.CI.image = PluginManager.parameters('Galv_CursorImage')["Cursor Image"];
Galv.CI.frames = Number(PluginManager.parameters('Galv_CursorImage')["Image Frames"]);
Galv.CI.animSpeed = Number(PluginManager.parameters('Galv_CursorImage')["Animation Speed"]);
Galv.CI.center = PluginManager.parameters('Galv_CursorImage')["Position Centered"].toLowerCase() == 'true' ? true : false;
Galv.CI.cIndent = Number(PluginManager.parameters('Galv_CursorImage')["Command Indent"]);
Galv.CI.iIndent = Number(PluginManager.parameters('Galv_CursorImage')["Item Indent"]);
var tmp = PluginManager.parameters('Galv_CursorImage')["Position Offset"].split(",");
Galv.CI.offset = {x: Number(tmp[0]), y: Number(tmp[1])};
tmp = null;

// Pre Cache
//-----------------------------------------------------------------------------

Galv.CI.Scene_Boot_loadSystemImages = Scene_Boot.loadSystemImages;
Scene_Boot.loadSystemImages = function() {
	Galv.CI.Scene_Boot_loadSystemImages.call(this);
    ImageManager.loadSystem(Galv.CI.image);
};

// Window Stuff
//-----------------------------------------------------------------------------

Galv.CI.Game_System_initialize = Game_System.prototype.initialize;
Game_System.prototype.initialize = function() {
	Galv.CI.Game_System_initialize.call(this);
	this._cursorHidden = Galv.CI.initHidden;
};

// Window Stuff
//-----------------------------------------------------------------------------

Galv.CI.Window_Selectable_initialize = Window_Selectable.prototype.initialize;
Window_Selectable.prototype.initialize = function(x, y, width, height) {
	Galv.CI.Window_Selectable_initialize.call(this,x,y,width,height);
	this.createGalvCursor();
};

Window_Selectable.prototype.createGalvCursor = function() {
	if(TESTING_DISABLE_GALV_CURSOR) return;
	this._galvCursor = new Sprite_GalvCursor();
	this._galvCursor.setup(this);
	this.addChild(this._galvCursor);
};

Window_BattleEnemy.prototype.createGalvCursor = function() { return; };
Window_NameInput.prototype.createGalvCursor = function() { return; };
Window_NumberInput.prototype.createGalvCursor = function() { return; };
Window_ShopNumber.prototype.createGalvCursor = function() { return; };
Window_BattleStatus.prototype.createGalvCursor = function() { return; };
Window_ActorCommand.prototype.createGalvCursor = function() { return; };
Window_BattleLog.prototype.createGalvCursor = function() { return; };
Window_MenuStatus.prototype.createGalvCursor = function() { return; };
Window_TitleCommand.prototype.createGalvCursor = function() { return; };

Galv.CI.Window_BattleStatus_drawActorName = Window_BattleStatus.prototype.drawActorName;
Window_BattleStatus.prototype.drawActorName = function(actor, x, y, width) {
	x += Galv.CI.iIndent;
	Galv.CI.Window_BattleStatus_drawActorName.call(this,actor,x,y,width);
};

Galv.CI.Window_Command_textPadding = Window_Command.prototype.textPadding;
Window_Command.prototype.textPadding = function() {
    return Galv.CI.Window_Command_textPadding.call(this) + Galv.CI.cIndent;
};

Galv.CI.Window_EquipSlot_drawText = Window_EquipSlot.prototype.drawText;
Window_EquipSlot.prototype.drawText = function(text, x, y, maxWidth, align) {
	x += Galv.CI.iIndent;
	Galv.CI.Window_EquipSlot_drawText.call(this,text,x,y,maxWidth,align);
};

Galv.CI.Window_Selectable_drawItemName = Window_Selectable.prototype.drawItemName;
Window_Selectable.prototype.drawItemName = function(item, x, y, width) {
	x += Galv.CI.iIndent;
	Galv.CI.Window_Selectable_drawItemName.call(this,item,x,y,width);
};

Galv.CI.Window_EquipSlot_drawIcon = Window_EquipSlot.prototype.drawIcon;
Window_EquipSlot.prototype.drawIcon = function(iconIndex, x, y) {
	x += Galv.CI.iIndent;
    Galv.CI.Window_EquipSlot_drawIcon.call(this,iconIndex, x, y);
};

})();

// Sprite_GalvCursor
//-----------------------------------------------------------------------------

function Sprite_GalvCursor() {
    this.initialize.apply(this, arguments);
}

Sprite_GalvCursor.prototype = Object.create(Sprite_Base.prototype);
Sprite_GalvCursor.prototype.constructor = Sprite_GalvCursor;

Sprite_GalvCursor.prototype.initialize = function() {
    Sprite_Base.prototype.initialize.call(this);
	//this.setup(window);
};

Sprite_GalvCursor.prototype.setup = function(window) {
    this._window = window;
	this.createImage();
	this._ticker = 0;
	this._pattern = 0;
	this.updateFrame();
};

Sprite_GalvCursor.prototype.createImage = function() {
	this.bitmap = ImageManager.loadSystem(Galv.CI.image);
	this._frameWidth = this.bitmap.width / Galv.CI.frames;
	this._frameHeight = this.bitmap.height;
	this._maxPattern = Galv.CI.frames - 1;
	this._tickSpeed = Galv.CI.animSpeed;
	this.anchor.y = 0.5;
	this.opacity = 0;
};

Sprite_GalvCursor.prototype.update = function() {
    Sprite_Base.prototype.update.call(this);
	if (this._window.isCursorVisible() && !$gameSystem._cursorHidden) {
		this.opacity = this._window.openness >= 255 ? 255 : 0;
		if (this._window.active) this.updateFrame();
		this.updatePosition();
	} else {
		this.opacity = 0;
	};
};

Sprite_GalvCursor.prototype.updateFrame = function() {
    var pw = this._frameWidth;
    var ph = this._frameHeight;
    var sx = this._pattern * pw;
	this.setFrame(sx, 0, pw, ph);

	this._ticker += 1;
	if (this._ticker >= this._tickSpeed) {
		this._pattern = this._pattern == this._maxPattern ? 0 : this._pattern + 1;
		this._ticker = 0;
	};
};

Sprite_GalvCursor.prototype.updatePosition = function() {
	var rect = this._window._cursorRect;
	this.y = rect.y + Galv.CI.offset.y + this._window.standardPadding() + this.yPos(rect.height);
	this.x = rect.x + Galv.CI.offset.x;
};

if (Galv.CI.center) {
	Sprite_GalvCursor.prototype.yPos = function(height) {
		return height / 2;
	};
} else {
	Sprite_GalvCursor.prototype.yPos = function(height) {
		return 0;
	};
};


code:
//-----------------------------------------------------------------------------
//  Galv's Quest Log
//-----------------------------------------------------------------------------
//  For: RPGMAKER MV
//  Galv_QuestLog.js
//-----------------------------------------------------------------------------
//  2017-07-24 - Version 1.3 - added ability to remove failed quest category
//                             from the quest log.
//  2017-02-01 - Version 1.2 - added ability to show/hide quest categories
//                             during game
//  2016-12-12 - Version 1.1 - added setting to change seperator character for
//                             objectives and resolutions.
//  2016-11-10 - Version 1.0 - release
//-----------------------------------------------------------------------------
// Terms can be found at:
// galvs-scripts.com
//-----------------------------------------------------------------------------

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

var Galv = Galv || {};                  // Galv's main object
Galv.QUEST = Galv.QUEST || {};          // Galv's stuff

//-----------------------------------------------------------------------------
/*:
 * @plugindesc (v.1.3) A system to track quests/sidequests in your RPG.
 *
 * @author Galv - galvs-scripts.com
 *
 * @param File
 * @desc The name of your quests txt file (without .txt).
 * @default Quests
 *
 * @param Folder
 * @desc The folder name in your project where the txt file is located.
 * @default data
 *
 * @param Separator Character
 * @desc The character used to separate objective/resolution text.
 * Default: , (comma)
 * @default ,
 *
 * @param - OPTIONS -
 * @desc
 * @default
 *
 * @param Font Size
 * @desc The font size for quest text in the quest log
 * Default: 28
 * @default 22
 *
 * @param Categories
 * @desc An ordered list of quest categories separated by commas with | to designate hex color code for each
 * @default Main Quests|#ffcc66,Side Quests|#ffff99,Crafting Quests|#ccccff
 *
 * @param -- ICONS --
 * @desc
 * @default
 *
 * @param Not Complete Icon
 * @desc Icon displayed next to objectives not completed yet
 * @default 163
 *
 * @param Complete Icon
 * @desc Icon displayed next to objectives that are completed
 * @default 164
 *
 * @param Failed Icon
 * @desc Icon displayed next to objectives that were failed
 * @default 162
 *
 * @param Tracked Quest Icon
 * @desc Icon displayed next to currently tracked quest
 * @default 88
 *
 * @param -- VOCAB --
 * @desc
 * @default
 *
 * @param Quest Command
 * @desc Text used for Quest command in menu. Leave blank to not use this.
 * @default Quest Log
 *
 * @param Active Cmd Txt
 * @desc The command to view active quests
 * @default Active
 *
 * @param Completed Cmd Txt
 * @desc The command to view completed quests
 * @default Complete
 *
 * @param Failed Cmd Txt
 * @desc The command to view failed quests. Leave this blank to remove failed quests from menu
 * @default Failed
 *
 * @param Desc Txt
 * @desc The heading above the quest description
 * @default Details
 *
 * @param Objectives Txt
 * @desc The heading above the quest description
 * @default Objectives
 *
 * @param Difficulty Txt
 * @desc The text beside the level/difficulty value of the quest
 * @default Level
 *
 * @param No Tracked Quest
 * @desc Text displayed when no quest is being tracked
 * @default No Quest Selected
 *
 * @param -- EXTRA --
 * @desc The below settings are for Galv's Timed Message Popups
 * @default
 *
 * @param Pop XY
 * @desc The X,Y position for the timed popup
 * @default 20,20
 *
 * @param Pop Time
 * @desc How many frames the popup stays on screen
 * @default 130
 *
 * @param Pop New Quest
 * @desc Text displayed before the name of the quest when it is activated
 * @default New Quest:
 *
 * @param Pop Complete Quest
 * @desc Text displayed before the name of the quest when it is completed
 * @default Quest Completed:
 *
 * @param Pop Fail Quest
 * @desc Text displayed before the name of the quest when it is failed
 * @default Quest Failed:
 *
 * @param Pop New Objective
 * @desc Text displayed before the name of an objective when it is activated
 * @default New Objective:
 *
 * @param Pop Complete Objective
 * @desc Text displayed before the name of an objective when it is completed
 * @default Objective Completed:
 *
 * @param Pop Fail Objective
 * @desc Text displayed before the name of an objective when it is failed
 * @default Objective Failed:
 *
 * @help
 *   Galv's Quest Log
 * ----------------------------------------------------------------------------
 * Another quest log plugin for RPG Maker MV but written in Galv's style. Help
 * the player keep track of multiple quests and give notification of when
 * quests are accepted, changed or completed.
 *
 * MAKING A QUEST
 * --------------
 * Quest information is stored in a .txt file in your project, by default:
 * /data/Quests.txt
 * Each quest must be set up using tags and data explained below.
 *
 * <quest i:Quest Name|d|c>
 * objectiveName,objectiveName,objectiveName,objectiveName,objectiveName
 * resolution text, resolution text, resolution text
 * Description text lines here...
 * Description text lines here...
 * Description text lines here...
 * Description text lines here...
 * </quest>
 *
 * i = the quest id. This must be a unique number
 * Quest Name = the text used as the quest's name
 * d = difficulty value. eg. if a quest has a recommended level.
 * c = the category id. 0 for first, 1 for second, etc. based on the list of
 *     categories set up in the plugin settings.
 * -- The second line is used for objective names. If no objectives, leave the
 * line blank and they won't be displayed in the quest log.
 * -- The third line is used for resolution texts that can be selected using a
 * script call and displayed underneath the quest description. This line can
 * be left blank if not used.
 * The other lines are used for quest description and can use some formatting
 * code such as \c[x] and \i[x] to change color or add icons, etc.
 *
 * View the /data/Quest.txt file in the demo for examples.
 *
 * MODIFYING QUESTS
 * ----------------
 * Objectives in a quest or an entire quest's status can be changed via script
 * calls (further down). This quest log does not automate anything, you will
 * need to do the script calls manually as quests are completed in your RPG.
 *
 * QUEST TRACKING
 * --------------
 * You can track a quest by calling a script call (further down) with the quest
 * id. If the quest is already complete or failed, the quest cannot be tracked.
 * By tracking a quest you can detect from within an evente which quest id is
 * being tracked and use that in conditional branches to change reactions.
 *
 * The tracked quest will also appear on the main quest screen when no other
 * quest is being tracked.
 *
 * QUEST POPUPS
 * ------------
 * This plugin doesn't come with quest popup notifications, however if you use
 * Galv's Timed Message Popup plugin, it will automatically make notifications
 * using those.
 * ----------------------------------------------------------------------------
 *
 * ----------------------------------------------------------------------------
 *  SCRIPT calls
 * ----------------------------------------------------------------------------
 *
 *    Galv.QUEST.viewLog();   // starts the quest log scene manually
 *
 *    Galv.QUEST.catStatus(id,status); // id is the index number of the quest
 *                                     // category you set up in the plugin
 *                                     // settings. 0 first, 1 second, etc
 *                                     // status can be true or false to set
 *                                     // if the category is visible or not.
 *                                     // Categories are all true by default
 *
 *    Galv.QUEST.track(id);   // set which quest is being tracked
 *
 *    Galv.QUEST.activate(id);   // Add a quest to the Quest log as active
 *    Galv.QUEST.fail(id);       // Fail a quest in the Quest Log.
 *    Galv.QUEST.complete(id);   // Complete a quest in the Quest Log
 *
 *    Galv.QUEST.resolution(id,i);  // set resolution text to resolution index
 *                                  // i = -1 for none, 0 is first resolution
 *
 *    Galv.QUEST.objective(id,objId,status); // Change a quest's objective
 *                                           // id     = the quest's id
 *                                           // objId  = the objective index
 *                                           //          (0 is first)
 *                                           // status can be...
 *                                           //  -1  or  'hide'
 *                                           //   0  or  'activate'
 *                                           //   1  or  'complete'
 *                                           //   2  or  'fail'
 * EXAMPLES
 * Galv.QUEST.objective(3,0,'complete');  // complete quest 3's 1st objective
 * Galv.QUEST.objective(3,0,1);           // complete quest 3's 1st objective
 * Galv.QUEST.complete(3);  // complete quest 3 (not changing any objectives)
 * Galv.QUEST.objective(1,2,'hide');      // hide quest 1's 3rd objective
 *
 * EXTRA
 * If you have Galv's Timed Message Popups installed, it will automatically
 * display popups as quests and objectives are gained, completed or failed.
 * You can prevent a popup by adding a true argument at the end of the script
 * call. eg, the following are examples of not displaying popups:
 * Galv.QUEST.objective(3,0,'complete',true);
 * Galv.QUEST.fail(2,true);
 * Galv.QUEST.activate(3,true);
 *
 * ----------------------------------------------------------------------------
 *  SCRIPT for CONTROL VARIABLES
 * ----------------------------------------------------------------------------
 *
 *    Galv.QUEST.status(id)   // returns 0 incomplete, 1 complete, 2 failed
 *                            // returns -1 if quest was never activated.
 *
 *    Galv.QUEST.status(id,x) // x is the objective number to check status of
 *                            // (remember 0 is the first objective)
 *                            // returns same numbers as above
 *
 *    Galv.QUEST.isTracked()  // returns the id of the tracked quest.
 *                            // 0 if no quest is being tracked.
 *
 * ----------------------------------------------------------------------------
 */

//-----------------------------------------------------------------------------
//  CODE STUFFS
//-----------------------------------------------------------------------------

(function() {

//-----------------------------------------------------------------------------
// GET TXT FILE
//-----------------------------------------------------------------------------

Galv.QUEST.file = {};
Galv.QUEST.file.getString = function(filePath, language) {
	var request = new XMLHttpRequest();
	request.open("GET", filePath);
	request.overrideMimeType('application/json');
	request.onload = function() {
		if (request.status < 400) {
			if(language === 0)
				Galv.QUEST.createJPQuests(request.responseText);
			if(language === 1)
				Galv.QUEST.createENQuests(request.responseText);
		}
	};
	request.send();
};

Galv.QUEST.createENQuests = function(string) {
	var lines = string.split("\n");
	var bIndex = 0;
	var record = false;
	Galv.QUEST.entxt = {};

	for (var i = 0; i < lines.length; i++) {
		if (lines[i][0] == '<') {
			if (lines[i].contains('</quest>')) {
				record = false;
			} else if (lines[i].contains('<quest')) {
				var qId = lines[i].match(/<quest (.*):(.*)>/i);
				if (qId) {
					bIndex = Number(qId[1]);
					Galv.QUEST.entxt[bIndex] = {};
					Galv.QUEST.entxt[bIndex].desc = [];

					var s = qId[2].split('|');
					Galv.QUEST.entxt[bIndex].name = s[0] || '???';
					Galv.QUEST.entxt[bIndex].difficulty = s[1] || '???';
					Galv.QUEST.entxt[bIndex].category = s[2] || 0;

					record = true;
				}
			}
		} else if (record) {
			Galv.QUEST.entxt[bIndex].desc.push(lines[i]);
		}
	};
};

Galv.QUEST.createJPQuests = function(string) {
	var lines = string.split("\n");
	var bIndex = 0;
	var record = false;
	Galv.QUEST.jptxt = {};

	for (var i = 0; i < lines.length; i++) {
		if (lines[i][0] == '<') {
			if (lines[i].contains('</quest>')) {
				record = false;
			} else if (lines[i].contains('<quest')) {
				var qId = lines[i].match(/<quest (.*):(.*)>/i);
				if (qId) {
					bIndex = Number(qId[1]);
					Galv.QUEST.jptxt[bIndex] = {};
					Galv.QUEST.jptxt[bIndex].desc = [];

					var s = qId[2].split('|');
					Galv.QUEST.jptxt[bIndex].name = s[0] || '???';
					Galv.QUEST.jptxt[bIndex].difficulty = s[1] || '???';
					Galv.QUEST.jptxt[bIndex].category = s[2] || 0;

					record = true;
				}
			}
		} else if (record) {
			Galv.QUEST.jptxt[bIndex].desc.push(lines[i]);
		}
	};
};

Galv.QUEST.fileName = function() {
	if (!Galv.QUEST.entxt) {
		var filename = PluginManager.parameters('Galv_QuestLog')["File"];;
		var folder = PluginManager.parameters('Galv_QuestLog')["Folder"];
		if (folder !== "") folder = folder + "/";
		//Galv.QUEST.entxt = {};
		Galv.QUEST.file.getString(folder + filename + "EN.txt", 1);
	};
	if (!Galv.QUEST.jptxt) {
		var filename = PluginManager.parameters('Galv_QuestLog')["File"];;
		var folder = PluginManager.parameters('Galv_QuestLog')["Folder"];
		if (folder !== "") folder = folder + "/";
		//Galv.QUEST.jptxt = {};
		Galv.QUEST.file.getString(folder + filename + "JP.txt", 0);
	};
}();

Galv.QUEST.sep = PluginManager.parameters('Galv_QuestLog')["Separator Character"];

// Options
Galv.QUEST.fontSize = Number(PluginManager.parameters('Galv_QuestLog')["Font Size"]);

//var cats = PluginManager.parameters('Galv_QuestLog')["Categories"].split(',');
var catsEN = RemGALVQuestCategoriesEN.split(',');
var catsJP = RemGALVQuestCategoriesJP.split(',');
Galv.QUEST.categoriesEN = []; Galv.QUEST.categoriesJP = [];
for (var i = 0; i < catsEN.length; i++) {
	var dataEN = catsEN[i].split("|");
	var dataJP = catsJP[i].split("|");
	Galv.QUEST.categoriesEN[i] = {id:i,name:dataEN[0],color:dataEN[1]};
	Galv.QUEST.categoriesJP[i] = {id:i,name:dataJP[0],color:dataJP[1]};
}

// Vocab
Galv.QUEST.menuCmd = PluginManager.parameters('Galv_QuestLog')["Quest Command"];
Galv.QUEST.txtCmdActive = PluginManager.parameters('Galv_QuestLog')["Active Cmd Txt"];
Galv.QUEST.txtCmdComplete = PluginManager.parameters('Galv_QuestLog')["Completed Cmd Txt"];
Galv.QUEST.txtCmdFailed = PluginManager.parameters('Galv_QuestLog')["Failed Cmd Txt"];
Galv.QUEST.txtDesc = PluginManager.parameters('Galv_QuestLog')["Desc Txt"];
Galv.QUEST.txtObj = PluginManager.parameters('Galv_QuestLog')["Objectives Txt"];
Galv.QUEST.txtDiff = PluginManager.parameters('Galv_QuestLog')["Difficulty Txt"];
Galv.QUEST.txtNoTrack = PluginManager.parameters('Galv_QuestLog')["No Tracked Quest"];

// Icons
Galv.QUEST.icon0 = Number(PluginManager.parameters('Galv_QuestLog')["Not Complete Icon"]);
Galv.QUEST.icon1 = Number(PluginManager.parameters('Galv_QuestLog')["Complete Icon"]);
Galv.QUEST.icon2 = Number(PluginManager.parameters('Galv_QuestLog')["Failed Icon"]);
Galv.QUEST.icon3 = Number(PluginManager.parameters('Galv_QuestLog')["Tracked Quest Icon"]);

// Extra
var txt = PluginManager.parameters('Galv_QuestLog')["Pop XY"].split(',');
Galv.QUEST.popXY = [Number(txt[0]),Number(txt[1])];

Galv.QUEST.popTime = Number(PluginManager.parameters('Galv_QuestLog')["Pop Time"]);
Galv.QUEST.txtPopQA = PluginManager.parameters('Galv_QuestLog')["Pop New Quest"];
Galv.QUEST.txtPopQC = PluginManager.parameters('Galv_QuestLog')["Pop Complete Quest"];
Galv.QUEST.txtPopQF = PluginManager.parameters('Galv_QuestLog')["Pop Fail Quest"];
Galv.QUEST.txtPopOA = PluginManager.parameters('Galv_QuestLog')["Pop New Objective"];
Galv.QUEST.txtPopOC = PluginManager.parameters('Galv_QuestLog')["Pop Complete Objective"];
Galv.QUEST.txtPopOF = PluginManager.parameters('Galv_QuestLog')["Pop Fail Objective"];

//-----------------------------------------------------------------------------
// FUNCTIONALITY
//-----------------------------------------------------------------------------

// change status of a category
Galv.QUEST.catStatus = function(id,status) {
	$gameSystem._quests.categoryActive[id] = status;
};

// remove quest from active, completed or failed lists. Quest will still exist as obtained, however.
Galv.QUEST.removeQuest = function(id) {
	if ($gameSystem._quests.quest[id]) {
		Galv.QUEST.sliceArray($gameSystem._quests.active,id);
		Galv.QUEST.sliceArray($gameSystem._quests.completed,id);
		Galv.QUEST.sliceArray($gameSystem._quests.failed,id);
		$gameSystem._quests.quest[id]._status = -1;
	}
};

Galv.QUEST.sliceArray = function(array,element) {
	var index = array.indexOf(element);
	if (index > -1) {
    	array.splice(index, 1);
	}
};

// create quest if doesn't exist
Galv.QUEST.create = function(id) {
	if (!$gameSystem._quests.quest[id] && Galv.QUEST.jptxt[id]) {
		Galv.QUEST.removeQuest(id);
		$gameSystem._quests.quest[id] = new Game_Quest(id);
	}
};

Galv.QUEST.convStatus = {
	0: 'active',
	1: 'completed',
	2: 'failed',
	'-1': 'hidden',
	'hide': -1,
	'active': 0,
	'activate': 0,
	'completed': 1,
	'complete': 1,
	'failed': 2,
	'fail': 2,
};

// Change quest status
Galv.QUEST.put = function(id,status) {
	var status = status || 0;
	var place = Galv.QUEST.convStatus[status];

	if (status != 0) $gameSystem._quests.tracked = null;
	if ($gameSystem._quests.quest[id]) {
		Galv.QUEST.removeQuest(id);          // remove from all array
		$gameSystem._quests[place].unshift(id); // add to desired array
		$gameSystem._quests.quest[id]._status = status;  // set quest status
	}
};

Galv.QUEST.fail = function(id,hidePopup) {
	Galv.QUEST.create(id);
	Galv.QUEST.put(id,2);
	if (!hidePopup) Galv.QUEST.popup(id,2);
};

Galv.QUEST.complete = function(id,hidePopup) {
	Galv.QUEST.create(id);
	Galv.QUEST.put(id,1);
	if (!hidePopup) Galv.QUEST.popup(id,1);
};

Galv.QUEST.activate = function(id,hidePopup) {
	Galv.QUEST.create(id);
	Galv.QUEST.put(id,0);
	if (!hidePopup) Galv.QUEST.popup(id,0);
};

Galv.QUEST.popup = function(id,status,obj) {
	// plugin writers overwrite this if they want to use different notification/popup
	if (!Imported.Galv_MessageCaptions || !SceneManager._scene) return;
	var x = Galv.QUEST.popXY[0];
	var y = Galv.QUEST.popXY[1];
	var time = Galv.QUEST.popTime;
	switch (status) {
		case -1:
			return; // -1 is hiding an objective.
		case 0:
			var txt = obj != undefined ? Galv.QUEST.txtPopOA : Galv.QUEST.txtPopQA;
			break;
		case 1:
			var txt = obj != undefined ? Galv.QUEST.txtPopOC : Galv.QUEST.txtPopQC;
			break;
		case 2:
			var txt = obj != undefined ? Galv.QUEST.txtPopOF : Galv.QUEST.txtPopQF;
			break;
	}
	if (txt) {
		if (obj != undefined) {
			var name = $gameSystem._quests.quest[id].objectives()[obj];
		} else {
			var name = $gameSystem._quests.quest[id].name();
		}
		SceneManager._scene.createCaptionWindow([x,y],time,[txt + " " + name],[],0);
	}

};

// Change quest objective status
Galv.QUEST.objective = function(id,objId,status,hidePopup) {
	Galv.QUEST.create(id);
	if (isNaN(status)) var status = Galv.QUEST.convStatus[status];
	// status can be: 0 is not yet complete, 1 is completed, 2 is failed
	if ($gameSystem._quests.quest[id]) {
		$gameSystem._quests.quest[id]._objectives[objId] = status;
		if (!hidePopup) Galv.QUEST.popup(id,status,objId);
	}
};

Galv.QUEST.track = function(id) {
	if ($gameSystem._quests.quest[id] && $gameSystem._quests.quest[id]._status == 0) {
		$gameSystem._quests.tracked = id;
	} else {
		$gameSystem._quests.tracked = null;
	}
};

Galv.QUEST.isTracked = function() {
	return $gameSystem._quests.tracked || 0;
};

Galv.QUEST.status = function(id,obj) {
	if ($gameSystem._quests.quest[id]) {
		if (obj != undefined) {
			return $gameSystem._quests.quest[id]._objectives[obj];
		} else {
			return $gameSystem._quests.quest[id]._status;
		}
	} else {
		return -1;
	}
};

Galv.QUEST.resolution = function(id,index) {
	if ($gameSystem._quests.quest[id]) $gameSystem._quests.quest[id]._resolution = index;
};

Galv.QUEST.viewLog = function() {
	SceneManager.push(Scene_QuestLog);
};

//-----------------------------------------------------------------------------
//  GAME SYSTEM
//-----------------------------------------------------------------------------

Galv.QUEST.Game_System_initialize = Game_System.prototype.initialize;
Game_System.prototype.initialize = function() {
	Galv.QUEST.Game_System_initialize.call(this);
	this._quests = {
		tracked: null,
		quest: {},        // id: Game_Quest  - to store obtained quest objects
		active: [],       // array of quest id's player has activated
		completed: [],    // array of quest id's player has completed
		failed: [],       // array of quest id's player has failed
		categoryHide: {active:[],completed:[],failed:[]},  // arrays containing data if category id is expanded or not (0/null for open, 1/true for closed)
		categoryActive: [],
	};

	// set all cats to true
	for (var i = 0; i < Galv.QUEST.categoriesEN.length; i++) {
		this._quests.categoryActive[i] = true;
	}
};

})();

//-----------------------------------------------------------------------------
//  GAME QUEST
//-----------------------------------------------------------------------------

function Game_Quest() {
    this.initialize.apply(this, arguments);
}

Game_Quest.prototype.initialize = function(id,cat) {
	this._id = id;
	this._cat = cat || 0;
	this._objectives = []; // indexes can be 0,1,2 to store the status of objectives. 0 (or undefined/null) is not yet complete, 1 is completed, 2 is failed
	this._resolution = -1; // the selected resolution to display under the quest description in the quest log. -1 for none.
	this._status = 0;      // 0 is not yet completed, 1 is completed, 2 is failed
};

Game_Quest.prototype.desc = function() {
	if(TextManager.isJapanese)
		return Galv.QUEST.jptxt[this._id].desc.slice(2);
	else if(TextManager.isEnglish)
		return Galv.QUEST.entxt[this._id].desc.slice(2);
	// returns the description without the first 2 lines (which is objectives and resolutions)
};

Game_Quest.prototype.name = function() {
	if(TextManager.isJapanese)
		return Galv.QUEST.jptxt[this._id].name;
	else if(TextManager.isEnglish)
		return Galv.QUEST.entxt[this._id].name;
};

Game_Quest.prototype.difficulty = function() {
	if(TextManager.isJapanese) {
		var diff = Galv.QUEST.jptxt[this._id].difficulty;
		var text = "";
		for(;diff>0;diff--) text += "★";
		return text;
	}
	else if(TextManager.isEnglish) {
		var diff = Galv.QUEST.entxt[this._id].difficulty;
		var text = "";
		for(;diff>0;diff--) text += "★";
		return text;
	}
};

Game_Quest.prototype.category = function() {
	if(TextManager.isJapanese)
		return Galv.QUEST.jptxt[this._id].category;
	else if(TextManager.isEnglish)
		return Galv.QUEST.entxt[this._id].category;
};

Game_Quest.prototype.objectives = function() {
	var array;

	if(TextManager.isJapanese)
		array = Galv.QUEST.jptxt[this._id].desc[0].split(Galv.QUEST.sep);
	else if(TextManager.isEnglish)
		array = Galv.QUEST.entxt[this._id].desc[0].split(Galv.QUEST.sep);

	return array[0].length <= 1 ? [] : array;
};

Game_Quest.prototype.resolutions = function() {
	var array;

	if(TextManager.isJapanese)
		array = Galv.QUEST.jptxt[this._id].desc[1].split(Galv.QUEST.sep);
	else if(TextManager.isEnglish)
		array = Galv.QUEST.entxt[this._id].desc[1].split(Galv.QUEST.sep);

	return array[0].length <= 1 ? [] : array;
};

Game_Quest.prototype.hasResolution = function() {
	return this._resolution >= 0;
};

Game_Quest.prototype.resoTxtArray = function() {
	var txt = "";
	if (this._resolution >= 0) {
		var txt = this.resolutions()[this._resolution];
		txt = txt.split('|');
	}
	return txt;
};

//-----------------------------------------------------------------------------
//  SCENE QUESTLOG
//-----------------------------------------------------------------------------

function Scene_QuestLog() {
    this.initialize.apply(this, arguments);
}

Scene_QuestLog.prototype = Object.create(Scene_ItemBase.prototype);
Scene_QuestLog.prototype.constructor = Scene_QuestLog;

Scene_QuestLog.prototype.initialize = function() {
    Scene_ItemBase.prototype.initialize.call(this);
};

Scene_QuestLog.prototype.create = function() {
    Scene_ItemBase.prototype.create.call(this);
    this.createCategoryWindow();
    this.createQuestListWindow();
    this.createInfoWindow();
};

Scene_QuestLog.prototype.createCategoryWindow = function() {
	this._categoryWindow = new Window_QuestCategory();
	this._categoryWindow.setHandler('ok',     this.onCategoryOk.bind(this));
	this._categoryWindow.setHandler('cancel', this.popScene.bind(this));
	this.addWindow(this._categoryWindow);
};

Scene_QuestLog.prototype.createQuestListWindow = function() {
	var wy = this._categoryWindow.y + this._categoryWindow.height;
	var ww = Graphics.boxWidth / 2;
	var wh = Graphics.boxHeight - wy;
	this._itemWindow = new Window_QuestList(0, wy, ww, wh);
	this._itemWindow.setHandler('ok',     this.onItemOk.bind(this));
	this._itemWindow.setHandler('cancel', this.onItemCancel.bind(this));
	this.addWindow(this._itemWindow);
	this._categoryWindow.setItemWindow(this._itemWindow);
};

Scene_QuestLog.prototype.createInfoWindow = function() {
	var ww = this._itemWindow.width;
	var wh = this._itemWindow.height;
	var wx = this._itemWindow.x + ww;
	var wy = this._itemWindow.y;
	this._helpWindow = new Window_QuestInfo(wx,wy,ww,wh);
	this.addWindow(this._helpWindow);

	this._itemWindow.setHelpWindow(this._helpWindow);
	this._categoryWindow.setHelpWindow(this._helpWindow);
};

Scene_QuestLog.prototype.onCategoryOk = function() {
	this._itemWindow.activate();
	this._itemWindow.select(0);
};

Scene_QuestLog.prototype.onItemOk = function() {
	this._itemWindow.setTracking();
	this._itemWindow.refresh();
	this._helpWindow.refresh();
	this._itemWindow.activate();
};

Scene_QuestLog.prototype.onItemCancel = function() {
    this._itemWindow.deselect();
    this._categoryWindow.activate();
};

//-----------------------------------------------------------------------------
//  WINDOW QUESTCATEGORY
//-----------------------------------------------------------------------------

function Window_QuestCategory() {
    this.initialize.apply(this, arguments);
}

Window_QuestCategory.prototype = Object.create(Window_HorzCommand.prototype);
Window_QuestCategory.prototype.constructor = Window_QuestCategory;

Window_QuestCategory.prototype.initialize = function() {
    Window_HorzCommand.prototype.initialize.call(this, 0, 0);
};

Window_QuestCategory.prototype.windowWidth = function() {
    return Graphics.boxWidth;
};

Window_QuestCategory.prototype.maxCols = function() {
    return Galv.QUEST.txtCmdFailed == "" ? 2 : 3;
};

Window_QuestCategory.prototype.update = function() {
    Window_HorzCommand.prototype.update.call(this);
    if (this._itemWindow) {
        this._itemWindow.setCategory(this.currentSymbol());
    }
};

Window_QuestCategory.prototype.makeCommandList = function() {
    //this.addCommand(Galv.QUEST.txtCmdActive,    'active');
    //this.addCommand(Galv.QUEST.txtCmdComplete,  'completed');
	this.addCommand(TextManager.RemGALVQuestActive,    'active');
    this.addCommand(TextManager.RemGALVQuestCompleted,  'completed');

    if (Galv.QUEST.txtCmdFailed != "") this.addCommand(Galv.QUEST.txtCmdFailed,   'failed');
};

Window_QuestCategory.prototype.setItemWindow = function(itemWindow) {
    this._itemWindow = itemWindow;
    this.update();
};

//-----------------------------------------------------------------------------
//  WINDOW QUESTCATEGORY
//-----------------------------------------------------------------------------

function Window_QuestList() {
    this.initialize.apply(this, arguments);
}

Window_QuestList.prototype = Object.create(Window_Selectable.prototype);
Window_QuestList.prototype.constructor = Window_QuestList;

Window_QuestList.prototype.initialize = function(x, y, width, height) {
    Window_Selectable.prototype.initialize.call(this, x, y, width, height);
    this._category = 'none';
    this._data = [];
};

Window_QuestList.prototype.setCategory = function(category) {
    if (this._category !== category) {
        this._category = category;
        this.refresh();
        this.resetScroll();
    }
};

Window_QuestList.prototype.maxCols = function() {
    return 1;
};

Window_QuestList.prototype.spacing = function() {
    return 48;
};

Window_QuestList.prototype.maxItems = function() {
    return this._data ? this._data.length : 1;
};

Window_QuestList.prototype.item = function(index) {
    var index = index == undefined ? this.index() : index;
	var obj = isNaN(this._data[index]) ? this._data[index] : $gameSystem._quests.quest[this._data[index]];

    return this._data && index >= 0 ? obj : null;
};

Window_QuestList.prototype.setTracking = function() {
	if (!this.item()) return;
	if (this.item().categoryTitle != undefined) {
		// hide/show category
		var catId = this.item().categoryTitle;
		$gameSystem._quests.categoryHide[this._category][catId] = !$gameSystem._quests.categoryHide[this._category][catId];
	} else {
		// Track quest
		if (this.item()._id == Galv.QUEST.isTracked()) {
			Galv.QUEST.track();
		} else {
			Galv.QUEST.track(this.item()._id);
		}
	}
};

Window_QuestList.prototype.makeItemList = function() {
	this._data = [];
	this.buildQuestList();
	switch (this._category) {
		case 'active':
			this._data = this.buildQuestList($gameSystem._quests.active);
			break;
		case 'completed':
			this._data = this.buildQuestList($gameSystem._quests.completed);
			break;
		case 'failed':
			this._data = this.buildQuestList($gameSystem._quests.failed);
			break;
	}
};

Window_QuestList.prototype.buildQuestList = function(questList) {
	var list = [];
	var questList = questList || [];

	// setup lists for categories
	for (var i = 0; i < Galv.QUEST.categoriesEN.length; i++) {
		if ($gameSystem._quests.categoryActive[i]) list[i] = [{categoryTitle:i,count:0}];
	}

	// put quests into categories
	for (var i = 0; i < questList.length; i++) {
		var cat = $gameSystem._quests.quest[questList[i]].category();
		if (!$gameSystem._quests.categoryActive[cat]) continue;
		list[cat][0].count += 1;

		if (!$gameSystem._quests.categoryHide[this._category][cat]) { // only add it if category isn't hidden
			list[cat].push(questList[i]);
		}
	}

	// concat lists
	var final = [];
	for (var i = 0; i < list.length; i++) {
		final = final.concat(list[i]);
	}
	final = final.filter(function(n){ return n != undefined });

	return final;
};

Window_QuestList.prototype.drawItem = function(index) {
    var item = this.item(index);
    if (item) {
		var rect = this.itemRect(index);
		rect.width -= this.textPadding();

		if (item.categoryTitle != undefined) {
			var cat = "";
			if(TextManager.isEnglish)
				cat = Galv.QUEST.categoriesEN[item.categoryTitle];
			else if(TextManager.isJapanese)
				cat = Galv.QUEST.categoriesJP[item.categoryTitle];
			var txt = cat.name;
			this.changeTextColor(cat.color);
			this.drawText(txt,rect.x + 4,rect.y,rect.width);
			this.drawText("(" + item.count + ")",rect.x,rect.y,rect.width,'right');
			this.changeTextColor(this.normalColor());
		} else {
			var icon = item._id == $gameSystem._quests.tracked ? Galv.QUEST.icon3 : Galv.QUEST['icon' + item._status];
			this.drawIcon(icon,rect.x,rect.y);
			this.drawText(item.name(),rect.x + 40,rect.y,rect.width);
		}
    }
};

Window_QuestList.prototype.updateHelp = function() {
    this.setHelpWindowItem(this.item());
};

Window_QuestList.prototype.refresh = function() {
    this.makeItemList();
    this.createContents();
	this.contents.fontSize = Galv.QUEST.fontSize;
    this.drawAllItems();
};

//-----------------------------------------------------------------------------
//  WINDOW QUESTINFO
//-----------------------------------------------------------------------------

function Window_QuestInfo() {
    this.initialize.apply(this, arguments);
}

Window_QuestInfo.prototype = Object.create(Window_Base.prototype);
Window_QuestInfo.prototype.constructor = Window_QuestInfo;

Window_QuestInfo.prototype.initialize = function(x,y,width,height) {
Window_Base.prototype.initialize.call(this, x, y, width, height);
	this._quest = null;
	this.refresh();
};

Window_QuestInfo.prototype.clear = function() {
	this.setItem();
};

Window_QuestInfo.prototype.setItem = function(quest) {
	if (this._quest !== quest) {
		this._quest = quest;
		this.refresh();
	}
};

Window_QuestInfo.prototype.refresh = function() {
    this.contents.clear();
	if (this._quest) {
	    this.drawQuest(this._quest);
	} else if ($gameSystem._quests.tracked) {
		this.drawQuest($gameSystem._quests.quest[$gameSystem._quests.tracked]);
	} else {
		this.drawNoQuest();
	}
};

Window_QuestInfo.prototype.drawHorzLine = function(y) {
    var lineY = y + this.lineHeight() / 2 - 1;
    this.contents.paintOpacity = 48;
    this.contents.fillRect(0, lineY, this.contentsWidth(), 2, this.normalColor());
    this.contents.paintOpacity = 255;
};

Window_QuestInfo.prototype.standardFontSize = function() {
    return Galv.QUEST.fontSize;
};

Window_QuestInfo.prototype.lineHeight = function() {
    return Galv.QUEST.fontSize + 6;
};

Window_QuestInfo.prototype.drawQuest = function(quest) {
	if (quest.categoryTitle != undefined) return;
	this.changeTextColor(this.normalColor());
	// quest heading
	var icon = quest._id == $gameSystem._quests.tracked ? Galv.QUEST.icon3 : Galv.QUEST['icon' + quest._status];
	this.drawIcon(icon,0,0);
	var oy = Math.max((28 - this.standardFontSize()) / 2,0);
	this.drawText(quest.name(),40,oy,this.contentsWidth() - 40);
	var lineY = Math.max(32,this.lineHeight());
	this.drawHorzLine(lineY);

	var line = this.lineHeight();
	var y = lineY + line;
	var w = this.contentsWidth();

	// quest difficulty
	this.drawText(Galv.QUEST.txtDiff + " " + quest.difficulty(),0,y,w,'right');

	// quest desc
	this.changeTextColor(this.systemColor());
	//this.drawText(Galv.QUEST.txtDesc,0,y,w);
	this.drawText(TextManager.RemGALVQuestDetails,0,y,w);

	this.changeTextColor(this.normalColor());
	var desc = quest.desc().slice();;

	if (quest.hasResolution()) {
		// if quest has a selected resolution, add it
		desc.push("");
		desc = desc.concat(quest.resoTxtArray()); // add resolution txt
	}

	y += 10;
	for (var i = 0; i < desc.length; i++) {
		y += line;
		this.drawTextEx(desc[i], 0, y);
	}
	y += line * 2;

	// quest objectives
	var objs = quest.objectives();
	if (objs.length > 0) {
		this.changeTextColor(this.systemColor());
		//this.drawText(Galv.QUEST.txtObj,0,y,w);
		this.drawText(TextManager.RemGALVQuestObjectives,0,y,w);
		this.changeTextColor(this.normalColor());
		y += line + 10;

		// list objectives
		for (var i = 0; i < objs.length; i++) {
			var status = quest._objectives[i] || 0;
			if (status >= 0) {
				var icon = Galv.QUEST['icon' + status];
				this.drawIcon(icon,0,y);
				this.drawTextEx(objs[i],40,y + oy);
				y += line + 8;
			}
		}
	}
};

Window_QuestInfo.prototype.drawNoQuest = function() {
	var y = this.contentsHeight() / 2 - this.standardFontSize() / 2 - this.standardPadding();
	this.drawText(Galv.QUEST.txtNoTrack,0,y,this.contentsWidth(),'center');
};

//-----------------------------------------------------------------------------
//  ADD MENU COMMAND
//-----------------------------------------------------------------------------

if (Galv.QUEST.menuCmd) { // only add this if there's menu command text
	/*
	Galv.QUEST.Window_MenuCommand_addOriginalCommands = Window_MenuCommand.prototype.addOriginalCommands;
	Window_MenuCommand.prototype.addOriginalCommands = function() {
		Galv.QUEST.Window_MenuCommand_addOriginalCommands.call(this);
		this.addQuestCommand();
	};

	Window_MenuCommand.prototype.addQuestCommand = function() {
		var enabled = true;
		this.addCommand(Galv.QUEST.menuCmd, 'quest', enabled);
	};
	*/

	Galv.QUEST.Scene_Menu_createCommandWindow = Scene_Menu.prototype.createCommandWindow;
	Scene_Menu.prototype.createCommandWindow = function() {
		Galv.QUEST.Scene_Menu_createCommandWindow.call(this);
		this._commandWindow.setHandler('quest',      this.commandQuestLog.bind(this));
	};

	Scene_Menu.prototype.commandQuestLog = function() {
		Galv.QUEST.viewLog();
	};
};


code:
//=============================================================================
// Yanfly Engine Plugins - Gamepad Config
// GamepadConfig.js
// Version: 1.01
//=============================================================================

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

var Yanfly = Yanfly || {};
Yanfly.GamepadConfig = Yanfly.GamepadConfig || {};
Yanfly.GamepadConfig.version = 1.01;

//=============================================================================
 /*:
 * @plugindesc v1.01 Allows players to adjust their button configuration
 * for gamepads.
 * @author Yanfly Engine Plugins
 *
 * @param Command Name
 * @desc This is the option name that appears in the main menu.
 * @default Gamepad Config
 *
 * @param Button Name
 * @desc This is how a button name will appear in the config menu.
 * @default Button %1
 *
 * @param OK Button
 * @desc This is the command name for the OK button.
 * @default OK / Talk
 *
 * @param OK Help
 * @desc This is the help description for the OK button.
 * @default Used to accept menu actions and talk to people.
 *
 * @param Cancel Button
 * @desc Cancel Button
 * @desc This is the command name for the Cancel button.
 * @default Cancel
 *
 * @param Cancel Help
 * @desc This is the help description for the Cancel button.
 * @default Used to cancel menu actions.
 *
 * @param Shift Button
 * @desc This is the command name for the Shift button.
 * @default Dash
 *
 * @param Shift Help
 * @desc This is the help description for the Shift button.
 * @default Hold this button to dash on the field.
 *
 * @param Menu Button
 * @desc This is the command name for the Menu button.
 * @default Menu
 *
 * @param Menu Help
 * @desc This is the help description for the Menu button.
 * @default Access the Main Menu from the field.
 *
 * @param PageUp Button
 * @desc This is the command name for the Page Up button.
 * @default Page Up
 *
 * @param PageUp Help
 * @desc This is the help description for the Page Up button.
 * @default Use it to quickly scroll up menus.
 *
 * @param PageDown Button
 * @desc This is the command name for the Page Down button.
 * @default Page Down
 *
 * @param PageDown Help
 * @desc This is the help description for the Page Down button.
 * @default Use it to quickly scroll down menus.
 *
 * @param Reset Default
 * @desc This is the command name to reset the config to default.
 * @default Reset to Default
 *
 * @param Reset Help
 * @desc This is the help description for the Reset button.
 * @default Returns your controller to default settings.
 *
 * @param Finish Config
 * @desc This is the command name for the finish button.
 * @default Finish Configuration
 *
 * @param Finish Help
 * @desc This is the help description for the Finish button.
 * @default Are you done configuring your gamepad?
 *
 * @help
 * Adds a "Gamepad Config" option to the Options Menu if a gamepad is detected.
 * Players can then adjust the button configuration to their liking and it will
 * be loaded automatically each time they play the game. Keep in mind that if
 * at any point where a Gamepad is not detected inside of the Option or Gamepad
 * Config menu, the game will automatically eject the player out the prevent
 * the player from being locked inside.
 *
 * ============================================================================
 * Options Core Settings - Adding the New Options
 * ============================================================================
 *
 * If you are using YEP_OptionsCore.js, you can add a new Option using this
 * plugin. Here's the following code/parameter settings you can use with it.
 *
 * ---------
 * Settings:
 * ---------
 *
 * Name:
 * \i[83]Gamepad Config
 *
 * Help Description:
 * Configure the game's gamepad settings.
 *
 * Symbol:
 * gamepadConfig
 *
 * Show/Hide:
 * if (Imported.GamepadConfig && Input.isControllerConnected()) {
 *   show = !Utils.isMobileDevice();
 * } else {
 *   show = false;
 * }
 *
 * Enable:
 * enabled = true;
 *
 * Ext:
 * ext = 0;
 *
 * ----------
 * Functions:
 * ----------
 *
 * Make Option Code:
 * this.addCommand(name, symbol, enabled, ext);
 *
 * Draw Option Code:
 * var rect = this.itemRectForText(index);
 * var statusWidth = this.statusWidth();
 * var titleWidth = rect.width - statusWidth;
 * this.resetTextColor();
 * this.changePaintOpacity(this.isCommandEnabled(index));
 * this.drawOptionsName(index);
 *
 * Process OK Code:
 * this.playOkSound();
 * SceneManager.push(Scene_GamepadConfig);
 *
 * Cursor Right Code:
 * // Empty. Provided by this plugin.
 *
 * Cursor Left Code:
 * // Empty. Provided by this plugin.
 *
 * Default Config Code:
 * // Empty. Provided by this plugin.
 *
 * Save Config Code:
 * // Empty. Provided by this plugin.
 *
 * Load Config Code:
 * // Empty. Provided by this plugin.
 *
 * ============================================================================
 * Changelog
 * ============================================================================
 *
 * Version 1.01:
 * - Compatibility update with YEP_OptionsCore.js!
 *
 * Version 1.00:
 * - Finished Plugin!
 */
//=============================================================================

//=============================================================================
// Parameter Variables
//=============================================================================

Yanfly.Parameters = PluginManager.parameters('GamepadConfig');
Yanfly.Param = Yanfly.Param || {};

Yanfly.Param.GamepadConfigName = String(Yanfly.Parameters['Command Name']);
Yanfly.Param.GamepadConfigButton = String(Yanfly.Parameters['Button Name']);
Yanfly.Param.GamepadConfigOkTx = String(Yanfly.Parameters['OK Button']);
Yanfly.Param.GamepadConfigOkHelp = String(Yanfly.Parameters['OK Help']);
Yanfly.Param.GamepadConfigCancelTx = String(Yanfly.Parameters['Cancel Button']);
Yanfly.Param.GamepadConfigCancelHelp = String(Yanfly.Parameters['Cancel Help']);
Yanfly.Param.GamepadConfigShiftTx = String(Yanfly.Parameters['Shift Button']);
Yanfly.Param.GamepadConfigShiftHelp = String(Yanfly.Parameters['Shift Help']);
Yanfly.Param.GamepadConfigMenuTx = String(Yanfly.Parameters['Menu Button']);
Yanfly.Param.GamepadConfigMenuHelp = String(Yanfly.Parameters['Menu Help']);
Yanfly.Param.GamepadConfigPgUpTx = String(Yanfly.Parameters['PageUp Button']);
Yanfly.Param.GamepadConfigPgUpHelp = String(Yanfly.Parameters['PageUp Help']);
Yanfly.Param.GamepadConfigPgDnTx = String(Yanfly.Parameters['PageDown Button']);
Yanfly.Param.GamepadConfigPgDnHelp = String(Yanfly.Parameters['PageDown Help']);
Yanfly.Param.GamepadConfigResetTx = String(Yanfly.Parameters['Reset Default']);
Yanfly.Param.GamepadConfigResetHelp = String(Yanfly.Parameters['Reset Help']);
Yanfly.Param.GamepadConfigFinishTx = String(Yanfly.Parameters['Finish Config']);
Yanfly.Param.GamepadConfigFinishHelp = String(Yanfly.Parameters['Finish Help']);

//=============================================================================
// Input
//=============================================================================

Input.getPressedGamepadButton = function() {
	if (Yanfly.Param.GamepadTimer > 0) {
		Yanfly.Param.GamepadTimer -= 1;
		return -1;
	}
	if (navigator.getGamepads) {
		var gamepads = navigator.getGamepads();
		if (gamepads) {
			for (var i = 0; i < gamepads.length; i++) {
				var gamepad = gamepads[i];
				if (gamepad && gamepad.connected) {
					return this.gamepadButtonId(gamepad);
				}
			}
		}
  }
	return -1;
};

Input.gamepadButtonId = function(gamepad) {
  var buttons = gamepad.buttons;
  for (var i = 0; i < buttons.length; i++) {
    if (buttons[i].pressed) return i;
  }
	return -1;
};

Input.getGamepadButton = function(type) {
	for (var i = 0; i < 12; ++i) {
		if (Input.gamepadMapper[i] === type) return i;
	}
	return null;
};

Input.isControllerConnected = function() {
	if (navigator.getGamepads) {
		var gamepads = navigator.getGamepads();
		if (gamepads) {
			for (var i = 0; i < gamepads.length; i++) {
				var gamepad = gamepads[i];
				if (gamepad && gamepad.connected) return true;
			}
		}
	}
	return false;
};

//=============================================================================
// ConfigManager
//=============================================================================

ConfigManager.gamepadInput = {
	0: 'ok',
	1: 'cancel',
	2: 'shift',
	3: 'menu',
	4: 'pageup',
	5: 'pagedown',
	12: 'up',
	13: 'down',
	14: 'left',
	15: 'right',
};

Yanfly.GamepadConfig.ConfigManager_makeData = ConfigManager.makeData;
ConfigManager.makeData = function() {
  var config = Yanfly.GamepadConfig.ConfigManager_makeData.call(this);
	config.gamepadInput = this.gamepadInput;
	return config;
};

Yanfly.GamepadConfig.ConfigManager_applyData = ConfigManager.applyData;
ConfigManager.applyData = function(config) {
  Yanfly.GamepadConfig.ConfigManager_applyData.call(this, config);
	this.gamepadInput = this.readGamepadConfig(config, 'gamepadInput');
	this.applyGamepadConfig();
};

ConfigManager.applyGamepadConfig = function() {
	Input.gamepadMapper = this.gamepadInput;
	Input.update();
	Input.clear();
};

ConfigManager.readGamepadConfig = function(config, name) {
    var value = config[name];
    if (value !== undefined) {
        return value;
    } else {
        return {
					0: 'ok',
					1: 'cancel',
					2: 'shift',
					3: 'menu',
					4: 'pageup',
					5: 'pagedown',
					12: 'up',
					13: 'down',
					14: 'left',
					15: 'right',
				};
    }
};

//=============================================================================
// Window_Options
//=============================================================================

Yanfly.GamepadConfig.Window_Options_addGeneralOptions =
	Window_Options.prototype.addGeneralOptions;
Window_Options.prototype.addGeneralOptions = function() {
  Yanfly.GamepadConfig.Window_Options_addGeneralOptions.call(this);
  if (!Imported.YEP_OptionsCore) this.addGameConfigCommand();
};

Window_Options.prototype.addGameConfigCommand = function() {
	if (Input.isControllerConnected()) {
		this.addCommand(Yanfly.Param.GamepadConfigName, 'gamepadConfig', true);
		this._addedController = true;
	}
};

Yanfly.GamepadConfig.Window_Options_update =
	Window_Options.prototype.update;
Window_Options.prototype.update = function() {
	Yanfly.GamepadConfig.Window_Options_update.call(this);
	if (this._addedController && !Input.isControllerConnected()) {
		this.refresh();
		this.height = this.windowHeight();
		this.updatePlacement();
	}
};

if (!Imported.YEP_OptionsCore) {

Yanfly.GamepadConfig.Window_Options_drawItem =
	Window_Options.prototype.drawItem;
Window_Options.prototype.drawItem = function(index) {
    if (this.commandSymbol(index) === 'gamepadConfig') {
			var rect = this.itemRectForText(index);
			var text = this.commandName(index);
	    this.resetTextColor();
	    this.changePaintOpacity(this.isCommandEnabled(index));
	    this.drawText(text, rect.x, rect.y, rect.width, 'left');
		} else {
			Yanfly.GamepadConfig.Window_Options_drawItem.call(this, index);
		}
};

Yanfly.GamepadConfig.Window_Options_processOk =
	Window_Options.prototype.processOk;
Window_Options.prototype.processOk = function() {
  if (this.commandSymbol(this.index()) === 'gamepadConfig') {
		Window_Command.prototype.processOk.call(this);
	} else {
		Yanfly.GamepadConfig.Window_Options_processOk.call(this);
	}
};

}; // Imported.YEP_OptionsCore

//=============================================================================
// Window_GamepadConfig
//=============================================================================

function Window_GamepadConfig() {
    this.initialize.apply(this, arguments);
}

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

Window_GamepadConfig.prototype.initialize = function(helpWindow) {
	var wy = helpWindow.height;
	Window_Command.prototype.initialize.call(this, 0, wy);
  this.setHelpWindow(helpWindow);
	this.height = Graphics.boxHeight - wy;
	this.refresh();
	this.activate();
	this.select(0);
};

Window_GamepadConfig.prototype.windowWidth = function() {
    return Graphics.boxWidth;
};

Window_GamepadConfig.prototype.makeCommandList = function(index) {
	for (var i = 0; i < 6; ++i) {
		var text = this.getButtonTypeText(i);
		this.addCommand(text, 'button', true);
	}
	this.addCommand('', 'filler', true);
	this.addCommand(this.getButtonTypeText(7), 'reset', true);
	this.addCommand(this.getButtonTypeText(8), 'finish', true);
};

Window_GamepadConfig.prototype.drawItem = function(index) {
	if (index > 5) {
		Window_Command.prototype.drawItem.call(this, index);
	} else {
		var rect = this.itemRectForText(index);
    var align = this.itemTextAlign();
		var ww = rect.width / 2;
    this.resetTextColor();
    this.changePaintOpacity(this.isCommandEnabled(index));
		this.drawText(this.commandName(index), rect.x, rect.y, ww, align);
		var text = this.getButtonConfig(index);
		this.drawText(text, rect.x + ww, rect.y, ww, align);
	}
};

Window_GamepadConfig.prototype.getButtonTypeText = function(index) {
	if (index === 0) return TextManager.yanflyOptionsOkButtonName;
	if (index === 1) return TextManager.yanflyOptionsCancelButtonName;
	if (index === 2) return TextManager.yanflyOptionsShiftButtonName;
	if (index === 3) return TextManager.yanflyOptionsMenuButtonName;
	if (index === 4) return TextManager.yanflyOptionsPageUpButtonName;
	if (index === 5) return TextManager.yanflyOptionsPageDownButtonName;
	if (index === 7) return TextManager.yanflyOptionsResetDefaultName;
	if (index === 8) return TextManager.yanflyOptionsFinishConfigName;
	return '';
};

Window_GamepadConfig.prototype.getButtonConfig = function(index) {
	if (index > 5) return '';
	var key = this.getButtonKey(index);
	var button = Input.getGamepadButton(key);
  return TextManager.yanflyOptionsGamepadButtonName.format(button);
};

Window_GamepadConfig.prototype.getButtonKey = function(index) {
	if (index === 0) return 'ok';
	if (index === 1) return 'cancel';
	if (index === 2) return 'shift';
	if (index === 3) return 'menu';
	if (index === 4) return 'pageup';
	if (index === 5) return 'pagedown';
};

Window_GamepadConfig.prototype.itemTextAlign = function() {
    return 'center';
};

Window_GamepadConfig.prototype.clearButtonConfig = function(index) {
    var rect = this.itemRectForText(index);
		rect.x += rect.width / 2;
		rect.width /= 2;
		this.contents.clearRect(rect.x, rect.y, rect.width, rect.height);
};

Window_GamepadConfig.prototype.updateHelp = function() {
    if (!this._helpWindow) return;
		switch (this.index()) {
		case 0:
			this._helpWindow.setText(TextManager.yanflyOptionsOkButtonHelp);
			break;
		case 1:
			this._helpWindow.setText(TextManager.yanflyOptionsCancelButtonHelp);
			break;
		case 2:
			this._helpWindow.setText(TextManager.yanflyOptionsShiftButtonHelp);
			break;
		case 3:
			this._helpWindow.setText(TextManager.yanflyOptionsMenuButtonHelp);
			break;
		case 4:
			this._helpWindow.setText(TextManager.yanflyOptionsPageUpButtonHelp);
			break;
		case 5:
			this._helpWindow.setText(TextManager.yanflyOptionsPageDownButtonHelp);
			break;
		case 7:
			this._helpWindow.setText(TextManager.yanflyOptionsResetDefaultHelp);
			break;
		case 8:
			this._helpWindow.setText(TextManager.yanflyOptionsFinishConfigHelp);
			break;
		default:
			this._helpWindow.clear();
			break;
		}
};

//=============================================================================
// Scene_Options
//=============================================================================

Yanfly.GamepadConfig.Scene_Options_createOptionsWindow =
	Scene_Options.prototype.createOptionsWindow;
Scene_Options.prototype.createOptionsWindow = function() {
  Yanfly.GamepadConfig.Scene_Options_createOptionsWindow.call(this);
	this._optionsWindow.setHandler('gamepadConfig',
		this.commandGamepadConfig.bind(this));
};

Scene_Options.prototype.commandGamepadConfig = function() {
	SceneManager.push(Scene_GamepadConfig);
};

//=============================================================================
// Scene_GamepadConfig
//=============================================================================

function Scene_GamepadConfig() {
  this.initialize.apply(this, arguments);
}

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

Scene_GamepadConfig.prototype.initialize = function() {
  Scene_MenuBase.prototype.initialize.call(this);
};

Scene_GamepadConfig.prototype.create = function() {
  Scene_MenuBase.prototype.create.call(this);
  this.createHelpWindow();
	this.createGamepadConfigWindow();
};

Scene_GamepadConfig.prototype.terminate = function() {
  Scene_MenuBase.prototype.terminate.call(this);
  ConfigManager.save();
};

Scene_GamepadConfig.prototype.update = function() {
  Scene_MenuBase.prototype.update.call(this);
	this.updateAttachedController();
	this.updateButtonConfig();
	this.updateAfterConfig();
};

Scene_GamepadConfig.prototype.updateAttachedController = function() {
	if (Input.isControllerConnected()) return;
	this.popScene();
};

Scene_GamepadConfig.prototype.createGamepadConfigWindow = function() {
	this._configWindow = new Window_GamepadConfig(this._helpWindow);
	this._configWindow.setHandler('button', this.commandButton.bind(this));
	this._configWindow.setHandler('reset', this.commandReset.bind(this));
	this._configWindow.setHandler('finish', this.popScene.bind(this));
	this.addWindow(this._configWindow);
};

Scene_GamepadConfig.prototype.commandButton = function() {
	var index = this._configWindow.index();
	this._configWindow.clearButtonConfig(index);
	this._configEnabled = true;
	Yanfly.Param.GamepadTimer = 12;
};

Scene_GamepadConfig.prototype.commandReset = function() {
	ConfigManager.gamepadInput = {
		0: 'ok',
		1: 'cancel',
		2: 'shift',
		3: 'menu',
		4: 'pageup',
		5: 'pagedown',
		12: 'up',
		13: 'down',
		14: 'left',
		15: 'right',
	};
	ConfigManager.applyGamepadConfig();
	this.refreshWindows();
};

Scene_GamepadConfig.prototype.refreshWindows = function() {
	this._configWindow.refresh();
	this._configWindow.activate();
	ConfigManager.save();
};

Scene_GamepadConfig.prototype.updateButtonConfig = function() {
	if (!this._configEnabled) return;
	var buttonId = Input.getPressedGamepadButton();
	if (buttonId > 11) return;
	if (buttonId >= 0) this.applyButtonConfig(buttonId);
};

Scene_GamepadConfig.prototype.applyButtonConfig = function(buttonId) {
	this._configEnabled = false;
	var index = this._configWindow.index();
	var newConfig = this._configWindow.getButtonKey(index);
	var formerConfig = Input.gamepadMapper[buttonId];
	var formerButton = Input.getGamepadButton(newConfig);
	ConfigManager.gamepadInput[buttonId] = newConfig;
	ConfigManager.gamepadInput[formerButton] = formerConfig;
	ConfigManager.applyGamepadConfig();
	this._configTimer = 12;
};

Scene_GamepadConfig.prototype.updateAfterConfig = function() {
	if (!this._configTimer) return;
	if (--this._configTimer > 0) return;
	SoundManager.playEquip();
	this.refreshWindows();
};

//=============================================================================
// End of File
//=============================================================================