code:
/*:
 * @plugindesc Writes all errors to a text file in a deployed game so that issues can be accurately reported. <ID: ze_trace_b4ucga>
 * @author Zalerinian
 *
 * @param level
 * @text Log Level
 * @desc The lowest level of events to log. Selecting None will effectively disable the log.
 * @type select
 * @option Error
 * @option Warning
 * @option Info
 * @option Debug
 * @option None
 * @default Error
 *
 * @param file
 * @text Log File
 * @desc The file to use for logging. This is relative to game.exe, NOT the game's content. Default: Log.txt
 * @type text
 * @default Log.txt
 *
 * @param truncate
 * @text Empty Log on Startup
 * @desc Clear the log file each time the game is run. Organizes log files, but results in old errors being cleared out.
 * @type boolean
 * @default true
 *
 * @help
 * ==============================================================================
 * * Overview
 * ==============================================================================
 * This plugin will write errors, warnings, and other messages to a log file for
 * desktop-deployed games. It will disable itself when deployed on the web, so
 * you don't have to worry about removing it for a web export.
 *
 * The types of messages logged by the plugin can be configured using the plugin
 * parameters.
 *
 * ==============================================================================
 * * Changing the behavior
 * ==============================================================================
 * The Trace plugin allows other plugins/developers to alter the logging level
 * After the game has started. The logging level will be stored in save files,
 * and will default to the value define by the plugin if the value is not present
 * in a save.
 *
 * To change the log level of the trace plugin, use the Zale.Trace.setTraceLevel
 * function. You should use one of the constants in the Zale.Trace._Levels
 * object, or you may receive an error. It also helps make your code clearer as
 * to what level you're setting.
 *
 * To change the log file we're using, use the Zale.Trace.setTraceFile function,
 * which will make sure to close the previous file and manage the file handles.
 */

var Zale = Zale || {};
Zale.Trace = {};

var Imported = Imported || {};
Imported["Zale_ConsoleTrace"] = "1.0.0";

(function() {
	'use strict'

	// The plugin is only available on desktop clients, as there is no file system access on the web,
	// and the console will always be available.
	if(Utils.isNwjs()) {
		Zale.Trace._Levels = {
			None: 5,
			Error: 4,
			Warning: 3,
			Info: 2,
			Debug: 1
		};

		Zale.Trace.Level = Zale.Trace._Levels.None;
		Zale.Trace._queue = [];
		Zale.Trace._queueIdx = 0;
		Zale.Trace._fileHandle = -1;
		Zale.Trace._fileHandleBackup = -1;
		Zale.Trace._writing = false;
		Zale.Trace._file = "";
		Zale.Trace._instanceID = Date.now();

		let fs = require('fs');
		let plugin = $plugins.filter(function(p) {
		  return p.description.contains('<ID: ze_trace_b4ucga>') && p.status
		})[0];

		if(plugin == null) {
			internalError("[Trace] Failed to load plugin parameters!");
			return;
		}

		// In order to prevent an infinite loop if there's an error in this plugin, we store the current
		// logging level, set the level to not log anything, log the error in the console as per usual,
		// and then reset the level so future calls to console.error go through the plugin.
		function internalError(message) {
			let level = Zale.Trace.Level;
			Zale.Trace.Level = Zale.Trace._Levels["None"];
			console.error(message);
			Zale.Trace.Level = level;
		}

		// Opens the specified path as the trace file, and store it so we
		// can keep trying to open it if it fails.
		function openTraceFile(path) {
			Zale.Trace._file = path;
			if(Zale.Trace._truncate) {
				fs.open(path, "w", 0o666, handleFileOpen);
			} else {
				fs.open(path, "a", 0o666, handleFileOpen);
			}
		}

		// If there was an error opening the file, try again in 5 seconds. Otherwise, set the
		// file handle, mark that we're no longer switching files, and if we're not writing,
		// write a message if we need to.
		function handleFileOpen(err, fd) {
			if(err != null) {
				internalError("[Trace] Failed to open file for logging. Trying again in 5 seconds.");
				internalError(err);
				setTimeout(function() { Zale.Trace.setTraceFile(Zale.Trace._file); }, 5000);
				return;
			}
			Zale.Trace._fileHandle = fd;
			if(!Zale.Trace._writing) {
				writeMessageIfNeeded();
			}
		}

		// IF we have a valid file handle and there are messages to be written, write them.
		// if the queue length and queue index are equal, then we clear the queue and set the
		// index back to 0, because we caught up with all our messages, and mark writing as false.
		// If we don't have any queued messages or a valid file handle, mark writing as false.
		// If we are writing, we're not done with the queue, and a valid file handle, write the next message!
		function writeMessageIfNeeded() {
			if(Zale.Trace._fileHandle >= 0) {
				if(Zale.Trace._queue.length > 0) {
					if(Zale.Trace._queue.length == Zale.Trace._queueIdx) {
						Zale.Trace._queue.length = 0;
						Zale.Trace._queueIdx = 0;
						Zale.Trace._writing = false;
						return;
					} else {
						Zale.Trace._writing = true;
						let msg = Zale.Trace._queue[Zale.Trace._queueIdx];
						let output = "";
						if(msg.type != null) {
							let rightNow = new Date();
							output = "[" + msg.type.toUpperCase();
							if(!Zale.Trace._truncate) {
								output += " (" + Zale.Trace._instanceID + ") ";
							}
							let hours = rightNow.getHours();
							let ampm = rightNow.getHours() >= 12 ? "pm" : "am";
							hours = hours == 0 ? 12 : hours;
							if(hours > 12) {
								hours -= 12;
							}
							let today = (rightNow.getMonth() + 1) + "/" + rightNow.getDate() + "/" + rightNow.getFullYear();
							let now = hours.padZero(2) + ":" + rightNow.getMinutes().padZero(2) + ":" + rightNow.getSeconds().padZero(2);
							output += " " + today + " " + now + ampm + "] ";
						}
						output += msg.message + "\r\n";
						fs.write(Zale.Trace._fileHandle, output, null, 'utf8', verifyWrite);
					}
				} else {
					Zale.Trace._writing = false;
				}
			} else {
				Zale.Trace._writing = false;
			}
		}

		// Makes sure that there was no error when writing a message to the log. If there was, report it,
		// wait a second, and then try again, without incrementing the queue index so we try that
		// same message again.
		// If it didn't have an error, increment the queue index and see if another message needs to be written.
		function verifyWrite(err, bytesWritten, string) {
			if(err != null) {
				internalError("There was an error writing a message to the log file.");
				internalError(err);
				setTimeout(function() { writeMessageIfNeeded(); }, 1000);
				return;
			}
			Zale.Trace._queueIdx++;
			writeMessageIfNeeded();
		}

		// Verifies that the given value is a valid trace level, and then puts the new level in effect.
		Zale.Trace.setTraceLevel = function(level) {
			if(typeof Zale.Trace._Levels[level] === "number") {
				Zale.Trace.Level = Zale.Trace._Levels[level];
			} else if(typeof level === "number") {
				let keys = Object.keys(Zale.Trace._Levels);
				for(let i = 0; i < keys.length; ++i) {
					if(Zale.Trace._Levels[keys[i]] == level) {
						Zale.Trace.setTraceLevel(keys[i]);
						return;
					}
				}
				internalError("[Trace] " + level + " is does not have a valid level mapping!");
			} else {
				internalError("[Trace] " + level + " is not a valid trace level!");
			}
		}

		// Sets the file we're writing to. If there's already one open, make note of its file handle
		// incase we can't open the new one, and then close and discard the current file handle so
		// that the system will stop writing, instead queueing up any more messages.
		// If the close had an error, we restore the current file, verify that the system has stopped,
		// and then begin writing again.
		// If no file was open, we have nothing to close, so we just open the new one.
		Zale.Trace.setTraceFile = function(filepath) {
			if(Zale.Trace._fileHandle >= 0) {
				if(filepath == Zale.Trace.file) {
					return;
				}
				Zale.Trace._fileHandleBackup = Zale.Trace._fileHandle;
				fs.close(Zale.Trace._fileHandle, function(error) {
					if(error != null) {
						internalError("[Trace] Failed to close old log file");
						internalError(error);
						Zale.Trace._fileHandle = Zale.Trace._fileHandleBackup;
						Zale.Trace._fileHandleBackup = -1;
						if(!Zale.Trace._writing) {
							writeMessageIfNeeded();
						}
						return;
					}
					Zale.Trace._fileHandleBackup = -1;
					openTraceFile(filepath);
				});
				Zale.Trace._fileHandle = -1;
			} else {
				openTraceFile(filepath);
			}
		}

		// If we're not currently writing messages to the queue, try to start it.
		// We need the writing check because this is async recursion. writeMessageIfNeeded has verifyWrite
		// called as it's IO callback, which will then call writeMessageIfNeeded to write the next message
		// in the queue, or to clear the queue and index to free up memory, and to mark that we're no longer
		// writing.
		// If we didn't have this check and called writeMessageIfNeeded multiple times, the callbacks would
		// be called too many times, and we'd try to write a message that doesn't exist, and we'd crash.
		Zale.Trace.logMessage = function(type, message) {
			Zale.Trace._queue.push({type: type, message: message});
			if(!Zale.Trace._writing) {
				writeMessageIfNeeded();
				return;
			}
		}

		// Set the trace level and file according to the plugin parameters.
		Zale.Trace.__params = plugin.parameters;
		Zale.Trace._truncate = plugin.parameters.truncate === "true";
		Zale.Trace.setTraceLevel(plugin.parameters.level);
		Zale.Trace.setTraceFile(plugin.parameters.file);
		if(!Zale.Trace._truncate) {
			//Zale.Trace.logMessage(null, "[Game Startup] Instance ID: " + Zale.Trace._instanceID);
		}

		// Alias the console methods so that they add messages to the queue
		let console_error = console.error;
		console.error = function(msg) {
			if(Zale.Trace.Level <= Zale.Trace._Levels.Error) {
				Zale.Trace.logMessage("error", msg);
			}
			console_error.apply(this, arguments);
		}

		let console_warn = console.warn;
		console.warn = function(msg) {
			if(Zale.Trace.Level <= Zale.Trace._Levels.Warning) {
				Zale.Trace.logMessage("warn", msg);
			}
			console_warn.apply(this, arguments);
		}

		let console_log = console.log;
		console.log = function(msg) {
			if(Zale.Trace.Level <= Zale.Trace._Levels.Info) {
				Zale.Trace.logMessage("info", msg);
			}
			console_log.apply(this, arguments);
		}

		let console_info = console.info;
		console.info = function(msg) {
			if(Zale.Trace.Level <= Zale.Trace._Levels.Info) {
				Zale.Trace.logMessage("info", msg);
			}
			console_info.apply(this, arguments);
		}

		let console_debug = console.debug;
		console.debug = function(msg) {
			if(Zale.Trace.Level <= Zale.Trace._Levels.Debug) {
				Zale.Trace.logMessage("debug", msg);
			}
			console_debug.apply(this, arguments);
		}

		let DataManager_msc = DataManager.makeSaveContents;
		DataManager.makeSaveContents = function() {
			let contents = DataManager_msc.apply(this, arguments);
			contents._zale_trace = {level: Zale.Trace.Level, file: Zale.Trace._file};
			return contents;
		}

		let DataManager_esc = DataManager.extractSaveContents;
		DataManager.extractSaveContents = function(contents) {
			DataManager_esc.apply(this, arguments);
			let settings = contents._zale_trace;
			if(settings == undefined) {
				settings = {level: plugin.parameters.level, file: plugin.parameters.file};
			}
			Zale.Trace.setTraceLevel(settings.level);
			Zale.Trace.setTraceFile(settings.file);
			//console.log("[ConsoleTrace] Set trace level " + settings.level + " in file " + settings.file);
		}

	}
})();


code:
//=============================================================================
// CustomizeErrorScreen.js
// ----------------------------------------------------------------------------
// Copyright (c) 2015 Triacontane
// This software is released under the MIT License.
// http://opensource.org/licenses/mit-license.php
// ----------------------------------------------------------------------------
// Version
// 1.2.0 2016/11/10 連絡先のリンクを開く際に、既定のブラウザで開くよう変更
// 1.1.1 2016/07/13 表記方法を少しだけ変更
// 1.1.0 2016/07/13 ローカル実行時、エラー情報のパスを出力しないよう修正
// 1.0.1 2016/06/25 エラー発生時のリンク先を別画面で開くよう修正
// 1.0.0 2016/05/14 初版
// ----------------------------------------------------------------------------
// [Blog]   : http://triacontane.blogspot.jp/
// [Twitter]: https://twitter.com/triacontane/
// [GitHub] : https://github.com/triacontane/
//=============================================================================

