code:
/*
############################################
	作者: COBRA
	改造や配布好き勝手にしても大丈夫だよ
	寧ろ積極的に配布して皆のゲーム開発を快適にしてあげて
	http://cobrara.blogspot.jp/
############################################
*/

// Version 1.0.1
// 2017/12/3 1.0.1 フォントカラーを指定した場合後に続くテキストカラーも変更されてしまう問題を修正しました
// 2017/12/2 1.0.0

/*:
* @plugindesc エロステータス作れちゃうプラグイン(NPC用)
* @author COBRA
* @help Version 1.0.1
* ※width 0pxの画像を表示しようとすると永遠にロード中と勘違いして
* いつまでたってもエロステータスは表示されません

*
* @param コモンイベント
* @desc ベースになるコモンイベントを指定してね
* Default:
* @default
*
* @param
*
* @param ピクチャの原点
* @desc 入力を省いた時の値になります
* Default: 左上
* @default 左上
*
* @param
*
* @param テキストのサイズ
* @desc 入力を省いた時の値になります
* Default: 26
* @default 26
*
* @param テキストの原点
* @desc 入力を省いた時の値になります
* Default: 左上
* @default 左上
*
* @param テキストの揃え
* @desc 入力を省いた時の値になります
* Default: 中
* @default 中
*
* @param
*
* @param ページ移動のSEの名前
* @desc ←→でエロステータスのページを切り替えた時に鳴らすSEの名前
* Default: Cursor2
* @default Cursor2
*
* @param ページ移動のSEの音量
* @desc ←→でエロステータスのページを切り替えた時に鳴らすSEの音量
* Default: 90
* @default 90
*
* @param ページ移動のSEのピッチ
* @desc ←→でエロステータスのページを切り替えた時に鳴らすSEのピッチ
* Default: 100
* @default 100
*
* @param ページ移動のSEの位相
* @desc ←→でエロステータスのページを切り替えた時に鳴らすSEの位相
* Default: 0
* @default 0
*/

//使いやすくする為日本語で

CBR_eroStaNPC = {};//[0]=[] [1]=[]で1ページと2ページのデータを入れる
CBR_eroStaNPC.character = {};
CBR_eroStaNPC.param = {};//初期値を入れる

//var hoge ="test=123=2 = hog";
//hoge.split(/^([^=\s]+)\s*=\s?/);
/*
$dataCommonEventsに存在してる
*/

//タイトルでコモンイベント実行
var _CBR_eroStaNPC_Scene_Title_update = Scene_Title.prototype.update;
Scene_Title.prototype.update = function () {
	_CBR_eroStaNPC_Scene_Title_update.call(this);
	if (!CBR_eroStaNPC.data && this.isActive()) {
		CBR_eroStaNPC.data = [];
		var param = PluginManager.parameters('CBR_eroStatus_NPC');
		$gameTemp.reserveCommonEvent(Number(param['コモンイベント']));
		CBR_eroStaNPC.param['pic原点'] = param['ピクチャの原点'] || '左上';
		if (Number(param['テキストのサイズ']) === 0) {
			CBR_eroStaNPC.param['txtサイズ'] = 0;
		} else {
			CBR_eroStaNPC.param['txtサイズ'] = Number(param['テキストのサイズ']) || 26;
		}
		CBR_eroStaNPC.param['txt原点'] = param['テキストの原点'] || '左上';
		CBR_eroStaNPC.param['txt揃え'] = param['テキストの揃え'] || '中';
		CBR_eroStaNPC.param['se名'] = param['ページ移動のSEの名前'] || 'Cursor2';
		if (Number(param['ページ移動のSEの音量']) === 0) {
			CBR_eroStaNPC.param['se音量'] = 0;
		} else {
			CBR_eroStaNPC.param['se音量'] = Number(param['ページ移動のSEの音量']) || 100;
		}
		if (Number(param['ページ移動のSEのピッチ']) === 0) {
			CBR_eroStaNPC.param['seピッチ'] = 0;
		} else {
			CBR_eroStaNPC.param['seピッチ'] = Number(param['ページ移動のSEのピッチ']) || 100;
		}
		CBR_eroStaNPC.param['se位相'] = Number(param['ページ移動のSEの位相']) || 0;

		$gameMap.updateInterpreter();
	}
};

//これから入れるページを指定
CBR_eroStaNPC.setPage = function (val) {
	this._setPage = val;
	this.data[val] = this.data[val] || { 'p': [], 't': [] };//速度重視の為addではなくこっちでやる
};

//基本データ追加
CBR_eroStaNPC.addPic = function (ary) {
	var tempD = {};
	var key = this.data[this._setPage].p.length;//そのページの何番目になるのか

	for (var i = 0, len = ary.length; i < len; i++) {
		var temp = ary[i].split(/^([^=\s]+)\s*=\s?/);
		switch (temp[1]) {
			case "名前":
			case "x":
			case "y":
			case "拡大":
			case "透明度":
			case "原点":
				//差分処理
				var m = temp[2].match(/^[<|＜](.+)[>|＞]$/);
				if (m) {
					this.character[m[1]] = {
						'page': this._setPage,
						'type': 'p',
						'key': key,
						'name': temp[1],
						'val': temp[2]
					}
				} else {
					temp[2].replace(/^@(<|＜)/, '$1');
					if (temp[1] != '名前' && temp[1] != '原点') {
						temp[2] = Number(temp[2]);
					}
					tempD[temp[1]] = temp[2];
				}

				break;
			default:
				alert('エラー/addPicに予期しない文字が入ってる→' + ary[i][0]);
				break;
		}
	}
	//デフォの値はここで設定
	if (!tempD['原点']) { tempD['原点'] = this.param['pic原点']; }
	if (!tempD['透明度']) { tempD['透明度'] = 1; }
	if (!tempD['拡大']) { tempD['拡大'] = 1; }

	this.data[this._setPage].p[key] = tempD;
};

CBR_eroStaNPC.addTxt = function (ary) {
	var tempD = {};
	var key = this.data[this._setPage].t.length;

	for (var i = 0, len = ary.length; i < len; i++) {
		var temp = ary[i].split(/^([^=\s]+)\s*=\s?/);
		switch (temp[1]) {
			case "テキスト":
			case "x":
			case "y":
			case "原点":
			case "揃え":
			case "サイズ":
				//差分処理
				var m = temp[2].match(/^[<|＜](.+)[>|＞]$/);
				if (m) {
					this.character[m[1]] = {
						'page': this._setPage,
						'type': 't',
						'key': key,
						'name': temp[1],
						'val': temp[2]
					}
				} else {
					temp[2].replace(/^@(<|＜)/, '$1');
					if (temp[1] != 'テキスト' && temp[1] != '原点' && temp[1] != '揃え') {
						temp[2] = Number(temp[2]);
					}
					tempD[temp[1]] = temp[2];
				}
				break;
			default:
				alert('エラー/addTxtに予期しない文字が入ってる→' + ary[i][0]);
				break;
		}
	}
	if (!tempD['原点']) { tempD['原点'] = this.param['txt原点']; }
	if (!tempD['揃え']) { tempD['揃え'] = this.param['txt揃え']; }
	if (!tempD['サイズ']) { tempD['サイズ'] = this.param['txtサイズ']; }
	this.data[this._setPage].t[key] = tempD;
};

CBR_eroStaNPC.changeChara = function (ary) {
	for (var i = 0, len = ary.length; i < len; i++) {
		var temp = ary[i].split(/^([^=\s]+)\s*=\s?/);
		data = this.character[temp[1]];
		if (temp[1] == 'x' || temp[1] == 'y' || temp[1] == '拡大' || temp[1] == '透明度') { }
		this.data[data.page][data.type][data.key][data.name] = temp[2];//オブジェクトの書き換え
	}
};

//########### Scene ###########
function Scene_EroStaNPC() {
	this.initialize.apply(this, arguments);
}
Scene_EroStaNPC.prototype = Object.create(Scene_MenuBase.prototype);
Scene_EroStaNPC.prototype.constructor = Scene_EroStaNPC;

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

	this._eroStaNPCWindow = new Window_EroStaNPC();
	this._eroStaNPCWindow.setHandler('cancel', this.popScene.bind(this));

	this._eroStaNPCWindow._margin = 0;//背景ピッチリする為
	this._eroStaNPCWindow.margin = 0;//本当はこっちだけどね
	this._eroStaNPCWindow._windowFrameSprite.visible = false;//枠線を消す

	this.addWindow(this._eroStaNPCWindow);
};

Scene_EroStaNPC.prototype.update = function () {
	Scene_Base.prototype.update.call(this);
};

//########### window ###########
function Window_EroStaNPC() {
	this.initialize.apply(this, arguments);
}

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

Window_EroStaNPC.prototype.initialize = function () {//windowを作る
	var width = Graphics.boxWidth;
	var height = Graphics.boxHeight;
	Window_Selectable.prototype.initialize.call(this, 0, 0, width, height);
	this.CBR_setPage(1);
	this.CBR_setComplete(false);
};

Window_EroStaNPC.prototype.CBR_setPage = function (val) {//現在のページ
	this._CBR_page = val;
};
Window_EroStaNPC.prototype.CBR_page = function () {
	return this._CBR_page;
};
Window_EroStaNPC.prototype.CBR_setComplete = function (val) {//描写終わったかどうか
	this._CBR_complete = val;
};
Window_EroStaNPC.prototype.CBR_complete = function () {
	return this._CBR_complete;
};

Window_EroStaNPC.prototype.update = function () {//毎回image描写してもいいけどそれだと負荷が多くなるのでこの方法で
	Window_Selectable.prototype.update.call(this);

	var allPage = CBR_eroStaNPC.data.length - 1;
	//2ページある時は2

	if (2 < CBR_eroStaNPC.data.length && this.isOpenAndActive()) {//2ページ以上存在して操作があった時
		if (Input.isRepeated('right') || Input.isRepeated('left')) {
			AudioManager.playSe({ "name": CBR_eroStaNPC.param['se名'], "volume": CBR_eroStaNPC.param['se音量'], "pitch": CBR_eroStaNPC.param['seピッチ'], "pan": CBR_eroStaNPC.param['se位相'] });
			if (Input.isRepeated('right')) {//右の時
				if (this.CBR_page() < allPage) {
					this.CBR_setPage(this.CBR_page() + 1);
				} else {
					this.CBR_setPage(1);
				}
			} else {//左の時
				if (this.CBR_page() == 1) {
					this.CBR_setPage(allPage);
				} else {
					this.CBR_setPage(this.CBR_page() - 1);
				}
			}
			this.CBR_setComplete(false);//初期化
		}
	}

	if (!this.CBR_complete()) {//まだ画像の描写してないのなら
		var flag = false;
		var ary = CBR_eroStaNPC.data[this.CBR_page()].p;
		var p_data = [];

		//ピクチャの数だけ
		for (var i = 0, len = ary.length; i < len; i++) {
			var name = ary[i]['名前'];
			if (!name) {
				continue;
			}
			name = name.replace(/\\(\\)|\\([VNP])\[(\d+)\]|\\(<)(.+)\\>/g, function (a, b, c, d, e, f) {//汚いけどこれは毎回やらないとね
				if (b) {//\\
					return '\\';
				} else if (c) {//[VNP]
					d = Number(d);
					switch (c) {
						case 'V':
							return $gameVariables.value(d);
							break;
						case 'N':
							return $gameActors._data[d]._name;
							break;
						case 'P':
							return $dataActors[$gameParty._actors[d - 1]].name;
							break;
					}
				} else {//script
					return eval(f);
				}
			});

			if (name) {
				var temp = ImageManager.loadPicture(name);//初回読み込み
				if (temp) {
					if (!temp.width) {//暗号化するとwidthでしか判別できない　探せばあるかもしれないけど
						//if(temp._isLoading || temp._loadingState == 'requesting'){//前者は古いver用 ロード中ならアウト
						flag = true;
						break;
					}
				} else {//その名前の画像が無かったら
					flag = true;
					this.CBR_setComplete(true);
					break;
				}
				p_data[i] = {
					'w': temp.width,
					'h': temp.height,
				}
			}
		}

		if (!flag) {//全ロードが終わってたら
			this.contents.clear();

			//ピクチャの表示
			var ary = CBR_eroStaNPC.data[this.CBR_page()].p;
			for (var i = 0, len = ary.length; i < len; i++) {
				var name = ary[i]['名前'];
				if (!name) {
					continue;
				}
				//変数とか文字化
				name = name.replace(/\\(\\)|\\([VNP])\[(\d+)\]|\\(<)(.+)\\>/g, function (a, b, c, d, e, f) {
					if (b) {//\\
						return '\\';
					} else if (c) {//[VNP]
						d = Number(d);
						switch (c) {
							case 'V':
								return $gameVariables.value(d);
								break;
							case 'N':
								return $gameActors._data[d]._name;
								break;
							case 'P':
								return $dataActors[$gameParty._actors[d - 1]].name;
								break;
						}
					} else {//script
						return eval(f);
					}
				});

				if (name) {
					this.changePaintOpacity(ary[i]['透明度']);

					//原点処理
					var x = ary[i].x;
					var y = ary[i].y;
					var lr = ary[i]['原点'].charAt(0);
					var ud = ary[i]['原点'].charAt(1);

					if (lr == '中') {
						x -= p_data[i].w * ary[i]['拡大'] / 2;
					} else if (lr == '右') {
						x -= p_data[i].w * ary[i]['拡大'];
					}
					if (ud == '中') {
						y -= p_data[i].h * ary[i]['拡大'] / 2;
					} else if (ud == '下') {
						y -= p_data[i].h * ary[i]['拡大'];
					}

					this.drawPicture('pictures', name, 0, 0, x, y, 0, 0, ary[i]['拡大'], 0);
				}
			}

			//テキストの表示
			this.resetTextColor();
			var ary = CBR_eroStaNPC.data[this.CBR_page()].t;
			for (var i = 0, len = ary.length; i < len; i++) {
				var temp = ary[i]['テキスト'];
				if (!temp) {
					continue;
				}

				var opAry = temp.match(/(\\\{|\\\}|\\[CI]\[\d+\])+/g);

				//先頭にある場合は"","tesa"になる
				var strAry = temp.split(/(?:\\\{|\\\}|\\[CI]\[\d+\])+/);

				var str = '';

				var allW = 0;
				var maxSize = null;
				var dataFAry = [];
				var dataWAry = [];
				var drawI = [];
				var drawC = [];
				//分割した配列の数
				for (var k = 0, len2 = strAry.length; k < len2; k++) {

					//前方にある\{のフォントサイズを入れる
					dataFAry[k] = k ? dataFAry[k - 1] : 0;
					drawI[k] = [];

					//変数とか文字化
					strAry[k] = strAry[k].replace(/\\(\\)|\\([VNP])\[(\d+)\]|\\(G)|\\(<)(.+)\\>/g, function (a, b, c, d, e, f, g) {
						if (b) {//\\
							return '\\';
						} else if (c) {//[VNP]
							d = Number(d);
							switch (c) {
								case 'V':
									return $gameVariables.value(d);
									break;
								case 'N':
									return $gameActors._data[d]._name;
									break;
								case 'P':
									return $dataActors[$gameParty._actors[d - 1]].name;
									break;
							}
						} else if (e) {//G
							return $dataSystem.currencyUnit;
						} else {//script
							return eval(g);
						}
					});

					//自身の前に区切りマッチがあったら
					if (0 < k) {
						var temp = opAry[k - 1].split('\\');//\\{\\}を分割する
						for (var m = 1, len3 = temp.length; m < len3; m++) {

							switch (temp[m].charAt(0)) {
								case '{':
									dataFAry[k] += 12;
									break;
								case '}':
									dataFAry[k] -= 12;
									break;
								case 'C':
									drawC[k] = Number(temp[m].match(/\[(\d+)\]/)[1]);//Cは複数あっても最後のが適応されれば良いわけで
									break;
								case 'I':
									drawI[k][drawI[k].length] = Number(temp[m].match(/\[(\d+)\]/)[1]);
									break;
							}
						}
					}
					this.contents.fontSize = 18;
					this.contents.context.font = this.contents._makeFontNameText();
					dataWAry[k] = this.contents.context.measureText(strAry[k]).width;//何の為に+4するのか忘れた
					allW += dataWAry[k];

					if (strAry[k]) {//先頭に\{や変数がある時の問題　アイコン乃場合もここを通さないと
						if (maxSize === null) {//まだ記録されてなかったら入れよう
							maxSize = dataFAry[k];
						} else {
							maxSize = (maxSize < dataFAry[k]) ? dataFAry[k] : maxSize;
						}
					}
				}

				maxSize += ary[i]['サイズ'];
				var x = ary[i].x;
				var y = ary[i].y;
				var lr = ary[i]['原点'].charAt(0);
				var ud = ary[i]['原点'].charAt(1);

				/*
				デフォは原点左中、やりたいのはデフォ左上
				アイコンは左上

				上上の場合→y + (max / 2) - (max - size)/2
				上中の場合→y + (max / 2)
				上下の場合→y + (max / 2) + (max - size)/2

				中上の場合→y - (max - size)/2
				中中の場合→y
				中下の場合→y + (max - size)/2

				下上の場合→y - (max / 2) - (max - size)/2
				下中の場合→y - (max / 2)
				下下の場合→y - (max / 2) + (max - size)/2
				*/

				//原点の左右
				if (lr == '中') {
					x -= allW / 2;
				} else if (lr == '右') {
					x -= allW;
				}
				//原点の上下
				if (ud == '上') {
					y += maxSize / 2;
				} else if (ud == '下') {
					y -= maxSize / 2;
				}

				//各文字のサイズの描写
				for (var k = 0, len2 = strAry.length; k < len2; k++) {
					this.contents.fontSize = 18;
					this.contents.context.font = this.contents._makeFontNameText();
					//bottom→下揃え原点の上　top→上揃え原点の下　center→原点
					var trueY = y;
					var iconY = y;
					if (ary[i]['揃え'] == '上') {
						trueY -= (maxSize - ary[i]['サイズ'] - dataFAry[k]) / 2;
						iconY = y - maxSize / 2;
					} else if (ary[i]['揃え'] == '下') {
						trueY += (maxSize - ary[i]['サイズ'] - dataFAry[k]) / 2;
						iconY = y + (maxSize / 2 - Window_Base._iconWidth);
					} else {
						iconY = y - (Window_Base._iconWidth) / 2;
					}
					if (drawI[k].length) {
						for (var m = 0, len3 = drawI[k].length; m < len3; m++) {
							this.drawIcon(drawI[k][m], x, iconY);
							x += Window_Base._iconWidth;
						}
					}
					if (drawC[k]) {
						this.changeTextColor(this.textColor(drawC[k]));
					}
					this.contents.drawText(strAry[k], x, trueY, dataWAry[k], 0, 'left');
					x += dataWAry[k];
				}
				this.contents.fontSize = this.standardFontSize();
				this.resetTextColor();
				this.changePaintOpacity(true);
			}

			this.activate();
			this.CBR_setComplete(true);
		}
	}
};

Window_EroStaNPC.prototype.drawPicture = function (dir, filename, sx, sy, x, y, w, h, zoom, hue) {
	var bitmap = ImageManager.loadBitmap('img/' + dir + '/', filename, hue, true);
	this.contents.blt(bitmap, sx, sy, bitmap.width, bitmap.height, x, y, bitmap.width * zoom, bitmap.height * zoom);
};
Window_EroStaNPC.prototype.standardPadding = function () {
	return 0;
};

var _CBR_Game_Interpreter_pluginCommand = Game_Interpreter.prototype.pluginCommand;
Game_Interpreter.prototype.pluginCommand = function (command, args) {
	_CBR_Game_Interpreter_pluginCommand.call(this, command, args);
	if (command.toUpperCase() === 'CBR_EROSTATUS_NPC') {
		SceneManager.push(Scene_EroStaNPC);
	}
};

repo_name: dazed/translations

license: unknown


code:
/*
############################################
	作者: COBRA
	改造や配布好き勝手にしても大丈夫だよ
	寧ろ積極的に配布して皆のゲーム開発を快適にしてあげて
	http://cobrara.blogspot.jp/
############################################
*/

// Version 1.1.2
// 2018/4/26 ロードした際ステータスの変更もロードされるよう修正
// 2017/12/13 最新のバージョン(1.5)でデプロイメントすると1回目だけ画像が表示されない問題を修正
// 2017/8/27 1.1.0 ページの表示・非表示機能を追加しました
// 2017/7/30 1.0.4 最新のコアスクリプト(ver1.2c)にも対応しました
// 2017/5/4 1.0.3 エロステータス画面を開いてる最中NPCが動いてしまう問題を修正しました
// 2017/1/31 1.0.2 changeにおいて最後の項目に｢@@,@_,@=｣が含まれている場合エスケープされない問題を修正しました
// 2017/1/30 1.0.1 ピクチャ名に変数が反映されないバグを修正しました
// 2017/1/24 1.0.0

/*:
* @plugindesc エロステータス作れちゃうプラグイン(本体)
* @author COBRA
* @help Version 1.1.2
* 自由にいじれちゃうエロステータス画面
*
* 画像はimg/picturesにpngで保存してください
*
* 0pxの画像を表示しようとするとバグります
*
*
* 詳しくはこちらで
* http://cobrara.blogspot.jp/2017/01/blog-post_24.html
*
* 横幅：816　縦幅：624

* @param eroStaName
* @desc メニューに表示される名前だよ
* Default: エロステータス
* @default エロステータス
*
*
* @param
*
*
* @param commonEvent
* @desc エロステ画面を開く直前に実行されるコモンイベント、数値
* Default:
* @default
*/

var CBR_eroStatus = [];
var CBR_eroStatusState = {};

//表示するページ変える
Game_System.prototype.CBR_eroSta_page = function (list) {
	this.availablePage = list;
	CBR_eroStatusState.num = this.availablePage;
};

//起動・ロード・ニューゲーム時
var _CBR_Game_System_initialize = Game_System.prototype.initialize;
Game_System.prototype.initialize = function () {
	_CBR_Game_System_initialize.call(this);

	//初期値
	CBR_eroStatus = [];
	CBR_eroStatusState.num = [];
	CBR_eroStatusState.numOrigin = [];
	CBR_eroStatusState.now = null;
	CBR_eroStatusState.name = null;
	CBR_eroStatusState.event = null;

	this.availablePage = [];

	//ページ数取得
	//こっちがあったら

	for (var i = 0, len = $plugins.length; i < len; i++) {
		var temp = $plugins[i].name.match(/^CBR_eroStatus_(\d+)/);//プラグインが存在して
		if (temp) {
			CBR_eroStatusState.numOrigin[CBR_eroStatusState.numOrigin.length] = Number(temp[1]);
			CBR_eroStatusState.num[CBR_eroStatusState.num.length] = Number(temp[1]);
		}
	}

	//変更箇所の保存
	CBR_eroStatusState.numOrigin.sort(function (a, b) { return a - b; });//_nの小さい順に
	this._CBR_eroSta_change_list = [];

	//numOriginに[1,2,4,8]ってページが入ってる

	//numには表示すべき[2,4]だけが入ってる

	//エロステには[obj,obj,obj,obj]とOriginに対応した順番で入ってる

	this._CBR_eroSta_pageList = [];

	var param = PluginManager.parameters('CBR_eroStatus_main');
	CBR_eroStatusState.name = '' + (param['eroStaName'] || 'エロステータス');
	CBR_eroStatusState.event = Number(param['commonEvent']) || null;

	for (var i = 0, len = CBR_eroStatusState.numOrigin.length; i < len; i++) {//ページの数だけ
		var n = CBR_eroStatusState.numOrigin[i];
		var param = PluginManager.parameters('CBR_eroStatus_' + n);
		//nは_n.js　1,2,3
		//iはページの順番　 0,1,2
		//保存する場合は0から99
		CBR_eroStatus[i] = { 'p': [], 't': [] };

		this._CBR_eroSta_change_list[i] = {
			'p': [],
			't': []
		};

		for (var k = 1; k < 100; k++) {
			this.CBR_eroSta_add(
				'p',
				i,
				k - 1,
				param['picName_' + k],
				param['picX_' + k],
				param['picY_' + k],
				param['picOrigin_' + k],
				param['picShow_' + k],
				param['picOpacity_' + k],
				param['picZoom_' + k]
			);
			this.CBR_eroSta_add(
				't',
				i,
				k - 1,
				param['txtSubject_' + k],
				param['txtX_' + k],
				param['txtY_' + k],
				param['txtOrigin_' + k],
				param['txtShow_' + k],
				param['txtAlign_' + k],
				param['txtSize_' + k]
			);
		}
	}

	this._CBR_eroSta_change_list = [];
	for (var i = 0, len = CBR_eroStatusState.numOrigin.length; i < len; i++) {//ページ分だけチェンジリスト作る
		this._CBR_eroSta_change_list[i] = {
			'p': [],
			't': []
		};
	}

};

//セーブデータ読み込み時に実行
var _CBR_Game_System_onAfterLoad = Game_System.prototype.onAfterLoad;
Game_System.prototype.onAfterLoad = function () {
	_CBR_Game_System_onAfterLoad.call(this);

	if (this.availablePage.length) {
		CBR_eroStatusState.num = this.availablePage;
	};

	for (var i = 0, len = CBR_eroStatusState.numOrigin.length; i < len; i++) {//ページ数分繰り返す
		for (var j = 0; j < 2; j++) {
			var ty = (!j) ? 'p' : 't';
			var list = this._CBR_eroSta_change_list[i][ty];//変更したいナンバーリスト
			for (var k = 0, len2 = list.length; k < len2; k++) {
				var koumokuList = list[k].list;
				for (var m = 0, len3 = koumokuList.length; m < len3; m++) {//チェンジする項目数
					if (!CBR_eroStatus[i][ty][list[k].page]) {//その項目のデフォが存在しなかったら作成
						this.CBR_eroSta_add(ty, i);
					}
					CBR_eroStatus[i][ty][list[k].num][koumokuList[m].name] = koumokuList[m].val;
				}

			}
		}
	}
};

Game_System.prototype.CBR_eroSta_getPageIndex = function (num) {//aはaligin or opacity bはzoom
	var ary = CBR_eroStatusState.numOrigin;
	for (var i = 0, len = ary.length; i < len; i++) {
		if (ary[i] == num) {
			return i;
		}
	}
};

Game_System.prototype.CBR_eroSta_add = function (type, page, num, data, x, y, origin, show, a, b) {//aはaligin or opacity bはzoom
	if (type == 'p') {
		CBR_eroStatus[page].p[num] = {
			'name': data,
			'x': this.CBR_eroSta_changeVal('x', x),
			'y': this.CBR_eroSta_changeVal('y', y),
			'origin': origin || 'left',
			'show': (show == 'on'),
			'opacity': this.CBR_eroSta_changeVal('opacity', a),
			'zoom': this.CBR_eroSta_changeVal('zoom', b)
		};
	} else if (type == 't') {
		CBR_eroStatus[page].t[num] = {
			'subject': data,
			'x': this.CBR_eroSta_changeVal('x', x),
			'y': this.CBR_eroSta_changeVal('y', y),
			'origin': origin || 'left',
			'show': (show == 'on'),
			'align': a || 'top',
			'size': this.CBR_eroSta_changeVal('size', b)

		};
	}
};

Game_System.prototype.CBR_eroSta_changeVal = function (name, val) {//チェンジする時 add時　ロード時のチェンジで反映させよう
	switch (name) {
		case 'x':
		case 'y':
			return Number(val) || 0;
			break;
		case 'opacity':
		case 'zoom':
			if (val) {
				return Number(val) / 100;
			} else {
				return 1;
			}
			break;
		case 'show':
			return (val == 'on');
			break;
		case 'size':
			return Number(val) || 28;
			break;
		case 'name':
		case 'subject':
			return val || '';
			break;
		default:
			return val;
			break;
	}
};