/*:
 * @plugindesc Customize Error Screen
 * @author triacontane
 *
 * @param MainMessage
 * @desc
 * @default !!Error!!
 *
 * @param HyperLink
 * @desc
 * @default
 *
 * @param OutputDetail
 * @desc
 * @default ON
 *
 * @help Visualize detail information for Error Screen.
 *
 * This plugin is released under the MIT License.
 */
/*:ja
 * @plugindesc エラー画面表示改善プラグイン
 * @author トリアコンタン
 *
 * @param メインメッセージ
 * @desc エラー画面に共通で表示されるメッセージ
 * @default 以下のエラーが発生しました。
 *
 * @param ハイパーリンク
 * @desc エラー画面に表示するリンク先URL
 * @default
 *
 * @param 詳細情報出力
 * @desc エラー情報の詳細(スタックトレース)を出力します。
 * @default ON
 *
 * @help エラー画面の表示を改善します。固定メッセージと連絡先のハイパーリンクを
 * 指定できるほか、エラーの詳細情報（スタックトレース）も表示されるようになります。
 * またURL用にエンコードされて表示される全角文字列をもとの文字列に
 * デコードして表示します。
 *
 * このプラグインにはプラグインコマンドはありません。
 *
 * 利用規約：
 *  作者に無断で改変、再配布が可能で、利用形態（商用、18禁利用等）
 *  についても制限はありません。
 *  このプラグインはもうあなたのものです。
 */

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

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

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

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

    //=============================================================================
    // パラメータの取得と整形
    //=============================================================================
    var paramMainMessage  = getParamString(['MainMessage', 'メインメッセージ']);
	//var paramMainMessage  = TextManager.RemErrorMessage;
    var paramHyperLink    = getParamString(['HyperLink', 'ハイパーリンク']);
    var paramOutputDetail = getParamBoolean(['OutputDetail', '詳細情報出力']);

    //=============================================================================
    // SceneManager
    //  エラー情報の出力処理を追加します。
    //=============================================================================
    var _SceneManager_onError = SceneManager.onError;
    SceneManager.onError      = function(e) {
        _SceneManager_onError.apply(this, arguments);
        try {
            Graphics.printErrorDetail(e, decodeURIComponent(e.filename));
        } catch (e2) {
        }
    };

    var _SceneManager_catchException = SceneManager.catchException;
    SceneManager.catchException      = function(e) {
        _SceneManager_catchException.apply(this, arguments);
        Graphics.printErrorDetail(e);
    };

    //=============================================================================
    // Graphics
    //  エラー情報を出力します。
    //=============================================================================
    var _Graphics__makeErrorHtml = Graphics._makeErrorHtml;
    Graphics._makeErrorHtml      = function(name, message) {
        arguments[1] = decodeURIComponent(message);
        return _Graphics__makeErrorHtml.apply(this, arguments);
    };

    Graphics.printErrorDetail = function(e) {
        this.hideFps();
        this._setErrorPrinterStyle();
        if (this._errorPrinter) {
            this._makeMainMessage();
            if (paramHyperLink)    this._makeHyperLink();
            if (paramOutputDetail) {
                var stack = String(e.stack) || '';
                if (Utils.isNwjs()) {
                    stack = stack.replace(/file:.*js\//g, '');
                    stack = stack.replace(/ at /g, '
');
                }
                this._makeStackTrace(stack);
            }
        }
    };

    Graphics._makeMainMessage = function() {
        var mainMessage       = document.createElement('div');
        var style             = mainMessage.style;
        style.color           = 'white';
        style.textAlign       = 'left';
        style.fontSize        = '18px';
        //mainMessage.innerHTML = '
' + paramMainMessage;
		mainMessage.innerHTML = '
' + TextManager.RemErrorMessage;
        this._errorPrinter.appendChild(mainMessage);
    };

    Graphics._makeHyperLink = function() {
        var hyperLink            = document.createElement('a');
        var style                = hyperLink.style;
        style.color              = 'blue';
        style.textAlign          = 'left';
        style.fontSize           = '20px';
        style['text-decoration'] = 'underline';
        style.cursor             = 'pointer';
        hyperLink.addEventListener('click', this._openUrl.bind(this, paramHyperLink));
        hyperLink.innerHTML = paramHyperLink;
        this._errorPrinter.appendChild(hyperLink);
    };

    Graphics._openUrl = function(url) {
        if (!Utils.isNwjs()) {
            window.open(url);
            return;
        }
        var exec = require('child_process').exec;
        switch (process.platform) {
            case 'win32':
                exec('rundll32.exe url.dll,FileProtocolHandler "' + url + '"');
                break;
            default:
                exec('open "' + url + '"');
                break;
        }
    };

    Graphics._makeStackTrace = function(stack) {
        var stackTrace         = document.createElement('div');
        var style              = stackTrace.style;
        style.color            = 'white';
        style.textAlign        = 'left';
        style.fontSize         = '18px';
        style.userSelect       = 'text';
        style.webkitUserSelect = 'text';
        style.msUserSelect     = 'text';
        style.mozUserSelect    = 'text';
        stackTrace.innerHTML   = '

' + stack + '
';
        this._errorPrinter.appendChild(stackTrace);
    };

    Graphics._setErrorPrinterStyle = function() {
        this._errorPrinter.width  = this._width * 0.9;
        this._errorPrinter.height = this._height * 0.9;
        var style                 = this._errorPrinter.style;
        style.textAlign           = 'center';
        style.textShadow          = '1px 1px 3px #000';
        style.fontSize            = '22px';
        style.zIndex              = 99;
        this._centerElement(this._errorPrinter);
    };
})();

repo_name: Rexhunk/karryn

license: unknown


code:
//=============================================================================
// 🏤drowsepost Plugins - Map Camera Controller
// DP_MapZoom.js
// Version: 0.822
// https://github.com/drowsepost/rpgmaker-mv-plugins/blob/master/DP_MapZoom.js
//=============================================================================

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

var drowsepost = drowsepost || {};

//=============================================================================
/*:
 * @plugindesc Control the magnification of the map scene.
 * @author drowsepost
 *
 * @param Base Scale
 * @desc Set the basic magnification ratio.(Start up)
 * Default: 1 (0 or more)
 * @default 1
 *
 * @param Encount Effect
 * @desc Corrected code of encounter effect
 * Default: true (ON: true / OFF: false)
 * @default true
 * @type boolean
 *
 * @param Camera Controll
 * @desc camera control during magnification processing
 * Default: true (ON: true / OFF: false / Minimum: minimum)
 * @default true
 * @type select
 * @option ON
 * @value true
 * @option OFF
 * @value false
 * @option Minimum
 * @value minimum
 *
 * @param Weather Patch
 * @desc Change weather sprite generation range
 * Default: true (ON: true / OFF: false)
 * @default true
 * @type boolean
 *
 * @param Picture Size Fixation
 * @desc Exclude pictures from map zooming process
 * Default: true (ON: true / OFF: false)
 * @default true
 * @type boolean
 *
 * @param Old Focus
 * @desc Use trackless focus similar to the old version.
 * Default: false (ON: true / OFF: false)
 * @default false
 * @type boolean
 *
 * @help
 * ============================================================================
 * About
 * ============================================================================
 * It controls the enlargement ratio of the map scene by
 * reflecting the calculation of the enlargement ratio
 * to various coordinate processing.
 * (sorry... english support is immature. by drowsepost)
 *
 * ============================================================================
 * How To Use
 * ============================================================================
 *
 * ◆ plugin command:
 * dpZoom {zoom ratio} {animate frames} {event id or "this" or "player"}
 * rename: mapSetZoom
 *
 * e.g.:
 * dpZoom 0.8 360 this
 * -> zoom out to 0.8x , animate 360 frames, centering to event of called
 *
 * dpZoom 1
 * -> zoom to 1x(reset), Immediate
 *
 * dpZoom 3 60 1
 * -> zoom to 3x , animate 60 frames, centering to Event id:001
 *
 * dpFocus {event id or "this" or "player"} {animate frames}
 * Place the specified event in the center of the screen without changing
 * the enlargement ratio of the screen.
 * The camera follows the movement of the event
 *
 * ◆ map meta:
 * if you need setting to Default Magnification on the map,
 * fill in the following in the "Note" field
 *
 * <zoomScale: {zoom ratio}>
 * Specify the enlargement ratio to be the basis for each map
 *
 * e.g.:
 * <zoomScale:0.5>
 * -> zoom out to 0.5x , Immediate
 *
 * if you need setting to Default Camera target on the map,
 * fill in the following in the "Note" field
 *
 * <camTarget: {event id or "player"}>
 * Events can be in the center of the screen.
 * The screen follows the movement of the event.
 *
 * e.g.:
 * <camTarget: 3>
 * -> set center of the screen Event ID "3"
 *
 * ============================================================================
 * Technical information
 * ============================================================================
 * If "screenX" or "screenY" used by another plugin is misaligned,
 * multiply "screenX" or "screenY" by "$gameScreen.zoomScale()".
 *
 * This plugin controls "$gameScreen"
 *
 * This plugin use savedata
 * "$gameMap._dp_scale", "$gameMap._dp_pan", "$gameMap._dp_target"
 *
 * license: MIT
 *
 */
 /*:ja
 * @plugindesc マップの拡大率を制御します。
 * @author drowsepost
 *
 * @param Base Scale
 * @desc 基本の拡大率を設定します。(0以上)
 * Default: 1
 * @default 1
 *
 * @param Encount Effect
 * @desc エンカウントエフェクトに拡大率を反映
 * Default: true (ON: true / OFF: false)
 * @default true
 * @type boolean
 *
 * @param Camera Controll
 * @desc 拡大処理中のセンタリング制御をこのプラグインが行う
 * Default: true (ON: true / OFF: false / 最小: minimum)
 * @default true
 * @type select
 * @option ON
 * @value true
 * @option OFF
 * @value false
 * @option Minimum
 * @value minimum
 *
 * @param Weather Patch
 * @desc 天候スプライトの生成範囲を広げる修正を適用します。
 * Default: true (ON: true / OFF: false)
 * @default true
 * @type boolean
 *
 * @param Picture Size Fixation
 * @desc ピクチャをマップの拡大処理から除外します
 * Default: true (ON: true / OFF: false)
 * @default true
 * @type boolean
 *
 * @param Old Focus
 * @desc 古いバージョンの追跡なしのフォーカスを使用します。
 * Default: false (ON: true / OFF: false)
 * @default false
 * @type boolean
 *
 * @help
 * ============================================================================
 * About
 * ============================================================================
 * 各種座標処理に拡大率の計算を反映し
 * マップシーンの拡大率を制御します。
 * また、指定したイベントをカメラが追うように指定します。
 * 標準のフォーカス対象は先頭のプレイヤーとなります。
 *
 * ============================================================================
 * How To Use
 * ============================================================================
 * ◆ マップメモ欄
 *
 * <zoomScale:0.5>
 * などと記述すると、マップごとに基準になる拡大率を指定することが出来ます。
 *
 * <camTarget: 3>
 * 等と記述すると、イベントID n番のイベントが画面中央になった状態にできます。
 * フォーカスはイベントの移動に画面が追従します。
 *
 * ◆ プラグインコマンド
 *
 * (1)ズーム機能
 * dpZoom {倍率} {変更にかけるフレーム数} {対象イベントID / this / player}
 * 指定したイベントにフォーカスを合わせつつ画面の拡大率を変更できます。
 * 第3引数に何も指定しない場合、画面中央に向かって拡大します。
 *
 * 例:
 * プラグインコマンドにおいて対象イベントの部分に
 * 「this」もしくは「このイベント」と指定すると、
 * イベント実行中のオブジェクトを指定します。
 * dpZoom 2 360 this
 * たとえば上記はそのイベントが中心になるように6秒かけて2倍の拡大率に変化します。
 * <非推奨> mapSetZoom は利用できますが、非推奨とします。
 *
 * (2)フォーカス機能
 * dpFocus {対象イベントID / this / player} {変更にかけるフレーム数}
 * 画面の拡大率を変更せずに指定したイベントにフォーカスを合わせます。
 *
 * ============================================================================
 * Settings
 * ============================================================================
 * Base Scale
 * ゲーム開始時の拡大倍率を指定します。
 * 倍率には0以上を指定してください。
 *
 * Encount Effect
 * エンカウントエフェクトを置き換えるかどうかを指定します。
 * オリジナルのエフェクトで置き換えている場合はこちらをfalseにしてください。
 * しかしその場合、画面の拡大率をそれぞれ反映できるように調整する必要があります。
 *
 * Camera Controll
 * falseの場合はイベントを指定した拡大を含む拡大中のカメラ制御は動作しません。
 * 別プラグインでカメラ制御を行う場合にご利用ください。
 *
 * Weather Patch
 * trueの場合、天候スプライトの生成範囲に関する修正を行い、
 * 拡大率変更後も天候スプライトをまんべんなく分布させます
 * 別プラグインで天候演出の制御を行っている場合等はfalseにしてください。
 *
 * Picture Size Fixation
 * trueの場合、ピクチャを拡大処理から除外します。
 *
 * Old Focus
 * trueの場合、古いDP_MapZoom.jsと同様のフォーカス処理を行います。
 * このフォーカス処理は対象イベントまでの座標のずれを基準にしているため、
 * イベントの移動を追尾しません。
 *
 * ============================================================================
 * Technical information
 * ============================================================================
 * 現在の画面の拡大率は$gameScreen.zoomScale()で取得できます。
 * これはプラグインの利用に関わらず元から存在する関数です。
 * 他のプラグインで利用する「screenX」や「screenY」がずれる場合は、
 * 「screenX」や「screenY」にそれぞれ$gameScreen.zoomScale()を掛けて下さい。
 *
 * このプラグインは$gameScreenを制御します。
 *
 * 指定された拡大率設定は$gameMap._dp_scaleが保持します。
 * シーン離脱時のスクロール量は$gameMap._dp_panが保持します。
 * マップのフォーカスイベントは$gameMap._dp_targetが保持します。
 *
 * ライセンス: MIT
 *
 */