Game_System.prototype.CBR_eroSta_change = function (ary) {
	var txt_ary = {
		'fontsize': 'fontSize',
		'vardigit': 'varDigit'
	};

	var checkList = {
		'p': ['name', 'origin', 'x', 'y', 'show', 'opacity', 'zoom'],
		't': ['subject', 'origin', 'x', 'y', 'show', 'align', 'size']
	}

	for (var i = 0, len = ary.length; i < len; i++) {//変更したいpage_type_nの分だけ
		var temp = ary[i].split(/@@|@_|@=|_|=/);
		var temp2 = ary[i].match(/@@|@_|@=|_|=/g);

		var list = [];//aryを分割したものを入れる
		var temp3 = '';
		for (var k = 0, len2 = temp.length; k < len2; k++) {
			if (temp2[k]) {
				if (temp2[k].charAt(0) == '@') {
					temp3 += temp[k] + temp2[k].charAt(1);
				} else {
					list[list.length] = temp3 + temp[k];
					temp3 = '';
				}
			} else {
				list[list.length] = temp3 + temp[k];
			}
		}

		list[0] = Number(list[0]);
		var page = null;
		for (var k = 0, len2 = CBR_eroStatusState.numOrigin.length; k < len2; k++) {//ページ数だけ回す
			if (CBR_eroStatusState.numOrigin[k] == list[0]) {//nと一致したら
				page = k;
			}
		}
		var type = list[1];
		var n = Number(list[2]) - 1;

		//しつこい気もするけどエロステータス開く時の軽さを最優先で
		var obj = this._CBR_eroSta_change_list[page][type];

		var objNum = false;
		for (var k = 0, len2 = obj.length; k < len2; k++) {//このページのchange数
			if (n == obj[k].num) {//nとチェンジしたい番号が一緒だったら
				objNum = k;
				break;
			}
		}
		if (objNum === false) {
			objNum = len2;
			obj[objNum] = {
				'num': n,
				'list': []
			};
		}

		//変更したいパラメータ数だけ回す
		var chaList = obj[objNum].list;
		for (var k = 3, len2 = list.length; k + 1 < len2; k += 2) {
			var listNum = false;
			for (var m = 0, len3 = chaList.length; m < len3; m++) {//既に存在するチェンジ数
				if (list[k] == chaList[m].name) {//一致する箇所があるかどうか
					listNum = m;
					break;
				}
			}
			if (listNum === false) {//無かったら
				listNum = len3;
				for (var m = 0, len3 = checkList[type].length; m < len3; m++) {//ちゃんと項目通りかチェック
					if (list[k] == checkList[type][m]) {
						break;
					} else if ((m + 1) == len3) {//もし無かったら
						alert('ERROR:CBR_eroSta_change引数');
					}
				}
			}
			list[k + 1] = this.CBR_eroSta_changeVal(list[k], list[k + 1]);
			chaList[listNum] = {
				'name': list[k],
				'val': list[k + 1]
			};
			CBR_eroStatus[page][type][n][list[k]] = list[k + 1];
		}
	}
};

//########### Scene ###########
function Scene_EroStatus() {
	this.initialize.apply(this, arguments);
}
Scene_EroStatus.prototype = Object.create(Scene_MenuBase.prototype);
Scene_EroStatus.prototype.constructor = Scene_EroStatus;

Scene_EroStatus.prototype.initialize = function () {
	Scene_MenuBase.prototype.initialize.call(this);
};
Scene_EroStatus.prototype.create = function () {
	Scene_MenuBase.prototype.create.call(this);
	if (CBR_eroStatusState.event) {
		$gameTemp.reserveCommonEvent(CBR_eroStatusState.event);

	}
	this._eroStatusWindow = new Window_EroStatus();
	this._eroStatusWindow.setHandler('cancel', this.popScene.bind(this));

	this._eroStatusWindow._margin = 0;//背景ピッチリする為
	this._eroStatusWindow.margin = 0;//本当はこっちだけどね
	this._eroStatusWindow._windowFrameSprite.visible = false;//枠線を消す

	this.addWindow(this._eroStatusWindow);
};

Scene_EroStatus.prototype.update = function () {

	$gameMap.refreshIfNeeded();
	if (this.isActive()) {
		$gameMap.updateInterpreter();
	}
	$gameMap.updateVehicles();

	Scene_Base.prototype.update.call(this);
};

//########### window ###########
function Window_EroStatus() {
	this.initialize.apply(this, arguments);
}

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

Window_EroStatus.prototype.initialize = function () {//windowを作る
	var width = Graphics.boxWidth;
	var height = Graphics.boxHeight;
	Window_Selectable.prototype.initialize.call(this, 0, 0, width, height);
	CBR_eroStatusState.now = 0;
	this._CBR_complete = false;
};

Window_EroStatus.prototype.CBR_complete = function () {//描写終わったかどうか
	return this._CBR_complete;
};

Window_EroStatus.prototype.update = function () {//毎回image描写してもいいけどそれだと負荷が多くなるのでこの方法で
	Window_Selectable.prototype.update.call(this);

	if (1 < CBR_eroStatusState.num.length && this.isOpenAndActive()) {//操作があった時
		if (Input.isRepeated('right') || Input.isRepeated('left')) {
			SoundManager.playCursor(2);//音楽鳴らす
			CBR_eroStatusState.now = ((CBR_eroStatusState.now + 1) < CBR_eroStatusState.num.length) ? CBR_eroStatusState.now + 1 : 0;
			this._CBR_complete = false;//初期化
			//this._statusWindow.refresh();//切り替えしたんでリフレッシュ
		}
	}

	var page = $gameSystem.CBR_eroSta_getPageIndex(CBR_eroStatusState.num[CBR_eroStatusState.now]);

	if (!this.CBR_complete()) {//まだ画像の描写してないのなら
		var flag = false;
		var ary = CBR_eroStatus[page].p;
		var p_data = [];
		//ピクチャの数だけ
		for (var i = 0, len = ary.length; i < len; i++) {
			var name = ary[i].name;
			if (!name || !ary[i].show) {
				continue;
			}
			name = name.replace(/\\(\\)|\\([VNP])\[(\d+)\]|\\(<)(.+)\\>/g, function (a, b, c, d, e, f) {//汚いけどこれは毎回やらないとね
				if (b) {//\\
					return '\\';
				} else if (c) {//[VNP]
					d = Number(d);
					switch (c) {
						case 'V':
							return $gameVariables.value(d);
							break;
						case 'N':
							return $gameActors._data[d]._name;
							break;
						case 'P':
							return $dataActors[$gameParty._actors[d - 1]].name;
							break;
					}
				} else {//script
					return eval(f);
				}
			});

			if (ary[i].var) {//変数があったら入れる
				var v = '' + $gameVariables.value(ary[i].var);
				if (ary[i].varDigit) {//2ケタの時は2まで
					if (v.length >= ary[i].varDigit) {
						name += v.substr(-1 * ary[i].varDigit, 1);
					} else {
						name = false;
					}
				} else {
					name += v;
				}
			}
			if (name) {
				var temp = ImageManager.loadPicture(name);//初回読み込み
				if (temp) {
					//if(temp._isLoading || temp._loadingState == 'requesting'){//前者は古いver用 ロード中ならアウト
					if (!temp.width) {//前者は古いver用 ロード中ならアウト
						flag = true;
						break;
					}
				} else {//その名前の画像が無かったら
					flag = true;
					this._CBR_complete = true;
					break;
				}
				p_data[i] = {
					'w': temp.width,
					'h': temp.height,
				}
			}
		}

		if (!flag) {//全ロードが終わってたら
			this.contents.clear();

			//ピクチャの表示
			var ary = CBR_eroStatus[page].p;
			for (var i = 0, len = ary.length; i < len; i++) {
				var name = ary[i].name;
				if (!name || !ary[i].show) {
					continue;
				}

				//変数とか文字化
				name = name.replace(/\\(\\)|\\([VNP])\[(\d+)\]|\\(<)(.+)\\>/g, function (a, b, c, d, e, f) {
					if (b) {//\\
						return '\\';
					} else if (c) {//[VNP]
						d = Number(d);
						switch (c) {
							case 'V':
								return $gameVariables.value(d);
								break;
							case 'N':
								return $gameActors._data[d]._name;
								break;
							case 'P':
								return $dataActors[$gameParty._actors[d - 1]].name;
								break;
						}
					} else {//script
						return eval(f);
					}
				});

				if (name) {
					this.changePaintOpacity(ary[i].opacity);

					var x = ary[i].x;
					var y = ary[i].y;
					if (ary[i].origin == 'center') {
						x -= p_data[i].w * ary[i].zoom / 2;
						y -= p_data[i].h * ary[i].zoom / 2;
					}
					this.drawPicture('pictures', name, 0, 0, x, y, 0, 0, ary[i].zoom, 0);
				}
			}

			//テキストの表示
			this.resetTextColor();
			var ary = CBR_eroStatus[page].t;
			for (var i = 0, len = ary.length; i < len; i++) {
				var size = ary[i].size;// ary[i].fontSize;
				var temp = ary[i].subject;
				if (!temp || !ary[i].show) {
					continue;
				}

				var opAry = temp.match(/(\\\{|\\\}|\\[CI]\[\d+\])+/g);

				//先頭にある場合は"","tesa"になる
				var strAry = temp.split(/(?:\\\{|\\\}|\\[CI]\[\d+\])+/);

				var str = '';
				var allW = 0;
				var maxSize = null;
				var dataFAry = [];
				var dataWAry = [];
				var drawI = [];
				var drawC = [];
				//分割した配列の数
				for (var k = 0, len2 = strAry.length; k < len2; k++) {

					//前方にある\{のフォントサイズを入れる
					dataFAry[k] = k ? dataFAry[k - 1] : 0;
					drawI[k] = [];

					//変数とか文字化
					strAry[k] = strAry[k].replace(/\\(\\)|\\([VNP])\[(\d+)\]|\\(G)|\\(<)(.+)\\>/g, function (a, b, c, d, e, f, g) {
						if (b) {//\\
							return '\\';
						} else if (c) {//[VNP]
							d = Number(d);
							switch (c) {
								case 'V':
									return $gameVariables.value(d);
									break;
								case 'N':
									return $gameActors._data[d]._name;
									break;
								case 'P':
									return $dataActors[$gameParty._actors[d - 1]].name;
									break;
							}
						} else if (e) {//G
							return $dataSystem.currencyUnit;
						} else {//script
							return eval(g);
						}
					});

					//自身の前に区切りマッチがあったら
					if (0 < k) {
						var temp = opAry[k - 1].split('\\');//\\{\\}を分割する
						for (var m = 1, len3 = temp.length; m < len3; m++) {

							switch (temp[m].charAt(0)) {
								case '{':
									dataFAry[k] += 6;
									break;
								case '}':
									dataFAry[k] -= 6;
									break;
								case 'C':
									drawC[k] = Number(temp[m].match(/\[(\d+)\]/)[1]);//Cは複数あっても最後のが適応されれば良いわけで
									break;
								case 'I':
									drawI[k][drawI[k].length] = Number(temp[m].match(/\[(\d+)\]/)[1]);
									break;
							}
						}
					}
					this.contents.fontSize = size + dataFAry[k];
					this.contents.context.font = this.contents._makeFontNameText();
					dataWAry[k] = this.contents.context.measureText(strAry[k]).width;//何の為に+4するのか忘れた
					allW += dataWAry[k];

					if (strAry[k]) {//先頭に\{や変数がある時の問題　アイコン乃場合もここを通さないと
						if (maxSize === null) {//まだ記録されてなかったら入れよう
							maxSize = dataFAry[k];
						} else {
							maxSize = (maxSize < dataFAry[k]) ? dataFAry[k] : maxSize;
						}
					}
				}

				var x = ary[i].x;
				if (ary[i].origin == 'center') {
					x -= allW / 2;
				} else if (ary[i].origin == 'right') {
					x -= allW;
				}
				for (var k = 0, len2 = strAry.length; k < len2; k++) {
					this.contents.fontSize = size + dataFAry[k];
					this.contents.context.font = this.contents._makeFontNameText();
					//bottom→下揃え原点の上　top→上揃え原点の下　center→原点
					var line = ary[i].y;
					var iconLine = ary[i].y;
					if (ary[i].align == 'top') {
						line += (size + dataFAry[k]) / 2;
					} else if (ary[i].align == 'bottom') {
						line -= (size + dataFAry[k]) / 2;
						iconLine -= Window_Base._iconWidth;
					} else {
						iconLine -= Window_Base._iconWidth / 2;
					}
					if (drawI[k].length) {
						for (var m = 0, len3 = drawI[k].length; m < len3; m++) {
							this.drawIcon(drawI[k][m], x, iconLine);
							x += Window_Base._iconWidth;
						}
					}
					if (drawC[k]) {
						this.changeTextColor(this.textColor(drawC[k]));
					}
					this.contents.drawText(strAry[k], x, line, dataWAry[k], 0, 'left');
					x += dataWAry[k];
				}
				this.contents.fontSize = this.standardFontSize();
			}
			this.resetTextColor();
			this.changePaintOpacity(true);

			this.activate();
			this._CBR_complete = true;
		}
	}
};

Window_EroStatus.prototype.drawPicture = function (dir, filename, sx, sy, x, y, w, h, zoom, hue) {
	var bitmap = ImageManager.loadBitmap('img/' + dir + '/', filename, hue, true);
	this.contents.blt(bitmap, sx, sy, bitmap.width, bitmap.height, x, y, bitmap.width * zoom, bitmap.height * zoom);
};
Window_EroStatus.prototype.standardPadding = function () {
	return 0;
};
Window_Status.prototype.lineColor = function () {
	return this.normalColor();
};
Window_Status.prototype.maxEquipmentLines = function () {
	return 6;
};