(function() {
    "use strict";
    var parameters = PluginManager.parameters('DP_MapZoom');
    var user_scale = Number(parameters['Base Scale'] || 1);
    var user_fix_encount = Boolean(parameters['Encount Effect'] === 'true' || false);
    var user_use_camera = Boolean(parameters['Camera Controll'] === 'true' || false);
    var user_use_camera_transfer = Boolean(parameters['Camera Controll'] === 'minimum' || false);
    var user_fix_weather = Boolean(parameters['Weather Patch'] === 'true' || false);
    var user_fix_picture = Boolean(parameters['Picture Size Fixation'] === 'true' || false);
    var user_use_oldfocus = Boolean(parameters['Old Focus'] === 'true' || false);
    var user_map_marginright = 0;
    var user_map_marginbottom = 0;

    /*
    Main Functions
    =============================================================================
    実際の拡大処理
    */
    var camera = {};

    /*
    dp_renderSize
    タイル拡大率を保持および仮想的なレンダリング範囲を算出します。
    */
    var dp_renderSize = {
        _scale : undefined,
        width: undefined,
        height: undefined,

        /**
         * 拡大率からレンダリングするべきオブジェクトのサイズを設定します。
         * @param {number} scale
         */
        onChange: (function(scale){
            if(!('_scene' in SceneManager)) return;
            if(!('_spriteset' in SceneManager._scene)) return;
            var scale = scale || this._scale;
            var spriteset = SceneManager._scene._spriteset;

            //マップサイズ変更
            spriteset._tilemap.width = Math.ceil((Graphics.width + spriteset._tilemap._margin * 2) / scale);
            spriteset._tilemap.height = Math.ceil((Graphics.height + spriteset._tilemap._margin * 2) / scale);

            //パララックスサイズ変更
            spriteset._parallax.move(0, 0, Math.round(Graphics.width / scale), Math.round(Graphics.height / scale));

            // Foreground.js対応
            if (spriteset._foreground && spriteset._foreground instanceof TilingSprite) {
                spriteset._foreground.move(0, 0, Math.round(Graphics.width / scale), Math.round(Graphics.height / scale));
            }

            spriteset._tilemap.refresh();
        }),

        /**
         * scaleをリセットします
         */
        reset: (function(){
            this.scale = 1;
        })
    };

    Object.defineProperty(dp_renderSize, 'scale', {
        get: function() {
            return this._scale;
        },
        set: function(val) {
            if(val != this._scale) {
                this._scale = Number(val);
                this.width = Math.ceil(Graphics.boxWidth / this._scale);
                this.height = Math.ceil(Graphics.boxHeight / this._scale);
                this.onChange();
            }
        }
    });

    /**
     * ズームすべき座標を算出
     * @return {object} PIXI.Point
     */
    var dp_getZoomPos = function() {
        return new PIXI.Point(
            camera.target.screenX(),
            camera.target.screenY() - ($gameMap.tileHeight() / 2)
        );
    };

    /**
     * マップのレンダリング原点と表示位置のずれを取得します。
     * @return {object} PIXI.Point
     */
    var dp_getVisiblePos = function () {
        var screen = $gameScreen;
        var scale = screen.zoomScale();
        return new PIXI.Point(
            Math.round(screen.zoomX() * (scale - dp_renderSize.scale)),
            Math.round(screen.zoomY() * (scale - dp_renderSize.scale))
        );
    };

    /**
     * フォーカスされているキャラクターから画面の中心がどれだけずれているか取得します
     * @return {object} PIXI.Point
     */
    var dp_getpan = function() {
        var centerPosX = (($gameMap.screenTileX() - 1) / 2);
        var centerPosY = (($gameMap.screenTileY() - 1) / 2);

        var pan_x = ($gameMap.displayX() + centerPosX) - camera.target._realX;
        var pan_y = ($gameMap.displayY() + centerPosY) - camera.target._realY;

        return new PIXI.Point(
            ($gameMap.screenTileX() >= $dataMap.width )? 0 : pan_x,
            ($gameMap.screenTileY() >= $dataMap.height )? 0 : pan_y
        );
    };

    /**
     * 画面の拡大率を設定します。
     * @param {number} scale
     */
    var dp_setZoom = function(scale) {
        dp_renderSize.scale = scale;
        $gameMap._dp_scale = scale;

        $gameScreen.setZoom(0, 0, scale);
        camera.center();
    };

    /*
    Camera Object
    ===================================================================================
    */

    /**
     * カメラのアニメーションを制御するオブジェクト
     */
    camera.animation = (function(){
        //private
        var _active = false;
        var _duration, _target, _pan_target, _pan_prev;

        //public
        var r = {
            /**
             * アニメーションのスタート
             * @param {number} scale 目標とする拡大率
             * @param {object} pos 目標とする座標のズレ PIXI.Point
             * @param {number} dulation 変化にかけるフレーム
             */
            start : (function(scale, pos, duration) {
                var is_zoomout = ($gameScreen.zoomScale() > scale)? true : false;

                _target = scale || $gameScreen.zoomScale();
                _duration = duration || 0;
                _pan_target = pos || new PIXI.Point();
                _pan_prev = dp_getpan();

                if(is_zoomout) {
                    dp_renderSize.scale = scale;
                    camera.center(_pan_prev.x, _pan_prev.y);
                }

                _active = true;
            }),
            /**
             * アニメーションのアップデート
             * camera.animation.update
             */
            update: (function() {
                if(!_active) return;
                if(_duration <= 1) {
                    r.end();
                    return;
                }

                _pan_prev.x = ((_pan_prev.x * (_duration - 1) + _pan_target.x) / _duration);
                _pan_prev.y = ((_pan_prev.y * (_duration - 1) + _pan_target.y) / _duration);

                $gameScreen.setZoom(0, 0, (($gameScreen.zoomScale() * (_duration - 1) + _target) / _duration));
                camera.center(_pan_prev.x, _pan_prev.y);

                _duration--;
            }),
            /**
             * アニメーションの終了
             */
            end : (function() {
                if(!_active) return;
                _active = false;

                $gameMap._dp_pan = _pan_target;
                dp_setZoom(_target);
            })
        };

        return r;
    }());

    /**
     * カメラのズームを開始する関数
     * @param {number} ratio 拡大率
     * @param {number} duration 変化にかけるフレーム
     * @param {any} target フォーカスするイベントIDもしくはゲームイベントオブジェクト
     */
    camera.zoom = function(ratio, duration, target) {
        if((typeof ratio !== 'number') || (ratio < 0)){
            ratio = dp_renderSize.scale;
        }

        var target_pan = dp_getpan();
        if(typeof target !== 'undefined') {
            if(user_use_oldfocus) {
                target_pan = camera.targetPan(target);
            } else {
                camera.target = target;
                target_pan = new PIXI.Point();
            }
        }

        if(duration > 0){
            camera.animation.start(ratio, target_pan, duration);
        } else {
            $gameMap._dp_pan = target_pan;
            dp_setZoom(ratio);
        }
    };

    /**
     * 指定されたイベントIDをイベントインスタンスにして返却
     * @param {any} event イベントIDもしくはイベントオブジェクトもしくはプレイヤー
     * @return {object} Game_CharacterBase
     */
    camera.getEvent = function(event) {
        var _target;
        if(typeof event === 'object') {
            if('_eventId' in event) _target = $gameMap.event(event._eventId);
        }

        if(typeof event === 'number') {
            _target = $gameMap.event(event);
        }

        if(!(_target instanceof Game_CharacterBase)) {
            _target = $gamePlayer;
        }

        return _target;
    }

    /**
     * カメラターゲットから目標イベントまでのマップ上のズレ(x,y)を取得
     * @param {any} event イベントIDもしくはイベントオブジェクトもしくはプレイヤー
     * @return {object} PIXI.Point
     */
    camera.targetPan = function(event) {
        var _target = camera.getEvent(event);

        return new PIXI.Point(
            _target._realX - camera.target._realX,
            _target._realY - camera.target._realY
        );
    };

    /**
     * フォーカスしたターゲットをカメラ中央に配置
     * @param {number} panX 画面をずらすマスの数。横。
     * @param {number} panY 画面をずらすマスの数。縦。
     * @param {boolean} force_center カメラ制御無効でも実行
     */
    camera.center = function(panX, panY, force_center) {
        if((!user_use_camera) && (!force_center)) return;
        var px = Number(panX || $gameMap._dp_pan.x);
        var py = Number(panY || $gameMap._dp_pan.y);
        camera.target.center(camera.target._realX + px, camera.target._realY + py);
    };

    /**
     * カメラがフォーカスする対象
     * @param {any} event イベントIDもしくはゲームイベントもしくはプレイヤー
     * @return {object} ゲームイベントもしくはプレイヤー
     */
    Object.defineProperty(camera, 'target', {
        get: function() {
            if($gameMap._dp_target === 0) return $gamePlayer;
            return $gameMap.event($gameMap._dp_target);
        },
        set: function(event) {
            var _target = camera.getEvent(event);

            $gameMap._dp_target = 0;
            if(typeof _target === 'object') {
                if('_eventId' in _target) $gameMap._dp_target = _target._eventId;
            }
        }
    });

    //公開
    drowsepost.camera = camera;

    /*
    Command Entry
    ===================================================================================
    @param {array} args スペース区切りで指定したプラグインコマンドの引数(array<string>)
    */
    drowsepost.fn = drowsepost.fn || {};

    /**
     * 拡大率を変更せずにフォーカス変更
     * {target} {frame}
     */
    var _p_dpfocus = ('dpFocus' in drowsepost.fn)? drowsepost.fn.dpFocus : (function(){});
    drowsepost.fn.dpFocus = (function(_a){
        _p_dpfocus.call(this, _a);

        var _s = this;
        var _target;

        if(_a.length < 1) _a.push('player');

        if((_a[0] === 'this') || (_a[0] === 'このイベント')) _target = _s;
        else if((_a[0] === 'player') || (_a[0] === 'プレイヤー')) _target = $gamePlayer;
        else _target = parseInt(_a[0]);

        camera.zoom(dp_renderSize.scale, parseInt(_a[1]), _target);
    });

    /**
     * 画面拡大率を変更
     * 第三引数にターゲット指定でフォーカスも変更
     * {zoom} {frame} {target}
     */
    var _p_dpzoom = ('dpZoom' in drowsepost.fn)? drowsepost.fn.dpZoom : (function(){});
    drowsepost.fn.mapSetZoom = drowsepost.fn.dpZoom = (function(_a){
        _p_dpzoom.call(this, _a);

        var _s = this;
        var _target;

        if(_a.length > 2) {
            if((_a[2] === 'this') || (_a[2] === 'このイベント')) _target = _s;
            else if((_a[2] === 'player') || (_a[2] === 'プレイヤー')) _target = $gamePlayer;
            else _target = parseInt(_a[2]);
        }

        camera.zoom(parseFloat(_a[0]), parseInt(_a[1]), _target);
    });

    /*
    Game_Interpreter
    ===================================================================================
    コマンドパーサーの追加
    */
    (function(){
        //@override
        var _parent_pluginCommand = Game_Interpreter.prototype.pluginCommand;
        Game_Interpreter.prototype.pluginCommand = function(command, args) {
            _parent_pluginCommand.call(this, command, args);

            if('DP_Basics' in Imported) return;
            if(!(command in drowsepost.fn)) return;
            if(typeof drowsepost.fn[command] === 'function') {
                drowsepost.fn[command].call(this, args);
            }
        };

    }());

    /*
    Game Map
    =============================================================================
    拡大率($gameScreen.zoomScale())の反映
    */
    (function(){
        //@override
        var _parent_initialize = Game_Map.prototype.initialize;
        Game_Map.prototype.initialize = function() {
            _parent_initialize.call(this);

            //保存用変数エントリー
            this._dp_scale = user_scale;
            this._dp_pan = new PIXI.Point();
            this._dp_target = 0;
        };

        //@override
        Game_Map.prototype.screenTileX = function() {
            return (Graphics.width - user_map_marginright) / (this.tileWidth() * $gameScreen.zoomScale());
        };

        //@override
        Game_Map.prototype.screenTileY = function() {
            return (Graphics.height - user_map_marginbottom) / (this.tileHeight() * $gameScreen.zoomScale());
        };

        //@override
        Game_Map.prototype.canvasToMapX = function(x) {
            var tileWidth = this.tileWidth() * $gameScreen.zoomScale();
            var originX = this._displayX * tileWidth;
            var mapX = Math.floor((originX + x) / tileWidth);
            return this.roundX(mapX);
        };

        //@override
        Game_Map.prototype.canvasToMapY = function(y) {
            var tileHeight = this.tileHeight() * $gameScreen.zoomScale();
            var originY = this._displayY * tileHeight;
            var mapY = Math.floor((originY + y) / tileHeight);
            return this.roundY(mapY);
        };

    }());

    /*
    Game Character
    =============================================================================
    Game Characterに注視する場合の処理を追加
    */
    (function(){
        Game_Character.prototype.centerX = function() {
            return ($gameMap.screenTileX() - 1) / 2.0;
        };

        Game_Character.prototype.centerY = function() {
            return ($gameMap.screenTileY() - 1) / 2.0;
        };

        Game_Character.prototype.center = function(x, y) {
            return $gameMap.setDisplayPos(x - this.centerX(), y - this.centerY());
        };

        Game_Character.prototype.updateScroll = function(lastScrolledX, lastScrolledY) {
            var x1 = lastScrolledX;
            var y1 = lastScrolledY;
            var x2 = this.scrolledX();
            var y2 = this.scrolledY();
            if (y2 > y1 && y2 > this.centerY()) {
                $gameMap.scrollDown(y2 - y1);
            }
            if (x2 < x1 && x2 < this.centerX()) {
                $gameMap.scrollLeft(x1 - x2);
            }
            if (x2 > x1 && x2 > this.centerX()) {
                $gameMap.scrollRight(x2 - x1);
            }
            if (y2 < y1 && y2 < this.centerY()) {
                $gameMap.scrollUp(y1 - y2);
            }
        };

    }());

    /*
    Game Player
    =============================================================================
    拡大率の反映
    */
    (function(){
        //@override
        Game_Player.prototype.centerX = function() {
            return ($gameMap.screenTileX() - 1) / 2.0;
        };

        //@override
        Game_Player.prototype.centerY = function() {
            return ($gameMap.screenTileY() - 1)  / 2.0;
        };

        //@override
        var _parent_updateScroll = Game_Player.prototype.updateScroll;
        Game_Player.prototype.updateScroll = function(lastScrolledX, lastScrolledY) {
            if (typeof $gameMap !== 'object') return;
            if ($gameMap._dp_target !== 0) return;
            _parent_updateScroll.call(this, lastScrolledX, lastScrolledY);
        };

    }());

    /*
    Game Event
    =============================================================================
    Game Eventに注視する場合の処理を追加
    */
    (function(){
        //@override
        var _parent_update = Game_Event.prototype.update;
        Game_Event.prototype.update = function() {
            var lastScrolledX = this.scrolledX();
            var lastScrolledY = this.scrolledY();

            _parent_update.call(this);

            this.updateScroll(lastScrolledX, lastScrolledY);
        };

        Game_Event.prototype.updateScroll = function(lastScrolledX, lastScrolledY) {
            if (typeof $gameMap !== 'object') return;
            if ($gameMap._dp_target !== this._eventId) return;
            Game_Character.prototype.updateScroll.call(this, lastScrolledX, lastScrolledY);
        }

    }());

    /*
    Weather
    =============================================================================
    描画反映変更機能の追加
    */
    (function(){
        //天候スプライトの生成範囲をGraphic基準ではなく実際の描画範囲に合わせる
        if(!user_fix_weather) return;
        //@override
        var _parent_rebornSprite = Weather.prototype._rebornSprite;
        Weather.prototype._rebornSprite = function(sprite) {
            _parent_rebornSprite.call(this, sprite);
            sprite.ax = Math.randomInt(dp_renderSize.width + 100) - 50 + this.origin.x;
            sprite.ay = Math.randomInt(dp_renderSize.height + 200) - 100 + this.origin.y;
            sprite.opacity = 160 + Math.randomInt(60);
        };

    }());

    /*
    Sprite_Picture
    =============================================================================
    ピクチャdot by dot配置機能の追加
    */
    (function(){
        //ピクチャの配置と拡大率を、スクリーンの拡大率で打ち消す
        if(!user_fix_picture) return;

        //@override
        var _parent_updateScale = Sprite_Picture.prototype.updateScale;
        Sprite_Picture.prototype.updateScale = function() {
            _parent_updateScale.call(this);
            var picture = this.picture();
            this.scale.x = (1 / $gameScreen.zoomScale()) * (picture.scaleX() / 100);
            this.scale.y = (1 / $gameScreen.zoomScale()) * (picture.scaleY() / 100);
        };

        //@override
        var _parent_updatePosition = Sprite_Picture.prototype.updatePosition;
        Sprite_Picture.prototype.updatePosition = function() {
            _parent_updatePosition.call(this);
            var picture = this.picture();
            var map_s = dp_getVisiblePos();
            this.x = Math.floor((picture.x() + map_s.x) * (1 / $gameScreen.zoomScale()));
            this.y = Math.floor((picture.y() + map_s.y) * (1 / $gameScreen.zoomScale()));
        };
    }());

    /*
    Spriteset_Base
    =============================================================================
    拡大座標の調整
    */
    (function(){
        //@override
        var _parent_updatePosition = Spriteset_Base.prototype.updatePosition;
        Spriteset_Base.prototype.updatePosition = function() {
            _parent_updatePosition.call(this);

            var map_s = dp_getVisiblePos();
            this.x = map_s.x * -1;
            this.y = map_s.y * -1;

            this.x += Math.round($gameScreen.shake());
        };
    }());

    /*
    Scene_Map
    =============================================================================
    拡大率の引継ぎ
    */
    (function(){
        /*
        マップシーンの開始
        */
        //@override
        var _parent_start = Scene_Map.prototype.start;
        Scene_Map.prototype.start = function() {
            _parent_start.call(this);

            //移動後処理
            if(this._transfer) {
                //マップ設定情報で拡大率変更
                //イベントエディタからのテスト実行では$gameMap.metaが定義されない。
                $gameMap._dp_scale = ('meta' in $dataMap)
                    ? Number($dataMap.meta.zoomScale || $gameMap._dp_scale)
                    : $gameMap._dp_scale;

                //カメラターゲット
                //イベントエディタからのテスト実行では$gameMap.metaが定義されない。
                $gameMap._dp_target = ('meta' in $dataMap)
                    ? Number($dataMap.meta.camTarget || 0)
                    : 0;

                //パン
                $gameMap._dp_pan = new PIXI.Point();
            }

            //標準レンダリングサイズにリセット
            dp_renderSize.reset();

            //カメラターゲット設定
            camera.target = $gameMap._dp_target;

            //マップシーン開始時に拡大率変更をフック。
            dp_setZoom($gameMap._dp_scale);

            //画面中心を強制設定する
            if((!user_use_camera) && user_use_camera_transfer) camera.center(null, null, true);
        };

        /*
        マップシーンの終了
        */
        //@override
        var _parent_terminate = Scene_Map.prototype.terminate;
        Scene_Map.prototype.terminate = function() {
            //マップシーン終了時に拡大率情報を保存。
            camera.animation.end();

            var zoomPos = dp_getZoomPos();
            $gameScreen.setZoom(zoomPos.x, zoomPos.y, dp_renderSize.scale);
            $gameMap._dp_pan = dp_getpan();

            _parent_terminate.call(this);
        };

        /*
        エンカウントエフェクト
        */
        if(!user_fix_encount) return;
        //@override
        Scene_Map.prototype.updateEncounterEffect = function() {
            if (this._encounterEffectDuration > 0) {
                this._encounterEffectDuration--;
                var speed = this.encounterEffectSpeed();
                var n = speed - this._encounterEffectDuration;
                var p = n / speed;
                var q = ((p - 1) * 20 * p + 5) * p + 1;
                var zoomPos = dp_getZoomPos();

                if (n === 2) {
                    $gameScreen.setZoom(zoomPos.x, zoomPos.y, dp_renderSize.scale);
                    this.snapForBattleBackground();
                    this.startFlashForEncounter(speed / 2);
                }

                $gameScreen.setZoom(zoomPos.x, zoomPos.y, (q * dp_renderSize.scale));
                if (n === Math.floor(speed / 6)) {
                    this.startFlashForEncounter(speed / 2);
                }
                if (n === Math.floor(speed / 2)) {
                    BattleManager.playBattleBgm();
                    this.startFadeOut(this.fadeSpeed());
                }
            }
        };
        //エンカウントエフェクトここまで

    }());

    /*
    Game_Screen
    =============================================================================
    アニメーション処理のフック
    */
    (function(){
        //@override
        var _parent_update = Game_Screen.prototype.update;
        Game_Screen.prototype.update = function() {
            _parent_update.call(this);
            camera.animation.update();
        };

        //@override
        var _parent_initialize = Game_Screen.prototype.initialize;
        Game_Screen.prototype.initialize = function() {
            _parent_initialize.call(this);
            dp_renderSize.reset();
        };
    }());

}());