//#########　コマンドの追加　##########
Scene_Menu.prototype.commandEroSta = function () {
	SceneManager.push(Scene_EroStatus);
};
setTimeout(function () {
	var _Scene_Menu_createCommandWindow = Scene_Menu.prototype.createCommandWindow;
	Scene_Menu.prototype.createCommandWindow = function () {
		_Scene_Menu_createCommandWindow.call(this);
		this._commandWindow.setHandler('eroStatus', this.commandEroSta.bind(this));
	};
}, 0);
_Window_MenuCommand_addOriginalCommands = Window_MenuCommand.prototype.addOriginalCommands;
Window_MenuCommand.prototype.addOriginalCommands = function () {
	_Window_MenuCommand_addOriginalCommands.call(this);
	this.addCommand(CBR_eroStatusState.name, 'eroStatus', true);
};


code:
/*
############################################
	作者: COBRA
	改造や配布好き勝手にしても大丈夫だよ
	寧ろ積極的に配布して皆のゲーム快適にして
	http://cobrara.blogspot.jp/
############################################
*/

/*:
* @plugindesc 画像合成プラグイン
* @author COBRA
* @help Version 2.0.0
*
* ver1.5.1のコアスクリプトに対応させました。
* バージョン変わると全く違うものになるのね、超ビックリした
*
* イベント→スクリプトで実行してください
*
* CBR.imgFusion.fusion([
*	"ピクチャ名１",
*	"ピクチャ名２",
*	"ピクチャ名３"
* ])
* ※ピクチャ名1の画像がベースになってそこにピクチャ2とピクチャ3が表示されます
* ピクチャ2と3に変化はありません
*
* CBR.imgFusion.resetFusion("合成解除したいピクチャ名")
*/

var CBR = CBR || {};
CBR.imgFusion = {
	'list': []
};

//追加分のどれかがロード中だったら何も描写しないようにする

//ビットマップをロードする時別のものにすりかえる
//ビットマップ自体を変更する

//ビットマップは　onload→_renewCanvas→._createCanvas

CBR.imgFusion.fusion = function (ary) {
	for (var i = 0, len = ary.length; i < len; i++) {
		ImageManager.loadPicture(ary[i]);//ロードしとく
	}

	var name = ary.shift();
	//もし存在してたら上書き
	for (var i = 0, len = CBR.imgFusion.list.length; i < len; i++) {
		if (CBR.imgFusion.list[i].name == name) {
			CBR.imgFusion.list[i].material = ary;
			break;
		}
	}

	if (i === len) {//ロードしてなかったら
		CBR.imgFusion.list.push({
			'name': name,
			'material': ary
		});
	}
};

var CBR_ImageManager_loadPicture = ImageManager.loadPicture;
ImageManager.loadPicture = function (filename, hue) {
	var flag = false;
	var list;
	for (var i = 0, len = CBR.imgFusion.list.length; i < len; i++) {
		if (CBR.imgFusion.list[i].name == filename) {
			list = CBR.imgFusion.list[i].material;
			flag = true;
		}
	}

	if (flag) {//合成対象だったら
		var bitmap = this.loadBitmap('img/pictures/', filename, hue, true);//loadBitmapでキャッシュも返ってくる
		bitmap.CBR_imgFusion_list = list;
		bitmap.CBR_imgFusion_fusionComplete = false;

		if (bitmap._loadingState == 'loaded') {//ロードしていた場合
			if (!bitmap.CBR_imgFusion_name) {//合成がまだの場合

				//素材のロードが終わるまで表示させたくない
				bitmap.CBR_imgFusion_name = filename;
				bitmap.CBR_imgFusion_list = list;

				bitmap.clear();

				bitmap._onLoad = CBR_imgFusion_onLoad.bind(bitmap);
				bitmap._onLoad();

				return bitmap;

			} else {
				return CBR_ImageManager_loadPicture.call(this, filename, hue);
			}
		} else {//ロードしてない場合
			//onloadを変更
			bitmap._image.removeEventListener('load', bitmap._loadListener);
			bitmap._image.addEventListener('load', bitmap._loadListener = CBR_imgFusion_onLoad.bind(bitmap));
			bitmap.CBR_imgFusion_name = filename;
			bitmap.CBR_imgFusion_list = list;
			bitmap._onLoad = CBR_imgFusion_onLoad.bind(bitmap);//ロード時合成したものを反すようにする

			return bitmap;
		}

	} else {//違ったら普通にリターン
		return CBR_ImageManager_loadPicture.call(this, filename, hue);
	}
};

var CBR_imgFusion_onLoad = function () {
	if (this.CBR_imgFusion_fusionComplete) {
		return;
	}

	//合成要素の確認
	var loaded = true;
	for (var i = 0, len = this.CBR_imgFusion_list.length; i < len; i++) {
		var img = new Image();
		img.src = 'img/pictures/' + this.CBR_imgFusion_list[i] + '.png';
		if (!img.complete) {//読みこまれてない場合
			img.CBR_imgFusion_parentImg = this.CBR_imgFusion_name;
			//ロード後ベースのonloadを実行して全て読みこめてるかどうか再チェック
			img.onload = function () {
				var bitmap = ImageManager.loadBitmap('img/pictures/', this.CBR_imgFusion_parentImg, 0, true);
				bitmap._onLoad();
			};
			loaded = false;
		}
	}

	//要素が全てロードされてたら
	if (loaded) {
		//素材の描写　ベースの描写はまた別なのでここでやってもおｋ
		for (var i = 0, len = this.CBR_imgFusion_list.length; i < len; i++) {
			var img = new Image();
			img.src = 'img/pictures/' + this.CBR_imgFusion_list[i] + '.png';
			this._context.drawImage(img, 0, 0);
		}

		if (this._loadingState == 'loaded') {
			this.__context.drawImage(this._image, 0, 0);

			this._setDirty();
			this._callLoadListeners();
		} else {//ベースを描く
			switch (this._loadingState) {
				case 'requesting':
					this._loadingState = 'requestCompleted';
					if (this._decodeAfterRequest) {
						this.decode();
					} else {
						this._loadingState = 'purged';
						this._clearImgInstance();
					}
					break;

				case 'decrypting':
					window.URL.revokeObjectURL(this._image.src);
					this._loadingState = 'decryptCompleted';
					if (this._decodeAfterRequest) {
						this.decode();
					} else {
						this._loadingState = 'purged';
						this._clearImgInstance();
					}
					break;
			}
		}
		this.CBR_imgFusion_fusionComplete = true;
	}
};

CBR.imgFusion.resetFusion = function (name) {
	for (var i = 0, len = CBR.imgFusion.list.length; i < len; i++) {
		if (CBR.imgFusion.list[i].name == name) {
			CBR.imgFusion.list.splice(i, 1);
		}
	}

	var bitmap = ImageManager.loadPicture(name);
	bitmap._onLoad = Bitmap.prototype._onLoad.bind(bitmap);

	delete bitmap.CBR_imgFusion_name;
	delete bitmap.CBR_imgFusion_list;
	delete bitmap.CBR_imgFusion_fusionComplete;

	if (bitmap.width) {//表示する前のピクチャをリセット
		bitmap.clear();
		bitmap.__context.drawImage(bitmap._image, 0, 0);
		bitmap._setDirty();
		bitmap._callLoadListeners();
	}
};


code:
/*:
 * @plugindesc Plugin used to set basic parameters.
 * @author RM CoreScript team
 *
 * @help This plugin does not provide plugin commands.
 *
* @param cacheLimit
 * @desc For setting the upper limit of image memory cache. (MPix)
 * @default 10
 *
 * @param screenWidth
* @desc For setting the screen width.
 * @default 816
 *
 * @param screenHeight
 * @desc For setting the screen height.
 * @default 624
 *
 * @param changeWindowWidthTo
 * @desc If set, change window width to this value
 *
 * @param changeWindowHeightTo
 * @desc If set, change window height to this value
 *
 * @param renderingMode
 * @desc Rendering mode (canvas/webgl/auto)
 * @default auto
 *
 * @param alwaysDash
 * @desc To set initial value as to whether the player always dashes. (on/off)
 * @default off
 */

/*:ja
 * @plugindesc 基本的なパラメーターを設定するプラグインです。
 * @author RM CoreScript team
 *
 * @help このプラグインにはプラグインコマンドはありません。
 *
 * @param cacheLimit
 * @desc 画像のメモリへのキャッシュの上限値 (MPix)
 * @default 10
 *
 * @param screenWidth
 * @desc 画面サイズの幅
 * @default 816
 *
 * @param screenHeight
 * @desc 画面サイズの高さ
 * @default 624
 *
 * @param changeWindowWidthTo
 * @desc 値が設定された場合、ウインドウの幅を指定した値に変更
 *
 * @param changeWindowHeightTo
 * @desc 値が設定された場合、ウインドウの高さを指定した値に変更
 *
 * @param renderingMode
 * @desc レンダリングモード (canvas/webgl/auto)
 * @default auto
 *
 * @param alwaysDash
 * @desc プレイヤーが常時ダッシュするかどうかの初期値 (on/off)
 * @default off
 */

(function () {
    function toNumber(str, def) {
        return isNaN(str) ? def : +(str || def);
    }

    var parameters = PluginManager.parameters('Community_Basic');
    var cacheLimit = toNumber(parameters['cacheLimit'], 10);
    var screenWidth = toNumber(parameters['screenWidth'], 816);
    var screenHeight = toNumber(parameters['screenHeight'], 624);
    var renderingMode = parameters['renderingMode'].toLowerCase();
    var alwaysDash = parameters['alwaysDash'].toLowerCase() === 'on';
    var windowWidthTo = toNumber(parameters['changeWindowWidthTo'], 0);
    var windowHeightTo = toNumber(parameters['changeWindowHeightTo'], 0);

    var windowWidth;
    var windowHeight;

    if (windowWidthTo) {
        windowWidth = windowWidthTo;
    } else if (screenWidth !== SceneManager._screenWidth) {
        windowWidth = screenWidth;
    }

    if (windowHeightTo) {
        windowHeight = windowHeightTo;
    } else if (screenHeight !== SceneManager._screenHeight) {
        windowHeight = screenHeight;
    }

    ImageCache.limit = cacheLimit * 1000 * 1000;
    SceneManager._screenWidth = screenWidth;
    SceneManager._screenHeight = screenHeight;
    SceneManager._boxWidth = screenWidth;
    SceneManager._boxHeight = screenHeight;

    SceneManager.preferableRendererType = function () {
        if (Utils.isOptionValid('canvas')) {
            return 'canvas';
        } else if (Utils.isOptionValid('webgl')) {
            return 'webgl';
        } else if (renderingMode === 'canvas') {
            return 'canvas';
        } else if (renderingMode === 'webgl') {
            return 'webgl';
        } else {
            return 'auto';
        }
    };

    var _ConfigManager_applyData = ConfigManager.applyData;
    ConfigManager.applyData = function (config) {
        _ConfigManager_applyData.apply(this, arguments);
        if (config['alwaysDash'] === undefined) {
            this.alwaysDash = alwaysDash;
        }
    };

    var _SceneManager_initNwjs = SceneManager.initNwjs;
    SceneManager.initNwjs = function () {
        _SceneManager_initNwjs.apply(this, arguments);

        if (Utils.isNwjs() && windowWidth && windowHeight) {
            var dw = windowWidth - window.innerWidth;
            var dh = windowHeight - window.innerHeight;
            window.moveBy(-dw / 2, -dh / 2);
            window.resizeBy(dw, dh);
        }
    };
})();


code:
//=============================================================================
// CustomizeConfigItem.js
// ----------------------------------------------------------------------------
// Copyright (c) 2015 Triacontane
// This software is released under the MIT License.
// http://opensource.org/licenses/mit-license.php
// ----------------------------------------------------------------------------
// Version
// 2.1.0 2017/12/15 追加項目のデフォルト項目を含めた並び順を自由に設定できる機能を追加
//                  項目名称を日本語化
// 2.0.1 2017/10/15 2.0.0の修正によりスイッチ項目を有効にしたときにゲーム開始するとエラーになる問題を修正
// 2.0.0 2017/09/10 ツクールの型指定機能に対応し、各オプション項目を任意の数だけ追加できる機能を追加
// 1.2.3 2017/06/08 1.2.2の修正により起動できなくなっていた問題を修正
// 1.2.2 2017/05/27 競合の可能性のある記述（Objectクラスへのプロパティ追加）をリファクタリング
// 1.2.1 2016/12/08 1.2.0の機能追加以降、デフォルト項目で決定ボタンを押すとエラーになっていた現象を修正
// 1.2.0 2016/12/02 各項目で決定ボタンを押したときに実行されるスクリプトを設定できる機能を追加
// 1.1.1 2016/08/14 スイッチ項目、音量項目の初期値が無効になっていた問題を修正
// 1.1.0 2016/04/29 項目をクリックしたときに項目値が循環するよう修正
// 1.0.0 2016/01/17 初版
// ----------------------------------------------------------------------------
// [Blog]   : http://triacontane.blogspot.jp/
// [Twitter]: https://twitter.com/triacontane/
// [GitHub] : https://github.com/triacontane/
//=============================================================================

/*:
 * @plugindesc オプション任意項目作成プラグイン
 * @author トリアコンタン
 *
 * @param 数値項目
 * @desc 追加する数値項目のオプション項目情報です。
 * @default
 * @type struct<NumberData>[]
 *
 * @param 文字項目
 * @desc 追加する文字項目のオプション項目情報です。
 * @default
 * @type struct<StringData>[]
 *
 * @param スイッチ項目
 * @desc 追加するスイッチ項目のオプション項目情報です。
 * @default
 * @type struct<BooleanData>[]
 *
 * @param 音量項目
 * @desc 追加する音量項目のオプション項目情報です。
 * @default
 * @type struct<VolumeData>[]
 *
 * @help オプション画面に任意の項目を追加します。
 * 項目の種類は、以下の四種類があります。
 * 不要な項目は値を空に設定してください。
 *
 * ・スイッチ項目：
 * ON/OFFを選択する項目です。指定した番号のスイッチと値が同期されます。
 * オプションから値を設定すれば、それがスイッチに反映され、
 * スイッチを変更すれば、オプションの値に反映されます。
 * さらに、値はセーブデータ間で共有されます。
 * 隠しフラグを設定すると、オプション画面に表示されなくなります。
 * ゲームを進めないと出現しない項目などに利用できます。
 * 隠しフラグはプラグインコマンドから解除できます。
 *
 * スクリプトは上級者向け項目です。対象にカーソルを合わせて決定ボタンを
 * 押下すると指定したJavaScriptを実行できます。
 * 主に専用の設定画面などの遷移に使用します。
 *
 * ・数値項目：
 * 数値を選択する項目です。指定した番号の変数と値が同期されます。
 * スイッチ項目で指定した内容に加えて、
 * 最小値と最大値および一回の入力で変化する値を指定します。
 *
 * ・音量項目：
 * 音量を選択する項目です。BGMボリュームなどと同じ仕様で
 * キャラクターごとのボイス音量等に使ってください。
 *
 * ・文字項目：
 * 文字を選択する項目です。指定した文字の配列から項目を選択します。
 * 選択した文字のインデックス(開始位置は0)が変数に設定されます。
 * 初期値に設定する値もインデックスです。
 *
 * プラグインコマンド詳細
 *  イベントコマンド「プラグインコマンド」から実行。
 *  （パラメータの間は半角スペースで区切る）
 *
 *  CC_UNLOCK or
 *  オプション任意項目の隠し解除 [項目名]
 *  　指定した項目の隠しフラグを解除します。
 *  使用例：CC_UNLOCK 数値項目1
 *
 * 利用規約：
 *  作者に無断で改変、再配布が可能で、利用形態（商用、18禁利用等）
 *  についても制限はありません。
 *  このプラグインはもうあなたのものです。
 */

/*~struct~NumberData:
 * @param Name
 * @text 項目名称
 * @desc 項目の名称です。
 * @default 数値項目1
 *
 * @param DefaultValue
 * @text 初期値
 * @desc 項目の初期値です。
 * @default 0
 * @type number
 *
 * @param VariableID
 * @text 変数番号
 * @desc 項目の設定内容が格納される変数番号です。
 * @default 0
 * @type variable
 *
 * @param HiddenFlag
 * @text 隠しフラグ
 * @desc 項目がデフォルトで隠されるようになります。プラグインコマンドの実行で表示されます。
 * @default false
 * @type boolean
 *
 * @param Script
 * @text スクリプト
 * @desc 項目を決定したときに実行されるスクリプトです。
 * @default
 *
 * @param NumberMin
 * @text 最小値
 * @desc 項目の最小値です。
 * @default 0
 * @type number
 *
 * @param NumberMax
 * @text 最大値
 * @desc 項目の最大値です。
 * @default 100
 * @type number
 *
 * @param NumberStep
 * @text 変化値
 * @desc 項目を操作したときの数値の変化量です。
 * @default 20
 * @type number
 *
 * @param AddPosition
 * @text 追加位置
 * @desc 項目を追加する位置です。指定した項目の上に追加されます。
 * @default
 * @type select
 * @option 末尾に追加
 * @value
 * @option 常時ダッシュ
 * @value alwaysDash
 * @option コマンド記憶
 * @value commandRemember
 * @option BGM 音量
 * @value bgmVolume
 * @option BGS 音量
 * @value bgsVolume
 * @option ME 音量
 * @value meVolume
 * @option SE 音量
 * @value seVolume
 */
/*~struct~BooleanData:
 * @param Name
 * @text 項目名称
 * @desc 項目の名称です。
 * @default スイッチ項目1
 *
 * @param DefaultValue
 * @text 初期値
 * @desc 項目の初期値です。
 * @default false
 * @type boolean
 *
 * @param SwitchID
 * @text スイッチ番号
 * @desc 項目の設定内容が格納されるスイッチ番号です。
 * @default 0
 * @type switch
 *
 * @param HiddenFlag
 * @text 隠しフラグ
 * @desc 項目がデフォルトで隠されるようになります。プラグインコマンドの実行で表示されます。
 * @default false
 * @type boolean
 *
 * @param Script
 * @text スクリプト
 * @desc 項目を決定したときに実行されるスクリプトです。
 * @default
 *
 * @param AddPosition
 * @text 追加位置
 * @desc 項目を追加する位置です。指定した項目の上に追加されます。
 * @default
 * @type select
 * @option 末尾に追加
 * @value
 * @option 常時ダッシュ
 * @value alwaysDash
 * @option コマンド記憶
 * @value commandRemember
 * @option BGM 音量
 * @value bgmVolume
 * @option BGS 音量
 * @value bgsVolume
 * @option ME 音量
 * @value meVolume
 * @option SE 音量
 * @value seVolume
 */
/*~struct~StringData:
 * @param Name
 * @text 項目名称
 * @desc 項目の名称です。
 * @default 文字列項目1
 *
 * @param DefaultValue
 * @text 初期値
 * @desc 項目の初期値です。インデックスの数値を指定します。
 * @default 0
 * @type number
 *
 * @param VariableID
 * @text 変数番号
 * @desc 項目の設定内容が格納される変数番号です。
 * @default 0
 * @type variable
 *
 * @param HiddenFlag
 * @text 隠しフラグ
 * @desc 項目がデフォルトで隠されるようになります。プラグインコマンドの実行で表示されます。
 * @default false
 * @type boolean
 *
 * @param Script
 * @text スクリプト
 * @desc 項目を決定したときに実行されるスクリプトです。
 * @default
 *
 * @param StringItems
 * @text 内容の配列
 * @desc 項目の設定内容の配列です。
 * @default
 * @type string[]
 *
 * @param AddPosition
 * @text 追加位置
 * @desc 項目を追加する位置です。指定した項目の上に追加されます。
 * @default
 * @type select
 * @option 末尾に追加
 * @value
 * @option 常時ダッシュ
 * @value alwaysDash
 * @option コマンド記憶
 * @value commandRemember
 * @option BGM 音量
 * @value bgmVolume
 * @option BGS 音量
 * @value bgsVolume
 * @option ME 音量
 * @value meVolume
 * @option SE 音量
 * @value seVolume
 */
/*~struct~VolumeData:
 * @param Name
 * @text 項目名称
 * @desc 項目の名称です。
 * @default 音量項目1
 *
 * @param DefaultValue
 * @text 初期値
 * @desc 項目の初期値です。
 * @default 0
 * @type number
 *
 * @param VariableID
 * @text 変数番号
 * @desc 項目の設定内容が格納される変数番号です。
 * @default 0
 * @type variable
 *
 * @param HiddenFlag
 * @text 隠しフラグ
 * @desc 項目がデフォルトで隠されるようになります。プラグインコマンドの実行で表示されます。
 * @default false
 * @type boolean
 *
 * @param Script
 * @text スクリプト
 * @desc 項目を決定したときに実行されるスクリプトです。
 * @default
 *
 * @param AddPosition
 * @text 追加位置
 * @desc 項目を追加する位置です。指定した項目の上に追加されます。
 * @default
 * @type select
 * @option 末尾に追加
 * @value
 * @option 常時ダッシュ
 * @value alwaysDash
 * @option コマンド記憶
 * @value commandRemember
 * @option BGM 音量
 * @value bgmVolume
 * @option BGS 音量
 * @value bgsVolume
 * @option ME 音量
 * @value meVolume
 * @option SE 音量
 * @value seVolume
 */

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

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

    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 getParamArrayJson = function (paramNames, defaultValue) {
        var value = getParamString(paramNames) || null;
        try {
            value = JSON.parse(value);
            if (value === null) {
                value = defaultValue;
            } else {
                value = value.map(function (valueData) {
                    return JSON.parse(valueData);
                });
            }
        } catch (e) {
            alert(`!!!Plugin param is wrong.!!!\nPlugin:${pluginName}.js\nName:[${paramNames}]\nValue:${value}`);
            value = defaultValue;
        }
        return value;
    };

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

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

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

    var getArgJson = function (arg, defaultValue) {
        try {
            arg = JSON.parse(arg || null);
            if (arg === null) {
                arg = defaultValue;
            }
        } catch (e) {
            alert(`!!!Plugin param is wrong.!!!\nPlugin:${pluginName}.js\nValue:${arg}`);
            arg = defaultValue;
        }
        return arg;
    };

    var iterate = function (that, handler) {
        Object.keys(that).forEach(function (key, index) {
            handler.call(that, key, that[key], index);
        });
    };

    //=============================================================================
    // パラメータの取得と整形
    //=============================================================================
    var param = {};
    param.numberOptions = getParamArrayJson(['NumberOptions', '数値項目'], []);
    param.stringOptions = getParamArrayJson(['StringOptions', '文字項目'], []);
    param.switchOptions = getParamArrayJson(['SwitchOptions', 'スイッチ項目'], []);
    param.volumeOptions = getParamArrayJson(['VolumeOptions', '音量項目'], []);

    var localOptionWindowIndex = 0;

    //=============================================================================
    // Game_Interpreter
    //  プラグインコマンドを追加定義します。
    //=============================================================================
    var _Game_Interpreter_pluginCommand = Game_Interpreter.prototype.pluginCommand;
    Game_Interpreter.prototype.pluginCommand = function (command, args) {
        _Game_Interpreter_pluginCommand.call(this, command, args);
        this.pluginCommandCustomizeConfigItem(command, args);
    };

    Game_Interpreter.prototype.pluginCommandCustomizeConfigItem = function (command, args) {
        switch (getCommandName(command)) {
            case 'CC_UNLOCK':
            case 'オプション任意項目の隠し解除':
                ConfigManager.customParamUnlock(args[0]);
                break;
        }
    };

    //=============================================================================
    // ConfigManager
    //  追加項目の設定値や初期値を管理します。
    //=============================================================================
    ConfigManager.customParams = null;
    ConfigManager.hiddenInfo = {};
    ConfigManager._symbolNumber = 'Number';
    ConfigManager._symbolBoolean = 'Boolean';
    ConfigManager._symbolString = 'String';
    ConfigManager._symbolVolume = 'Volume';

    ConfigManager.getCustomParams = function () {
        if (this.customParams) {
            return this.customParams;
        }
        this.customParams = {};
        param.numberOptions.forEach(function (optionItem, index) {
            this.makeNumberOption(optionItem, index);
        }, this);
        param.stringOptions.forEach(function (optionItem, index) {
            this.makeStringOption(optionItem, index);
        }, this);
        param.switchOptions.forEach(function (optionItem, index) {
            this.makeSwitchOption(optionItem, index);
        }, this);
        param.volumeOptions.forEach(function (optionItem, index) {
            this.makeVolumeOption(optionItem, index);
        }, this);
        return this.customParams;
    };

    ConfigManager.makeNumberOption = function (optionItem, index) {
        var data = this.makeCommonOption(optionItem, index, this._symbolNumber);
        data.min = getArgNumber(optionItem.NumberMin);
        data.max = getArgNumber(optionItem.NumberMax);
        data.offset = getArgNumber(optionItem.NumberStep);
        this.pushOptionData(data);
    };

    ConfigManager.makeStringOption = function (optionItem, index) {
        var data = this.makeCommonOption(optionItem, index, this._symbolString);
        data.values = getArgJson(optionItem.StringItems, ['no item']);
        data.min = 0;
        data.max = data.values.length - 1;
        this.pushOptionData(data);
    };

    ConfigManager.makeSwitchOption = function (optionItem, index) {
        var data = this.makeCommonOption(optionItem, index, this._symbolBoolean);
        data.initValue = getArgBoolean(optionItem.DefaultValue);
        data.variable = getArgNumber(optionItem.SwitchID);
        this.pushOptionData(data);
    };

    ConfigManager.makeVolumeOption = function (optionItem, index) {
        var data = this.makeCommonOption(optionItem, index, this._symbolVolume);
        this.pushOptionData(data);
    };

    ConfigManager.makeCommonOption = function (optionItem, index, type) {
        var data = {};
        data.symbol = `${type}${index + 1}`;
        data.name = optionItem.Name;
        data.hidden = getArgBoolean(optionItem.HiddenFlag);
        data.script = optionItem.Script;
        data.initValue = getArgNumber(optionItem.DefaultValue);
        data.variable = getArgNumber(optionItem.VariableID, 0);
        data.addPotion = optionItem.AddPosition;
        return data;
    };

    ConfigManager.pushOptionData = function (data) {
        this.customParams[data.symbol] = data;
    };

    var _ConfigManager_makeData = ConfigManager.makeData;
    ConfigManager.makeData = function () {
        var config = _ConfigManager_makeData.apply(this, arguments);
        config.hiddenInfo = {};
        iterate(this.getCustomParams(), function (symbol) {
            config[symbol] = this[symbol];
            config.hiddenInfo[symbol] = this.hiddenInfo[symbol];
        }.bind(this));
        return config;
    };

    var _ConfigManager_applyData = ConfigManager.applyData;
    ConfigManager.applyData = function (config) {
        _ConfigManager_applyData.apply(this, arguments);
        iterate(this.getCustomParams(), function (symbol, item) {
            if (symbol.contains(this._symbolBoolean)) {
                this[symbol] = this.readFlagCustom(config, symbol, item);
            } else if (symbol.contains(this._symbolVolume)) {
                this[symbol] = this.readVolumeCustom(config, symbol, item);
            } else {
                this[symbol] = this.readOther(config, symbol, item);
            }
            this.hiddenInfo[symbol] = (config.hiddenInfo ? config.hiddenInfo[symbol] : item.hidden);
        }.bind(this));
    };

    ConfigManager.customParamUnlock = function (name) {
        iterate(this.getCustomParams(), function (symbol, item) {
            if (item.name === name) this.hiddenInfo[symbol] = false;
        }.bind(this));
        this.save();
    };

    ConfigManager.readOther = function (config, name, item) {
        var value = config[name];
        if (value !== undefined) {
            return Number(value).clamp(item.min, item.max);
        } else {
            return item.initValue;
        }
    };

    ConfigManager.readFlagCustom = function (config, name, item) {
        if (config[name] !== undefined) {
            return this.readFlag(config, name);
        } else {
            return item.initValue;
        }
    };

    ConfigManager.readVolumeCustom = function (config, name, item) {
        if (config[name] !== undefined) {
            return this.readVolume(config, name);
        } else {
            return item.initValue;
        }
    };

    ConfigManager.exportCustomParams = function () {
        if (!$gameVariables || !$gameSwitches) return;
        iterate(this.getCustomParams(), function (symbol, item) {
            if (item.variable > 0) {
                if (symbol.contains(this._symbolBoolean)) {
                    $gameSwitches.setValue(item.variable, !!this[symbol]);
                } else {
                    $gameVariables.setValue(item.variable, this[symbol]);
                }
            }
        }.bind(this));
    };

    ConfigManager.importCustomParams = function () {
        if (!$gameVariables || !$gameSwitches) return;
        iterate(this.getCustomParams(), function (symbol, item) {
            if (item.variable > 0) {
                if (symbol.contains(this._symbolBoolean)) {
                    this[symbol] = $gameSwitches.value(item.variable);
                } else if (symbol.contains(this._symbolVolume)) {
                    this[symbol] = $gameVariables.value(item.variable).clamp(0, 100);
                } else {
                    this[symbol] = $gameVariables.value(item.variable).clamp(item.min, item.max);
                }
            }
        }.bind(this));
    };

    var _ConfigManager_save = ConfigManager.save;
    ConfigManager.save = function () {
        _ConfigManager_save.apply(this, arguments);
        this.exportCustomParams();
    };

    //=============================================================================
    // Game_Map
    //  リフレッシュ時にオプション値を同期します。
    //=============================================================================
    var _Game_Map_refresh = Game_Map.prototype.refresh;
    Game_Map.prototype.refresh = function () {
        _Game_Map_refresh.apply(this, arguments);
        ConfigManager.importCustomParams();
    };

    //=============================================================================
    // DataManager
    //  セーブ時とロード時にオプション値を同期します。
    //=============================================================================
    var _DataManager_setupNewGame = DataManager.setupNewGame;
    DataManager.setupNewGame = function () {
        _DataManager_setupNewGame.apply(this, arguments);
        ConfigManager.exportCustomParams();
    };

    var _DataManager_loadGameWithoutRescue = DataManager.loadGameWithoutRescue;
    DataManager.loadGameWithoutRescue = function (savefileId) {
        var result = _DataManager_loadGameWithoutRescue.apply(this, arguments);
        ConfigManager.exportCustomParams();
        return result;
    };

    //=============================================================================
    // Window_Options
    //  追加項目を描画します。
    //=============================================================================
    var _Window_Options_initialize = Window_Options.prototype.initialize;
    Window_Options.prototype.initialize = function () {
        this._customParams = ConfigManager.getCustomParams();
        _Window_Options_initialize.apply(this, arguments);
        this.select(localOptionWindowIndex);
        localOptionWindowIndex = 0;
    };

    var _Window_Options_makeCommandList = Window_Options.prototype.makeCommandList;
    Window_Options.prototype.makeCommandList = function () {
        _Window_Options_makeCommandList.apply(this, arguments);
        this.addCustomOptions();
    };

    Window_Options.prototype.addCustomOptions = function () {
        iterate(this._customParams, function (key, item) {
            if (!ConfigManager.hiddenInfo[key]) {
                this.addCommand(item.name, key);
                if (item.addPotion) {
                    this.shiftCustomOptions(item.addPotion);
                }
            }
        }.bind(this));
    };

    Window_Options.prototype.shiftCustomOptions = function (addPotion) {
        var targetCommand = this._list.filter(function (command) {
            return command.symbol === addPotion;
        })[0];
        if (!targetCommand) {
            return;
        }
        var targetIndex = this._list.indexOf(targetCommand);
        var newCommand = this._list.pop();
        this._list.splice(targetIndex, 0, newCommand);
    };

    var _Window_Options_statusText = Window_Options.prototype.statusText;
    Window_Options.prototype.statusText = function (index) {
        var result = _Window_Options_statusText.apply(this, arguments);
        var symbol = this.commandSymbol(index);
        var value = this.getConfigValue(symbol);
        if (this.isNumberSymbol(symbol)) {
            result = this.numberStatusText(value);
        } else if (this.isStringSymbol(symbol)) {
            result = this.stringStatusText(value, symbol);
        }
        return result;
    };

    Window_Options.prototype.isNumberSymbol = function (symbol) {
        return symbol.contains(ConfigManager._symbolNumber);
    };

    Window_Options.prototype.isStringSymbol = function (symbol) {
        return symbol.contains(ConfigManager._symbolString);
    };

    Window_Options.prototype.isCustomSymbol = function (symbol) {
        return !!this._customParams[symbol];
    };

    Window_Options.prototype.numberStatusText = function (value) {
        return value;
    };

    Window_Options.prototype.stringStatusText = function (value, symbol) {
        return this._customParams[symbol].values[value];
    };

    var _Window_Options_processOk = Window_Options.prototype.processOk;
    Window_Options.prototype.processOk = function () {
        if (!this._shiftValue(1, true)) _Window_Options_processOk.apply(this, arguments);
        this.execScript();
    };

    var _Window_Options_cursorRight = Window_Options.prototype.cursorRight;
    Window_Options.prototype.cursorRight = function (wrap) {
        if (!this._shiftValue(1, false)) _Window_Options_cursorRight.apply(this, arguments);
    };

    var _Window_Options_cursorLeft = Window_Options.prototype.cursorLeft;
    Window_Options.prototype.cursorLeft = function (wrap) {
        if (!this._shiftValue(-1, false)) _Window_Options_cursorLeft.apply(this, arguments);
    };

    Window_Options.prototype._shiftValue = function (sign, loopFlg) {
        var symbol = this.commandSymbol(this.index());
        var value = this.getConfigValue(symbol);
        if (this.isNumberSymbol(symbol)) {
            value += this.numberOffset(symbol) * sign;
            this.changeValue(symbol, this._clampValue(value, symbol, loopFlg));
            return true;
        }
        if (this.isStringSymbol(symbol)) {
            value += sign;
            this.changeValue(symbol, this._clampValue(value, symbol, loopFlg));
            return true;
        }
        return false;
    };

    Window_Options.prototype.execScript = function () {
        var symbol = this.commandSymbol(this.index());
        if (!this.isCustomSymbol(symbol)) return;
        var script = this._customParams[symbol].script;
        if (script) eval(script);
        localOptionWindowIndex = this.index();
    };

    Window_Options.prototype._clampValue = function (value, symbol, loopFlg) {
        var maxValue = this._customParams[symbol].max;
        var minValue = this._customParams[symbol].min;
        if (loopFlg) {
            if (value > maxValue) value = minValue;
            if (value < minValue) value = maxValue;
        }
        return value.clamp(this._customParams[symbol].min, this._customParams[symbol].max);
    };

    Window_Options.prototype.numberOffset = function (symbol) {
        var value = this._customParams[symbol].offset;
        if (Input.isPressed('shift')) value *= 10;
        return value;
    };

    Window_Options.prototype.windowHeight = function () {
        return this.fittingHeight(Math.min(this.numVisibleRows(), 14));
    };
})();