code:
//=============================================================================
// DevToolsManage.js
// ----------------------------------------------------------------------------
// (C)2015-2018 Triacontane
// This software is released under the MIT License.
// http://opensource.org/licenses/mit-license.php
// ----------------------------------------------------------------------------
// Version
// 2.5.1 2018/03/25 BGMが演奏されていないときに高速モードを切り替えるとエラーになる問題を修正
// 2.5.0 2018/03/17 最前面に表示しているとき、画面がフォーカスを失うと画面自動で右寄せになる機能を追加
//                  最新のNW.jsで使用できなくなる一部機能を削除
// 2.4.5 2018/03/06 各種ファンクションキーにCtrlおよびAltの同時押し要否の設定を追加しました。
// 2.4.4 2018/03/03 ブレークポイントから再開したときにキー入力が押しっぱなし扱いになってしまう場合があるMVの仕様を考慮。
// 2.4.3 2018/02/18 2.4.1の機能に加えて他のエディタから起動したとき全般で戦闘テストができるようにしました。
// 2.4.2 2018/02/18 ヘルプの記述を追加
// 2.4.1 2018/02/18 ブラウザ起動時に戦闘テストができる機能を追加しました。オプションのbtestは利用者が付与してください。
// 2.4.0 2018/02/15 ブラウザ起動時もテストプレーと判断した場合は一部の機能が使えるようにしました。
// 2.3.4 2017/12/02 リファクタリング
// 2.3.2 2017/11/23 Fix missing menu bar height at SceneManager.setWindowSizeForMenuBar
// 2.3.1 2017/11/11 画面キャプチャ管理プラグインとの連携による修正
// 2.3.0 2017/09/25 競合対策でマップとデータのリロード機能を無効にする設定を追加
//                  最新のNW.jsかつメニューバーを表示しない場合にエラーになる問題を修正
// 2.2.2 2017/09/25 ヘルプに注意事項を追記
// 2.2.1 2017/09/01 スクリプトエラー発生時に警告を出力する機能を追加
// 2.2.0 2017/08/09 パラメータ型指定機能に対応。一部パラメータは再設定が必要です。
//                  起動時に自動で最前面に表示するパラメータを追加。
//                  NW.jsを最新化したときに発生するエラーに対処（ただし一部機能は使用できません）
// 2.1.1 2017/03/10 コミュニティ版でロード時にエンジン名称を出力するよう修正。
// 2.1.0 2016/12/25 スローモーション機能を追加しました。一時的にゲーム速度を最低1/60倍速まで低下できます。
// 2.0.0 2016/12/16 ES2015向けにリファクタリングしました。
//                  JSON形式でのセーブ＆ロードに対応しました。
//                  ゲーム画面にフォーカスを戻した際に、マップとデータベースの再読込を自動で行うようにしました。
//                  「最前面に表示」機能をゲーム中に切り替えられるようにしました。
//                  一部、余分な機能を無効化しました。
// 1.5.1 2016/08/14 コアスクリプトのバージョンを出力するようにしました。
// 1.5.0 2016/06/25 スクリプトの常駐実行機能を追加
// 1.4.2 2016/06/14 SceneManager.initializeでエラーが発生した際にエラー内容を確認できない問題を修正
// 1.4.1 2016/06/14 YEP_CoreEngine.jsと併用したときにウィンドウ高さ補正が効かなくなる問題を修正
// 1.4.0 2016/06/03 メニューバーからデバッグ用のコマンドを実行できる機能を追加
//                  ゲーム画面の更新を停止し、一時的にフリーズする機能を追加
//                  セーブデータのエンコード・デコード機能を追加
// 1.3.0 2016/05/04 スクリプトのその場実行機能を追加
//                  モバイル偽装機能を追加
//                  コードのリファクタリング
// 1.2.2 2016/03/19 ゲームのスピード高速化を8倍速まで対応
// 1.2.1 2016/02/27 タイトルカットしたときにイベントテスト、戦闘テストが正しく開始されない不具合を修正
// 1.2.0 2016/02/24 ゲームのスピードを高速(2倍速)化する機能を追加
//                  戦闘を勝利扱いで即終了する機能を追加
// 1.1.0 2016/01/11 ゲーム開始時にFPS表示（FPS表示/MS表示に対応）を有効にする機能を追加
//                  タイトル画面を飛ばして最新のセーブファイルをロードする機能を追加
// 1.0.2 2016/01/02 繰り返しリセットすると警告が出る問題の解消
//                  ゲームウィンドウを端に寄せる機能(笑)を追加
// 1.0.1 2015/12/19 F12キーでリセットする機能を追加（F5と同様の動作）
// 1.0.0 2015/12/12 初版
// ----------------------------------------------------------------------------
// [Blog]   : https://triacontane.blogspot.jp/
// [Twitter]: https://twitter.com/triacontane/
// [GitHub] : https://github.com/triacontane/
//=============================================================================