code:
//=============================================================================
// CustomizeMaxSaveFile.js
// ----------------------------------------------------------------------------
// Copyright (c) 2015 Triacontane
// This software is released under the MIT License.
// http://opensource.org/licenses/mit-license.php
// ----------------------------------------------------------------------------
// Version
// 1.1.1 2017/02/25 セーブファイル数により大きな値を設定できるよう上限を開放
// 1.1.0 2016/11/03 オートセーブなど最大数以上のIDに対してセーブするプラグインとの競合に対応
// 1.0.0 2016/03/19 初版
// ----------------------------------------------------------------------------
// [Blog]   : http://triacontane.blogspot.jp/
// [Twitter]: https://twitter.com/triacontane/
// [GitHub] : https://github.com/triacontane/
//=============================================================================

/*:
 * @plugindesc Customize max save file number
 * @author triacontane
 *
 * @param SaveFileNumber
 * @desc max save file number(1...100)
 * @default 20
 *
 * @help Customize max save file number
 *
 * No plugin command
 *
 * This plugin is released under the MIT License.
 */
/*:ja
 * @plugindesc 最大セーブファイル数変更プラグイン
 * @author トリアコンタン
 *
 * @param セーブファイル数
 * @desc 最大セーブファイル数です。
 * @default 20
 *
 * @help 最大セーブファイル数をパラメータで指定した値に変更します。
 *
 * このプラグインにはプラグインコマンドはありません。
 *
 * 利用規約：
 *  作者に無断で改変、再配布が可能で、利用形態（商用、18禁利用等）
 *  についても制限はありません。
 *  このプラグインはもうあなたのものです。
 */

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

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

    var 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 paramSaveFileNumber = getParamNumber(['SaveFileNumber', 'セーブファイル数'], 0);

    //=============================================================================
    // DataManager
    //  セーブファイルの数をカスタマイズします。
    //=============================================================================
    var _DataManager_loadGlobalInfo = DataManager.loadGlobalInfo;
    DataManager.loadGlobalInfo = function () {
        if (!this._globalInfo) {
            this._globalInfo = _DataManager_loadGlobalInfo.apply(this, arguments);
        }
        return this._globalInfo;
    };

    var _DataManager_saveGlobalInfo = DataManager.saveGlobalInfo;
    DataManager.saveGlobalInfo = function (info) {
        _DataManager_saveGlobalInfo.apply(this, arguments);
        this._globalInfo = null;
    };

    var _DataManager_maxSavefiles = DataManager.maxSavefiles;
    DataManager.maxSavefiles = function () {
        return paramSaveFileNumber ? paramSaveFileNumber : _DataManager_maxSavefiles.apply(this, arguments);
    };

    var _DataManager_isThisGameFile = DataManager.isThisGameFile;
    DataManager.isThisGameFile = function (savefileId) {
        if (savefileId > this.maxSavefiles()) {
            return false;
        } else {
            return _DataManager_isThisGameFile.apply(this, arguments);
        }
    };
})();


code:
//=============================================================================
// DynamicDatabase.js
// ----------------------------------------------------------------------------
// (C)2015-2018 Triacontane
// This software is released under the MIT License.
// http://opensource.org/licenses/mit-license.php
// ----------------------------------------------------------------------------
// Version
// 1.2.9 2018/08/04 1.2.8の修正により、レベルアップメッセージなどでアクター名が正常に取得できなくなっていた問題を修正
// 1.2.8 2018/04/29 アクターの名前、二つ名、プロフィールについて一部の制御文字が正常に動作していなかった問題を修正
// 1.2.7 2017/10/07 リファクタリング
// 1.2.6 2017/06/09 全設定一覧のスプレッドシートへのリンクを説明に追加
// 1.2.5 2017/06/02 1.2.4の修正により動作しなくなっていた問題を修正
// 1.2.4 2017/05/27 競合の可能性のある記述（Objectクラスへのプロパティ追加）をリファクタリング
// 1.2.3 2017/02/16 1.2.2で数値を0に設定すると動的設定が効かなくなる問題を修正
// 1.2.2 2017/02/16 データベースに項目を追加するプラグインで発生する可能性のある競合対策
// 1.2.1 2017/02/12 汎用的な競合対策
// 1.2.0 2017/02/10 アクターと職業のデータベースについて「特徴」のみ動的データベースに対応
// 1.1.1 2017/01/19 設定値に入れた小数点以下の値が切り捨てられていた問題を修正
// 1.1.0 2016/08/15 コード整形、ドロップアイテムにドロップアイテムIDの定義が抜けていたのを修正
// 1.0.2 2016/05/16 特徴と効果にデータIDの定義を追加
// 1.0.1 2016/01/03 iterateとisEmptyが重複定義されないよう対応
// 1.0.0 2015/12/28 初版
// ----------------------------------------------------------------------------
// [Blog]   : https://triacontane.blogspot.jp/
// [Twitter]: https://twitter.com/triacontane/
// [GitHub] : https://github.com/triacontane/
//=============================================================================

/*:
 * @plugindesc 動的データベース構築プラグイン
 * @author トリアコンタン
 *
 * @help データベースの各項目を動的な値に変更するプラグインです。
 * 変数やJavaScriptの関数を使ってより高度なデータベースを構築できます。
 *
 * 注意！　データベースファイルを保存、更新するプラグインと併用しないでください。
 *
 * 文字列項目：各項目に直接入力した制御文字が利用できます。
 * 数値項目：メモ欄に入力した制御文字＋JavaScript計算式が利用できます。
 * 選択項目：メモ欄に入力した制御文字＋JavaScript計算式が利用できます。
 * 　　　　　※一番上の選択肢が 0 になります。
 *
 * 数値、選択項目の場合、メモ欄に以下の通り指定してください。
 * 　<DD（項目名）:（計算式）>
 *
 * 設定例１（アイテムの価格に10番の変数の2倍の値を設定したい場合）
 * 　<DD価格:\V[10] * 2>
 *
 * 設定例２（武器の攻撃力に、元の値と10番の変数の値との乗算値を設定したい場合）
 * 　<DD攻撃力:prev * \V[10]>
 *
 * 対象データベースは以下の全項目になります。
 * 　アクター（特徴のみ）
 * 　職業（特徴のみ）
 * 　スキル
 * 　アイテム
 * 　武器
 * 　防具
 * 　敵キャラ
 * 　ステート
 *
 * 設定可能な項目の詳細は以下のリンクを参照ください。
 * https://docs.google.com/spreadsheets/d/1BnTyJr3Z1WoW4FMKtvKaICl4SQ5ehL5RxTDSV81oVQc/edit#gid=894678948
 *
 * このプラグインにはプラグインコマンドはありません。
 *
 * 利用規約：
 *  作者に無断で改変、再配布が可能で、利用形態（商用、18禁利用等）
 *  についても制限はありません。
 *  このプラグインはもうあなたのものです。
 */