/*:
 * @plugindesc Developer tools management plugin
 * @author triacontane
 *
 * @param StartupDevTool
 * @desc It will start the developer tools at the start of the game.
 * @default true
 * @type boolean
 *
 * @param FuncKeyReload
 * @desc 画面のリロードを行うキーです(F1～F12)。デフォルトF5キーと同様の役割を持ちます。
 * @default F12
 * @option none
 * @option F1
 * @option F2
 * @option F3
 * @option F4
 * @option F5
 * @option F6
 * @option F7
 * @option F8
 * @option F9
 * @option F10
 * @option F11
 * @option F12
 *
 * @param FuncKeyOnTop
 * @desc ゲーム画面を最前面に表示するキーです。(F1～F12)。
 * @default
 * @option none
 * @option F1
 * @option F2
 * @option F3
 * @option F4
 * @option F5
 * @option F6
 * @option F7
 * @option F8
 * @option F9
 * @option F10
 * @option F11
 * @option F12
 *
 * @param FuncKeyRapidGame
 * @desc ゲームを高速化するキーです。(F1～F12)。
 * @default F10
 * @option none
 * @option F1
 * @option F2
 * @option F3
 * @option F4
 * @option F5
 * @option F6
 * @option F7
 * @option F8
 * @option F9
 * @option F10
 * @option F11
 * @option F12
 *
 * @param FuncKeyScript
 * @desc スクリプト実行用のウィンドウをポップアップするキーです。(F1～F12)。
 * @default F6
 * @option none
 * @option F1
 * @option F2
 * @option F3
 * @option F4
 * @option F5
 * @option F6
 * @option F7
 * @option F8
 * @option F9
 * @option F10
 * @option F11
 * @option F12
 *
 * @param FuncKeyFreeze
 * @desc 画面の更新を一時停止するキーです。(F1～F12)。
 * @default
 * @option none
 * @option F1
 * @option F2
 * @option F3
 * @option F4
 * @option F5
 * @option F6
 * @option F7
 * @option F8
 * @option F9
 * @option F10
 * @option F11
 * @option F12
 *
 * @param SimultaneousCtrl
 * @desc 各機能を利用する際にCtrlキーの同時押しが必要かどうかです。他のプラグインと対象キーが競合する場合に利用します。
 * @default false
 * @type boolean
 *
 * @param SimultaneousAlt
 * @desc 各機能を利用する際にAltキーの同時押しが必要かどうかです。他のプラグインと対象キーが競合する場合に利用します。
 * @default false
 * @type boolean
 *
 * @param ShowFPS
 * @desc 初期状態で画面左上にFPSもしくはMSを表示します（FPS/MS/OFF）。
 * @default OFF
 * @type select
 * @option FPS
 * @option MS
 * @option OFF
 *
 * @param CutTitle
 * @desc タイトル画面をとばして最新のセーブファイルをロードします。
 * 起動時にCTRLを押し続けるとカットが無効になります。
 * @default false
 * @type boolean
 *
 * @param RapidStart
 * @desc 高速化された状態でゲームを開始します。（ON/OFF）
 * @default false
 * @type boolean
 *
 * @param RapidSpeed
 * @desc 高速化を実行した際のスピード倍率です。
 * @default 2
 * @type number
 * @min -60
 * @max 16
 *
 * @param FakeMobile
 * @desc モバイル実行を偽装します。(ON/OFF)
 * モバイル版で異なるUIを使用する場合の表示確認ができます。
 * @default false
 * @type boolean
 *
 * @param MenuBarVisible
 * @desc メニューバーを表示し各種デバッグコマンドを実行できます。(ON/OFF)
 * @default true
 * @type boolean
 *
 * @param ClickMenu
 * @desc クリックメニューから各種デバッグコマンドを実行できます。(-1:無効 0:左 1:ホイール 2:右)
 * @default 1
 * @type select
 * @option 無効
 * @value -1
 * @option 左
 * @value 0
 * @option ホイール
 * @value 1
 * @option 右
 * @value 2
 *
 * @param JsonSave
 * @desc JSON形式でセーブ＆ロードできます。テキストエディタ等でセーブファイルを自由に編集できるようになります。
 * @default false
 * @type boolean
 *
 * @param OutputStartupInfo
 * @desc 起動時に様々な情報をログ出力します。
 * @default true
 * @type boolean
 *
 * @param StartupOnTop
 * @desc 起動時にゲーム画面が最前面に固定されます。
 * @default false
 * @type boolean
 *
 * @param UseReloadData
 * @desc オンフォーカスでマップとデータを再読込します。競合等で動作に問題がある場合は無効にしてください。
 * @default true
 * @type boolean
 *
 * @param ShiftRightOnBlur
 * @desc ゲーム画面が最前面に表示されているときにフォーカスを失うと、指定した座標分画面を右寄せします。
 * @default 640
 * @type number
 *
 * @help デベロッパツールの挙動を調整する制作支援プラグインです。
 * このプラグインはローカル環境でのテストプレー時のみ有効となります。
 * また、UserAgentやコアスクリプトのバージョン等役立つ情報をログに出力します。
 * 快適な開発支援のために以下の機能を提供します。
 *
 * 1. ゲーム開始時にデベロッパツールが自動で立ち上がります。(通常はF8で起動)
 *    OFFにしていた場合でもエラーが発生すると自動で立ち上がります。
 *
 * 2. ゲーム画面を常に最前面に表示してくれます。画面を見ながら作業をする場合に便利です。
 *    ゲーム中にメニューバーから切り替えできます。
 *
 * 3. マップやイベントを修正して再保存すると、ゲーム画面にフォーカスを戻した瞬間に
 *    マップとデータベースを自動でリロードしてくれます。
 *
 * 4. タイトル画面を飛ばして最新のセーブファイルをロードできます。
 *
 * 5. マップ上でのゲームのスピードを高速化(8倍速まで)できます。
 *    (マップ上で高速、フェードアウト、メッセージ表示の高速スキップ)
 *    ゲームスピードが高速の場合は、BGMのピッチが変化します。
 *
 * 6. 強制的に敵を全滅させて勝利することができます。報酬も取得できます。
 *
 * 7. 任意のスクリプトを毎フレーム実行させることができます。
 *    スクリプトの戻り値が変化したときのみ結果をコンソールに出力します。
 *
 * 8. ゲーム画面の更新を一時的に止めて画面をフリーズさせることができます。
 *
 * 9. セーブデータを保存する際にエンコーディングせずjson形式のままセーブ・ロードできます。
 *
 * このプラグインにはプラグインコマンドはありません。
 *
 * ver2.2.0にて型指定機能に対応したことで一部パラメータの再設定が必要になりました。
 * それ以前からアップデートした場合プラグイン管理画面から一度、削除して再設定してください。
 *
 * 画面キャプチャ管理プラグインと連携すると画面キャプチャ用のメニューバーが表示されます。
 * https://raw.githubusercontent.com/triacontane/RPGMakerMV/master/MakeScreenCapture.js
 *
 * ブラウザ起動時でも当プラグインのデバッグ機能を有効にしたい場合は、起動URLのオプションに
 * 「test」もしくは「best」を付与してください。
 * ただしNW.js由来のいくつかの機能は無効になります。
 *
 * This plugin is released under the MIT License.
 */

/*:ja
 * @plugindesc 総合開発支援プラグイン
 * @author トリアコンタン
 *
 * @param 開始時に起動
 * @desc ゲーム開始時に同時にデベロッパツールを起動します。
 * @default true
 * @type boolean
 *
 * @param リロードキー
 * @desc 画面のリロードを行うキーです(F1～F12)。デフォルトF5キーと同様の役割を持ちます。
 * 以前のツクールとの後方互換性を持たせるための機能です。
 * @default F12
 * @type select
 * @option none
 * @option F1
 * @option F2
 * @option F3
 * @option F4
 * @option F5
 * @option F6
 * @option F7
 * @option F8
 * @option F9
 * @option F10
 * @option F11
 * @option F12
 *
 * @param 最前面に表示キー
 * @desc ゲーム画面を最前面表示を切り替えるキーです。(F1～F12)。
 * @default F11
 * @type select
 * @option none
 * @option F1
 * @option F2
 * @option F3
 * @option F4
 * @option F5
 * @option F6
 * @option F7
 * @option F8
 * @option F9
 * @option F10
 * @option F11
 * @option F12
 *
 * @param 高速化切替キー
 * @desc ゲームの高速化を切り替えるキーです。(F1～F12)。
 * @default
 * @type select
 * @option none
 * @option F1
 * @option F2
 * @option F3
 * @option F4
 * @option F5
 * @option F6
 * @option F7
 * @option F8
 * @option F9
 * @option F10
 * @option F11
 * @option F12
 *
 * @param 強制戦闘勝利キー
 * @desc 戦闘を勝利扱いで強制終了するキーです。(F1～F12)。
 * @default
 * @type select
 * @option none
 * @option F1
 * @option F2
 * @option F3
 * @option F4
 * @option F5
 * @option F6
 * @option F7
 * @option F8
 * @option F9
 * @option F10
 * @option F11
 * @option F12
 *
 * @param スクリプト実行キー
 * @desc スクリプト常駐実行用のキーです。(F1～F12)。
 * @default
 * @type select
 * @option none
 * @option F1
 * @option F2
 * @option F3
 * @option F4
 * @option F5
 * @option F6
 * @option F7
 * @option F8
 * @option F9
 * @option F10
 * @option F11
 * @option F12
 *
 * @param フリーズキー
 * @desc 画面の更新を一時停止するキーです。(F1～F12)。
 * @default F10
 * @type select
 * @option none
 * @option F1
 * @option F2
 * @option F3
 * @option F4
 * @option F5
 * @option F6
 * @option F7
 * @option F8
 * @option F9
 * @option F10
 * @option F11
 * @option F12
 *
 * @param Ctrl同時押し
 * @desc 各機能を利用する際にCtrlキーの同時押しが必要かどうかです。他のプラグインと対象キーが競合する場合に利用します。
 * @default false
 * @type boolean
 *
 * @param Alt同時押し
 * @desc 各機能を利用する際にAltキーの同時押しが必要かどうかです。他のプラグインと対象キーが競合する場合に利用します。
 * @default false
 * @type boolean
 *
 * @param FPS表示
 * @desc 初期状態で画面左上にFPSを表示します。（FPS/MS/OFF）
 * @default OFF
 * @type select
 * @option FPS
 * @option MS
 * @option OFF
 *
 * @param タイトルカット
 * @desc タイトル画面をとばして最新のセーブファイルをロードします。
 * 起動時にCTRLを押し続けるとカットが無効になります。
 * @default false
 * @type boolean
 *
 * @param 高速開始
 * @desc 高速化された状態でゲームを開始します。（ON/OFF）
 * @default false
 * @type boolean
 *
 * @param 高速スピード
 * @desc 高速化を実行した際のスピード倍率です。(-60...16)
 * 負の値を設定するとスローモーションになります。
 * @default 2
 * @type number
 * @min -60
 * @max 16
 *
 * @param モバイル偽装
 * @desc モバイル実行を偽装します。(ON/OFF)
 * モバイル版で異なるUIを使用する場合の表示確認ができます。
 * @default false
 * @type boolean
 *
 * @param メニューバー表示
 * @desc メニューバーを表示し各種デバッグコマンドを実行できます。(ON/OFF)
 * @default true
 * @type boolean
 *
 * @param クリックメニュー
 * @desc クリックメニューから各種デバッグコマンドを実行できます。(-1:無効 0:左 1:ホイール 2:右)
 * @default 1
 * @type select
 * @option 無効
 * @value -1
 * @option 左
 * @value 0
 * @option ホイール
 * @value 1
 * @option 右
 * @value 2
 *
 * @param JSON形式セーブ
 * @desc JSON形式でセーブ＆ロードできます。テキストエディタ等でセーブファイルを自由に編集できるようになります。
 * @default false
 * @type boolean
 *
 * @param 起動時情報出力
 * @desc 起動時に様々な情報をログ出力します。
 * @default true
 * @type boolean
 *
 * @param 最前面で起動
 * @desc 起動時にゲーム画面が最前面に固定されます。
 * @default false
 * @type boolean
 *
 * @param リロード機能を使う
 * @desc オンフォーカスでマップとデータを再読込します。競合等で動作に問題がある場合は無効にしてください。
 * @default true
 * @type boolean
 *
 * @param 右寄せ座標
 * @desc ゲーム画面が最前面に表示されているときにフォーカスを失うと、指定した座標分画面を右寄せします。
 * @default 640
 * @type number
 *
 * @help デベロッパツールの挙動を調整する制作支援プラグインです。
 * このプラグインはローカル環境でのテストプレー時のみ有効となります。
 * また、UserAgentやコアスクリプトのバージョン等役立つ情報をログに出力します。
 * 快適な開発支援のために以下の機能を提供します。
 *
 * 1. ゲーム開始時にデベロッパツールが自動で立ち上がります。(通常はF8で起動)
 *    OFFにしていた場合でもエラーが発生すると自動で立ち上がります。
 *
 * 2. ゲーム画面を常に最前面に表示してくれます。画面を見ながら作業をする場合に便利です。
 *    ゲーム中にメニューバーから切り替えできます。
 *
 * 3. マップやイベントを修正して再保存すると、ゲーム画面にフォーカスを戻した瞬間に
 *    マップとデータベースを自動でリロードしてくれます。
 *
 * 4. タイトル画面を飛ばして最新のセーブファイルをロードできます。
 *
 * 5. マップ上でのゲームのスピードを高速化(16倍速まで)できます。
 *    (マップ上で高速、フェードアウト、メッセージ表示の高速スキップ)
 *    逆に低速化(1/60倍速まで)することもできます。速度倍率に負の値を設定してください。
 *    ゲームスピードが変化した場合は、BGMのピッチが変化します。
 *
 * 6. 強制的に敵を全滅させて勝利することができます。報酬も取得できます。
 *
 * 7. 任意のスクリプトを毎フレーム実行させることができます。
 *    スクリプトの戻り値が変化したときのみ結果をコンソールに出力します。
 *
 * 8. ゲーム画面の更新を一時的に止めて画面をフリーズさせることができます。
 *
 * 9. セーブデータを保存する際にエンコーディングせずjson形式のままセーブ・ロードできます。
 *
 * このプラグインにはプラグインコマンドはありません。
 *
 * ver2.2.0にて型指定機能に対応したことで一部パラメータの再設定が必要になりました。
 * それ以前からアップデートした場合プラグイン管理画面から一度、削除して再設定してください。
 *
 * 画面キャプチャ管理プラグインと連携すると画面キャプチャ用のメニューバーが表示されます。
 * https://raw.githubusercontent.com/triacontane/RPGMakerMV/master/MakeScreenCapture.js
 *
 * ブラウザ起動時でも当プラグインのデバッグ機能を有効にしたい場合は、起動URLのオプションに
 * 「test」もしくは「best」を付与してください。
 * ただしNW.js由来のいくつかの機能は無効になります。
 *
 * 外部エディタから起動する場合、以下の起動パラメータが指定可能です。
 * この指定はプラグインパラメータより優先されます。
 * devToolOff : デベロッパツールが起動しなくなります。
 * onTop : 最前面に画面を表示します。
 *
 * 利用規約：
 *  作者に無断で改変、再配布が可能で、利用形態（商用、18禁利用等）
 *  についても制限はありません。
 *  このプラグインはもうあなたのものです。
 */

var p = null;

/**
 * Controller_NwJs
 * NW.jsのウィンドウを操作します。
 * @constructor
 */
function Controller_NwJs() {
    this.initialize.apply(this, arguments);
}

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

    //=============================================================================
    // p
    //  ログ出力をより短い関数名で実現します。(RGSS互換)
    //=============================================================================
    p = function() {
        console.log.apply(console, arguments);
        SceneManager.getNwJs().showDevTools();
    };

    //=============================================================================
    // ローカル関数
    //  プラグインパラメータやプラグインコマンドパラメータの整形やチェックをします
    //=============================================================================
    const getParamString = function(paramNames, upperFlg) {
        const value = getParamOther(paramNames);
        return value === null ? '' : upperFlg ? value.toUpperCase() : 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 getParamBoolean = function(paramNames) {
        const value = getParamOther(paramNames);
        return (value || '').toUpperCase() === 'ON' || (value || '').toUpperCase() === 'TRUE';
    };

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

    const paramStartupDevTool    = getParamBoolean(['StartupDevTool', '開始時に起動']);
    const paramFuncKeyReload     = getParamString(['FuncKeyReload', 'リロードキー']);
    const paramFuncKeyOnTop      = getParamString(['FuncKeyOnTop', '最前面に表示キー']);
    const paramFuncKeyRapidGame  = getParamString(['FuncKeyRapidGame', '高速化切替キー']);
    const paramFuncKeyVictory    = getParamString(['FuncKeyVictory', '強制戦闘勝利キー']);
    const paramFuncKeyScript     = getParamString(['FuncKeyScript', 'スクリプト実行キー']);
    const paramFuncKeyFreeze     = getParamString(['FuncKeyFreeze', 'フリーズキー']);
    const paramShowFPS           = getParamString(['ShowFPS', 'FPS表示'], true);
    const paramCutTitle          = getParamBoolean(['CutTitle', 'タイトルカット']);
    const paramRapidStart        = getParamBoolean(['RapidStart', '高速開始']);
    const paramRapidSpeed        = getParamNumber(['RapidSpeed', '高速スピード'], -60, 16);
    const paramFakeMobile        = getParamBoolean(['FakeMobile', 'モバイル偽装']);
    const paramMenuBarVisible    = getParamBoolean(['MenuBarVisible', 'メニューバー表示']);
    const paramClickMenu         = getParamNumber(['ClickMenu', 'クリックメニュー'], -1);
    const paramJsonSave          = getParamBoolean(['JsonSave', 'JSON形式セーブ']);
    const paramOutputStartupInfo = getParamBoolean(['OutputStartupInfo', '起動時情報出力']);
    const paramStartupOnTop      = getParamBoolean(['StartupOnTop', '最前面で起動']);
    const paramUseReloadData     = getParamBoolean(['UseReloadData', 'リロード機能を使う']);
    const paramSimultaneousCtrl  = getParamBoolean(['SimultaneousCtrl', 'Ctrl同時押し']);
    const paramSimultaneousAlt   = getParamBoolean(['SimultaneousAlt', 'Alt同時押し']);
    const paramShiftRightOnBlur  = getParamNumber(['ShiftRightOnBlur', '右寄せ座標'], -1000, 1000);

    //=============================================================================
    // Graphics
    //  FPSの表示を設定します。
    //=============================================================================
    Graphics.setFPSMeter = function(type) {
        switch (type) {
            case 'FPS':
                this.hideFps();
                this._switchFPSMeter();
                break;
            case 'MS':
                this.hideFps();
                this._switchFPSMeter();
                this._switchFPSMeter();
                break;
        }
    };

    const _Graphics__createAllElements = Graphics._createAllElements;
    Graphics._createAllElements        = function() {
        _Graphics__createAllElements.apply(this, arguments);
        if (paramOutputStartupInfo) {
            this.outputStartUpLog();
        }
    };

    Graphics.outputStartUpLog = function() {
        console.log('********************************');
        console.log('***   User Agent             ***');
        console.log('********************************');
        console.log(navigator.userAgent);
        console.log('********************************');
        console.log('***   Core Version           ***');
        console.log('********************************');
        console.log('RPG Maker Name    : ' + Utils.RPGMAKER_NAME);
        console.log('RPG Maker Version : ' + Utils.RPGMAKER_VERSION);
        console.log('RPG Maker Engine  : ' + (Utils.RPGMAKER_ENGINE || 'Official Version'));
        console.log('********************************');
        console.log('***   Audio                  ***');
        console.log('********************************');
        console.log('Can Play OGG : ' + WebAudio.canPlayOgg());
        console.log('Can Play M4A : ' + WebAudio.canPlayM4a());

        if (Utils.isNwjs()) {
            console.log('********************************');
            console.log('***   Environment            ***');
            console.log('********************************');
            console.log('Platform : ' + process.platform);
            console.log(process.env);
            console.log('*********************************');
            console.log('***   document head           ***');
            console.log('*********************************');
            console.log(document.head);
            console.log('*********************************');
            console.log('***   document body           ***');
            console.log('*********************************');
            console.log(document.body);
        }
    };

    // テストプレー時以外は以降の機能を無効
    if (!Utils.isOptionValid('test') && !DataManager.isBattleTest()) {
        console.log(pluginName + ' is valid only test play!');
        return;
    }

    //=============================================================================
    // Utils
    //  モバイルモードを偽装します。
    //=============================================================================
    const _Utils_isMobileDevice = Utils.isMobileDevice;
    Utils.isMobileDevice        = function() {
        return _Utils_isMobileDevice.apply(this, arguments) || paramFakeMobile;
    };

    Utils.isNwjsNormal = function() {
        return this.isNwjs() && navigator.userAgent.match(/Chrome\/4/);
    };

    //=============================================================================
    // Input
    //  promptを再定義します。
    //=============================================================================
    const _Input_wrapNwjsAlert = Input._wrapNwjsAlert;
    Input._wrapNwjsAlert       = function() {
        _Input_wrapNwjsAlert.apply(this, arguments);
        const _window_prompt = window.prompt;
        window.prompt        = function(value, defaultValue) {
            return SceneManager.getNwJs().prompt(value, defaultValue, _window_prompt);
        };
    };

    Input.functionReverseMapper = {
        F1 : 112,
        F2 : 113,
        F3 : 114,
        F4 : 115,
        F5 : 116,
        F6 : 117,
        F7 : 118,
        F8 : 119,
        F9 : 120,
        F10: 121,
        F11: 122,
        F12: 123
    };

    var _Input__shouldPreventDefault = Input._shouldPreventDefault;
    Input._shouldPreventDefault = function(keyCode) {
        return _Input__shouldPreventDefault.apply(this, arguments) || keyCode === 9; // Tab
    };

    //=============================================================================
    // SceneManager
    //  状況に応じてデベロッパツールを自動制御します。
    //=============================================================================
    SceneManager.originalTitle     = null;
    SceneManager._rapidGame        = false;
    SceneManager._lastScriptString = null;
    SceneManager._lastScriptResult = null;

    const _SceneManager_initialize = SceneManager.initialize;
    SceneManager.initialize        = function() {
        _SceneManager_initialize.apply(this, arguments);
        this.initDevCommand();
        Graphics.setFPSMeter(paramShowFPS);
        if (!Utils.isNwjs()) {
            return;
        }
        this._freeze  = false;
        this._nwJsGui = new Controller_NwJs();
        if (this.isAlwaysOnTop()) {
            this._nwJsGui.toggleAlwaysOnTop();
        }
    };

    SceneManager.initDevCommand = function() {
        this.devCommands = [
            {code: 102, use: true, name: '最前面に表示', key: paramFuncKeyOnTop, type: 'checkbox'},
            {code: 103, use: true, name: 'リロード', key: paramFuncKeyReload, type: 'normal'},
            {code: 104, use: true, name: '高速モード切替', key: paramFuncKeyRapidGame, type: 'checkbox'},
            {code: 105, use: true, name: '戦闘強制勝利', key: paramFuncKeyVictory, type: 'normal'},
            {code: 106, use: true, name: '常駐スクリプト実行', key: paramFuncKeyScript, type: 'normal'},
            {code: 107, use: true, name: '画面フリーズ', key: paramFuncKeyFreeze, type: 'checkbox'},
            {code: 108, use: !!SceneManager.takeCapture, name: '画面キャプチャ', key: null, type: 'normal'}
        ];
    };

    SceneManager.getNwJs = function() {
        return this._nwJsGui;
    };

    SceneManager.isAlwaysOnTop = function() {
        return paramStartupOnTop || Utils.isOptionValid('onTop');
    };

    SceneManager.toggleFreeze = function() {
        Input.clear();
        this._freeze = !this._freeze;
        this.updateDocumentTitle();
        return this._freeze;
    };

    const _SceneManager_catchException = SceneManager.catchException;
    SceneManager.catchException        = function(e) {
        if (this._nwJsGui) this._nwJsGui.showDevTools(false);
        _SceneManager_catchException.apply(this, arguments);
    };

    const _SceneManager_onError = SceneManager.onError;
    SceneManager.onError        = function(e) {
        if (this._nwJsGui) this._nwJsGui.showDevTools(false);
        _SceneManager_onError.apply(this, arguments);
    };

    const _SceneManager_onKeyDown = SceneManager.onKeyDown;
    SceneManager.onKeyDown        = function(event) {
        _SceneManager_onKeyDown.apply(this, arguments);
        if (paramSimultaneousCtrl === event.ctrlKey && paramSimultaneousAlt === event.altKey) {
            this.onKeyDownForDevToolManage(event);
        }
    };

    SceneManager.onKeyDownForDevToolManage = function(event) {
        let commandCode = null;
        this.devCommands.some(function(commandInfo) {
            if (Input.functionReverseMapper[commandInfo.key] === event.keyCode) {
                commandCode = commandInfo.code;
                return true;
            }
            return false;
        });
        if (commandCode && this._nwJsGui) this.executeDevCommand(commandCode, event);
    };

    SceneManager.executeDevCommand = function(code, event) {
        const command = this['executeDevCommand' + code];
        return command ? command.call(SceneManager, event) : null;
    };

    SceneManager.executeDevCommand102 = function() {
        return this._nwJsGui.toggleAlwaysOnTop();
    };

    SceneManager.executeDevCommand103 = function() {
        location.reload();
    };

    SceneManager.executeDevCommand104 = function() {
        return this.toggleRapid();
    };

    SceneManager.executeDevCommand105 = function() {
        BattleManager.forceVictory();
    };

    SceneManager.executeDevCommand106 = function() {
        this.showScriptDialog();
    };

    SceneManager.executeDevCommand107 = function() {
        return this.toggleFreeze();
    };

    SceneManager.executeDevCommand108 = function() {
        return this.takeCapture();
    };

    SceneManager.isRapid = function() {
        return SceneManager._rapidGame && paramRapidSpeed > 1;
    };

    SceneManager.isSlow = function() {
        return SceneManager._rapidGame && paramRapidSpeed < -1;
    };

    SceneManager.toggleRapid = function() {
        this._rapidGame = !this._rapidGame;
        const bgm       = AudioManager.saveBgm();
        if (bgm.name) {
            AudioManager.playBgm(bgm, bgm.pos);
            AudioManager._bgmBuffer.play(true, bgm.pos);
        }
        this.updateDocumentTitle();
        return this.isRapid();
    };

    SceneManager.updateDocumentTitle = function() {
        if (!this.originalTitle) {
            this.originalTitle = document.title;
        }
        document.title = this.originalTitle + this.addDocumentTitleRapidOrSlow() +
            this.addDocumentTitleAlwaysOnTop() +
            this.addDocumentTitleFreeze();
    };

    SceneManager.addDocumentTitleRapidOrSlow = function() {
        if (this.isRapid()) {
            return ' [!!!Rapid!!!] * ' + paramRapidSpeed;
        } else if (this.isSlow()) {
            return ' [!!!Slow!!!] / ' + -paramRapidSpeed;
        } else {
            return '';
        }
    };

    SceneManager.addDocumentTitleAlwaysOnTop = function() {
        return this._nwJsGui.isOnTop() ? ' [!!!Always On Top!!!]' : '';
    };

    SceneManager.addDocumentTitleFreeze = function() {
        return this._freeze ? ' [!!!Freeze!!!]' : '';
    };

    SceneManager.isCurrentScene = function(sceneClass) {
        return this._scene && this._scene.constructor === sceneClass;
    };

    SceneManager.showScriptDialog = function() {
        const promptValue  = '常駐実行したいスクリプトを入力してください。';
        const scriptString = window.prompt(promptValue, this._nwJsGui.readClipboard());
        if (scriptString !== null && scriptString !== '') {
            this._nwJsGui.showDevTools();
            this._nwJsGui.writeClipboard(scriptString);
            this.executeScript(scriptString);
            this._lastScriptString = scriptString;
        }
    };

    SceneManager.executeScript = function(scriptString) {
        let result = null;
        try {
            result = eval(scriptString);
            if (!this._lastScriptString) {
                SoundManager.playOk();
                console.log('Execute Script : ' + scriptString);
                console.log('Execute Result : ');
            }
        } catch (e) {
            if (!this._lastScriptString) {
                SoundManager.playBuzzer();
                console.log('Error Script : ' + scriptString);
                console.error(e.stack);
            }
            result = e.toString();
        }
        if (!this._lastScriptString || result !== this._lastScriptResult) {
            console.log(result);
        }
        this._lastScriptResult = result;
    };

    const _SceneManager_initNwjs = SceneManager.initNwjs;
    SceneManager.initNwjs        = function() {
        _SceneManager_initNwjs.apply(this, arguments);
        if (Utils.isNwjs()) {
            this.addMenuBar();
        }
    };

    SceneManager.addMenuBar = function() {
        if (!paramMenuBarVisible) {
            this._needAdjustScreen = false;
            return;
        }
        const gui        = require('nw.gui');
        const gameWindow = gui.Window.get();
        if (!gameWindow.menu || gameWindow.menu.type !== 'menubar') {
            this._needAdjustScreen = true;
        }
        gameWindow.menu = new gui.Menu({type: 'menubar'});
    };

    const _SceneManager_run = SceneManager.run;
    SceneManager.run        = function(sceneClass) {
        _SceneManager_run.apply(this, arguments);
        this.setWindowSizeForMenuBar();
    };

    SceneManager.setWindowSizeForMenuBar = function() {
        if (!this._needAdjustScreen) {
            return;
        }
        const gui        = require('nw.gui');
        const gameWindow = gui.Window.get();
        var height       = this.getMenuBarHeight();
        gameWindow.moveBy(0, -height);
        gameWindow.resizeBy(0, height);

        setTimeout(function() { // Fix missing menu bar height
            var style_height = parseInt(Graphics._canvas.style.height, 10);
            var height_diff  = SceneManager._screenHeight - style_height;
            if (height_diff !== 0) {
                gameWindow.moveBy(0, -height_diff);
                gameWindow.resizeBy(0, height_diff);
            }
        }, 500);
    };

    SceneManager.getMenuBarHeight = function() {
        return Utils.isNwjsNormal() ? 20 : 25;
    };

    const _SceneManager_requestUpdate = SceneManager.requestUpdate;
    SceneManager._updateRateCount     = 0;
    SceneManager.requestUpdate        = function() {
        if (this.isSlow()) {
            this._updateRateCount++;
            if (this._updateRateCount >= -paramRapidSpeed) {
                this.updateInputData();
                _SceneManager_requestUpdate.apply(this, arguments);
                this._updateRateCount = 0;
            } else if (!this._stopped) {
                requestAnimationFrame(this.requestUpdate.bind(this));
            }
        } else {
            this._updateRateCount = 0;
            _SceneManager_requestUpdate.apply(this, arguments);
        }
    };

    const _SceneManager_updateMain = SceneManager.updateMain;
    SceneManager.updateMain        = function() {
        if (this.isSlow()) {
            this.changeScene();
            this.updateScene();
            this.renderScene();
            this.requestUpdate();
        } else {
            const newTime = this._getTimeInMsWithoutMobileSafari();
            // for break point
            if (newTime - this._currentTime > 1000) {
                Input.clear();
            }
            _SceneManager_updateMain.apply(this, arguments);
        }
    };

    const _SceneManager_updateScene = SceneManager.updateScene;
    SceneManager.updateScene        = function() {
        this.updateScript();
        if (this.isUsingReload()) {
            this.updateDataReload();
        }
        if (this._freeze || this.isReloading()) {
            return;
        }
        _SceneManager_updateScene.apply(this, arguments);
    };

    SceneManager.isUsingReload = function() {
        return paramUseReloadData && !DataManager.isBattleTest() && !DataManager.isEventTest() && Utils.isNwjs();
    };

    SceneManager.updateScript = function() {
        if (this._lastScriptString) {
            this.executeScript(this._lastScriptString);
        }
    };

    SceneManager.updateDataReload = function() {
        if (this.isOnFocusGameWindow() && !this._reloadGenerator) {
            this._reloadGenerator = this.reloadGenerator();
        }
        if (this._reloadGenerator && DataManager.isDatabaseLoaded()) {
            if (!this._reloadGenerator.next().value) {
                this._reloadGenerator = null;
            }
        }
    };

    SceneManager.reloadGenerator = function*() {
        this._preVersionId = DataManager.reloadSystemData();
        yield true;
        if (this._preVersionId !== $dataSystem.versionId) {
            this.reloadMapData();
            DataManager.loadDatabase();
            console.log('Database Reload');
            yield true;
        }
        return false;
    };

    SceneManager.isOnFocusGameWindow = function() {
        if (this.getNwJs().isOnFocus()) {
            this.getNwJs().setOnFocus(false);
            return true;
        }
        return false;
    };

    SceneManager.reloadMapData = function() {
        if (this._scene instanceof Scene_Map && $gamePlayer.canMove()) {
            $gamePlayer.reserveTransfer(
                $gameMap.mapId(), $gamePlayer.x, $gamePlayer.y, $gamePlayer.direction(), 2);
            $gamePlayer.requestMapReload();
            console.log('Map Reload');
        }
    };

    SceneManager.isReloading = function() {
        return !!this._reloadGenerator;
    };

    //=============================================================================
    // BattleManager
    //  強制勝利を追加定義します。
    //=============================================================================
    BattleManager.forceVictory = function() {
        if (SceneManager.isCurrentScene(Scene_Battle) && !this.isBattleAlreadyEnd()) {
            $gameTroop.members().forEach(function(enemy) {
                enemy.addNewState(enemy.deathStateId());
            });
            this.processVictory();
        }
    };

    BattleManager.isBattleAlreadyEnd = function() {
        return this._phase === 'battleEnd';
    };

    //=============================================================================
    // AudioManager
    //  高速化実行時にBGMのピッチを強制的に最大にします。
    //=============================================================================
    const _AudioManager_playBgm = AudioManager.playBgm;
    AudioManager.playBgm        = function(bgm, pos) {
        const originalPitch = bgm.pitch;
        if (SceneManager.isRapid()) {
            arguments[0].pitch = 150;
        }
        if (SceneManager.isSlow()) {
            arguments[0].pitch = 50;
        }
        _AudioManager_playBgm.apply(this, arguments);
        this._currentBgm.pitch = originalPitch;
    };

    //=============================================================================
    // DataManager
    //  セーブデータのエンコード・デコードを実施します。
    //=============================================================================
    DataManager.decodeSaveGame = function(savefileId) {
        if (this.isThisGameFile(savefileId)) {
            const json = StorageManager.load(savefileId);
            StorageManager.saveToLocalFileJson(savefileId, json);
        }
    };

    DataManager.encodeSaveGame = function(savefileId) {
        const json = StorageManager.loadFromLocalFileJson(savefileId);
        if (json) {
            StorageManager.save(savefileId, json);
        }
    };

    const _DataManager_saveGameWithoutRescue = DataManager.saveGameWithoutRescue;
    DataManager.saveGameWithoutRescue        = function(savefileId) {
        const result = _DataManager_saveGameWithoutRescue.apply(this, arguments);
        if (paramJsonSave) this.decodeSaveGame(savefileId);
        return result;
    };

    const _DataManager_loadGameWithoutRescue = DataManager.loadGameWithoutRescue;
    DataManager.loadGameWithoutRescue        = function(savefileId) {
        this.encodeSaveGame(savefileId);
        return _DataManager_loadGameWithoutRescue.apply(this, arguments);
    };

    const _DataManager_loadDatabase = DataManager.loadDatabase;
    DataManager.loadDatabase        = function() {
        if (this.isNeedSuppressBtest()) {
            this._suppressBattleTest = true;
        }
        _DataManager_loadDatabase.apply(this, arguments);
        this._suppressBattleTest = false;
    };

    const _DataManager_isBattleTest = DataManager.isBattleTest;
    DataManager.isBattleTest        = function() {
        return this._suppressBattleTest ? false : _DataManager_isBattleTest.apply(this, arguments);
    };

    DataManager.isNeedSuppressBtest = function() {
        if (!this.isBattleTest()) {
            return false;
        }
        if (Utils.isNwjs()) {
            return this._databaseFiles.some(function(databaseFile) {
                return !StorageManager.isExistTestData(databaseFile.src);
            });
        } else {
            return true;
        }
    };

    DataManager.reloadSystemData = function() {
        for (let i = 0; i < this._databaseFiles.length; i++) {
            const name = this._databaseFiles[i].name;
            if (name === '$dataSystem') {
                var preVersionId = $dataSystem.versionId;
                this.loadDataFile(name, this._databaseFiles[i].src);
                return preVersionId;
            }
        }
        return null;
    };

    //=============================================================================
    // StorageManager
    //  jsonセーブファイルの読み込みと書き込みを行います。
    //=============================================================================
    StorageManager.saveToLocalFileJson = function(savefileId, json) {
        const fs       = require('fs');
        const dirPath  = this.localFileDirectoryPath();
        const filePath = dirPath + 'file%1.json'.format(savefileId);
        if (!fs.existsSync(dirPath)) {
            fs.mkdirSync(dirPath);
        }
        fs.writeFileSync(filePath, json);
    };

    StorageManager.loadFromLocalFileJson = function(savefileId) {
        const fs       = require('fs');
        const filePath = this.localFileDirectoryPath() + 'file%1.json'.format(savefileId);
        if (fs.existsSync(filePath)) {
            return fs.readFileSync(filePath, {encoding: 'utf8'});
        }
        return null;
    };

    StorageManager.isExistTestData = function(fileName) {
        const fs       = require('fs');
        const path     = require('path');
        const filePath = path.join(path.dirname(process.mainModule.filename), 'data/Test_' + fileName);
        return fs.existsSync(filePath);
    };

    //=============================================================================
    // Scene_Base
    //  マップの高速化を提供します。
    //=============================================================================
    const _Scene_Base_fadeSpeed    = Scene_Base.prototype.fadeSpeed;
    Scene_Base.prototype.fadeSpeed = function() {
        return SceneManager.isRapid() ? 1 : _Scene_Base_fadeSpeed.apply(this, arguments);
    };

    const _Scene_Base_startFadeIn    = Scene_Base.prototype.startFadeIn;
    Scene_Base.prototype.startFadeIn = function(duration, white) {
        if (SceneManager.isRapid()) arguments[0] = 1;
        _Scene_Base_startFadeIn.apply(this, arguments);
    };

    const _Scene_Base_startFadeOut    = Scene_Base.prototype.startFadeOut;
    Scene_Base.prototype.startFadeOut = function(duration, white) {
        if (SceneManager.isRapid()) arguments[0] = 1;
        _Scene_Base_startFadeOut.apply(this, arguments);
    };

    //=============================================================================
    // Scene_Boot
    //  タイトル画面をとばしてマップ画面に遷移します。
    //=============================================================================
    const _Scene_Boot_start    = Scene_Boot.prototype.start;
    Scene_Boot.prototype.start = function() {
        _Scene_Boot_start.apply(this, arguments);
        if (paramRapidStart) SceneManager.toggleRapid();
        this.cutSceneTitle();
    };

    Scene_Boot.prototype.cutSceneTitle = function() {
        if (paramCutTitle && !DataManager.isBattleTest() && !DataManager.isEventTest() && !Input.isPressed('control')) {
            if (!this.goToLatestContinue()) {
                this.goToNewGame();
            }
        }
    };

    Scene_Boot.prototype.goToNewGame = function() {
        DataManager.setupNewGame();
        SceneManager.goto(Scene_Map);
    };

    Scene_Boot.prototype.goToLatestContinue = function() {
        if (DataManager.isAnySavefileExists()) {
            if (DataManager.loadGame(DataManager.latestSavefileId())) {
                this.reloadMapIfUpdated();
                SceneManager.goto(Scene_Map);
                $gameSystem.onAfterLoad();
                return true;
            } else {
                return false;
            }
        } else {
            return false;
        }
    };
    Scene_Boot.prototype.reloadMapIfUpdated = Scene_Load.prototype.reloadMapIfUpdated;

    //=============================================================================
    // Scene_Map
    //  高速モードを実装します。
    //=============================================================================
    const _Scene_Map_isFastForward    = Scene_Map.prototype.isFastForward;
    Scene_Map.prototype.isFastForward = function() {
        return _Scene_Map_isFastForward.apply(this, arguments) || SceneManager.isRapid();
    };

    const _Scene_Map_updateMainMultiply    = Scene_Map.prototype.updateMainMultiply;
    Scene_Map.prototype.updateMainMultiply = function() {
        _Scene_Map_updateMainMultiply.apply(this, arguments);
        if (this.isFastForward() && SceneManager.isRapid()) {
            for (let i = 2; i <= paramRapidSpeed; i++) {
                this.updateMain();
            }
        }
    };

    //=============================================================================
    // Window_Base
    //  ウィンドウの高速開閉を提供します。
    //=============================================================================
    const _Window_Base_updateOpen    = Window_Base.prototype.updateOpen;
    Window_Base.prototype.updateOpen = function() {
        if (SceneManager.isRapid() && this._opening) this.openness = 255;
        _Window_Base_updateOpen.apply(this, arguments);
    };

    const _Window_Base_updateClose    = Window_Base.prototype.updateClose;
    Window_Base.prototype.updateClose = function() {
        if (SceneManager.isRapid() && this._closing) this.openness = 0;
        _Window_Base_updateClose.apply(this, arguments);
    };

    //=============================================================================
    // Window_Message
    //  メッセージの高速化を提供します。
    //=============================================================================
    const _Window_Message_isTriggered    = Window_Message.prototype.isTriggered;
    Window_Message.prototype.isTriggered = function() {
        return _Window_Message_isTriggered.apply(this, arguments) || SceneManager.isRapid();
    };

    const _Window_Message_startPause    = Window_Message.prototype.startPause;
    Window_Message.prototype.startPause = function() {
        _Window_Message_startPause.apply(this, arguments);
        if (SceneManager.isRapid()) this.startWait(1);
    };

    var _Game_Interpreter_command355      = Game_Interpreter.prototype.command355;
    Game_Interpreter.prototype.command355 = function() {
        try {
            return _Game_Interpreter_command355.apply(this, arguments);
        } catch (e) {
            console.warn(`Script Error!! Event ID:${this._eventId}`);
            throw e;
        }
    };

    var _Game_Interpreter_command111      = Game_Interpreter.prototype.command111;
    Game_Interpreter.prototype.command111 = function() {
        if (this._params[0] === 12) {
            try {
                return _Game_Interpreter_command111.apply(this, arguments);
            } catch (e) {
                if (this._params[0] === 12) {
                    console.warn(`Script Error!! Event ID:${this._eventId}`);
                }
                throw e;
            }
        } else {
            return _Game_Interpreter_command111.apply(this, arguments);
        }
    };

    var _Game_Character_processMoveCommand      = Game_Character.prototype.processMoveCommand;
    Game_Character.prototype.processMoveCommand = function(command) {
        try {
            _Game_Character_processMoveCommand.apply(this, arguments);
        } catch (e) {
            if (command.code === Game_Character.ROUTE_SCRIPT) {
                console.warn(`Script Error!! ${this.getInformation()}`);
            }
            throw e;
        }
    };

    Game_Character.prototype.getInformation = function() {
        return `X:${this._x} Y:${this._y}`;
    };

    Game_Event.prototype.getInformation = function() {
        return `ID:${this._eventId} Name:${this.event().name}` + Game_Character.prototype.getInformation.call(this);
    };

    Game_Player.prototype.getInformation = function() {
        return 'Player' + Game_Character.prototype.getInformation.call(this);
    };

    //=============================================================================
    // Controller_NwJs
    //  Nw.jsのAPI呼び出しを管理します。
    //=============================================================================
    Controller_NwJs.prototype.constructor = Controller_NwJs;
    Controller_NwJs.prototype.initialize  = function() {
        this._nwGui           = require('nw.gui');
        this._onFocus         = false;
        this._menuBar         = this.getWindow().menu;
        this._menuClick       = null;
        this._onTop           = false;
        this.setOnFocus(false);
        this.initSetting();
    };

    Controller_NwJs.prototype.initSetting = function() {
        this.addEventListener();
        if (paramMenuBarVisible) {
            this.makeMenu(this._menuBar);
            this.setMenuBar(this._menuBar);
        }
        this.initClickMenu();
        if (this.isStartUpDevTool()) {
            this.showDevTools();
        }
        setTimeout(function() {
            this.addOnFocusListener();
            SceneManager.updateDocumentTitle();
        }.bind(this), 1000);
    };

    Controller_NwJs.prototype.isStartUpDevTool = function() {
        return paramStartupDevTool && !Utils.isOptionValid('devToolOff');
    };

    Controller_NwJs.prototype.initClickMenu = function() {
        this._menuClick      = new this._nwGui.Menu();
        this._clickMenuItems = {};
        this.makeMenu(this._menuClick);
    };

    Controller_NwJs.prototype.setMenuBar = function(menu) {
        this.getWindow().menu = menu;
    };

    Controller_NwJs.prototype.makeMenu = function(menuObject) {
        this.getSortedDevCommands().forEach(function(commandInfo) {
            if (commandInfo.use) this.makeMenuItem(commandInfo, menuObject);
        }, this);
    };

    Controller_NwJs.prototype.makeMenuItem = function(commandInfo, menuObject) {
        const ctrl     = paramSimultaneousCtrl ? 'Ctrl+' : '';
        const alt      = paramSimultaneousAlt ? 'Alt+' : '';
        const key      = commandInfo.key && commandInfo.key[0] === 'F' ? commandInfo.key : '';
        const menuItem = new this._nwGui.MenuItem({
            label: commandInfo.name + (key ? `(${ctrl}${alt}${key})` : ''),
            type : commandInfo.type,
        });
        if (menuObject === this._menuClick) {
            this._clickMenuItems[commandInfo.name] = menuItem;
        }
        menuItem.click = function() {
            const result = SceneManager.executeDevCommand(commandInfo.code);
            if (commandInfo.type === 'checkbox') this._clickMenuItems[commandInfo.name].checked = result;
        }.bind(this);
        menuObject.append(menuItem);
    };

    Controller_NwJs.prototype.getSortedDevCommands = function() {
        return SceneManager.devCommands.sort(function(a, b) {
            if (a.key && b.key) {
                return Input.functionReverseMapper[a.key] - Input.functionReverseMapper[b.key];
            } else if (a.key || b.key) {
                return a.key ? -1 : 1;
            } else {
                return a.code - b.code;
            }
        });
    };

    Controller_NwJs.prototype.setOnFocus = function(value) {
        this._onFocus = value;
    };

    Controller_NwJs.prototype.isOnFocus = function() {
        return this._onFocus;
    };

    Controller_NwJs.prototype.addEventListener = function() {
        document.addEventListener('mousedown', function(event) {
            if (event.button === paramClickMenu) {
                this._menuClick.popup(event.pageX, event.pageY);
            }
        }.bind(this));
    };

    Controller_NwJs.prototype.addOnFocusListener = function() {
        const currentWin = this.getWindow();
        currentWin.removeAllListeners();
        currentWin.on('focus', this.onFocus.bind(this));
        currentWin.on('blur', this.onBlur.bind(this));
    };

    Controller_NwJs.prototype.onFocus = function() {
        if (this._disableScreenShift) {
            return;
        }
        this._onFocus = true;
        setTimeout(function() {
            if (this._moveOnBlur) {
                this.getWindow().moveBy(-paramShiftRightOnBlur, 0);
                this._moveOnBlur = false;
            }
        }.bind(this), 100);
    };

    Controller_NwJs.prototype.onBlur = function() {
        if (this._disableScreenShift) {
            return;
        }
        setTimeout(function() {
            if (!this._moveOnBlur && this._onTop) {
                this.getWindow().moveBy(paramShiftRightOnBlur, 0);
                this._moveOnBlur = true;
            }
        }.bind(this), 100);
    };

    Controller_NwJs.prototype.getWindow = function() {
        return this._nwGui.Window.get();
    };

    Controller_NwJs.prototype.getClipboard = function() {
        return this._nwGui.Clipboard.get();
    };

    Controller_NwJs.prototype.toggleAlwaysOnTop = function() {
        this._onTop = !this._onTop;
        this.getWindow().setAlwaysOnTop(this._onTop);
        SceneManager.updateDocumentTitle();
        return this._onTop;
    };

    Controller_NwJs.prototype.isOnTop = function() {
        return this._onTop;
    };

    Controller_NwJs.prototype.prompt = function(value, defaultValue, aliasPrompt) {
        const win    = this.getWindow();
        const result = aliasPrompt.call(window, value, defaultValue);
        win.focus();
        Input.clear();
        return result;
    };

    Controller_NwJs.prototype.showDevTools = function() {
        this._disableScreenShift = true;
        this.getWindow().showDevTools();
        setTimeout(function() {
            this.focus();
        }.bind(this), 1000);
    };

    Controller_NwJs.prototype.focus = function() {
        this._disableScreenShift = true;
        this.getWindow().focus();
        setTimeout(function() {
            this._disableScreenShift = false;
        }.bind(this), 500);
    };

    Controller_NwJs.prototype.readClipboard = function(mode) {
        if (!mode) mode = 'text';
        return this.getClipboard().get(mode);
    };

    Controller_NwJs.prototype.writeClipboard = function(copyValue, mode) {
        if (!mode) mode = 'text';
        if (mode === 'text') copyValue = copyValue.toString();
        this.getClipboard().set(copyValue, mode);
    };
})();