(function () {
    'use strict';

    Number.prototype.times = function (handler) {
        var i = 0;
        while (i < this) handler.call(this, i++);
    };

    //=============================================================================
    // Scene_Boot
    //  ダイナミックデータベースの構築開始
    //=============================================================================
    var _Scene_Boot_start = Scene_Boot.prototype.start;
    Scene_Boot.prototype.start = function () {
        _Scene_Boot_start.call(this);
        DynamicDatabaseManager.makeDynamicDatabase();
    };

    //=============================================================================
    // Game_Actor
    //  アクター名、二つ名、プロフィールについて変更されるまではDBから再取得するよう修正
    //=============================================================================
    var _Game_Actor_setup = Game_Actor.prototype.setup;
    Game_Actor.prototype.setup = function (actorId) {
        _Game_Actor_setup.apply(this, arguments);
        this.__nickname = null;
        this.__profile = null;
        this.__name = null;
    };

    Object.defineProperty(Game_Actor.prototype, '_profile', {
        get: function () {
            return this.__profile !== null ? this.__profile : this.actor().profile;
        },
        set: function (name) {
            this.__profile = name;
        },
    });

    Object.defineProperty(Game_Actor.prototype, '_nickname', {
        get: function () {
            return this.__nickname !== null ? this.__nickname : this.actor().nickname;
        },
        set: function (name) {
            this.__nickname = name;
        },
    });

    Object.defineProperty(Game_Actor.prototype, '_name', {
        get: function () {
            return this.__name !== null ? this.__name : this.actor().name;
        },
        set: function (name) {
            this.__name = name;
        },
    });
})();

/**
 * DynamicDatabaseManager
 *  ダイナミックデータベースの構築処理を定義します。
 * @constructor
 */
function DynamicDatabaseManager() {
    throw new Error('This is a static class');
}

DynamicDatabaseManager._columnMapper = null;
DynamicDatabaseManager._targetData = null;

DynamicDatabaseManager._columnMapperCoomon = {
    animationId: 'アニメーション',
    hitType: '命中タイプ',
    iconIndex: 'アイコン',
    occasion: '使用可能時',
    repeats: '連続回数',
    scope: '範囲',
    speed: '速度補正',
    successRate: '成功率',
    tpCost: '消費TP',
    tpGain: '得TP',
    mpCost: '消費MP',
    damage_elementId: '属性',
    damage_type: 'タイプ',
    damage_variance: '分散度',
    price: '価格',
    params_0: '最大HP',
    params_1: '最大MP',
    params_2: '攻撃力',
    params_3: '防御力',
    params_4: '魔法力',
    params_5: '魔法防御',
    params_6: '敏捷性',
    params_7: '運'
};

DynamicDatabaseManager._columnMapperSkills = {
    stypeId: 'スキルタイプ',
    requiredWtypeId1: '武器タイプ1',
    requiredWtypeId2: '武器タイプ2'
};

DynamicDatabaseManager._columnMapperItems = {
    itypeId: 'アイテムタイプ',
    consumable: '消耗'
};

DynamicDatabaseManager._columnMapperWeapons = {
    wtypeId: '武器タイプ'
};

DynamicDatabaseManager._columnMapperArmors = {
    atypeId: '防具タイプ',
    etypeId: '装備タイプ'
};

DynamicDatabaseManager._columnMapperEnemies = {
    battlerHue: '色相',
    exp: '経験値',
    gold: '所持金'
};

DynamicDatabaseManager._columnMapperStates = {
    autoRemovalTiming: '自動解除のタイミング',
    chanceByDamage: 'ダメージで解除_ダメージ',
    maxTurns: '継続ターン数_最大',
    minTurns: '継続ターン数_最小',
    motion: '[SV] モーション',
    overlay: '[SV] 重ね合わせ',
    priority: '優先度',
    removeAtBattleEnd: '戦闘終了時に解除',
    removeByDamage: 'ダメージで解除',
    removeByRestriction: '行動制約で解除',
    removeByWalking: '歩数で解除',
    restriction: '行動制約',
    stepsToRemove: '歩数で解除_歩数'
};

DynamicDatabaseManager._targetDynamicDatabase = {
    $dataActors: DynamicDatabaseManager._columnMapperCoomon,
    $dataClasses: DynamicDatabaseManager._columnMapperCoomon,
    $dataSkills: DynamicDatabaseManager._columnMapperSkills,
    $dataItems: DynamicDatabaseManager._columnMapperItems,
    $dataWeapons: DynamicDatabaseManager._columnMapperWeapons,
    $dataArmors: DynamicDatabaseManager._columnMapperArmors,
    $dataEnemies: DynamicDatabaseManager._columnMapperEnemies,
    $dataStates: DynamicDatabaseManager._columnMapperStates
};

DynamicDatabaseManager._isEmpty = function (that) {
    return Object.keys(that).length <= 0;
};

DynamicDatabaseManager._iterate = function (that, handler) {
    Object.keys(that).forEach(function (key, index) {
        handler.call(that, key, that[key], index);
    });
};

DynamicDatabaseManager.makeDynamicDatabase = function () {
    this._setColumnMapperDynamic();
    this._iterate(this._targetDynamicDatabase, function (dataKey, columnMap) {
        this._makeDynamicData(window[dataKey], columnMap);
    }.bind(this));
};

DynamicDatabaseManager._setColumnMapperDynamic = function () {
    this._getMaxLength('effects').times(function (i) {
        this._columnMapperCoomon['effects_%1_code'.format(i)] = '使用効果%1_タイプ'.format(i + 1);
        this._columnMapperCoomon['effects_%1_dataId'.format(i)] = '使用効果%1_データID'.format(i + 1);
        this._columnMapperCoomon['effects_%1_value1'.format(i)] = '使用効果%1_内容1'.format(i + 1);
        this._columnMapperCoomon['effects_%1_value2'.format(i)] = '使用効果%1_内容2'.format(i + 1);
    }.bind(this));
    this._getMaxLength('traits').times(function (i) {
        this._columnMapperCoomon['traits_%1_code'.format(i)] = '特徴%1_タイプ'.format(i + 1);
        this._columnMapperCoomon['traits_%1_dataId'.format(i)] = '特徴%1_データID'.format(i + 1);
        this._columnMapperCoomon['traits_%1_value'.format(i)] = '特徴%1_内容'.format(i + 1);
    }.bind(this));
    this._getMaxLength('actions').times(function (i) {
        this._columnMapperEnemies['actions_%1_conditionParam1'.format(i)] = '行動%1_条件1'.format(i + 1);
        this._columnMapperEnemies['actions_%1_conditionParam2'.format(i)] = '行動%1_条件2'.format(i + 1);
        this._columnMapperEnemies['actions_%1_conditionType'.format(i)] = '行動%1_条件タイプ'.format(i + 1);
        this._columnMapperEnemies['actions_%1_rating'.format(i)] = '行動%1_R'.format(i + 1);
        this._columnMapperEnemies['actions_%1_skillId'.format(i)] = '行動%1_スキル'.format(i + 1);
    }.bind(this));
    Number(3).times(function (i) {
        this._columnMapperEnemies['dropItems_%1_denominator'.format(i)] = 'ドロップアイテム%1_ドロップアイテム'.format(i + 1);
        this._columnMapperEnemies['dropItems_%1_dataId'.format(i)] = 'ドロップアイテム%1_ドロップアイテムID'.format(i + 1);
        this._columnMapperEnemies['dropItems_%1_kind'.format(i)] = 'ドロップアイテム%1_出現率'.format(i + 1);
    }.bind(this));
};

DynamicDatabaseManager._getMaxLength = function (keyName) {
    var length = 0;
    this._iterate(this._targetDynamicDatabase, function (dataKey) {
        var dataArray = window[dataKey];
        dataArray.forEach(function (data) {
            if (data && data.hasOwnProperty(keyName)) {
                length = Math.max(data[keyName].length, length);
            }
        });
    });
    return length;
};

DynamicDatabaseManager._makeDynamicData = function (dataArray, columnMap) {
    this._columnMapper = columnMap;
    dataArray.forEach(function (data) {
        if (data) {
            this._targetData = data;
            this._iterate(data, function (key, value) {
                this._makeProperty(data, key, key, value);
            }.bind(this));
        }
    }.bind(this));
};

DynamicDatabaseManager._makeProperty = function (parent, keyPath, key, child) {
    if (key === 'meta') {
        return;
    }
    switch (typeof child) {
        case 'string':
            if (child.match(/\\/g)) {
                this._makePropertyString(parent, key, child);
            }
            break;
        case 'boolean':
        case 'number':
            if (this._isEmpty(parent.meta)) {
                return;
            }
            var propName = this._columnMapper[keyPath] || this._columnMapperCoomon[keyPath];
            var metaTag = 'DD' + propName;
            if (propName != null && parent.meta[metaTag] != null) {
                this._makePropertyFormula(parent, key, child, metaTag);
            }
            parent[propName] = child;
            break;
        case 'object':
            if (!child || this._isEmpty(parent.meta)) {
                return;
            }
            child.meta = parent.meta;
            this._iterate(child, function (valuesKey, valuesItem) {
                this._makeProperty(child, keyPath + '_' + valuesKey, valuesKey, valuesItem);
            }.bind(this));
            break;
    }
};

DynamicDatabaseManager._makePropertyFormula = function (parent, key, child, metaTag) {
    var data = this._targetData;
    Object.defineProperty(parent, key, {
        get: function () {
            var prev = child;
            var result = eval(DynamicDatabaseManager._convertEscapeCharacters(this.meta[metaTag]));
            return typeof child === 'number' ? result : !!result;
        }
    });
};

DynamicDatabaseManager._makePropertyString = function (parent, key, child) {
    Object.defineProperty(parent, key, {
        get: function () {
            return DynamicDatabaseManager._convertEscapeCharacters(child);
        }
    });
};

DynamicDatabaseManager._convertEscapeCharacters = function (text) {
    text = text.replace(/\\/g, '\x1b');
    text = text.replace(/\x1b\x1b/g, '\\');
    text = text.replace(/\x1bV\[(\d+)\]/gi, function () {
        return $gameVariables ? $gameVariables.value(parseInt(arguments[1], 10)) : 0;
    });
    text = text.replace(/\x1bV\[(\d+)\]/gi, function () {
        return $gameVariables ? $gameVariables.value(parseInt(arguments[1], 10)) : 0;
    });
    text = text.replace(/\x1bS\[(\d+)\]/gi, function () {
        return $gameSwitches ? ($gameSwitches.value(parseInt(arguments[1], 10)) ? '1' : '0') : '0';
    });
    text = text.replace(/\x1bN\[(\d+)\]/gi, function () {
        var n = parseInt(arguments[1]);
        var actor = (n >= 1 && $gameActors ? $gameActors.actor(n) : null);
        return actor ? actor.name() : '';
    });
    text = text.replace(/\x1bP\[(\d+)\]/gi, function () {
        var n = parseInt(arguments[1]);
        var actor = (n >= 1 && $gameParty ? $gameParty.members()[n - 1] : null);
        return actor ? actor.name() : '';
    });
    text = text.replace(/\x1bG/gi, TextManager.currencyUnit);
    return text;
};


code:
//=============================================================================
// DynamicVariables.js
// ----------------------------------------------------------------------------
// (C)2016 Triacontane
// This software is released under the MIT License.
// http://opensource.org/licenses/mit-license.php
// ----------------------------------------------------------------------------
// Version
// 1.1.0 2018/08/19 イベントページの出現条件および敵キャラの行動パターンで各オブジェクトおよびデータを参照できる機能を追加
// 1.0.5 2018/01/27 1.0.4の更新でもともと入っていた値の取得方法をvalueに変更
// 1.0.4 2018/01/15 実行時に対象スイッチIDおよび代入されているもとの値を参照できる機能を追加
// 1.0.3 2017/08/12 パラメータの型指定機能に対応
// 1.0.2 2016/11/04 指定範囲外のスイッチの値を正しく返していなかった問題を修正
// 1.0.1 2016/11/01 結果が空文字の場合に0が設定されないよう修正
// 1.0.0 2016/10/27 初版
// ----------------------------------------------------------------------------
// [Blog]   : https://triacontane.blogspot.jp/
// [Twitter]: https://twitter.com/triacontane/
// [GitHub] : https://github.com/triacontane/
//=============================================================================

/*:
 * @plugindesc DynamicVariablesPlugin
 * @author triacontane
 *
 * @param DynamicSwitchStart
 * @desc 動的スイッチの開始位置番号です。
 * @default 0
 * @type switch
 *
 * @param DynamicSwitchEnd
 * @desc 動的スイッチの終了位置番号です。
 * @default 0
 * @type switch
 *
 * @param DynamicVariableStart
 * @desc 動的変数の開始位置番号です。
 * @default 0
 * @type variable
 *
 * @param DynamicVariableEnd
 * @desc 動的変数の終了位置番号です。
 * @default 0
 * @type variable
 *
 * @param ValidException
 * @desc スクリプト実行時に例外処理を行います。不正なスクリプトで強制終了しなくなる代わりに実行速度が僅かに低下します。
 * @default false
 * @type boolean
 *
 * @help 指定範囲内の変数、スイッチを参照しようとした際に、
 * 「変数名称」及び「スイッチ名称」をJavaScriptとして評価した結果を返すようにします。
 * JavaScript中では式の簡略化のために以下のローカル変数が利用できます。
 *
 * id        # 処理対象のスイッチ、変数ID
 * value     # 処理対象のスイッチ、変数IDにもともと入っていた値
 * v(n)      # [n]番の変数の値
 * s(n)      # [n]番のスイッチの値
 * max       # Math.maxに変換されます。(例 : max(1, 2) -> 2)
 * min       # Math.minに変換されます。(例 : min(1, 2) -> 1)
 * gPlayer   # $gamePlayerに変換されます。(例 : gPlayer.x -> プレイヤーX座標)
 * dSystem   # $dataSystemsに変換されます。(例：dSystem.startX -> 開始位置X座標)
 * ※ Math.max以外にも一般的なMathモジュールのメソッドが使用可能です。
 *    また、他のゲームオブジェクト、データオブジェクトも同じ記法で参照できます。
 *    いずれも利用には、多少のJavaScriptの知識が必要になります。
 *
 * イベントページの出現条件でスイッチを参照する場合、追加で以下の変数が使えます。
 * e         # イベントオブジェクトへの参照
 * d         # イベントデータへの参照
 *
 * 敵キャラの行動パターンでスイッチを参照する場合、追加で以下の変数が使えます。
 * e         # 敵キャラオブジェクトへの参照
 * d         # 敵キャラデータへの参照
 *
 * 上記以外の状況でeやdを参照するとエラーになるで注意してください。
 *
 * 動的変数は、指定範囲内の変数およびスイッチを参照するすべての箇所(※)で有効です。
 * また、範囲内の変数及びスイッチに対する値の設定は無視されます。
 *
 * ※変数・スイッチを参照する例
 * 1. イベントページの決定処理
 * 2. 敵キャラの行動決定処理
 * 3. 条件分岐
 * 4. イベントコマンドの各種オペランド
 * 5. スキルやアイテムの計算式（ただしv[1]で参照した場合は除く）
 * 6. その他プラグインによる参照
 *
 * スクリプト中でさらに動的変数およびスイッチを参照することもできますが
 * 同じ番号の変数 or スイッチを参照しようとすると循環参照となりエラーが発生します。
 *
 * ・設定例1
 * イベントページの「スイッチ」に「名称」が以下のものを設定する。
 * v(1) > 0 || s(1) # 変数[1]が[0]より大きい、もしくはスイッチ[1]がON
 * 以上の条件を満たした場合に対象ページが表示される。
 *
 * ・設定例2
 * イベントページの「スイッチ」に「名称」が以下のものを設定する。
 * v(1) < v(2) && !s(2) # 変数[1]が変数[2]より小さい、かつスイッチ[2]がOFF
 * 以上の条件を満たした場合に対象ページが表示される。
 *
 * ・設定例3
 * イベントページの「スイッチ」に「名称」が以下のものを設定する。
 * gPlayer.x % 2 === 0 # プレイヤーのX座標が偶数
 * 以上の条件を満たした場合に対象ページが表示される。
 *
 * ・使用上の注意
 * 通常、イベントのページを決定する処理は、いずれかのスイッチもしくは変数が
 * 変更されたときにのみ実行されます。本プラグインでは、パフォーマンス上の理由から
 * その仕様を維持します。
 * もし、指定している条件がスイッチおよび変数と完全に無関係な場合(設定例3のケース等)
 * イベントのメモ欄に以下の通り入力すると、そのイベントのみ
 * 常にページの条件チェックを行うように変更できます。
 *
 * <DV常時リフレッシュ>
 * <DVAlwaysRefresh>
 *
 * （参考）基本的なJavaScript演算子
 * ・四則演算    : + - * /
 * ・論理和(Or)  : ||
 * ・論理積(And) : &&
 * ・否定(Not)   : !
 *
 * このプラグインにはプラグインコマンドはありません。
 *
 * This plugin is released under the MIT License.
 */
/*:ja
 * @plugindesc 動的変数プラグイン
 * @author トリアコンタン
 *
 * @param 動的スイッチ開始位置
 * @desc 動的スイッチの開始位置番号です。
 * @default 0
 * @type switch
 *
 * @param 動的スイッチ終了位置
 * @desc 動的スイッチの終了位置番号です。
 * @default 0
 * @type switch
 *
 * @param 動的変数開始位置
 * @desc 動的変数の開始位置番号です。
 * @default 0
 * @type variable
 *
 * @param 動的変数終了位置
 * @desc 動的変数の終了位置番号です。
 * @default 0
 * @type variable
 *
 * @param 例外処理
 * @desc スクリプト実行時に例外処理を行います。不正なスクリプトで強制終了しなくなる代わりに実行速度が僅かに低下します。
 * @default false
 * @type boolean
 *
 * @help 指定範囲内の変数、スイッチを参照しようとした際に、
 * 「変数名称」及び「スイッチ名称」をJavaScriptとして実行した結果を返すよう
 * 変更します。JavaScript中では式の簡略化のために以下のローカル変数が利用できます。
 *
 * id        # 処理対象のスイッチ、変数ID
 * value     # 処理対象のスイッチ、変数IDにもともと入っていた値
 * v(n)      # [n]番の変数の値
 * s(n)      # [n]番のスイッチの値
 * max       # Math.maxに変換されます。(例 : max(1, 2) -> 2)
 * min       # Math.minに変換されます。(例 : min(1, 2) -> 1)
 * gPlayer   # $gamePlayerに変換されます。(例 : gPlayer.x -> プレイヤーX座標)
 * dSystem   # $dataSystemsに変換されます。(例：dSystem.startX -> 開始位置X座標)
 * ※ Math.max以外にも一般的なMathモジュールのメソッドが使用可能です。
 *    また、他のゲームオブジェクト、データオブジェクトも同じ記法で参照できます。
 *    いずれも利用には、多少のJavaScriptの知識が必要になります。
 *
 * また、以下のスクリプトでスイッチや変数にもともと入っている値を参照できます。
 * this._data[id]
 *
 * 動的変数は、指定範囲内の変数およびスイッチを参照するすべての箇所(※)で有効です。
 * また、範囲内の変数及びスイッチに対する値の設定は無視されます。
 *
 * ※変数・スイッチを参照する例
 * 1. イベントページの決定処理
 * 2. 敵キャラの行動決定処理
 * 3. 条件分岐
 * 4. イベントコマンドの各種オペランド
 * 5. スキルやアイテムの計算式（ただしv[1]で参照した場合は除く）
 * 6. その他プラグインによる参照
 *
 * スクリプト中でさらに動的変数およびスイッチを参照することもできますが
 * 同じ番号の変数 or スイッチを参照しようとすると循環参照となりエラーが発生します。
 *
 * ・設定例1
 * イベントページの「スイッチ」に「名称」が以下のものを設定する。
 * v(1) > 0 || s(1) # 変数[1]が[0]より大きい、もしくはスイッチ[1]がON
 * 以上の条件を満たした場合に対象ページが表示される。
 *
 * ・設定例2
 * イベントページの「スイッチ」に「名称」が以下のものを設定する。
 * v(1) < v(2) && !s(2) # 変数[1]が変数[2]より小さい、かつスイッチ[2]がOFF
 * 以上の条件を満たした場合に対象ページが表示される。
 *
 * ・設定例3
 * イベントページの「スイッチ」に「名称」が以下のものを設定する。
 * gPlayer.x % 2 === 0 # プレイヤーのX座標が偶数
 * 以上の条件を満たした場合に対象ページが表示される。
 *
 * ・使用上の注意
 * 通常、イベントのページを決定する処理は、いずれかのスイッチもしくは変数が
 * 変更されたときにのみ実行されます。本プラグインでは、パフォーマンス上の理由から
 * その仕様を維持します。
 * もし、指定している条件がスイッチおよび変数と完全に無関係な場合
 * (設定例3のケース等)イベントのメモ欄に以下の通り入力すると、そのイベントのみ
 * 常にページの条件チェックを行うように変更できます。
 *
 * <DV常時リフレッシュ>
 * <DVAlwaysRefresh>
 *
 * （参考）基本的なJavaScript演算子
 * ・四則演算    : + - * /
 * ・論理和(Or)  : ||
 * ・論理積(And) : &&
 * ・否定(Not)   : !
 *
 * このプラグインにはプラグインコマンドはありません。
 *
 * 利用規約：
 *  作者に無断で改変、再配布が可能で、利用形態（商用、18禁利用等）
 *  についても制限はありません。
 *  このプラグインはもうあなたのものです。
 */

(function () {
    'use strict';
    var pluginName = 'DynamicVariables';
    var metaTagPrefix = 'DV';

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

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

    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 getMetaValue = function (object, name) {
        var metaTagName = metaTagPrefix + (name ? name : '');
        return object.meta.hasOwnProperty(metaTagName) ? object.meta[metaTagName] : undefined;
    };

    var getMetaValues = function (object, names) {
        if (!Array.isArray(names)) return getMetaValue(object, names);
        for (var i = 0, n = names.length; i < n; i++) {
            var value = getMetaValue(object, names[i]);
            if (value !== undefined) return value;
        }
        return undefined;
    };

    //=============================================================================
    // パラメータの取得と整形
    //=============================================================================
    var paramDynamicSwitchStart = getParamNumber(['DynamicSwitchStart', '動的スイッチ開始位置'], 0);
    var paramDynamicSwitchEnd = getParamNumber(['DynamicSwitchEnd', '動的スイッチ終了位置'], 0);
    var paramDynamicVariableStart = getParamNumber(['DynamicVariableStart', '動的変数開始位置'], 0);
    var paramDynamicVariableEnd = getParamNumber(['DynamicVariableEnd', '動的変数終了位置'], 0);
    var paramValidException = getParamBoolean(['ValidException', '例外処理']);

    // eval参照用
    var e = null;
    var d = null;

    //=============================================================================
    // Game_Variables
    //  動的変数の取得処理を追加定義します。
    //=============================================================================
    var _Game_Variables_value = Game_Variables.prototype.value;
    Game_Variables.prototype.value = function (variableId) {
        var value = _Game_Variables_value.apply(this, arguments);
        if (variableId >= paramDynamicVariableStart && variableId <= paramDynamicVariableEnd) {
            return this.getDynamicValue($dataSystem.variables[variableId], variableId, value);
        } else {
            return value;
        }
    };

    Game_Variables.prototype.getOriginalValue = function (variableId) {
        return _Game_Variables_value.apply(this, arguments);
    };

    Game_Variables.prototype.getDynamicValue = function (dynamicScript, id, value) {
        if (!dynamicScript) {
            return value;
        }
        var v = $gameVariables.value.bind($gameVariables), s = $gameSwitches.value.bind($gameSwitches);
        var max = Math.max, min = Math.min, abs = Math.abs, floor = Math.floor, pow = Math.pow, random = Math.random;

        var dActors = $dataActors;
        var dClasses = $dataClasses;
        var dSkills = $dataSkills;
        var dItems = $dataItems;
        var dWeapons = $dataWeapons;
        var dArmors = $dataArmors;
        var dEnemies = $dataEnemies;
        var dTroops = $dataTroops;
        var dStates = $dataStates;
        var dAnimations = $dataAnimations;
        var dTilesets = $dataTilesets;
        var dCommonEvents = $dataCommonEvents;
        var dSystem = $dataSystem;
        var dMapInfos = $dataMapInfos;
        var dMap = $dataMap;
        var gTemp = $gameTemp;
        var gSystem = $gameSystem;
        var gScreen = $gameScreen;
        var gTimer = $gameTimer;
        var gMessage = $gameMessage;
        var gSwitches = $gameSwitches;
        var gActors = $gameActors;
        var gParty = $gameParty;
        var gTroop = $gameTroop;
        var gMap = $gameMap;
        var gPlayer = $gamePlayer;
        if (paramValidException) {
            try {
                return eval(dynamicScript);
            } catch (e) {
                console.error(e.message);
                return 0;
            }
        } else {
            return eval(dynamicScript);
        }
    };

    //=============================================================================
    // Game_Switches
    //  動的スイッチの取得処理を追加定義します。
    //=============================================================================
    var _Game_Switches_value = Game_Switches.prototype.value;
    Game_Switches.prototype.value = function (switchId) {
        var value = _Game_Switches_value.apply(this, arguments);
        if (switchId >= paramDynamicSwitchStart && switchId <= paramDynamicSwitchEnd) {
            return !!this.getDynamicValue($dataSystem.switches[switchId], switchId, value);
        } else {
            return value;
        }
    };

    Game_Switches.prototype.getOriginalValue = function (switchId) {
        return _Game_Switches_value.apply(this, arguments);
    };

    Game_Switches.prototype.getDynamicValue = Game_Variables.prototype.getDynamicValue;

    //=============================================================================
    // Game_Event
    //  必要な場合、イベントページを毎フレームリフレッシュします。
    //=============================================================================
    var _Game_Event_initialize = Game_Event.prototype.initialize;
    Game_Event.prototype.initialize = function (mapId, eventId) {
        _Game_Event_initialize.apply(this, arguments);
        this._needsAlwaysRefresh = this.isNeedAlwaysRefresh();
    };

    Game_Event.prototype.isNeedAlwaysRefresh = function () {
        return getMetaValues(this.event(), ['AlwaysRefresh', '常時リフレッシュ']);
    };

    var _Game_Event_update = Game_Event.prototype.update;
    Game_Event.prototype.update = function () {
        if (this._needsAlwaysRefresh) {
            this.refresh();
        }
        _Game_Event_update.apply(this, arguments);
    };

    var _Game_Event_meetsConditions = Game_Event.prototype.meetsConditions;
    Game_Event.prototype.meetsConditions = function (page) {
        e = this;
        d = this.event();
        var result = _Game_Event_meetsConditions.apply(this, arguments);
        e = null;
        d = null;
        return result;
    };

    /**
     * Game_Enemy
     * 敵キャラ情報をスクリプト実行用に記憶します。
     */
    var _Game_Enemy_meetsSwitchCondition = Game_Enemy.prototype.meetsSwitchCondition;
    Game_Enemy.prototype.meetsSwitchCondition = function (param) {
        e = this;
        d = this.enemy();
        var result = _Game_Enemy_meetsSwitchCondition.apply(this, arguments);
        e = null;
        d = null;
        return result;
    };
})();